Civitai 组件预览实战:基于 Ladle + Mantine v7 + Tailwind 的隔离式 UI 开发与视觉回归工作流
Civitai 组件预览实战基于 Ladle Mantine v7 Tailwind 的隔离式 UI 开发与视觉回归工作流【免费下载链接】civitaiA repository of models, textual inversions, and more项目地址: https://gitcode.com/GitHub_Trending/ci/civitai本文介绍 Civitai 仓库中一套面向 UI 开发与视觉排障的组件预览工作流基于 Ladle轻量级 Storybook 替代品在真实 Mantine v7 Tailwind 样式环境下隔离渲染 React 组件无需启动完整开发服务器即可快速查看、截图并迭代组件外观。读完本文你将掌握从创建 Story、启动 Ladle、暗色/亮色双主题截图到复杂组件分级处理的完整闭环方法并了解本仓库.ladle/目录下的真实工程配置。为什么需要隔离式组件预览Civitai 是一个包含数千个组件src/components 下 2500 文件的大型 Next.js 应用。在完整开发服务器上预览单个组件的成本很高路由、鉴权、tRPC 上下文、全局 Provider 都会拖慢启动与迭代节奏。Ladle 方案的核心优势在于无需 dev server。它把单个组件放进一个极简的 HTML 页面中配合与主应用一致的 Mantine 主题与 Tailwind 样式让你可以在几秒内完成「改代码 → 看效果 → 再改」的循环。这正好覆盖以下四类典型场景对应技能文档中的 When to Use修改 UI 组件之后主动预览改动效果确认视觉没有回归用户要求查看效果时例如 show me what it looks like 或 generate a preview排查视觉 Bug 时为出问题的组件创建 Story 来复现问题并迭代修复提交前审查组件改动在 commit 之前对变更做一次快速的视觉走查。前置条件项目根目录的 Ladle 工程配置Ladle 的配置集中在仓库根目录的 .ladle 文件夹下包含三个文件文件作用.ladle/components.tsx全局 ProviderMantineProvider 主题子集.ladle/config.mjsStory 发现与 Vite 配置接入.ladle/vite.config.tsVite 配置~/路径别名 PostCSS此外ladle/react已作为开发依赖安装在 package.jsonladle/react: ^5.1.1。如果当前 worktree 中缺少上述文件可以从 main 分支拷贝或参考本文末尾的「Setup Reference」一节手动重建。.ladle/components.tsx让预览贴近真实运行环境预览质量的关键在于「渲染环境与主应用一致」。该文件通过 Ladle 的GlobalProvider把每个 Story 包进一个与主应用同源的 MantineProvider 中import { MantineProvider, createTheme, Modal } from mantine/core; import type { GlobalProvider } from ladle/react; import mantine/core/styles.layer.css; import ../src/styles/globals.css; // Subset of the app theme (from src/providers/ThemeProvider.tsx) const theme createTheme({ components: { Modal: Modal.extend({ styles: { content: { maxWidth: 100%, overflowX: hidden }, inner: { paddingLeft: 0, paddingRight: 0 }, }, }), Badge: { styles: { leftSection: { lineHeight: 1 } }, defaultProps: { radius: sm, variant: light }, }, ActionIcon: { defaultProps: { color: gray, variant: subtle }, }, Tooltip: { defaultProps: { withArrow: true }, }, }, colors: { dark: [ #C1C2C5, #A6A7AB, #8c8fa3, #5C5F66, #373A40, #2C2E33, #25262B, #1A1B1E, #141517, #101113, ], blue: [ #E7F5FF, #D0EBFF, #A5D8FF, #74C0FC, #4DABF7, #339AF0, #228BE6, #1C7ED6, #1971C2, #1864AB, ], }, white: #fefefe, black: #222, }); export const Provider: GlobalProvider ({ children, globalState }) ( MantineProvider theme{theme} defaultColorScheme{globalState.theme dark ? dark : light} forceColorScheme{globalState.theme dark ? dark : light} div classNameladle-story-wrapper style{{ padding: 24, width: fit-content }} {children} /div /MantineProvider );这段代码与仓库实际文件一致几个关键点值得说明主题子集注释明确指出这份主题是主应用主题的裁剪版来源是 src/providers/ThemeProvider.tsx。对照源码可以看到Modal.extend、Badge、ActionIcon、Tooltip的组件级配置以及dark/blue色板都取自主主题保证预览与生产视觉一致。主主题还定义了 Drawer、Popover、Rating、Switch、Menu 等更多组件配置与 gray/yellow/green/red/orange/lime 等完整色板预览环境按需裁剪即可。明暗双主题驱动globalState.theme来自 Ladle 的全局状态通过defaultColorScheme与forceColorScheme双重指定让 Story 可以随 URL 参数themedark|light切换。样式导入mantine/core/styles.layer.css是 Mantine v7 的层叠样式入口../src/styles/globals.css即 src/styles/globals.css是主应用的全局样式。Tailwind 依赖 PostCSS 管线在构建期注入见下文 Vite 配置。ladle-story-wrapper类名这是截图阶段用于定位渲染区域的钩子后面会用到固定 24px padding 与fit-content宽度保证不同 Story 的截图尺寸一致。.ladle/config.mjsStory 发现规则/** type {import(ladle/react).UserConfig} */ export default { stories: src/**/*.stories.tsx, defaultStory: , viteConfig: .ladle/vite.config.ts, };stories字段声明了 Story 的自动发现范围src/**/*.stories.tsx。也就是说任何放在src下、以.stories.tsx结尾的文件都会被 Ladle 自动收录为 Story无需手工注册。.ladle/vite.config.ts路径别名与 PostCSSimport { defineConfig } from vite; import path from path; export default defineConfig({ resolve: { alias: { ~: path.resolve(__dirname, ../src), }, }, css: { postcss: path.resolve(__dirname, ..), }, });~别名把~解析到src目录与主应用 tsconfig 的路径映射保持一致见 tsconfig.json 中~/*: [./src/*]。这样 Story 里可以直接import { x } from ~/shared/...与主应用代码写法一致。PostCSS指向仓库根目录的 postcss.config.js从而启用 Tailwind 以及 package.json 中声明的postcss-preset-mantine、postcss-simple-vars、postcss-assign-layer等 Mantine v7 样式处理插件保证 Tailwind 类与 Mantine 样式在预览环境中都能正确编译。四步工作流整个预览流程分为四步创建 Story → 启动 Ladle → 双主题截图 → 展示并迭代。第一步创建/更新 Story在要预览的组件旁边创建.stories.tsx文件src/components/MyComponent/MyComponent.stories.tsx src/pages/challenges/EligibleModels.stories.tsxStory 的标准结构如下import { /* Mantine components */ } from mantine/core; // Import the component or recreate the relevant JSX // Mock data that represents realistic API responses const mockData [ ... ]; // Render the component with different states function Preview({ data }) { return ( div style{{ width: 320 }} {/* Constrain to realistic width */} MyComponent data{data} / /div ); } /** Default state */ export const Default () Preview data{mockData} /; /** Empty state */ export const Empty () Preview data{[]} /; /** Loading or edge case states */ export const LongList () Preview data{longMockData} /;需要严格遵守的编写规范约束真实宽度在外层 wrapper 上设置贴近真实场景的width侧边栏 320px、主内容区 600px避免组件在无限宽度下变形原样拷贝 props从真实组件中复制 Mantine 组件 props 和 Tailwind 类名保证预览即生产继承父容器样式如果组件原本位于 Accordion、Card 等容器内要把父容器的内联styles如 Accordion styles一并复制进 Story保留主题钩子如果组件内部使用了useComputedColorScheme、useMantineThemeStory 中也要保留以便暗色/亮色主题正确生效24 个变体至少覆盖默认态、空态、单项态、溢出态等关键状态default / empty / single item / overflow每个变体对应一个具名导出。第二步启动 Ladle启动前先探测端口是否已有实例在运行Ladle 约定固定使用 61111 端口避免与 3000 的开发服务器及其它服务冲突# Check if Ladle is already running curl -s -o /dev/null -w %{http_code} http://localhost:61111/ # If not running, start it (from project root or worktree root) cd worktree-path npx ladle serve --port 61111 # Wait for it to be ready (~3-5 seconds)启动后 Ladle 会自动发现所有匹配src/**/*.stories.tsx的 Story即第一步创建的EligibleModels.stories.tsx、ModelCard.stories.tsx等文件。第三步双主题截图截图环节借助仓库中的浏览器自动化技能.claude/skills/browser-automation/SKILL.md完成# Create a browser session node ~/.claude/skills/browser-automation/cli.mjs session http://localhost:61111 --name ladle # Capture all story variants in dark and light themes node ~/.claude/skills/browser-automation/cli.mjs run const stories [ { name: default, path: my-component--default }, { name: empty, path: my-component--empty }, ]; const themes [dark, light]; const dir session-screenshots-dir; for (const theme of themes) { for (const story of stories) { await page.goto(http://localhost:61111/?story story.path theme theme modepreview); await page.waitForTimeout(800); const wrapper page.locator(.ladle-story-wrapper); await wrapper.screenshot({ path: dir /crop- theme - story.name .png }); } } --label Component preview screenshots -s ladle这段脚本的关键点URL 参数?storystory-paththemedark|lightmodepreview直接定位到某个 Story 的某个变体并指定明暗主题对应.ladle/components.tsx中globalState.theme的取值每个页面等待 800ms 渲染稳定定位到.ladle-story-wrapper正是 .ladle/components.tsx 中包裹 children 的容器做裁剪截图得到无多余留白、带统一 padding 的截图截图命名采用crop-theme-story-name.png暗色/亮色一目了然。Story 路径格式由文件名与导出名推导而来——kebab-case 文件名 -- kebab-case 导出名文件导出Story 路径EligibleModels.stories.tsxDefaulteligible-models--defaultModelCard.stories.tsxWithBadgemodel-card--with-badge第四步展示与迭代内联展示用 Read 工具读取 PNG 截图在对话中直接展示给用户打开本地查看如需用户在系统图片查看器中打开可执行start path-to-screenshot征求反馈询问 Does this look right? Want me to adjust anything?迭代闭环如需修改改组件 → 重新截图 → 再次展示循环直至满意。复杂组件的分级处理策略并非所有组件都能直接丢进 Story。技能文档把组件按耦合程度分为三档简单直接做纯展示组件badge、card、list、accordion 等只依赖 Mantine Tailwind 的组件props 简单的组件。这类组件只需按第一步的规范写 Story 即可。中等Mock 数据依赖 tRPC 数据的组件从类型定义中提取出类型构造逼真的 mock 对象包含图片的组件用占位 div 或空图片 fallback包含链接的组件用div或a href#替代 Next.js 的LinkLadle 环境没有 Next.js 路由上下文。困难上报给用户深度耦合多个 Providerauth、router、tRPC context的组件使用复杂 hooks、会发起 API 调用的组件重度依赖 CSS Module 的组件。遇到困难案例时向用户说明并提供三个选项This component depends on [auth/router/tRPC context]. I can either:Mock out the dependencies (more setup, more accurate)Extract just the visual parts into the story (faster, close enough)Skip the preview and we can check it on the dev server insteadWhat would you prefer?即完整 mock 依赖更准确但更费时、只抽取视觉部分更快但近似、跳过预览改用 dev server。由用户权衡取舍。Setup Reference手动重建 Ladle 配置如果当前 worktree 缺少.ladle/三件套可以按以下内容从零创建。上文已给出 .ladle/components.tsx、.ladle/config.mjs、.ladle/vite.config.ts 的完整内容此处补充安装命令pnpm add -D ladle/react本仓库使用 pnpm 管理依赖见 pnpm-workspace.yaml 与根目录 package.json安装后即可在任意 worktree 中执行npx ladle serve --port 61111。实战 Tips 汇总先暗后亮Civitai 默认是暗色模式所以截图时先拍 dark 主题再拍 light约束宽度始终设置与真实上下文一致的宽度——侧边栏约 320px、主内容区约 600px、整页约 1200px复制父级样式组件若位于 Accordion、Card 等容器内部要在 Story 中复刻父容器的样式否则间距、圆角、阴影会失真Story 生命周期一次性审查用的 Story 可在用后删除可复用组件的 Story 可以保留成为长期的视觉回归资产固定端口始终使用 61111避免与 dev server3000及其它服务端口冲突。小结这套工作流把「查看组件效果」从分钟级的 dev server 启动中解放出来Story 即文档、截图即证据、双主题即覆盖。结合 .ladle/components.tsx 对 src/providers/ThemeProvider.tsx 主题子集的复用预览环境与生产环境的视觉保真度得以保证而「简单直做 / 中等 mock / 困难上报」的分级策略则让它在面对 Civitai 这种高度依赖 auth、router、tRPC 上下文的大型应用时依然可控可落地。【免费下载链接】civitaiA repository of models, textual inversions, and more项目地址: https://gitcode.com/GitHub_Trending/ci/civitai创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →