From b52e505327228a96967e6b921984c5ee6c0cbbd2 Mon Sep 17 00:00:00 2001
From: "Visal .In"
Date: Thu, 22 Aug 2024 23:30:42 +0700
Subject: [PATCH] feat: add theme and disable theme toggle option (#151)
* feat: add theme and disable theme toggle option
* feat(embed): override theme variables (#152)
---------
Co-authored-by: Georges KABBOUCHI
---
src/app/(theme)/client/layout.tsx | 4 +-
src/app/(theme)/connect/page.tsx | 7 ++-
src/app/(theme)/embed/sqlite/page-client.tsx | 22 ++++++++++
src/app/(theme)/embed/sqlite/page.tsx | 46 +++++++++++++-------
src/app/(theme)/layout.tsx | 30 -------------
src/app/(theme)/playground/client/page.tsx | 7 ++-
src/app/(theme)/theme_layout.tsx | 42 ++++++++++++++++++
src/components/gui/connection-dialog.tsx | 4 +-
src/components/gui/sidebar-tab.tsx | 40 +++++++++--------
src/components/gui/studio.tsx | 4 --
src/components/my-studio.tsx | 4 --
src/context/theme-provider.tsx | 29 +++++++++---
12 files changed, 152 insertions(+), 87 deletions(-)
create mode 100644 src/app/(theme)/embed/sqlite/page-client.tsx
delete mode 100644 src/app/(theme)/layout.tsx
create mode 100644 src/app/(theme)/theme_layout.tsx
diff --git a/src/app/(theme)/client/layout.tsx b/src/app/(theme)/client/layout.tsx
index 63a1aac0..ca668d44 100644
--- a/src/app/(theme)/client/layout.tsx
+++ b/src/app/(theme)/client/layout.tsx
@@ -1,9 +1,9 @@
-import { Fragment } from "react";
+import ThemeLayout from "../theme_layout";
export default async function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
- return {children};
+ return {children};
}
diff --git a/src/app/(theme)/connect/page.tsx b/src/app/(theme)/connect/page.tsx
index ad89ef0f..c02987af 100644
--- a/src/app/(theme)/connect/page.tsx
+++ b/src/app/(theme)/connect/page.tsx
@@ -1,6 +1,7 @@
import { Metadata } from "next";
import { getSessionFromCookie } from "@/lib/auth";
import ConnectBody from "./page-client";
+import ThemeLayout from "../theme_layout";
export const metadata: Metadata = {
title: "LibSQL Studio",
@@ -10,5 +11,9 @@ export const metadata: Metadata = {
export default async function Home() {
const { user } = await getSessionFromCookie();
- return ;
+ return (
+
+
+
+ );
}
diff --git a/src/app/(theme)/embed/sqlite/page-client.tsx b/src/app/(theme)/embed/sqlite/page-client.tsx
new file mode 100644
index 00000000..db8cc506
--- /dev/null
+++ b/src/app/(theme)/embed/sqlite/page-client.tsx
@@ -0,0 +1,22 @@
+"use client";
+import { Studio } from "@/components/gui/studio";
+import IframeDriver from "@/drivers/iframe-driver";
+import { useSearchParams } from "next/navigation";
+import { useEffect, useMemo } from "react";
+
+export default function EmbedPageClient() {
+ const searchParams = useSearchParams();
+ const driver = useMemo(() => new IframeDriver(), []);
+
+ useEffect(() => {
+ return driver.listen();
+ }, [driver]);
+
+ return (
+
+ );
+}
diff --git a/src/app/(theme)/embed/sqlite/page.tsx b/src/app/(theme)/embed/sqlite/page.tsx
index 225e87a1..abe190a1 100644
--- a/src/app/(theme)/embed/sqlite/page.tsx
+++ b/src/app/(theme)/embed/sqlite/page.tsx
@@ -1,23 +1,37 @@
-"use client";
+import ThemeLayout from "../../theme_layout";
+import EmbedPageClient from "./page-client";
-import MyStudio from "@/components/my-studio";
-import IframeDriver from "@/drivers/iframe-driver";
-import { useSearchParams } from "next/navigation";
-import { useEffect, useMemo } from "react";
+export default async function EmbedPage(props: {
+ searchParams: {
+ theme?: string;
+ disableThemeToggle?: string;
+ [key: string]: any;
+ };
+}) {
+ let overrideTheme: "dark" | "light" | undefined = undefined;
+ const disableToggle = props.searchParams.disableThemeToggle === "1";
-export default function EmbedPageClient() {
- const searchParams = useSearchParams();
- const driver = useMemo(() => new IframeDriver(), []);
+ if (props.searchParams.theme) {
+ overrideTheme = props.searchParams.theme === "dark" ? "dark" : "light";
+ }
- useEffect(() => {
- return driver.listen();
- }, [driver]);
+ const overrideThemeVariables: Record = {};
+
+ for (const key in props.searchParams) {
+ if (!key.startsWith("themeVariables[")) {
+ continue;
+ }
+
+ overrideThemeVariables[key.slice(15, -1)] = props.searchParams[key];
+ }
return (
-
+
+
+
);
}
diff --git a/src/app/(theme)/layout.tsx b/src/app/(theme)/layout.tsx
deleted file mode 100644
index 33a13bb1..00000000
--- a/src/app/(theme)/layout.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import { Analytics } from "@vercel/analytics/react";
-import { Inter } from "next/font/google";
-import ThemeProvider from "@/context/theme-provider";
-import { cookies } from "next/headers";
-import { Toaster } from "@/components/ui/sonner";
-import { Fragment } from "react";
-import Script from "next/script";
-import { cn } from "@/lib/utils";
-
-const inter = Inter({ subsets: ["latin"] });
-
-export default async function RootLayout({
- children,
-}: {
- children: React.ReactNode;
-}) {
- const cookieStore = cookies();
- const theme = cookieStore.get("theme")?.value === "dark" ? "dark" : "light";
-
- return (
-
-
- {children}
-
-
-
-
-
- );
-}
diff --git a/src/app/(theme)/playground/client/page.tsx b/src/app/(theme)/playground/client/page.tsx
index d595fef0..bb5f0c5d 100644
--- a/src/app/(theme)/playground/client/page.tsx
+++ b/src/app/(theme)/playground/client/page.tsx
@@ -3,6 +3,7 @@ import PlaygroundEditorBody from "./page-client";
import { eq, sql } from "drizzle-orm";
import { dbDataset } from "@/db/schema-dataset";
import { Metadata } from "next";
+import ThemeLayout from "../../theme_layout";
export const metadata: Metadata = {
title:
@@ -55,5 +56,9 @@ export default async function PlaygroundEditor({
templateFile = searchParams.url;
}
- return ;
+ return (
+
+
+
+ );
}
diff --git a/src/app/(theme)/theme_layout.tsx b/src/app/(theme)/theme_layout.tsx
new file mode 100644
index 00000000..44fb8143
--- /dev/null
+++ b/src/app/(theme)/theme_layout.tsx
@@ -0,0 +1,42 @@
+import { Analytics } from "@vercel/analytics/react";
+import { Inter } from "next/font/google";
+import ThemeProvider from "@/context/theme-provider";
+import { cookies } from "next/headers";
+import { Toaster } from "@/components/ui/sonner";
+import { Fragment, PropsWithChildren } from "react";
+import Script from "next/script";
+import { cn } from "@/lib/utils";
+
+const inter = Inter({ subsets: ["latin"] });
+
+export default async function ThemeLayout({
+ children,
+ overrideTheme,
+ disableToggle,
+ overrideThemeVariables,
+}: PropsWithChildren<{
+ overrideTheme?: "dark" | "light";
+ disableToggle?: boolean;
+ overrideThemeVariables?: Record;
+}>) {
+ const cookieStore = cookies();
+ const theme =
+ overrideTheme ??
+ (cookieStore.get("theme")?.value === "dark" ? "dark" : "light");
+ const style = overrideThemeVariables ?? {};
+
+ return (
+
+
+ {children}
+
+
+
+
+
+ );
+}
diff --git a/src/components/gui/connection-dialog.tsx b/src/components/gui/connection-dialog.tsx
index b007c56e..8d6ee35a 100644
--- a/src/components/gui/connection-dialog.tsx
+++ b/src/components/gui/connection-dialog.tsx
@@ -25,9 +25,7 @@ export default function ConnectingDialog({
We have problem connecting to database
-
-
{message}
-
+ {message}
-
-
-
+ {!disableToggle && (
+
+
+
+ )}
{config.sideBarFooterComponent && (
diff --git a/src/components/gui/studio.tsx b/src/components/gui/studio.tsx
index 80fe1c26..800dd567 100644
--- a/src/components/gui/studio.tsx
+++ b/src/components/gui/studio.tsx
@@ -20,13 +20,9 @@ interface StudioProps {
docDriver?: SavedDocDriver;
name: string;
color: string;
-
onBack?: () => void;
sideBarFooterComponent?: ReactElement;
-
theme?: "dark" | "light";
- onThemeChange?: (theme: "dark" | "light") => void;
-
extensions?: StudioExtension[];
}
diff --git a/src/components/my-studio.tsx b/src/components/my-studio.tsx
index fb42664f..d3511348 100644
--- a/src/components/my-studio.tsx
+++ b/src/components/my-studio.tsx
@@ -1,4 +1,3 @@
-import { useTheme } from "@/context/theme-provider";
import { useRouter } from "next/navigation";
import { ReactElement, useCallback, useMemo } from "react";
import { toast } from "sonner";
@@ -32,7 +31,6 @@ function MyStudioInternal({
}: MyStudioProps) {
const router = useRouter();
const { openBlockEditor } = useBlockEditor();
- const { theme, toggleTheme } = useTheme();
const goBack = useCallback(() => {
router.push("/connect");
@@ -91,8 +89,6 @@ function MyStudioInternal({
driver={driver}
name={name}
color={color ?? "blue"}
- theme={theme}
- onThemeChange={toggleTheme}
onBack={goBack}
collaboration={collabarator}
docDriver={docDriver}
diff --git a/src/context/theme-provider.tsx b/src/context/theme-provider.tsx
index b64c0126..57e79a8b 100644
--- a/src/context/theme-provider.tsx
+++ b/src/context/theme-provider.tsx
@@ -14,9 +14,11 @@ type ThemeType = "dark" | "light";
const ThemeContext = createContext<{
theme: ThemeType;
+ disableToggle: boolean;
toggleTheme: (theme?: string) => void;
}>({
theme: "dark",
+ disableToggle: false,
toggleTheme: () => {
throw new Error("Not implemented");
},
@@ -29,14 +31,24 @@ export function useTheme() {
export default function ThemeProvider({
children,
defaultTheme,
-}: PropsWithChildren<{ defaultTheme: ThemeType }>) {
+ disableToggle,
+}: PropsWithChildren<{ defaultTheme: ThemeType; disableToggle?: boolean }>) {
const [theme, setTheme] = useState(defaultTheme);
- const toggleTheme = useCallback(() => {
- const newTheme = theme === "dark" ? "light" : "dark";
- setCookie("theme", newTheme);
- setTheme(newTheme);
- }, [setTheme, theme]);
+ const toggleTheme = useCallback(
+ (assignedTheme?: string) => {
+ setTheme((prevTheme) => {
+ if (assignedTheme) {
+ return assignedTheme === "dark" ? "dark" : "light";
+ }
+
+ const newTheme = prevTheme === "dark" ? "light" : "dark";
+ setCookie("theme", newTheme);
+ return newTheme;
+ });
+ },
+ [setTheme]
+ );
useEffect(() => {
if (theme === "light") {
@@ -46,7 +58,10 @@ export default function ThemeProvider({
}
}, [theme]);
- const value = useMemo(() => ({ toggleTheme, theme }), [toggleTheme, theme]);
+ const value = useMemo(
+ () => ({ toggleTheme, theme, disableToggle: disableToggle ?? false }),
+ [toggleTheme, theme, disableToggle]
+ );
return (
{children}