1249 lines
31 KiB
Vue
1249 lines
31 KiB
Vue
<template>
|
|
<div class="board-dashboard">
|
|
<!-- Sidebar Navigation -->
|
|
<aside :class="['sidebar', { 'sidebar--collapsed': sidebarCollapsed }]">
|
|
<div class="sidebar__header">
|
|
<div class="sidebar__logo">
|
|
<img src="/MONACOUSA-Flags_376x376.png" alt="MonacoUSA" class="sidebar__logo-img" />
|
|
<span v-if="!sidebarCollapsed" class="sidebar__logo-text">Board Portal</span>
|
|
</div>
|
|
<button @click="sidebarCollapsed = !sidebarCollapsed" class="sidebar__toggle">
|
|
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
:d="sidebarCollapsed ? 'M13 5l7 7-7 7' : 'M11 19l-7-7 7-7'" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<nav class="sidebar__nav">
|
|
<a v-for="item in boardNavItems" :key="item.name"
|
|
:href="item.path"
|
|
:class="['sidebar__nav-item', { 'sidebar__nav-item--active': item.active }]">
|
|
<component :is="item.icon" class="sidebar__nav-icon" />
|
|
<span v-if="!sidebarCollapsed" class="sidebar__nav-label">{{ item.name }}</span>
|
|
</a>
|
|
</nav>
|
|
|
|
<div class="sidebar__footer">
|
|
<div class="sidebar__profile">
|
|
<div class="sidebar__profile-avatar">
|
|
<img src="https://ui-avatars.com/api/?name=Board+Member&background=DC2626&color=fff" alt="Profile" />
|
|
</div>
|
|
<div v-if="!sidebarCollapsed" class="sidebar__profile-info">
|
|
<span class="sidebar__profile-name">Board Member</span>
|
|
<span class="sidebar__profile-role">Executive Board</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
|
|
<!-- Main Content -->
|
|
<main class="main-content">
|
|
<!-- Top Bar -->
|
|
<header class="topbar">
|
|
<div class="topbar__left">
|
|
<h1 class="topbar__title">Board Overview</h1>
|
|
<span class="topbar__subtitle">Strategic Insights & Governance</span>
|
|
</div>
|
|
|
|
<div class="topbar__right">
|
|
<button class="topbar__notification">
|
|
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" />
|
|
</svg>
|
|
<span class="topbar__notification-badge">3</span>
|
|
</button>
|
|
|
|
<div class="topbar__date">
|
|
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
|
</svg>
|
|
{{ currentDate }}
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Executive Summary Cards -->
|
|
<section class="executive-summary">
|
|
<StatCard
|
|
v-for="metric in executiveMetrics"
|
|
:key="metric.label"
|
|
:label="metric.label"
|
|
:value="metric.value"
|
|
:trend="metric.trend"
|
|
:prefix="metric.prefix"
|
|
:variant="metric.variant"
|
|
:icon="metric.icon"
|
|
:description="metric.description"
|
|
:format="metric.format"
|
|
/>
|
|
</section>
|
|
|
|
<!-- Strategic Insights Grid -->
|
|
<div class="insights-grid">
|
|
<!-- Financial Performance Chart -->
|
|
<NeumorphicCard class="financial-chart">
|
|
<template #header>
|
|
<div class="card-header">
|
|
<h2 class="card-title">Financial Performance</h2>
|
|
<div class="card-actions">
|
|
<select class="period-selector">
|
|
<option>Quarterly</option>
|
|
<option>Monthly</option>
|
|
<option>Yearly</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<div class="chart-container">
|
|
<canvas ref="financialChart"></canvas>
|
|
</div>
|
|
|
|
<template #footer>
|
|
<div class="chart-legend">
|
|
<span class="legend-item">
|
|
<span class="legend-dot" style="background: #DC2626"></span>
|
|
Revenue
|
|
</span>
|
|
<span class="legend-item">
|
|
<span class="legend-dot" style="background: #10B981"></span>
|
|
Profit
|
|
</span>
|
|
<span class="legend-item">
|
|
<span class="legend-dot" style="background: #3B82F6"></span>
|
|
Expenses
|
|
</span>
|
|
</div>
|
|
</template>
|
|
</NeumorphicCard>
|
|
|
|
<!-- Key Performance Indicators -->
|
|
<NeumorphicCard class="kpi-card">
|
|
<template #header>
|
|
<h2 class="card-title">Key Performance Indicators</h2>
|
|
</template>
|
|
|
|
<div class="kpi-list">
|
|
<div v-for="kpi in keyPerformanceIndicators" :key="kpi.name" class="kpi-item">
|
|
<div class="kpi-header">
|
|
<span class="kpi-name">{{ kpi.name }}</span>
|
|
<span :class="['kpi-status', `kpi-status--${kpi.status}`]">
|
|
{{ kpi.status }}
|
|
</span>
|
|
</div>
|
|
<div class="kpi-progress">
|
|
<div class="kpi-progress-bar">
|
|
<div class="kpi-progress-fill"
|
|
:style="{ width: `${kpi.progress}%` }"
|
|
:class="`kpi-progress-fill--${kpi.status}`"></div>
|
|
</div>
|
|
<span class="kpi-value">{{ kpi.value }} / {{ kpi.target }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</NeumorphicCard>
|
|
</div>
|
|
|
|
<!-- Board Activities and Decisions -->
|
|
<div class="board-grid">
|
|
<!-- Upcoming Board Meetings -->
|
|
<NeumorphicCard class="meetings-card">
|
|
<template #header>
|
|
<h2 class="card-title">Upcoming Board Meetings</h2>
|
|
</template>
|
|
|
|
<div class="meetings-list">
|
|
<div v-for="meeting in upcomingMeetings" :key="meeting.id" class="meeting-item">
|
|
<div class="meeting-date">
|
|
<span class="meeting-month">{{ meeting.month }}</span>
|
|
<span class="meeting-day">{{ meeting.day }}</span>
|
|
</div>
|
|
<div class="meeting-details">
|
|
<h3 class="meeting-title">{{ meeting.title }}</h3>
|
|
<p class="meeting-info">
|
|
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
</svg>
|
|
{{ meeting.time }} • {{ meeting.duration }}
|
|
</p>
|
|
<div class="meeting-attendees">
|
|
<img v-for="attendee in meeting.attendees.slice(0, 3)"
|
|
:key="attendee"
|
|
:src="`https://ui-avatars.com/api/?name=${attendee}&background=random`"
|
|
:alt="attendee"
|
|
class="attendee-avatar" />
|
|
<span v-if="meeting.attendees.length > 3" class="attendee-more">
|
|
+{{ meeting.attendees.length - 3 }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<ProfessionalButton size="sm" variant="outline">
|
|
View Agenda
|
|
</ProfessionalButton>
|
|
</div>
|
|
</div>
|
|
</NeumorphicCard>
|
|
|
|
<!-- Recent Resolutions -->
|
|
<NeumorphicCard class="resolutions-card">
|
|
<template #header>
|
|
<div class="card-header">
|
|
<h2 class="card-title">Recent Resolutions</h2>
|
|
<ProfessionalButton size="sm" variant="ghost">View All</ProfessionalButton>
|
|
</div>
|
|
</template>
|
|
|
|
<div class="resolutions-list">
|
|
<div v-for="resolution in recentResolutions" :key="resolution.id" class="resolution-item">
|
|
<div class="resolution-status" :class="`resolution-status--${resolution.status}`">
|
|
<svg v-if="resolution.status === 'approved'" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
|
|
</svg>
|
|
<svg v-else-if="resolution.status === 'pending'" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z" clip-rule="evenodd" />
|
|
</svg>
|
|
<svg v-else fill="currentColor" viewBox="0 0 20 20">
|
|
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
|
|
</svg>
|
|
</div>
|
|
<div class="resolution-content">
|
|
<h4 class="resolution-title">{{ resolution.title }}</h4>
|
|
<p class="resolution-description">{{ resolution.description }}</p>
|
|
<div class="resolution-meta">
|
|
<span class="resolution-date">{{ resolution.date }}</span>
|
|
<span class="resolution-votes">
|
|
{{ resolution.votesFor }}-{{ resolution.votesAgainst }}-{{ resolution.abstain }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</NeumorphicCard>
|
|
</div>
|
|
|
|
<!-- Strategic Initiatives -->
|
|
<NeumorphicCard class="initiatives-card">
|
|
<template #header>
|
|
<div class="card-header">
|
|
<h2 class="card-title">Strategic Initiatives</h2>
|
|
<div class="card-actions">
|
|
<ProfessionalButton size="sm" variant="primary">
|
|
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
|
</svg>
|
|
New Initiative
|
|
</ProfessionalButton>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<div class="initiatives-grid">
|
|
<div v-for="initiative in strategicInitiatives" :key="initiative.id" class="initiative-card">
|
|
<div class="initiative-header">
|
|
<span :class="['initiative-priority', `initiative-priority--${initiative.priority}`]">
|
|
{{ initiative.priority }} Priority
|
|
</span>
|
|
<span class="initiative-deadline">Due {{ initiative.deadline }}</span>
|
|
</div>
|
|
<h3 class="initiative-title">{{ initiative.title }}</h3>
|
|
<p class="initiative-description">{{ initiative.description }}</p>
|
|
<div class="initiative-progress">
|
|
<div class="progress-header">
|
|
<span class="progress-label">Progress</span>
|
|
<span class="progress-value">{{ initiative.progress }}%</span>
|
|
</div>
|
|
<div class="progress-bar">
|
|
<div class="progress-fill" :style="{ width: `${initiative.progress}%` }"></div>
|
|
</div>
|
|
</div>
|
|
<div class="initiative-team">
|
|
<img v-for="member in initiative.team.slice(0, 4)"
|
|
:key="member"
|
|
:src="`https://ui-avatars.com/api/?name=${member}&background=random`"
|
|
:alt="member"
|
|
class="team-avatar" />
|
|
<span v-if="initiative.team.length > 4" class="team-more">
|
|
+{{ initiative.team.length - 4 }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</NeumorphicCard>
|
|
</main>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, onMounted } from 'vue';
|
|
import Chart from 'chart.js/auto';
|
|
import NeumorphicCard from '../../components/core/NeumorphicCard.vue';
|
|
import ProfessionalButton from '../../components/core/ProfessionalButton.vue';
|
|
import StatCard from '../../components/core/StatCard.vue';
|
|
|
|
// Data
|
|
const sidebarCollapsed = ref(false);
|
|
const currentDate = ref(new Date().toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }));
|
|
|
|
const boardNavItems = [
|
|
{ name: 'Overview', path: '/board', icon: 'HomeIcon', active: true },
|
|
{ name: 'Financial Reports', path: '/board/financial', icon: 'ChartIcon' },
|
|
{ name: 'Governance', path: '/board/governance', icon: 'ShieldIcon' },
|
|
{ name: 'Committees', path: '/board/committees', icon: 'UsersIcon' },
|
|
{ name: 'Documents', path: '/board/documents', icon: 'DocumentIcon' },
|
|
{ name: 'Voting', path: '/board/voting', icon: 'VoteIcon' },
|
|
{ name: 'Calendar', path: '/board/calendar', icon: 'CalendarIcon' },
|
|
{ name: 'Communications', path: '/board/communications', icon: 'MailIcon' }
|
|
];
|
|
|
|
const executiveMetrics = [
|
|
{
|
|
label: 'Annual Revenue',
|
|
value: 8500000,
|
|
trend: 12.5,
|
|
prefix: '$',
|
|
variant: 'primary',
|
|
description: 'YoY Growth',
|
|
format: 'currency'
|
|
},
|
|
{
|
|
label: 'Net Profit Margin',
|
|
value: 18.3,
|
|
trend: 2.1,
|
|
suffix: '%',
|
|
variant: 'success',
|
|
description: 'Above industry average',
|
|
format: 'percentage'
|
|
},
|
|
{
|
|
label: 'Member Retention',
|
|
value: 94.2,
|
|
trend: 3.5,
|
|
suffix: '%',
|
|
variant: 'info',
|
|
description: 'Best in 5 years',
|
|
format: 'percentage'
|
|
},
|
|
{
|
|
label: 'Strategic Goals Met',
|
|
value: '14/16',
|
|
trend: 0,
|
|
variant: 'warning',
|
|
description: 'This quarter',
|
|
format: 'string'
|
|
}
|
|
];
|
|
|
|
const keyPerformanceIndicators = ref([
|
|
{ name: 'Revenue Growth', progress: 85, value: '8.5M', target: '10M', status: 'on-track' },
|
|
{ name: 'Cost Reduction', progress: 92, value: '920K', target: '1M', status: 'achieved' },
|
|
{ name: 'Member Acquisition', progress: 68, value: '340', target: '500', status: 'at-risk' },
|
|
{ name: 'Digital Transformation', progress: 75, value: '15', target: '20', status: 'on-track' },
|
|
{ name: 'ESG Score', progress: 88, value: '88', target: '100', status: 'on-track' }
|
|
]);
|
|
|
|
const upcomingMeetings = ref([
|
|
{
|
|
id: 1,
|
|
month: 'JAN',
|
|
day: '15',
|
|
title: 'Q1 Board Meeting',
|
|
time: '2:00 PM EST',
|
|
duration: '3 hours',
|
|
attendees: ['John D.', 'Sarah M.', 'Robert K.', 'Lisa T.', 'Michael B.']
|
|
},
|
|
{
|
|
id: 2,
|
|
month: 'FEB',
|
|
day: '10',
|
|
title: 'Strategic Planning Session',
|
|
time: '10:00 AM EST',
|
|
duration: 'Full day',
|
|
attendees: ['John D.', 'Sarah M.', 'Robert K.']
|
|
},
|
|
{
|
|
id: 3,
|
|
month: 'MAR',
|
|
day: '22',
|
|
title: 'Annual General Meeting',
|
|
time: '3:00 PM EST',
|
|
duration: '2 hours',
|
|
attendees: ['John D.', 'Sarah M.', 'Robert K.', 'Lisa T.']
|
|
}
|
|
]);
|
|
|
|
const recentResolutions = ref([
|
|
{
|
|
id: 1,
|
|
title: 'Technology Infrastructure Upgrade',
|
|
description: 'Approved $500K investment in cloud migration and cybersecurity enhancements.',
|
|
status: 'approved',
|
|
date: 'Dec 20, 2024',
|
|
votesFor: 7,
|
|
votesAgainst: 1,
|
|
abstain: 1
|
|
},
|
|
{
|
|
id: 2,
|
|
title: 'ESG Policy Framework',
|
|
description: 'Pending review of environmental, social, and governance policy implementation.',
|
|
status: 'pending',
|
|
date: 'Dec 28, 2024',
|
|
votesFor: 0,
|
|
votesAgainst: 0,
|
|
abstain: 0
|
|
},
|
|
{
|
|
id: 3,
|
|
title: 'Executive Compensation Review',
|
|
description: 'Approved revised compensation structure aligned with performance metrics.',
|
|
status: 'approved',
|
|
date: 'Dec 15, 2024',
|
|
votesFor: 8,
|
|
votesAgainst: 0,
|
|
abstain: 1
|
|
}
|
|
]);
|
|
|
|
const strategicInitiatives = ref([
|
|
{
|
|
id: 1,
|
|
title: 'Digital Member Experience',
|
|
description: 'Transform member journey through AI-powered personalization and seamless digital services.',
|
|
priority: 'high',
|
|
progress: 65,
|
|
deadline: 'Q2 2025',
|
|
team: ['Tech Team', 'UX Team', 'Data Team', 'Marketing', 'Operations']
|
|
},
|
|
{
|
|
id: 2,
|
|
title: 'International Expansion',
|
|
description: 'Establish presence in 3 new European markets with localized services and partnerships.',
|
|
priority: 'high',
|
|
progress: 40,
|
|
deadline: 'Q4 2025',
|
|
team: ['Business Dev', 'Legal', 'Marketing']
|
|
},
|
|
{
|
|
id: 3,
|
|
title: 'Sustainability Program',
|
|
description: 'Achieve carbon neutrality and implement comprehensive ESG reporting framework.',
|
|
priority: 'medium',
|
|
progress: 55,
|
|
deadline: 'Q3 2025',
|
|
team: ['Operations', 'Finance', 'Compliance', 'Facilities']
|
|
},
|
|
{
|
|
id: 4,
|
|
title: 'Partnership Network',
|
|
description: 'Build strategic alliances with 10+ industry leaders for enhanced member benefits.',
|
|
priority: 'medium',
|
|
progress: 30,
|
|
deadline: 'Q2 2025',
|
|
team: ['Business Dev', 'Legal']
|
|
}
|
|
]);
|
|
|
|
// Chart setup
|
|
const financialChart = ref(null);
|
|
|
|
onMounted(() => {
|
|
if (financialChart.value) {
|
|
new Chart(financialChart.value, {
|
|
type: 'line',
|
|
data: {
|
|
labels: ['Q1', 'Q2', 'Q3', 'Q4'],
|
|
datasets: [
|
|
{
|
|
label: 'Revenue',
|
|
data: [1800000, 2100000, 2300000, 2300000],
|
|
borderColor: '#DC2626',
|
|
backgroundColor: 'rgba(220, 38, 38, 0.1)',
|
|
tension: 0.4
|
|
},
|
|
{
|
|
label: 'Profit',
|
|
data: [320000, 380000, 410000, 420000],
|
|
borderColor: '#10B981',
|
|
backgroundColor: 'rgba(16, 185, 129, 0.1)',
|
|
tension: 0.4
|
|
},
|
|
{
|
|
label: 'Expenses',
|
|
data: [1480000, 1720000, 1890000, 1880000],
|
|
borderColor: '#3B82F6',
|
|
backgroundColor: 'rgba(59, 130, 246, 0.1)',
|
|
tension: 0.4
|
|
}
|
|
]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
plugins: {
|
|
legend: {
|
|
display: false
|
|
}
|
|
},
|
|
scales: {
|
|
y: {
|
|
beginAtZero: true,
|
|
ticks: {
|
|
callback: function(value) {
|
|
return '$' + (value / 1000000).toFixed(1) + 'M';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
@import '../../styles/neumorphic-system.scss';
|
|
|
|
.board-dashboard {
|
|
display: flex;
|
|
min-height: 100vh;
|
|
background: linear-gradient(135deg, $neutral-50 0%, $neutral-100 100%);
|
|
}
|
|
|
|
// Sidebar styles (same as admin dashboard)
|
|
.sidebar {
|
|
width: $sidebar-width;
|
|
background: linear-gradient(145deg, #ffffff, #f0f0f0);
|
|
box-shadow: $shadow-soft-lg;
|
|
display: flex;
|
|
flex-direction: column;
|
|
transition: width $transition-base $ease-in-out-soft;
|
|
position: relative;
|
|
z-index: 10;
|
|
|
|
&--collapsed {
|
|
width: $sidebar-width-collapsed;
|
|
}
|
|
|
|
&__header {
|
|
padding: $space-6;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
border-bottom: 1px solid rgba($neutral-300, 0.3);
|
|
}
|
|
|
|
&__logo {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: $space-3;
|
|
}
|
|
|
|
&__logo-img {
|
|
width: 40px;
|
|
height: 40px;
|
|
object-fit: contain;
|
|
}
|
|
|
|
&__logo-text {
|
|
font-family: $font-heading;
|
|
font-size: $text-lg;
|
|
font-weight: $font-bold;
|
|
color: $neutral-800;
|
|
}
|
|
|
|
&__toggle {
|
|
width: 32px;
|
|
height: 32px;
|
|
border: none;
|
|
background: $neutral-100;
|
|
border-radius: $radius-lg;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
cursor: pointer;
|
|
box-shadow: $shadow-soft-sm;
|
|
transition: all $transition-base;
|
|
|
|
svg {
|
|
width: 16px;
|
|
height: 16px;
|
|
color: $neutral-600;
|
|
}
|
|
|
|
&:hover {
|
|
box-shadow: $shadow-soft-md;
|
|
}
|
|
|
|
&:active {
|
|
box-shadow: $shadow-inset-sm;
|
|
}
|
|
}
|
|
|
|
&__nav {
|
|
flex: 1;
|
|
padding: $space-4;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
&__nav-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: $space-3;
|
|
padding: $space-3 $space-4;
|
|
margin-bottom: $space-2;
|
|
border-radius: $radius-lg;
|
|
color: $neutral-700;
|
|
text-decoration: none;
|
|
transition: all $transition-base;
|
|
|
|
&:hover {
|
|
background: rgba($primary-500, 0.05);
|
|
color: $primary-600;
|
|
}
|
|
|
|
&--active {
|
|
background: linear-gradient(145deg, rgba($primary-500, 0.1), rgba($primary-600, 0.15));
|
|
color: $primary-600;
|
|
box-shadow: $shadow-inset-sm;
|
|
}
|
|
}
|
|
|
|
&__nav-icon {
|
|
width: 20px;
|
|
height: 20px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
&__nav-label {
|
|
font-size: $text-sm;
|
|
font-weight: $font-medium;
|
|
}
|
|
|
|
&__footer {
|
|
padding: $space-4;
|
|
border-top: 1px solid rgba($neutral-300, 0.3);
|
|
}
|
|
|
|
&__profile {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: $space-3;
|
|
}
|
|
|
|
&__profile-avatar {
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: $radius-full;
|
|
overflow: hidden;
|
|
box-shadow: $shadow-soft-sm;
|
|
|
|
img {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: cover;
|
|
}
|
|
}
|
|
|
|
&__profile-info {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
&__profile-name {
|
|
font-size: $text-sm;
|
|
font-weight: $font-semibold;
|
|
color: $neutral-800;
|
|
}
|
|
|
|
&__profile-role {
|
|
font-size: $text-xs;
|
|
color: $neutral-600;
|
|
}
|
|
}
|
|
|
|
// Main content
|
|
.main-content {
|
|
flex: 1;
|
|
padding: $space-8;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
// Topbar
|
|
.topbar {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: $space-8;
|
|
|
|
&__left {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: $space-1;
|
|
}
|
|
|
|
&__title {
|
|
font-family: $font-heading;
|
|
font-size: $text-3xl;
|
|
font-weight: $font-bold;
|
|
color: $neutral-800;
|
|
}
|
|
|
|
&__subtitle {
|
|
font-size: $text-base;
|
|
color: $neutral-600;
|
|
}
|
|
|
|
&__right {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: $space-4;
|
|
}
|
|
|
|
&__notification {
|
|
position: relative;
|
|
width: 44px;
|
|
height: 44px;
|
|
border: none;
|
|
background: linear-gradient(145deg, #ffffff, #f0f0f0);
|
|
border-radius: $radius-lg;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
cursor: pointer;
|
|
box-shadow: $shadow-soft-sm;
|
|
transition: all $transition-base;
|
|
|
|
svg {
|
|
width: 20px;
|
|
height: 20px;
|
|
color: $neutral-600;
|
|
}
|
|
|
|
&:hover {
|
|
box-shadow: $shadow-soft-md;
|
|
}
|
|
}
|
|
|
|
&__notification-badge {
|
|
position: absolute;
|
|
top: 8px;
|
|
right: 8px;
|
|
width: 18px;
|
|
height: 18px;
|
|
background: $primary-500;
|
|
color: white;
|
|
border-radius: $radius-full;
|
|
font-size: $text-xs;
|
|
font-weight: $font-bold;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
&__date {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: $space-2;
|
|
padding: $space-2 $space-4;
|
|
background: linear-gradient(145deg, #ffffff, #f0f0f0);
|
|
border-radius: $radius-lg;
|
|
box-shadow: $shadow-soft-sm;
|
|
|
|
svg {
|
|
width: 16px;
|
|
height: 16px;
|
|
color: $neutral-500;
|
|
}
|
|
|
|
font-size: $text-sm;
|
|
color: $neutral-700;
|
|
}
|
|
}
|
|
|
|
// Executive Summary
|
|
.executive-summary {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
|
gap: $space-6;
|
|
margin-bottom: $space-8;
|
|
}
|
|
|
|
// Insights Grid
|
|
.insights-grid {
|
|
display: grid;
|
|
grid-template-columns: 2fr 1fr;
|
|
gap: $space-6;
|
|
margin-bottom: $space-8;
|
|
|
|
@media (max-width: $breakpoint-lg) {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
}
|
|
|
|
// Board Grid
|
|
.board-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
|
|
gap: $space-6;
|
|
margin-bottom: $space-8;
|
|
|
|
@media (max-width: $breakpoint-md) {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
}
|
|
|
|
// Card styles
|
|
.card-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.card-title {
|
|
font-family: $font-heading;
|
|
font-size: $text-xl;
|
|
font-weight: $font-semibold;
|
|
color: $neutral-800;
|
|
}
|
|
|
|
.card-actions {
|
|
display: flex;
|
|
gap: $space-2;
|
|
}
|
|
|
|
// Financial Chart
|
|
.financial-chart {
|
|
.chart-container {
|
|
height: 300px;
|
|
padding: $space-4 0;
|
|
}
|
|
|
|
.chart-legend {
|
|
display: flex;
|
|
justify-content: center;
|
|
gap: $space-6;
|
|
|
|
.legend-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: $space-2;
|
|
font-size: $text-sm;
|
|
color: $neutral-600;
|
|
}
|
|
|
|
.legend-dot {
|
|
width: 12px;
|
|
height: 12px;
|
|
border-radius: $radius-full;
|
|
}
|
|
}
|
|
}
|
|
|
|
.period-selector {
|
|
padding: $space-2 $space-3;
|
|
background: $neutral-50;
|
|
border: none;
|
|
border-radius: $radius-md;
|
|
box-shadow: $shadow-inset-sm;
|
|
font-size: $text-sm;
|
|
color: $neutral-700;
|
|
cursor: pointer;
|
|
}
|
|
|
|
// KPI Card
|
|
.kpi-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: $space-4;
|
|
}
|
|
|
|
.kpi-item {
|
|
padding: $space-3;
|
|
background: rgba($neutral-100, 0.5);
|
|
border-radius: $radius-lg;
|
|
}
|
|
|
|
.kpi-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: $space-2;
|
|
}
|
|
|
|
.kpi-name {
|
|
font-size: $text-sm;
|
|
font-weight: $font-medium;
|
|
color: $neutral-700;
|
|
}
|
|
|
|
.kpi-status {
|
|
font-size: $text-xs;
|
|
font-weight: $font-semibold;
|
|
text-transform: uppercase;
|
|
padding: $space-1 $space-2;
|
|
border-radius: $radius-full;
|
|
|
|
&--achieved {
|
|
background: rgba($success-500, 0.1);
|
|
color: $success-500;
|
|
}
|
|
|
|
&--on-track {
|
|
background: rgba($info-500, 0.1);
|
|
color: $info-500;
|
|
}
|
|
|
|
&--at-risk {
|
|
background: rgba($warning-500, 0.1);
|
|
color: $warning-500;
|
|
}
|
|
}
|
|
|
|
.kpi-progress {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: $space-2;
|
|
}
|
|
|
|
.kpi-progress-bar {
|
|
height: 6px;
|
|
background: rgba($neutral-300, 0.3);
|
|
border-radius: $radius-full;
|
|
overflow: hidden;
|
|
box-shadow: $shadow-inset-sm;
|
|
}
|
|
|
|
.kpi-progress-fill {
|
|
height: 100%;
|
|
border-radius: $radius-full;
|
|
transition: width $transition-slow;
|
|
|
|
&--achieved {
|
|
background: linear-gradient(90deg, $success-500, #059669);
|
|
}
|
|
|
|
&--on-track {
|
|
background: linear-gradient(90deg, $info-500, #2563EB);
|
|
}
|
|
|
|
&--at-risk {
|
|
background: linear-gradient(90deg, $warning-500, #D97706);
|
|
}
|
|
}
|
|
|
|
.kpi-value {
|
|
font-size: $text-xs;
|
|
color: $neutral-600;
|
|
text-align: right;
|
|
}
|
|
|
|
// Meetings Card
|
|
.meetings-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: $space-4;
|
|
}
|
|
|
|
.meeting-item {
|
|
display: flex;
|
|
gap: $space-4;
|
|
padding: $space-4;
|
|
background: rgba($neutral-100, 0.5);
|
|
border-radius: $radius-lg;
|
|
transition: all $transition-base;
|
|
|
|
&:hover {
|
|
background: rgba($neutral-100, 0.8);
|
|
box-shadow: $shadow-soft-sm;
|
|
}
|
|
}
|
|
|
|
.meeting-date {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 60px;
|
|
height: 60px;
|
|
background: linear-gradient(135deg, $primary-500, $primary-600);
|
|
border-radius: $radius-lg;
|
|
color: white;
|
|
flex-shrink: 0;
|
|
|
|
.meeting-month {
|
|
font-size: $text-xs;
|
|
text-transform: uppercase;
|
|
opacity: 0.9;
|
|
}
|
|
|
|
.meeting-day {
|
|
font-size: $text-xl;
|
|
font-weight: $font-bold;
|
|
}
|
|
}
|
|
|
|
.meeting-details {
|
|
flex: 1;
|
|
|
|
.meeting-title {
|
|
font-size: $text-base;
|
|
font-weight: $font-semibold;
|
|
color: $neutral-800;
|
|
margin-bottom: $space-1;
|
|
}
|
|
|
|
.meeting-info {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: $space-2;
|
|
font-size: $text-sm;
|
|
color: $neutral-600;
|
|
margin-bottom: $space-2;
|
|
|
|
svg {
|
|
width: 14px;
|
|
height: 14px;
|
|
}
|
|
}
|
|
|
|
.meeting-attendees {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: -$space-2;
|
|
|
|
.attendee-avatar {
|
|
width: 24px;
|
|
height: 24px;
|
|
border-radius: $radius-full;
|
|
border: 2px solid white;
|
|
margin-right: -8px;
|
|
}
|
|
|
|
.attendee-more {
|
|
margin-left: $space-2;
|
|
font-size: $text-xs;
|
|
color: $neutral-600;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Resolutions Card
|
|
.resolutions-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: $space-3;
|
|
}
|
|
|
|
.resolution-item {
|
|
display: flex;
|
|
gap: $space-3;
|
|
padding: $space-3;
|
|
background: rgba($neutral-100, 0.5);
|
|
border-radius: $radius-lg;
|
|
}
|
|
|
|
.resolution-status {
|
|
width: 32px;
|
|
height: 32px;
|
|
border-radius: $radius-lg;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
flex-shrink: 0;
|
|
|
|
svg {
|
|
width: 16px;
|
|
height: 16px;
|
|
}
|
|
|
|
&--approved {
|
|
background: rgba($success-500, 0.1);
|
|
color: $success-500;
|
|
}
|
|
|
|
&--pending {
|
|
background: rgba($warning-500, 0.1);
|
|
color: $warning-500;
|
|
}
|
|
|
|
&--rejected {
|
|
background: rgba($error-500, 0.1);
|
|
color: $error-500;
|
|
}
|
|
}
|
|
|
|
.resolution-content {
|
|
flex: 1;
|
|
|
|
.resolution-title {
|
|
font-size: $text-sm;
|
|
font-weight: $font-semibold;
|
|
color: $neutral-800;
|
|
margin-bottom: $space-1;
|
|
}
|
|
|
|
.resolution-description {
|
|
font-size: $text-sm;
|
|
color: $neutral-600;
|
|
line-height: $leading-normal;
|
|
margin-bottom: $space-2;
|
|
}
|
|
|
|
.resolution-meta {
|
|
display: flex;
|
|
gap: $space-3;
|
|
font-size: $text-xs;
|
|
color: $neutral-500;
|
|
|
|
.resolution-votes {
|
|
font-weight: $font-medium;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Strategic Initiatives
|
|
.initiatives-card {
|
|
margin-bottom: $space-8;
|
|
}
|
|
|
|
.initiatives-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
|
gap: $space-4;
|
|
}
|
|
|
|
.initiative-card {
|
|
padding: $space-4;
|
|
background: rgba($neutral-100, 0.5);
|
|
border-radius: $radius-lg;
|
|
transition: all $transition-base;
|
|
|
|
&:hover {
|
|
background: rgba($neutral-100, 0.8);
|
|
box-shadow: $shadow-soft-sm;
|
|
transform: translateY(-2px);
|
|
}
|
|
}
|
|
|
|
.initiative-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: $space-3;
|
|
}
|
|
|
|
.initiative-priority {
|
|
font-size: $text-xs;
|
|
font-weight: $font-semibold;
|
|
text-transform: uppercase;
|
|
padding: $space-1 $space-2;
|
|
border-radius: $radius-full;
|
|
|
|
&--high {
|
|
background: rgba($error-500, 0.1);
|
|
color: $error-500;
|
|
}
|
|
|
|
&--medium {
|
|
background: rgba($warning-500, 0.1);
|
|
color: $warning-500;
|
|
}
|
|
|
|
&--low {
|
|
background: rgba($info-500, 0.1);
|
|
color: $info-500;
|
|
}
|
|
}
|
|
|
|
.initiative-deadline {
|
|
font-size: $text-xs;
|
|
color: $neutral-600;
|
|
}
|
|
|
|
.initiative-title {
|
|
font-size: $text-base;
|
|
font-weight: $font-semibold;
|
|
color: $neutral-800;
|
|
margin-bottom: $space-2;
|
|
}
|
|
|
|
.initiative-description {
|
|
font-size: $text-sm;
|
|
color: $neutral-600;
|
|
line-height: $leading-normal;
|
|
margin-bottom: $space-3;
|
|
}
|
|
|
|
.initiative-progress {
|
|
margin-bottom: $space-3;
|
|
|
|
.progress-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: $space-1;
|
|
}
|
|
|
|
.progress-label,
|
|
.progress-value {
|
|
font-size: $text-xs;
|
|
color: $neutral-600;
|
|
}
|
|
|
|
.progress-value {
|
|
font-weight: $font-semibold;
|
|
}
|
|
|
|
.progress-bar {
|
|
height: 6px;
|
|
background: rgba($neutral-300, 0.3);
|
|
border-radius: $radius-full;
|
|
overflow: hidden;
|
|
box-shadow: $shadow-inset-sm;
|
|
}
|
|
|
|
.progress-fill {
|
|
height: 100%;
|
|
background: linear-gradient(90deg, $primary-500, $primary-600);
|
|
border-radius: $radius-full;
|
|
transition: width $transition-slow;
|
|
}
|
|
}
|
|
|
|
.initiative-team {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: -$space-2;
|
|
|
|
.team-avatar {
|
|
width: 28px;
|
|
height: 28px;
|
|
border-radius: $radius-full;
|
|
border: 2px solid white;
|
|
margin-right: -8px;
|
|
}
|
|
|
|
.team-more {
|
|
margin-left: $space-3;
|
|
font-size: $text-xs;
|
|
font-weight: $font-medium;
|
|
color: $neutral-600;
|
|
background: rgba($neutral-200, 0.5);
|
|
padding: $space-1 $space-2;
|
|
border-radius: $radius-full;
|
|
}
|
|
}
|
|
|
|
// Dark mode support
|
|
@include dark-mode {
|
|
.board-dashboard {
|
|
background: linear-gradient(135deg, $neutral-900 0%, $neutral-800 100%);
|
|
}
|
|
|
|
// Update other dark mode styles as needed
|
|
}
|
|
</style> |