From 7a7ec1bb64ecf1df2b8783b41c1a15b4455f0861 Mon Sep 17 00:00:00 2001 From: Irvin Zhan <4621962+izhan@users.noreply.github.com> Date: Mon, 4 May 2026 23:44:06 -0700 Subject: [PATCH 1/2] [GTMBot] Restructure dark mode docs (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - New: learn/theme/dark-mode.mdx — tighter designer article matching responsive-design.mdx structure - Rewrite: guides/dark-mode.mdx — narrowed to toggle implementation only - Update: customizing-theme.mdx — one-sentence dark mode subsection under Colors - Update: exporting-theme.mdx — cross-link to Learn article - Update: docs.json — add dark-mode to Learn > Theme nav --- packages/docs/docs.json | 1 + packages/docs/guides/dark-mode.mdx | 174 +++++------------- .../docs/learn/theme/customizing-theme.mdx | 42 +++-- packages/docs/learn/theme/dark-mode.mdx | 34 ++++ packages/docs/learn/theme/exporting-theme.mdx | 10 +- 5 files changed, 104 insertions(+), 157 deletions(-) create mode 100644 packages/docs/learn/theme/dark-mode.mdx diff --git a/packages/docs/docs.json b/packages/docs/docs.json index 38e5d533..0617e11a 100644 --- a/packages/docs/docs.json +++ b/packages/docs/docs.json @@ -95,6 +95,7 @@ "group": "Theme", "pages": [ "learn/theme/customizing-theme", + "learn/theme/dark-mode", "learn/theme/importing-tokens", "learn/theme/exporting-theme", "learn/theme/adding-custom-fonts" diff --git a/packages/docs/guides/dark-mode.mdx b/packages/docs/guides/dark-mode.mdx index e2451184..9eb7129d 100644 --- a/packages/docs/guides/dark-mode.mdx +++ b/packages/docs/guides/dark-mode.mdx @@ -1,111 +1,29 @@ --- -title: Dark mode -description: Add dark mode to your project using Subframe's built-in theme support +title: Dark mode toggle +description: Add a dark mode toggle to your app using Subframe's generated theme. --- import CliSyncAllCommand from "/snippets/cli-sync-all-command.mdx" -Subframe has built-in dark mode support. Enable it in your theme to define light and dark values side by side, then sync to get a fully configured Tailwind setup. +When [dark mode](/learn/theme/dark-mode) is enabled in your theme, the CLI generates CSS variables that switch between light and dark values. Activate dark mode by adding the `dark` class to the `` element. -## Enable dark mode - -1. Open **Theme** in the top navigation -2. In the Colors section, click **Add dark mode** -3. Each token now shows light and dark values — edit the dark values to define your dark palette -4. Preview your components and pages in both light and dark mode using the light/dark mode toggle in the toolbar - - - Dark mode colors typically invert the scale: light mode's lightest shade becomes dark mode's darkest, and vice versa. - - -To remove dark mode, click **Remove dark mode** in the Colors section. This deletes all dark overrides. You can undo this using version history. - -## How the generated code works - -When dark mode is enabled, Subframe generates theme tokens as CSS variables so light and dark values can switch at runtime. - - - - -The CLI syncs two files: - -- **`tailwind.config.js`** — references CSS variables instead of hardcoded values, with `darkMode: 'selector'` enabled -- **`theme.css`** — defines `:root` variables for light mode and `.dark` overrides for dark mode - -```js tailwind.config.js -module.exports = { - darkMode: 'selector', - theme: { - extend: { - colors: { - "brand-primary": "rgb(var(--color-brand-primary) / )", - // ... all color tokens as CSS variable references - }, - }, - }, -} -``` - -```css theme.css -:root { - --color-brand-primary: 26 26 26; - --color-default-background: 252 252 252; - /* ... light mode values */ -} - -.dark { - --color-brand-primary: 212 212 212; - --color-default-background: 10 10 10; - /* ... dark mode overrides */ -} -``` - -Import `theme.css` in your global stylesheet or entry point: - -```css globals.css -@import "./subframe/theme.css"; -``` - - - - -The generated `theme.css` includes a `@custom-variant` for dark mode and a `.dark` block with overrides: - -```css theme.css -@custom-variant dark (&:where(.dark, .dark *)); - -@theme { - --color-brand-primary: rgb(26 26 26); - --color-default-background: rgb(252 252 252); - /* ... light mode values */ -} - -.dark { - --color-brand-primary: rgb(212 212 212); - --color-default-background: rgb(10 10 10); - /* ... dark mode overrides */ -} -``` - - - - -## Sync to code - -Run the CLI to sync your theme (including dark mode) to your codebase: +## Sync your theme -## Enable dark mode in your app +The CLI generates `:root` variables for light mode and `.dark` overrides for dark mode. See [Exporting theme](/learn/theme/exporting-theme) for details on the generated output. -To activate dark mode, set the `dark` class on the `` element. Here are a few ways to accomplish that: +## Add a toggle -### Next.js with next-themes + + ```bash npm install next-themes ``` +Wrap your app in the `ThemeProvider`: + ```tsx app/layout.tsx import { ThemeProvider } from "next-themes" @@ -122,31 +40,7 @@ export default function RootLayout({ children }) { } ``` -### React with context - -```tsx ThemeProvider.tsx -import { createContext, useContext, useEffect, useState } from "react" - -const ThemeContext = createContext({ theme: "light", toggleTheme: () => {} }) - -export function ThemeProvider({ children }) { - const [theme, setTheme] = useState("light") - - useEffect(() => { - const root = window.document.documentElement - root.classList.remove("light", "dark") - root.classList.add(theme) - }, [theme]) - - const toggleTheme = () => setTheme(theme === "light" ? "dark" : "light") - - return {children} -} - -export const useTheme = () => useContext(ThemeContext) -``` - -### Theme toggle button +Add a toggle button: ```tsx import { useTheme } from "next-themes" @@ -154,30 +48,44 @@ import { useTheme } from "next-themes" export function ThemeToggle() { const { theme, setTheme } = useTheme() - return + return ( + + ) } ``` -## Best practices + + - - +Use a context provider to manage theme state: -Always test your application in both light and dark modes. Check for: +```tsx ThemeProvider.tsx +import { createContext, useContext, useEffect, useState } from "react" -- Sufficient contrast ratios (use browser DevTools) -- Readability of all text -- Visibility of borders and dividers -- Proper styling of interactive states +const ThemeContext = createContext({ theme: "light", toggleTheme: () => {} }) - - +export function ThemeProvider({ children }) { + const [theme, setTheme] = useState(() => { + if (typeof window !== "undefined") { + return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" + } + return "light" + }) -Use the user's system preference as the default: + useEffect(() => { + document.documentElement.classList.remove("light", "dark") + document.documentElement.classList.add(theme) + }, [theme]) -```tsx - + const toggleTheme = () => setTheme(theme === "light" ? "dark" : "light") + + return {children} +} + +export const useTheme = () => useContext(ThemeContext) ``` - - + + diff --git a/packages/docs/learn/theme/customizing-theme.mdx b/packages/docs/learn/theme/customizing-theme.mdx index 0bed6095..5a2f7497 100644 --- a/packages/docs/learn/theme/customizing-theme.mdx +++ b/packages/docs/learn/theme/customizing-theme.mdx @@ -11,7 +11,7 @@ Click **Theme** in the top navigation, or press Cmd + K an The theme page has a left sidebar for navigating between sections: Colors, Typography, Borders, Corners, and Shadows. Click any section to scroll to it. -The Colors section header contains the main actions: **Ask AI**, **Import tokens**, **Export**, and a **⋯** menu with **Reset theme** and **Show version history**. +The Colors section header contains the main actions: **Ask AI**, **Import tokens**, **Export**, and a **⋯** menu with **Reset theme** and **Show version history**. All changes save automatically and apply immediately across your project. @@ -25,7 +25,7 @@ Use Ask AI to update your theme from a prompt: 1. Click **Ask AI** in the sidebar 2. Describe your changes: "warmer tones, rounder corners", "make it brutalist", or "retro theme with muted colors and bold typography" -3. Review the preview — AI updates colors, typography, corners, and shadows +3. Review the preview — AI updates colors, typography, corners, and shadows 4. Click **Apply** to update your theme Ask AI can also rename or delete tokens when the changes call for it. All component references update automatically. @@ -42,9 +42,9 @@ Subframe organizes colors into **color tokens** grouped by **folders**.
Neutral background with default text color
``` -**Color tokens** define individual colors for your design system. They can be used for specific UI purposes like Brand Primary, Default Background, or Neutral Border. Tokens can reference other tokens as aliases (e.g. Brand Primary → Brand 700). +**Color tokens** define individual colors for your design system. They can be used for specific UI purposes like Brand Primary, Default Background, or Neutral Border. Tokens can reference other tokens as aliases (e.g. Brand Primary → Brand 700). -**Folders** group related color tokens together. Organize tokens however you want — by brand, by feature, by shade scale, or any grouping that fits your system. A default **Colors** folder holds standalone tokens. +**Folders** group related color tokens together. Organize tokens however you want — by brand, by feature, by shade scale, or any grouping that fits your system. A default **Colors** folder holds standalone tokens. To quickly add tokens from an existing design system, see [Importing tokens](/learn/theme/importing-tokens). @@ -70,6 +70,10 @@ To quickly add tokens from an existing design system, see [Importing tokens](/le Click any token to open color picker. Set a direct color value or reference another token as an alias. +### Dark mode + +Enable dark mode to add separate light and dark values for each color token. See [Dark mode](/learn/theme/dark-mode) for details. + ## Typography Text tokens define typography styles with font family, size, weight, line height, and letter spacing. @@ -91,10 +95,10 @@ New tokens duplicate the properties from the first token. Typography tokens auto Click any text token to edit: -- **Font size** — Pixel value -- **Line height** — Pixel value -- **Font weight** — Slider based on font's supported weights -- **Letter spacing** — Slider from `-0.05em` to `0.05em` +- **Font size** — Pixel value +- **Line height** — Pixel value +- **Font weight** — Slider based on font's supported weights +- **Letter spacing** — Slider from `-0.05em` to `0.05em` ### Changing font families @@ -131,9 +135,9 @@ When generating code, border styles turn into explicit values for the border: Click any border token to edit: -- **Border style** — Solid or dashed -- **Border size** — Pixel width -- **Border color** — Color token reference or direct value +- **Border style** — Solid or dashed +- **Border size** — Pixel width +- **Border color** — Color token reference or direct value ## Corners @@ -177,11 +181,11 @@ Shadow tokens auto-sort based on perceived shadow effect. Click any shadow token to edit individual shadow layers. Each layer has: -- **Inset** — Whether shadow appears inside element -- **X/Y offset** — Horizontal and vertical offset in pixels -- **Blur radius** — Blur amount in pixels -- **Spread radius** — Spread amount in pixels -- **Color** — Shadow color with opacity +- **Inset** — Whether shadow appears inside element +- **X/Y offset** — Horizontal and vertical offset in pixels +- **Blur radius** — Blur amount in pixels +- **Spread radius** — Spread amount in pixels +- **Color** — Shadow color with opacity Add multiple layers for complex shadow effects. @@ -193,7 +197,7 @@ Add multiple layers for complex shadow effects. Apply a theme preset to start fresh: -1. Click **⋯** in the sidebar and select **Reset theme** +1. Click **⋯** in the sidebar and select **Reset theme** 2. Browse 10 preset styles 3. Customize brand colors, fonts, and corner radius 4. Toggle between Light and Dark mode @@ -206,7 +210,7 @@ Each preset configures color palettes (brand, neutral, error, success, warning), View and restore previous versions of your theme: -1. Click **⋯** in the sidebar and select **Version history** +1. Click **⋯** in the sidebar and select **Version history** 2. Browse the timeline and select a version to preview 3. Click **Restore** to revert to that version @@ -214,4 +218,4 @@ Select **Exit version history** from the same menu to return to editing. ## Limitations -**Spacing not configurable** — Spacing tokens (padding, gaps) use Tailwind defaults. Extend your Tailwind config manually for custom spacing in your codebase. +**Spacing not configurable** — Spacing tokens (padding, gaps) use Tailwind defaults. Extend your Tailwind config manually for custom spacing in your codebase. diff --git a/packages/docs/learn/theme/dark-mode.mdx b/packages/docs/learn/theme/dark-mode.mdx new file mode 100644 index 00000000..29f8476b --- /dev/null +++ b/packages/docs/learn/theme/dark-mode.mdx @@ -0,0 +1,34 @@ +--- +title: Dark mode +description: Define light and dark color values for your theme. +--- + +import CliSyncAllCommand from "/snippets/cli-sync-all-command.mdx" + +Your theme supports light and dark color modes. When dark mode is enabled, each color token has separate light and dark values. + +## Adding dark mode + +1. Open **Theme** in the top navigation +2. Click **Add dark mode** in the Colors section +3. Edit the dark value for each color token + +{/* TODO: Add screenshot of dark mode color tokens */} + +Preview your designs in dark mode using the light/dark toggle in the toolbar. + +## Removing dark mode + +Click **Remove dark mode** in the Colors section. This deletes all dark color overrides. + +Removing dark mode is destructive. Use [version history](/learn/projects/version-history) to restore if needed. + +## Code export + +When dark mode is enabled, the CLI generates theme tokens as CSS variables with `:root` and `.dark` blocks so light and dark values switch at runtime. See [Exporting theme](/learn/theme/exporting-theme) for the full generated output. + +Run the CLI to sync your theme: + + + +To add a dark mode toggle to your app, see the [Dark mode toggle](/guides/dark-mode) guide. diff --git a/packages/docs/learn/theme/exporting-theme.mdx b/packages/docs/learn/theme/exporting-theme.mdx index 97cb8f2d..206d452a 100644 --- a/packages/docs/learn/theme/exporting-theme.mdx +++ b/packages/docs/learn/theme/exporting-theme.mdx @@ -11,8 +11,8 @@ Your theme generates a Tailwind CSS configuration that your codebase uses for st Click **Export** in the sidebar to view the generated Tailwind configuration for your theme. The dialog has two tabs: -- **Tailwind CSS v3** — Shows a `tailwind.config.js` file with your tokens as a JavaScript module -- **Tailwind CSS v4** — Shows a `theme.css` file with your tokens as CSS variables inside a `@theme` block +- **Tailwind CSS v3** — Shows a `tailwind.config.js` file with your tokens as a JavaScript module +- **Tailwind CSS v4** — Shows a `theme.css` file with your tokens as CSS variables inside a `@theme` block Click **Copy to clipboard** to copy either format. @@ -22,10 +22,10 @@ Click **Copy to clipboard** to copy either format. The generated config includes colors, font sizes, font families, box shadows, border radius, container settings, and responsive breakpoints. -When [dark mode](/guides/dark-mode) is enabled, the export includes additional dark mode overrides: +When [dark mode](/learn/theme/dark-mode) is enabled, the export includes additional dark mode overrides: -- **Tailwind v3** — An additional `theme.css` file with `:root` and `.dark` CSS variable blocks, and `darkMode: 'selector'` in the config -- **Tailwind v4** — A `.dark` block and `@custom-variant dark` declaration in the `theme.css` file +- **Tailwind v3** — An additional `theme.css` file with `:root` and `.dark` CSS variable blocks, and `darkMode: 'selector'` in the config +- **Tailwind v4** — A `.dark` block and `@custom-variant dark` declaration in the `theme.css` file ## Sync to code From 270ea95696d05ad23415d0b39b0e4a324acee5b5 Mon Sep 17 00:00:00 2001 From: Irvin Zhan <4621962+izhan@users.noreply.github.com> Date: Mon, 4 May 2026 23:54:49 -0700 Subject: [PATCH 2/2] [GTMBot] v3: fix copy, use Steps, fix ordering, complete Vite guide - Use component for toggle procedures (matches installation.mdx pattern) - Add missing Vite/React steps: wrap app + add toggle button - Explain generated code inline instead of linking out - Move dark-mode to end of nav in both Guides and Theme - Fix ambiguous language around CSS variables and class toggling --- packages/docs/docs.json | 8 +- packages/docs/guides/dark-mode.mdx | 124 ++++++++++++++++++++++-- packages/docs/learn/theme/dark-mode.mdx | 4 +- 3 files changed, 123 insertions(+), 13 deletions(-) diff --git a/packages/docs/docs.json b/packages/docs/docs.json index 0617e11a..96961bac 100644 --- a/packages/docs/docs.json +++ b/packages/docs/docs.json @@ -48,11 +48,11 @@ "pages": [ "guides/mcp-server", "guides/skills", - "guides/dark-mode", "guides/component-docs", "guides/accessibility", "guides/testing", - "guides/publish-to-npm" + "guides/publish-to-npm", + "guides/dark-mode" ] }, { @@ -95,10 +95,10 @@ "group": "Theme", "pages": [ "learn/theme/customizing-theme", - "learn/theme/dark-mode", "learn/theme/importing-tokens", "learn/theme/exporting-theme", - "learn/theme/adding-custom-fonts" + "learn/theme/adding-custom-fonts", + "learn/theme/dark-mode" ] }, "learn/flows/flows", diff --git a/packages/docs/guides/dark-mode.mdx b/packages/docs/guides/dark-mode.mdx index 9eb7129d..348371b8 100644 --- a/packages/docs/guides/dark-mode.mdx +++ b/packages/docs/guides/dark-mode.mdx @@ -5,24 +5,98 @@ description: Add a dark mode toggle to your app using Subframe's generated theme import CliSyncAllCommand from "/snippets/cli-sync-all-command.mdx" -When [dark mode](/learn/theme/dark-mode) is enabled in your theme, the CLI generates CSS variables that switch between light and dark values. Activate dark mode by adding the `dark` class to the `` element. +When you [enable dark mode](/learn/theme/dark-mode) in your theme, the CLI generates your color tokens as CSS variables instead of hardcoded values. Light mode values load by default, and dark mode values activate when a `dark` class is present on the page. This guide covers how to toggle between them. + +## How the generated code works + + + + +The CLI syncs two files: + +- **`tailwind.config.js`** — references CSS variables instead of hardcoded values, with `darkMode: 'selector'` enabled +- **`theme.css`** — defines `:root` variables for light mode and `.dark` overrides for dark mode + +```js tailwind.config.js +module.exports = { + darkMode: 'selector', + theme: { + extend: { + colors: { + "brand-primary": "rgb(var(--color-brand-primary) / )", + // ... all color tokens as CSS variable references + }, + }, + }, +} +``` + +```css theme.css +:root { + --color-brand-primary: 26 26 26; + --color-default-background: 252 252 252; + /* ... light mode values */ +} + +.dark { + --color-brand-primary: 212 212 212; + --color-default-background: 10 10 10; + /* ... dark mode overrides */ +} +``` + +Import `theme.css` in your global stylesheet or entry point: + +```css globals.css +@import "./subframe/theme.css"; +``` + + + + +The generated `theme.css` includes a `@custom-variant` for dark mode and a `.dark` block with overrides: + +```css theme.css +@custom-variant dark (&:where(.dark, .dark *)); + +@theme { + --color-brand-primary: rgb(26 26 26); + --color-default-background: rgb(252 252 252); + /* ... light mode values */ +} + +.dark { + --color-brand-primary: rgb(212 212 212); + --color-default-background: rgb(10 10 10); + /* ... dark mode overrides */ +} +``` + + + ## Sync your theme - +Run the CLI to sync your theme (including dark mode) to your codebase: -The CLI generates `:root` variables for light mode and `.dark` overrides for dark mode. See [Exporting theme](/learn/theme/exporting-theme) for details on the generated output. + ## Add a toggle +To switch between light and dark mode, your app needs to toggle the `dark` class on the `` element. Here's how to set that up: + + + + ```bash npm install next-themes ``` -Wrap your app in the `ThemeProvider`: + + ```tsx app/layout.tsx import { ThemeProvider } from "next-themes" @@ -40,7 +114,8 @@ export default function RootLayout({ children }) { } ``` -Add a toggle button: + + ```tsx import { useTheme } from "next-themes" @@ -56,10 +131,14 @@ export function ThemeToggle() { } ``` + + + -Use a context provider to manage theme state: + + ```tsx ThemeProvider.tsx import { createContext, useContext, useEffect, useState } from "react" @@ -87,5 +166,38 @@ export function ThemeProvider({ children }) { export const useTheme = () => useContext(ThemeContext) ``` + + + +```tsx main.tsx +import { ThemeProvider } from "./ThemeProvider" + +ReactDOM.createRoot(document.getElementById("root")!).render( + + + +) +``` + + + + +```tsx +import { useTheme } from "./ThemeProvider" + +export function ThemeToggle() { + const { theme, toggleTheme } = useTheme() + + return ( + + ) +} +``` + + + + diff --git a/packages/docs/learn/theme/dark-mode.mdx b/packages/docs/learn/theme/dark-mode.mdx index 29f8476b..311de776 100644 --- a/packages/docs/learn/theme/dark-mode.mdx +++ b/packages/docs/learn/theme/dark-mode.mdx @@ -25,9 +25,7 @@ Click **Remove dark mode** in the Colors section. This deletes all dark color ov ## Code export -When dark mode is enabled, the CLI generates theme tokens as CSS variables with `:root` and `.dark` blocks so light and dark values switch at runtime. See [Exporting theme](/learn/theme/exporting-theme) for the full generated output. - -Run the CLI to sync your theme: +When dark mode is enabled, the CLI generates your color tokens as CSS variables. Light mode values load by default, and dark mode values activate when a `dark` class is present on the page. Run the CLI to sync: