Compare commits
2 Commits
e5e45043a8
...
b08d347727
| Author | SHA1 | Date | |
|---|---|---|---|
|
b08d347727
|
|||
|
1d00b8e171
|
+3
-3
@@ -39,9 +39,9 @@
|
|||||||
<!-- <link href="https://example.com/favicon.png" rel="icon" sizes="192x192"> -->
|
<!-- <link href="https://example.com/favicon.png" rel="icon" sizes="192x192"> -->
|
||||||
|
|
||||||
<!-- Font preloads (should be done for each font file) -->
|
<!-- Font preloads (should be done for each font file) -->
|
||||||
<link href="public/fonts/material-icons-round/material-icons-round-latin-400-normal.woff2" rel="preload" as="font" type="font/woff2" crossorigin="anonymous">
|
<link href="/fonts/material-icons-round/material-icons-round-latin-400-normal.woff2" rel="preload" as="font" type="font/woff2" crossorigin="anonymous">
|
||||||
<link href="public/fonts/roboto/Roboto-VariableFont_wdth-wght.woff2" rel="preload" as="font" type="font/woff2" crossorigin="anonymous">
|
<link href="/fonts/roboto/Roboto-VariableFont_wdth-wght.woff2" rel="preload" as="font" type="font/woff2" crossorigin="anonymous">
|
||||||
<link href="public/fonts/roboto-slab/RobotoSlab-VariableFont_wght.woff2" rel="preload" as="font" type="font/woff2" crossorigin="anonymous">
|
<link href="/fonts/roboto-slab/RobotoSlab-VariableFont_wght.woff2" rel="preload" as="font" type="font/woff2" crossorigin="anonymous">
|
||||||
|
|
||||||
<!-- CSS -->
|
<!-- CSS -->
|
||||||
<link href="/src/style.css" rel="stylesheet" media="screen">
|
<link href="/src/style.css" rel="stylesheet" media="screen">
|
||||||
|
|||||||
+2
-1
@@ -9,7 +9,8 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"vue": "^3.5.0"
|
"vue": "^3.5.0",
|
||||||
|
"vue-router": "^4.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/vite": "^4.0.0",
|
"@tailwindcss/vite": "^4.0.0",
|
||||||
|
|||||||
Generated
+18
@@ -11,6 +11,9 @@ importers:
|
|||||||
vue:
|
vue:
|
||||||
specifier: ^3.5.0
|
specifier: ^3.5.0
|
||||||
version: 3.5.35
|
version: 3.5.35
|
||||||
|
vue-router:
|
||||||
|
specifier: ^4.4.0
|
||||||
|
version: 4.6.4(vue@3.5.35)
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@tailwindcss/vite':
|
'@tailwindcss/vite':
|
||||||
specifier: ^4.0.0
|
specifier: ^4.0.0
|
||||||
@@ -470,6 +473,9 @@ packages:
|
|||||||
'@vue/compiler-ssr@3.5.35':
|
'@vue/compiler-ssr@3.5.35':
|
||||||
resolution: {integrity: sha512-rGhAeXgdM7/ffTJGXT69rCCdTmjDewnFuUZfBQQHTdcEBeWdT5HCGY60y2ytLJr9/Dsu7IntUi5z/w0h6Rjnzw==}
|
resolution: {integrity: sha512-rGhAeXgdM7/ffTJGXT69rCCdTmjDewnFuUZfBQQHTdcEBeWdT5HCGY60y2ytLJr9/Dsu7IntUi5z/w0h6Rjnzw==}
|
||||||
|
|
||||||
|
'@vue/devtools-api@6.6.4':
|
||||||
|
resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==}
|
||||||
|
|
||||||
'@vue/reactivity@3.5.35':
|
'@vue/reactivity@3.5.35':
|
||||||
resolution: {integrity: sha512-tVc+SsHConvh/Lz64qq1pP3rYArBmK42xonovEcxY74SQtvctZodG/zhq54P5dr38cVuw25d27cPNRdlMidpGQ==}
|
resolution: {integrity: sha512-tVc+SsHConvh/Lz64qq1pP3rYArBmK42xonovEcxY74SQtvctZodG/zhq54P5dr38cVuw25d27cPNRdlMidpGQ==}
|
||||||
|
|
||||||
@@ -684,6 +690,11 @@ packages:
|
|||||||
yaml:
|
yaml:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
vue-router@4.6.4:
|
||||||
|
resolution: {integrity: sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==}
|
||||||
|
peerDependencies:
|
||||||
|
vue: ^3.5.0
|
||||||
|
|
||||||
vue@3.5.35:
|
vue@3.5.35:
|
||||||
resolution: {integrity: sha512-cx89fnr+0kVGHiNFG6y6s0bdjypJRFNZn6x3WPstNdQR1bi1mbB7h4v5IBGTsPJU3nK1+0Iqj3Zf+hZWMieR4Q==}
|
resolution: {integrity: sha512-cx89fnr+0kVGHiNFG6y6s0bdjypJRFNZn6x3WPstNdQR1bi1mbB7h4v5IBGTsPJU3nK1+0Iqj3Zf+hZWMieR4Q==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -984,6 +995,8 @@ snapshots:
|
|||||||
'@vue/compiler-dom': 3.5.35
|
'@vue/compiler-dom': 3.5.35
|
||||||
'@vue/shared': 3.5.35
|
'@vue/shared': 3.5.35
|
||||||
|
|
||||||
|
'@vue/devtools-api@6.6.4': {}
|
||||||
|
|
||||||
'@vue/reactivity@3.5.35':
|
'@vue/reactivity@3.5.35':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/shared': 3.5.35
|
'@vue/shared': 3.5.35
|
||||||
@@ -1181,6 +1194,11 @@ snapshots:
|
|||||||
jiti: 2.7.0
|
jiti: 2.7.0
|
||||||
lightningcss: 1.32.0
|
lightningcss: 1.32.0
|
||||||
|
|
||||||
|
vue-router@4.6.4(vue@3.5.35):
|
||||||
|
dependencies:
|
||||||
|
'@vue/devtools-api': 6.6.4
|
||||||
|
vue: 3.5.35
|
||||||
|
|
||||||
vue@3.5.35:
|
vue@3.5.35:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/compiler-dom': 3.5.35
|
'@vue/compiler-dom': 3.5.35
|
||||||
|
|||||||
+1
-53
@@ -1,55 +1,3 @@
|
|||||||
<script setup>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="min-h-screen bg-light font-sans text-dark antialiased">
|
<RouterView />
|
||||||
<div class="max-w-7xl mx-auto px-8 py-16">
|
|
||||||
<h1 class="text-3xl font-bold mb-2">MK Design System</h1>
|
|
||||||
<p class="text-secondary">Phase 1 & 2 complete — components coming in Phase 3+</p>
|
|
||||||
|
|
||||||
<div class="mt-12 grid gap-4 grid-cols-2 lg:grid-cols-4">
|
|
||||||
<div class="rounded-xl p-6 bg-gradient-primary text-white shadow-primary">
|
|
||||||
<p class="text-sm font-medium opacity-80">Primary gradient</p>
|
|
||||||
<p class="text-lg font-bold mt-1">#e91e63</p>
|
|
||||||
</div>
|
|
||||||
<div class="rounded-xl p-6 bg-gradient-secondary text-white shadow-secondary">
|
|
||||||
<p class="text-sm font-medium opacity-80">Secondary gradient</p>
|
|
||||||
<p class="text-lg font-bold mt-1">#7b809a</p>
|
|
||||||
</div>
|
|
||||||
<div class="rounded-xl p-6 bg-gradient-success text-white shadow-success">
|
|
||||||
<p class="text-sm font-medium opacity-80">Success gradient</p>
|
|
||||||
<p class="text-lg font-bold mt-1">#4caf50</p>
|
|
||||||
</div>
|
|
||||||
<div class="rounded-xl p-6 bg-gradient-info text-white shadow-info">
|
|
||||||
<p class="text-sm font-medium opacity-80">Info gradient</p>
|
|
||||||
<p class="text-lg font-bold mt-1">#1a73e8</p>
|
|
||||||
</div>
|
|
||||||
<div class="rounded-xl p-6 bg-gradient-warning text-white shadow-warning">
|
|
||||||
<p class="text-sm font-medium opacity-80">Warning gradient</p>
|
|
||||||
<p class="text-lg font-bold mt-1">#fb8c00</p>
|
|
||||||
</div>
|
|
||||||
<div class="rounded-xl p-6 bg-gradient-danger text-white shadow-danger">
|
|
||||||
<p class="text-sm font-medium opacity-80">Danger gradient</p>
|
|
||||||
<p class="text-lg font-bold mt-1">#f44335</p>
|
|
||||||
</div>
|
|
||||||
<div class="rounded-xl p-6 bg-gradient-dark text-white shadow-dark">
|
|
||||||
<p class="text-sm font-medium opacity-80">Dark gradient</p>
|
|
||||||
<p class="text-lg font-bold mt-1">#344767</p>
|
|
||||||
</div>
|
|
||||||
<div class="rounded-xl p-6 bg-gradient-light text-dark shadow-soft-md">
|
|
||||||
<p class="text-sm font-medium opacity-60">Light gradient</p>
|
|
||||||
<p class="text-lg font-bold mt-1">#f0f2f5</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-12 flex flex-wrap gap-3">
|
|
||||||
<span class="text-sm font-medium text-dark">Shadows:</span>
|
|
||||||
<span class="px-4 py-2 bg-white rounded-lg shadow-soft-xs text-sm">soft-xs</span>
|
|
||||||
<span class="px-4 py-2 bg-white rounded-lg shadow-soft-sm text-sm">soft-sm</span>
|
|
||||||
<span class="px-4 py-2 bg-white rounded-lg shadow-soft-md text-sm">soft-md</span>
|
|
||||||
<span class="px-4 py-2 bg-white rounded-lg shadow-soft-lg text-sm">soft-lg</span>
|
|
||||||
<span class="px-4 py-2 bg-white rounded-lg shadow-blur text-sm">blur</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -0,0 +1,134 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { useRoute, RouterLink } from 'vue-router'
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const sidebarOpen = ref(false)
|
||||||
|
|
||||||
|
const navItems = [
|
||||||
|
{ label: 'Dashboard', path: '/', icon: 'dashboard' },
|
||||||
|
{ label: 'Table List', path: '/tables', icon: 'table_view' },
|
||||||
|
{ label: 'Typography', path: '/typography', icon: 'text_fields' },
|
||||||
|
{ label: 'Icons', path: '/icons', icon: 'auto_awesome' },
|
||||||
|
{ label: 'Maps', path: '/maps', icon: 'map' },
|
||||||
|
{ label: 'Notifications', path: '/notifications',icon: 'notifications' },
|
||||||
|
]
|
||||||
|
|
||||||
|
function isActive(path) {
|
||||||
|
if (path === '/') return route.path === '/'
|
||||||
|
return route.path.startsWith(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
const pageTitle = computed(() => route.meta.title ?? '')
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<!-- Sidebar backdrop on mobile -->
|
||||||
|
<div
|
||||||
|
v-if="sidebarOpen"
|
||||||
|
class="fixed inset-0 z-20 bg-black/40 lg:hidden"
|
||||||
|
@click="sidebarOpen = false"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Sidebar -->
|
||||||
|
<aside
|
||||||
|
class="fixed inset-y-0 left-0 z-30 flex w-64 flex-col bg-gradient-dark shadow-dark transition-transform duration-300"
|
||||||
|
:class="sidebarOpen ? 'translate-x-0' : '-translate-x-full lg:translate-x-0'"
|
||||||
|
>
|
||||||
|
<!-- Brand -->
|
||||||
|
<div class="flex items-center gap-3 px-6 py-5">
|
||||||
|
<div class="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-gradient-primary shadow-primary">
|
||||||
|
<span class="material-icons text-base text-white">layers</span>
|
||||||
|
</div>
|
||||||
|
<span class="text-sm font-semibold text-white">MK Design System</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mx-4 border-t border-white/20" />
|
||||||
|
|
||||||
|
<!-- Nav -->
|
||||||
|
<nav class="flex-1 space-y-0.5 overflow-y-auto px-4 py-4">
|
||||||
|
<RouterLink
|
||||||
|
v-for="item in navItems"
|
||||||
|
:key="item.path"
|
||||||
|
:to="item.path"
|
||||||
|
class="flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-all duration-200"
|
||||||
|
:class="isActive(item.path)
|
||||||
|
? 'bg-gradient-primary shadow-primary text-white'
|
||||||
|
: 'text-white/60 hover:bg-white/10 hover:text-white'"
|
||||||
|
@click="sidebarOpen = false"
|
||||||
|
>
|
||||||
|
<span class="material-icons text-lg leading-none">{{ item.icon }}</span>
|
||||||
|
{{ item.label }}
|
||||||
|
</RouterLink>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<div class="mx-4 border-t border-white/20" />
|
||||||
|
<div class="space-y-0.5 px-4 py-4">
|
||||||
|
<RouterLink
|
||||||
|
to="/profile"
|
||||||
|
class="flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-all duration-200"
|
||||||
|
:class="isActive('/profile')
|
||||||
|
? 'bg-gradient-primary shadow-primary text-white'
|
||||||
|
: 'text-white/60 hover:bg-white/10 hover:text-white'"
|
||||||
|
@click="sidebarOpen = false"
|
||||||
|
>
|
||||||
|
<span class="material-icons text-lg leading-none">person</span>
|
||||||
|
Profile
|
||||||
|
</RouterLink>
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
class="flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium text-white/60 transition-all hover:bg-white/10 hover:text-white"
|
||||||
|
>
|
||||||
|
<span class="material-icons text-lg leading-none">settings</span>
|
||||||
|
Settings
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
class="flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium text-white/60 transition-all hover:bg-white/10 hover:text-white"
|
||||||
|
>
|
||||||
|
<span class="material-icons text-lg leading-none">logout</span>
|
||||||
|
Log Out
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<!-- Main -->
|
||||||
|
<div class="flex min-h-screen flex-col lg:pl-64">
|
||||||
|
|
||||||
|
<!-- Top navbar -->
|
||||||
|
<header class="sticky top-0 z-20 flex items-center justify-between bg-white/80 px-6 py-3 shadow-soft-sm backdrop-blur-sm">
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<!-- Hamburger (mobile) -->
|
||||||
|
<button
|
||||||
|
class="rounded-lg p-1.5 text-secondary hover:bg-gray-100 lg:hidden"
|
||||||
|
@click="sidebarOpen = true"
|
||||||
|
>
|
||||||
|
<span class="material-icons text-xl leading-none">menu</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Breadcrumb -->
|
||||||
|
<div>
|
||||||
|
<p class="text-xs text-secondary">Pages / {{ pageTitle }}</p>
|
||||||
|
<h6 class="text-sm font-bold text-dark">{{ pageTitle }}</h6>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Right actions -->
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<button class="rounded-lg p-2 text-secondary hover:bg-gray-100 hover:text-dark">
|
||||||
|
<span class="material-icons text-xl leading-none">notifications</span>
|
||||||
|
</button>
|
||||||
|
<button class="rounded-lg p-2 text-secondary hover:bg-gray-100 hover:text-dark">
|
||||||
|
<span class="material-icons text-xl leading-none">account_circle</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- Page content -->
|
||||||
|
<main class="flex-1 px-6 py-6">
|
||||||
|
<slot />
|
||||||
|
</main>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
+2
-1
@@ -1,5 +1,6 @@
|
|||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
import './style.css'
|
import './style.css'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
|
import router from './router/index.js'
|
||||||
|
|
||||||
createApp(App).mount('#app')
|
createApp(App).use(router).mount('#app')
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { createRouter, createWebHistory } from 'vue-router'
|
||||||
|
import HomeView from '../views/HomeView.vue'
|
||||||
|
|
||||||
|
export default createRouter({
|
||||||
|
history: createWebHistory(),
|
||||||
|
routes: [
|
||||||
|
{ path: '/', component: HomeView, meta: { title: 'Dashboard' } },
|
||||||
|
{ path: '/tables', component: () => import('../views/TableListView.vue'), meta: { title: 'Table List' } },
|
||||||
|
{ path: '/typography', component: () => import('../views/TypographyView.vue'), meta: { title: 'Typography' } },
|
||||||
|
{ path: '/icons', component: () => import('../views/IconsView.vue'), meta: { title: 'Icons' } },
|
||||||
|
{ path: '/maps', component: () => import('../views/MapsView.vue'), meta: { title: 'Maps' } },
|
||||||
|
{ path: '/notifications',component: () => import('../views/NotificationsView.vue'), meta: { title: 'Notifications' } },
|
||||||
|
{ path: '/profile', component: () => import('../views/ProfileView.vue'), meta: { title: 'Profile' } },
|
||||||
|
],
|
||||||
|
})
|
||||||
@@ -42,6 +42,15 @@
|
|||||||
|
|
||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
SAFELIST
|
||||||
|
Utilities built from dynamic class strings (template literals)
|
||||||
|
are invisible to content scanning. @source inline() forces
|
||||||
|
Tailwind to generate them regardless.
|
||||||
|
============================================================ */
|
||||||
|
|
||||||
|
@source inline("bg-gradient-primary bg-gradient-secondary bg-gradient-success bg-gradient-warning bg-gradient-danger bg-gradient-info bg-gradient-dark bg-gradient-light shadow-primary shadow-secondary shadow-success shadow-warning shadow-danger shadow-info shadow-dark");
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
DESIGN TOKENS
|
DESIGN TOKENS
|
||||||
All values exposed as CSS custom properties AND Tailwind
|
All values exposed as CSS custom properties AND Tailwind
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
<script setup>
|
||||||
|
import DashboardLayout from '../layouts/DashboardLayout.vue'
|
||||||
|
|
||||||
|
const stats = [
|
||||||
|
{ label: "Today's Money", value: '$53,000', change: '+55%', positive: true, icon: 'weekend', gradient: 'primary' },
|
||||||
|
{ label: "Today's Users", value: '2,300', change: '+3%', positive: true, icon: 'leaderboard',gradient: 'info' },
|
||||||
|
{ label: 'New Clients', value: '+3,462', change: '-2%', positive: false,icon: 'store', gradient: 'success' },
|
||||||
|
{ label: 'Sales', value: '$103,430',change: '+5%', positive: true, icon: 'person', gradient: 'danger' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const projects = [
|
||||||
|
{ name: 'Material UI XD', budget: '$14,000', progress: 60, status: 'working' },
|
||||||
|
{ name: 'Add Progress Track', budget: '$3,000', progress: 10, status: 'cancelled' },
|
||||||
|
{ name: 'Fix Platform Errors',budget: 'Not set', progress: 100, status: 'done' },
|
||||||
|
{ name: 'Launch Mobile App', budget: '$20,500', progress: 100, status: 'done' },
|
||||||
|
{ name: 'Add the New Pricing',budget: '$500', progress: 25, status: 'working' },
|
||||||
|
{ name: 'Redesign New Online',budget: '$2,000', progress: 40, status: 'cancelled' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const statusClass = {
|
||||||
|
done: 'bg-success/10 text-success',
|
||||||
|
working: 'bg-info/10 text-info',
|
||||||
|
cancelled: 'bg-danger/10 text-danger',
|
||||||
|
}
|
||||||
|
|
||||||
|
const gradientProgress = (value, gradient) => ({
|
||||||
|
width: `${value}%`,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DashboardLayout>
|
||||||
|
<!-- Stat cards -->
|
||||||
|
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2 xl:grid-cols-4 mt-6">
|
||||||
|
<div
|
||||||
|
v-for="stat in stats"
|
||||||
|
:key="stat.label"
|
||||||
|
class="rounded-2xl bg-white p-4 shadow-soft-md"
|
||||||
|
>
|
||||||
|
<div class="flex items-start justify-between">
|
||||||
|
<div
|
||||||
|
class="-mt-10 flex h-16 w-16 shrink-0 items-center justify-center rounded-xl shadow-soft-md"
|
||||||
|
:class="`bg-gradient-${stat.gradient} shadow-${stat.gradient}`"
|
||||||
|
>
|
||||||
|
<span class="material-icons text-3xl text-white">{{ stat.icon }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="text-right">
|
||||||
|
<p class="text-sm font-medium text-secondary">{{ stat.label }}</p>
|
||||||
|
<h4 class="text-2xl font-bold text-dark">{{ stat.value }}</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-4 border-t border-gray-100 pt-3">
|
||||||
|
<p class="text-sm text-secondary">
|
||||||
|
<span :class="stat.positive ? 'text-success' : 'text-danger'" class="font-medium">
|
||||||
|
{{ stat.change }}
|
||||||
|
</span>
|
||||||
|
than last week
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Projects table -->
|
||||||
|
<div class="mt-6 rounded-2xl bg-white shadow-soft-md">
|
||||||
|
<div class="flex items-center justify-between border-b border-gray-100 px-6 py-4">
|
||||||
|
<h6 class="text-sm font-bold text-dark">Projects</h6>
|
||||||
|
<p class="text-xs text-secondary">
|
||||||
|
<span class="font-medium text-success">30 done</span> this month
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="w-full text-left text-sm">
|
||||||
|
<thead>
|
||||||
|
<tr class="border-b border-gray-100">
|
||||||
|
<th class="px-6 py-3 text-xs font-bold uppercase tracking-wide text-secondary">Project</th>
|
||||||
|
<th class="px-6 py-3 text-xs font-bold uppercase tracking-wide text-secondary">Budget</th>
|
||||||
|
<th class="px-6 py-3 text-xs font-bold uppercase tracking-wide text-secondary">Status</th>
|
||||||
|
<th class="px-6 py-3 text-xs font-bold uppercase tracking-wide text-secondary">Completion</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr
|
||||||
|
v-for="(p, i) in projects"
|
||||||
|
:key="p.name"
|
||||||
|
:class="i < projects.length - 1 ? 'border-b border-gray-100' : ''"
|
||||||
|
>
|
||||||
|
<td class="px-6 py-3 font-medium text-dark">{{ p.name }}</td>
|
||||||
|
<td class="px-6 py-3 text-secondary">{{ p.budget }}</td>
|
||||||
|
<td class="px-6 py-3">
|
||||||
|
<span class="rounded-full px-2.5 py-1 text-xs font-medium capitalize" :class="statusClass[p.status]">
|
||||||
|
{{ p.status }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-3">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div class="h-1.5 flex-1 overflow-hidden rounded-full bg-gray-200">
|
||||||
|
<div
|
||||||
|
class="h-full rounded-full bg-gradient-info"
|
||||||
|
:style="{ width: `${p.progress}%` }"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span class="w-8 shrink-0 text-right text-xs font-medium text-dark">{{ p.progress }}%</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DashboardLayout>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
<script setup>
|
||||||
|
import DashboardLayout from '../layouts/DashboardLayout.vue'
|
||||||
|
|
||||||
|
const groups = [
|
||||||
|
{
|
||||||
|
label: 'Navigation',
|
||||||
|
icons: ['home','menu','close','arrow_back','arrow_forward','chevron_left','chevron_right',
|
||||||
|
'expand_more','expand_less','more_vert','more_horiz','open_in_new','launch'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Actions',
|
||||||
|
icons: ['add','edit','delete','save','search','filter_list','sort','share','download',
|
||||||
|
'upload','copy_all','content_paste','refresh','sync'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Status & Feedback',
|
||||||
|
icons: ['check_circle','error','warning','info','notifications','notification_important',
|
||||||
|
'done','done_all','pending','hourglass_empty','lock','lock_open'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Content',
|
||||||
|
icons: ['dashboard','table_view','text_fields','auto_awesome','map','bar_chart',
|
||||||
|
'pie_chart','analytics','insights','summarize','article','description'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'People & Social',
|
||||||
|
icons: ['person','group','account_circle','face','supervised_user_circle',
|
||||||
|
'person_add','logout','login','badge','contacts'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Media & Files',
|
||||||
|
icons: ['image','photo','video_library','music_note','folder','folder_open',
|
||||||
|
'attachment','cloud','cloud_upload','cloud_download','storage','backup'],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DashboardLayout>
|
||||||
|
<div class="space-y-6">
|
||||||
|
<div
|
||||||
|
v-for="group in groups"
|
||||||
|
:key="group.label"
|
||||||
|
class="rounded-2xl bg-white p-6 shadow-soft-md"
|
||||||
|
>
|
||||||
|
<h6 class="mb-4 text-sm font-bold text-dark">{{ group.label }}</h6>
|
||||||
|
<div class="grid grid-cols-4 gap-3 sm:grid-cols-6 md:grid-cols-8 lg:grid-cols-10 xl:grid-cols-13">
|
||||||
|
<div
|
||||||
|
v-for="icon in group.icons"
|
||||||
|
:key="icon"
|
||||||
|
class="group flex flex-col items-center gap-2 rounded-xl p-3 transition-all hover:bg-primary/5 hover:shadow-soft-xs cursor-default"
|
||||||
|
:title="icon"
|
||||||
|
>
|
||||||
|
<span class="material-icons text-2xl text-secondary transition-colors group-hover:text-primary">
|
||||||
|
{{ icon }}
|
||||||
|
</span>
|
||||||
|
<span class="w-full truncate text-center text-xs text-secondary group-hover:text-dark">
|
||||||
|
{{ icon }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DashboardLayout>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
<script setup>
|
||||||
|
import DashboardLayout from '../layouts/DashboardLayout.vue'
|
||||||
|
|
||||||
|
const integrations = [
|
||||||
|
{
|
||||||
|
name: 'Google Maps',
|
||||||
|
package: '@googlemaps/js-api-loader',
|
||||||
|
description: 'Full-featured maps with Places, Directions, and Street View. Requires an API key.',
|
||||||
|
docs: 'https://developers.google.com/maps/documentation/javascript',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Mapbox GL JS',
|
||||||
|
package: 'mapbox-gl',
|
||||||
|
description: 'High-performance vector tile maps with rich customization and offline support.',
|
||||||
|
docs: 'https://docs.mapbox.com/mapbox-gl-js/',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Leaflet + vue-leaflet',
|
||||||
|
package: '@vue-leaflet/vue-leaflet',
|
||||||
|
description: 'Lightweight, open-source maps using OpenStreetMap tiles. No API key required.',
|
||||||
|
docs: 'https://vue-leaflet.github.io/vue-leaflet/',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DashboardLayout>
|
||||||
|
<div class="space-y-6">
|
||||||
|
|
||||||
|
<!-- Placeholder map area -->
|
||||||
|
<div class="relative overflow-hidden rounded-2xl bg-white shadow-soft-md">
|
||||||
|
<div class="flex h-96 items-center justify-center bg-gradient-to-br from-gray-100 to-gray-200">
|
||||||
|
<!-- Grid lines to suggest a map -->
|
||||||
|
<svg class="absolute inset-0 h-full w-full opacity-30" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
|
||||||
|
<path d="M 40 0 L 0 0 0 40" fill="none" stroke="#adb5bd" stroke-width="0.5"/>
|
||||||
|
</pattern>
|
||||||
|
</defs>
|
||||||
|
<rect width="100%" height="100%" fill="url(#grid)" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<!-- Simulated pin -->
|
||||||
|
<div class="relative flex flex-col items-center">
|
||||||
|
<div class="flex h-14 w-14 items-center justify-center rounded-full bg-gradient-primary shadow-primary">
|
||||||
|
<span class="material-icons text-2xl text-white">place</span>
|
||||||
|
</div>
|
||||||
|
<div class="-mt-1 h-3 w-px bg-primary" />
|
||||||
|
<div class="mt-4 rounded-xl bg-white px-6 py-4 shadow-soft-lg text-center">
|
||||||
|
<p class="text-sm font-bold text-dark">Map Integration</p>
|
||||||
|
<p class="text-xs text-secondary">Mount your map library component here</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Integration options -->
|
||||||
|
<div class="rounded-2xl bg-white p-6 shadow-soft-md">
|
||||||
|
<h6 class="mb-1 text-sm font-bold text-dark">Recommended Integrations</h6>
|
||||||
|
<p class="mb-6 text-xs text-secondary">
|
||||||
|
Maps require a third-party library. Choose one and mount it inside
|
||||||
|
<code class="rounded bg-gray-100 px-1.5 py-0.5 font-mono text-xs text-primary">MapsView.vue</code>.
|
||||||
|
</p>
|
||||||
|
<div class="grid gap-4 sm:grid-cols-3">
|
||||||
|
<div
|
||||||
|
v-for="lib in integrations"
|
||||||
|
:key="lib.name"
|
||||||
|
class="rounded-xl border border-gray-200 p-4 transition-shadow hover:shadow-soft-sm"
|
||||||
|
>
|
||||||
|
<p class="font-semibold text-dark text-sm">{{ lib.name }}</p>
|
||||||
|
<code class="mt-1 block text-xs text-secondary font-mono">{{ lib.package }}</code>
|
||||||
|
<p class="mt-2 text-xs text-secondary leading-relaxed">{{ lib.description }}</p>
|
||||||
|
<a
|
||||||
|
:href="lib.docs"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
class="mt-3 inline-flex items-center gap-1 text-xs font-medium text-primary hover:underline"
|
||||||
|
>
|
||||||
|
Docs <span class="material-icons text-xs leading-none">open_in_new</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</DashboardLayout>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import DashboardLayout from '../layouts/DashboardLayout.vue'
|
||||||
|
|
||||||
|
const dismissed = ref(new Set())
|
||||||
|
|
||||||
|
const alerts = [
|
||||||
|
{ id: 1, type: 'success', icon: 'check_circle', title: 'Success', message: 'This is a success notification — something went well.' },
|
||||||
|
{ id: 2, type: 'info', icon: 'info', title: 'Info', message: 'This is an info notification — just letting you know.' },
|
||||||
|
{ id: 3, type: 'warning', icon: 'warning', title: 'Warning', message: 'This is a warning notification — you should take action.' },
|
||||||
|
{ id: 4, type: 'danger', icon: 'error', title: 'Error', message: 'This is an error notification — something went wrong.' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const typeStyle = {
|
||||||
|
success: 'bg-success text-white',
|
||||||
|
info: 'bg-info text-white',
|
||||||
|
warning: 'bg-warning text-white',
|
||||||
|
danger: 'bg-danger text-white',
|
||||||
|
}
|
||||||
|
|
||||||
|
const notifications = [
|
||||||
|
{ id: 10, avatar: 'PC', color: 'primary', name: 'Patrick Collins', time: '13 minutes ago', text: 'New message in Design System channel' },
|
||||||
|
{ id: 11, avatar: 'MR', color: 'info', name: 'Mikaela Ramos', time: '2 hours ago', text: 'Updated the icon grid component' },
|
||||||
|
{ id: 12, avatar: 'TP', color: 'success', name: 'Tom Perez', time: 'Yesterday', text: 'Released v0.2.0 with table improvements' },
|
||||||
|
{ id: 13, avatar: 'LC', color: 'warning', name: 'Lacina Cosmo', time: '2 days ago', text: 'Flagged a responsiveness issue on mobile' },
|
||||||
|
{ id: 14, avatar: 'AM', color: 'danger', name: 'Ally Maria', time: 'Last week', text: 'Added font preload entries to index.html' },
|
||||||
|
]
|
||||||
|
|
||||||
|
function dismiss(id) {
|
||||||
|
dismissed.value.add(id)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DashboardLayout>
|
||||||
|
<div class="grid gap-6 lg:grid-cols-2">
|
||||||
|
|
||||||
|
<!-- Dismissible alerts -->
|
||||||
|
<div class="rounded-2xl bg-white p-6 shadow-soft-md">
|
||||||
|
<h6 class="mb-1 text-sm font-bold text-dark">Alert States</h6>
|
||||||
|
<p class="mb-6 text-xs text-secondary">Dismissible alerts for each semantic color</p>
|
||||||
|
<div class="space-y-3">
|
||||||
|
<transition-group name="alert">
|
||||||
|
<div
|
||||||
|
v-for="alert in alerts"
|
||||||
|
v-show="!dismissed.has(alert.id)"
|
||||||
|
:key="alert.id"
|
||||||
|
class="flex items-start gap-3 rounded-lg p-4 text-sm font-medium"
|
||||||
|
:class="typeStyle[alert.type]"
|
||||||
|
>
|
||||||
|
<span class="material-icons text-lg leading-none shrink-0">{{ alert.icon }}</span>
|
||||||
|
<p class="flex-1">
|
||||||
|
<span class="font-bold">{{ alert.title }} — </span>{{ alert.message }}
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
class="shrink-0 opacity-70 hover:opacity-100 transition-opacity"
|
||||||
|
@click="dismiss(alert.id)"
|
||||||
|
>
|
||||||
|
<span class="material-icons text-lg leading-none">close</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</transition-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Notification feed -->
|
||||||
|
<div class="rounded-2xl bg-white p-6 shadow-soft-md">
|
||||||
|
<div class="mb-6 flex items-center justify-between">
|
||||||
|
<h6 class="text-sm font-bold text-dark">Recent Notifications</h6>
|
||||||
|
<span class="rounded-full bg-primary/10 px-2.5 py-1 text-xs font-medium text-primary">
|
||||||
|
{{ notifications.length }} new
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div
|
||||||
|
v-for="n in notifications"
|
||||||
|
:key="n.id"
|
||||||
|
class="flex items-start gap-3"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex h-9 w-9 shrink-0 items-center justify-center rounded-xl text-xs font-bold text-white shadow-soft-sm"
|
||||||
|
:class="`bg-gradient-${n.color} shadow-${n.color}`"
|
||||||
|
>
|
||||||
|
{{ n.avatar }}
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 min-w-0">
|
||||||
|
<p class="text-sm font-medium text-dark truncate">{{ n.name }}</p>
|
||||||
|
<p class="text-xs text-secondary mt-0.5">{{ n.text }}</p>
|
||||||
|
</div>
|
||||||
|
<span class="shrink-0 text-xs text-secondary">{{ n.time }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</DashboardLayout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.alert-leave-active {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
.alert-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(1rem);
|
||||||
|
max-height: 0;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,240 @@
|
|||||||
|
<script setup>
|
||||||
|
import DashboardLayout from '../layouts/DashboardLayout.vue'
|
||||||
|
|
||||||
|
const stats = [
|
||||||
|
{ label: 'Followers', value: '4,812' },
|
||||||
|
{ label: 'Following', value: '294' },
|
||||||
|
{ label: 'Projects', value: '32' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const socials = [
|
||||||
|
{ icon: 'facebook', color: 'text-blue-600', label: 'Facebook' },
|
||||||
|
{ icon: 'twitter', color: 'text-sky-500', label: 'Twitter' },
|
||||||
|
{ icon: 'instagram', color: 'text-pink-500', label: 'Instagram' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const conversations = [
|
||||||
|
{ initials: 'OP', color: 'primary', name: 'Olivia Park', preview: 'Hey, I loved the new component library!', time: '5m' },
|
||||||
|
{ initials: 'JD', color: 'info', name: 'James Donovan', preview: 'Can you review my PR when you get a chance?', time: '22m' },
|
||||||
|
{ initials: 'SR', color: 'success', name: 'Sofia Reyes', preview: 'The design tokens look great in production.', time: '1h' },
|
||||||
|
{ initials: 'ML', color: 'warning', name: 'Marco Lin', preview: 'Pushed the icon fix — all shadows resolved.', time: '3h' },
|
||||||
|
{ initials: 'AM', color: 'secondary', name: 'Ally Maria', preview: 'Updated the font preload entries in index.html.', time: '1d' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const projects = [
|
||||||
|
{ name: 'MK Design System', role: 'Lead', gradient: 'primary', members: ['PC', 'JD', 'SR'] },
|
||||||
|
{ name: 'Dashboard Rework', role: 'Contributor', gradient: 'info', members: ['ML', 'AM'] },
|
||||||
|
{ name: 'Icon Library', role: 'Owner', gradient: 'success', members: ['OP', 'JD'] },
|
||||||
|
{ name: 'Typography Scale', role: 'Reviewer', gradient: 'warning', members: ['SR', 'ML', 'PC'] },
|
||||||
|
]
|
||||||
|
|
||||||
|
const memberColor = { PC: 'primary', JD: 'info', SR: 'success', ML: 'warning', AM: 'secondary', OP: 'danger' }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DashboardLayout>
|
||||||
|
|
||||||
|
<!-- Cover + avatar -->
|
||||||
|
<div class="relative mb-20">
|
||||||
|
<div class="h-48 overflow-hidden rounded-2xl bg-gradient-dark shadow-dark">
|
||||||
|
<!-- Decorative grid -->
|
||||||
|
<svg class="h-full w-full opacity-10" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<pattern id="pgrid" width="40" height="40" patternUnits="userSpaceOnUse">
|
||||||
|
<path d="M 40 0 L 0 0 0 40" fill="none" stroke="white" stroke-width="0.5"/>
|
||||||
|
</pattern>
|
||||||
|
</defs>
|
||||||
|
<rect width="100%" height="100%" fill="url(#pgrid)" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Avatar -->
|
||||||
|
<div class="absolute -bottom-14 left-8 flex h-28 w-28 items-center justify-center rounded-2xl bg-gradient-primary text-4xl font-bold text-white shadow-primary ring-4 ring-white">
|
||||||
|
EC
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid gap-6 lg:grid-cols-3">
|
||||||
|
|
||||||
|
<!-- Left column -->
|
||||||
|
<div class="space-y-6">
|
||||||
|
|
||||||
|
<!-- Identity card -->
|
||||||
|
<div class="rounded-2xl bg-white p-6 shadow-soft-md">
|
||||||
|
<h4 class="text-xl font-bold text-dark">Esthera Carter</h4>
|
||||||
|
<p class="mt-0.5 text-sm text-secondary">Lead Designer · San Francisco, CA</p>
|
||||||
|
|
||||||
|
<!-- Stats -->
|
||||||
|
<div class="mt-5 grid grid-cols-3 divide-x divide-gray-100 rounded-xl border border-gray-100">
|
||||||
|
<div v-for="s in stats" :key="s.label" class="flex flex-col items-center py-3">
|
||||||
|
<span class="text-lg font-bold text-dark">{{ s.value }}</span>
|
||||||
|
<span class="text-xs text-secondary">{{ s.label }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Bio -->
|
||||||
|
<p class="mt-5 text-sm leading-relaxed text-secondary">
|
||||||
|
Building design systems and component libraries. Obsessed with typography,
|
||||||
|
spacing, and making sure every pixel is intentional.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- Socials -->
|
||||||
|
<div class="mt-5 flex items-center gap-3">
|
||||||
|
<a
|
||||||
|
v-for="s in socials"
|
||||||
|
:key="s.icon"
|
||||||
|
href="#"
|
||||||
|
class="flex h-8 w-8 items-center justify-center rounded-lg bg-gray-100 transition-colors hover:bg-gray-200"
|
||||||
|
:title="s.label"
|
||||||
|
>
|
||||||
|
<span class="material-icons text-base" :class="s.color">tag</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Conversations -->
|
||||||
|
<div class="rounded-2xl bg-white p-6 shadow-soft-md">
|
||||||
|
<h6 class="mb-4 text-sm font-bold text-dark">Conversations</h6>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div
|
||||||
|
v-for="c in conversations"
|
||||||
|
:key="c.name"
|
||||||
|
class="flex items-start gap-3 cursor-pointer group"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex h-9 w-9 shrink-0 items-center justify-center rounded-xl text-xs font-bold text-white"
|
||||||
|
:class="`bg-gradient-${c.color} shadow-${c.color}`"
|
||||||
|
>
|
||||||
|
{{ c.initials }}
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 min-w-0">
|
||||||
|
<p class="text-sm font-medium text-dark group-hover:text-primary transition-colors">{{ c.name }}</p>
|
||||||
|
<p class="text-xs text-secondary truncate">{{ c.preview }}</p>
|
||||||
|
</div>
|
||||||
|
<span class="shrink-0 text-xs text-secondary">{{ c.time }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Right column -->
|
||||||
|
<div class="space-y-6 lg:col-span-2">
|
||||||
|
|
||||||
|
<!-- Projects -->
|
||||||
|
<div class="rounded-2xl bg-white p-6 shadow-soft-md">
|
||||||
|
<div class="mb-4 flex items-center justify-between">
|
||||||
|
<h6 class="text-sm font-bold text-dark">Projects</h6>
|
||||||
|
<button class="rounded-lg bg-gradient-primary px-4 py-2 text-xs font-medium text-white shadow-primary">
|
||||||
|
+ New
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid gap-4 sm:grid-cols-2">
|
||||||
|
<div
|
||||||
|
v-for="p in projects"
|
||||||
|
:key="p.name"
|
||||||
|
class="group relative overflow-hidden rounded-xl border border-gray-100 p-4 transition-shadow hover:shadow-soft-md"
|
||||||
|
>
|
||||||
|
<!-- Gradient accent bar -->
|
||||||
|
<div class="absolute left-0 top-0 h-full w-1 rounded-l-xl" :class="`bg-gradient-${p.gradient}`" />
|
||||||
|
|
||||||
|
<div class="pl-3">
|
||||||
|
<div class="flex items-start justify-between">
|
||||||
|
<div>
|
||||||
|
<p class="text-sm font-semibold text-dark">{{ p.name }}</p>
|
||||||
|
<span
|
||||||
|
class="mt-1 inline-block rounded-full px-2 py-0.5 text-xs font-medium"
|
||||||
|
:class="`bg-${p.gradient}/10 text-${p.gradient}`"
|
||||||
|
>
|
||||||
|
{{ p.role }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<button class="text-secondary hover:text-dark">
|
||||||
|
<span class="material-icons text-base leading-none">more_vert</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Member avatars -->
|
||||||
|
<div class="mt-3 flex items-center">
|
||||||
|
<div class="flex -space-x-2">
|
||||||
|
<div
|
||||||
|
v-for="m in p.members"
|
||||||
|
:key="m"
|
||||||
|
class="flex h-7 w-7 items-center justify-center rounded-lg text-xs font-bold text-white ring-2 ring-white"
|
||||||
|
:class="`bg-gradient-${memberColor[m]} shadow-${memberColor[m]}`"
|
||||||
|
:title="m"
|
||||||
|
>
|
||||||
|
{{ m }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<div class="rounded-2xl bg-white p-6 shadow-soft-md">
|
||||||
|
<h6 class="mb-5 text-sm font-bold text-dark">Profile Settings</h6>
|
||||||
|
<div class="space-y-4">
|
||||||
|
|
||||||
|
<div class="grid gap-4 sm:grid-cols-2">
|
||||||
|
<div>
|
||||||
|
<label class="mb-1 block text-xs font-medium text-secondary">First Name</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value="Esthera"
|
||||||
|
class="w-full rounded-lg border border-gray-200 px-3 py-2 text-sm text-dark outline-none focus:border-primary focus:ring-1 focus:ring-primary transition-colors"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="mb-1 block text-xs font-medium text-secondary">Last Name</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value="Carter"
|
||||||
|
class="w-full rounded-lg border border-gray-200 px-3 py-2 text-sm text-dark outline-none focus:border-primary focus:ring-1 focus:ring-primary transition-colors"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="mb-1 block text-xs font-medium text-secondary">Email Address</label>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
value="esthera@mkdesign.dev"
|
||||||
|
class="w-full rounded-lg border border-gray-200 px-3 py-2 text-sm text-dark outline-none focus:border-primary focus:ring-1 focus:ring-primary transition-colors"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="mb-1 block text-xs font-medium text-secondary">Location</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value="San Francisco, CA"
|
||||||
|
class="w-full rounded-lg border border-gray-200 px-3 py-2 text-sm text-dark outline-none focus:border-primary focus:ring-1 focus:ring-primary transition-colors"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="mb-1 block text-xs font-medium text-secondary">Bio</label>
|
||||||
|
<textarea
|
||||||
|
rows="3"
|
||||||
|
class="w-full rounded-lg border border-gray-200 px-3 py-2 text-sm text-dark outline-none focus:border-primary focus:ring-1 focus:ring-primary transition-colors resize-none"
|
||||||
|
>Building design systems and component libraries. Obsessed with typography, spacing, and making sure every pixel is intentional.</textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-end">
|
||||||
|
<button class="rounded-lg bg-gradient-primary px-6 py-2.5 text-sm font-medium text-white shadow-primary hover:shadow-soft-md transition-shadow">
|
||||||
|
Save Changes
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</DashboardLayout>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
<script setup>
|
||||||
|
import DashboardLayout from '../layouts/DashboardLayout.vue'
|
||||||
|
|
||||||
|
const rows = [
|
||||||
|
{ initials: 'OA', color: 'primary', name: 'Esthera Jackson', email: 'esthera@argon.com', role: 'Manager', org: 'Organization', online: true, date: '23/04/18' },
|
||||||
|
{ initials: 'LB', color: 'info', name: 'Landon Brighton', email: 'landon@argon.com', role: 'Programator',org: 'Developer', online: false, date: '11/01/19' },
|
||||||
|
{ initials: 'MR', color: 'success', name: 'Mikaela Ramos', email: 'mikaela@argon.com', role: 'Executive', org: 'Projects', online: true, date: '19/09/17' },
|
||||||
|
{ initials: 'TP', color: 'warning', name: 'Tom Perez', email: 'tom@argon.com', role: 'Projects', org: 'Organization', online: true, date: '24/12/08' },
|
||||||
|
{ initials: 'LC', color: 'danger', name: 'Lacina Cosmo', email: 'lacina@argon.com', role: 'Programator',org: 'Developer', online: false, date: '04/10/21' },
|
||||||
|
{ initials: 'AM', color: 'secondary', name: 'Ally Maria', email: 'ally@argon.com', role: 'Manager', org: 'Executive', online: true, date: '14/03/20' },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DashboardLayout>
|
||||||
|
<div class="rounded-2xl bg-white shadow-soft-md">
|
||||||
|
<!-- Header -->
|
||||||
|
<div class="flex items-center justify-between border-b border-gray-100 px-6 py-4">
|
||||||
|
<h6 class="text-sm font-bold text-dark">Authors Table</h6>
|
||||||
|
<button class="rounded-lg bg-gradient-primary px-4 py-2 text-xs font-medium text-white shadow-primary hover:shadow-soft-md transition-shadow">
|
||||||
|
+ New Entry
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Table -->
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="w-full text-left text-sm">
|
||||||
|
<thead>
|
||||||
|
<tr class="border-b border-gray-100">
|
||||||
|
<th class="px-6 py-3 text-xs font-bold uppercase tracking-wide text-secondary">Author</th>
|
||||||
|
<th class="px-6 py-3 text-xs font-bold uppercase tracking-wide text-secondary">Function</th>
|
||||||
|
<th class="px-6 py-3 text-xs font-bold uppercase tracking-wide text-secondary">Status</th>
|
||||||
|
<th class="px-6 py-3 text-xs font-bold uppercase tracking-wide text-secondary">Employed</th>
|
||||||
|
<th class="px-6 py-3 text-xs font-bold uppercase tracking-wide text-secondary">Action</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr
|
||||||
|
v-for="(row, i) in rows"
|
||||||
|
:key="row.email"
|
||||||
|
:class="i < rows.length - 1 ? 'border-b border-gray-100' : ''"
|
||||||
|
>
|
||||||
|
<!-- Author -->
|
||||||
|
<td class="px-6 py-3">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div
|
||||||
|
class="flex h-9 w-9 shrink-0 items-center justify-center rounded-xl text-xs font-bold text-white shadow-soft-sm"
|
||||||
|
:class="`bg-gradient-${row.color} shadow-${row.color}`"
|
||||||
|
>
|
||||||
|
{{ row.initials }}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="font-medium text-dark">{{ row.name }}</p>
|
||||||
|
<p class="text-xs text-secondary">{{ row.email }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<!-- Function -->
|
||||||
|
<td class="px-6 py-3">
|
||||||
|
<p class="font-medium text-dark">{{ row.role }}</p>
|
||||||
|
<p class="text-xs text-secondary">{{ row.org }}</p>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<!-- Status -->
|
||||||
|
<td class="px-6 py-3">
|
||||||
|
<span
|
||||||
|
class="inline-flex items-center gap-1.5 rounded-full px-2.5 py-1 text-xs font-medium"
|
||||||
|
:class="row.online ? 'bg-success/10 text-success' : 'bg-gray-100 text-secondary'"
|
||||||
|
>
|
||||||
|
<span class="h-1.5 w-1.5 rounded-full" :class="row.online ? 'bg-success' : 'bg-gray-400'" />
|
||||||
|
{{ row.online ? 'Online' : 'Offline' }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<!-- Employed -->
|
||||||
|
<td class="px-6 py-3 text-secondary">{{ row.date }}</td>
|
||||||
|
|
||||||
|
<!-- Action -->
|
||||||
|
<td class="px-6 py-3">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<button class="text-xs font-medium text-info hover:underline">Edit</button>
|
||||||
|
<button class="text-xs font-medium text-danger hover:underline">Delete</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DashboardLayout>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
<script setup>
|
||||||
|
import DashboardLayout from '../layouts/DashboardLayout.vue'
|
||||||
|
|
||||||
|
const headings = [
|
||||||
|
{ tag: 'h1', label: 'h1. Heading', size: 'text-5xl', weight: 'font-light' },
|
||||||
|
{ tag: 'h2', label: 'h2. Heading', size: 'text-4xl', weight: 'font-light' },
|
||||||
|
{ tag: 'h3', label: 'h3. Heading', size: 'text-3xl', weight: 'font-normal' },
|
||||||
|
{ tag: 'h4', label: 'h4. Heading', size: 'text-2xl', weight: 'font-normal' },
|
||||||
|
{ tag: 'h5', label: 'h5. Heading', size: 'text-xl', weight: 'font-medium' },
|
||||||
|
{ tag: 'h6', label: 'h6. Heading', size: 'text-base',weight: 'font-medium' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const weights = [
|
||||||
|
{ label: 'Light 300', class: 'font-light', value: 300 },
|
||||||
|
{ label: 'Regular 400',class: 'font-normal', value: 400 },
|
||||||
|
{ label: 'Medium 500', class: 'font-medium', value: 500 },
|
||||||
|
{ label: 'Bold 700', class: 'font-bold', value: 700 },
|
||||||
|
{ label: 'Black 900', class: 'font-black', value: 900 },
|
||||||
|
]
|
||||||
|
|
||||||
|
const colors = [
|
||||||
|
{ label: 'Primary', class: 'text-primary' },
|
||||||
|
{ label: 'Secondary', class: 'text-secondary' },
|
||||||
|
{ label: 'Success', class: 'text-success' },
|
||||||
|
{ label: 'Warning', class: 'text-warning' },
|
||||||
|
{ label: 'Danger', class: 'text-danger' },
|
||||||
|
{ label: 'Info', class: 'text-info' },
|
||||||
|
{ label: 'Dark', class: 'text-dark' },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DashboardLayout>
|
||||||
|
<div class="grid gap-6 lg:grid-cols-2">
|
||||||
|
|
||||||
|
<!-- Headings -->
|
||||||
|
<div class="rounded-2xl bg-white p-6 shadow-soft-md">
|
||||||
|
<h6 class="mb-1 text-sm font-bold text-dark">Headings</h6>
|
||||||
|
<p class="mb-6 text-xs text-secondary">Roboto Variable — font-light through font-medium</p>
|
||||||
|
<div class="space-y-3">
|
||||||
|
<component
|
||||||
|
:is="h.tag"
|
||||||
|
v-for="h in headings"
|
||||||
|
:key="h.tag"
|
||||||
|
:class="[h.size, h.weight, 'text-dark leading-tight']"
|
||||||
|
>
|
||||||
|
{{ h.label }}
|
||||||
|
</component>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Font weights -->
|
||||||
|
<div class="rounded-2xl bg-white p-6 shadow-soft-md">
|
||||||
|
<h6 class="mb-1 text-sm font-bold text-dark">Font Weights</h6>
|
||||||
|
<p class="mb-6 text-xs text-secondary">Roboto Variable covers 100–900 in a single file</p>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div v-for="w in weights" :key="w.value">
|
||||||
|
<p class="mb-0.5 text-xs text-secondary">{{ w.label }}</p>
|
||||||
|
<p class="text-xl text-dark" :class="w.class">
|
||||||
|
The quick brown fox jumps over the lazy dog
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Body & UI text -->
|
||||||
|
<div class="rounded-2xl bg-white p-6 shadow-soft-md">
|
||||||
|
<h6 class="mb-1 text-sm font-bold text-dark">Body & UI Text</h6>
|
||||||
|
<p class="mb-6 text-xs text-secondary">Scale used across components</p>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div>
|
||||||
|
<p class="mb-1 text-xs text-secondary">text-base (1rem) — body</p>
|
||||||
|
<p class="text-base text-dark">Design systems give teams a shared language for building consistent, scalable products.</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="mb-1 text-xs text-secondary">text-sm (0.875rem) — UI labels</p>
|
||||||
|
<p class="text-sm text-dark">Design systems give teams a shared language for building consistent, scalable products.</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="mb-1 text-xs text-secondary">text-xs (0.75rem) — captions, meta</p>
|
||||||
|
<p class="text-xs text-secondary">Design systems give teams a shared language for building consistent, scalable products.</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="mb-1 text-xs text-secondary">Inline elements</p>
|
||||||
|
<p class="text-sm text-dark">
|
||||||
|
Regular text with <strong>bold emphasis</strong>, <em>italic style</em>,
|
||||||
|
and <code class="rounded bg-gray-100 px-1.5 py-0.5 font-mono text-xs text-primary">inline code</code> fragments.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Text colors -->
|
||||||
|
<div class="rounded-2xl bg-white p-6 shadow-soft-md">
|
||||||
|
<h6 class="mb-1 text-sm font-bold text-dark">Semantic Text Colors</h6>
|
||||||
|
<p class="mb-6 text-xs text-secondary">All map to @theme --color-* tokens</p>
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div v-for="c in colors" :key="c.label" class="flex items-center gap-4">
|
||||||
|
<span class="w-20 shrink-0 text-xs text-secondary">{{ c.label }}</span>
|
||||||
|
<p class="text-sm font-medium" :class="c.class">
|
||||||
|
The quick brown fox jumps over the lazy dog
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</DashboardLayout>
|
||||||
|
</template>
|
||||||
Reference in New Issue
Block a user