diff --git a/apps/web/src/apps/index.tsx b/apps/web/src/apps/index.tsx index 689f224..478f9d5 100644 --- a/apps/web/src/apps/index.tsx +++ b/apps/web/src/apps/index.tsx @@ -1,5 +1,6 @@ -import { lazy, Suspense } from 'react'; +import { lazy, Suspense, useState } from 'react'; import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom'; +import { ThemeProvider, ColorSchemeType, DensityType } from '@repo/ui/provider'; import { NotFound } from '@repo/ui/components/system-pages/not-found'; import { Forbidden } from '@repo/ui/components/system-pages/forbidden'; import { Maintenance } from '@repo/ui/components/system-pages/maintenance'; @@ -7,22 +8,39 @@ import { ComingSoon } from '@repo/ui/components/system-pages/coming-soon'; const AuthModule = lazy(() => import('./auth')); const AppModule = lazy(() => import('./modules')); +const ShowcaseView = lazy(() => import('./showcase/showcase-view')); export default function App() { + const [colorScheme, setColorScheme] = useState('light'); + const [density, setDensity] = useState('standard'); + return ( - - Loading...}> - - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - - + + + Loading...}> + + } /> + } /> + + } + /> + } /> + } /> + } /> + } /> + } /> + } /> + + + + ); } diff --git a/apps/web/src/apps/showcase/showcase-view.tsx b/apps/web/src/apps/showcase/showcase-view.tsx new file mode 100644 index 0000000..f7e7305 --- /dev/null +++ b/apps/web/src/apps/showcase/showcase-view.tsx @@ -0,0 +1,84 @@ +import { ColorSchemeType, DensityType } from '@repo/ui/provider'; +import { Button } from '@repo/ui/components/button'; +import { Card } from '@repo/ui/components/card'; +import { Container } from '@repo/ui/components/container'; +import { Select } from '@repo/ui/components/select'; +import { Group, Stack } from '@repo/ui/components/group'; +import { Text, Title } from '@repo/ui/components/text'; +import { TextInput } from '@repo/ui/components/input'; +import { Checkbox } from '@repo/ui/components/checkbox'; + +interface ShowcaseViewProps { + colorScheme: ColorSchemeType; + setColorScheme: (val: ColorSchemeType) => void; + density: DensityType; + setDensity: (val: DensityType) => void; +} + +export default function ShowcaseView({ colorScheme, setColorScheme, density, setDensity }: ShowcaseViewProps) { + return ( + + + UI Gateway Showcase + + {/* Control Panel */} + + Control Panel + + setDensity((val as DensityType) || 'standard')} + data={[ + { value: 'compact', label: 'Compact' }, + { value: 'standard', label: 'Standard' }, + { value: 'spacious', label: 'Spacious' }, + ]} + /> + + + + {/* Showcase Area */} + + +
+ Typography + This is dimmed small text. + This is standard text describing the components below. +
+ +
+ Buttons + + + + + + +
+ +
+ Form Elements + + + + + +
+
+
+
+
+ ); +} diff --git a/packages/ui/package.json b/packages/ui/package.json index bf2fdcd..758c527 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -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", diff --git a/packages/ui/src/components/button.ts b/packages/ui/src/components/button.ts new file mode 100644 index 0000000..ed36b20 --- /dev/null +++ b/packages/ui/src/components/button.ts @@ -0,0 +1 @@ +export { Button, type ButtonProps } from '@mantine/core'; diff --git a/packages/ui/src/components/card.ts b/packages/ui/src/components/card.ts new file mode 100644 index 0000000..eb92515 --- /dev/null +++ b/packages/ui/src/components/card.ts @@ -0,0 +1 @@ +export { Card, type CardProps } from '@mantine/core'; diff --git a/packages/ui/src/components/checkbox.ts b/packages/ui/src/components/checkbox.ts new file mode 100644 index 0000000..33b461c --- /dev/null +++ b/packages/ui/src/components/checkbox.ts @@ -0,0 +1 @@ +export { Checkbox, type CheckboxProps } from '@mantine/core'; diff --git a/packages/ui/src/components/container.ts b/packages/ui/src/components/container.ts new file mode 100644 index 0000000..e1e7813 --- /dev/null +++ b/packages/ui/src/components/container.ts @@ -0,0 +1 @@ +export { Container, type ContainerProps } from '@mantine/core'; diff --git a/packages/ui/src/components/group.ts b/packages/ui/src/components/group.ts new file mode 100644 index 0000000..4d64a09 --- /dev/null +++ b/packages/ui/src/components/group.ts @@ -0,0 +1 @@ +export { Group, type GroupProps, Stack, type StackProps } from '@mantine/core'; diff --git a/packages/ui/src/components/input.ts b/packages/ui/src/components/input.ts new file mode 100644 index 0000000..509a3de --- /dev/null +++ b/packages/ui/src/components/input.ts @@ -0,0 +1 @@ +export { TextInput, type TextInputProps } from '@mantine/core'; diff --git a/packages/ui/src/components/select.ts b/packages/ui/src/components/select.ts new file mode 100644 index 0000000..1d4dc94 --- /dev/null +++ b/packages/ui/src/components/select.ts @@ -0,0 +1 @@ +export { Select, type SelectProps } from '@mantine/core'; diff --git a/packages/ui/src/components/system-pages/coming-soon.tsx b/packages/ui/src/components/system-pages/coming-soon.tsx index 02b6c91..42904d1 100644 --- a/packages/ui/src/components/system-pages/coming-soon.tsx +++ b/packages/ui/src/components/system-pages/coming-soon.tsx @@ -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 ( -
-
- {/* Code */} -

Coming Soon

+ +
+ + + Coming Soon + - {/* Title */} -

Feature in Progress

+ + Feature in Progress + - {/* Description */} -

- This feature is currently under development. Stay tuned! We'll have it ready for you very soon. -

+ + This feature is currently under development. Stay tuned! We'll have it ready for you very soon. + - {/* Actions */} - {showActions && ( - - )} -
-
+ + )} + + + ); } diff --git a/packages/ui/src/components/system-pages/forbidden.tsx b/packages/ui/src/components/system-pages/forbidden.tsx index f583524..d52f386 100644 --- a/packages/ui/src/components/system-pages/forbidden.tsx +++ b/packages/ui/src/components/system-pages/forbidden.tsx @@ -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 ( -
-
- {/* Code */} -

403 Error

+ +
+ + + 403 Error + - {/* Title */} -

Access Denied

+ + Access Denied + - {/* Description */} -

- Sorry, you don’t have permission to access this page. Please contact your administrator if you believe this is - a mistake. -

+ + Sorry, you don’t have permission to access this page. Please contact your administrator if you believe this + is a mistake. + - {/* Actions */} - {(showActionsBack || showActionsHome) && ( -
- {showActionsBack && ( - - )} + {(showActionsBack || showActionsHome) && ( + + {showActionsBack && ( + + )} - {showActionsHome && ( - - Back to Home - - )} -
- )} -
-
+ {showActionsHome && ( + + )} + + )} + + + ); } diff --git a/packages/ui/src/components/system-pages/maintenance.tsx b/packages/ui/src/components/system-pages/maintenance.tsx index bd7d508..a4308d6 100644 --- a/packages/ui/src/components/system-pages/maintenance.tsx +++ b/packages/ui/src/components/system-pages/maintenance.tsx @@ -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 ( -
-
- {/* Code */} -

Maintenance

+ +
+ + + Maintenance + - {/* Title */} -

We'll Be Back Soon

+ + We'll Be Back Soon + - {/* Description */} -

- Our system is currently undergoing scheduled maintenance. We are working hard to bring it back online as soon - as possible. -

+ + Our system is currently undergoing scheduled maintenance. We are working hard to bring it back online as + soon as possible. + - {/* Optional Actions */} - {showActions && ( - - )} -
-
+ + )} + + + ); } diff --git a/packages/ui/src/components/system-pages/not-found.tsx b/packages/ui/src/components/system-pages/not-found.tsx index 3f644ba..91a1127 100644 --- a/packages/ui/src/components/system-pages/not-found.tsx +++ b/packages/ui/src/components/system-pages/not-found.tsx @@ -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 ( -
-
-

404 Error

+ +
+ + + 404 Error + -

Page Not Found

+ + Page Not Found + -

- Sorry, the page you’re looking for doesn’t exist or has been moved. -

+ + Sorry, the page you’re looking for doesn’t exist or has been moved. + - {(showActionsBack || showActionsHome) && ( -
- {showActionsBack && ( - - )} + {(showActionsBack || showActionsHome) && ( + + {showActionsBack && ( + + )} - {showActionsHome && ( - - Back to Home - - )} -
- )} -
-
+ {showActionsHome && ( + + )} + + )} + + + ); } diff --git a/packages/ui/src/components/text.ts b/packages/ui/src/components/text.ts new file mode 100644 index 0000000..94ff3a3 --- /dev/null +++ b/packages/ui/src/components/text.ts @@ -0,0 +1 @@ +export { Text, type TextProps, Title, type TitleProps } from '@mantine/core'; diff --git a/packages/ui/src/provider/index.ts b/packages/ui/src/provider/index.ts new file mode 100644 index 0000000..3df4bde --- /dev/null +++ b/packages/ui/src/provider/index.ts @@ -0,0 +1 @@ +export * from './theme-provider'; diff --git a/packages/ui/src/provider/theme-provider.tsx b/packages/ui/src/provider/theme-provider.tsx new file mode 100644 index 0000000..84a226d --- /dev/null +++ b/packages/ui/src/provider/theme-provider.tsx @@ -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 ( + + {children} + + ); +} diff --git a/packages/ui/src/theme.css b/packages/ui/src/theme.css index 964e3ea..927fed0 100644 --- a/packages/ui/src/theme.css +++ b/packages/ui/src/theme.css @@ -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; - } } diff --git a/packages/ui/src/theme/tokens/colors.ts b/packages/ui/src/theme/tokens/colors.ts new file mode 100644 index 0000000..30424a6 --- /dev/null +++ b/packages/ui/src/theme/tokens/colors.ts @@ -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', +]; diff --git a/packages/ui/src/theme/tokens/index.ts b/packages/ui/src/theme/tokens/index.ts new file mode 100644 index 0000000..e8ee8f0 --- /dev/null +++ b/packages/ui/src/theme/tokens/index.ts @@ -0,0 +1,3 @@ +export * from './colors'; +export * from './typography'; +export * from './radius'; diff --git a/packages/ui/src/theme/tokens/radius.ts b/packages/ui/src/theme/tokens/radius.ts new file mode 100644 index 0000000..945f236 --- /dev/null +++ b/packages/ui/src/theme/tokens/radius.ts @@ -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 +}; diff --git a/packages/ui/src/theme/tokens/typography.ts b/packages/ui/src/theme/tokens/typography.ts new file mode 100644 index 0000000..5117f48 --- /dev/null +++ b/packages/ui/src/theme/tokens/typography.ts @@ -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' }, + }, + }, +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a17388b..50b5f6e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -161,6 +161,12 @@ importers: packages/ui: dependencies: + '@mantine/core': + specifier: ^8.3.15 + version: 8.3.15(@mantine/hooks@8.3.15)(@types/react@19.2.7)(react-dom@19.2.3)(react@19.2.3) + '@mantine/hooks': + specifier: ^8.3.15 + version: 8.3.15(react@19.2.3) '@repo/utils': specifier: workspace:* version: link:../utils @@ -392,7 +398,6 @@ packages: /@babel/runtime@7.28.4: resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} engines: {node: '>=6.9.0'} - dev: true /@babel/template@7.27.2: resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} @@ -899,6 +904,47 @@ packages: resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@floating-ui/core@1.7.4: + resolution: {integrity: sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==} + dependencies: + '@floating-ui/utils': 0.2.10 + dev: false + + /@floating-ui/dom@1.7.5: + resolution: {integrity: sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==} + dependencies: + '@floating-ui/core': 1.7.4 + '@floating-ui/utils': 0.2.10 + dev: false + + /@floating-ui/react-dom@2.1.7(react-dom@19.2.3)(react@19.2.3): + resolution: {integrity: sha512-0tLRojf/1Go2JgEVm+3Frg9A3IW8bJgKgdO0BN5RkF//ufuz2joZM63Npau2ff3J6lUVYgDSNzNkR+aH3IVfjg==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + dependencies: + '@floating-ui/dom': 1.7.5 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + dev: false + + /@floating-ui/react@0.27.18(react-dom@19.2.3)(react@19.2.3): + resolution: {integrity: sha512-xJWJxvmy3a05j643gQt+pRbht5XnTlGpsEsAPnMi5F5YTOEEJymA90uZKBD8OvIv5XvZ1qi4GcccSlqT3Bq44Q==} + peerDependencies: + react: '>=17.0.0' + react-dom: '>=17.0.0' + dependencies: + '@floating-ui/react-dom': 2.1.7(react-dom@19.2.3)(react@19.2.3) + '@floating-ui/utils': 0.2.10 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + tabbable: 6.4.0 + dev: false + + /@floating-ui/utils@0.2.10: + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + dev: false + /@humanwhocodes/config-array@0.13.0: resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} engines: {node: '>=10.10.0'} @@ -989,6 +1035,34 @@ packages: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + /@mantine/core@8.3.15(@mantine/hooks@8.3.15)(@types/react@19.2.7)(react-dom@19.2.3)(react@19.2.3): + resolution: {integrity: sha512-wBn/GogB4x7a2Uj7Ztt3amRaApjED+9XqfE4wyCLh88R7KV55k9vnTdCx+irI/GLOOu9tXNUGm3a4t5sTajwkQ==} + peerDependencies: + '@mantine/hooks': 8.3.15 + react: ^18.x || ^19.x + react-dom: ^18.x || ^19.x + dependencies: + '@floating-ui/react': 0.27.18(react-dom@19.2.3)(react@19.2.3) + '@mantine/hooks': 8.3.15(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + react-number-format: 5.4.4(react-dom@19.2.3)(react@19.2.3) + react-remove-scroll: 2.7.2(@types/react@19.2.7)(react@19.2.3) + react-textarea-autosize: 8.5.9(@types/react@19.2.7)(react@19.2.3) + type-fest: 4.41.0 + transitivePeerDependencies: + - '@types/react' + dev: false + + /@mantine/hooks@8.3.15(react@19.2.3): + resolution: {integrity: sha512-AUSnpUlzttHzJht3CJ1YWi16iy6NWRwtyWO5RLGHHsmiW05DyG0qOPKF8+R5dLHuOCnl3XOu4roI2Y1ku9U04Q==} + peerDependencies: + react: ^18.x || ^19.x + dependencies: + react: 19.2.3 + dev: false + /@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3): resolution: {integrity: sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==} peerDependencies: @@ -2137,7 +2211,6 @@ packages: resolution: {integrity: sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==} dependencies: csstype: 3.2.3 - dev: true /@types/resolve@1.20.6: resolution: {integrity: sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==} @@ -3182,6 +3255,11 @@ packages: is-wsl: 2.2.0 dev: true + /clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + dev: false + /color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -3253,7 +3331,6 @@ packages: /csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - dev: true /damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} @@ -3388,6 +3465,10 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dev: false + /detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + dev: false + /devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} dependencies: @@ -4335,6 +4416,11 @@ packages: hasown: 2.0.2 math-intrinsics: 1.1.0 + /get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + dev: false + /get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} @@ -6049,11 +6135,56 @@ packages: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} dev: false + /react-number-format@5.4.4(react-dom@19.2.3)(react@19.2.3): + resolution: {integrity: sha512-wOmoNZoOpvMminhifQYiYSTCLUDOiUbBunrMrMjA+dV52sY+vck1S4UhR6PkgnoCquvvMSeJjErXZ4qSaWCliA==} + peerDependencies: + react: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + dependencies: + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + dev: false + /react-refresh@0.18.0: resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} engines: {node: '>=0.10.0'} dev: true + /react-remove-scroll-bar@2.3.8(@types/react@19.2.7)(react@19.2.3): + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 19.2.7 + react: 19.2.3 + react-style-singleton: 2.2.3(@types/react@19.2.7)(react@19.2.3) + tslib: 2.8.1 + dev: false + + /react-remove-scroll@2.7.2(@types/react@19.2.7)(react@19.2.3): + resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 19.2.7 + react: 19.2.3 + react-remove-scroll-bar: 2.3.8(@types/react@19.2.7)(react@19.2.3) + react-style-singleton: 2.2.3(@types/react@19.2.7)(react@19.2.3) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@19.2.7)(react@19.2.3) + use-sidecar: 1.1.3(@types/react@19.2.7)(react@19.2.3) + dev: false + /react-router-dom@7.11.0(react-dom@19.2.3)(react@19.2.3): resolution: {integrity: sha512-e49Ir/kMGRzFOOrYQBdoitq3ULigw4lKbAyKusnvtDu2t4dBX4AGYPrzNvorXmVuOyeakai6FUPW5MmibvVG8g==} engines: {node: '>=20.0.0'} @@ -6082,6 +6213,36 @@ packages: set-cookie-parser: 2.7.2 dev: false + /react-style-singleton@2.2.3(@types/react@19.2.7)(react@19.2.3): + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 19.2.7 + get-nonce: 1.0.1 + react: 19.2.3 + tslib: 2.8.1 + dev: false + + /react-textarea-autosize@8.5.9(@types/react@19.2.7)(react@19.2.3): + resolution: {integrity: sha512-U1DGlIQN5AwgjTyOEnI1oCcMuEr1pv1qOtklB2l4nyMGbHzWrI0eFsYK0zos2YWqAolJyG0IWJaqWmWj5ETh0A==} + engines: {node: '>=10'} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + dependencies: + '@babel/runtime': 7.28.4 + react: 19.2.3 + use-composed-ref: 1.4.0(@types/react@19.2.7)(react@19.2.3) + use-latest: 1.3.0(@types/react@19.2.7)(react@19.2.3) + transitivePeerDependencies: + - '@types/react' + dev: false + /react@19.2.3: resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==} engines: {node: '>=0.10.0'} @@ -6780,6 +6941,10 @@ packages: '@pkgr/core': 0.2.9 dev: false + /tabbable@6.4.0: + resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} + dev: false + /tailwind-merge@3.4.0: resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==} dev: false @@ -6976,6 +7141,11 @@ packages: engines: {node: '>=14.16'} dev: false + /type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + dev: false + /typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} @@ -7181,6 +7351,77 @@ packages: dependencies: punycode: 2.3.1 + /use-callback-ref@1.3.3(@types/react@19.2.7)(react@19.2.3): + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 19.2.7 + react: 19.2.3 + tslib: 2.8.1 + dev: false + + /use-composed-ref@1.4.0(@types/react@19.2.7)(react@19.2.3): + resolution: {integrity: sha512-djviaxuOOh7wkj0paeO1Q/4wMZ8Zrnag5H6yBvzN7AKKe8beOaED9SF5/ByLqsku8NP4zQqsvM2u3ew/tJK8/w==} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 19.2.7 + react: 19.2.3 + dev: false + + /use-isomorphic-layout-effect@1.2.1(@types/react@19.2.7)(react@19.2.3): + resolution: {integrity: sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 19.2.7 + react: 19.2.3 + dev: false + + /use-latest@1.3.0(@types/react@19.2.7)(react@19.2.3): + resolution: {integrity: sha512-mhg3xdm9NaM8q+gLT8KryJPnRFOz1/5XPBhmDEVZK1webPzDjrPk7f/mbpeLqTgB9msytYWANxgALOCJKnLvcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 19.2.7 + react: 19.2.3 + use-isomorphic-layout-effect: 1.2.1(@types/react@19.2.7)(react@19.2.3) + dev: false + + /use-sidecar@1.1.3(@types/react@19.2.7)(react@19.2.3): + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 19.2.7 + detect-node-es: 1.1.0 + react: 19.2.3 + tslib: 2.8.1 + dev: false + /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} dev: false