diff --git a/packages/react/components.json b/packages/react/components.json index 943a49837..129dfc1d3 100644 --- a/packages/react/components.json +++ b/packages/react/components.json @@ -1,6 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema.json", - "style": "default", + "style": "new-york", "rsc": false, "tsx": true, "tailwind": { diff --git a/packages/react/package-lock.json b/packages/react/package-lock.json index e4fcaa079..dcb3f6538 100644 --- a/packages/react/package-lock.json +++ b/packages/react/package-lock.json @@ -8,6 +8,7 @@ "name": "holodex-react", "version": "0.0.1", "dependencies": { + "@radix-ui/react-icons": "^1.3.0", "@radix-ui/themes": "^1.1.2", "@tanstack/react-query": "^4.35.0", "class-variance-authority": "^0.7.0", @@ -35,6 +36,7 @@ "zustand": "^4.4.1" }, "devDependencies": { + "@radix-ui/colors": "^3.0.0-rc.4", "@types/react": "^18.2.21", "@types/react-dom": "^18.2.7", "@typescript-eslint/eslint-plugin": "^6.7.0", @@ -58,7 +60,8 @@ "typescript-plugin-css-modules": "^5.0.1", "unocss": "^0.56.1", "unocss-preset-autoprefixer": "^0.0.6", - "vite": "^4.4.9" + "vite": "^4.4.9", + "windy-radix-palette": "^1.0.0-rc.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -1097,9 +1100,10 @@ "dev": true }, "node_modules/@radix-ui/colors": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/colors/-/colors-2.1.0.tgz", - "integrity": "sha512-gcBnxjS2u2c6thQz/9K1+Pt2ZYcm5WKU4SLi0emYkRmYbVUw+37rlc5wgLtYOsSsRP9nxVtbJJYj6WVO7UUmZg==" + "version": "3.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@radix-ui/colors/-/colors-3.0.0-rc.4.tgz", + "integrity": "sha512-dUG9WQCdjKPiiqbQsahUGmOuC+9kCltckQtej7hkVIQp56xirLaMsNrOs9xMYXnIbNqK/vZCmoEk+q1Nda+2AA==", + "dev": true }, "node_modules/@radix-ui/number": { "version": "1.0.1", @@ -1568,6 +1572,14 @@ } } }, + "node_modules/@radix-ui/react-icons": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.0.tgz", + "integrity": "sha512-jQxj/0LKgp+j9BiTXz3O3sgs26RNet2iLWmsPyRz2SIcR4q/4SbazXfnYwbAr+vLYKSfc7qxzyGQA1HLlYiuNw==", + "peerDependencies": { + "react": "^16.x || ^17.x || ^18.x" + } + }, "node_modules/@radix-ui/react-id": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.1.tgz", @@ -2293,6 +2305,11 @@ } } }, + "node_modules/@radix-ui/themes/node_modules/@radix-ui/colors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/colors/-/colors-2.1.0.tgz", + "integrity": "sha512-gcBnxjS2u2c6thQz/9K1+Pt2ZYcm5WKU4SLi0emYkRmYbVUw+37rlc5wgLtYOsSsRP9nxVtbJJYj6WVO7UUmZg==" + }, "node_modules/@remix-run/router": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.8.0.tgz", @@ -7852,6 +7869,16 @@ "node": ">= 8" } }, + "node_modules/windy-radix-palette": { + "version": "1.0.0-rc.0", + "resolved": "https://registry.npmjs.org/windy-radix-palette/-/windy-radix-palette-1.0.0-rc.0.tgz", + "integrity": "sha512-KW90etBbOr8EwV7z5PS7optM7n31HqVMUe1kWoLFZqDcpXtLyeYwxrIPv0yUevNaIWUXxFIPzdNzTWAvVON3UA==", + "dev": true, + "peerDependencies": { + "@radix-ui/colors": ">=3.0.0-rc.4", + "tailwindcss": ">=3.0.0" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -8588,9 +8615,10 @@ "dev": true }, "@radix-ui/colors": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/colors/-/colors-2.1.0.tgz", - "integrity": "sha512-gcBnxjS2u2c6thQz/9K1+Pt2ZYcm5WKU4SLi0emYkRmYbVUw+37rlc5wgLtYOsSsRP9nxVtbJJYj6WVO7UUmZg==" + "version": "3.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@radix-ui/colors/-/colors-3.0.0-rc.4.tgz", + "integrity": "sha512-dUG9WQCdjKPiiqbQsahUGmOuC+9kCltckQtej7hkVIQp56xirLaMsNrOs9xMYXnIbNqK/vZCmoEk+q1Nda+2AA==", + "dev": true }, "@radix-ui/number": { "version": "1.0.1", @@ -8827,6 +8855,12 @@ "@radix-ui/react-use-controllable-state": "1.0.1" } }, + "@radix-ui/react-icons": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.0.tgz", + "integrity": "sha512-jQxj/0LKgp+j9BiTXz3O3sgs26RNet2iLWmsPyRz2SIcR4q/4SbazXfnYwbAr+vLYKSfc7qxzyGQA1HLlYiuNw==", + "requires": {} + }, "@radix-ui/react-id": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.1.tgz", @@ -9217,6 +9251,13 @@ "@radix-ui/react-tooltip": "^1.0.6", "@radix-ui/react-visually-hidden": "^1.0.3", "classnames": "^2.3.2" + }, + "dependencies": { + "@radix-ui/colors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/colors/-/colors-2.1.0.tgz", + "integrity": "sha512-gcBnxjS2u2c6thQz/9K1+Pt2ZYcm5WKU4SLi0emYkRmYbVUw+37rlc5wgLtYOsSsRP9nxVtbJJYj6WVO7UUmZg==" + } } }, "@remix-run/router": { @@ -12954,6 +12995,13 @@ "isexe": "^2.0.0" } }, + "windy-radix-palette": { + "version": "1.0.0-rc.0", + "resolved": "https://registry.npmjs.org/windy-radix-palette/-/windy-radix-palette-1.0.0-rc.0.tgz", + "integrity": "sha512-KW90etBbOr8EwV7z5PS7optM7n31HqVMUe1kWoLFZqDcpXtLyeYwxrIPv0yUevNaIWUXxFIPzdNzTWAvVON3UA==", + "dev": true, + "requires": {} + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/packages/react/package.json b/packages/react/package.json index d853ebb13..77ee39a74 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -10,6 +10,7 @@ "preview": "vite preview" }, "dependencies": { + "@radix-ui/react-icons": "^1.3.0", "@radix-ui/themes": "^1.1.2", "@tanstack/react-query": "^4.35.0", "class-variance-authority": "^0.7.0", @@ -37,6 +38,7 @@ "zustand": "^4.4.1" }, "devDependencies": { + "@radix-ui/colors": "^3.0.0-rc.4", "@types/react": "^18.2.21", "@types/react-dom": "^18.2.7", "@typescript-eslint/eslint-plugin": "^6.7.0", @@ -60,6 +62,7 @@ "typescript-plugin-css-modules": "^5.0.1", "unocss": "^0.56.1", "unocss-preset-autoprefixer": "^0.0.6", - "vite": "^4.4.9" + "vite": "^4.4.9", + "windy-radix-palette": "^1.0.0-rc.0" } -} +} \ No newline at end of file diff --git a/packages/react/src/components/layout/useFrame.ts b/packages/react/src/components/layout/useFrame.ts index 402ad2378..7383ddbc3 100644 --- a/packages/react/src/components/layout/useFrame.ts +++ b/packages/react/src/components/layout/useFrame.ts @@ -1,10 +1,9 @@ -import { proxy } from 'valtio'; -import { useSnapshot } from 'valtio'; +import { proxyWithPersist } from '@/valtio-persist'; const MobileSizeBreak = 768; const FooterSizeBreak = 500; -export const frameContext = proxy({ +export const frameContext = proxyWithPersist('page_pref', { pageIsFullscreen: false, siteIsSmall: window.innerWidth < MobileSizeBreak, sidebarShouldBeFullscreen: window.innerWidth < FooterSizeBreak, @@ -18,7 +17,7 @@ export const frameContext = proxy({ }, // it's always open at init unless it's small. - sidebarOpen: window.innerWidth < MobileSizeBreak, + sidebarOpen: window.innerWidth > MobileSizeBreak, // sidebar would stay open if it could. sidebarPrefOpen: true, @@ -58,5 +57,5 @@ export const frameContext = proxy({ frameContext.sidebarOpen = true; frameContext.sidebarPrefOpen = frameContext.sidebarOpen; } -}) +}, ['sidebarPrefOpen']) diff --git a/packages/react/src/hooks/useTheme.ts b/packages/react/src/hooks/useTheme.ts new file mode 100644 index 000000000..baefc522f --- /dev/null +++ b/packages/react/src/hooks/useTheme.ts @@ -0,0 +1,52 @@ +import { proxyWithPersist } from "@/valtio-persist/index"; +import { useEffect } from "react"; +import { useSnapshot } from "valtio/react"; + +export const cssVariablesStore = proxyWithPersist('page-theme', { + + '--background': '0 0% 100%', + '--foreground': '222.2 84% 4.9%', + '--primary': '222.2 47.4% 11.2%', + '--primary-foreground': '210 40% 98%', + '--secondary': '210 40% 96.1%', + '--secondary-foreground': '222.2 47.4% 11.2%', + '--muted': '210 40% 96.1%', + '--muted-foreground': '215.4 16.3% 46.9%', + '--accent': '210 40% 96.1%', + '--accent-foreground': '222.2 47.4% 11.2%', + '--destructive': '0 84.2% 60.2%', + '--destructive-foreground': '210 40% 98%', + '--border': '214.3 31.8% 91.4%', + '--input': '214.3 31.8% 91.4%', + '--ring': '222.2 84% 4.9%', + +}, ['--background', '--foreground', '--primary', '--primary-foreground', '--secondary', '--muted', '--accent', '--destructive', '--border', '--input', '--ring']); + + +export function useThemeInit() { + const snap = useSnapshot(cssVariablesStore); + + useEffect(() => { + const setCssVariable = (property: string, value: string) => { + document.documentElement.style.setProperty(property, value); + }; + + setCssVariable('--background', snap['--background']); + setCssVariable('--foreground', snap['--foreground']); + setCssVariable('--primary', snap['--primary']); + setCssVariable('--primary-foreground', snap['--primary-foreground']); + setCssVariable('--secondary', snap['--secondary']); + setCssVariable('--secondary-foreground', snap['--secondary-foreground']); + setCssVariable('--muted', snap['--muted']); + setCssVariable('--muted-foreground', snap['--muted-foreground']); + setCssVariable('--accent', snap['--accent']); + setCssVariable('--accent-foreground', snap['--accent-foreground']); + setCssVariable('--destructive', snap['--destructive']); + setCssVariable('--destructive-foreground', snap['--destructive-foreground']); + setCssVariable('--border', snap['--border']); + setCssVariable('--input', snap['--input']); + setCssVariable('--ring', snap['--ring']); + }, [snap]); // This effect runs whenever the snapshot (and thus the state) changes + + return null; // This component doesn't need to render anything visible +}; \ No newline at end of file diff --git a/packages/react/src/index.css b/packages/react/src/index.css index 6a7572500..c27f1521b 100644 --- a/packages/react/src/index.css +++ b/packages/react/src/index.css @@ -1,75 +1,21 @@ @tailwind base; @tailwind components; @tailwind utilities; - + @layer base { :root { - --background: 0 0% 100%; - --foreground: 222.2 84% 4.9%; - - --card: 0 0% 100%; - --card-foreground: 222.2 84% 4.9%; - - --popover: 0 0% 100%; - --popover-foreground: 222.2 84% 4.9%; - - --primary: 222.2 47.4% 11.2%; - --primary-foreground: 210 40% 98%; - - --secondary: 210 40% 96.1%; - --secondary-foreground: 222.2 47.4% 11.2%; - - --muted: 210 40% 96.1%; - --muted-foreground: 215.4 16.3% 46.9%; - - --accent: 210 40% 96.1%; - --accent-foreground: 222.2 47.4% 11.2%; - - --destructive: 0 84.2% 60.2%; - --destructive-foreground: 210 40% 98%; - - --border: 214.3 31.8% 91.4%; - --input: 214.3 31.8% 91.4%; - --ring: 222.2 84% 4.9%; - --radius: 0.5rem; - } - - .dark { - --background: 222.2 84% 4.9%; - --foreground: 210 40% 98%; - - --card: 222.2 84% 4.9%; - --card-foreground: 210 40% 98%; - - --popover: 222.2 84% 4.9%; - --popover-foreground: 210 40% 98%; - - --primary: 210 40% 98%; - --primary-foreground: 222.2 47.4% 11.2%; - - --secondary: 217.2 32.6% 17.5%; - --secondary-foreground: 210 40% 98%; - - --muted: 217.2 32.6% 17.5%; - --muted-foreground: 215 20.2% 65.1%; - - --accent: 217.2 32.6% 17.5%; - --accent-foreground: 210 40% 98%; - - --destructive: 0 62.8% 30.6%; - --destructive-foreground: 210 40% 98%; - - --border: 217.2 32.6% 17.5%; - --input: 217.2 32.6% 17.5%; - --ring: 212.7 26.8% 83.9%; + /* other radix / shadcn variables are stored and configured by + @link{./hooks/useTheme.ts} + */ } } - + @layer base { * { @apply border-border; } + body { @apply bg-background text-foreground; } diff --git a/packages/react/src/main.tsx b/packages/react/src/main.tsx index 2688fa7f3..0f0a7826b 100644 --- a/packages/react/src/main.tsx +++ b/packages/react/src/main.tsx @@ -3,12 +3,16 @@ import ReactDOM from "react-dom/client"; import "./index.css"; import "uno.css"; import { Frame } from "./components/layout/Frame.tsx"; +import { useThemeInit } from "./hooks/useTheme.ts"; +function App() { + useThemeInit(); + + return ; +} ReactDOM.createRoot(document.getElementById("root")!).render( - {/* */} - - {/* */} + , ); diff --git a/packages/react/src/valtio-persist/index.ts b/packages/react/src/valtio-persist/index.ts index 660a49443..55eb68bd5 100644 --- a/packages/react/src/valtio-persist/index.ts +++ b/packages/react/src/valtio-persist/index.ts @@ -11,14 +11,14 @@ const pick = (obj: T, ...keys: K[]) => ( /** * Creates a proxy object with persistence, allowing you to store and retrieve data from local storage. */ -function proxyWithPersist(key: string, initialObject: T, persistFields: (keyof T)[]) { +export function proxyWithPersist(key: string, initialObject: T, persistFields: (keyof T)[]): T { if (typeof window === "undefined") return proxy(initialObject); const storageItem = localStorage.getItem(key); - const state = proxy({ + const state = proxy({ ...initialObject, ...(storageItem !== null ? JSON.parse(storageItem) : {}) - }); + } as T); subscribe(state, () => { const subobject = pick(initialObject, ...persistFields) diff --git a/packages/react/tailwind.config.js b/packages/react/tailwind.config.js index 0377ea1de..bae54a4c0 100644 --- a/packages/react/tailwind.config.js +++ b/packages/react/tailwind.config.js @@ -72,5 +72,5 @@ module.exports = { }, }, }, - plugins: [require("tailwindcss-animate")], + plugins: [require("tailwindcss-animate"), require("windy-radix-palette")], } \ No newline at end of file diff --git a/packages/react/vite.config.ts b/packages/react/vite.config.ts index 6019827f1..311295e40 100644 --- a/packages/react/vite.config.ts +++ b/packages/react/vite.config.ts @@ -2,11 +2,17 @@ import { defineConfig } from "vite"; // Faster React using swc apparently import react from "@vitejs/plugin-react-swc"; import UnoCSS from 'unocss/vite' +import { fileURLToPath, URL } from "url"; // import react from '@vitejs/plugin-react' // https://vitejs.dev/config/ export default defineConfig({ plugins: [react(), UnoCSS()], + resolve: { + alias: { + "@": fileURLToPath(new URL("./src", import.meta.url)), + }, + }, css: { modules: { localsConvention: 'camelCaseOnly'