feat: update UI dashboard page
This commit is contained in:
+45
-26
@@ -1,6 +1,25 @@
|
|||||||
@import 'tailwindcss';
|
@import 'tailwindcss';
|
||||||
@import '@heroui/styles';
|
@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 {
|
.app-shell {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: var(--sidebar-width) minmax(0, 1fr);
|
grid-template-columns: var(--sidebar-width) minmax(0, 1fr);
|
||||||
@@ -17,8 +36,8 @@
|
|||||||
top: 0;
|
top: 0;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
padding: 24px 16px;
|
padding: 24px 16px;
|
||||||
border-right: 1px solid var(--border);
|
border-right: 1px solid var(--color-app-border);
|
||||||
background: var(--surface);
|
background: var(--color-app-surface);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,7 +55,7 @@
|
|||||||
place-items: center;
|
place-items: center;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
background: var(--primary);
|
background: var(--color-app-primary);
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +80,7 @@
|
|||||||
|
|
||||||
.sidebar__brand span {
|
.sidebar__brand span {
|
||||||
margin-top: 3px;
|
margin-top: 3px;
|
||||||
color: var(--text-muted);
|
color: var(--color-app-text-muted);
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,10 +90,10 @@
|
|||||||
height: 36px;
|
height: 36px;
|
||||||
margin-bottom: 14px;
|
margin-bottom: 14px;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--color-app-border);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
color: var(--text-muted);
|
color: var(--color-app-text-muted);
|
||||||
background: var(--surface);
|
background: var(--color-app-surface);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
transition:
|
transition:
|
||||||
@@ -84,14 +103,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.sidebar__toggle:hover {
|
.sidebar__toggle:hover {
|
||||||
color: var(--primary);
|
color: var(--color-app-primary);
|
||||||
border-color: var(--primary);
|
border-color: var(--color-app-primary);
|
||||||
background: var(--primary-soft);
|
background: var(--color-app-primary-soft);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar__toggle:focus-visible,
|
.sidebar__toggle:focus-visible,
|
||||||
.sidebar__link:focus-visible {
|
.sidebar__link:focus-visible {
|
||||||
outline: 2px solid var(--focus);
|
outline: 2px solid var(--color-app-focus);
|
||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +125,7 @@
|
|||||||
min-height: 42px;
|
min-height: 42px;
|
||||||
padding: 10px 12px;
|
padding: 10px 12px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
color: var(--text-muted);
|
color: var(--color-app-text-muted);
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
@@ -123,20 +142,20 @@
|
|||||||
height: 28px;
|
height: 28px;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
border-radius: 7px;
|
border-radius: 7px;
|
||||||
color: var(--primary-dark);
|
color: var(--color-app-primary-dark);
|
||||||
background: var(--primary-soft);
|
background: var(--color-app-primary-soft);
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar__link:hover {
|
.sidebar__link:hover {
|
||||||
color: var(--text);
|
color: var(--color-app-text);
|
||||||
background: var(--interactive-hover);
|
background: var(--color-app-interactive-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar__link--active {
|
.sidebar__link--active {
|
||||||
color: var(--primary);
|
color: var(--color-app-primary);
|
||||||
background: var(--interactive-active);
|
background: var(--color-app-interactive-active);
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-shell--collapsed .sidebar {
|
.app-shell--collapsed .sidebar {
|
||||||
@@ -168,7 +187,7 @@
|
|||||||
|
|
||||||
.main-content {
|
.main-content {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
padding: 32px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-header {
|
.page-header {
|
||||||
@@ -188,7 +207,7 @@
|
|||||||
.page-header p {
|
.page-header p {
|
||||||
max-width: 720px;
|
max-width: 720px;
|
||||||
margin: 8px 0 0;
|
margin: 8px 0 0;
|
||||||
color: var(--text-muted);
|
color: var(--color-app-text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-grid {
|
.stat-grid {
|
||||||
@@ -199,10 +218,10 @@
|
|||||||
|
|
||||||
.stat-card,
|
.stat-card,
|
||||||
.content-panel {
|
.content-panel {
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--color-app-border);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
background: var(--surface);
|
background: var(--color-app-surface);
|
||||||
box-shadow: 0 16px 42px var(--shadow-color);
|
box-shadow: var(--shadow-app-panel);
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-card {
|
.stat-card {
|
||||||
@@ -211,7 +230,7 @@
|
|||||||
|
|
||||||
.stat-card span {
|
.stat-card span {
|
||||||
display: block;
|
display: block;
|
||||||
color: var(--text-muted);
|
color: var(--color-app-text-muted);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,7 +252,7 @@
|
|||||||
|
|
||||||
.content-panel p {
|
.content-panel p {
|
||||||
margin: 8px 0 0;
|
margin: 8px 0 0;
|
||||||
color: var(--text-muted);
|
color: var(--color-app-text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 900px) {
|
@media (max-width: 900px) {
|
||||||
@@ -250,7 +269,7 @@
|
|||||||
height: auto;
|
height: auto;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
border-right: 0;
|
border-right: 0;
|
||||||
border-bottom: 1px solid var(--border);
|
border-bottom: 1px solid var(--color-app-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar__brand {
|
.sidebar__brand {
|
||||||
|
|||||||
@@ -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 (
|
||||||
|
<Card
|
||||||
|
variant="default"
|
||||||
|
className="w-full max-w-100 overflow-hidden rounded-lg border border-gray-300 bg-white shadow-none"
|
||||||
|
>
|
||||||
|
{/* Image */}
|
||||||
|
<div className="relative h-48 overflow-hidden border-b border-gray-300">
|
||||||
|
<img src={image} alt={title} className="h-full w-full object-cover" />
|
||||||
|
|
||||||
|
{/* Course code */}
|
||||||
|
<div className="absolute left-4 top-4 rounded-sm border border-gray-300 bg-white px-3 py-1.5">
|
||||||
|
<span className="text-lg font-semibold text-gray-800">{code}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Content */}
|
||||||
|
<Card.Content className="px-5 py-5">
|
||||||
|
<h3 className="mb-3 text-xl font-medium leading-tight text-gray-900">
|
||||||
|
{title}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<p className="line-clamp-2 text-lg leading-8 text-gray-700">
|
||||||
|
{description}
|
||||||
|
</p>
|
||||||
|
</Card.Content>
|
||||||
|
|
||||||
|
{/* Footer */}
|
||||||
|
<Card.Footer className="mx-5 flex items-center justify-between border-t border-gray-300 px-0 py-5">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span
|
||||||
|
className={`rounded-full px-2.5 py-1 text-sm font-medium ${
|
||||||
|
statusStyles[status] ?? 'bg-gray-100 text-gray-600'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{status}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span className="text-sm text-gray-600">Updated {formattedDate}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
<Button
|
||||||
|
isIconOnly
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
aria-label={`Edit ${title}`}
|
||||||
|
>
|
||||||
|
<PencilIcon className="h-5 w-5" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
isIconOnly
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
aria-label={`More actions for ${title}`}
|
||||||
|
>
|
||||||
|
<EllipsisVerticalIcon className="h-5 w-5" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Card.Footer>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CourseCard;
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
function StatGrid({ items }) {
|
|
||||||
return (
|
|
||||||
<section className="stat-grid" aria-label="Metrics">
|
|
||||||
{items.map((item) => (
|
|
||||||
<article className="stat-card" key={item.label}>
|
|
||||||
<span>{item.label}</span>
|
|
||||||
<strong>{item.value}</strong>
|
|
||||||
</article>
|
|
||||||
))}
|
|
||||||
</section>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default StatGrid
|
|
||||||
@@ -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;
|
|
||||||
@@ -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)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
+2
-17
@@ -1,27 +1,12 @@
|
|||||||
:root {
|
: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-width: 264px;
|
||||||
--sidebar-collapsed-width: 88px;
|
--sidebar-collapsed-width: 88px;
|
||||||
|
|
||||||
font-family:
|
font-family:
|
||||||
Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
|
Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
|
||||||
sans-serif;
|
sans-serif;
|
||||||
color: var(--text);
|
color: var(--color-app-text);
|
||||||
background: var(--bg);
|
background: var(--color-app-bg);
|
||||||
font-synthesis: none;
|
font-synthesis: none;
|
||||||
text-rendering: optimizeLegibility;
|
text-rendering: optimizeLegibility;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
|
|||||||
@@ -2,9 +2,6 @@ import { StrictMode } from 'react'
|
|||||||
import { createRoot } from 'react-dom/client'
|
import { createRoot } from 'react-dom/client'
|
||||||
import './index.css'
|
import './index.css'
|
||||||
import App from './App.jsx'
|
import App from './App.jsx'
|
||||||
import { applyThemeCssVariables } from './config/theme.js'
|
|
||||||
|
|
||||||
applyThemeCssVariables()
|
|
||||||
|
|
||||||
createRoot(document.getElementById('root')).render(
|
createRoot(document.getElementById('root')).render(
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
|
|||||||
@@ -1,29 +1,54 @@
|
|||||||
import PageHeader from '../../components/PageHeader.jsx';
|
import CourseCard from '../../components/CourseCard.jsx';
|
||||||
import StatGrid from '../../components/StatGrid.jsx';
|
import {
|
||||||
import { Typography, SearchField, Separator } from '@heroui/react';
|
Typography,
|
||||||
|
SearchField,
|
||||||
|
Separator,
|
||||||
|
Button,
|
||||||
|
Tabs
|
||||||
|
} from '@heroui/react';
|
||||||
import {
|
import {
|
||||||
BellIcon,
|
BellIcon,
|
||||||
QuestionMarkCircleIcon,
|
QuestionMarkCircleIcon,
|
||||||
UserCircleIcon
|
UserCircleIcon,
|
||||||
|
FunnelIcon,
|
||||||
|
PlusIcon
|
||||||
} from '@heroicons/react/16/solid';
|
} from '@heroicons/react/16/solid';
|
||||||
|
|
||||||
const stats = [
|
const stats = [
|
||||||
{ label: 'Khoa hoc dang mo', value: '24' },
|
{
|
||||||
{ label: 'Hoc vien', value: '1,248' },
|
code: 'LDR-101',
|
||||||
{ label: 'Lop trong tuan', value: '18' },
|
title: 'Foundations of Modern Leadership',
|
||||||
{ label: 'Ty le hoan thanh', value: '82%' }
|
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() {
|
function DashboardPage() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* <PageHeader
|
|
||||||
title="Tong quan"
|
|
||||||
description="Theo doi nhanh tinh hinh dao tao va cac chi so LMS."
|
|
||||||
/> */}
|
|
||||||
<div className="mb-3 flex flex-row items-center justify-between">
|
<div className="mb-3 flex flex-row items-center justify-between">
|
||||||
<SearchField name="search">
|
<SearchField name="search">
|
||||||
<SearchField.Group className="w-[280px]">
|
<SearchField.Group className="rounded-xl border border-gray-300 w-100">
|
||||||
<SearchField.SearchIcon />
|
<SearchField.SearchIcon />
|
||||||
|
|
||||||
<SearchField.Input
|
<SearchField.Input
|
||||||
@@ -34,22 +59,90 @@ function DashboardPage() {
|
|||||||
<SearchField.ClearButton />
|
<SearchField.ClearButton />
|
||||||
</SearchField.Group>
|
</SearchField.Group>
|
||||||
</SearchField>
|
</SearchField>
|
||||||
<div className="flex flex-row items-center gap-2">
|
<div className="flex flex-row items-center gap-5">
|
||||||
<BellIcon className="mr-1 inline h-6 w-6" />
|
<BellIcon className="mr-1 inline h-6 w-6" />
|
||||||
<QuestionMarkCircleIcon className="mr-1 inline h-6 w-6" />
|
<QuestionMarkCircleIcon className="mr-1 inline h-6 w-6" />
|
||||||
<UserCircleIcon className="mr-1 inline h-6 w-6" />
|
<UserCircleIcon className="mr-1 inline h-6 w-6" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Separator className="my-4" />
|
<Separator className="my-4" />
|
||||||
<div className="mb-4">
|
<div className="mb-4 flex flex-row items-center justify-between">
|
||||||
<Typography variant="h3" className="mb-2">
|
<div>
|
||||||
Course
|
<Typography variant="h3" className="mb-2">
|
||||||
</Typography>
|
Course
|
||||||
<Typography variant="body1" className="text-gray-600">
|
</Typography>
|
||||||
Manage and organize your learning content.
|
<Typography variant="body1" className="text-gray-600">
|
||||||
</Typography>
|
Manage and organize your learning content.
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-row item-center gap-2">
|
||||||
|
<Button variant="outline" className="rounded-lg">
|
||||||
|
<FunnelIcon />
|
||||||
|
Filter
|
||||||
|
</Button>
|
||||||
|
<Button className="rounded-lg">
|
||||||
|
<PlusIcon />
|
||||||
|
New Course
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Separator className="my-4" />
|
||||||
|
<div className="flex flex-row items-center justify-between my-3 bg-white rounded-md border p-3">
|
||||||
|
<Tabs defaultSelectedKey="all" className="w-fit">
|
||||||
|
<Tabs.ListContainer>
|
||||||
|
<Tabs.List
|
||||||
|
aria-label="Course status"
|
||||||
|
className="gap-1 rounded-md bg-gray-100"
|
||||||
|
>
|
||||||
|
<Tabs.Tab
|
||||||
|
id="all"
|
||||||
|
className="h-7 rounded px-6 py-5 text-base font-normal text-gray-700"
|
||||||
|
>
|
||||||
|
All
|
||||||
|
<Tabs.Indicator className="rounded bg-white shadow-sm" />
|
||||||
|
</Tabs.Tab>
|
||||||
|
|
||||||
|
<Tabs.Tab
|
||||||
|
id="draft"
|
||||||
|
className="h-7 rounded px-6 py-5 text-base font-normal text-gray-500"
|
||||||
|
>
|
||||||
|
Draft
|
||||||
|
<Tabs.Indicator className="rounded bg-white shadow-sm" />
|
||||||
|
</Tabs.Tab>
|
||||||
|
|
||||||
|
<Tabs.Tab
|
||||||
|
id="published"
|
||||||
|
className="h-7 rounded px-6 py-5 text-base font-normal text-gray-500"
|
||||||
|
>
|
||||||
|
Published
|
||||||
|
<Tabs.Indicator className="rounded bg-white shadow-sm" />
|
||||||
|
</Tabs.Tab>
|
||||||
|
|
||||||
|
<Tabs.Tab
|
||||||
|
id="archived"
|
||||||
|
className="h-7 rounded px-6 py-5 text-base font-normal text-gray-500"
|
||||||
|
>
|
||||||
|
Archived
|
||||||
|
<Tabs.Indicator className="rounded bg-white shadow-sm" />
|
||||||
|
</Tabs.Tab>
|
||||||
|
</Tabs.List>
|
||||||
|
</Tabs.ListContainer>
|
||||||
|
</Tabs>
|
||||||
|
<SearchField name="search">
|
||||||
|
<SearchField.Group className="rounded-xl border border-gray-300 w-100">
|
||||||
|
<SearchField.SearchIcon />
|
||||||
|
|
||||||
|
<SearchField.Input placeholder="Search course by title or code..." />
|
||||||
|
|
||||||
|
<SearchField.ClearButton />
|
||||||
|
</SearchField.Group>
|
||||||
|
</SearchField>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-1 gap-5 md:grid-cols-2 xl:grid-cols-4">
|
||||||
|
{stats.map((course) => (
|
||||||
|
<CourseCard key={course.code} course={course} image={courseImage} />
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
<StatGrid items={stats} />
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user