组件
- 手风琴(Accordion)
- 警报(Alert)
- 警报对话框(Alert Dialog)
- 长宽比(Aspect Ratio)
- 头像(Avatar)
- 徽章(Badge)
- 面包屑(Breadcrumb)
- 按钮(Button)
- 日历(Calendar)
- 卡片(Card)
- 轮播(Carousel)
- 图表(Chart)
- 复选框(Checkbox)
- 可折叠(Collapsible)
- 组合框(Combobox)
- 命令(Command)
- 上下文菜单(Context Menu)
- 数据表格(Data Table)
- 日期选择器(Date Picker)
- 对话框(Dialog)
- 抽屉(Drawer)
- 下拉菜单(Dropdown Menu)
- React Hook Form
- 悬浮卡片(Hover Card)
- 输入框(Input)
- OTP 输入(Input OTP)
- 标签(Label)
- 菜单栏(Menubar)
- 导航菜单(Navigation Menu)
- 分页(Pagination)
- 气泡卡片(Popover)
- 进度条(Progress)
- 单选按钮组(Radio Group)
- 可调整大小(Resizable)
- 滚动区域(Scroll-area)
- 选择器(Select)
- 分隔符(Separator)
- 侧拉面板(Sheet)
- 侧边栏(Sidebar)
- 骨架屏(Skeleton)
- 滑块(Slider)
- Sonner(轻量通知)
- 开关(Switch)
- 表格(Table)
- 选项卡(Tabs)
- 文本域(Textarea)
- 吐司(Toast)
- 切换(Toggle)
- 切换组(Toggle Group)
- 工具提示(Tooltip)
- 排版(Typography)
修改你的 tailwind.css 文件
将 :root[class~="dark"]
添加到你的 tailwind.css 文件中。这将允许你在 HTML 元素上使用 dark
类来应用深色模式样式。
.dark,
:root[class~="dark"] {
...;
}
安装 remix-themes
首先安装 remix-themes
pnpm add remix-themes
创建会话存储和主题会话解析器
import { createThemeSessionResolver } from "remix-themes"
// You can default to 'development' if process.env.NODE_ENV is not set
const isProduction = process.env.NODE_ENV === "production"
const sessionStorage = createCookieSessionStorage({
cookie: {
name: "theme",
path: "/",
httpOnly: true,
sameSite: "lax",
secrets: ["s3cr3t"],
// Set domain and secure only if in production
...(isProduction
? { domain: "your-production-domain.com", secure: true }
: {}),
},
})
export const themeSessionResolver = createThemeSessionResolver(sessionStorage)
设置 Remix Themes
将 ThemeProvider
添加到你的根布局中。
import clsx from "clsx"
import { PreventFlashOnWrongTheme, ThemeProvider, useTheme } from "remix-themes"
import { themeSessionResolver } from "./sessions.server"
// Return the theme from the session storage using the loader
export async function loader({ request }: LoaderFunctionArgs) {
const { getTheme } = await themeSessionResolver(request)
return {
theme: getTheme(),
}
}
// Wrap your app with ThemeProvider.
// `specifiedTheme` is the stored theme in the session storage.
// `themeAction` is the action name that's used to change the theme in the session storage.
export default function AppWithProviders() {
const data = useLoaderData<typeof loader>()
return (
<ThemeProvider specifiedTheme={data.theme} themeAction="/action/set-theme">
<App />
</ThemeProvider>
)
}
export function App() {
const data = useLoaderData<typeof loader>()
const [theme] = useTheme()
return (
<html lang="en" className={clsx(theme)}>
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta />
<PreventFlashOnWrongTheme ssrTheme={Boolean(data.theme)} />
<Links />
</head>
<body>
<Outlet />
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
)
}
添加一个 action 路由
在 /routes/action.set-theme.ts
中创建一个文件。确保将文件名传递给 ThemeProvider 组件。当用户更改主题时,此路由用于将会话存储中存储的首选主题。
import { createThemeAction } from "remix-themes"
import { themeSessionResolver } from "./sessions.server"
export const action = createThemeAction(themeSessionResolver)
添加模式切换
在你的网站上放置一个模式切换按钮,以在亮色和深色模式之间切换。
import { Moon, Sun } from "lucide-react"
import { Theme, useTheme } from "remix-themes"
import { Button } from "./ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "./ui/dropdown-menu"
export function ModeToggle() {
const [, setTheme] = useTheme()
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon">
<Sun className="h-[1.2rem] w-[1.2rem] scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" />
<Moon className="absolute h-[1.2rem] w-[1.2rem] scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" />
<span className="sr-only">Toggle theme</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => setTheme(Theme.LIGHT)}>
Light
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme(Theme.DARK)}>
Dark
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}