kobalte icon indicating copy to clipboard operation
kobalte copied to clipboard

No mention of Color Mode Script & dark / light mode handling on the website ?

Open carere opened this issue 1 year ago • 2 comments

Describe the bug As describe in the title, I don't find mention about any dark / light mode handling on the website anymore. Is that normal ?

Expected behavior The website should specify how to handle dark / light mode.

carere avatar Dec 07 '24 12:12 carere

Found this strange too when troubleshooting

This is the example mentioned on the shadcn-solid website, however I am having bugs currently

import { ColorModeProvider, ColorModeScript } from "@kobalte/core";
import { MetaProvider } from "@solidjs/meta";
import { Router } from "@solidjs/router";
import { FileRoutes } from "@solidjs/start";
import { Suspense } from "solid-js";
import { isServer } from "solid-js/web";
import { getCookie } from "vinxi/http";

export default function App() {
  return (
    <Router
      root={props => (
        <MetaProvider>
          <Suspense>
            <ColorModeScript />
            <ColorModeProvider>{props.children}</ColorModeProvider>
          </Suspense>
        </MetaProvider>
      )}
    >
      <FileRoutes />
    </Router>
  );
}

remirth avatar Dec 10 '24 20:12 remirth

that could help

import { HiOutlineMoon, HiOutlineSun } from "solid-icons/hi";
import { Show } from "solid-js";

import { Button } from "./button";
import { useTheme } from "./theme/theme-provider-context";

const iconWidth = 24;

const ModeToggle = () => {
  const { theme, setNextTheme } = useTheme();

  return (
    <Button variant="ghost" onClick={setNextTheme}>
      <Show when={theme() === "light"}>
        Light theme
        <HiOutlineSun width={iconWidth} />
      </Show>
      <Show when={theme() === "dark"}>
        Dark theme
        <HiOutlineMoon width={iconWidth} />
      </Show>
      <Show when={theme() === "system"}>
        System theme
        <HiOutlineSun width={iconWidth} />
        <HiOutlineMoon width={iconWidth} />
      </Show>
    </Button>
  );
};

export default ModeToggle;

import {
  createContext,
  createEffect,
  createSignal,
  ParentProps,
  useContext,
} from "solid-js";

type Theme = "light" | "dark" | "system";
const themeKey = "theme_key";
const order: Theme[] = ["light", "dark", "system"];

const ThemeContext = createContext<{
  theme: () => Theme;
  setNextTheme: () => void;
}>();

export const ThemeProvider = (
  props: {
    initialTheme?: Theme;
  } & ParentProps,
) => {
  const [theme, setTheme] = createSignal<Theme>(
    props.initialTheme ||
      (localStorage.getItem(themeKey) as Theme) ||
      props.initialTheme ||
      "system",
  );

  createEffect(() => {
    const currentTheme = theme();
    const isDark =
      currentTheme === "system"
        ? window.matchMedia("(prefers-color-scheme: dark)").matches
        : currentTheme === "dark";
    document.documentElement.classList[isDark ? "add" : "remove"]("dark");
    localStorage.setItem(themeKey, currentTheme);
  });

  const setNextTheme = () => {
    setTheme(order[(order.indexOf(theme()) + 1) % order.length] as Theme);
  };

  return (
    <ThemeContext.Provider value={{ theme, setNextTheme }}>
      {props.children}
    </ThemeContext.Provider>
  );
};

export const useTheme = () => {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error("useTheme must be used within a ThemeProvider");
  }
  return context;
};

OchirDarmaev avatar Jun 22 '25 22:06 OchirDarmaev