Skip to content

Commit e9b1ab4

Browse files
committed
adds docs for theme provider
1 parent 76e03e6 commit e9b1ab4

File tree

4 files changed

+193
-10
lines changed

4 files changed

+193
-10
lines changed

app/components/layout.tsx

+5
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,11 @@ function Navigation({ className, style }: WithStyleProps) {
183183
Table
184184
</NavLink>
185185
</li>
186+
<li>
187+
<NavLink to="/components/theme-provider" prefetch="intent">
188+
Theme Provider
189+
</NavLink>
190+
</li>
186191
<li>
187192
<NavLink to="/components/tooltip" prefetch="intent">
188193
Tooltip
+166
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
import {
2+
CodeBlock,
3+
CodeBlockBody,
4+
CodeBlockCode,
5+
CodeBlockCopyButton,
6+
CodeBlockExpanderButton,
7+
CodeBlockHeader,
8+
CodeBlockTitle,
9+
} from "@/code-block";
10+
import { code } from "@/code-block/code";
11+
import { InlineCode } from "@/inline-code";
12+
import { preventWrongThemeFlashScriptContent } from "@/theme-provider";
13+
import { FileText } from "@phosphor-icons/react/FileText";
14+
import type { HeadersFunction, MetaFunction } from "@remix-run/node";
15+
16+
export const meta: MetaFunction = () => {
17+
return [
18+
{ title: "@ngrok/mantle — Theme Provider" },
19+
{ name: "description", content: "mantle is ngrok's UI library and design system" },
20+
];
21+
};
22+
23+
export const headers: HeadersFunction = () => {
24+
return {
25+
"Cache-Control": "max-age=300, stale-while-revalidate=604800",
26+
};
27+
};
28+
29+
export default function Page() {
30+
return (
31+
<div>
32+
<h1 className="text-5xl font-medium">Theme Provider</h1>
33+
<p className="mb-4 mt-4 text-xl text-gray-600">
34+
ThemeProvider is a React Context Provider that provides the current theme to the application and a function to
35+
change it.
36+
</p>
37+
<div className="space-y-4">
38+
<p>
39+
To use the <InlineCode>ThemeProvider</InlineCode>, wrap your application&apos;s entry point. This should be
40+
done as high in the component tree as possible.
41+
</p>
42+
<p>
43+
You should also add the <InlineCode>PreventWrongThemeFlash</InlineCode> component to the head of your
44+
application to prevent a Flash of Unstyled Content (FOUC) when the app first loads.
45+
</p>
46+
<CodeBlock className="rounded-b-lg rounded-t-none">
47+
<CodeBlockHeader>
48+
<FileText className="h-5 w-5" weight="fill" />
49+
<CodeBlockTitle>root.tsx</CodeBlockTitle>
50+
</CodeBlockHeader>
51+
<CodeBlockBody>
52+
<CodeBlockCopyButton />
53+
<CodeBlockCode language="tsx">{code`
54+
import { PreventWrongThemeFlash, ThemeProvider } from "@ngrok/mantle";
55+
56+
export default function App() {
57+
return (
58+
<html className="h-full" lang="en-US" dir="ltr">
59+
<head>
60+
// 👇 add this as high in the <head> as possible!
61+
<PreventWrongThemeFlash />
62+
<meta charSet="utf-8" />
63+
<meta name="author" content="ngrok" />
64+
<meta name="viewport" content="width=device-width, initial-scale=1" />
65+
<Meta />
66+
<Links />
67+
</head>
68+
<body className="h-full min-h-full overflow-y-scroll bg-background">
69+
// 👇 wrap your app entry in the ThemeProvider
70+
<ThemeProvider>
71+
<Outlet />
72+
</ThemeProvider>
73+
</body>
74+
</html>
75+
);
76+
}
77+
`}</CodeBlockCode>
78+
<CodeBlockExpanderButton />
79+
</CodeBlockBody>
80+
</CodeBlock>
81+
<p>
82+
Sometimes you cannot use the <InlineCode>PreventWrongThemeFlash</InlineCode> component because your webserver
83+
is not able to render React components. In this case, you can use the copy the following script and add it to
84+
your application&apos;s <InlineCode>&lt;head&gt;</InlineCode>:
85+
</p>
86+
<CodeBlock className="rounded-b-lg rounded-t-none">
87+
<CodeBlockHeader>
88+
<FileText className="h-5 w-5" weight="fill" />
89+
<CodeBlockTitle>index.html</CodeBlockTitle>
90+
</CodeBlockHeader>
91+
<CodeBlockBody>
92+
<CodeBlockCopyButton />
93+
<CodeBlockCode language="html">{code`<script>
94+
${preventWrongThemeFlashScriptContent({ defaultTheme: "system" })}
95+
</script>
96+
`}</CodeBlockCode>
97+
<CodeBlockExpanderButton />
98+
</CodeBlockBody>
99+
</CodeBlock>
100+
<p>
101+
Then, in your application, you can use the <InlineCode>useTheme</InlineCode> hook to get and change the
102+
current theme:
103+
</p>
104+
<CodeBlock className="rounded-b-lg rounded-t-none">
105+
<CodeBlockHeader>
106+
<FileText className="h-5 w-5" weight="fill" />
107+
<CodeBlockTitle>app.tsx</CodeBlockTitle>
108+
</CodeBlockHeader>
109+
<CodeBlockBody>
110+
<CodeBlockCopyButton />
111+
<CodeBlockCode language="tsx">{code`
112+
import {
113+
isTheme,
114+
Select,
115+
SelectContent,
116+
SelectGroup,
117+
SelectItem,
118+
SelectLabel,
119+
SelectTrigger,
120+
theme,
121+
useTheme,
122+
} from "@ngrok/mantle";
123+
124+
function App() {
125+
const [currentTheme, setTheme] = useTheme();
126+
127+
return (
128+
<>
129+
<Select
130+
value={currentTheme}
131+
onValueChange={(value) => {
132+
const maybeNewTheme = isTheme(value) ? value : undefined;
133+
if (maybeNewTheme) {
134+
setTheme(maybeNewTheme);
135+
}
136+
}}
137+
>
138+
<div className="ml-auto">
139+
<span className="sr-only">Theme Switcher</span>
140+
<SelectTrigger className="w-min">
141+
<Sun className="mr-1 h-6 w-6" />
142+
</SelectTrigger>
143+
</div>
144+
<SelectContent>
145+
<SelectGroup>
146+
<SelectLabel>Choose a theme</SelectLabel>
147+
<SelectItem value={theme("system")}>System</SelectItem>
148+
<SelectItem value={theme("light")}>Light</SelectItem>
149+
<SelectItem value={theme("dark")}>Dark</SelectItem>
150+
<SelectItem value={theme("light-high-contrast")}>Light High Contrast</SelectItem>
151+
<SelectItem value={theme("dark-high-contrast")}>Dark High Contrast</SelectItem>
152+
</SelectGroup>
153+
</SelectContent>
154+
</Select>
155+
{/* The rest of your app... */}
156+
</>
157+
);
158+
}
159+
`}</CodeBlockCode>
160+
</CodeBlockBody>
161+
<CodeBlockExpanderButton />
162+
</CodeBlock>
163+
</div>
164+
</div>
165+
);
166+
}

app/types/routes.ts

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export const routePatterns = [
1616
"/components/sheet",
1717
"/components/skeleton",
1818
"/components/table",
19+
"/components/theme-provider",
1920
"/components/tooltip",
2021
] as const;
2122

@@ -42,6 +43,7 @@ export const routes = [
4243
"/components/sheet",
4344
"/components/skeleton",
4445
"/components/table",
46+
"/components/theme-provider",
4547
"/components/tooltip",
4648
] as const;
4749

components/theme-provider/index.tsx

+20-10
Original file line numberDiff line numberDiff line change
@@ -185,20 +185,14 @@ export function determineThemeFromMediaQuery({
185185
return prefersDarkMode ? "dark" : "light";
186186
}
187187

188-
/**
189-
* PreventWrongThemeFlash is a React component that prevents the wrong theme from flashing on initial page load.
190-
* Render as high as possible in the DOM, preferably in the <head> element.
191-
*/
192-
const PreventWrongThemeFlash = ({
188+
export function preventWrongThemeFlashScriptContent({
193189
defaultTheme = "system",
194190
storageKey = DEFAULT_STORAGE_KEY,
195191
}: {
196192
defaultTheme?: Theme;
197193
storageKey?: string;
198-
}) => (
199-
<script
200-
dangerouslySetInnerHTML={{
201-
__html: `
194+
}) {
195+
return `
202196
(function() {
203197
const themes = ${JSON.stringify(themes)};
204198
const isTheme = (value) => typeof value === "string" && themes.includes(value);
@@ -225,7 +219,23 @@ const PreventWrongThemeFlash = ({
225219
htmlElement.dataset.appliedTheme = initialTheme;
226220
htmlElement.dataset.theme = themePreference;
227221
})();
228-
`.trim(),
222+
`.trim();
223+
}
224+
225+
/**
226+
* PreventWrongThemeFlash is a React component that prevents the wrong theme from flashing on initial page load.
227+
* Render as high as possible in the DOM, preferably in the <head> element.
228+
*/
229+
const PreventWrongThemeFlash = ({
230+
defaultTheme = "system",
231+
storageKey = DEFAULT_STORAGE_KEY,
232+
}: {
233+
defaultTheme?: Theme;
234+
storageKey?: string;
235+
}) => (
236+
<script
237+
dangerouslySetInnerHTML={{
238+
__html: preventWrongThemeFlashScriptContent({ defaultTheme, storageKey }),
229239
}}
230240
/>
231241
);

0 commit comments

Comments
 (0)