From 6e7fdeb3a33bd0beab9cf1bce7e894e07df7fe56 Mon Sep 17 00:00:00 2001 From: Marco Beretta <81851188+berry-13@users.noreply.github.com> Date: Fri, 18 Jul 2025 18:54:03 +0200 Subject: [PATCH] feat: integrate Tailwind CSS and update theme context for improved styling --- package-lock.json | 208 +++++++++++++-------- packages/client/package.json | 5 + packages/client/postcss.config.js | 8 + packages/client/src/components/index.ts | 1 + packages/client/src/hooks/ThemeContext.tsx | 92 +++------ packages/client/src/index.css | 172 +++++++++++++++++ packages/client/src/index.ts | 3 + packages/client/tailwind.config.js | 130 +++++++++++++ 8 files changed, 476 insertions(+), 143 deletions(-) create mode 100644 packages/client/postcss.config.js create mode 100644 packages/client/src/index.css create mode 100644 packages/client/tailwind.config.js diff --git a/package-lock.json b/package-lock.json index 1328da8600..c586b5d11d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4595,44 +4595,6 @@ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" } }, - "client/node_modules/autoprefixer": { - "version": "10.4.20", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", - "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "browserslist": "^4.23.3", - "caniuse-lite": "^1.0.30001646", - "fraction.js": "^4.3.7", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.1", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, "client/node_modules/babel-plugin-polyfill-corejs2": { "version": "0.4.12", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.12.tgz", @@ -4746,23 +4708,6 @@ "url": "https://opencollective.com/core-js" } }, - "client/node_modules/electron-to-chromium": { - "version": "1.5.103", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.103.tgz", - "integrity": "sha512-P6+XzIkfndgsrjROJWfSvVEgNHtPgbhVyTkwLjUM2HU/h7pZRORgaTlHqfAikqxKmdJMLW8fftrdGWbd/Ds0FA==", - "dev": true, - "license": "ISC" - }, - "client/node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "client/node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -4773,13 +4718,6 @@ "node": ">=4" } }, - "client/node_modules/node-releases": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", - "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", - "dev": true, - "license": "MIT" - }, "client/node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -27104,6 +27042,36 @@ "tslib": "^2.8.0" } }, + "node_modules/@tailwindcss/typography": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.16.tgz", + "integrity": "sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.castarray": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "postcss-selector-parser": "6.0.10" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" + } + }, + "node_modules/@tailwindcss/typography/node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@tanstack/match-sorter-utils": { "version": "8.11.8", "resolved": "https://registry.npmjs.org/@tanstack/match-sorter-utils/-/match-sorter-utils-8.11.8.tgz", @@ -28855,9 +28823,9 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.17", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.17.tgz", - "integrity": "sha512-/cpVNRLSfhOtcGflT13P2794gVSgmPgTR+erw5ifnMLZb0UnSlkK4tquLmkd3BhA+nLo5tX8Cu0upUsGKvKbmg==", + "version": "10.4.21", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", + "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", "dev": true, "funding": [ { @@ -28873,12 +28841,13 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "browserslist": "^4.22.2", - "caniuse-lite": "^1.0.30001578", + "browserslist": "^4.24.4", + "caniuse-lite": "^1.0.30001702", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", + "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "bin": { @@ -28891,6 +28860,70 @@ "postcss": "^8.1.0" } }, + "node_modules/autoprefixer/node_modules/browserslist": { + "version": "4.25.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", + "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001726", + "electron-to-chromium": "^1.5.173", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/autoprefixer/node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -29668,9 +29701,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001706", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001706.tgz", - "integrity": "sha512-3ZczoTApMAZwPKYWmwVbQMFpXBDds3/0VciVoUwPUbldlYyVLmRVuRs/PcUZtHpbLRpzzDvrvnFuREsGt6lUug==", + "version": "1.0.30001727", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz", + "integrity": "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==", "funding": [ { "type": "opencollective", @@ -31607,9 +31640,10 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.28", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.28.tgz", - "integrity": "sha512-VufdJl+rzaKZoYVUijN13QcXVF5dWPZANeFTLNy+OSpHdDL5ynXTF35+60RSBbaQYB1ae723lQXHCrf4pyLsMw==" + "version": "1.5.187", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.187.tgz", + "integrity": "sha512-cl5Jc9I0KGUoOoSbxvTywTa40uspGJt/BDBoDLoxJRSBpWh4FFXBsjNRHfQrONsV/OoEjDfHUmZQa2d6Ze4YgA==", + "license": "ISC" }, "node_modules/elliptic": { "version": "6.6.1", @@ -32044,9 +32078,10 @@ } }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", "engines": { "node": ">=6" } @@ -37623,6 +37658,13 @@ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" }, + "node_modules/lodash.castarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", + "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", @@ -39964,9 +40006,10 @@ "dev": true }, "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "license": "MIT" }, "node_modules/node-stdlib-browser": { "version": "1.3.1", @@ -49823,15 +49866,20 @@ "@rollup/plugin-node-resolve": "^15.0.0", "@rollup/plugin-replace": "^5.0.5", "@rollup/plugin-terser": "^0.4.4", + "@tailwindcss/typography": "^0.5.10", "@testing-library/react": "^16.3.0", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", + "autoprefixer": "^10.4.20", + "postcss": "^8.4.31", "react-hook-form": "^7.60.0", "rimraf": "^5.0.1", "rollup": "^4.0.0", "rollup-plugin-peer-deps-external": "^2.2.4", "rollup-plugin-postcss": "^4.0.2", "rollup-plugin-typescript2": "^0.35.0", + "tailwindcss": "^3.4.1", + "tailwindcss-animate": "^1.0.5", "typescript": "^5.0.0" }, "peerDependencies": { diff --git a/packages/client/package.json b/packages/client/package.json index 8e4cffda0a..a59922742d 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -70,15 +70,20 @@ "@rollup/plugin-node-resolve": "^15.0.0", "@rollup/plugin-replace": "^5.0.5", "@rollup/plugin-terser": "^0.4.4", + "@tailwindcss/typography": "^0.5.10", "@testing-library/react": "^16.3.0", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", + "autoprefixer": "^10.4.20", + "postcss": "^8.4.31", "react-hook-form": "^7.60.0", "rimraf": "^5.0.1", "rollup": "^4.0.0", "rollup-plugin-peer-deps-external": "^2.2.4", "rollup-plugin-postcss": "^4.0.2", "rollup-plugin-typescript2": "^0.35.0", + "tailwindcss": "^3.4.1", + "tailwindcss-animate": "^1.0.5", "typescript": "^5.0.0" } } diff --git a/packages/client/postcss.config.js b/packages/client/postcss.config.js new file mode 100644 index 0000000000..9b5194ec68 --- /dev/null +++ b/packages/client/postcss.config.js @@ -0,0 +1,8 @@ +module.exports = { + plugins: [ + require('postcss-import'), + require('postcss-preset-env'), + require('tailwindcss'), + require('autoprefixer'), + ], +}; diff --git a/packages/client/src/components/index.ts b/packages/client/src/components/index.ts index f166e8103f..523eaf404e 100644 --- a/packages/client/src/components/index.ts +++ b/packages/client/src/components/index.ts @@ -4,6 +4,7 @@ export * from './AlertDialog'; export * from './Breadcrumb'; export * from './Button'; export * from './Checkbox'; +export * from './Collapsible'; export * from './DataTableColumnHeader'; export * from './Dialog'; export * from './DropdownMenu'; diff --git a/packages/client/src/hooks/ThemeContext.tsx b/packages/client/src/hooks/ThemeContext.tsx index 74516fcab0..e7c8f6b083 100644 --- a/packages/client/src/hooks/ThemeContext.tsx +++ b/packages/client/src/hooks/ThemeContext.tsx @@ -1,7 +1,5 @@ -//ThemeContext.js -// source: https://plainenglish.io/blog/light-and-dark-mode-in-react-web-application-with-tailwind-css-89674496b942 -import { useSetAtom } from 'jotai'; import React, { createContext, useState, useEffect } from 'react'; +import { useSetAtom } from 'jotai'; import { getInitialTheme, applyFontSize } from '~/utils'; import { fontSizeAtom } from '~/store'; @@ -10,21 +8,10 @@ type ProviderValue = { setTheme: React.Dispatch>; }; -const defaultContextValue: ProviderValue = { - theme: getInitialTheme(), - setTheme: () => { - return; - }, -}; - -export const isDark = (theme: string): boolean => { - if (theme === 'system') { - return window.matchMedia('(prefers-color-scheme: dark)').matches; - } - return theme === 'dark'; -}; - -export const ThemeContext = createContext(defaultContextValue); +export const ThemeContext = createContext({ + theme: 'light', + setTheme: () => {}, +}); export const ThemeProvider = ({ initialTheme, @@ -33,56 +20,35 @@ export const ThemeProvider = ({ initialTheme?: string; children: React.ReactNode; }) => { - const [theme, setTheme] = useState(getInitialTheme); + const [theme, setTheme] = useState(() => initialTheme ?? getInitialTheme()); const setFontSize = useSetAtom(fontSizeAtom); - const rawSetTheme = (rawTheme: string) => { - const root = window.document.documentElement; - const darkMode = isDark(rawTheme); - - root.classList.remove(darkMode ? 'light' : 'dark'); - root.classList.add(darkMode ? 'dark' : 'light'); - - localStorage.setItem('color-theme', rawTheme); - }; - useEffect(() => { - const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); - const changeThemeOnSystemChange = () => { - rawSetTheme(mediaQuery.matches ? 'dark' : 'light'); - }; + const root = document.documentElement; + const darkMode = + theme === 'system' + ? window.matchMedia('(prefers-color-scheme: dark)').matches + : theme === 'dark'; - mediaQuery.addEventListener('change', changeThemeOnSystemChange); - - return () => { - mediaQuery.removeEventListener('change', changeThemeOnSystemChange); - }; - }, []); - - useEffect(() => { - const fontSize = localStorage.getItem('fontSize'); - if (fontSize == null) { - setFontSize('text-base'); - applyFontSize('text-base'); - localStorage.setItem('fontSize', JSON.stringify('text-base')); - return; - } - try { - applyFontSize(JSON.parse(fontSize)); - } catch (error) { - console.log(error); - } - // Reason: This effect should only run once, and `setFontSize` is a stable function - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - if (initialTheme) { - rawSetTheme(initialTheme); - } - - useEffect(() => { - rawSetTheme(theme); + root.classList.toggle('dark', darkMode); + root.classList.toggle('light', !darkMode); + localStorage.setItem('color-theme', theme); }, [theme]); + useEffect(() => { + if (theme !== 'system') return; + const mq = window.matchMedia('(prefers-color-scheme: dark)'); + const handler = (e: MediaQueryListEvent) => setTheme(e.matches ? 'dark' : 'light'); + + mq.addEventListener('change', handler); + return () => mq.removeEventListener('change', handler); + }, [theme]); + + useEffect(() => { + const saved = localStorage.getItem('fontSize') || 'text-base'; + applyFontSize(saved); + setFontSize(saved); + }, [setFontSize]); + return {children}; }; diff --git a/packages/client/src/index.css b/packages/client/src/index.css new file mode 100644 index 0000000000..d9aeee7b9e --- /dev/null +++ b/packages/client/src/index.css @@ -0,0 +1,172 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +/* Custom Variables */ +:root { + --white: #fff; + --black: #000; + --gray-20: #ececf1; + --gray-50: #f7f7f8; + --gray-100: #ececec; + --gray-200: #e3e3e3; + --gray-300: #cdcdcd; + --gray-400: #999696; + --gray-500: #595959; + --gray-600: #424242; + --gray-700: #2f2f2f; + --gray-800: #212121; + --gray-850: #171717; + --gray-900: #0d0d0d; + --green-50: #ecfdf5; + --green-100: #d1fae5; + --green-200: #a7f3d0; + --green-300: #6ee7b7; + --green-400: #34d399; + --green-500: #10b981; + --green-600: #059669; + --green-700: #047857; + --green-800: #065f46; + --green-900: #064e3b; + --green-950: #022c22; + --red-50: #fef2f2; + --red-100: #fee2e2; + --red-200: #fecaca; + --red-300: #fca5a5; + --red-400: #f87171; + --red-500: #ef4444; + --red-600: #dc2626; + --red-700: #b91c1c; + --red-800: #991b1b; + --red-900: #7f1d1d; + --red-950: #450a0a; + --amber-50: #fffbeb; + --amber-100: #fef3c7; + --amber-200: #fde68a; + --amber-300: #fcd34d; + --amber-400: #fbbf24; + --amber-500: #f59e0b; + --amber-600: #d97706; + --amber-700: #b45309; + --amber-800: #92400e; + --amber-900: #78350f; + --amber-950: #451a03; +} + +html { + --presentation: var(--white); + --text-primary: var(--gray-800); + --text-secondary: var(--gray-600); + --text-secondary-alt: var(--gray-500); + --text-tertiary: var(--gray-500); + --text-warning: var(--amber-500); + --ring-primary: var(--gray-500); + --header-primary: var(--white); + --header-hover: var(--gray-50); + --header-button-hover: var(--gray-50); + --surface-active: var(--gray-100); + --surface-active-alt: var(--gray-200); + --surface-hover: var(--gray-200); + --surface-hover-alt: var(--gray-300); + --surface-primary: var(--white); + --surface-primary-alt: var(--gray-50); + --surface-primary-contrast: var(--gray-100); + --surface-secondary: var(--gray-50); + --surface-secondary-alt: var(--gray-200); + --surface-tertiary: var(--gray-100); + --surface-tertiary-alt: var(--white); + --surface-dialog: var(--white); + --surface-submit: var(--green-700); + --surface-submit-hover: var(--green-800); + --surface-destructive: var(--red-700); + --surface-destructive-hover: var(--red-800); + --surface-chat: var(--white); + --border-light: var(--gray-200); + --border-medium-alt: var(--gray-300); + --border-medium: var(--gray-300); + --border-heavy: var(--gray-400); + --border-xheavy: var(--gray-500); + + --background: 0 0% 100%; + --foreground: 0 0% 3.9%; + --card: 0 0% 100%; + --card-foreground: 0 0% 3.9%; + --primary: 0 0% 9%; + --primary-foreground: 0 0% 98%; + --secondary: 0 0% 96.1%; + --secondary-foreground: 0 0% 9%; + --muted: 0 0% 96.1%; + --muted-foreground: 0 0% 45.1%; + --accent: 0 0% 96.1%; + --accent-foreground: 0 0% 9%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + --border: 0 0% 89.8%; + --input: 0 0% 89.8%; + --ring: 0 0% 3.9%; + --radius: 0.5rem; + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; + --switch-unchecked: 0 0% 58%; +} + +.dark { + --presentation: var(--gray-800); + --text-primary: var(--gray-100); + --text-secondary: var(--gray-300); + --text-secondary-alt: var(--gray-400); + --text-tertiary: var(--gray-500); + --text-warning: var(--amber-500); + --header-primary: var(--gray-700); + --header-hover: var(--gray-600); + --header-button-hover: var(--gray-700); + --surface-active: var(--gray-500); + --surface-active-alt: var(--gray-700); + --surface-hover: var(--gray-600); + --surface-hover-alt: var(--gray-600); + --surface-primary: var(--gray-900); + --surface-primary-alt: var(--gray-850); + --surface-primary-contrast: var(--gray-850); + --surface-secondary: var(--gray-800); + --surface-secondary-alt: var(--gray-800); + --surface-tertiary: var(--gray-700); + --surface-tertiary-alt: var(--gray-700); + --surface-dialog: var(--gray-850); + --surface-submit: var(--green-700); + --surface-submit-hover: var(--green-800); + --surface-destructive: var(--red-800); + --surface-destructive-hover: var(--red-900); + --surface-chat: var(--gray-700); + --border-light: var(--gray-700); + --border-medium-alt: var(--gray-600); + --border-medium: var(--gray-600); + --border-heavy: var(--gray-500); + --border-xheavy: var(--gray-400); + + --background: 0 0% 7%; + --foreground: 0 0% 98%; + --card: 0 0% 3.9%; + --card-foreground: 0 0% 98%; + --primary: 0 0% 98%; + --primary-foreground: 0 0% 9%; + --secondary: 0 0% 14.9%; + --secondary-foreground: 0 0% 98%; + --muted: 0 0% 14.9%; + --muted-foreground: 0 0% 63.9%; + --accent: 0 0% 14.9%; + --accent-foreground: 0 0% 98%; + --destructive: 0 62.8% 40.6%; + --destructive-foreground: 0 0% 98%; + --border: 0 0% 14.9%; + --input: 0 0% 14.9%; + --ring: 0 0% 83.1%; + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55%; + --switch-unchecked: 0 0% 40%; +} diff --git a/packages/client/src/index.ts b/packages/client/src/index.ts index b1b10a4b67..f3958687a9 100644 --- a/packages/client/src/index.ts +++ b/packages/client/src/index.ts @@ -1,3 +1,6 @@ +// Styles +import './index.css'; + // Components export * from './components'; diff --git a/packages/client/tailwind.config.js b/packages/client/tailwind.config.js new file mode 100644 index 0000000000..8fd98fdec4 --- /dev/null +++ b/packages/client/tailwind.config.js @@ -0,0 +1,130 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: ['./src/**/*.{js,jsx,ts,tsx}'], + darkMode: ['class'], + theme: { + extend: { + width: { + authPageWidth: '370px', + }, + keyframes: { + 'accordion-down': { + from: { height: 0 }, + to: { height: 'var(--radix-accordion-content-height)' }, + }, + 'accordion-up': { + from: { height: 'var(--radix-accordion-content-height)' }, + to: { height: 0 }, + }, + }, + animation: { + 'fade-in': 'fadeIn 0.5s ease-out forwards', + 'accordion-down': 'accordion-down 0.2s ease-out', + 'accordion-up': 'accordion-up 0.2s ease-out', + }, + colors: { + gray: { + 20: '#ececf1', + 50: '#f7f7f8', + 100: '#ececec', + 200: '#e3e3e3', + 300: '#cdcdcd', + 400: '#999696', + 500: '#595959', + 600: '#424242', + 700: '#2f2f2f', + 800: '#212121', + 850: '#171717', + 900: '#0d0d0d', + }, + green: { + 50: '#f1f9f7', + 100: '#def2ed', + 200: '#a6e5d6', + 300: '#6dc8b9', + 400: '#41a79d', + 500: '#10a37f', + 550: '#349072', + 600: '#126e6b', + 700: '#0a4f53', + 800: '#06373e', + 900: '#031f29', + }, + 'brand-purple': '#ab68ff', + presentation: 'var(--presentation)', + 'text-primary': 'var(--text-primary)', + 'text-secondary': 'var(--text-secondary)', + 'text-secondary-alt': 'var(--text-secondary-alt)', + 'text-tertiary': 'var(--text-tertiary)', + 'text-warning': 'var(--text-warning)', + 'ring-primary': 'var(--ring-primary)', + 'header-primary': 'var(--header-primary)', + 'header-hover': 'var(--header-hover)', + 'header-button-hover': 'var(--header-button-hover)', + 'surface-active': 'var(--surface-active)', + 'surface-active-alt': 'var(--surface-active-alt)', + 'surface-hover': 'var(--surface-hover)', + 'surface-hover-alt': 'var(--surface-hover-alt)', + 'surface-primary': 'var(--surface-primary)', + 'surface-primary-alt': 'var(--surface-primary-alt)', + 'surface-primary-contrast': 'var(--surface-primary-contrast)', + 'surface-secondary': 'var(--surface-secondary)', + 'surface-secondary-alt': 'var(--surface-secondary-alt)', + 'surface-tertiary': 'var(--surface-tertiary)', + 'surface-tertiary-alt': 'var(--surface-tertiary-alt)', + 'surface-dialog': 'var(--surface-dialog)', + 'surface-submit': 'var(--surface-submit)', + 'surface-submit-hover': 'var(--surface-submit-hover)', + 'surface-destructive': 'var(--surface-destructive)', + 'surface-destructive-hover': 'var(--surface-destructive-hover)', + 'surface-chat': 'var(--surface-chat)', + 'border-light': 'var(--border-light)', + 'border-medium': 'var(--border-medium)', + 'border-medium-alt': 'var(--border-medium-alt)', + 'border-heavy': 'var(--border-heavy)', + 'border-xheavy': 'var(--border-xheavy)', + /* These are test styles */ + border: 'hsl(var(--border))', + input: 'hsl(var(--input))', + ['switch-unchecked']: 'hsl(var(--switch-unchecked))', + ring: 'hsl(var(--ring))', + background: 'hsl(var(--background))', + foreground: 'hsl(var(--foreground))', + primary: { + DEFAULT: 'hsl(var(--primary))', + foreground: 'hsl(var(--primary-foreground))', + }, + secondary: { + DEFAULT: 'hsl(var(--secondary))', + foreground: 'hsl(var(--secondary-foreground))', + }, + destructive: { + DEFAULT: 'hsl(var(--destructive))', + foreground: 'hsl(var(--destructive-foreground))', + }, + muted: { + DEFAULT: 'hsl(var(--muted))', + foreground: 'hsl(var(--muted-foreground))', + }, + accent: { + DEFAULT: 'hsl(var(--accent))', + foreground: 'hsl(var(--accent-foreground))', + }, + card: { + DEFAULT: 'hsl(var(--card))', + foreground: 'hsl(var(--card-foreground))', + }, + }, + borderRadius: { + lg: 'var(--radius)', + md: 'calc(var(--radius) - 2px)', + sm: 'calc(var(--radius) - 4px)', + }, + }, + }, + plugins: [ + require('tailwindcss-animate'), + require('tailwindcss-radix')(), + // require('@tailwindcss/typography'), + ], +};