upd: tampilan dark dan light

This commit is contained in:
2026-04-02 11:59:21 +08:00
parent 5136342877
commit ac17e059c7
6 changed files with 68 additions and 44 deletions

View File

@@ -4,38 +4,38 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { createRouter, RouterProvider } from '@tanstack/react-router' import { createRouter, RouterProvider } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen' import { routeTree } from './routeTree.gen'
const theme = createTheme({ const theme = createTheme({
primaryColor: 'brand-blue', primaryColor: 'brand-blue',
colors: { colors: {
'brand-blue': [ 'brand-blue': [
'#ebf2ff', '#f0f9ff',
'#d6e4ff', '#e0f2fe',
'#adc8ff', '#bae6fd',
'#85acff', '#7dd3fc',
'#5c90ff', '#38bdf8',
'#2563eb', // Primary Blue '#0ea5e9', // Primary Blue (Sky)
'#1e4fb8', '#0284c7',
'#173b85', '#0369a1',
'#102752', '#075985',
'#09131f', '#0c4a6e',
], ],
'brand-purple': [ 'brand-purple': [
'#f3ebff', '#faf5ff',
'#e7d6ff', '#f3e8ff',
'#cfadff', '#e9d5ff',
'#b785ff', '#d8b4fe',
'#9f5cff', '#c084fc',
'#7c3aed', // Primary Purple '#a855f7', // Primary Purple
'#632eb8', '#9333ea',
'#4a2285', '#7e22ce',
'#311652', '#6b21a8',
'#180b1f', '#581c87',
], ],
}, },
fontFamily: 'Inter, system-ui, Avenir, Helvetica, Arial, sans-serif', fontFamily: 'Inter, system-ui, Avenir, Helvetica, Arial, sans-serif',
headings: { headings: {
fontFamily: 'Inter, system-ui, sans-serif', fontFamily: 'Inter, system-ui, sans-serif',
fontWeight: '600', fontWeight: '500', // Softer headings
}, },
}) })
@@ -59,8 +59,8 @@ declare module '@tanstack/react-router' {
export function App() { export function App() {
return ( return (
<> <>
<ColorSchemeScript defaultColorScheme="dark" /> <ColorSchemeScript defaultColorScheme="auto" />
<MantineProvider theme={theme} defaultColorScheme="dark" forceColorScheme="dark"> <MantineProvider theme={theme} defaultColorScheme="auto">
<QueryClientProvider client={queryClient}> <QueryClientProvider client={queryClient}>
<RouterProvider router={router} /> <RouterProvider router={router} />
</QueryClientProvider> </QueryClientProvider>

View File

@@ -1,4 +1,4 @@
import { Card, Group, Text, ThemeIcon, Badge, Avatar, Stack, Button, Progress, Box } from '@mantine/core' import { Card, Group, Text, ThemeIcon, Badge, Avatar, Stack, Button, Progress, Box, useComputedColorScheme } from '@mantine/core'
import { Link } from '@tanstack/react-router' import { Link } from '@tanstack/react-router'
import { TbDeviceMobile, TbActivity, TbAlertTriangle, TbChevronRight } from 'react-icons/tb' import { TbDeviceMobile, TbActivity, TbAlertTriangle, TbChevronRight } from 'react-icons/tb'
@@ -13,6 +13,7 @@ interface AppCardProps {
export function AppCard({ id, name, status, users, errors, version }: AppCardProps) { export function AppCard({ id, name, status, users, errors, version }: AppCardProps) {
const statusColor = status === 'active' ? 'teal' : status === 'warning' ? 'orange' : 'red' const statusColor = status === 'active' ? 'teal' : status === 'warning' ? 'orange' : 'red'
const scheme = useComputedColorScheme('light', { getInitialValueInEffect: true })
return ( return (
<Card <Card
@@ -22,12 +23,12 @@ export function AppCard({ id, name, status, users, errors, version }: AppCardPro
className="premium-card glass" className="premium-card glass"
styles={(theme) => ({ styles={(theme) => ({
root: { root: {
backgroundColor: 'rgba(30, 41, 59, 0.4)', backgroundColor: 'var(--mantine-color-body)',
borderColor: 'rgba(255,255,255,0.08)', borderColor: scheme === 'dark' ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.05)',
transition: 'transform 0.2s ease, box-shadow 0.2s ease', transition: 'transform 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease, border-color 0.2s ease',
'&:hover': { '&:hover': {
transform: 'translateY(-4px)', transform: 'translateY(-4px)',
boxShadow: '0 12px 24px -8px rgba(0, 0, 0, 0.4)', boxShadow: theme.shadows.md,
borderColor: 'rgba(37, 99, 235, 0.3)', borderColor: 'rgba(37, 99, 235, 0.3)',
}, },
}, },

View File

@@ -1,5 +1,6 @@
import { APP_CONFIGS } from '@/frontend/config/appMenus' import { APP_CONFIGS } from '@/frontend/config/appMenus'
import { import {
ActionIcon,
AppShell, AppShell,
Avatar, Avatar,
Box, Box,
@@ -14,6 +15,7 @@ import {
ThemeIcon ThemeIcon
} from '@mantine/core' } from '@mantine/core'
import { useDisclosure } from '@mantine/hooks' import { useDisclosure } from '@mantine/hooks'
import { useMantineColorScheme, useComputedColorScheme } from '@mantine/core'
import { Link, useLocation, useMatches, useNavigate, useParams } from '@tanstack/react-router' import { Link, useLocation, useMatches, useNavigate, useParams } from '@tanstack/react-router'
import { import {
TbApps, TbApps,
@@ -23,7 +25,9 @@ import {
TbDeviceMobile, TbDeviceMobile,
TbLogout, TbLogout,
TbSettings, TbSettings,
TbUserCircle TbUserCircle,
TbSun,
TbMoon
} from 'react-icons/tb' } from 'react-icons/tb'
interface DashboardLayoutProps { interface DashboardLayoutProps {
@@ -31,7 +35,10 @@ interface DashboardLayoutProps {
} }
export function DashboardLayout({ children }: DashboardLayoutProps) { export function DashboardLayout({ children }: DashboardLayoutProps) {
const [opened, { toggle }] = useDisclosure() const [mobileOpened, { toggle: toggleMobile }] = useDisclosure()
const [desktopOpened, { toggle: toggleDesktop }] = useDisclosure(true)
const { toggleColorScheme } = useMantineColorScheme()
const computedColorScheme = useComputedColorScheme('light', { getInitialValueInEffect: true })
const location = useLocation() const location = useLocation()
const navigate = useNavigate() const navigate = useNavigate()
const { appId } = useParams({ strict: false }) as { appId?: string } const { appId } = useParams({ strict: false }) as { appId?: string }
@@ -54,19 +61,21 @@ export function DashboardLayout({ children }: DashboardLayoutProps) {
navbar={{ navbar={{
width: 260, width: 260,
breakpoint: 'sm', breakpoint: 'sm',
collapsed: { mobile: !opened }, collapsed: { mobile: !mobileOpened, desktop: !desktopOpened },
}} }}
padding="xl" padding="xl"
styles={(theme) => ({ styles={(theme) => ({
main: { main: {
backgroundColor: theme.colors.dark[7], // Dark mode background backgroundColor: computedColorScheme === 'dark' ? theme.colors.dark[9] : theme.colors.gray[0],
transition: 'background-color 0.2s ease',
}, },
})} })}
> >
<AppShell.Header px="xl"> <AppShell.Header px="xl">
<Group h="100%" justify="space-between"> <Group h="100%" justify="space-between">
<Group> <Group>
<Burger opened={opened} onClick={toggle} hiddenFrom="sm" size="sm" /> <Burger opened={mobileOpened} onClick={toggleMobile} hiddenFrom="sm" size="sm" />
<Burger opened={desktopOpened} onClick={toggleDesktop} visibleFrom="sm" size="sm" />
<Group gap="xs"> <Group gap="xs">
<ThemeIcon <ThemeIcon
size={34} size={34}
@@ -88,6 +97,14 @@ export function DashboardLayout({ children }: DashboardLayoutProps) {
</Group> </Group>
<Group gap="md"> <Group gap="md">
<ActionIcon
onClick={() => toggleColorScheme()}
variant="default"
size="lg"
aria-label="Toggle color scheme"
>
{computedColorScheme === 'dark' ? <TbSun size={18} /> : <TbMoon size={18} />}
</ActionIcon>
<Menu shadow="md" width={200} position="bottom-end"> <Menu shadow="md" width={200} position="bottom-end">
<Menu.Target> <Menu.Target>
<Avatar <Avatar

View File

@@ -22,8 +22,8 @@ export function StatsCard({ title, value, description, icon: Icon, color, trend
className="premium-card" className="premium-card"
styles={(theme) => ({ styles={(theme) => ({
root: { root: {
backgroundColor: theme.colors.dark[6], backgroundColor: 'var(--mantine-color-body)',
borderColor: 'rgba(255,255,255,0.05)', borderColor: 'rgba(128,128,128,0.1)',
}, },
})} })}
> >

View File

@@ -1,4 +1,4 @@
import { Card, Group, Text, ThemeIcon, Stack, Progress, Badge } from '@mantine/core' import { Card, Group, Text, ThemeIcon, Stack, Progress, Badge, useComputedColorScheme } from '@mantine/core'
import { IconType } from 'react-icons' import { IconType } from 'react-icons'
import { TbTrendingUp, TbTrendingDown } from 'react-icons/tb' import { TbTrendingUp, TbTrendingDown } from 'react-icons/tb'
@@ -27,6 +27,8 @@ export function SummaryCard({
progress, progress,
isError isError
}: SummaryCardProps) { }: SummaryCardProps) {
const scheme = useComputedColorScheme('light', { getInitialValueInEffect: true })
return ( return (
<Card <Card
withBorder withBorder
@@ -35,9 +37,13 @@ export function SummaryCard({
className="glass" className="glass"
styles={(theme) => ({ styles={(theme) => ({
root: { root: {
backgroundColor: isError && Number(value) > 0 ? 'rgba(239, 68, 68, 0.05)' : 'rgba(30, 41, 59, 0.4)', backgroundColor: isError && Number(value) > 0
borderColor: isError && Number(value) > 10 ? 'rgba(239, 68, 68, 0.3)' : 'rgba(255, 255, 255, 0.08)', ? (scheme === 'dark' ? 'rgba(239, 68, 68, 0.1)' : 'rgba(255, 241, 242, 1)') // light pink for error in light mode
transition: 'transform 0.2s ease', : 'var(--mantine-color-body)',
borderColor: isError && Number(value) > 10
? 'rgba(239, 68, 68, 0.3)'
: scheme === 'dark' ? 'rgba(255, 255, 255, 0.08)' : 'rgba(0, 0, 0, 0.05)',
transition: 'transform 0.2s ease, background-color 0.2s ease, border-color 0.2s ease',
'&:hover': { '&:hover': {
transform: 'translateY(-4px)', transform: 'translateY(-4px)',
} }

View File

@@ -27,8 +27,8 @@ html, body {
height: 100%; height: 100%;
width: 100%; width: 100%;
font-family: var(--font-inter); font-family: var(--font-inter);
background-color: var(--bg-dark); /* Default to Dark Mode as per App.tsx */ /* background-color handled by Mantine */
color: #F8FAFC; color: var(--mantine-color-text);
} }
body { body {
@@ -53,9 +53,9 @@ body {
/* Premium Dashboard Utilities */ /* Premium Dashboard Utilities */
.glass { .glass {
background: rgba(30, 41, 59, 0.7); background: var(--mantine-color-default);
backdrop-filter: blur(12px); backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.1); border: 1px solid rgba(128, 128, 128, 0.1);
border-radius: 24px; /* XL rounding for cards */ border-radius: 24px; /* XL rounding for cards */
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
} }