feat: Integrate Mantine UI library, establish a theme provider, and refactor core UI components.
This commit is contained in:
@@ -3,9 +3,11 @@
|
||||
"version": "0.0.0",
|
||||
"exports": {
|
||||
"./theme.css": "./src/theme.css",
|
||||
"./components/*": "./src/components/*.tsx",
|
||||
"./components/system-pages/*": "./src/components/system-pages/*.tsx",
|
||||
"./components/*": "./src/components/*.ts",
|
||||
"./hooks/*": "./src/hooks/*.ts",
|
||||
"./utils/*": "./src/utils/*.ts"
|
||||
"./utils/*": "./src/utils/*.ts",
|
||||
"./provider": "./src/provider/index.ts"
|
||||
},
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
@@ -18,6 +20,8 @@
|
||||
"react-dom": "^19.2.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@mantine/core": "^8.3.15",
|
||||
"@mantine/hooks": "^8.3.15",
|
||||
"@repo/utils": "workspace:*",
|
||||
"dayjs": "^1.11.19",
|
||||
"tailwind-merge": "^3.4.0",
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export { Button, type ButtonProps } from '@mantine/core';
|
||||
@@ -0,0 +1 @@
|
||||
export { Card, type CardProps } from '@mantine/core';
|
||||
@@ -0,0 +1 @@
|
||||
export { Checkbox, type CheckboxProps } from '@mantine/core';
|
||||
@@ -0,0 +1 @@
|
||||
export { Container, type ContainerProps } from '@mantine/core';
|
||||
@@ -0,0 +1 @@
|
||||
export { Group, type GroupProps, Stack, type StackProps } from '@mantine/core';
|
||||
@@ -0,0 +1 @@
|
||||
export { TextInput, type TextInputProps } from '@mantine/core';
|
||||
@@ -0,0 +1 @@
|
||||
export { Select, type SelectProps } from '@mantine/core';
|
||||
@@ -2,35 +2,32 @@ interface ComingSoonProps {
|
||||
showActions?: boolean;
|
||||
}
|
||||
|
||||
export function ComingSoon(props: ComingSoonProps) {
|
||||
const { showActions = false } = props;
|
||||
import { Title, Text, Button, Container, Stack, Center } from '@mantine/core';
|
||||
|
||||
export function ComingSoon({ showActions = false }: ComingSoonProps) {
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center bg-white px-4">
|
||||
<div className="w-full max-w-md text-center">
|
||||
{/* Code */}
|
||||
<p className="text-sm font-medium uppercase tracking-widest text-gray-400">Coming Soon</p>
|
||||
<Container size="sm" h="100vh" pos="relative">
|
||||
<Center h="100%">
|
||||
<Stack align="center" ta="center" gap="md">
|
||||
<Text size="sm" fw={500} tt="uppercase" c="dimmed" lts="var(--mantine-spacing-xs)">
|
||||
Coming Soon
|
||||
</Text>
|
||||
|
||||
{/* Title */}
|
||||
<h1 className="mt-3 text-6xl font-extrabold text-brand-900">Feature in Progress</h1>
|
||||
<Title order={1} fw={900} c="brand">
|
||||
Feature in Progress
|
||||
</Title>
|
||||
|
||||
{/* Description */}
|
||||
<p className="mt-4 text-base text-gray-500">
|
||||
This feature is currently under development. Stay tuned! We'll have it ready for you very soon.
|
||||
</p>
|
||||
<Text size="md" c="dimmed">
|
||||
This feature is currently under development. Stay tuned! We'll have it ready for you very soon.
|
||||
</Text>
|
||||
|
||||
{/* Actions */}
|
||||
{showActions && (
|
||||
<div className="mt-8 flex justify-center gap-3">
|
||||
<a
|
||||
href="/"
|
||||
className="rounded-md bg-brand-500 px-5 py-2.5 text-sm font-medium text-white hover:bg-brand-400"
|
||||
>
|
||||
{showActions && (
|
||||
<Button component="a" href="/" color="brand" size="md" mt="xl">
|
||||
Back to Home
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Button>
|
||||
)}
|
||||
</Stack>
|
||||
</Center>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,47 +3,43 @@ interface ForbiddenProps {
|
||||
showActionsHome?: boolean;
|
||||
}
|
||||
|
||||
export function Forbidden(props: ForbiddenProps) {
|
||||
const { showActionsBack = true, showActionsHome = true } = props;
|
||||
import { Title, Text, Button, Container, Stack, Group, Center } from '@mantine/core';
|
||||
|
||||
export function Forbidden({ showActionsBack = true, showActionsHome = true }: ForbiddenProps) {
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center bg-white px-4">
|
||||
<div className="w-full max-w-md text-center">
|
||||
{/* Code */}
|
||||
<p className="text-sm font-medium uppercase tracking-widest text-gray-400">403 Error</p>
|
||||
<Container size="sm" h="100vh" pos="relative">
|
||||
<Center h="100%">
|
||||
<Stack align="center" ta="center" gap="md">
|
||||
<Text size="sm" fw={500} tt="uppercase" c="dimmed" lts="var(--mantine-spacing-xs)">
|
||||
403 Error
|
||||
</Text>
|
||||
|
||||
{/* Title */}
|
||||
<h1 className="mt-3 text-6xl font-extrabold text-brand-900">Access Denied</h1>
|
||||
<Title order={1} fw={900} c="brand">
|
||||
Access Denied
|
||||
</Title>
|
||||
|
||||
{/* Description */}
|
||||
<p className="mt-4 text-base text-gray-500">
|
||||
Sorry, you don’t have permission to access this page. Please contact your administrator if you believe this is
|
||||
a mistake.
|
||||
</p>
|
||||
<Text size="md" c="dimmed">
|
||||
Sorry, you don’t have permission to access this page. Please contact your administrator if you believe this
|
||||
is a mistake.
|
||||
</Text>
|
||||
|
||||
{/* Actions */}
|
||||
{(showActionsBack || showActionsHome) && (
|
||||
<div className="mt-8 flex justify-center gap-3">
|
||||
{showActionsBack && (
|
||||
<button
|
||||
onClick={() => window.history.back()}
|
||||
className="rounded-md border border-gray-300 px-5 py-2.5 text-sm font-medium text-gray-700 hover:bg-gray-100 cursor-pointer"
|
||||
>
|
||||
Go Back
|
||||
</button>
|
||||
)}
|
||||
{(showActionsBack || showActionsHome) && (
|
||||
<Group mt="xl" justify="center">
|
||||
{showActionsBack && (
|
||||
<Button variant="default" size="md" onClick={() => window.history.back()}>
|
||||
Go Back
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{showActionsHome && (
|
||||
<a
|
||||
href="/"
|
||||
className="rounded-md bg-brand-500 px-5 py-2.5 text-sm font-medium text-white hover:bg-brand-400"
|
||||
>
|
||||
Back to Home
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{showActionsHome && (
|
||||
<Button component="a" href="/" color="brand" size="md">
|
||||
Back to Home
|
||||
</Button>
|
||||
)}
|
||||
</Group>
|
||||
)}
|
||||
</Stack>
|
||||
</Center>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,36 +2,33 @@ interface MaintenanceProps {
|
||||
showActions?: boolean;
|
||||
}
|
||||
|
||||
export function Maintenance(props: MaintenanceProps) {
|
||||
const { showActions = false } = props;
|
||||
import { Title, Text, Button, Container, Stack, Center } from '@mantine/core';
|
||||
|
||||
export function Maintenance({ showActions = false }: MaintenanceProps) {
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center bg-white px-4">
|
||||
<div className="w-full max-w-md text-center">
|
||||
{/* Code */}
|
||||
<p className="text-sm font-medium uppercase tracking-widest text-gray-400">Maintenance</p>
|
||||
<Container size="sm" h="100vh" pos="relative">
|
||||
<Center h="100%">
|
||||
<Stack align="center" ta="center" gap="md">
|
||||
<Text size="sm" fw={500} tt="uppercase" c="dimmed" lts="var(--mantine-spacing-xs)">
|
||||
Maintenance
|
||||
</Text>
|
||||
|
||||
{/* Title */}
|
||||
<h1 className="mt-3 text-6xl font-extrabold text-brand-900">We'll Be Back Soon</h1>
|
||||
<Title order={1} fw={900} c="brand">
|
||||
We'll Be Back Soon
|
||||
</Title>
|
||||
|
||||
{/* Description */}
|
||||
<p className="mt-4 text-base text-gray-500">
|
||||
Our system is currently undergoing scheduled maintenance. We are working hard to bring it back online as soon
|
||||
as possible.
|
||||
</p>
|
||||
<Text size="md" c="dimmed">
|
||||
Our system is currently undergoing scheduled maintenance. We are working hard to bring it back online as
|
||||
soon as possible.
|
||||
</Text>
|
||||
|
||||
{/* Optional Actions */}
|
||||
{showActions && (
|
||||
<div className="mt-8 flex justify-center gap-3">
|
||||
<a
|
||||
href="/"
|
||||
className="rounded-md bg-brand-500 px-5 py-2.5 text-sm font-medium text-white hover:bg-brand-400"
|
||||
>
|
||||
{showActions && (
|
||||
<Button component="a" href="/" color="brand" size="md" mt="xl">
|
||||
Back to Home
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Button>
|
||||
)}
|
||||
</Stack>
|
||||
</Center>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,42 +3,42 @@ interface NotFoundProps {
|
||||
showActionsHome?: boolean;
|
||||
}
|
||||
|
||||
export function NotFound(props: NotFoundProps) {
|
||||
const { showActionsBack = true, showActionsHome = true } = props;
|
||||
import { Title, Text, Button, Container, Stack, Group, Center } from '@mantine/core';
|
||||
|
||||
export function NotFound({ showActionsBack = true, showActionsHome = true }: NotFoundProps) {
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center bg-white px-4">
|
||||
<div className="w-full max-w-md text-center">
|
||||
<p className="text-sm font-medium uppercase tracking-widest text-gray-400">404 Error</p>
|
||||
<Container size="sm" h="100vh" pos="relative">
|
||||
<Center h="100%">
|
||||
<Stack align="center" ta="center" gap="md">
|
||||
<Text size="sm" fw={500} tt="uppercase" c="dimmed" lts="var(--mantine-spacing-xs)">
|
||||
404 Error
|
||||
</Text>
|
||||
|
||||
<h1 className="mt-3 text-6xl font-extrabold text-brand-900">Page Not Found</h1>
|
||||
<Title order={1} fw={900} c="brand">
|
||||
Page Not Found
|
||||
</Title>
|
||||
|
||||
<p className="mt-4 text-base text-gray-500">
|
||||
Sorry, the page you’re looking for doesn’t exist or has been moved.
|
||||
</p>
|
||||
<Text size="md" c="dimmed">
|
||||
Sorry, the page you’re looking for doesn’t exist or has been moved.
|
||||
</Text>
|
||||
|
||||
{(showActionsBack || showActionsHome) && (
|
||||
<div className="mt-8 flex justify-center gap-3">
|
||||
{showActionsBack && (
|
||||
<button
|
||||
onClick={() => window.history.back()}
|
||||
className="rounded-md border border-gray-300 px-5 py-2.5 text-sm font-medium text-gray-700 hover:bg-gray-100 cursor-pointer"
|
||||
>
|
||||
Go Back
|
||||
</button>
|
||||
)}
|
||||
{(showActionsBack || showActionsHome) && (
|
||||
<Group mt="xl" justify="center">
|
||||
{showActionsBack && (
|
||||
<Button variant="default" size="md" onClick={() => window.history.back()}>
|
||||
Go Back
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{showActionsHome && (
|
||||
<a
|
||||
href="/"
|
||||
className="rounded-md bg-brand-500 px-5 py-2.5 text-sm font-medium text-white hover:bg-brand-400"
|
||||
>
|
||||
Back to Home
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{showActionsHome && (
|
||||
<Button component="a" href="/" color="brand" size="md">
|
||||
Back to Home
|
||||
</Button>
|
||||
)}
|
||||
</Group>
|
||||
)}
|
||||
</Stack>
|
||||
</Center>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export { Text, type TextProps, Title, type TitleProps } from '@mantine/core';
|
||||
@@ -0,0 +1 @@
|
||||
export * from './theme-provider';
|
||||
@@ -0,0 +1,70 @@
|
||||
import { MantineProvider, createTheme, MantineThemeOverride } from '@mantine/core';
|
||||
import React from 'react';
|
||||
import { brandColors, errorColors, warningColors, successColors, infoColors, draculaColors, blueColors } from '../theme/tokens/colors';
|
||||
import { typography } from '../theme/tokens/typography';
|
||||
import { radius } from '../theme/tokens/radius';
|
||||
|
||||
export type ColorSchemeType = 'light' | 'dark' | 'dracula' | 'blue';
|
||||
export type DensityType = 'compact' | 'standard' | 'spacious';
|
||||
|
||||
interface ThemeProviderProps {
|
||||
children: React.ReactNode;
|
||||
colorScheme?: ColorSchemeType;
|
||||
density?: DensityType;
|
||||
}
|
||||
|
||||
export function ThemeProvider({ children, colorScheme = 'light', density = 'standard' }: ThemeProviderProps) {
|
||||
const densityStyles = {
|
||||
compact: {
|
||||
spacing: { xs: '0.25rem', sm: '0.5rem', md: '0.75rem', lg: '1rem', xl: '1.25rem' },
|
||||
},
|
||||
standard: {
|
||||
spacing: { xs: '0.5rem', sm: '0.75rem', md: '1rem', lg: '1.5rem', xl: '2rem' },
|
||||
},
|
||||
spacious: {
|
||||
spacing: { xs: '0.75rem', sm: '1rem', md: '1.5rem', lg: '2rem', xl: '3rem' },
|
||||
}
|
||||
};
|
||||
|
||||
const baseTheme = createTheme({
|
||||
colors: {
|
||||
brand: brandColors,
|
||||
error: errorColors,
|
||||
warning: warningColors,
|
||||
success: successColors,
|
||||
info: infoColors,
|
||||
dracula: draculaColors,
|
||||
bluetheme: blueColors,
|
||||
},
|
||||
primaryColor: 'brand',
|
||||
fontFamily: typography.fontFamily,
|
||||
headings: typography.headings,
|
||||
spacing: densityStyles[density].spacing,
|
||||
radius: radius,
|
||||
});
|
||||
|
||||
let mantineColorScheme: 'light' | 'dark' = 'light';
|
||||
let themeOverride: MantineThemeOverride = baseTheme;
|
||||
|
||||
if (colorScheme === 'dark') {
|
||||
mantineColorScheme = 'dark';
|
||||
} else if (colorScheme === 'dracula') {
|
||||
mantineColorScheme = 'dark';
|
||||
themeOverride = createTheme({
|
||||
...baseTheme,
|
||||
primaryColor: 'dracula',
|
||||
});
|
||||
} else if (colorScheme === 'blue') {
|
||||
mantineColorScheme = 'light';
|
||||
themeOverride = createTheme({
|
||||
...baseTheme,
|
||||
primaryColor: 'bluetheme',
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<MantineProvider theme={themeOverride} forceColorScheme={mantineColorScheme} defaultColorScheme={mantineColorScheme}>
|
||||
{children}
|
||||
</MantineProvider>
|
||||
);
|
||||
}
|
||||
+6
-208
@@ -1,219 +1,17 @@
|
||||
@import 'tailwindcss';
|
||||
@source "../src";
|
||||
|
||||
/* =========================================
|
||||
THEME VARIABLES (CENTRALIZED)
|
||||
MANTINE BASE STYLES
|
||||
========================================= */
|
||||
@theme {
|
||||
/* -------------------------------
|
||||
COLORS: PALETTE
|
||||
------------------------------- */
|
||||
/* Brand (Purple based on your code) */
|
||||
--color-brand-50: #f5f3fd;
|
||||
--color-brand-100: #e6dbfb;
|
||||
--color-brand-200: #d0b6f8;
|
||||
--color-brand-300: #b78ff5;
|
||||
--color-brand-400: #9f64f1;
|
||||
--color-brand-500: #7d39ed; /* Primary */
|
||||
--color-brand-600: #652ed9;
|
||||
--color-brand-700: #4a23a5;
|
||||
--color-brand-800: #321a7a;
|
||||
--color-brand-900: #1b0f4a;
|
||||
|
||||
/* Neutrals */
|
||||
--color-gray-50: #f5f6f7;
|
||||
--color-gray-100: #eceff1;
|
||||
--color-gray-200: #e0e3e7;
|
||||
--color-gray-300: #d1d5db;
|
||||
--color-gray-400: #9ca3af;
|
||||
--color-gray-500: #6b7280;
|
||||
--color-gray-600: #4b5563;
|
||||
--color-gray-700: #374151;
|
||||
--color-gray-800: #1f2937;
|
||||
--color-gray-900: #111827;
|
||||
|
||||
/* -------------------------------
|
||||
COLORS: SEMANTICS (COMPLETED)
|
||||
------------------------------- */
|
||||
|
||||
/* Error (Red) */
|
||||
--color-error-50: #fef2f2;
|
||||
--color-error-100: #fee2e2;
|
||||
--color-error-200: #fecaca;
|
||||
--color-error-300: #fca5a5;
|
||||
--color-error-400: #f87171;
|
||||
--color-error-500: #ef4444;
|
||||
--color-error-600: #dc2626;
|
||||
--color-error-700: #b91c1c;
|
||||
--color-error-800: #991b1b;
|
||||
--color-error-900: #7f1d1d;
|
||||
|
||||
/* Warning (Amber/Orange) */
|
||||
--color-warning-50: #fffbeb;
|
||||
--color-warning-100: #fef3c7;
|
||||
--color-warning-200: #fde68a;
|
||||
--color-warning-300: #fcd34d;
|
||||
--color-warning-400: #fbbf24;
|
||||
--color-warning-500: #f59e0b;
|
||||
--color-warning-600: #d97706;
|
||||
--color-warning-700: #b45309;
|
||||
--color-warning-800: #92400e;
|
||||
--color-warning-900: #78350f;
|
||||
|
||||
/* Success (Green) */
|
||||
--color-success-50: #f0fdf4;
|
||||
--color-success-100: #dcfce7;
|
||||
--color-success-200: #bbf7d0;
|
||||
--color-success-300: #86efac;
|
||||
--color-success-400: #4ade80;
|
||||
--color-success-500: #22c55e;
|
||||
--color-success-600: #16a34a;
|
||||
--color-success-700: #15803d;
|
||||
--color-success-800: #166534;
|
||||
--color-success-900: #14532d;
|
||||
|
||||
/* Info (Blue/Sky) */
|
||||
--color-info-50: #f0f9ff;
|
||||
--color-info-100: #e0f2fe;
|
||||
--color-info-200: #bae6fd;
|
||||
--color-info-300: #7dd3fc;
|
||||
--color-info-400: #38bdf8;
|
||||
--color-info-500: #0ea5e9;
|
||||
--color-info-600: #0284c7;
|
||||
--color-info-700: #0369a1;
|
||||
--color-info-800: #075985;
|
||||
--color-info-900: #0c4a6e;
|
||||
|
||||
/* -------------------------------
|
||||
BASE FONT & TYPOGRAPHY
|
||||
------------------------------- */
|
||||
--base-font-size: 13px;
|
||||
|
||||
/* Scale */
|
||||
--text-xs: calc(var(--base-font-size) * 0.846); /* ~11px */
|
||||
--text-sm: calc(var(--base-font-size) * 0.923); /* ~12px */
|
||||
--text-base: var(--base-font-size); /* 13px */
|
||||
--text-lg: calc(var(--base-font-size) * 1.154); /* ~15px */
|
||||
--text-xl: calc(var(--base-font-size) * 1.385); /* ~18px */
|
||||
--text-2xl: calc(var(--base-font-size) * 1.692); /* ~22px */
|
||||
|
||||
/* Weights */
|
||||
--font-weight-normal: 400;
|
||||
--font-weight-medium: 500;
|
||||
--font-weight-semibold: 600;
|
||||
--font-weight-bold: 700;
|
||||
|
||||
/* -------------------------------
|
||||
SHAPE & DEPTH
|
||||
------------------------------- */
|
||||
--radius-sm: 0.125rem; /* 2px */
|
||||
--radius-md: 0.25rem; /* 4px */
|
||||
--radius-lg: 0.5rem; /* 8px */
|
||||
--radius-xl: 0.75rem; /* 12px */
|
||||
|
||||
/* -------------------------------
|
||||
FORM ITEM SPECIFICS
|
||||
------------------------------- */
|
||||
/* Form Item Spacing */
|
||||
--form-item-margin-bottom: 1.25rem; /* 20px */
|
||||
|
||||
/* Label Configuration */
|
||||
--form-label-font-size: var(--text-sm); /* Uses scale text-sm (~12px) */
|
||||
--form-label-color: var(--color-gray-700);
|
||||
--form-label-font-weight: var(--font-weight-medium);
|
||||
--form-label-margin-bottom: 0.375rem; /* ~6px */
|
||||
|
||||
/* Error/Warning Message Configuration */
|
||||
--form-msg-font-size: var(--text-xs); /* Uses scale text-xs (~11px) */
|
||||
--form-msg-margin-top: 0.375rem; /* ~6px */
|
||||
|
||||
--input-height: 2.6rem; /* ~34px */
|
||||
--input-font-size: var(--text-base);
|
||||
--input-padding-x: 0.92rem; /* ~12px */
|
||||
--input-padding-y: 0.62rem; /* ~8px */
|
||||
--input-radius: 0.375rem; /* 6px */
|
||||
|
||||
/* Input Number Specific */
|
||||
--input-handler-width: 1.5rem; /* 24px (Slightly wider for better clickable) */
|
||||
/* Textarea Specific */
|
||||
--textarea-min-height: 6.15rem; /* 80px */
|
||||
--textarea-padding-x: 0.92rem; /* 12px */
|
||||
--textarea-padding-y: 0.62rem; /* 8px */
|
||||
|
||||
/* Input Colors */
|
||||
--input-bg: #ffffff;
|
||||
--input-border: var(--color-gray-300);
|
||||
--input-border-hover: var(--color-brand-400);
|
||||
--input-text: var(--color-gray-800);
|
||||
--input-placeholder: var(--color-gray-400);
|
||||
|
||||
--focus-ring-color: var(--color-brand-100);
|
||||
--focus-border-color: var(--color-brand-500);
|
||||
|
||||
--disabled-bg: #f3f4f6;
|
||||
--disabled-text: var(--color-gray-400);
|
||||
--disabled-border: #e5e7eb;
|
||||
|
||||
/* CHECKBOX & RADIO COMPONENT VARIABLES*/
|
||||
|
||||
/* 16px is a perfect fit for a 13px font size.
|
||||
It's easier to read than 14px, but not overpowering. */
|
||||
--checkbox-size: 16px; /* ~16px (relative to 13px base) */
|
||||
--checkbox-radius: var(--radius-md);
|
||||
|
||||
/* * Position the check mark icon precisely in the center of the 16px box */
|
||||
--checkbox-check-width: 5px;
|
||||
--checkbox-check-height: 9px;
|
||||
--checkbox-check-top: 1.5px; /* Fine-tuning vertical position */
|
||||
--checkbox-check-left: 4.5px; /* Fine-tuning horizontal position */
|
||||
|
||||
/* SWITCH COMPONENT VARIABLES */
|
||||
|
||||
/* Using pixels (px) for Switch is often safer
|
||||
to avoid sub-pixel rendering artifacts (circles becoming oval)
|
||||
on low screen resolutions, while still maintaining proportion to the rest scale. */
|
||||
|
||||
/* A height of 20px fits with a line-height of 13px text,
|
||||
A width of 36px provides a compact and modern ratio. */
|
||||
--switch-width: 36px;
|
||||
--switch-height: 20px;
|
||||
|
||||
/* Handle (lingkaran) = Height - (Padding * 2) */
|
||||
/* 20px - (2px * 2) = 16px */
|
||||
--switch-handle-size: 16px;
|
||||
--switch-padding: 2px; /* Distance between handle and edge */
|
||||
|
||||
/* Calculate active position (Checked) */
|
||||
/* 36px - 16px - 2px = 18px */
|
||||
--switch-checked-pos: calc(var(--switch-width) - var(--switch-handle-size) - var(--switch-padding));
|
||||
|
||||
/* Additional variable for label inside switch (ON/OFF text) if any */
|
||||
--switch-inner-margin-left: 6px;
|
||||
--switch-inner-margin-right: 20px;
|
||||
/* Margin Calculation for Inner Text */
|
||||
/* Handle edge spacing: Handle size (16px) + Padding (2px) + Gap (4px) = 22px */
|
||||
--switch-inner-indent-handle: 22px;
|
||||
/* Empty edge spacing: Padding (2px) + Gap (4px) = 6px */
|
||||
--switch-inner-indent-edge: 6px;
|
||||
}
|
||||
@import '@mantine/core/styles.css';
|
||||
|
||||
/* =========================================
|
||||
BASE RESETS
|
||||
BASE RESETS (Minimal, let Mantine handle most)
|
||||
========================================= */
|
||||
@layer base {
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
||||
background-color: #ffffff;
|
||||
color: var(--color-gray-800);
|
||||
font-size: var(--base-font-size);
|
||||
line-height: var(--text-base--line-height);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea,
|
||||
select,
|
||||
button {
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import { MantineColorsTuple } from '@mantine/core';
|
||||
|
||||
export const brandColors: MantineColorsTuple = [
|
||||
'#f5f3fd', // 50
|
||||
'#e6dbfb', // 100
|
||||
'#d0b6f8', // 200
|
||||
'#b78ff5', // 300
|
||||
'#9f64f1', // 400
|
||||
'#7d39ed', // 500 (Primary)
|
||||
'#652ed9', // 600
|
||||
'#4a23a5', // 700
|
||||
'#321a7a', // 800
|
||||
'#1b0f4a', // 900
|
||||
];
|
||||
|
||||
export const errorColors: MantineColorsTuple = [
|
||||
'#fef2f2', '#fee2e2', '#fecaca', '#fca5a5', '#f87171',
|
||||
'#ef4444', '#dc2626', '#b91c1c', '#991b1b', '#7f1d1d',
|
||||
];
|
||||
|
||||
export const warningColors: MantineColorsTuple = [
|
||||
'#fffbeb', '#fef3c7', '#fde68a', '#fcd34d', '#fbbf24',
|
||||
'#f59e0b', '#d97706', '#b45309', '#92400e', '#78350f',
|
||||
];
|
||||
|
||||
export const successColors: MantineColorsTuple = [
|
||||
'#f0fdf4', '#dcfce7', '#bbf7d0', '#86efac', '#4ade80',
|
||||
'#22c55e', '#16a34a', '#15803d', '#166534', '#14532d',
|
||||
];
|
||||
|
||||
export const infoColors: MantineColorsTuple = [
|
||||
'#f0f9ff', '#e0f2fe', '#bae6fd', '#7dd3fc', '#38bdf8',
|
||||
'#0ea5e9', '#0284c7', '#0369a1', '#075985', '#0c4a6e',
|
||||
];
|
||||
|
||||
export const draculaColors: MantineColorsTuple = [
|
||||
'#f8f8f2', '#f1fa8c', '#8be9fd', '#50fa7b', '#ffb86c',
|
||||
'#ff79c6', '#bd93f9', '#6272a4', '#44475a', '#282a36',
|
||||
]; // Reusing standard dracula palette as a tuple for simplicity,
|
||||
// usually this would be mapped to specific grays/primary.
|
||||
|
||||
export const blueColors: MantineColorsTuple = [
|
||||
'#e3f2fd', '#bbdefb', '#90caf9', '#64b5f6', '#42a5f5',
|
||||
'#2196f3', '#1e88e5', '#1976d2', '#1565c0', '#0d47a1',
|
||||
];
|
||||
|
||||
export const grayColors: MantineColorsTuple = [
|
||||
'#f5f6f7', '#eceff1', '#e0e3e7', '#d1d5db', '#9ca3af',
|
||||
'#6b7280', '#4b5563', '#374151', '#1f2937', '#111827',
|
||||
];
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from './colors';
|
||||
export * from './typography';
|
||||
export * from './radius';
|
||||
@@ -0,0 +1,7 @@
|
||||
export const radius = {
|
||||
xs: '0.125rem', // 2px
|
||||
sm: '0.25rem', // 4px
|
||||
md: '0.375rem', // 6px (Input radius)
|
||||
lg: '0.5rem', // 8px
|
||||
xl: '0.75rem', // 12px
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
export const typography = {
|
||||
fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif",
|
||||
fontSizes: {
|
||||
xs: 'calc(13px * 0.846)',
|
||||
sm: 'calc(13px * 0.923)',
|
||||
md: '13px',
|
||||
lg: 'calc(13px * 1.154)',
|
||||
xl: 'calc(13px * 1.385)',
|
||||
},
|
||||
lineHeights: {
|
||||
xs: '1.4',
|
||||
sm: '1.45',
|
||||
md: '1.5',
|
||||
lg: '1.55',
|
||||
xl: '1.6',
|
||||
},
|
||||
headings: {
|
||||
fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif",
|
||||
sizes: {
|
||||
h1: { fontSize: 'calc(13px * 2.5)' },
|
||||
h2: { fontSize: 'calc(13px * 2)' },
|
||||
h3: { fontSize: 'calc(13px * 1.75)' },
|
||||
h4: { fontSize: 'calc(13px * 1.5)' },
|
||||
h5: { fontSize: 'calc(13px * 1.25)' },
|
||||
h6: { fontSize: '13px' },
|
||||
},
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user