From 8181bd61ec7748fa2b69b911835c3426d232236a Mon Sep 17 00:00:00 2001
From: Firman Ramdhani <33869609+firmanramdhani@users.noreply.github.com>
Date: Fri, 27 Feb 2026 13:34:59 +0700
Subject: [PATCH 1/8] feat: refactor setup tailwind and css
---
apps/web/src/apps/index.tsx | 5 +-
.../src/apps/modules/example/example.page.tsx | 2 +-
apps/web/src/main.css | 4 +-
packages/ui/package.json | 16 ++++--
packages/ui/src/components/index.ts | 4 --
packages/ui/src/index.ts | 2 -
packages/ui/src/{globals.css => theme.css} | 3 --
pnpm-lock.yaml | 51 ++++---------------
8 files changed, 28 insertions(+), 59 deletions(-)
delete mode 100644 packages/ui/src/components/index.ts
delete mode 100644 packages/ui/src/index.ts
rename packages/ui/src/{globals.css => theme.css} (99%)
diff --git a/apps/web/src/apps/index.tsx b/apps/web/src/apps/index.tsx
index 2d5110c..689f224 100644
--- a/apps/web/src/apps/index.tsx
+++ b/apps/web/src/apps/index.tsx
@@ -1,6 +1,9 @@
import { lazy, Suspense } from 'react';
import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom';
-import { NotFound, Forbidden, Maintenance, ComingSoon } from '@repo/ui';
+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';
+import { ComingSoon } from '@repo/ui/components/system-pages/coming-soon';
const AuthModule = lazy(() => import('./auth'));
const AppModule = lazy(() => import('./modules'));
diff --git a/apps/web/src/apps/modules/example/example.page.tsx b/apps/web/src/apps/modules/example/example.page.tsx
index a72890b..e6c1363 100644
--- a/apps/web/src/apps/modules/example/example.page.tsx
+++ b/apps/web/src/apps/modules/example/example.page.tsx
@@ -1,3 +1,3 @@
export default function ExamplePage() {
- return
example
;
+ return example
;
}
diff --git a/apps/web/src/main.css b/apps/web/src/main.css
index 7ca3c1a..1a6a0b5 100644
--- a/apps/web/src/main.css
+++ b/apps/web/src/main.css
@@ -1 +1,3 @@
-@import '@repo/ui/global.css';
+@import 'tailwindcss';
+@import '@repo/ui/theme.css';
+@source "../../../packages/ui/src";
diff --git a/packages/ui/package.json b/packages/ui/package.json
index 9b4ea97..bf2fdcd 100644
--- a/packages/ui/package.json
+++ b/packages/ui/package.json
@@ -2,8 +2,10 @@
"name": "@repo/ui",
"version": "0.0.0",
"exports": {
- ".": "./src/index.ts",
- "./global.css": "./src/globals.css"
+ "./theme.css": "./src/theme.css",
+ "./components/*": "./src/components/*.tsx",
+ "./hooks/*": "./src/hooks/*.ts",
+ "./utils/*": "./src/utils/*.ts"
},
"license": "MIT",
"scripts": {
@@ -11,12 +13,13 @@
"test": "vitest run",
"test:watch": "vitest --watch"
},
+ "peerDependencies": {
+ "react": "^19.2.3",
+ "react-dom": "^19.2.3"
+ },
"dependencies": {
"@repo/utils": "workspace:*",
- "@tailwindcss/vite": "^4.1.18",
"dayjs": "^1.11.19",
- "react": "^19.2.3",
- "react-dom": "^19.2.3",
"tailwind-merge": "^3.4.0",
"tailwind-variants": "^3.2.2",
"tailwindcss": "^4.1.18"
@@ -24,10 +27,13 @@
"devDependencies": {
"@repo/eslint-config": "workspace:*",
"@repo/typescript-config": "workspace:*",
+ "@tailwindcss/vite": "^4.1.18",
"@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.2",
"eslint": "^8.57.1",
+ "react": "^19.2.3",
+ "react-dom": "^19.2.3",
"typescript": "5.5.4",
"vite": "^5.1.4",
"vitest": "^4.0.17"
diff --git a/packages/ui/src/components/index.ts b/packages/ui/src/components/index.ts
deleted file mode 100644
index 3b8c2a2..0000000
--- a/packages/ui/src/components/index.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export * from './system-pages/coming-soon';
-export * from './system-pages/forbidden';
-export * from './system-pages/maintenance';
-export * from './system-pages/not-found';
diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts
deleted file mode 100644
index d1c67c0..0000000
--- a/packages/ui/src/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-// UI Components
-export * from './components';
diff --git a/packages/ui/src/globals.css b/packages/ui/src/theme.css
similarity index 99%
rename from packages/ui/src/globals.css
rename to packages/ui/src/theme.css
index f5db9ed..964e3ea 100644
--- a/packages/ui/src/globals.css
+++ b/packages/ui/src/theme.css
@@ -1,6 +1,3 @@
-@import 'tailwindcss';
-@source "../src";
-
/* =========================================
THEME VARIABLES (CENTRALIZED)
========================================= */
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index ef118d1..a17388b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -164,18 +164,9 @@ importers:
'@repo/utils':
specifier: workspace:*
version: link:../utils
- '@tailwindcss/vite':
- specifier: ^4.1.18
- version: 4.1.18(vite@5.4.17)
dayjs:
specifier: ^1.11.19
version: 1.11.19
- react:
- specifier: ^19.2.3
- version: 19.2.3
- react-dom:
- specifier: ^19.2.3
- version: 19.2.3(react@19.2.3)
tailwind-merge:
specifier: ^3.4.0
version: 3.4.0
@@ -192,6 +183,9 @@ importers:
'@repo/typescript-config':
specifier: workspace:*
version: link:../configs/typescript
+ '@tailwindcss/vite':
+ specifier: ^4.1.18
+ version: 4.1.18(vite@5.4.17)
'@types/react':
specifier: ^19.2.7
version: 19.2.7
@@ -204,6 +198,12 @@ importers:
eslint:
specifier: ^8.57.1
version: 8.57.1
+ react:
+ specifier: ^19.2.3
+ version: 19.2.3
+ react-dom:
+ specifier: ^19.2.3
+ version: 19.2.3(react@19.2.3)
typescript:
specifier: 5.5.4
version: 5.5.4
@@ -1872,7 +1872,6 @@ packages:
magic-string: 0.30.21
source-map-js: 1.2.1
tailwindcss: 4.1.18
- dev: false
/@tailwindcss/oxide-android-arm64@4.1.18:
resolution: {integrity: sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==}
@@ -1880,7 +1879,6 @@ packages:
cpu: [arm64]
os: [android]
requiresBuild: true
- dev: false
optional: true
/@tailwindcss/oxide-darwin-arm64@4.1.18:
@@ -1889,7 +1887,6 @@ packages:
cpu: [arm64]
os: [darwin]
requiresBuild: true
- dev: false
optional: true
/@tailwindcss/oxide-darwin-x64@4.1.18:
@@ -1898,7 +1895,6 @@ packages:
cpu: [x64]
os: [darwin]
requiresBuild: true
- dev: false
optional: true
/@tailwindcss/oxide-freebsd-x64@4.1.18:
@@ -1907,7 +1903,6 @@ packages:
cpu: [x64]
os: [freebsd]
requiresBuild: true
- dev: false
optional: true
/@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18:
@@ -1916,7 +1911,6 @@ packages:
cpu: [arm]
os: [linux]
requiresBuild: true
- dev: false
optional: true
/@tailwindcss/oxide-linux-arm64-gnu@4.1.18:
@@ -1925,7 +1919,6 @@ packages:
cpu: [arm64]
os: [linux]
requiresBuild: true
- dev: false
optional: true
/@tailwindcss/oxide-linux-arm64-musl@4.1.18:
@@ -1934,7 +1927,6 @@ packages:
cpu: [arm64]
os: [linux]
requiresBuild: true
- dev: false
optional: true
/@tailwindcss/oxide-linux-x64-gnu@4.1.18:
@@ -1943,7 +1935,6 @@ packages:
cpu: [x64]
os: [linux]
requiresBuild: true
- dev: false
optional: true
/@tailwindcss/oxide-linux-x64-musl@4.1.18:
@@ -1952,7 +1943,6 @@ packages:
cpu: [x64]
os: [linux]
requiresBuild: true
- dev: false
optional: true
/@tailwindcss/oxide-wasm32-wasi@4.1.18:
@@ -1960,7 +1950,6 @@ packages:
engines: {node: '>=14.0.0'}
cpu: [wasm32]
requiresBuild: true
- dev: false
optional: true
bundledDependencies:
- '@napi-rs/wasm-runtime'
@@ -1976,7 +1965,6 @@ packages:
cpu: [arm64]
os: [win32]
requiresBuild: true
- dev: false
optional: true
/@tailwindcss/oxide-win32-x64-msvc@4.1.18:
@@ -1985,7 +1973,6 @@ packages:
cpu: [x64]
os: [win32]
requiresBuild: true
- dev: false
optional: true
/@tailwindcss/oxide@4.1.18:
@@ -2004,7 +1991,6 @@ packages:
'@tailwindcss/oxide-wasm32-wasi': 4.1.18
'@tailwindcss/oxide-win32-arm64-msvc': 4.1.18
'@tailwindcss/oxide-win32-x64-msvc': 4.1.18
- dev: false
/@tailwindcss/vite@4.1.18(vite@5.4.17):
resolution: {integrity: sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA==}
@@ -2015,7 +2001,6 @@ packages:
'@tailwindcss/oxide': 4.1.18
tailwindcss: 4.1.18
vite: 5.4.17
- dev: false
/@tybys/wasm-util@0.10.1:
resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
@@ -3397,7 +3382,6 @@ packages:
/detect-libc@2.1.2:
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
engines: {node: '>=8'}
- dev: false
/detect-newline@4.0.1:
resolution: {integrity: sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog==}
@@ -3470,7 +3454,6 @@ packages:
dependencies:
graceful-fs: 4.2.11
tapable: 2.3.0
- dev: false
/err-code@2.0.3:
resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==}
@@ -4449,7 +4432,6 @@ packages:
/graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
- dev: false
/graphemer@1.4.0:
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
@@ -4857,7 +4839,6 @@ packages:
/jiti@2.6.1:
resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==}
hasBin: true
- dev: false
/jju@1.4.0:
resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
@@ -4964,7 +4945,6 @@ packages:
cpu: [arm64]
os: [android]
requiresBuild: true
- dev: false
optional: true
/lightningcss-darwin-arm64@1.30.2:
@@ -4973,7 +4953,6 @@ packages:
cpu: [arm64]
os: [darwin]
requiresBuild: true
- dev: false
optional: true
/lightningcss-darwin-x64@1.30.2:
@@ -4982,7 +4961,6 @@ packages:
cpu: [x64]
os: [darwin]
requiresBuild: true
- dev: false
optional: true
/lightningcss-freebsd-x64@1.30.2:
@@ -4991,7 +4969,6 @@ packages:
cpu: [x64]
os: [freebsd]
requiresBuild: true
- dev: false
optional: true
/lightningcss-linux-arm-gnueabihf@1.30.2:
@@ -5000,7 +4977,6 @@ packages:
cpu: [arm]
os: [linux]
requiresBuild: true
- dev: false
optional: true
/lightningcss-linux-arm64-gnu@1.30.2:
@@ -5009,7 +4985,6 @@ packages:
cpu: [arm64]
os: [linux]
requiresBuild: true
- dev: false
optional: true
/lightningcss-linux-arm64-musl@1.30.2:
@@ -5018,7 +4993,6 @@ packages:
cpu: [arm64]
os: [linux]
requiresBuild: true
- dev: false
optional: true
/lightningcss-linux-x64-gnu@1.30.2:
@@ -5027,7 +5001,6 @@ packages:
cpu: [x64]
os: [linux]
requiresBuild: true
- dev: false
optional: true
/lightningcss-linux-x64-musl@1.30.2:
@@ -5036,7 +5009,6 @@ packages:
cpu: [x64]
os: [linux]
requiresBuild: true
- dev: false
optional: true
/lightningcss-win32-arm64-msvc@1.30.2:
@@ -5045,7 +5017,6 @@ packages:
cpu: [arm64]
os: [win32]
requiresBuild: true
- dev: false
optional: true
/lightningcss-win32-x64-msvc@1.30.2:
@@ -5054,7 +5025,6 @@ packages:
cpu: [x64]
os: [win32]
requiresBuild: true
- dev: false
optional: true
/lightningcss@1.30.2:
@@ -5074,7 +5044,6 @@ packages:
lightningcss-linux-x64-musl: 1.30.2
lightningcss-win32-arm64-msvc: 1.30.2
lightningcss-win32-x64-msvc: 1.30.2
- dev: false
/lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
@@ -6831,12 +6800,10 @@ packages:
/tailwindcss@4.1.18:
resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==}
- dev: false
/tapable@2.3.0:
resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==}
engines: {node: '>=6'}
- dev: false
/text-table@0.2.0:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
From 1d38a188b7e0bb3fc1dabe490ee317165e008aa4 Mon Sep 17 00:00:00 2001
From: Firman Ramdhani <33869609+firmanramdhani@users.noreply.github.com>
Date: Fri, 27 Feb 2026 15:00:17 +0700
Subject: [PATCH 2/8] feat: Integrate Mantine UI library, establish a theme
provider, and refactor core UI components.
---
apps/web/src/apps/index.tsx | 48 ++--
apps/web/src/apps/showcase/showcase-view.tsx | 84 ++++++
packages/ui/package.json | 8 +-
packages/ui/src/components/button.ts | 1 +
packages/ui/src/components/card.ts | 1 +
packages/ui/src/components/checkbox.ts | 1 +
packages/ui/src/components/container.ts | 1 +
packages/ui/src/components/group.ts | 1 +
packages/ui/src/components/input.ts | 1 +
packages/ui/src/components/select.ts | 1 +
.../components/system-pages/coming-soon.tsx | 45 ++--
.../src/components/system-pages/forbidden.tsx | 68 +++--
.../components/system-pages/maintenance.tsx | 47 ++--
.../src/components/system-pages/not-found.tsx | 62 ++---
packages/ui/src/components/text.ts | 1 +
packages/ui/src/provider/index.ts | 1 +
packages/ui/src/provider/theme-provider.tsx | 70 +++++
packages/ui/src/theme.css | 214 +--------------
packages/ui/src/theme/tokens/colors.ts | 50 ++++
packages/ui/src/theme/tokens/index.ts | 3 +
packages/ui/src/theme/tokens/radius.ts | 7 +
packages/ui/src/theme/tokens/typography.ts | 28 ++
pnpm-lock.yaml | 247 +++++++++++++++++-
23 files changed, 646 insertions(+), 344 deletions(-)
create mode 100644 apps/web/src/apps/showcase/showcase-view.tsx
create mode 100644 packages/ui/src/components/button.ts
create mode 100644 packages/ui/src/components/card.ts
create mode 100644 packages/ui/src/components/checkbox.ts
create mode 100644 packages/ui/src/components/container.ts
create mode 100644 packages/ui/src/components/group.ts
create mode 100644 packages/ui/src/components/input.ts
create mode 100644 packages/ui/src/components/select.ts
create mode 100644 packages/ui/src/components/text.ts
create mode 100644 packages/ui/src/provider/index.ts
create mode 100644 packages/ui/src/provider/theme-provider.tsx
create mode 100644 packages/ui/src/theme/tokens/colors.ts
create mode 100644 packages/ui/src/theme/tokens/index.ts
create mode 100644 packages/ui/src/theme/tokens/radius.ts
create mode 100644 packages/ui/src/theme/tokens/typography.ts
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
+
+ setColorScheme((val as ColorSchemeType) || 'light')}
+ data={[
+ { value: 'light', label: 'Light' },
+ { value: 'dark', label: 'Dark' },
+ { value: 'dracula', label: 'Dracula' },
+ { value: 'blue', label: 'Blue' },
+ ]}
+ />
+ 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
+
+ Filled Button
+ Outline Button
+ Light Button
+ Subtle Button
+
+
+
+
+
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 && (
-
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
-
- )}
+ {(showActionsBack || showActionsHome) && (
+
+ {showActionsBack && (
+ window.history.back()}>
+ Go Back
+
+ )}
- {showActionsHome && (
-
- Back to Home
-
- )}
-
- )}
-
-
+ {showActionsHome && (
+
+ Back to Home
+
+ )}
+
+ )}
+
+
+
);
}
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 && (
-
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
-
- )}
+ {(showActionsBack || showActionsHome) && (
+
+ {showActionsBack && (
+ window.history.back()}>
+ Go Back
+
+ )}
- {showActionsHome && (
-
- Back to Home
-
- )}
-
- )}
-
-
+ {showActionsHome && (
+
+ Back to Home
+
+ )}
+
+ )}
+
+
+
);
}
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
From b0ceb3e44444a1dd3101bdcb5e54ffb43faacbf3 Mon Sep 17 00:00:00 2001
From: Firman Ramdhani <33869609+firmanramdhani@users.noreply.github.com>
Date: Fri, 27 Feb 2026 15:26:36 +0700
Subject: [PATCH 3/8] feat: streamline component imports and update package
exports for better organization
---
apps/web/src/apps/index.tsx | 5 +---
apps/web/src/apps/showcase/showcase-view.tsx | 29 +++++++++++---------
packages/ui/package.json | 6 ++--
packages/ui/src/components/button.ts | 1 -
packages/ui/src/components/card.ts | 1 -
packages/ui/src/components/checkbox.ts | 1 -
packages/ui/src/components/container.ts | 1 -
packages/ui/src/components/group.ts | 1 -
packages/ui/src/components/index.ts | 6 ++++
packages/ui/src/components/input.ts | 1 -
packages/ui/src/components/select.ts | 1 -
packages/ui/src/components/text.ts | 1 -
packages/ui/src/hooks/index.ts | 1 +
13 files changed, 26 insertions(+), 29 deletions(-)
delete mode 100644 packages/ui/src/components/button.ts
delete mode 100644 packages/ui/src/components/card.ts
delete mode 100644 packages/ui/src/components/checkbox.ts
delete mode 100644 packages/ui/src/components/container.ts
delete mode 100644 packages/ui/src/components/group.ts
create mode 100644 packages/ui/src/components/index.ts
delete mode 100644 packages/ui/src/components/input.ts
delete mode 100644 packages/ui/src/components/select.ts
delete mode 100644 packages/ui/src/components/text.ts
create mode 100644 packages/ui/src/hooks/index.ts
diff --git a/apps/web/src/apps/index.tsx b/apps/web/src/apps/index.tsx
index 478f9d5..6c5edc4 100644
--- a/apps/web/src/apps/index.tsx
+++ b/apps/web/src/apps/index.tsx
@@ -1,10 +1,7 @@
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';
-import { ComingSoon } from '@repo/ui/components/system-pages/coming-soon';
+import { NotFound, Forbidden, Maintenance, ComingSoon } from '@repo/ui/components';
const AuthModule = lazy(() => import('./auth'));
const AppModule = lazy(() => import('./modules'));
diff --git a/apps/web/src/apps/showcase/showcase-view.tsx b/apps/web/src/apps/showcase/showcase-view.tsx
index f7e7305..33bcbfa 100644
--- a/apps/web/src/apps/showcase/showcase-view.tsx
+++ b/apps/web/src/apps/showcase/showcase-view.tsx
@@ -1,12 +1,5 @@
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';
+import { Button, Card, Container, Select, Group, Stack, Text, Title, TextInput, Checkbox } from '@repo/ui/components';
interface ShowcaseViewProps {
colorScheme: ColorSchemeType;
@@ -23,7 +16,9 @@ export default function ShowcaseView({ colorScheme, setColorScheme, density, set
{/* Control Panel */}
- Control Panel
+
+ Control Panel
+
-
Typography
- This is dimmed small text.
+
+ Typography
+
+
+ This is dimmed small text.
+
This is standard text describing the components below.
-
Buttons
+
+ Buttons
+
Filled Button
Outline Button
@@ -69,7 +70,9 @@ export default function ShowcaseView({ colorScheme, setColorScheme, density, set
-
Form Elements
+
+ Form Elements
+
diff --git a/packages/ui/package.json b/packages/ui/package.json
index 758c527..c171984 100644
--- a/packages/ui/package.json
+++ b/packages/ui/package.json
@@ -3,10 +3,8 @@
"version": "0.0.0",
"exports": {
"./theme.css": "./src/theme.css",
- "./components/system-pages/*": "./src/components/system-pages/*.tsx",
- "./components/*": "./src/components/*.ts",
- "./hooks/*": "./src/hooks/*.ts",
- "./utils/*": "./src/utils/*.ts",
+ "./components": "./src/components/index.ts",
+ "./hooks": "./src/hooks/index.ts",
"./provider": "./src/provider/index.ts"
},
"license": "MIT",
diff --git a/packages/ui/src/components/button.ts b/packages/ui/src/components/button.ts
deleted file mode 100644
index ed36b20..0000000
--- a/packages/ui/src/components/button.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { Button, type ButtonProps } from '@mantine/core';
diff --git a/packages/ui/src/components/card.ts b/packages/ui/src/components/card.ts
deleted file mode 100644
index eb92515..0000000
--- a/packages/ui/src/components/card.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { Card, type CardProps } from '@mantine/core';
diff --git a/packages/ui/src/components/checkbox.ts b/packages/ui/src/components/checkbox.ts
deleted file mode 100644
index 33b461c..0000000
--- a/packages/ui/src/components/checkbox.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { Checkbox, type CheckboxProps } from '@mantine/core';
diff --git a/packages/ui/src/components/container.ts b/packages/ui/src/components/container.ts
deleted file mode 100644
index e1e7813..0000000
--- a/packages/ui/src/components/container.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { Container, type ContainerProps } from '@mantine/core';
diff --git a/packages/ui/src/components/group.ts b/packages/ui/src/components/group.ts
deleted file mode 100644
index 4d64a09..0000000
--- a/packages/ui/src/components/group.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { Group, type GroupProps, Stack, type StackProps } from '@mantine/core';
diff --git a/packages/ui/src/components/index.ts b/packages/ui/src/components/index.ts
new file mode 100644
index 0000000..423278d
--- /dev/null
+++ b/packages/ui/src/components/index.ts
@@ -0,0 +1,6 @@
+export * from '@mantine/core';
+
+export * from './system-pages/coming-soon';
+export * from './system-pages/forbidden';
+export * from './system-pages/maintenance';
+export * from './system-pages/not-found';
diff --git a/packages/ui/src/components/input.ts b/packages/ui/src/components/input.ts
deleted file mode 100644
index 509a3de..0000000
--- a/packages/ui/src/components/input.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { TextInput, type TextInputProps } from '@mantine/core';
diff --git a/packages/ui/src/components/select.ts b/packages/ui/src/components/select.ts
deleted file mode 100644
index 1d4dc94..0000000
--- a/packages/ui/src/components/select.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { Select, type SelectProps } from '@mantine/core';
diff --git a/packages/ui/src/components/text.ts b/packages/ui/src/components/text.ts
deleted file mode 100644
index 94ff3a3..0000000
--- a/packages/ui/src/components/text.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { Text, type TextProps, Title, type TitleProps } from '@mantine/core';
diff --git a/packages/ui/src/hooks/index.ts b/packages/ui/src/hooks/index.ts
new file mode 100644
index 0000000..57bbcc5
--- /dev/null
+++ b/packages/ui/src/hooks/index.ts
@@ -0,0 +1 @@
+export * from '@mantine/hooks';
From 7cf9f8fab5da30bb40effa43a394ec37d6fac317 Mon Sep 17 00:00:00 2001
From: Firman Ramdhani <33869609+firmanramdhani@users.noreply.github.com>
Date: Fri, 27 Feb 2026 15:54:20 +0700
Subject: [PATCH 4/8] feat: simplify color scheme options, enhance theme
provider, and add density styles
---
apps/web/src/apps/showcase/showcase-view.tsx | 4 +-
packages/ui/src/provider/theme-provider.tsx | 45 +++--------
packages/ui/src/theme.css | 81 ++++++++++++++++++++
packages/ui/src/theme/tokens/colors.ts | 71 ++++++++++++-----
packages/ui/src/theme/tokens/density.ts | 11 +++
5 files changed, 153 insertions(+), 59 deletions(-)
create mode 100644 packages/ui/src/theme/tokens/density.ts
diff --git a/apps/web/src/apps/showcase/showcase-view.tsx b/apps/web/src/apps/showcase/showcase-view.tsx
index 33bcbfa..db003f2 100644
--- a/apps/web/src/apps/showcase/showcase-view.tsx
+++ b/apps/web/src/apps/showcase/showcase-view.tsx
@@ -27,8 +27,6 @@ export default function ShowcaseView({ colorScheme, setColorScheme, density, set
data={[
{ value: 'light', label: 'Light' },
{ value: 'dark', label: 'Dark' },
- { value: 'dracula', label: 'Dracula' },
- { value: 'blue', label: 'Blue' },
]}
/>
-
+
Typography
diff --git a/packages/ui/src/provider/theme-provider.tsx b/packages/ui/src/provider/theme-provider.tsx
index 84a226d..eabd25f 100644
--- a/packages/ui/src/provider/theme-provider.tsx
+++ b/packages/ui/src/provider/theme-provider.tsx
@@ -1,10 +1,11 @@
import { MantineProvider, createTheme, MantineThemeOverride } from '@mantine/core';
import React from 'react';
-import { brandColors, errorColors, warningColors, successColors, infoColors, draculaColors, blueColors } from '../theme/tokens/colors';
+import { brandColors, errorColors, warningColors, successColors, infoColors } from '../theme/tokens/colors';
import { typography } from '../theme/tokens/typography';
import { radius } from '../theme/tokens/radius';
+import { densityStyles } from '../theme/tokens/density';
-export type ColorSchemeType = 'light' | 'dark' | 'dracula' | 'blue';
+export type ColorSchemeType = 'light' | 'dark';
export type DensityType = 'compact' | 'standard' | 'spacious';
interface ThemeProviderProps {
@@ -14,18 +15,6 @@ interface ThemeProviderProps {
}
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,
@@ -33,8 +22,6 @@ export function ThemeProvider({ children, colorScheme = 'light', density = 'stan
warning: warningColors,
success: successColors,
info: infoColors,
- dracula: draculaColors,
- bluetheme: blueColors,
},
primaryColor: 'brand',
fontFamily: typography.fontFamily,
@@ -43,27 +30,15 @@ export function ThemeProvider({ children, colorScheme = 'light', density = 'stan
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',
- });
- }
+ const mantineColorScheme: 'light' | 'dark' = colorScheme;
+ const themeOverride: MantineThemeOverride = baseTheme;
return (
-
+
{children}
);
diff --git a/packages/ui/src/theme.css b/packages/ui/src/theme.css
index 927fed0..aa14709 100644
--- a/packages/ui/src/theme.css
+++ b/packages/ui/src/theme.css
@@ -15,3 +15,84 @@
-moz-osx-font-smoothing: grayscale;
}
}
+
+@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;
+}
diff --git a/packages/ui/src/theme/tokens/colors.ts b/packages/ui/src/theme/tokens/colors.ts
index 30424a6..4f99530 100644
--- a/packages/ui/src/theme/tokens/colors.ts
+++ b/packages/ui/src/theme/tokens/colors.ts
@@ -14,37 +14,66 @@ export const brandColors: MantineColorsTuple = [
];
export const errorColors: MantineColorsTuple = [
- '#fef2f2', '#fee2e2', '#fecaca', '#fca5a5', '#f87171',
- '#ef4444', '#dc2626', '#b91c1c', '#991b1b', '#7f1d1d',
+ '#fef2f2',
+ '#fee2e2',
+ '#fecaca',
+ '#fca5a5',
+ '#f87171',
+ '#ef4444',
+ '#dc2626',
+ '#b91c1c',
+ '#991b1b',
+ '#7f1d1d',
];
export const warningColors: MantineColorsTuple = [
- '#fffbeb', '#fef3c7', '#fde68a', '#fcd34d', '#fbbf24',
- '#f59e0b', '#d97706', '#b45309', '#92400e', '#78350f',
+ '#fffbeb',
+ '#fef3c7',
+ '#fde68a',
+ '#fcd34d',
+ '#fbbf24',
+ '#f59e0b',
+ '#d97706',
+ '#b45309',
+ '#92400e',
+ '#78350f',
];
export const successColors: MantineColorsTuple = [
- '#f0fdf4', '#dcfce7', '#bbf7d0', '#86efac', '#4ade80',
- '#22c55e', '#16a34a', '#15803d', '#166534', '#14532d',
+ '#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',
+ '#f0f9ff',
+ '#e0f2fe',
+ '#bae6fd',
+ '#7dd3fc',
+ '#38bdf8',
+ '#0ea5e9',
+ '#0284c7',
+ '#0369a1',
+ '#075985',
+ '#0c4a6e',
];
export const grayColors: MantineColorsTuple = [
- '#f5f6f7', '#eceff1', '#e0e3e7', '#d1d5db', '#9ca3af',
- '#6b7280', '#4b5563', '#374151', '#1f2937', '#111827',
+ '#f5f6f7',
+ '#eceff1',
+ '#e0e3e7',
+ '#d1d5db',
+ '#9ca3af',
+ '#6b7280',
+ '#4b5563',
+ '#374151',
+ '#1f2937',
+ '#111827',
];
diff --git a/packages/ui/src/theme/tokens/density.ts b/packages/ui/src/theme/tokens/density.ts
new file mode 100644
index 0000000..04238bd
--- /dev/null
+++ b/packages/ui/src/theme/tokens/density.ts
@@ -0,0 +1,11 @@
+export 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' },
+ },
+};
From ad3397ee3df07cdb28bae19ad7e8cd2d82eedc41 Mon Sep 17 00:00:00 2001
From: Firman Ramdhani <33869609+firmanramdhani@users.noreply.github.com>
Date: Fri, 27 Feb 2026 16:07:55 +0700
Subject: [PATCH 5/8] feat: enhance theme.css with Mantine color mapping,
spacing, typography, and animation styles
---
.vscode/settings.json | 2 +-
packages/ui/src/theme.css | 320 ++++++++++++++++++++++++++++----------
2 files changed, 236 insertions(+), 86 deletions(-)
diff --git a/.vscode/settings.json b/.vscode/settings.json
index f692183..2970030 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -4,5 +4,5 @@
"mode": "auto"
}
],
- "cSpell.words": ["Millis", "Pandang", "Ujung", "WITA"]
+ "cSpell.words": ["mantine", "Millis", "Pandang", "Ujung", "WITA"]
}
diff --git a/packages/ui/src/theme.css b/packages/ui/src/theme.css
index aa14709..bd556d8 100644
--- a/packages/ui/src/theme.css
+++ b/packages/ui/src/theme.css
@@ -1,98 +1,248 @@
@import 'tailwindcss';
@source "../src";
-/* =========================================
- MANTINE BASE STYLES
- ========================================= */
@import '@mantine/core/styles.css';
-
-/* =========================================
- BASE RESETS (Minimal, let Mantine handle most)
- ========================================= */
-@layer base {
- body {
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
- }
-}
+@import 'tailwindcss';
@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;
+ /* =========================================
+ 1. COLORS (Strictly mapped to Mantine 0-9)
+ ========================================= */
+ --color-brand-50: var(--mantine-color-brand-0);
+ --color-brand-100: var(--mantine-color-brand-1);
+ --color-brand-200: var(--mantine-color-brand-2);
+ --color-brand-300: var(--mantine-color-brand-3);
+ --color-brand-400: var(--mantine-color-brand-4);
+ --color-brand-500: var(--mantine-color-brand-5);
+ --color-brand-600: var(--mantine-color-brand-6);
+ --color-brand-700: var(--mantine-color-brand-7);
+ --color-brand-800: var(--mantine-color-brand-8);
+ --color-brand-900: var(--mantine-color-brand-9);
- /* 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;
+ --color-error-50: var(--mantine-color-error-0);
+ --color-error-100: var(--mantine-color-error-1);
+ --color-error-200: var(--mantine-color-error-2);
+ --color-error-300: var(--mantine-color-error-3);
+ --color-error-400: var(--mantine-color-error-4);
+ --color-error-500: var(--mantine-color-error-5);
+ --color-error-600: var(--mantine-color-error-6);
+ --color-error-700: var(--mantine-color-error-7);
+ --color-error-800: var(--mantine-color-error-8);
+ --color-error-900: var(--mantine-color-error-9);
- /* -------------------------------
- COLORS: SEMANTICS (COMPLETED)
- ------------------------------- */
+ --color-warning-50: var(--mantine-color-warning-0);
+ --color-warning-100: var(--mantine-color-warning-1);
+ --color-warning-200: var(--mantine-color-warning-2);
+ --color-warning-300: var(--mantine-color-warning-3);
+ --color-warning-400: var(--mantine-color-warning-4);
+ --color-warning-500: var(--mantine-color-warning-5);
+ --color-warning-600: var(--mantine-color-warning-6);
+ --color-warning-700: var(--mantine-color-warning-7);
+ --color-warning-800: var(--mantine-color-warning-8);
+ --color-warning-900: var(--mantine-color-warning-9);
- /* 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;
+ --color-success-50: var(--mantine-color-success-0);
+ --color-success-100: var(--mantine-color-success-1);
+ --color-success-200: var(--mantine-color-success-2);
+ --color-success-300: var(--mantine-color-success-3);
+ --color-success-400: var(--mantine-color-success-4);
+ --color-success-500: var(--mantine-color-success-5);
+ --color-success-600: var(--mantine-color-success-6);
+ --color-success-700: var(--mantine-color-success-7);
+ --color-success-800: var(--mantine-color-success-8);
+ --color-success-900: var(--mantine-color-success-9);
- /* 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;
+ --color-info-50: var(--mantine-color-info-0);
+ --color-info-100: var(--mantine-color-info-1);
+ --color-info-200: var(--mantine-color-info-2);
+ --color-info-300: var(--mantine-color-info-3);
+ --color-info-400: var(--mantine-color-info-4);
+ --color-info-500: var(--mantine-color-info-5);
+ --color-info-600: var(--mantine-color-info-6);
+ --color-info-700: var(--mantine-color-info-7);
+ --color-info-800: var(--mantine-color-info-8);
+ --color-info-900: var(--mantine-color-info-9);
- /* 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;
+ /* =========================================
+ 2. SPACING & CONTAINERS
+ ========================================= */
+ --spacing: 0.25rem;
- /* 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;
+ /* Core mapped to Mantine */
+ --spacing-xs: var(--mantine-spacing-xs);
+ --spacing-sm: var(--mantine-spacing-sm);
+ --spacing-md: var(--mantine-spacing-md);
+ --spacing-lg: var(--mantine-spacing-lg);
+ --spacing-xl: var(--mantine-spacing-xl);
+
+ --breakpoint-sm: 40rem;
+ --breakpoint-md: 48rem;
+ --breakpoint-lg: 64rem;
+ --breakpoint-xl: 80rem;
+ --breakpoint-2xl: 96rem;
+ --container-3xs: 16rem;
+ --container-2xs: 18rem;
+ --container-xs: 20rem;
+ --container-sm: 24rem;
+ --container-md: 28rem;
+ --container-lg: 32rem;
+ --container-xl: 36rem;
+ --container-2xl: 42rem;
+ --container-3xl: 48rem;
+ --container-4xl: 56rem;
+ --container-5xl: 64rem;
+ --container-6xl: 72rem;
+ --container-7xl: 80rem;
+
+ /* =========================================
+ 3. TYPOGRAPHY
+ ========================================= */
+ /* Core text sizes mapped to Mantine, extended kept static */
+ --text-xs: var(--mantine-font-size-xs);
+ --text-xs--line-height: calc(1 / 0.75);
+ --text-sm: var(--mantine-font-size-sm);
+ --text-sm--line-height: calc(1.25 / 0.875);
+ --text-base: var(--mantine-font-size-md);
+ --text-base--line-height: calc(1.5 / 1);
+ --text-lg: var(--mantine-font-size-lg);
+ --text-lg--line-height: calc(1.75 / 1.125);
+ --text-xl: var(--mantine-font-size-xl);
+ --text-xl--line-height: calc(1.75 / 1.25);
+
+ --text-2xl: 1.5rem;
+ --text-2xl--line-height: calc(2 / 1.5);
+ --text-3xl: 1.875rem;
+ --text-3xl--line-height: calc(2.25 / 1.875);
+ --text-4xl: 2.25rem;
+ --text-4xl--line-height: calc(2.5 / 2.25);
+ --text-5xl: 3rem;
+ --text-5xl--line-height: 1;
+ --text-6xl: 3.75rem;
+ --text-6xl--line-height: 1;
+ --text-7xl: 4.5rem;
+ --text-7xl--line-height: 1;
+ --text-8xl: 6rem;
+ --text-8xl--line-height: 1;
+ --text-9xl: 8rem;
+ --text-9xl--line-height: 1;
+
+ --font-weight-thin: 100;
+ --font-weight-extralight: 200;
+ --font-weight-light: 300;
+ --font-weight-normal: 400;
+ --font-weight-medium: 500;
+ --font-weight-semibold: 600;
+ --font-weight-bold: 700;
+ --font-weight-extrabold: 800;
+ --font-weight-black: 900;
+
+ --tracking-tighter: -0.05em;
+ --tracking-tight: -0.025em;
+ --tracking-normal: 0em;
+ --tracking-wide: 0.025em;
+ --tracking-wider: 0.05em;
+ --tracking-widest: 0.1em;
+
+ --leading-tight: 1.25;
+ --leading-snug: 1.375;
+ --leading-normal: 1.5;
+ --leading-relaxed: 1.625;
+ --leading-loose: 2;
+
+ /* =========================================
+ 4. RADIUS
+ ========================================= */
+ --radius-xs: var(--mantine-radius-xs);
+ --radius-sm: var(--mantine-radius-sm);
+ --radius-md: var(--mantine-radius-md);
+ --radius-lg: var(--mantine-radius-lg);
+ --radius-xl: var(--mantine-radius-xl);
+ --radius-2xl: 1rem;
+ --radius-3xl: 1.5rem;
+ --radius-4xl: 2rem;
+
+ /* =========================================
+ 5. SHADOWS & BLURS
+ ========================================= */
+ --shadow-2xs: 0 1px rgb(0 0 0 / 0.05);
+ --shadow-xs: var(--mantine-shadow-xs);
+ --shadow-sm: var(--mantine-shadow-sm);
+ --shadow-md: var(--mantine-shadow-md);
+ --shadow-lg: var(--mantine-shadow-lg);
+ --shadow-xl: var(--mantine-shadow-xl);
+ --shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);
+
+ --inset-shadow-2xs: inset 0 1px rgb(0 0 0 / 0.05);
+ --inset-shadow-xs: inset 0 1px 1px rgb(0 0 0 / 0.05);
+ --inset-shadow-sm: inset 0 2px 4px rgb(0 0 0 / 0.05);
+
+ --drop-shadow-xs: 0 1px 1px rgb(0 0 0 / 0.05);
+ --drop-shadow-sm: 0 1px 2px rgb(0 0 0 / 0.15);
+ --drop-shadow-md: 0 3px 3px rgb(0 0 0 / 0.12);
+ --drop-shadow-lg: 0 4px 4px rgb(0 0 0 / 0.15);
+ --drop-shadow-xl: 0 9px 7px rgb(0 0 0 / 0.1);
+ --drop-shadow-2xl: 0 25px 25px rgb(0 0 0 / 0.15);
+
+ --text-shadow-2xs: 0px 1px 0px rgb(0 0 0 / 0.15);
+ --text-shadow-xs: 0px 1px 1px rgb(0 0 0 / 0.2);
+ --text-shadow-sm: 0px 1px 0px rgb(0 0 0 / 0.075), 0px 1px 1px rgb(0 0 0 / 0.075), 0px 2px 2px rgb(0 0 0 / 0.075);
+ --text-shadow-md: 0px 1px 1px rgb(0 0 0 / 0.1), 0px 1px 2px rgb(0 0 0 / 0.1), 0px 2px 4px rgb(0 0 0 / 0.1);
+ --text-shadow-lg: 0px 1px 2px rgb(0 0 0 / 0.1), 0px 3px 2px rgb(0 0 0 / 0.1), 0px 4px 8px rgb(0 0 0 / 0.1);
+
+ --blur-xs: 4px;
+ --blur-sm: 8px;
+ --blur-md: 12px;
+ --blur-lg: 16px;
+ --blur-xl: 24px;
+ --blur-2xl: 40px;
+ --blur-3xl: 64px;
+
+ /* =========================================
+ 6. MISCELLANEOUS (Aspect, Anim, Perspective)
+ ========================================= */
+ --perspective-dramatic: 100px;
+ --perspective-near: 300px;
+ --perspective-normal: 500px;
+ --perspective-midrange: 800px;
+ --perspective-distant: 1200px;
+
+ --aspect-video: 16 / 9;
+
+ --ease-in: cubic-bezier(0.4, 0, 1, 1);
+ --ease-out: cubic-bezier(0, 0, 0.2, 1);
+ --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
+
+ --animate-spin: spin 1s linear infinite;
+ --animate-ping: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;
+ --animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
+ --animate-bounce: bounce 1s infinite;
+
+ @keyframes spin {
+ to {
+ transform: rotate(360deg);
+ }
+ }
+ @keyframes ping {
+ 75%,
+ 100% {
+ transform: scale(2);
+ opacity: 0;
+ }
+ }
+ @keyframes pulse {
+ 50% {
+ opacity: 0.5;
+ }
+ }
+ @keyframes bounce {
+ 0%,
+ 100% {
+ transform: translateY(-25%);
+ animation-timing-function: cubic-bezier(0.8, 0, 1, 1);
+ }
+ 50% {
+ transform: none;
+ animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
+ }
+ }
}
From 3439c7c6068e2fad357339ed9a8909ea9a35e4ad Mon Sep 17 00:00:00 2001
From: Firman Ramdhani <33869609+firmanramdhani@users.noreply.github.com>
Date: Fri, 27 Feb 2026 16:10:59 +0700
Subject: [PATCH 6/8] feat: add 72Mono font files and update theme.css for
improved styling
---
.../fonts/72Mono_webfonts/72Mono-Bold-Full.woff | Bin 0 -> 52776 bytes
.../72Mono_webfonts/72Mono-Bold-full.woff2 | Bin 0 -> 53272 bytes
.../fonts/72Mono_webfonts/72Mono-Bold.woff | Bin 0 -> 24820 bytes
.../fonts/72Mono_webfonts/72Mono-Bold.woff2 | Bin 0 -> 21408 bytes
.../72Mono_webfonts/72Mono-Regular-full.woff | Bin 0 -> 61204 bytes
.../72Mono_webfonts/72Mono-Regular-full.woff2 | Bin 0 -> 52156 bytes
.../fonts/72Mono_webfonts/72Mono-Regular.woff | Bin 0 -> 24432 bytes
.../fonts/72Mono_webfonts/72Mono-Regular.woff2 | Bin 0 -> 21112 bytes
packages/ui/src/theme.css | 4 +---
9 files changed, 1 insertion(+), 3 deletions(-)
create mode 100644 packages/ui/src/assets/fonts/72Mono_webfonts/72Mono-Bold-Full.woff
create mode 100644 packages/ui/src/assets/fonts/72Mono_webfonts/72Mono-Bold-full.woff2
create mode 100644 packages/ui/src/assets/fonts/72Mono_webfonts/72Mono-Bold.woff
create mode 100644 packages/ui/src/assets/fonts/72Mono_webfonts/72Mono-Bold.woff2
create mode 100644 packages/ui/src/assets/fonts/72Mono_webfonts/72Mono-Regular-full.woff
create mode 100644 packages/ui/src/assets/fonts/72Mono_webfonts/72Mono-Regular-full.woff2
create mode 100644 packages/ui/src/assets/fonts/72Mono_webfonts/72Mono-Regular.woff
create mode 100644 packages/ui/src/assets/fonts/72Mono_webfonts/72Mono-Regular.woff2
diff --git a/packages/ui/src/assets/fonts/72Mono_webfonts/72Mono-Bold-Full.woff b/packages/ui/src/assets/fonts/72Mono_webfonts/72Mono-Bold-Full.woff
new file mode 100644
index 0000000000000000000000000000000000000000..87409452f9ab7883fcde7c4b4678db7947420851
GIT binary patch
literal 52776
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≈yT`s
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