Skip to content

Commit

Permalink
feat: add theme and disable theme toggle option (#151)
Browse files Browse the repository at this point in the history
* feat: add theme and disable theme toggle option

* feat(embed): override theme variables (#152)

---------

Co-authored-by: Georges KABBOUCHI <[email protected]>
  • Loading branch information
invisal and KABBOUCHI authored Aug 22, 2024
1 parent 13738b1 commit b52e505
Show file tree
Hide file tree
Showing 12 changed files with 152 additions and 87 deletions.
4 changes: 2 additions & 2 deletions src/app/(theme)/client/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Fragment } from "react";
import ThemeLayout from "../theme_layout";

export default async function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return <Fragment>{children}</Fragment>;
return <ThemeLayout>{children}</ThemeLayout>;
}
7 changes: 6 additions & 1 deletion src/app/(theme)/connect/page.tsx
Original file line number Diff line number Diff line change
@@ -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",
Expand All @@ -10,5 +11,9 @@ export const metadata: Metadata = {
export default async function Home() {
const { user } = await getSessionFromCookie();

return <ConnectBody user={user} />;
return (
<ThemeLayout>
<ConnectBody user={user} />
</ThemeLayout>
);
}
22 changes: 22 additions & 0 deletions src/app/(theme)/embed/sqlite/page-client.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<Studio
driver={driver}
name={searchParams.get("name") || "Unnamed Connection"}
color={searchParams.get("color") || "gray"}
/>
);
}
46 changes: 30 additions & 16 deletions src/app/(theme)/embed/sqlite/page.tsx
Original file line number Diff line number Diff line change
@@ -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<string, string> = {};

for (const key in props.searchParams) {
if (!key.startsWith("themeVariables[")) {
continue;
}

overrideThemeVariables[key.slice(15, -1)] = props.searchParams[key];
}

return (
<MyStudio
driver={driver}
color={searchParams.get("color") || "gray"}
name={searchParams.get("name") || "Unnamed Connection"}
/>
<ThemeLayout
overrideTheme={overrideTheme}
disableToggle={disableToggle}
overrideThemeVariables={overrideThemeVariables}
>
<EmbedPageClient />
</ThemeLayout>
);
}
30 changes: 0 additions & 30 deletions src/app/(theme)/layout.tsx

This file was deleted.

7 changes: 6 additions & 1 deletion src/app/(theme)/playground/client/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -55,5 +56,9 @@ export default async function PlaygroundEditor({
templateFile = searchParams.url;
}

return <PlaygroundEditorBody preloadDatabase={templateFile} />;
return (
<ThemeLayout>
<PlaygroundEditorBody preloadDatabase={templateFile} />
</ThemeLayout>
);
}
42 changes: 42 additions & 0 deletions src/app/(theme)/theme_layout.tsx
Original file line number Diff line number Diff line change
@@ -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<string, string>;
}>) {
const cookieStore = cookies();
const theme =
overrideTheme ??
(cookieStore.get("theme")?.value === "dark" ? "dark" : "light");
const style = overrideThemeVariables ?? {};

return (
<body
className={cn(inter.className, theme)}
style={style}
suppressHydrationWarning
>
<ThemeProvider defaultTheme={theme} disableToggle={disableToggle}>
<Fragment>{children}</Fragment>
<Toaster />
</ThemeProvider>
<Analytics />
<Script async defer src="https://buttons.github.io/buttons.js" />
</body>
);
}
4 changes: 1 addition & 3 deletions src/components/gui/connection-dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@ export default function ConnectingDialog({
<div className="text-2xl font-semibold">
We have problem connecting to database
</div>
<p className="mt-4">
<pre>{message}</pre>
</p>
<pre className="mt-4">{message}</pre>
<div className="mt-4 flex gap-4">
<Button onClick={onRetry}>Retry</Button>
<Button variant={"secondary"} onClick={onBack}>
Expand Down
40 changes: 21 additions & 19 deletions src/components/gui/sidebar-tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ interface SidebarTabProps {

export default function SidebarTab({ tabs }: Readonly<SidebarTabProps>) {
const [selectedIndex, setSelectedIndex] = useState(0);
const { theme, toggleTheme } = useTheme();
const { theme, toggleTheme, disableToggle } = useTheme();
const [loadedIndex, setLoadedIndex] = useState(() => {
const a: boolean[] = new Array(tabs.length).fill(false);
a[0] = true;
Expand Down Expand Up @@ -61,24 +61,26 @@ export default function SidebarTab({ tabs }: Readonly<SidebarTabProps>) {
<div className="line-clamp-1 text-ellipsis">{config.name}</div>
</div>

<div className="flex justify-center items-center">
<button
onClick={() => toggleTheme()}
className="text-xs font-normal flex gap-0.5 border rounded px-2 py-1 bg-background"
>
{theme === "dark" ? (
<>
<LucideMoon className={cn("w-4 h-4")} />
Dark
</>
) : (
<>
<LucideSun className={cn("w-4 h-4")} />
Light
</>
)}
</button>
</div>
{!disableToggle && (
<div className="flex justify-center items-center">
<button
onClick={() => toggleTheme()}
className="text-xs font-normal flex gap-0.5 border rounded px-2 py-1 bg-background"
>
{theme === "dark" ? (
<>
<LucideMoon className={cn("w-4 h-4")} />
Dark
</>
) : (
<>
<LucideSun className={cn("w-4 h-4")} />
Light
</>
)}
</button>
</div>
)}
</div>

{config.sideBarFooterComponent && (
Expand Down
4 changes: 0 additions & 4 deletions src/components/gui/studio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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[];
}

Expand Down
4 changes: 0 additions & 4 deletions src/components/my-studio.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -32,7 +31,6 @@ function MyStudioInternal({
}: MyStudioProps) {
const router = useRouter();
const { openBlockEditor } = useBlockEditor();
const { theme, toggleTheme } = useTheme();

const goBack = useCallback(() => {
router.push("/connect");
Expand Down Expand Up @@ -91,8 +89,6 @@ function MyStudioInternal({
driver={driver}
name={name}
color={color ?? "blue"}
theme={theme}
onThemeChange={toggleTheme}
onBack={goBack}
collaboration={collabarator}
docDriver={docDriver}
Expand Down
29 changes: 22 additions & 7 deletions src/context/theme-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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");
},
Expand All @@ -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<ThemeType>(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") {
Expand All @@ -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 (
<ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>
Expand Down

0 comments on commit b52e505

Please sign in to comment.