From da7a3d896d3bb487554a7655121ef8602ecd1759 Mon Sep 17 00:00:00 2001 From: Sahaj Jain Date: Wed, 9 Apr 2025 23:16:43 +0530 Subject: [PATCH] feat: Add nuqs to apply theme from query param initially --- package.json | 1 + pnpm-lock.yaml | 33 ++++++++++++++ src/app.tsx | 45 ++++++++++--------- src/components/editor/theme-preview-panel.tsx | 1 - src/components/theme-provider.tsx | 4 ++ src/hooks/use-theme-preset-from-url.ts | 16 +++++++ 6 files changed, 78 insertions(+), 22 deletions(-) create mode 100644 src/hooks/use-theme-preset-from-url.ts diff --git a/package.json b/package.json index 51a6e0a3..e0b0745e 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "lucide-react": "^0.483.0", "motion": "^12.5.0", "next-themes": "^0.3.0", + "nuqs": "^2.4.1", "posthog-js": "^1.232.4", "react": "^18.3.1", "react-day-picker": "^8.10.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 413f93e2..4c9d121d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -149,6 +149,9 @@ importers: next-themes: specifier: ^0.3.0 version: 0.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + nuqs: + specifier: ^2.4.1 + version: 2.4.1(react-router@7.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) posthog-js: specifier: ^1.232.4 version: 1.234.9 @@ -2731,6 +2734,9 @@ packages: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} + mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + motion-dom@12.6.3: resolution: {integrity: sha512-gRY08RjcnzgFYLemUZ1lo/e9RkBxR+6d4BRvoeZDSeArG4XQXERSPapKl3LNQRu22Sndjf1h+iavgY0O4NrYqA==} @@ -2801,6 +2807,24 @@ packages: resolution: {integrity: sha512-1dKY+86/AIiq1tkKVD3l0WI+Gd3vkknVGAggsFeBkTvbhMQ1OND/LKkYv4JtXPKUJ8bOTCyLiqEg2P6QNdK+Gg==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + nuqs@2.4.1: + resolution: {integrity: sha512-u6sngTspqDe3jWHtcmqHQg3dl35niizCZAsm5gy7PBlgG2rwl71Dp2QUv5hwBaWKI9qz0wqILZY86TsRxq66SQ==} + peerDependencies: + '@remix-run/react': '>=2' + next: '>=14.2.0' + react: '>=18.2.0 || ^19.0.0-0' + react-router: ^6 || ^7 + react-router-dom: ^6 || ^7 + peerDependenciesMeta: + '@remix-run/react': + optional: true + next: + optional: true + react-router: + optional: true + react-router-dom: + optional: true + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -5840,6 +5864,8 @@ snapshots: minipass@7.1.2: {} + mitt@3.0.1: {} + motion-dom@12.6.3: dependencies: motion-utils: 12.6.3 @@ -5907,6 +5933,13 @@ snapshots: npm-package-arg: 10.1.0 semver: 7.7.1 + nuqs@2.4.1(react-router@7.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1): + dependencies: + mitt: 3.0.1 + react: 18.3.1 + optionalDependencies: + react-router: 7.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + object-assign@4.1.1: {} object-hash@3.0.0: {} diff --git a/src/app.tsx b/src/app.tsx index 49297e06..1850f2ed 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -9,6 +9,7 @@ import Home from "./pages/home"; import { lazy, Suspense } from "react"; import { Loading } from "./components/loading"; import { HelmetProvider } from "react-helmet-async"; +import { NuqsAdapter } from "nuqs/adapters/react-router/v7"; const Index = lazy(() => import("@/pages/index")); @@ -18,27 +19,29 @@ const options = { }; const App = () => ( - - - - - - - - }> - - } /> - } /> - - - - - - - + + + + + + + + + }> + + } /> + } /> + + + + + + + + ); export default App; diff --git a/src/components/editor/theme-preview-panel.tsx b/src/components/editor/theme-preview-panel.tsx index 4329e49d..401884a1 100644 --- a/src/components/editor/theme-preview-panel.tsx +++ b/src/components/editor/theme-preview-panel.tsx @@ -2,7 +2,6 @@ import { ThemeEditorPreviewProps } from "@/types/theme"; import { Tabs, TabsContent, TabsList } from "@/components/ui/tabs"; import { ScrollArea, ScrollBar } from "../ui/scroll-area"; import ColorPreview from "./theme-preview/color-preview"; -import ComponentsShowcase from "./theme-preview/components-showcase"; import TabsTriggerPill from "./theme-preview/tabs-trigger-pill"; import ExamplesPreviewContainer from "./theme-preview/examples-preview-container"; import { lazy } from "react"; diff --git a/src/components/theme-provider.tsx b/src/components/theme-provider.tsx index e3a8c7d5..18dca20b 100644 --- a/src/components/theme-provider.tsx +++ b/src/components/theme-provider.tsx @@ -4,6 +4,7 @@ import { colorFormatter } from "../utils/color-converter"; import { setShadowVariables } from "@/utils/shadows"; import { applyStyleToElement } from "@/utils/apply-style-to-element"; import { ThemeStyleProps, ThemeStyles } from "@/types/theme"; +import { useThemePresetFromUrl } from "@/hooks/use-theme-preset-from-url"; type Theme = "dark" | "light"; @@ -80,6 +81,9 @@ const updateThemeClass = (root: HTMLElement, mode: Theme) => { export function ThemeProvider({ children, ...props }: ThemeProviderProps) { const { themeState, setThemeState } = useEditorStore(); + // Handle theme preset from URL + useThemePresetFromUrl(); + useLayoutEffect(() => { const root = window.document.documentElement; const { currentMode: mode, styles: themeStyles } = themeState; diff --git a/src/hooks/use-theme-preset-from-url.ts b/src/hooks/use-theme-preset-from-url.ts new file mode 100644 index 00000000..20e20d85 --- /dev/null +++ b/src/hooks/use-theme-preset-from-url.ts @@ -0,0 +1,16 @@ +import { useQueryState } from "nuqs"; +import React from "react"; +import { useEditorStore } from "@/store/editor-store"; + +export const useThemePresetFromUrl = () => { + const [preset, setPreset] = useQueryState("theme"); + const applyThemePreset = useEditorStore((state) => state.applyThemePreset); + + // Apply theme preset if it exists in URL and remove it + React.useEffect(() => { + if (preset) { + applyThemePreset(preset); + setPreset(null); // Remove the preset from URL + } + }, [preset, setPreset, applyThemePreset]); +};