This commit is contained in:
721
pages/admin/dashboard-v2.vue
Normal file
721
pages/admin/dashboard-v2.vue
Normal file
@@ -0,0 +1,721 @@
|
||||
<template>
|
||||
<div class="admin-dashboard-v2">
|
||||
<!-- Neumorphic Header -->
|
||||
<div class="dashboard-header">
|
||||
<h1 class="dashboard-title">System Administration</h1>
|
||||
<p class="dashboard-subtitle">Complete platform control and management</p>
|
||||
</div>
|
||||
|
||||
<!-- Stats Grid with Neumorphic Cards -->
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card neumorphic-card" v-for="stat in stats" :key="stat.id">
|
||||
<div class="stat-content">
|
||||
<div class="stat-info">
|
||||
<div class="stat-label">{{ stat.label }}</div>
|
||||
<div class="stat-value">{{ stat.value }}</div>
|
||||
<div class="stat-change" :class="stat.changeType">
|
||||
<Icon :name="stat.changeIcon" class="change-icon" />
|
||||
<span>{{ stat.changeText }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-icon-wrapper neumorphic-inset">
|
||||
<Icon :name="stat.icon" class="stat-icon" :style="{ color: stat.color }" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Management Sections -->
|
||||
<div class="management-grid">
|
||||
<!-- User Management -->
|
||||
<div class="management-card neumorphic-card">
|
||||
<div class="card-header">
|
||||
<Icon name="mdi:account-group" class="header-icon" />
|
||||
<h2>User Management</h2>
|
||||
</div>
|
||||
<p class="card-description">Manage user accounts, roles, and permissions</p>
|
||||
|
||||
<!-- Morphing Dropdown for User Filters -->
|
||||
<div class="morphing-select-wrapper">
|
||||
<div class="select-trigger neumorphic-button" @click="toggleUserFilter">
|
||||
<span>{{ selectedUserFilter }}</span>
|
||||
<Icon name="mdi:chevron-down" class="dropdown-icon" :class="{ 'rotate': showUserFilter }" />
|
||||
</div>
|
||||
<Transition name="morph">
|
||||
<div v-if="showUserFilter" class="morphing-dropdown">
|
||||
<div
|
||||
v-for="option in userFilterOptions"
|
||||
:key="option"
|
||||
class="dropdown-option"
|
||||
@click="selectUserFilter(option)"
|
||||
>
|
||||
{{ option }}
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
|
||||
<div class="action-buttons">
|
||||
<button class="neumorphic-button primary" @click="showCreateUserDialog = true">
|
||||
<Icon name="mdi:account-plus" />
|
||||
Create User
|
||||
</button>
|
||||
<button class="neumorphic-button" @click="manageRoles">
|
||||
<Icon name="mdi:shield-account" />
|
||||
Manage Roles
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- System Maintenance -->
|
||||
<div class="management-card neumorphic-card">
|
||||
<div class="card-header">
|
||||
<Icon name="mdi:cog" class="header-icon" />
|
||||
<h2>System Maintenance</h2>
|
||||
</div>
|
||||
<p class="card-description">Backend operations and system health</p>
|
||||
|
||||
<!-- System Status Indicator -->
|
||||
<div class="system-status neumorphic-inset">
|
||||
<div class="status-indicator" :class="systemStatus.type"></div>
|
||||
<span>{{ systemStatus.text }}</span>
|
||||
</div>
|
||||
|
||||
<div class="action-buttons">
|
||||
<button class="neumorphic-button" @click="assignMemberIds">
|
||||
Assign Member IDs
|
||||
</button>
|
||||
<button class="neumorphic-button" @click="backfillEventIds">
|
||||
Backfill Event IDs
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Reports & Analytics -->
|
||||
<div class="management-card neumorphic-card">
|
||||
<div class="card-header">
|
||||
<Icon name="mdi:chart-line" class="header-icon" />
|
||||
<h2>Reports & Analytics</h2>
|
||||
</div>
|
||||
<p class="card-description">Generate insights and track metrics</p>
|
||||
|
||||
<!-- Report Type Dropdown -->
|
||||
<div class="morphing-select-wrapper">
|
||||
<div class="select-trigger neumorphic-button" @click="toggleReportType">
|
||||
<span>{{ selectedReportType }}</span>
|
||||
<Icon name="mdi:chevron-down" class="dropdown-icon" :class="{ 'rotate': showReportType }" />
|
||||
</div>
|
||||
<Transition name="morph">
|
||||
<div v-if="showReportType" class="morphing-dropdown">
|
||||
<div
|
||||
v-for="type in reportTypes"
|
||||
:key="type"
|
||||
class="dropdown-option"
|
||||
@click="selectReportType(type)"
|
||||
>
|
||||
{{ type }}
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
|
||||
<button class="neumorphic-button primary full-width" @click="generateReport">
|
||||
<Icon name="mdi:file-chart" />
|
||||
Generate Report
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Configuration -->
|
||||
<div class="management-card neumorphic-card">
|
||||
<div class="card-header">
|
||||
<Icon name="mdi:tune" class="header-icon" />
|
||||
<h2>Configuration</h2>
|
||||
</div>
|
||||
<p class="card-description">Portal settings and integrations</p>
|
||||
|
||||
<div class="config-grid">
|
||||
<button class="config-button neumorphic-button" @click="showMembershipConfig = true">
|
||||
<Icon name="mdi:card-account-details" />
|
||||
<span>Membership</span>
|
||||
</button>
|
||||
<button class="config-button neumorphic-button" @click="showRecaptchaConfig = true">
|
||||
<Icon name="mdi:robot" />
|
||||
<span>reCAPTCHA</span>
|
||||
</button>
|
||||
<button class="config-button neumorphic-button" @click="openEmailConfig">
|
||||
<Icon name="mdi:email" />
|
||||
<span>Email</span>
|
||||
</button>
|
||||
<button class="config-button neumorphic-button" @click="showNocoDBSettings = true">
|
||||
<Icon name="mdi:database" />
|
||||
<span>Database</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Activity Feed -->
|
||||
<div class="activity-section neumorphic-card">
|
||||
<div class="card-header">
|
||||
<Icon name="mdi:timeline" class="header-icon" />
|
||||
<h2>Recent Activity</h2>
|
||||
<button class="neumorphic-button small" @click="refreshActivity">
|
||||
<Icon name="mdi:refresh" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="activity-list">
|
||||
<div v-for="activity in recentActivity" :key="activity.id" class="activity-item neumorphic-inset">
|
||||
<Icon :name="activity.icon" class="activity-icon" :style="{ color: activity.color }" />
|
||||
<div class="activity-content">
|
||||
<p class="activity-text">{{ activity.text }}</p>
|
||||
<span class="activity-time">{{ activity.time }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
|
||||
// Define page meta
|
||||
definePageMeta({
|
||||
layout: 'admin',
|
||||
middleware: 'auth'
|
||||
})
|
||||
|
||||
// Stats data
|
||||
const stats = ref([
|
||||
{
|
||||
id: 1,
|
||||
label: 'Total Members',
|
||||
value: '1,247',
|
||||
changeType: 'positive',
|
||||
changeIcon: 'mdi:trending-up',
|
||||
changeText: '+12% this month',
|
||||
icon: 'mdi:account-group',
|
||||
color: '#CC0000'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
label: 'Active Sessions',
|
||||
value: '342',
|
||||
changeType: 'neutral',
|
||||
changeIcon: 'mdi:circle',
|
||||
changeText: 'Live now',
|
||||
icon: 'mdi:monitor-dashboard',
|
||||
color: '#10B981'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
label: 'Revenue MTD',
|
||||
value: '$48,392',
|
||||
changeType: 'positive',
|
||||
changeIcon: 'mdi:trending-up',
|
||||
changeText: '+8% vs last month',
|
||||
icon: 'mdi:currency-usd',
|
||||
color: '#3B82F6'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
label: 'System Health',
|
||||
value: '98.5%',
|
||||
changeType: 'positive',
|
||||
changeIcon: 'mdi:check-circle',
|
||||
changeText: 'All systems operational',
|
||||
icon: 'mdi:shield-check',
|
||||
color: '#10B981'
|
||||
}
|
||||
])
|
||||
|
||||
// Dropdown states
|
||||
const showUserFilter = ref(false)
|
||||
const selectedUserFilter = ref('All Users')
|
||||
const userFilterOptions = ref(['All Users', 'Active Users', 'Inactive Users', 'Admins', 'Members'])
|
||||
|
||||
const showReportType = ref(false)
|
||||
const selectedReportType = ref('Financial Report')
|
||||
const reportTypes = ref(['Financial Report', 'Member Report', 'Activity Report', 'Usage Report'])
|
||||
|
||||
// System status
|
||||
const systemStatus = ref({
|
||||
type: 'healthy',
|
||||
text: 'All systems operational'
|
||||
})
|
||||
|
||||
// Recent activity
|
||||
const recentActivity = ref([
|
||||
{
|
||||
id: 1,
|
||||
icon: 'mdi:account-plus',
|
||||
text: 'New member registration: John Doe',
|
||||
time: '2 minutes ago',
|
||||
color: '#10B981'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
icon: 'mdi:credit-card',
|
||||
text: 'Payment received from Jane Smith',
|
||||
time: '15 minutes ago',
|
||||
color: '#3B82F6'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
icon: 'mdi:calendar-check',
|
||||
text: 'Event created: Annual Gala 2024',
|
||||
time: '1 hour ago',
|
||||
color: '#F59E0B'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
icon: 'mdi:account-edit',
|
||||
text: 'Profile updated: Mike Johnson',
|
||||
time: '3 hours ago',
|
||||
color: '#6B7280'
|
||||
}
|
||||
])
|
||||
|
||||
// Dialog states
|
||||
const showCreateUserDialog = ref(false)
|
||||
const showMembershipConfig = ref(false)
|
||||
const showRecaptchaConfig = ref(false)
|
||||
const showNocoDBSettings = ref(false)
|
||||
|
||||
// Methods
|
||||
const toggleUserFilter = () => {
|
||||
showUserFilter.value = !showUserFilter.value
|
||||
showReportType.value = false
|
||||
}
|
||||
|
||||
const selectUserFilter = (option) => {
|
||||
selectedUserFilter.value = option
|
||||
showUserFilter.value = false
|
||||
}
|
||||
|
||||
const toggleReportType = () => {
|
||||
showReportType.value = !showReportType.value
|
||||
showUserFilter.value = false
|
||||
}
|
||||
|
||||
const selectReportType = (type) => {
|
||||
selectedReportType.value = type
|
||||
showReportType.value = false
|
||||
}
|
||||
|
||||
const manageRoles = () => {
|
||||
console.log('Managing roles...')
|
||||
}
|
||||
|
||||
const assignMemberIds = () => {
|
||||
console.log('Assigning member IDs...')
|
||||
}
|
||||
|
||||
const backfillEventIds = () => {
|
||||
console.log('Backfilling event IDs...')
|
||||
}
|
||||
|
||||
const generateReport = () => {
|
||||
console.log('Generating report:', selectedReportType.value)
|
||||
}
|
||||
|
||||
const openEmailConfig = () => {
|
||||
console.log('Opening email configuration...')
|
||||
}
|
||||
|
||||
const refreshActivity = () => {
|
||||
console.log('Refreshing activity...')
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// Close dropdowns when clicking outside
|
||||
document.addEventListener('click', (e) => {
|
||||
if (!e.target.closest('.morphing-select-wrapper')) {
|
||||
showUserFilter.value = false
|
||||
showReportType.value = false
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/design-mockups/styles/design-system.scss';
|
||||
|
||||
.admin-dashboard-v2 {
|
||||
padding: 2rem;
|
||||
background: linear-gradient(135deg, $neutral-50 0%, $neutral-100 100%);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
// Header
|
||||
.dashboard-header {
|
||||
text-align: center;
|
||||
margin-bottom: 3rem;
|
||||
|
||||
.dashboard-title {
|
||||
font-size: $text-4xl;
|
||||
font-weight: $font-bold;
|
||||
color: $neutral-800;
|
||||
margin-bottom: 0.5rem;
|
||||
background: linear-gradient(135deg, $primary-600, $primary-800);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
|
||||
.dashboard-subtitle {
|
||||
color: $neutral-600;
|
||||
font-size: $text-lg;
|
||||
}
|
||||
}
|
||||
|
||||
// Stats Grid
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: 1.5rem;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
@include neumorphic-card('md');
|
||||
padding: 1.5rem;
|
||||
transition: all $transition-base;
|
||||
|
||||
&:hover {
|
||||
@include neumorphic-card('lg');
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.stat-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.stat-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
color: $neutral-600;
|
||||
font-size: $text-sm;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: $text-3xl;
|
||||
font-weight: $font-bold;
|
||||
color: $neutral-800;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.stat-change {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
font-size: $text-sm;
|
||||
|
||||
&.positive {
|
||||
color: $success-500;
|
||||
}
|
||||
|
||||
&.neutral {
|
||||
color: $neutral-600;
|
||||
}
|
||||
|
||||
.change-icon {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.stat-icon-wrapper {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: $radius-xl;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: $shadow-inset-sm;
|
||||
|
||||
.stat-icon {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Management Grid
|
||||
.management-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
|
||||
gap: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.management-card {
|
||||
@include neumorphic-card('md');
|
||||
padding: 2rem;
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
.header-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
color: $primary-600;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: $text-xl;
|
||||
font-weight: $font-semibold;
|
||||
color: $neutral-800;
|
||||
}
|
||||
}
|
||||
|
||||
.card-description {
|
||||
color: $neutral-600;
|
||||
margin-bottom: 1.5rem;
|
||||
font-size: $text-sm;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.config-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.config-button {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 1rem;
|
||||
font-size: $text-sm;
|
||||
|
||||
svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Morphing Dropdown
|
||||
.morphing-select-wrapper {
|
||||
position: relative;
|
||||
margin-bottom: 1.5rem;
|
||||
|
||||
.select-trigger {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.75rem 1rem;
|
||||
cursor: pointer;
|
||||
|
||||
.dropdown-icon {
|
||||
transition: transform 0.3s $spring-smooth;
|
||||
|
||||
&.rotate {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.morphing-dropdown {
|
||||
@include morphing-dropdown();
|
||||
position: absolute;
|
||||
top: calc(100% + 8px);
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: $z-dropdown;
|
||||
|
||||
.dropdown-option {
|
||||
padding: 0.75rem 1rem;
|
||||
cursor: pointer;
|
||||
transition: all $transition-fast;
|
||||
color: $neutral-700;
|
||||
|
||||
&:hover {
|
||||
background: rgba($blue-500, 0.1);
|
||||
color: $blue-600;
|
||||
padding-left: 1.25rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Neumorphic Elements
|
||||
.neumorphic-card {
|
||||
background: linear-gradient(145deg, #ffffff, #f0f0f0);
|
||||
border-radius: $radius-xl;
|
||||
box-shadow: $shadow-soft-md;
|
||||
}
|
||||
|
||||
.neumorphic-button {
|
||||
@include neumorphic-button();
|
||||
padding: 0.75rem 1.5rem;
|
||||
border: none;
|
||||
border-radius: $radius-lg;
|
||||
font-weight: $font-medium;
|
||||
color: $neutral-700;
|
||||
cursor: pointer;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
|
||||
&.primary {
|
||||
background: linear-gradient(145deg, $primary-600, $primary-700);
|
||||
color: white;
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(145deg, $primary-700, $primary-800);
|
||||
}
|
||||
}
|
||||
|
||||
&.small {
|
||||
padding: 0.5rem 0.75rem;
|
||||
font-size: $text-sm;
|
||||
}
|
||||
|
||||
&.full-width {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.neumorphic-inset {
|
||||
box-shadow: $shadow-inset-sm;
|
||||
background: linear-gradient(145deg, #e6e6e6, #ffffff);
|
||||
}
|
||||
|
||||
// System Status
|
||||
.system-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 1rem;
|
||||
border-radius: $radius-lg;
|
||||
margin-bottom: 1.5rem;
|
||||
|
||||
.status-indicator {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
animation: pulse 2s infinite;
|
||||
|
||||
&.healthy {
|
||||
background-color: $success-500;
|
||||
}
|
||||
|
||||
&.warning {
|
||||
background-color: $warning-500;
|
||||
}
|
||||
|
||||
&.error {
|
||||
background-color: $error-500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Activity Section
|
||||
.activity-section {
|
||||
@include neumorphic-card('lg');
|
||||
padding: 2rem;
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1.5rem;
|
||||
|
||||
h2 {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.activity-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.activity-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 1rem;
|
||||
border-radius: $radius-lg;
|
||||
|
||||
.activity-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.activity-content {
|
||||
flex: 1;
|
||||
|
||||
.activity-text {
|
||||
color: $neutral-800;
|
||||
font-size: $text-sm;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.activity-time {
|
||||
color: $neutral-500;
|
||||
font-size: $text-xs;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Transitions
|
||||
.morph-enter-active,
|
||||
.morph-leave-active {
|
||||
transition: all 0.3s $spring-smooth;
|
||||
}
|
||||
|
||||
.morph-enter-from {
|
||||
opacity: 0;
|
||||
transform: scale(0.95) translateY(-10px);
|
||||
}
|
||||
|
||||
.morph-leave-to {
|
||||
opacity: 0;
|
||||
transform: scale(0.95) translateY(-10px);
|
||||
}
|
||||
|
||||
// Responsive
|
||||
@include responsive($breakpoint-md) {
|
||||
.admin-dashboard-v2 {
|
||||
padding: 3rem;
|
||||
}
|
||||
}
|
||||
|
||||
@include responsive($breakpoint-lg) {
|
||||
.stats-grid {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
|
||||
.management-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
886
pages/board/dashboard-v2.vue
Normal file
886
pages/board/dashboard-v2.vue
Normal file
@@ -0,0 +1,886 @@
|
||||
<template>
|
||||
<div class="board-dashboard-v2">
|
||||
<!-- Executive Header -->
|
||||
<div class="executive-header">
|
||||
<h1 class="dashboard-title">Executive Dashboard</h1>
|
||||
<p class="dashboard-subtitle">Strategic insights and governance overview</p>
|
||||
</div>
|
||||
|
||||
<!-- KPI Cards with Neumorphic Design -->
|
||||
<div class="kpi-grid">
|
||||
<div class="kpi-card neumorphic-card" v-for="kpi in kpis" :key="kpi.id">
|
||||
<div class="kpi-header">
|
||||
<div class="kpi-icon-wrapper neumorphic-inset">
|
||||
<Icon :name="kpi.icon" class="kpi-icon" :style="{ color: kpi.color }" />
|
||||
</div>
|
||||
<div class="kpi-trend" :class="kpi.trendType">
|
||||
<Icon :name="kpi.trendIcon" class="trend-icon" />
|
||||
<span>{{ kpi.trendValue }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="kpi-content">
|
||||
<div class="kpi-value">{{ kpi.value }}</div>
|
||||
<div class="kpi-label">{{ kpi.label }}</div>
|
||||
<div class="kpi-progress">
|
||||
<div class="progress-bar neumorphic-inset">
|
||||
<div class="progress-fill" :style="{ width: kpi.progress + '%', background: kpi.color }"></div>
|
||||
</div>
|
||||
<span class="progress-text">{{ kpi.progress }}% of target</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Strategic Initiatives & Governance -->
|
||||
<div class="governance-grid">
|
||||
<!-- Strategic Initiatives -->
|
||||
<div class="initiative-card neumorphic-card">
|
||||
<div class="card-header">
|
||||
<Icon name="mdi:target" class="header-icon" />
|
||||
<h2>Strategic Initiatives</h2>
|
||||
<div class="morphing-select-wrapper">
|
||||
<button class="select-trigger neumorphic-button small" @click="toggleQuarter">
|
||||
<span>{{ selectedQuarter }}</span>
|
||||
<Icon name="mdi:chevron-down" class="dropdown-icon" :class="{ 'rotate': showQuarter }" />
|
||||
</button>
|
||||
<Transition name="morph">
|
||||
<div v-if="showQuarter" class="morphing-dropdown">
|
||||
<div
|
||||
v-for="quarter in quarters"
|
||||
:key="quarter"
|
||||
class="dropdown-option"
|
||||
@click="selectQuarter(quarter)"
|
||||
>
|
||||
{{ quarter }}
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="initiatives-list">
|
||||
<div v-for="initiative in strategicInitiatives" :key="initiative.id" class="initiative-item">
|
||||
<div class="initiative-header">
|
||||
<span class="initiative-name">{{ initiative.name }}</span>
|
||||
<span class="initiative-status" :class="initiative.status">{{ initiative.statusText }}</span>
|
||||
</div>
|
||||
<div class="initiative-progress neumorphic-inset">
|
||||
<div class="progress-bar-slim">
|
||||
<div class="progress-fill-slim" :style="{ width: initiative.progress + '%' }"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="initiative-meta">
|
||||
<span class="initiative-owner">Owner: {{ initiative.owner }}</span>
|
||||
<span class="initiative-deadline">Due: {{ initiative.deadline }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Committee Overview -->
|
||||
<div class="committee-card neumorphic-card">
|
||||
<div class="card-header">
|
||||
<Icon name="mdi:account-group-outline" class="header-icon" />
|
||||
<h2>Committee Activities</h2>
|
||||
</div>
|
||||
|
||||
<div class="committee-grid">
|
||||
<div v-for="committee in committees" :key="committee.id" class="committee-item neumorphic-inset">
|
||||
<div class="committee-header">
|
||||
<Icon :name="committee.icon" class="committee-icon" :style="{ color: committee.color }" />
|
||||
<h3>{{ committee.name }}</h3>
|
||||
</div>
|
||||
<div class="committee-stats">
|
||||
<div class="stat">
|
||||
<span class="stat-value">{{ committee.members }}</span>
|
||||
<span class="stat-label">Members</span>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<span class="stat-value">{{ committee.meetings }}</span>
|
||||
<span class="stat-label">Meetings</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="neumorphic-button small full-width">View Details</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Financial Overview -->
|
||||
<div class="financial-section neumorphic-card">
|
||||
<div class="card-header">
|
||||
<Icon name="mdi:finance" class="header-icon" />
|
||||
<h2>Financial Overview</h2>
|
||||
<div class="time-selector">
|
||||
<button
|
||||
v-for="period in timePeriods"
|
||||
:key="period"
|
||||
class="time-button neumorphic-button small"
|
||||
:class="{ 'active': selectedPeriod === period }"
|
||||
@click="selectedPeriod = period"
|
||||
>
|
||||
{{ period }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="financial-grid">
|
||||
<div class="revenue-chart">
|
||||
<h3>Revenue Trend</h3>
|
||||
<div class="chart-placeholder neumorphic-inset">
|
||||
<Icon name="mdi:chart-line" class="chart-icon" />
|
||||
<span>Revenue chart visualization</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="financial-metrics">
|
||||
<div v-for="metric in financialMetrics" :key="metric.id" class="metric-item">
|
||||
<div class="metric-label">{{ metric.label }}</div>
|
||||
<div class="metric-value" :class="metric.type">{{ metric.value }}</div>
|
||||
<div class="metric-change">
|
||||
<Icon :name="metric.changeIcon" class="change-icon" />
|
||||
<span>{{ metric.change }} from last period</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Governance Actions -->
|
||||
<div class="governance-actions">
|
||||
<div class="action-card neumorphic-card">
|
||||
<Icon name="mdi:calendar-check" class="action-icon" />
|
||||
<h3>Board Meetings</h3>
|
||||
<p>Schedule and manage board meetings</p>
|
||||
<button class="neumorphic-button primary">Schedule Meeting</button>
|
||||
</div>
|
||||
|
||||
<div class="action-card neumorphic-card">
|
||||
<Icon name="mdi:file-document-outline" class="action-icon" />
|
||||
<h3>Documents</h3>
|
||||
<p>Access governance documents</p>
|
||||
<button class="neumorphic-button primary">View Documents</button>
|
||||
</div>
|
||||
|
||||
<div class="action-card neumorphic-card">
|
||||
<Icon name="mdi:vote" class="action-icon" />
|
||||
<h3>Resolutions</h3>
|
||||
<p>Review and vote on resolutions</p>
|
||||
<button class="neumorphic-button primary">View Resolutions</button>
|
||||
</div>
|
||||
|
||||
<div class="action-card neumorphic-card">
|
||||
<Icon name="mdi:chart-box-outline" class="action-icon" />
|
||||
<h3>Reports</h3>
|
||||
<p>Generate executive reports</p>
|
||||
<button class="neumorphic-button primary">Generate Report</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
|
||||
// Define page meta
|
||||
definePageMeta({
|
||||
layout: 'board',
|
||||
middleware: 'auth'
|
||||
})
|
||||
|
||||
// KPIs
|
||||
const kpis = ref([
|
||||
{
|
||||
id: 1,
|
||||
label: 'Member Growth',
|
||||
value: '24.8%',
|
||||
icon: 'mdi:account-multiple-plus',
|
||||
color: '#10B981',
|
||||
trendType: 'positive',
|
||||
trendIcon: 'mdi:trending-up',
|
||||
trendValue: '+5.2%',
|
||||
progress: 82
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
label: 'Revenue YTD',
|
||||
value: '$2.4M',
|
||||
icon: 'mdi:cash-multiple',
|
||||
color: '#3B82F6',
|
||||
trendType: 'positive',
|
||||
trendIcon: 'mdi:trending-up',
|
||||
trendValue: '+12.3%',
|
||||
progress: 68
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
label: 'Member Retention',
|
||||
value: '94.5%',
|
||||
icon: 'mdi:account-heart',
|
||||
color: '#CC0000',
|
||||
trendType: 'positive',
|
||||
trendIcon: 'mdi:trending-up',
|
||||
trendValue: '+2.1%',
|
||||
progress: 95
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
label: 'NPS Score',
|
||||
value: '72',
|
||||
icon: 'mdi:emoticon-happy',
|
||||
color: '#F59E0B',
|
||||
trendType: 'neutral',
|
||||
trendIcon: 'mdi:minus',
|
||||
trendValue: '0%',
|
||||
progress: 72
|
||||
}
|
||||
])
|
||||
|
||||
// Strategic Initiatives
|
||||
const strategicInitiatives = ref([
|
||||
{
|
||||
id: 1,
|
||||
name: 'Digital Transformation Initiative',
|
||||
status: 'on-track',
|
||||
statusText: 'On Track',
|
||||
progress: 65,
|
||||
owner: 'John Smith',
|
||||
deadline: 'Q2 2024'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Member Experience Enhancement',
|
||||
status: 'ahead',
|
||||
statusText: 'Ahead',
|
||||
progress: 78,
|
||||
owner: 'Sarah Johnson',
|
||||
deadline: 'Q1 2024'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'International Expansion',
|
||||
status: 'at-risk',
|
||||
statusText: 'At Risk',
|
||||
progress: 42,
|
||||
owner: 'Mike Chen',
|
||||
deadline: 'Q3 2024'
|
||||
}
|
||||
])
|
||||
|
||||
// Committees
|
||||
const committees = ref([
|
||||
{
|
||||
id: 1,
|
||||
name: 'Finance',
|
||||
icon: 'mdi:calculator',
|
||||
color: '#3B82F6',
|
||||
members: 7,
|
||||
meetings: 12
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Governance',
|
||||
icon: 'mdi:gavel',
|
||||
color: '#CC0000',
|
||||
members: 5,
|
||||
meetings: 8
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Audit',
|
||||
icon: 'mdi:magnify',
|
||||
color: '#F59E0B',
|
||||
members: 4,
|
||||
meetings: 10
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'Compensation',
|
||||
icon: 'mdi:cash',
|
||||
color: '#10B981',
|
||||
members: 6,
|
||||
meetings: 6
|
||||
}
|
||||
])
|
||||
|
||||
// Financial Metrics
|
||||
const financialMetrics = ref([
|
||||
{
|
||||
id: 1,
|
||||
label: 'Total Revenue',
|
||||
value: '$2.4M',
|
||||
type: 'positive',
|
||||
changeIcon: 'mdi:arrow-up',
|
||||
change: '+12.3%'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
label: 'Operating Expenses',
|
||||
value: '$1.8M',
|
||||
type: 'neutral',
|
||||
changeIcon: 'mdi:arrow-up',
|
||||
change: '+8.1%'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
label: 'Net Profit',
|
||||
value: '$620K',
|
||||
type: 'positive',
|
||||
changeIcon: 'mdi:arrow-up',
|
||||
change: '+24.5%'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
label: 'Cash Flow',
|
||||
value: '$450K',
|
||||
type: 'positive',
|
||||
changeIcon: 'mdi:arrow-up',
|
||||
change: '+15.2%'
|
||||
}
|
||||
])
|
||||
|
||||
// Dropdown states
|
||||
const showQuarter = ref(false)
|
||||
const selectedQuarter = ref('Q4 2023')
|
||||
const quarters = ref(['Q1 2023', 'Q2 2023', 'Q3 2023', 'Q4 2023', 'Q1 2024'])
|
||||
|
||||
// Time period selector
|
||||
const selectedPeriod = ref('YTD')
|
||||
const timePeriods = ref(['MTD', 'QTD', 'YTD'])
|
||||
|
||||
// Methods
|
||||
const toggleQuarter = () => {
|
||||
showQuarter.value = !showQuarter.value
|
||||
}
|
||||
|
||||
const selectQuarter = (quarter) => {
|
||||
selectedQuarter.value = quarter
|
||||
showQuarter.value = false
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// Close dropdown when clicking outside
|
||||
document.addEventListener('click', (e) => {
|
||||
if (!e.target.closest('.morphing-select-wrapper')) {
|
||||
showQuarter.value = false
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/design-mockups/styles/design-system.scss';
|
||||
|
||||
.board-dashboard-v2 {
|
||||
padding: 2rem;
|
||||
background: linear-gradient(135deg, $neutral-50 0%, $neutral-100 100%);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
// Executive Header
|
||||
.executive-header {
|
||||
text-align: center;
|
||||
margin-bottom: 3rem;
|
||||
|
||||
.dashboard-title {
|
||||
font-size: $text-4xl;
|
||||
font-weight: $font-bold;
|
||||
background: linear-gradient(135deg, $primary-600, $primary-800);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.dashboard-subtitle {
|
||||
color: $neutral-600;
|
||||
font-size: $text-lg;
|
||||
}
|
||||
}
|
||||
|
||||
// KPI Grid
|
||||
.kpi-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: 1.5rem;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.kpi-card {
|
||||
@include neumorphic-card('md');
|
||||
padding: 1.5rem;
|
||||
|
||||
.kpi-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.kpi-icon-wrapper {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: $radius-lg;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: $shadow-inset-sm;
|
||||
|
||||
.kpi-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.kpi-trend {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
font-size: $text-sm;
|
||||
font-weight: $font-semibold;
|
||||
|
||||
&.positive { color: $success-500; }
|
||||
&.negative { color: $error-500; }
|
||||
&.neutral { color: $neutral-600; }
|
||||
|
||||
.trend-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.kpi-value {
|
||||
font-size: $text-3xl;
|
||||
font-weight: $font-bold;
|
||||
color: $neutral-800;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.kpi-label {
|
||||
color: $neutral-600;
|
||||
font-size: $text-sm;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.kpi-progress {
|
||||
.progress-bar {
|
||||
height: 8px;
|
||||
border-radius: $radius-full;
|
||||
overflow: hidden;
|
||||
margin-bottom: 0.5rem;
|
||||
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
border-radius: $radius-full;
|
||||
transition: width 0.5s $spring-smooth;
|
||||
}
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
font-size: $text-xs;
|
||||
color: $neutral-500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Governance Grid
|
||||
.governance-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
|
||||
@media (max-width: $breakpoint-lg) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.initiative-card,
|
||||
.committee-card {
|
||||
@include neumorphic-card('md');
|
||||
padding: 2rem;
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1.5rem;
|
||||
position: relative;
|
||||
|
||||
.header-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
color: $primary-600;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: $text-xl;
|
||||
font-weight: $font-semibold;
|
||||
color: $neutral-800;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Strategic Initiatives
|
||||
.initiatives-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.initiative-item {
|
||||
padding: 1rem;
|
||||
border-radius: $radius-lg;
|
||||
background: $neutral-50;
|
||||
|
||||
.initiative-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.initiative-name {
|
||||
font-weight: $font-medium;
|
||||
color: $neutral-800;
|
||||
font-size: $text-sm;
|
||||
}
|
||||
|
||||
.initiative-status {
|
||||
padding: 0.25rem 0.75rem;
|
||||
border-radius: $radius-full;
|
||||
font-size: $text-xs;
|
||||
font-weight: $font-medium;
|
||||
|
||||
&.on-track {
|
||||
background: rgba($success-500, 0.1);
|
||||
color: $success-500;
|
||||
}
|
||||
|
||||
&.ahead {
|
||||
background: rgba($blue-500, 0.1);
|
||||
color: $blue-500;
|
||||
}
|
||||
|
||||
&.at-risk {
|
||||
background: rgba($warning-500, 0.1);
|
||||
color: $warning-500;
|
||||
}
|
||||
}
|
||||
|
||||
.initiative-progress {
|
||||
margin-bottom: 0.75rem;
|
||||
padding: 0.25rem;
|
||||
border-radius: $radius-full;
|
||||
|
||||
.progress-bar-slim {
|
||||
height: 4px;
|
||||
border-radius: $radius-full;
|
||||
background: rgba($neutral-300, 0.3);
|
||||
|
||||
.progress-fill-slim {
|
||||
height: 100%;
|
||||
background: linear-gradient(135deg, $primary-600, $primary-700);
|
||||
border-radius: $radius-full;
|
||||
transition: width 0.5s $spring-smooth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.initiative-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: $text-xs;
|
||||
color: $neutral-600;
|
||||
}
|
||||
}
|
||||
|
||||
// Committee Grid
|
||||
.committee-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.committee-item {
|
||||
padding: 1rem;
|
||||
border-radius: $radius-lg;
|
||||
|
||||
.committee-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
.committee-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: $text-sm;
|
||||
font-weight: $font-semibold;
|
||||
color: $neutral-800;
|
||||
}
|
||||
}
|
||||
|
||||
.committee-stats {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
.stat {
|
||||
text-align: center;
|
||||
|
||||
.stat-value {
|
||||
display: block;
|
||||
font-size: $text-xl;
|
||||
font-weight: $font-bold;
|
||||
color: $neutral-800;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: $text-xs;
|
||||
color: $neutral-600;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Financial Section
|
||||
.financial-section {
|
||||
@include neumorphic-card('lg');
|
||||
padding: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
|
||||
.time-selector {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
|
||||
.time-button {
|
||||
&.active {
|
||||
background: linear-gradient(145deg, $primary-600, $primary-700);
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.financial-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 2rem;
|
||||
|
||||
@media (max-width: $breakpoint-md) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.revenue-chart {
|
||||
h3 {
|
||||
font-size: $text-lg;
|
||||
margin-bottom: 1rem;
|
||||
color: $neutral-800;
|
||||
}
|
||||
|
||||
.chart-placeholder {
|
||||
height: 200px;
|
||||
border-radius: $radius-lg;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: $neutral-500;
|
||||
|
||||
.chart-icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
margin-bottom: 0.5rem;
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.financial-metrics {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.metric-item {
|
||||
padding: 1rem;
|
||||
|
||||
.metric-label {
|
||||
font-size: $text-xs;
|
||||
color: $neutral-600;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.metric-value {
|
||||
font-size: $text-xl;
|
||||
font-weight: $font-bold;
|
||||
margin-bottom: 0.5rem;
|
||||
|
||||
&.positive { color: $success-500; }
|
||||
&.negative { color: $error-500; }
|
||||
&.neutral { color: $neutral-800; }
|
||||
}
|
||||
|
||||
.metric-change {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
font-size: $text-xs;
|
||||
color: $neutral-600;
|
||||
|
||||
.change-icon {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Governance Actions
|
||||
.governance-actions {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.action-card {
|
||||
@include neumorphic-card('md');
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
transition: all $transition-base;
|
||||
|
||||
&:hover {
|
||||
@include neumorphic-card('lg');
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.action-icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
color: $primary-600;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: $text-lg;
|
||||
font-weight: $font-semibold;
|
||||
color: $neutral-800;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
p {
|
||||
color: $neutral-600;
|
||||
font-size: $text-sm;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
// Morphing Dropdown
|
||||
.morphing-select-wrapper {
|
||||
position: relative;
|
||||
|
||||
.select-trigger {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
|
||||
.dropdown-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
transition: transform 0.3s $spring-smooth;
|
||||
|
||||
&.rotate {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.morphing-dropdown {
|
||||
@include morphing-dropdown();
|
||||
position: absolute;
|
||||
top: calc(100% + 8px);
|
||||
right: 0;
|
||||
min-width: 150px;
|
||||
z-index: $z-dropdown;
|
||||
|
||||
.dropdown-option {
|
||||
padding: 0.5rem 1rem;
|
||||
cursor: pointer;
|
||||
transition: all $transition-fast;
|
||||
color: $neutral-700;
|
||||
font-size: $text-sm;
|
||||
|
||||
&:hover {
|
||||
background: rgba($blue-500, 0.1);
|
||||
color: $blue-600;
|
||||
padding-left: 1.25rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Neumorphic Elements
|
||||
.neumorphic-card {
|
||||
background: linear-gradient(145deg, #ffffff, #f0f0f0);
|
||||
border-radius: $radius-xl;
|
||||
box-shadow: $shadow-soft-md;
|
||||
}
|
||||
|
||||
.neumorphic-button {
|
||||
@include neumorphic-button();
|
||||
padding: 0.75rem 1.5rem;
|
||||
border: none;
|
||||
border-radius: $radius-lg;
|
||||
font-weight: $font-medium;
|
||||
color: $neutral-700;
|
||||
cursor: pointer;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
|
||||
&.primary {
|
||||
background: linear-gradient(145deg, $primary-600, $primary-700);
|
||||
color: white;
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(145deg, $primary-700, $primary-800);
|
||||
}
|
||||
}
|
||||
|
||||
&.small {
|
||||
padding: 0.5rem 0.75rem;
|
||||
font-size: $text-sm;
|
||||
}
|
||||
|
||||
&.full-width {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.neumorphic-inset {
|
||||
box-shadow: $shadow-inset-sm;
|
||||
background: linear-gradient(145deg, #e6e6e6, #ffffff);
|
||||
}
|
||||
|
||||
// Transitions
|
||||
.morph-enter-active,
|
||||
.morph-leave-active {
|
||||
transition: all 0.3s $spring-smooth;
|
||||
}
|
||||
|
||||
.morph-enter-from {
|
||||
opacity: 0;
|
||||
transform: scale(0.95) translateY(-10px);
|
||||
}
|
||||
|
||||
.morph-leave-to {
|
||||
opacity: 0;
|
||||
transform: scale(0.95) translateY(-10px);
|
||||
}
|
||||
</style>
|
||||
175
pages/design-test.vue
Normal file
175
pages/design-test.vue
Normal file
@@ -0,0 +1,175 @@
|
||||
<template>
|
||||
<div class="design-test-page">
|
||||
<div class="container">
|
||||
<h1 class="page-title">New Design System Test Pages</h1>
|
||||
<p class="page-subtitle">Testing implementation of the new Neumorphic design with morphing dropdowns</p>
|
||||
|
||||
<div class="navigation-grid">
|
||||
<NuxtLink to="/admin/dashboard-v2" class="nav-card neumorphic-card">
|
||||
<Icon name="mdi:view-dashboard" class="nav-icon" />
|
||||
<h2>Admin Dashboard V2</h2>
|
||||
<p>New admin dashboard with neumorphic design and morphing dropdowns</p>
|
||||
</NuxtLink>
|
||||
|
||||
<NuxtLink to="/board/dashboard-v2" class="nav-card neumorphic-card">
|
||||
<Icon name="mdi:chart-box" class="nav-icon" />
|
||||
<h2>Board Dashboard V2</h2>
|
||||
<p>Executive dashboard with KPIs and strategic insights</p>
|
||||
</NuxtLink>
|
||||
|
||||
<NuxtLink to="/admin/dashboard" class="nav-card neumorphic-card">
|
||||
<Icon name="mdi:view-dashboard-outline" class="nav-icon" />
|
||||
<h2>Current Admin Dashboard</h2>
|
||||
<p>Compare with the existing admin dashboard</p>
|
||||
</NuxtLink>
|
||||
|
||||
<NuxtLink to="/board/dashboard" class="nav-card neumorphic-card">
|
||||
<Icon name="mdi:chart-box-outline" class="nav-icon" />
|
||||
<h2>Current Board Dashboard</h2>
|
||||
<p>Compare with the existing board dashboard</p>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
|
||||
<div class="design-info">
|
||||
<h3>Design System Features</h3>
|
||||
<ul>
|
||||
<li>✨ Neumorphic cards and buttons with soft shadows</li>
|
||||
<li>💧 Glassmorphic blue morphing dropdowns</li>
|
||||
<li>🎯 Monaco red primary color maintained</li>
|
||||
<li>📱 Responsive grid layouts</li>
|
||||
<li>🎨 Professional and inviting aesthetic</li>
|
||||
<li>⚡ Smooth spring animations</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// No authentication required for testing
|
||||
definePageMeta({
|
||||
auth: false,
|
||||
layout: false
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// Import the new design system
|
||||
@import '@/design-mockups/styles/design-system.scss';
|
||||
|
||||
.design-test-page {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, $neutral-50 0%, $neutral-100 100%);
|
||||
padding: 3rem 1rem;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
text-align: center;
|
||||
font-size: $text-4xl;
|
||||
font-weight: $font-bold;
|
||||
background: linear-gradient(135deg, $primary-600, $primary-800);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.page-subtitle {
|
||||
text-align: center;
|
||||
color: $neutral-600;
|
||||
font-size: $text-lg;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.navigation-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 2rem;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.nav-card {
|
||||
@include neumorphic-card('md');
|
||||
padding: 2rem;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
transition: all $transition-base;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
|
||||
&:hover {
|
||||
@include neumorphic-card('lg');
|
||||
transform: translateY(-4px);
|
||||
|
||||
.nav-icon {
|
||||
transform: scale(1.1);
|
||||
color: $primary-600;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
color: $neutral-600;
|
||||
margin-bottom: 1rem;
|
||||
transition: all $transition-base;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: $text-xl;
|
||||
font-weight: $font-semibold;
|
||||
color: $neutral-800;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: $text-sm;
|
||||
color: $neutral-600;
|
||||
line-height: $leading-relaxed;
|
||||
}
|
||||
}
|
||||
|
||||
.design-info {
|
||||
@include neumorphic-card('lg');
|
||||
padding: 2rem;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
|
||||
h3 {
|
||||
font-size: $text-xl;
|
||||
font-weight: $font-semibold;
|
||||
color: $neutral-800;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
|
||||
li {
|
||||
padding: 0.75rem 0;
|
||||
color: $neutral-700;
|
||||
font-size: $text-base;
|
||||
border-bottom: 1px solid rgba($neutral-200, 0.5);
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Neumorphic Elements
|
||||
.neumorphic-card {
|
||||
background: linear-gradient(145deg, #ffffff, #f0f0f0);
|
||||
border-radius: $radius-xl;
|
||||
box-shadow: $shadow-soft-md;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user