diff --git a/src/App.css b/src/App.css index fe9fa18..7106dbf 100644 --- a/src/App.css +++ b/src/App.css @@ -1,6 +1,25 @@ @import 'tailwindcss'; @import '@heroui/styles'; +@theme { + --color-app-bg: #f8fafc; + --color-app-surface: #ffffff; + --color-app-surface-muted: #f1f5f9; + --color-app-border: #e2e8f0; + --color-app-border-input: #cbd5e1; + --color-app-text: #1e293b; + --color-app-text-strong: #0f172a; + --color-app-text-muted: #64748b; + --color-app-primary: #1a73e8; + --color-app-primary-dark: #1558b0; + --color-app-primary-soft: #e8f1fd; + --color-app-primary-contrast: #ffffff; + --color-app-interactive-hover: #f1f5f9; + --color-app-interactive-active: #e8f1fd; + --color-app-focus: #1a73e8; + --shadow-app-panel: 0 16px 42px rgb(0 0 0 / 5%); +} + .app-shell { display: grid; grid-template-columns: var(--sidebar-width) minmax(0, 1fr); @@ -17,8 +36,8 @@ top: 0; height: 100vh; padding: 24px 16px; - border-right: 1px solid var(--border); - background: var(--surface); + border-right: 1px solid var(--color-app-border); + background: var(--color-app-surface); overflow: hidden; } @@ -36,7 +55,7 @@ place-items: center; border-radius: 8px; color: #ffffff; - background: var(--primary); + background: var(--color-app-primary); font-weight: 800; } @@ -61,7 +80,7 @@ .sidebar__brand span { margin-top: 3px; - color: var(--text-muted); + color: var(--color-app-text-muted); font-size: 13px; } @@ -71,10 +90,10 @@ height: 36px; margin-bottom: 14px; place-items: center; - border: 1px solid var(--border); + border: 1px solid var(--color-app-border); border-radius: 8px; - color: var(--text-muted); - background: var(--surface); + color: var(--color-app-text-muted); + background: var(--color-app-surface); cursor: pointer; font-weight: 800; transition: @@ -84,14 +103,14 @@ } .sidebar__toggle:hover { - color: var(--primary); - border-color: var(--primary); - background: var(--primary-soft); + color: var(--color-app-primary); + border-color: var(--color-app-primary); + background: var(--color-app-primary-soft); } .sidebar__toggle:focus-visible, .sidebar__link:focus-visible { - outline: 2px solid var(--focus); + outline: 2px solid var(--color-app-focus); outline-offset: 2px; } @@ -106,7 +125,7 @@ min-height: 42px; padding: 10px 12px; border-radius: 8px; - color: var(--text-muted); + color: var(--color-app-text-muted); font-size: 15px; font-weight: 600; gap: 10px; @@ -123,20 +142,20 @@ height: 28px; place-items: center; border-radius: 7px; - color: var(--primary-dark); - background: var(--primary-soft); + color: var(--color-app-primary-dark); + background: var(--color-app-primary-soft); font-size: 11px; font-weight: 800; } .sidebar__link:hover { - color: var(--text); - background: var(--interactive-hover); + color: var(--color-app-text); + background: var(--color-app-interactive-hover); } .sidebar__link--active { - color: var(--primary); - background: var(--interactive-active); + color: var(--color-app-primary); + background: var(--color-app-interactive-active); } .app-shell--collapsed .sidebar { @@ -168,7 +187,7 @@ .main-content { min-width: 0; - padding: 32px; + padding: 16px; } .page-header { @@ -188,7 +207,7 @@ .page-header p { max-width: 720px; margin: 8px 0 0; - color: var(--text-muted); + color: var(--color-app-text-muted); } .stat-grid { @@ -199,10 +218,10 @@ .stat-card, .content-panel { - border: 1px solid var(--border); + border: 1px solid var(--color-app-border); border-radius: 8px; - background: var(--surface); - box-shadow: 0 16px 42px var(--shadow-color); + background: var(--color-app-surface); + box-shadow: var(--shadow-app-panel); } .stat-card { @@ -211,7 +230,7 @@ .stat-card span { display: block; - color: var(--text-muted); + color: var(--color-app-text-muted); font-size: 14px; } @@ -233,7 +252,7 @@ .content-panel p { margin: 8px 0 0; - color: var(--text-muted); + color: var(--color-app-text-muted); } @media (max-width: 900px) { @@ -250,7 +269,7 @@ height: auto; padding: 16px; border-right: 0; - border-bottom: 1px solid var(--border); + border-bottom: 1px solid var(--color-app-border); } .sidebar__brand { diff --git a/src/components/CourseCard.jsx b/src/components/CourseCard.jsx new file mode 100644 index 0000000..3e02dcb --- /dev/null +++ b/src/components/CourseCard.jsx @@ -0,0 +1,83 @@ +import { Card, Button } from '@heroui/react'; +import { PencilIcon, EllipsisVerticalIcon } from '@heroicons/react/24/outline'; + +const statusStyles = { + Published: 'bg-green-100 text-green-700', + Draft: 'bg-yellow-100 text-yellow-700', + Archived: 'bg-gray-100 text-gray-600' +}; + +function CourseCard({ course, image }) { + const { code, title, description, status, lastUpdate } = course; + + const formattedDate = new Date(lastUpdate).toLocaleDateString('en-GB', { + day: '2-digit', + month: '2-digit', + year: 'numeric' + }); + + return ( + + {/* Image */} +
+ {title} + + {/* Course code */} +
+ {code} +
+
+ + {/* Content */} + +

+ {title} +

+ +

+ {description} +

+
+ + {/* Footer */} + +
+ + {status} + + + Updated {formattedDate} +
+ +
+ + + +
+
+
+ ); +} + +export default CourseCard; diff --git a/src/components/StatGrid.jsx b/src/components/StatGrid.jsx deleted file mode 100644 index 2135f5f..0000000 --- a/src/components/StatGrid.jsx +++ /dev/null @@ -1,14 +0,0 @@ -function StatGrid({ items }) { - return ( -
- {items.map((item) => ( -
- {item.label} - {item.value} -
- ))} -
- ) -} - -export default StatGrid diff --git a/src/config/color.ts b/src/config/color.ts deleted file mode 100644 index 02d1964..0000000 --- a/src/config/color.ts +++ /dev/null @@ -1,121 +0,0 @@ -export const colors = { - // ========================= - // Brand - // ========================= - primary: { - main: '#1A73E8', - light: '#E8F1FD', - dark: '#1558B0', - contrast: '#FFFFFF', - }, - - // ========================= - // Text & Icon - // ========================= - slate: { - 50: '#F8FAFC', - 100: '#F1F5F9', - 200: '#E2E8F0', - 300: '#CBD5E1', - 400: '#94A3B8', - 500: '#64748B', - 600: '#475569', - 700: '#334155', - 800: '#1E293B', - 900: '#0F172A', - }, - - // ========================= - // Background - // ========================= - background: { - default: '#F8FAFC', - surface: '#FFFFFF', - muted: '#F1F5F9', - }, - - // ========================= - // Border - // ========================= - border: { - default: '#E2E8F0', - input: '#CBD5E1', - focus: '#1A73E8', - divider: '#E2E8F0', - }, - - // ========================= - // Status - // ========================= - status: { - success: { - main: '#16A34A', - light: '#DCFCE7', - dark: '#166534', - }, - - warning: { - main: '#D97706', - light: '#FEF3C7', - dark: '#92400E', - }, - - error: { - main: '#DC2626', - light: '#FEE2E2', - dark: '#991B1B', - }, - - info: { - main: '#2563EB', - light: '#DBEAFE', - dark: '#1E40AF', - }, - - neutral: { - main: '#64748B', - light: '#F1F5F9', - dark: '#475569', - }, - }, - - // ========================= - // Interactive - // ========================= - interactive: { - hover: '#F1F5F9', - active: '#E8F1FD', - selected: '#E8F1FD', - focus: '#1A73E8', - disabled: '#CBD5E1', - }, - - // ========================= - // Drag & Drop - // ========================= - drag: { - outline: '#1A73E8', - background: '#FFFFFF', - dropZone: '#1A73E8', - dropZoneBackground: '#E8F1FD', - }, - - // ========================= - // Overlay / Shadow - // ========================= - overlay: { - shadow: 'rgba(0, 0, 0, 0.05)', - backdrop: 'rgba(15, 23, 42, 0.32)', - }, - - // ========================= - // Common - // ========================= - common: { - white: '#FFFFFF', - black: '#000000', - transparent: 'transparent', - }, -} as const; - -export type Colors = typeof colors; \ No newline at end of file diff --git a/src/config/theme.js b/src/config/theme.js deleted file mode 100644 index 029b8ad..0000000 --- a/src/config/theme.js +++ /dev/null @@ -1,26 +0,0 @@ -import { colors } from './color' - -export const themeCssVariables = { - '--bg': colors.background.default, - '--surface': colors.background.surface, - '--surface-muted': colors.background.muted, - '--border': colors.border.default, - '--border-input': colors.border.input, - '--text': colors.slate[800], - '--text-strong': colors.slate[900], - '--text-muted': colors.slate[500], - '--primary': colors.primary.main, - '--primary-dark': colors.primary.dark, - '--primary-soft': colors.primary.light, - '--primary-contrast': colors.primary.contrast, - '--interactive-hover': colors.interactive.hover, - '--interactive-active': colors.interactive.active, - '--focus': colors.interactive.focus, - '--shadow-color': colors.overlay.shadow, -} - -export function applyThemeCssVariables() { - Object.entries(themeCssVariables).forEach(([key, value]) => { - document.documentElement.style.setProperty(key, value) - }) -} diff --git a/src/index.css b/src/index.css index 6573786..b40f971 100644 --- a/src/index.css +++ b/src/index.css @@ -1,27 +1,12 @@ :root { - --bg: #f6f7f9; - --surface: #ffffff; - --surface-muted: #f0f3f7; - --border: #dfe3ea; - --text: #1d2433; - --text-muted: #667085; - --primary: #2563eb; - --primary-dark: #1d4ed8; - --primary-soft: #e9f0ff; - --primary-contrast: #ffffff; - --interactive-hover: #f0f3f7; - --interactive-active: #e9f0ff; - --focus: #2563eb; - --shadow: 0 16px 42px rgba(29, 36, 51, 0.08); - --shadow-color: rgba(0, 0, 0, 0.05); --sidebar-width: 264px; --sidebar-collapsed-width: 88px; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; - color: var(--text); - background: var(--bg); + color: var(--color-app-text); + background: var(--color-app-bg); font-synthesis: none; text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; diff --git a/src/main.jsx b/src/main.jsx index 78aa425..b9a1a6d 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -2,9 +2,6 @@ import { StrictMode } from 'react' import { createRoot } from 'react-dom/client' import './index.css' import App from './App.jsx' -import { applyThemeCssVariables } from './config/theme.js' - -applyThemeCssVariables() createRoot(document.getElementById('root')).render( diff --git a/src/pages/Dashboard/DashboardPage.jsx b/src/pages/Dashboard/DashboardPage.jsx index e0a631a..001a4f4 100644 --- a/src/pages/Dashboard/DashboardPage.jsx +++ b/src/pages/Dashboard/DashboardPage.jsx @@ -1,29 +1,54 @@ -import PageHeader from '../../components/PageHeader.jsx'; -import StatGrid from '../../components/StatGrid.jsx'; -import { Typography, SearchField, Separator } from '@heroui/react'; +import CourseCard from '../../components/CourseCard.jsx'; +import { + Typography, + SearchField, + Separator, + Button, + Tabs +} from '@heroui/react'; import { BellIcon, QuestionMarkCircleIcon, - UserCircleIcon + UserCircleIcon, + FunnelIcon, + PlusIcon } from '@heroicons/react/16/solid'; const stats = [ - { label: 'Khoa hoc dang mo', value: '24' }, - { label: 'Hoc vien', value: '1,248' }, - { label: 'Lop trong tuan', value: '18' }, - { label: 'Ty le hoan thanh', value: '82%' } + { + code: 'LDR-101', + title: 'Foundations of Modern Leadership', + description: + 'An introductory course covering essential leadership principles for new managers.', + status: 'Published', + lastUpdate: '2026-08-19' + }, + { + code: 'TEC-204', + title: 'Advanced Cloud Architecture Patterns', + description: + 'Deep dive into scalable cloud infrastructure design and implementation strategies.', + status: 'Draft', + lastUpdate: '2026-08-19' + }, + { + code: 'CMP-099', + title: '2022 Annual Compliance Review', + description: 'Outdated compliance materials from the previous fiscal year.', + status: 'Archived', + lastUpdate: '2026-08-19' + } ]; +const courseImage = + 'https://images.unsplash.com/photo-1556761175-b413da4baf72?auto=format&fit=crop&w=800&q=80'; + function DashboardPage() { return ( <> - {/* */}
- + -
+
-
- - Course - - - Manage and organize your learning content. - +
+
+ + Course + + + Manage and organize your learning content. + +
+
+ + +
+
+ +
+ + + + + All + + + + + Draft + + + + + Published + + + + + Archived + + + + + + + + + + + + + + +
+
+ {stats.map((course) => ( + + ))}
- ); }