From 7c13833698d04b6b4cf9fe3f2fb46ecc1f058b92 Mon Sep 17 00:00:00 2001 From: TinsFox Date: Fri, 15 Nov 2024 15:56:37 +0800 Subject: [PATCH] feat: pro table (#15) * feat: pro table * refactor: splitting components * chore: use workspace typescript * feat(proTable): add storybook * fix(storybook): preview width * feat(storybook): light and dark mode * fix: height * style: pagination style * feat: support search * feat(ProTable): search form filed * feat(ProTable): column pinning sticky * feat(ProTable): pinned TypeScript * chore: remove function * fix: vitepress build * feat(proTable stories): reorganize ProTable stories for better clarity - Split stories into individual feature demonstrations - Add basic table example with simplified data structure - Add separate stories for pagination, loading, empty state - Add stories for search, custom toolbar, pinned columns - Add stories for custom column sizes and visibility - Add stories for refresh functionality and custom cells - Improve code organization and readability - Fix linting issues with console statements and spacing * feat(proTable): split table body * feat(proTable): split stories * chore: upgrade storybook * feat: split ProTable into dataTable * feat: fetch data * feat(data table): option * fix(data table): search options * chore: rename data-table-search * chore: remove TeamSwitcher * fix: preset value * chore: api * fix: pagination * feat(data table): when change page size, reset page index to 0 * chore: cSpell * feat: avatars --- .storybook/ThemeChanger.tsx | 43 ++ .storybook/main.ts | 3 + .storybook/manager.ts | 5 +- .storybook/preview.tsx | 42 +- .storybook/theme.ts | 63 ++ .vscode/settings.json | 4 +- locales/en/navigation.json | 3 +- locales/zh-CN/navigation.json | 3 +- package.json | 27 +- pnpm-lock.yaml | 614 +++++++-------- public/avatars/01.png | Bin 0 -> 13920 bytes public/avatars/02.png | Bin 0 -> 15326 bytes public/avatars/03.png | Bin 0 -> 14526 bytes public/avatars/04.png | Bin 0 -> 14077 bytes public/avatars/05.png | Bin 0 -> 14821 bytes public/avatars/shadcn.jpg | Bin 0 -> 23707 bytes src/components/data-table/context.tsx | 20 + .../data-table}/data-table-column-header.tsx | 0 .../data-table}/data-table-faceted-filter.tsx | 0 .../data-table-pagination.stories.tsx | 92 +++ .../data-table/data-table-pagination.tsx | 198 +++++ .../data-table/data-table-search.tsx | 164 ++++ .../data-table-skeleton.stories.tsx | 67 ++ .../data-table/data-table-skeleton.tsx | 35 + .../data-table/data-table-toolbar.stories.tsx | 57 ++ .../data-table/data-table-toolbar.tsx | 53 ++ src/components/data-table/data-table-types.ts | 132 ++++ src/components/data-table/data-table-util.ts | 27 + .../data-table-view-options.stories.tsx | 188 +++++ .../data-table}/data-table-view-options.tsx | 10 +- src/components/data-table/data-table.tsx | 81 ++ src/components/data-table/index.tsx | 27 + src/components/loading.tsx | 10 +- src/components/nav-sidebar/nav-user.tsx | 15 +- src/components/pro-table/index.tsx | 129 ++++ src/components/pro-table/types.ts | 140 ++++ src/components/team-switcher.tsx | 216 ------ src/hooks/query/use-album.ts | 30 +- src/hooks/query/use-tasks.ts | 33 + src/hooks/query/use-user.test.tsx | 2 +- src/hooks/query/use-user.ts | 39 +- src/hooks/query/user-memu.ts | 9 +- .../data/data.tsx => lib/data-dictionary.ts} | 0 .../(admin)/(with-layout)/list/card-list.tsx | 5 +- .../(with-layout)/list/components/columns.tsx | 115 --- .../list/components/data-table-pagination.tsx | 107 --- .../components/data-table-row-actions.tsx | 67 -- .../list/components/data-table-toolbar.tsx | 58 -- .../list/components/data-table.tsx | 124 ---- .../list/components/user-nav.tsx | 62 -- .../list/components/view-user.tsx | 143 ---- .../list/data-table/components/view-user.tsx | 252 +++++++ .../{basic-list.tsx => data-table/index.tsx} | 208 +----- .../(admin)/(with-layout)/list/data/seed.ts | 11 - .../(with-layout)/list/data/tasks.json | 702 ------------------ .../(admin)/(with-layout)/list/index.tsx | 2 +- .../(with-layout)/list/pro-table/index.tsx | 233 ++++++ .../(admin)/(with-layout)/list/table-list.tsx | 11 - .../components/album-card.tsx | 0 .../(with-layout)/list/table-list/index.tsx | 255 +++++++ src/pages/(admin)/layout.tsx | 2 +- src/providers/root-providers.tsx | 2 +- src/schema/album.ts | 8 + .../list/data/schema.ts => schema/task.ts} | 4 +- src/schema/user.ts | 8 +- tailwind.config.ts | 2 + tsconfig.app.json | 2 +- 67 files changed, 2735 insertions(+), 2229 deletions(-) create mode 100644 .storybook/ThemeChanger.tsx create mode 100644 .storybook/theme.ts create mode 100644 public/avatars/01.png create mode 100644 public/avatars/02.png create mode 100644 public/avatars/03.png create mode 100644 public/avatars/04.png create mode 100644 public/avatars/05.png create mode 100644 public/avatars/shadcn.jpg create mode 100644 src/components/data-table/context.tsx rename src/{pages/(admin)/(with-layout)/list/components => components/data-table}/data-table-column-header.tsx (100%) rename src/{pages/(admin)/(with-layout)/list/components => components/data-table}/data-table-faceted-filter.tsx (100%) create mode 100644 src/components/data-table/data-table-pagination.stories.tsx create mode 100644 src/components/data-table/data-table-pagination.tsx create mode 100644 src/components/data-table/data-table-search.tsx create mode 100644 src/components/data-table/data-table-skeleton.stories.tsx create mode 100644 src/components/data-table/data-table-skeleton.tsx create mode 100644 src/components/data-table/data-table-toolbar.stories.tsx create mode 100644 src/components/data-table/data-table-toolbar.tsx create mode 100644 src/components/data-table/data-table-types.ts create mode 100644 src/components/data-table/data-table-util.ts create mode 100644 src/components/data-table/data-table-view-options.stories.tsx rename src/{pages/(admin)/(with-layout)/list/components => components/data-table}/data-table-view-options.tsx (86%) create mode 100644 src/components/data-table/data-table.tsx create mode 100644 src/components/data-table/index.tsx create mode 100644 src/components/pro-table/index.tsx create mode 100644 src/components/pro-table/types.ts delete mode 100644 src/components/team-switcher.tsx create mode 100644 src/hooks/query/use-tasks.ts rename src/{pages/(admin)/(with-layout)/list/data/data.tsx => lib/data-dictionary.ts} (100%) delete mode 100644 src/pages/(admin)/(with-layout)/list/components/columns.tsx delete mode 100644 src/pages/(admin)/(with-layout)/list/components/data-table-pagination.tsx delete mode 100644 src/pages/(admin)/(with-layout)/list/components/data-table-row-actions.tsx delete mode 100644 src/pages/(admin)/(with-layout)/list/components/data-table-toolbar.tsx delete mode 100644 src/pages/(admin)/(with-layout)/list/components/data-table.tsx delete mode 100644 src/pages/(admin)/(with-layout)/list/components/user-nav.tsx delete mode 100644 src/pages/(admin)/(with-layout)/list/components/view-user.tsx create mode 100644 src/pages/(admin)/(with-layout)/list/data-table/components/view-user.tsx rename src/pages/(admin)/(with-layout)/list/{basic-list.tsx => data-table/index.tsx} (52%) delete mode 100755 src/pages/(admin)/(with-layout)/list/data/seed.ts delete mode 100644 src/pages/(admin)/(with-layout)/list/data/tasks.json create mode 100644 src/pages/(admin)/(with-layout)/list/pro-table/index.tsx delete mode 100644 src/pages/(admin)/(with-layout)/list/table-list.tsx rename src/pages/(admin)/(with-layout)/list/{ => table-list}/components/album-card.tsx (100%) create mode 100644 src/pages/(admin)/(with-layout)/list/table-list/index.tsx rename src/{pages/(admin)/(with-layout)/list/data/schema.ts => schema/task.ts} (52%) diff --git a/.storybook/ThemeChanger.tsx b/.storybook/ThemeChanger.tsx new file mode 100644 index 0000000..47595f3 --- /dev/null +++ b/.storybook/ThemeChanger.tsx @@ -0,0 +1,43 @@ +import { addons } from "@storybook/manager-api" +import { Moon, Sun } from "lucide-react" +import * as React from "react" + +import { useTheme } from "../src/components/theme/theme-provider" +import { Button } from "../src/components/ui/button" +import { darkTheme, lightTheme } from "./theme" + +export function ThemeChanger() { + const { theme, setTheme } = useTheme() + + React.useEffect(() => { + // 初始化时设置 Storybook 主题 + addons.setConfig({ + theme: theme === "dark" ? darkTheme : lightTheme, + }) + }, []) + + const toggleTheme = React.useCallback(() => { + const newTheme = theme === "dark" ? "light" : "dark" + setTheme(newTheme) + + // 更新 Storybook 管理界面主题 + addons.setConfig({ + theme: newTheme === "dark" ? darkTheme : lightTheme, + }) + }, [theme, setTheme]) + + return ( + + ) +} diff --git a/.storybook/main.ts b/.storybook/main.ts index 032058e..db86e2e 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -8,10 +8,13 @@ const config: StorybookConfig = { "@storybook/addon-essentials", "@chromatic-com/storybook", "@storybook/addon-interactions", + "storybook-dark-mode", ], framework: { name: "@storybook/react-vite", options: {}, }, + docs: {}, } + export default config diff --git a/.storybook/manager.ts b/.storybook/manager.ts index 0ac17cf..8da4553 100644 --- a/.storybook/manager.ts +++ b/.storybook/manager.ts @@ -1,6 +1,9 @@ import { addons } from "@storybook/manager-api" import { themes } from "@storybook/theming" +// 获取系统主题偏好 +const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches + addons.setConfig({ - theme: themes.dark, + theme: prefersDark ? themes.dark : themes.light, }) diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index 29dfbb9..0589705 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -1,8 +1,11 @@ import "../src/styles/index.css" import type { Preview } from "@storybook/react" +import { themes } from "@storybook/theming" import * as React from "react" +import { ThemeProvider } from "../src/components/theme/theme-provider" +import { ThemeSwitcher } from "../src/components/theme/theme-switcher" import { RootProviders } from "../src/providers/root-providers" const preview: Preview = { @@ -13,15 +16,40 @@ const preview: Preview = { date: /Date$/i, }, }, + backgrounds: { + disable: true, + grid: { + disable: true, + }, + }, + layout: "padded", + darkMode: { + current: "light", + dark: { ...themes.dark }, + light: { ...themes.light }, + darkClass: "dark", + lightClass: "light", + classTarget: "html", + stylePreview: true, + }, }, decorators: [ - (Story) => ( -
- - - -
- ), + (Story) => { + return ( + +
+ +
+ +
+
+ +
+
+
+
+ ) + }, ], } diff --git a/.storybook/theme.ts b/.storybook/theme.ts new file mode 100644 index 0000000..0eef223 --- /dev/null +++ b/.storybook/theme.ts @@ -0,0 +1,63 @@ +import { create } from "@storybook/theming/create" + +export const lightTheme = create({ + base: "light", + brandTitle: "My Storybook", + brandUrl: "/", + + // Colors + colorPrimary: "#0099FF", + colorSecondary: "#0099FF", + + // UI + appBg: "#F6F9FC", + appContentBg: "#FFFFFF", + appBorderColor: "rgba(0,0,0,.1)", + appBorderRadius: 4, + + // Text colors + textColor: "#333333", + textInverseColor: "#FFFFFF", + + // Toolbar default and active colors + barTextColor: "#999999", + barSelectedColor: "#0099FF", + barBg: "#FFFFFF", + + // Form colors + inputBg: "#FFFFFF", + inputBorder: "rgba(0,0,0,.1)", + inputTextColor: "#333333", + inputBorderRadius: 4, +}) + +export const darkTheme = create({ + base: "dark", + brandTitle: "My Storybook", + brandUrl: "/", + + // Colors + colorPrimary: "#0099FF", + colorSecondary: "#0099FF", + + // UI + appBg: "#1b1b1b", + appContentBg: "#262626", + appBorderColor: "rgba(255,255,255,.1)", + appBorderRadius: 4, + + // Text colors + textColor: "#FFFFFF", + textInverseColor: "#333333", + + // Toolbar default and active colors + barTextColor: "#999999", + barSelectedColor: "#0099FF", + barBg: "#1b1b1b", + + // Form colors + inputBg: "#333333", + inputBorder: "rgba(255,255,255,.1)", + inputTextColor: "#FFFFFF", + inputBorderRadius: 4, +}) diff --git a/.vscode/settings.json b/.vscode/settings.json index bfcdd11..c1fa65a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -53,5 +53,7 @@ "i18n-ally.namespace": true, "i18n-ally.keystyle": "nested", "i18n-ally.localesPaths": "locales", - "i18n-ally.displayLanguage": "zh-CN" + "i18n-ally.displayLanguage": "zh-CN", + "typescript.tsdk": "node_modules/typescript/lib", + "cSpell.words": ["autodocs", "hookform", "lucide", "ofetch", "tanstack"] } diff --git a/locales/en/navigation.json b/locales/en/navigation.json index 3bb5dde..b687876 100644 --- a/locales/en/navigation.json +++ b/locales/en/navigation.json @@ -16,8 +16,9 @@ "basic_form": "Basic Form", "step_form": "Step Form", "advanced_form": "Advanced Form", - "basic_list": "Basic List", + "data_table": "Data Table", "table_list": "Table List", + "pro_table": "Pro Table", "card_list": "Card List", "area_chart": "Area Chart", "bar_chart": "Bar Chart", diff --git a/locales/zh-CN/navigation.json b/locales/zh-CN/navigation.json index 2e39d9f..fc9f343 100644 --- a/locales/zh-CN/navigation.json +++ b/locales/zh-CN/navigation.json @@ -16,8 +16,9 @@ "basic_form": "基本表单", "step_form": "步骤表单", "advanced_form": "高级表单", - "basic_list": "基本列表", + "data_table": "数据表格", "table_list": "表格列表", + "pro_table": "高级表格", "card_list": "卡片列表", "area_chart": "面积图", "bar_chart": "柱状图", diff --git a/package.json b/package.json index 5e74bf1..dd16f52 100644 --- a/package.json +++ b/package.json @@ -91,26 +91,27 @@ "rehype-raw": "^7.0.0", "remark-gfm": "^4.0.0", "sonner": "^1.6.1", + "storybook-dark-mode": "^4.0.2", "tailwind-merge": "^2.5.4", "tailwindcss-animate": "^1.0.7", "vaul": "^0.9.9", "zod": "^3.23.8" }, "devDependencies": { - "@chromatic-com/storybook": "^1.9.0", + "@chromatic-com/storybook": "^3.2.2", "@commitlint/cli": "^19.5.0", "@commitlint/config-conventional": "^19.5.0", "@faker-js/faker": "^8.4.1", - "@storybook/addon-essentials": "^8.4.1", - "@storybook/addon-interactions": "^8.4.1", - "@storybook/addon-links": "^8.4.1", - "@storybook/addon-onboarding": "^8.4.1", - "@storybook/blocks": "^8.4.1", - "@storybook/manager-api": "^8.4.1", - "@storybook/react": "^8.4.1", - "@storybook/react-vite": "^8.4.1", - "@storybook/test": "^8.4.1", - "@storybook/theming": "^8.4.1", + "@storybook/addon-essentials": "^8.4.2", + "@storybook/addon-interactions": "^8.4.2", + "@storybook/addon-links": "^8.4.2", + "@storybook/addon-onboarding": "^8.4.2", + "@storybook/blocks": "^8.4.2", + "@storybook/manager-api": "^8.4.2", + "@storybook/react": "^8.4.2", + "@storybook/react-vite": "^8.4.2", + "@storybook/test": "^8.4.2", + "@storybook/theming": "^8.4.2", "@t3-oss/env-core": "^0.11.1", "@tailwindcss/typography": "^0.5.15", "@tanstack/react-query-devtools": "^5.59.17", @@ -128,14 +129,14 @@ "click-to-react-component": "^1.1.0", "eslint": "^9.14.0", "eslint-config-hyoban": "^3.1.12", - "eslint-plugin-storybook": "^0.8.0", + "eslint-plugin-storybook": "^0.11.0", "jsdom": "^25.0.1", "lint-staged": "^15.2.10", "postcss": "^8.4.47", "release-it": "^17.10.0", "release-it-pnpm": "^4.6.3", "simple-git-hooks": "^2.11.1", - "storybook": "^8.4.1", + "storybook": "^8.4.2", "tailwindcss": "^3.4.14", "turbo": "^2.2.3", "typescript": "^5.6.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 97f67d8..ca1c984 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -185,6 +185,9 @@ importers: sonner: specifier: ^1.6.1 version: 1.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + storybook-dark-mode: + specifier: ^4.0.2 + version: 4.0.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.2) tailwind-merge: specifier: ^2.5.4 version: 2.5.4 @@ -199,8 +202,8 @@ importers: version: 3.23.8 devDependencies: '@chromatic-com/storybook': - specifier: ^1.9.0 - version: 1.9.0(react@18.3.1) + specifier: ^3.2.2 + version: 3.2.2(react@18.3.1)(storybook@8.4.2) '@commitlint/cli': specifier: ^19.5.0 version: 19.5.0(@types/node@20.17.5)(typescript@5.6.3) @@ -211,35 +214,35 @@ importers: specifier: ^8.4.1 version: 8.4.1 '@storybook/addon-essentials': - specifier: ^8.4.1 - version: 8.4.1(@types/react@18.3.12)(storybook@8.4.1) + specifier: ^8.4.2 + version: 8.4.2(@types/react@18.3.12)(storybook@8.4.2) '@storybook/addon-interactions': - specifier: ^8.4.1 - version: 8.4.1(storybook@8.4.1) + specifier: ^8.4.2 + version: 8.4.2(storybook@8.4.2) '@storybook/addon-links': - specifier: ^8.4.1 - version: 8.4.1(react@18.3.1)(storybook@8.4.1) + specifier: ^8.4.2 + version: 8.4.2(react@18.3.1)(storybook@8.4.2) '@storybook/addon-onboarding': - specifier: ^8.4.1 - version: 8.4.1(react@18.3.1)(storybook@8.4.1) + specifier: ^8.4.2 + version: 8.4.2(react@18.3.1)(storybook@8.4.2) '@storybook/blocks': - specifier: ^8.4.1 - version: 8.4.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.1) + specifier: ^8.4.2 + version: 8.4.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.2) '@storybook/manager-api': - specifier: ^8.4.1 - version: 8.4.1(storybook@8.4.1) + specifier: ^8.4.2 + version: 8.4.2(storybook@8.4.2) '@storybook/react': - specifier: ^8.4.1 - version: 8.4.1(@storybook/test@8.4.1(storybook@8.4.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.1)(typescript@5.6.3) + specifier: ^8.4.2 + version: 8.4.2(@storybook/test@8.4.2(storybook@8.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.2)(typescript@5.6.3) '@storybook/react-vite': - specifier: ^8.4.1 - version: 8.4.1(@storybook/test@8.4.1(storybook@8.4.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.21.1)(storybook@8.4.1)(typescript@5.6.3)(vite@5.4.10(@types/node@20.17.5)(lightningcss@1.25.1)(terser@5.31.6)) + specifier: ^8.4.2 + version: 8.4.2(@storybook/test@8.4.2(storybook@8.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.21.1)(storybook@8.4.2)(typescript@5.6.3)(vite@5.4.10(@types/node@20.17.5)(lightningcss@1.25.1)(terser@5.31.6)) '@storybook/test': - specifier: ^8.4.1 - version: 8.4.1(storybook@8.4.1) + specifier: ^8.4.2 + version: 8.4.2(storybook@8.4.2) '@storybook/theming': - specifier: ^8.4.1 - version: 8.4.1(storybook@8.4.1) + specifier: ^8.4.2 + version: 8.4.2(storybook@8.4.2) '@t3-oss/env-core': specifier: ^0.11.1 version: 0.11.1(typescript@5.6.3)(zod@3.23.8) @@ -292,8 +295,8 @@ importers: specifier: ^3.1.12 version: 3.1.12(@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3))(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3))(eslint@9.14.0(jiti@1.21.6))(tailwindcss@3.4.14)(typescript@5.6.3) eslint-plugin-storybook: - specifier: ^0.8.0 - version: 0.8.0(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3) + specifier: ^0.11.0 + version: 0.11.0(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3) jsdom: specifier: ^25.0.1 version: 25.0.1 @@ -313,8 +316,8 @@ importers: specifier: ^2.11.1 version: 2.11.1 storybook: - specifier: ^8.4.1 - version: 8.4.1 + specifier: ^8.4.2 + version: 8.4.2 tailwindcss: specifier: ^3.4.14 version: 3.4.14 @@ -554,9 +557,11 @@ packages: '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} - '@chromatic-com/storybook@1.9.0': - resolution: {integrity: sha512-vYQ+TcfktEE3GHnLZXHCzXF/sN9dw+KivH8a5cmPyd9YtQs7fZtHrEgsIjWpYycXiweKMo1Lm1RZsjxk8DH3rA==} + '@chromatic-com/storybook@3.2.2': + resolution: {integrity: sha512-xmXt/GW0hAPbzNTrxYuVo43Adrtjue4DeVrsoIIEeJdGaPNNeNf+DHMlJKOBdlHmCnFUoe9R/0mLM9zUp5bKWw==} engines: {node: '>=16.0.0', yarn: '>=1.22.18'} + peerDependencies: + storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 '@commitlint/cli@19.5.0': resolution: {integrity: sha512-gaGqSliGwB86MDmAAKAtV9SV1SHdmN8pnGq4EJU4+hLisQ7IFfx4jvU4s+pk6tl0+9bv6yT+CaZkufOinkSJIQ==} @@ -1977,91 +1982,91 @@ packages: resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} engines: {node: '>=18'} - '@storybook/addon-actions@8.4.1': - resolution: {integrity: sha512-D6KohTIA4JCHNol1X7Whp4LpOVU4cS5FfyOorwYo/WIzpHrUYc4Pw/+ex6DOmU/kgrk14mr8d9obVehKW7iNtA==} + '@storybook/addon-actions@8.4.2': + resolution: {integrity: sha512-+hA200XN5aeA4T3jq8IifQq6Y+9FyNQ0Q+blM1L0Tl7WLzBc7B1kHQnKvhSj5pvMSBWc/Q/kY7Ev5t9gdOu13g==} peerDependencies: - storybook: ^8.4.1 + storybook: ^8.4.2 - '@storybook/addon-backgrounds@8.4.1': - resolution: {integrity: sha512-DIT1E9R9Sds8KTC+0m2X5cVa8hTNcKY1XKYTI9QdzQvdZzOt+K93AJqq2x8k5glingqUVpB6v2fSDmCUXp4+4g==} + '@storybook/addon-backgrounds@8.4.2': + resolution: {integrity: sha512-s4uag5VKuk8q2MSnuNS7Sv+v1/mykzGPXe/zZRW2ammtkdHp8Uy78eQS2G0aiG02chXCX+qQgWMyy5QItDcTFQ==} peerDependencies: - storybook: ^8.4.1 + storybook: ^8.4.2 - '@storybook/addon-controls@8.4.1': - resolution: {integrity: sha512-3ahbYdDx7iFUd4X1KelMSuPqVnladc0bH4m6DQZyN+wkRxdRlOD6iOGuOe2qi1Gv0b2VuVAt253i75tK/TPNLw==} + '@storybook/addon-controls@8.4.2': + resolution: {integrity: sha512-raCbHEj1xl4F3wKH6IdfEXNRaxKpY4QGhjSTE8Pte5iJSVhKG86taLqqRr+4dC7H1/LVMPU1XCGV4mkgDGtyxQ==} peerDependencies: - storybook: ^8.4.1 + storybook: ^8.4.2 - '@storybook/addon-docs@8.4.1': - resolution: {integrity: sha512-yPD/NssJf7pMJzaKvma02C6yX8ykPVnEjhRbNYcBNM8s8g/cT5JkROvIB+FOb4T81yhdfbGg9bGkpAXGX270IQ==} + '@storybook/addon-docs@8.4.2': + resolution: {integrity: sha512-jIpykha7hv2Inlrq31ZoYg2QhuCuvcO+Q+uvhT45RDTB+2US/fg3rJINKlw2Djq8RPPOXvty5W0yvE6CrWKhnQ==} peerDependencies: - storybook: ^8.4.1 + storybook: ^8.4.2 - '@storybook/addon-essentials@8.4.1': - resolution: {integrity: sha512-Hmb5fpVzQgyCacDtHeE7HJqIfolzeOnedsLyJVYVpKns/uOWXqpDuU8Fc0s3yTjr1QPIRKtbqV1STxoyXj2how==} + '@storybook/addon-essentials@8.4.2': + resolution: {integrity: sha512-+/vfPrXM/GWU3Kbrg92PepwAZr7lOeulTTYF4THK0CL3DfUUlkGNpBPLP5PtjCuIkVrTCjXiIEdVWk47d5m2+w==} peerDependencies: - storybook: ^8.4.1 + storybook: ^8.4.2 - '@storybook/addon-highlight@8.4.1': - resolution: {integrity: sha512-BBkUd6+i7lUEWZwoJDlUIwrs7EXkk+EoREUi27iiA1Lilw+NNhoC3kcBmj3+MccjRyeMeIWAgYyXF5qeB2s/JQ==} + '@storybook/addon-highlight@8.4.2': + resolution: {integrity: sha512-vTtwp7nyJ09SXrsMnH+pukCjHjRMjQXgHZHxvbrv09uoH8ldQMv9B7u+X+9Wcy/jYSKFz/ng7pWo4b4a2oXHkg==} peerDependencies: - storybook: ^8.4.1 + storybook: ^8.4.2 - '@storybook/addon-interactions@8.4.1': - resolution: {integrity: sha512-rMxKehtQogV6Scjb/oqMFM0Mwn8NJRuGFDRJE3TBijNSJ2HPJms+xXp8KVZJengadlsF5HFwQBbnZzIeFDQRLw==} + '@storybook/addon-interactions@8.4.2': + resolution: {integrity: sha512-+/NTENTApeOcONgFNQ6Olbk0GH3pTDG3w0eh00slCB+2agD1BcVKg8SSlHQV0lQF1cK3vWL/X3jeaxdFLYOjjg==} peerDependencies: - storybook: ^8.4.1 + storybook: ^8.4.2 - '@storybook/addon-links@8.4.1': - resolution: {integrity: sha512-wg83rNKo6mq5apV7f1qMn4q8xZ8wVx/42EEWxTOmnM37Q5kXltEBu+rUyBpPNDU8zBuXr/MRKIhK5h2k4WfWcg==} + '@storybook/addon-links@8.4.2': + resolution: {integrity: sha512-8nncReA/drR2cyAcUz484FIv+MXbyCQxYrA6yfWHthZfGu+vMIETvhh+eP4OpluVnxySoQ+hCVK/V8G2jcyAZg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.4.1 + storybook: ^8.4.2 peerDependenciesMeta: react: optional: true - '@storybook/addon-measure@8.4.1': - resolution: {integrity: sha512-Pg1ROj29hKt7grL/HmbIJ10WrkZf1Unx35SsP373bkPQ1ggYi9oxGqtfNchTF2zCb1xUpIikLYSJgkwdjqWxhA==} + '@storybook/addon-measure@8.4.2': + resolution: {integrity: sha512-z+j6xQwcUBSpgzl1XDU+xU4YYgLraLMljECW7NvRNyJ/PYixvol8R3wtzWbr+CBpxmvbXjEJCPlF+EjF9/mBWQ==} peerDependencies: - storybook: ^8.4.1 + storybook: ^8.4.2 - '@storybook/addon-onboarding@8.4.1': - resolution: {integrity: sha512-xcMCQ2HPvl8O/NHt2V5T1hDlzitRGI5ATSrfo7o7JjcsAgFNSNtcFn7YU8M5SIpHd5u4v24ubE/pMrsskpp/+Q==} + '@storybook/addon-onboarding@8.4.2': + resolution: {integrity: sha512-zWzOyRASnIPt2AcaEl1KhI+aOaKDuoIcNB7u1GoABj0YM+V9d6o3lvcsmOAQG5pgwgFyqyOnLwpTfvRSEyzGFA==} peerDependencies: - storybook: ^8.4.1 + storybook: ^8.4.2 - '@storybook/addon-outline@8.4.1': - resolution: {integrity: sha512-LPZ0gGHfbru66Lkw1whnc3F/r1hfnoORBoF98Hp+cjH34gR4t8te6xq5qSiupRUULGdSLdBRs/4EGRBeELfVjQ==} + '@storybook/addon-outline@8.4.2': + resolution: {integrity: sha512-oTMlPEyT4CBqzcQbfemoJzJ6yzeRAmvrAx9ssaBcnQQRsKxo0D2Ri/Jmm6SNcR0yBHxYRkvIH+2phLw8aiflCQ==} peerDependencies: - storybook: ^8.4.1 + storybook: ^8.4.2 - '@storybook/addon-toolbars@8.4.1': - resolution: {integrity: sha512-yrzX6BFeJM5KFY0+ZAYfRax2QgWi2e5vF6yPz+MGIPr4nhHay0wTkOHhkBhIPBjQO9x0vqc7MS2EBDydCBWqlg==} + '@storybook/addon-toolbars@8.4.2': + resolution: {integrity: sha512-DidzW/NQS224niMJIjcJI2ls83emqygUcS9GYNGgdc5Xwro/TPgGYOXP2qnXgYUxXQTHbrxmIbHdEehxC7CcYQ==} peerDependencies: - storybook: ^8.4.1 + storybook: ^8.4.2 - '@storybook/addon-viewport@8.4.1': - resolution: {integrity: sha512-O6DcuUfXQTytjl7mj4ld4ZX9x2pUUWKUx1TxiuMuH0EKb612RyYcdpXpDQQwsIzLV/f2BOetk9jmO2/MymfbWQ==} + '@storybook/addon-viewport@8.4.2': + resolution: {integrity: sha512-qVQ2UaxCNsUSFHnAAAizNPIJ/QwfMg7p5bBdpYROTZXJe+bxVp0rFzZmQgHZ3/sn+lzE4ItM4QEfxkfQUWi1ag==} peerDependencies: - storybook: ^8.4.1 + storybook: ^8.4.2 - '@storybook/blocks@8.4.1': - resolution: {integrity: sha512-C4w5T5fhg0iONXozHQ1bh9im2Lr1BiY7Bj/9XoFjkc5YeCzxlMpujFA6Nmo4ToUFW90QbvKN7/QVhbrtY9O1Jg==} + '@storybook/blocks@8.4.2': + resolution: {integrity: sha512-yAAvmOWaD8gIrepOxCh/RxQqd/1xZIwd/V+gsvAhW/thawN+SpI+zK63gmcqAPLX84hJ3Dh5pegRk0SoHNuDVA==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.4.1 + storybook: ^8.4.2 peerDependenciesMeta: react: optional: true react-dom: optional: true - '@storybook/builder-vite@8.4.1': - resolution: {integrity: sha512-//v2S+/huVTZB1tqVH7hpGQtEaRUFyhVFuf4Qk+xPuJItE6sgY4z8Iaz5vONTNMUouei867CXQRPQr3gCa3QVQ==} + '@storybook/builder-vite@8.4.2': + resolution: {integrity: sha512-dO5FB5yH1C6tr/kBHn1frvGwp8Pt0D1apgXWkJ5ITWEUfh6WwOqX2fqsWsqaNwE7gP0qn0XgwCIEkI/4Mj55SA==} peerDependencies: - storybook: ^8.4.1 + storybook: ^8.4.2 vite: ^4.0.0 || ^5.0.0 '@storybook/components@8.4.1': @@ -2069,21 +2074,28 @@ packages: peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/core@8.4.1': - resolution: {integrity: sha512-q3Q4OFBj7MHHbIFYk/Beejlqv5j7CC3+VWhGcr0TK3SGvdCIZ7EliYuc5JIOgDlEPsnTIk+lkgWI4LAA9mLzSw==} + '@storybook/components@8.4.2': + resolution: {integrity: sha512-+W59oF7D73LAxLNmCfFrfs98cH9pyNHK9HlJoO5/lKbK4IdWhhOoqUR/AJ3ueksoLuetFat4DxyE8SN1H4Bvrg==} + peerDependencies: + storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 + + '@storybook/core-events@8.4.1': + resolution: {integrity: sha512-HlRHaC95h3NELnMedi3LqkUFY9kKpFhxGMLhSojZp9xK/2G2ghS/cr3tWRjdN32ONTzMTia4HaLhnBIM1SHQ/w==} + peerDependencies: + storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 + + '@storybook/core@8.4.2': + resolution: {integrity: sha512-hF8GWoUZTjwwuV5j4OLhMHZtZQL/NYcVUBReC2Ba06c8PkFIKqKZwATr1zKd301gQ5Qwcn9WgmZxJTMgdKQtOg==} peerDependencies: prettier: ^2 || ^3 peerDependenciesMeta: prettier: optional: true - '@storybook/csf-plugin@8.4.1': - resolution: {integrity: sha512-MdQkyq6mJ31lBsWCG9VNtx8O0oLSc5h4kvWDPyIP6Dn58K0Hv2z9qvxxSvtFjXA7ES9X+ivjorTke1kearifhg==} + '@storybook/csf-plugin@8.4.2': + resolution: {integrity: sha512-1f0t6W5xbC1sSAHHs3uXYPIQs2NXAEtIGqn6X9i3xbbub6hDS8PF8BIm7dOjQ8dZOPp7d9ltR64V5CoLlsOigA==} peerDependencies: - storybook: ^8.4.1 - - '@storybook/csf@0.0.1': - resolution: {integrity: sha512-USTLkZze5gkel8MYCujSRBVIrUQ3YPBrLOx7GNk/0wttvVtlzWXAq9eLbQ4p/NicGxP+3T7KPEMVV//g+yubpw==} + storybook: ^8.4.2 '@storybook/csf@0.1.11': resolution: {integrity: sha512-dHYFQH3mA+EtnCkHXzicbLgsvzYjcDJ1JWsogbItZogkPHgSJM/Wr71uMkcvw8v9mmCyP4NpXJuu6bPoVsOnzg==} @@ -2098,45 +2110,45 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - '@storybook/instrumenter@8.4.1': - resolution: {integrity: sha512-MgrhrLVW78jqno+Dh9h9Es06Ja3867TlrIUd8B3K3U1hsCFUQuFKXJBuGjNJF8U0QJY/aSIRnAgUBurHdVkPcw==} + '@storybook/instrumenter@8.4.2': + resolution: {integrity: sha512-gPYCZ/0O6gRLI3zmenu2N6QtKzxDZFdT2xf4RWcNUSZyp28RZkRCIgKFMt3fTmvE0yMzAjQyRSkBdrONjQ44HA==} peerDependencies: - storybook: ^8.4.1 + storybook: ^8.4.2 - '@storybook/manager-api@8.4.1': - resolution: {integrity: sha512-7hb2k4zsp6lREGZbQ85QOlsC8EIMZXuY9Pg12VUgaZd+LmLjLuaqtrxRz3SwIgIWsRpFun9AHO0X37DmYNGTSw==} + '@storybook/manager-api@8.4.2': + resolution: {integrity: sha512-rhPc4cgQDKDH8NUyRh/ZaJW7QIhR/PO5MNX4xc+vz71sM2nO7ONA/FrgLtCuu4SULdwilEPvGefYvLK0dE+Caw==} peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/preview-api@8.4.1': - resolution: {integrity: sha512-VdnESYfXCUasNtMd5s1Q8DPqMnAUdpROn8mE8UAD79Cy7DSNesI1q0SATuJqh5iYCT/+3Tpjfghsr2zC/mOh8w==} + '@storybook/preview-api@8.4.2': + resolution: {integrity: sha512-5X/xvIvDPaWJKUBCo5zVeBbbjkhnwcI2KPkuOgrHVRRhuQ5WqD0RYxVtOOFNyQXme7g0nNl5RFNgvT7qv9qGeg==} peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/react-dom-shim@8.4.1': - resolution: {integrity: sha512-XhvuqkpqtcUjDA8XE4osq140SCddX3VHMdj+IwlrMdoSl32CAya01TH5YDDx6YMy6hM/QQbyVKaemG7RB/oU4Q==} + '@storybook/react-dom-shim@8.4.2': + resolution: {integrity: sha512-FZVTM1f34FpGnf6e3MDIKkz05gmn8H9wEccvQAgr8pEFe8VWfrpVWeUrmatSAfgrCMNXYC1avDend8UX6IM8Fg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.4.1 + storybook: ^8.4.2 - '@storybook/react-vite@8.4.1': - resolution: {integrity: sha512-khMEfB/fs4eryu0Swnqj3XUnmUW+1cAORa2gBcnkp51uX93cx5+t6UJIquW5ELB45+tGM5wIW2vVUDE0BOl4eA==} + '@storybook/react-vite@8.4.2': + resolution: {integrity: sha512-OoXaW/V1AqLggMyniRcnuwmqQ1/OtSn38t31lePX4nDDeJhbGT3ZPldRrwvsLb0EaD3N27uoL+QbAOgsYJIhwA==} engines: {node: '>=18.0.0'} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.4.1 + storybook: ^8.4.2 vite: ^4.0.0 || ^5.0.0 - '@storybook/react@8.4.1': - resolution: {integrity: sha512-ZwszrzV47nWQEZ0X4LyNgv5OFq4iy/7LpmxW6IncIO7PWm70OWG2BVtKFNsNQx0LY+hOtllWZbvg06mPQzahFA==} + '@storybook/react@8.4.2': + resolution: {integrity: sha512-rO5/aVKBVhIKENcL7G8ud4QKC5OyWBPCkJIvY6XUHIuhErJy9/4pP+sZ85jypVwx5kq+EqCPF8AEOWjIxB/4/Q==} engines: {node: '>=18.0.0'} peerDependencies: - '@storybook/test': 8.4.1 + '@storybook/test': 8.4.2 react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.4.1 + storybook: ^8.4.2 typescript: '>= 4.2.x' peerDependenciesMeta: '@storybook/test': @@ -2144,13 +2156,13 @@ packages: typescript: optional: true - '@storybook/test@8.4.1': - resolution: {integrity: sha512-najn9kCxB8NaHykhD7Fv+Iq0FnxmIJYOJlYiI8NMgVLwaSDFf6gnqAY6HHVPRqkhej8TuT1L2e2RxKqzWEB+mA==} + '@storybook/test@8.4.2': + resolution: {integrity: sha512-MipTdboStv0hsqF2Sw8TZgP0YnxCcDYwxkTOd4hmRzev/7Brtvpi4pqjqh8k98ZCvhrCPAPVIoX5drk+oi3YUA==} peerDependencies: - storybook: ^8.4.1 + storybook: ^8.4.2 - '@storybook/theming@8.4.1': - resolution: {integrity: sha512-Sz24isryVFZaVahXkjgnCsMAQqQeeKg41AtLsldlYdesIo6fr5tc6/SkTUy+CYadK4Dkhqp+vVRDnwToYYRGhA==} + '@storybook/theming@8.4.2': + resolution: {integrity: sha512-9j4fnu5LcV+qSs1rdwf61Bt14lms0T1LOZkHxGNcS1c1oH+cPS+sxECh2lxtni+mvOAHUlBs9pKhVZzRPdWpvg==} peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 @@ -2463,10 +2475,6 @@ packages: typescript: optional: true - '@typescript-eslint/scope-manager@5.62.0': - resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/scope-manager@8.12.2': resolution: {integrity: sha512-gPLpLtrj9aMHOvxJkSbDBmbRuYdtiEbnvO25bCMza3DhMjTQw0u7Y1M+YR5JPbMsXXnSPuCf5hfq0nEkQDL/JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2484,10 +2492,6 @@ packages: typescript: optional: true - '@typescript-eslint/types@5.62.0': - resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/types@8.12.2': resolution: {integrity: sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2496,15 +2500,6 @@ packages: resolution: {integrity: sha512-LLt4BLHFwSfASHSF2K29SZ+ZCsbQOM+LuarPjRUuHm+Qd09hSe3GCeaQbcCr+Mik+0QFRmep/FyZBO6fJ64U3w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@5.62.0': - resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - '@typescript-eslint/typescript-estree@8.12.2': resolution: {integrity: sha512-mME5MDwGe30Pq9zKPvyduyU86PH7aixwqYR2grTglAdB+AN8xXQ1vFGpYaUSJ5o5P/5znsSBeNcs5g5/2aQwow==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2523,12 +2518,6 @@ packages: typescript: optional: true - '@typescript-eslint/utils@5.62.0': - resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - '@typescript-eslint/utils@8.12.2': resolution: {integrity: sha512-UTTuDIX3fkfAz6iSVa5rTuSfWIYZ6ATtEocQ/umkRSyC9O919lbZ8dcH7mysshrCdrAM03skJOEYaBugxN+M6A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2541,10 +2530,6 @@ packages: peerDependencies: eslint: ^8.57.0 || ^9.0.0 - '@typescript-eslint/visitor-keys@5.62.0': - resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/visitor-keys@8.12.2': resolution: {integrity: sha512-PChz8UaKQAVNHghsHcPyx1OMHoFRUEA7rJSK/mDhdq85bk+PLsUHUBqTQTFt18VJZbmxBovM65fezlheQRsSDA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2608,9 +2593,6 @@ packages: '@vitest/pretty-format@2.0.5': resolution: {integrity: sha512-h8k+1oWHfwTkyTkb9egzwNMfJAEx4veaPSnMeKbVSjp4euqGSbQlm5+6VHwTr7u4FJslVVsUG5nopCaAYdOmSQ==} - '@vitest/pretty-format@2.1.1': - resolution: {integrity: sha512-SjxPFOtuINDUW8/UkElJYQSFtnWX7tMksSGW0vfjxMneFqxVr8YJ979QpMbDW7g+BIiq88RAGDjf7en6rvLPPQ==} - '@vitest/pretty-format@2.1.4': resolution: {integrity: sha512-L95zIAkEuTDbUX1IsjRl+vyBSLh3PwLLgKpghl37aCK9Jvw0iP+wKwIFhfjdUtA2myLgjrG6VU6JCFLv8q/3Ww==} @@ -2637,9 +2619,6 @@ packages: '@vitest/utils@2.0.5': resolution: {integrity: sha512-d8HKbqIcya+GR67mkZbrzhS5kKhtp8dQLcmRZLGTscGVg7yImT82cIrhtn2L8+VujWcy6KZweApgNmPsTAO/UQ==} - '@vitest/utils@2.1.1': - resolution: {integrity: sha512-Y6Q9TsI+qJ2CC0ZKj6VBb+T8UPz593N113nnUykqwANqhgf3QkZeHFlusgKLTqrnVHbj/XDKZcDHol+dxVT+rQ==} - '@vitest/utils@2.1.4': resolution: {integrity: sha512-MXDnZn0Awl2S86PSNIim5PWXgIAx8CIkzu35mBdSApUip6RFOGXBCf3YFyeEu8n1IHk4bWD46DeYFu9mQlFIRg==} @@ -2996,10 +2975,6 @@ packages: ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} - chai@5.1.1: - resolution: {integrity: sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==} - engines: {node: '>=12'} - chai@5.1.2: resolution: {integrity: sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==} engines: {node: '>=12'} @@ -3056,8 +3031,8 @@ packages: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} - chromatic@11.7.1: - resolution: {integrity: sha512-LvgPimdQdnQB07ZDxLEC2KtxgYeqTw0X71GA7fi3zhgtKLxZcE+BSZ/5I9rrQp1V8ydmfElfw0ZwnUH4fVgUAQ==} + chromatic@11.18.0: + resolution: {integrity: sha512-3o9Frn1oIS1hFLsJxVH9yVJ1O7+TCYoyL7OZzUorL/DCYduhXr5LDSBfpUsp7EdCPb64ufkbyFzSRNbt/xy9kg==} hasBin: true peerDependencies: '@chromatic-com/cypress': ^0.*.* || ^1.0.0 @@ -3778,8 +3753,8 @@ packages: peerDependencies: eslint: '>=5.0.0' - eslint-plugin-storybook@0.8.0: - resolution: {integrity: sha512-CZeVO5EzmPY7qghO2t64oaFM+8FTaD4uzOEjHKp516exyTKo+skKAL9GI3QALS2BXhyALJjNtwbmr1XinGE8bA==} + eslint-plugin-storybook@0.11.0: + resolution: {integrity: sha512-MvPJgF+ORwgK04a1CY5itO4pwdAOFIRqczlNEHL62+4Ocvj1d61GWRqIdeX1BNCKno6fdPC6TksUHCZMGsq26g==} engines: {node: '>= 18'} peerDependencies: eslint: '>=6' @@ -3805,10 +3780,6 @@ packages: '@typescript-eslint/eslint-plugin': optional: true - eslint-scope@5.1.1: - resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} - engines: {node: '>=8.0.0'} - eslint-scope@8.2.0: resolution: {integrity: sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3852,10 +3823,6 @@ packages: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} - estraverse@4.3.0: - resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} - engines: {node: '>=4.0'} - estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} @@ -4134,10 +4101,6 @@ packages: resolution: {integrity: sha512-3LifW9M4joGZasyYPz2A1U74zbC/45fvpXUvO/9KbSa+VV0aGZarWkfdgKyR9sExNP0t0x0ss/UMJpNpcaTspw==} engines: {node: '>=8'} - globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} - globby@14.0.2: resolution: {integrity: sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==} engines: {node: '>=18'} @@ -5813,10 +5776,6 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - requireindex@1.2.0: - resolution: {integrity: sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==} - engines: {node: '>=0.10.5'} - resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -6049,8 +6008,11 @@ packages: resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} engines: {node: '>=18'} - storybook@8.4.1: - resolution: {integrity: sha512-0tfFIFghjho9FtnFoiJMoxhcs2iIdvEF81GTSVnTsDVJrYA84nB+FxN3UY1fT0BcQ8BFlbf+OhSjZL7ufqqWKA==} + storybook-dark-mode@4.0.2: + resolution: {integrity: sha512-zjcwwQ01R5t1VsakA6alc2JDIRVtavryW8J3E3eKLDIlAMcvsgtpxlelWkZs2cuNspk6Z10XzhQVrUWtYc3F0w==} + + storybook@8.4.2: + resolution: {integrity: sha512-GMCgyAulmLNrkUtDkCpFO4SB77YrpiIxq6e5tzaQdXEuaDu1mdNwOuP3VG7nE2FzxmqDvagSgriM68YW9iFaZA==} hasBin: true peerDependencies: prettier: ^2 || ^3 @@ -6230,10 +6192,6 @@ packages: resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} engines: {node: '>=14.0.0'} - tinyspy@3.0.0: - resolution: {integrity: sha512-q5nmENpTHgiPVd1cJDDc9cVoYN5x4vCvwT3FMilvKPKneCBZAxn2YWQjDF0UMcE9k0Cay1gBiDfTMU0g+mPMQA==} - engines: {node: '>=14.0.0'} - tinyspy@3.0.2: resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} engines: {node: '>=14.0.0'} @@ -6314,18 +6272,9 @@ packages: resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} engines: {node: '>=6'} - tslib@1.14.1: - resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - tslib@2.7.0: resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} - tsutils@3.21.0: - resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} - engines: {node: '>= 6'} - peerDependencies: - typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' - tsx@4.19.0: resolution: {integrity: sha512-bV30kM7bsLZKZIOCHeMNVMJ32/LuJzLVajkQI/qf92J2Qr08ueLQvW00PUZGiuLPP760UINwupgUj8qrSCPUKg==} engines: {node: '>=18.0.0'} @@ -7093,7 +7042,7 @@ snapshots: '@babel/parser': 7.25.6 '@babel/template': 7.25.0 '@babel/types': 7.25.6 - debug: 4.3.6 + debug: 4.3.7 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -7106,12 +7055,13 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} - '@chromatic-com/storybook@1.9.0(react@18.3.1)': + '@chromatic-com/storybook@3.2.2(react@18.3.1)(storybook@8.4.2)': dependencies: - chromatic: 11.7.1 + chromatic: 11.18.0 filesize: 10.1.4 jsonfile: 6.1.0 react-confetti: 6.1.0(react@18.3.1) + storybook: 8.4.2 strip-ansi: 7.1.0 transitivePeerDependencies: - '@chromatic-com/cypress' @@ -8549,132 +8499,140 @@ snapshots: '@sindresorhus/merge-streams@4.0.0': {} - '@storybook/addon-actions@8.4.1(storybook@8.4.1)': + '@storybook/addon-actions@8.4.2(storybook@8.4.2)': dependencies: '@storybook/global': 5.0.0 '@types/uuid': 9.0.8 dequal: 2.0.3 polished: 4.3.1 - storybook: 8.4.1 + storybook: 8.4.2 uuid: 9.0.1 - '@storybook/addon-backgrounds@8.4.1(storybook@8.4.1)': + '@storybook/addon-backgrounds@8.4.2(storybook@8.4.2)': dependencies: '@storybook/global': 5.0.0 memoizerific: 1.11.3 - storybook: 8.4.1 + storybook: 8.4.2 ts-dedent: 2.2.0 - '@storybook/addon-controls@8.4.1(storybook@8.4.1)': + '@storybook/addon-controls@8.4.2(storybook@8.4.2)': dependencies: '@storybook/global': 5.0.0 dequal: 2.0.3 - storybook: 8.4.1 + storybook: 8.4.2 ts-dedent: 2.2.0 - '@storybook/addon-docs@8.4.1(@types/react@18.3.12)(storybook@8.4.1)': + '@storybook/addon-docs@8.4.2(@types/react@18.3.12)(storybook@8.4.2)': dependencies: '@mdx-js/react': 3.0.1(@types/react@18.3.12)(react@18.3.1) - '@storybook/blocks': 8.4.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.1) - '@storybook/csf-plugin': 8.4.1(storybook@8.4.1) - '@storybook/react-dom-shim': 8.4.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.1) + '@storybook/blocks': 8.4.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.2) + '@storybook/csf-plugin': 8.4.2(storybook@8.4.2) + '@storybook/react-dom-shim': 8.4.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.2) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - storybook: 8.4.1 + storybook: 8.4.2 ts-dedent: 2.2.0 transitivePeerDependencies: - '@types/react' - '@storybook/addon-essentials@8.4.1(@types/react@18.3.12)(storybook@8.4.1)': - dependencies: - '@storybook/addon-actions': 8.4.1(storybook@8.4.1) - '@storybook/addon-backgrounds': 8.4.1(storybook@8.4.1) - '@storybook/addon-controls': 8.4.1(storybook@8.4.1) - '@storybook/addon-docs': 8.4.1(@types/react@18.3.12)(storybook@8.4.1) - '@storybook/addon-highlight': 8.4.1(storybook@8.4.1) - '@storybook/addon-measure': 8.4.1(storybook@8.4.1) - '@storybook/addon-outline': 8.4.1(storybook@8.4.1) - '@storybook/addon-toolbars': 8.4.1(storybook@8.4.1) - '@storybook/addon-viewport': 8.4.1(storybook@8.4.1) - storybook: 8.4.1 + '@storybook/addon-essentials@8.4.2(@types/react@18.3.12)(storybook@8.4.2)': + dependencies: + '@storybook/addon-actions': 8.4.2(storybook@8.4.2) + '@storybook/addon-backgrounds': 8.4.2(storybook@8.4.2) + '@storybook/addon-controls': 8.4.2(storybook@8.4.2) + '@storybook/addon-docs': 8.4.2(@types/react@18.3.12)(storybook@8.4.2) + '@storybook/addon-highlight': 8.4.2(storybook@8.4.2) + '@storybook/addon-measure': 8.4.2(storybook@8.4.2) + '@storybook/addon-outline': 8.4.2(storybook@8.4.2) + '@storybook/addon-toolbars': 8.4.2(storybook@8.4.2) + '@storybook/addon-viewport': 8.4.2(storybook@8.4.2) + storybook: 8.4.2 ts-dedent: 2.2.0 transitivePeerDependencies: - '@types/react' - '@storybook/addon-highlight@8.4.1(storybook@8.4.1)': + '@storybook/addon-highlight@8.4.2(storybook@8.4.2)': dependencies: '@storybook/global': 5.0.0 - storybook: 8.4.1 + storybook: 8.4.2 - '@storybook/addon-interactions@8.4.1(storybook@8.4.1)': + '@storybook/addon-interactions@8.4.2(storybook@8.4.2)': dependencies: '@storybook/global': 5.0.0 - '@storybook/instrumenter': 8.4.1(storybook@8.4.1) - '@storybook/test': 8.4.1(storybook@8.4.1) + '@storybook/instrumenter': 8.4.2(storybook@8.4.2) + '@storybook/test': 8.4.2(storybook@8.4.2) polished: 4.3.1 - storybook: 8.4.1 + storybook: 8.4.2 ts-dedent: 2.2.0 - '@storybook/addon-links@8.4.1(react@18.3.1)(storybook@8.4.1)': + '@storybook/addon-links@8.4.2(react@18.3.1)(storybook@8.4.2)': dependencies: '@storybook/csf': 0.1.11 '@storybook/global': 5.0.0 - storybook: 8.4.1 + storybook: 8.4.2 ts-dedent: 2.2.0 optionalDependencies: react: 18.3.1 - '@storybook/addon-measure@8.4.1(storybook@8.4.1)': + '@storybook/addon-measure@8.4.2(storybook@8.4.2)': dependencies: '@storybook/global': 5.0.0 - storybook: 8.4.1 + storybook: 8.4.2 tiny-invariant: 1.3.3 - '@storybook/addon-onboarding@8.4.1(react@18.3.1)(storybook@8.4.1)': + '@storybook/addon-onboarding@8.4.2(react@18.3.1)(storybook@8.4.2)': dependencies: react-confetti: 6.1.0(react@18.3.1) - storybook: 8.4.1 + storybook: 8.4.2 transitivePeerDependencies: - react - '@storybook/addon-outline@8.4.1(storybook@8.4.1)': + '@storybook/addon-outline@8.4.2(storybook@8.4.2)': dependencies: '@storybook/global': 5.0.0 - storybook: 8.4.1 + storybook: 8.4.2 ts-dedent: 2.2.0 - '@storybook/addon-toolbars@8.4.1(storybook@8.4.1)': + '@storybook/addon-toolbars@8.4.2(storybook@8.4.2)': dependencies: - storybook: 8.4.1 + storybook: 8.4.2 - '@storybook/addon-viewport@8.4.1(storybook@8.4.1)': + '@storybook/addon-viewport@8.4.2(storybook@8.4.2)': dependencies: memoizerific: 1.11.3 - storybook: 8.4.1 + storybook: 8.4.2 - '@storybook/blocks@8.4.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.1)': + '@storybook/blocks@8.4.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.2)': dependencies: '@storybook/csf': 0.1.11 '@storybook/icons': 1.2.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - storybook: 8.4.1 + storybook: 8.4.2 ts-dedent: 2.2.0 optionalDependencies: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@storybook/builder-vite@8.4.1(storybook@8.4.1)(vite@5.4.10(@types/node@20.17.5)(lightningcss@1.25.1)(terser@5.31.6))': + '@storybook/builder-vite@8.4.2(storybook@8.4.2)(vite@5.4.10(@types/node@20.17.5)(lightningcss@1.25.1)(terser@5.31.6))': dependencies: - '@storybook/csf-plugin': 8.4.1(storybook@8.4.1) + '@storybook/csf-plugin': 8.4.2(storybook@8.4.2) browser-assert: 1.2.1 - storybook: 8.4.1 + storybook: 8.4.2 ts-dedent: 2.2.0 vite: 5.4.10(@types/node@20.17.5)(lightningcss@1.25.1)(terser@5.31.6) - '@storybook/components@8.4.1(storybook@8.4.1)': + '@storybook/components@8.4.1(storybook@8.4.2)': + dependencies: + storybook: 8.4.2 + + '@storybook/components@8.4.2(storybook@8.4.2)': + dependencies: + storybook: 8.4.2 + + '@storybook/core-events@8.4.1(storybook@8.4.2)': dependencies: - storybook: 8.4.1 + storybook: 8.4.2 - '@storybook/core@8.4.1': + '@storybook/core@8.4.2': dependencies: '@storybook/csf': 0.1.11 better-opn: 3.0.2 @@ -8692,15 +8650,11 @@ snapshots: - supports-color - utf-8-validate - '@storybook/csf-plugin@8.4.1(storybook@8.4.1)': + '@storybook/csf-plugin@8.4.2(storybook@8.4.2)': dependencies: - storybook: 8.4.1 + storybook: 8.4.2 unplugin: 1.12.3 - '@storybook/csf@0.0.1': - dependencies: - lodash: 4.17.21 - '@storybook/csf@0.1.11': dependencies: type-fest: 2.19.0 @@ -8712,39 +8666,39 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@storybook/instrumenter@8.4.1(storybook@8.4.1)': + '@storybook/instrumenter@8.4.2(storybook@8.4.2)': dependencies: '@storybook/global': 5.0.0 - '@vitest/utils': 2.1.1 - storybook: 8.4.1 + '@vitest/utils': 2.1.4 + storybook: 8.4.2 - '@storybook/manager-api@8.4.1(storybook@8.4.1)': + '@storybook/manager-api@8.4.2(storybook@8.4.2)': dependencies: - storybook: 8.4.1 + storybook: 8.4.2 - '@storybook/preview-api@8.4.1(storybook@8.4.1)': + '@storybook/preview-api@8.4.2(storybook@8.4.2)': dependencies: - storybook: 8.4.1 + storybook: 8.4.2 - '@storybook/react-dom-shim@8.4.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.1)': + '@storybook/react-dom-shim@8.4.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.2)': dependencies: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - storybook: 8.4.1 + storybook: 8.4.2 - '@storybook/react-vite@8.4.1(@storybook/test@8.4.1(storybook@8.4.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.21.1)(storybook@8.4.1)(typescript@5.6.3)(vite@5.4.10(@types/node@20.17.5)(lightningcss@1.25.1)(terser@5.31.6))': + '@storybook/react-vite@8.4.2(@storybook/test@8.4.2(storybook@8.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.21.1)(storybook@8.4.2)(typescript@5.6.3)(vite@5.4.10(@types/node@20.17.5)(lightningcss@1.25.1)(terser@5.31.6))': dependencies: '@joshwooding/vite-plugin-react-docgen-typescript': 0.3.0(typescript@5.6.3)(vite@5.4.10(@types/node@20.17.5)(lightningcss@1.25.1)(terser@5.31.6)) '@rollup/pluginutils': 5.1.0(rollup@4.21.1) - '@storybook/builder-vite': 8.4.1(storybook@8.4.1)(vite@5.4.10(@types/node@20.17.5)(lightningcss@1.25.1)(terser@5.31.6)) - '@storybook/react': 8.4.1(@storybook/test@8.4.1(storybook@8.4.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.1)(typescript@5.6.3) + '@storybook/builder-vite': 8.4.2(storybook@8.4.2)(vite@5.4.10(@types/node@20.17.5)(lightningcss@1.25.1)(terser@5.31.6)) + '@storybook/react': 8.4.2(@storybook/test@8.4.2(storybook@8.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.2)(typescript@5.6.3) find-up: 5.0.0 - magic-string: 0.30.11 + magic-string: 0.30.12 react: 18.3.1 react-docgen: 7.0.3 react-dom: 18.3.1(react@18.3.1) resolve: 1.22.8 - storybook: 8.4.1 + storybook: 8.4.2 tsconfig-paths: 4.2.0 vite: 5.4.10(@types/node@20.17.5)(lightningcss@1.25.1)(terser@5.31.6) transitivePeerDependencies: @@ -8753,36 +8707,36 @@ snapshots: - supports-color - typescript - '@storybook/react@8.4.1(@storybook/test@8.4.1(storybook@8.4.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.1)(typescript@5.6.3)': + '@storybook/react@8.4.2(@storybook/test@8.4.2(storybook@8.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.2)(typescript@5.6.3)': dependencies: - '@storybook/components': 8.4.1(storybook@8.4.1) + '@storybook/components': 8.4.2(storybook@8.4.2) '@storybook/global': 5.0.0 - '@storybook/manager-api': 8.4.1(storybook@8.4.1) - '@storybook/preview-api': 8.4.1(storybook@8.4.1) - '@storybook/react-dom-shim': 8.4.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.1) - '@storybook/theming': 8.4.1(storybook@8.4.1) + '@storybook/manager-api': 8.4.2(storybook@8.4.2) + '@storybook/preview-api': 8.4.2(storybook@8.4.2) + '@storybook/react-dom-shim': 8.4.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.2) + '@storybook/theming': 8.4.2(storybook@8.4.2) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - storybook: 8.4.1 + storybook: 8.4.2 optionalDependencies: - '@storybook/test': 8.4.1(storybook@8.4.1) + '@storybook/test': 8.4.2(storybook@8.4.2) typescript: 5.6.3 - '@storybook/test@8.4.1(storybook@8.4.1)': + '@storybook/test@8.4.2(storybook@8.4.2)': dependencies: '@storybook/csf': 0.1.11 '@storybook/global': 5.0.0 - '@storybook/instrumenter': 8.4.1(storybook@8.4.1) + '@storybook/instrumenter': 8.4.2(storybook@8.4.2) '@testing-library/dom': 10.4.0 '@testing-library/jest-dom': 6.5.0 '@testing-library/user-event': 14.5.2(@testing-library/dom@10.4.0) '@vitest/expect': 2.0.5 '@vitest/spy': 2.0.5 - storybook: 8.4.1 + storybook: 8.4.2 - '@storybook/theming@8.4.1(storybook@8.4.1)': + '@storybook/theming@8.4.2(storybook@8.4.2)': dependencies: - storybook: 8.4.1 + storybook: 8.4.2 '@stylistic/eslint-plugin@2.10.1(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3)': dependencies: @@ -8991,7 +8945,7 @@ snapshots: '@types/estree-jsx@1.0.5': dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 '@types/estree@1.0.5': {} @@ -9093,11 +9047,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@5.62.0': - dependencies: - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/visitor-keys': 5.62.0 - '@typescript-eslint/scope-manager@8.12.2': dependencies: '@typescript-eslint/types': 8.12.2 @@ -9120,31 +9069,15 @@ snapshots: - eslint - supports-color - '@typescript-eslint/types@5.62.0': {} - '@typescript-eslint/types@8.12.2': {} '@typescript-eslint/types@8.7.0': {} - '@typescript-eslint/typescript-estree@5.62.0(typescript@5.6.3)': - dependencies: - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.3.6 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.6.3 - tsutils: 3.21.0(typescript@5.6.3) - optionalDependencies: - typescript: 5.6.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/typescript-estree@8.12.2(typescript@5.6.3)': dependencies: '@typescript-eslint/types': 8.12.2 '@typescript-eslint/visitor-keys': 8.12.2 - debug: 4.3.6 + debug: 4.3.7 fast-glob: 3.3.2 is-glob: 4.0.3 minimatch: 9.0.5 @@ -9159,7 +9092,7 @@ snapshots: dependencies: '@typescript-eslint/types': 8.7.0 '@typescript-eslint/visitor-keys': 8.7.0 - debug: 4.3.6 + debug: 4.3.7 fast-glob: 3.3.2 is-glob: 4.0.3 minimatch: 9.0.5 @@ -9170,21 +9103,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@5.62.0(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3)': - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.14.0(jiti@1.21.6)) - '@types/json-schema': 7.0.15 - '@types/semver': 7.5.8 - '@typescript-eslint/scope-manager': 5.62.0 - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.6.3) - eslint: 9.14.0(jiti@1.21.6) - eslint-scope: 5.1.1 - semver: 7.6.3 - transitivePeerDependencies: - - supports-color - - typescript - '@typescript-eslint/utils@8.12.2(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@9.14.0(jiti@1.21.6)) @@ -9207,11 +9125,6 @@ snapshots: - supports-color - typescript - '@typescript-eslint/visitor-keys@5.62.0': - dependencies: - '@typescript-eslint/types': 5.62.0 - eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@8.12.2': dependencies: '@typescript-eslint/types': 8.12.2 @@ -9246,7 +9159,7 @@ snapshots: '@typescript-eslint/utils': 8.12.2(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3) '@unocss/config': 0.63.6 '@unocss/core': 0.63.6 - magic-string: 0.30.11 + magic-string: 0.30.12 synckit: 0.9.1 transitivePeerDependencies: - eslint @@ -9288,7 +9201,7 @@ snapshots: dependencies: '@vitest/spy': 2.0.5 '@vitest/utils': 2.0.5 - chai: 5.1.1 + chai: 5.1.2 tinyrainbow: 1.2.0 '@vitest/expect@2.1.4': @@ -9310,10 +9223,6 @@ snapshots: dependencies: tinyrainbow: 1.2.0 - '@vitest/pretty-format@2.1.1': - dependencies: - tinyrainbow: 1.2.0 - '@vitest/pretty-format@2.1.4': dependencies: tinyrainbow: 1.2.0 @@ -9331,7 +9240,7 @@ snapshots: '@vitest/spy@2.0.5': dependencies: - tinyspy: 3.0.0 + tinyspy: 3.0.2 '@vitest/spy@2.1.4': dependencies: @@ -9359,13 +9268,7 @@ snapshots: dependencies: '@vitest/pretty-format': 2.0.5 estree-walker: 3.0.3 - loupe: 3.1.1 - tinyrainbow: 1.2.0 - - '@vitest/utils@2.1.1': - dependencies: - '@vitest/pretty-format': 2.1.1 - loupe: 3.1.1 + loupe: 3.1.2 tinyrainbow: 1.2.0 '@vitest/utils@2.1.4': @@ -9395,7 +9298,7 @@ snapshots: '@vue/compiler-ssr': 3.5.12 '@vue/shared': 3.5.12 estree-walker: 2.0.2 - magic-string: 0.30.11 + magic-string: 0.30.12 postcss: 8.4.47 source-map-js: 1.2.1 @@ -9764,14 +9667,6 @@ snapshots: ccount@2.0.1: {} - chai@5.1.1: - dependencies: - assertion-error: 2.0.1 - check-error: 2.1.1 - deep-eql: 5.0.2 - loupe: 3.1.1 - pathval: 2.0.0 - chai@5.1.2: dependencies: assertion-error: 2.0.1 @@ -9858,7 +9753,7 @@ snapshots: chownr@2.0.0: {} - chromatic@11.7.1: {} + chromatic@11.18.0: {} ci-info@4.0.0: {} @@ -10320,7 +10215,7 @@ snapshots: esbuild-register@3.6.0(esbuild@0.23.1): dependencies: - debug: 4.3.6 + debug: 4.3.7 esbuild: 0.23.1 transitivePeerDependencies: - supports-color @@ -10661,12 +10556,11 @@ snapshots: dependencies: eslint: 9.14.0(jiti@1.21.6) - eslint-plugin-storybook@0.8.0(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3): + eslint-plugin-storybook@0.11.0(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3): dependencies: - '@storybook/csf': 0.0.1 - '@typescript-eslint/utils': 5.62.0(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3) + '@storybook/csf': 0.1.11 + '@typescript-eslint/utils': 8.12.2(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3) eslint: 9.14.0(jiti@1.21.6) - requireindex: 1.2.0 ts-dedent: 2.2.0 transitivePeerDependencies: - supports-color @@ -10704,11 +10598,6 @@ snapshots: optionalDependencies: '@typescript-eslint/eslint-plugin': 8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3))(eslint@9.14.0(jiti@1.21.6))(typescript@5.6.3) - eslint-scope@5.1.1: - dependencies: - esrecurse: 4.3.0 - estraverse: 4.3.0 - eslint-scope@8.2.0: dependencies: esrecurse: 4.3.0 @@ -10782,8 +10671,6 @@ snapshots: dependencies: estraverse: 5.3.0 - estraverse@4.3.0: {} - estraverse@5.3.0: {} estree-util-is-identifier-name@3.0.0: {} @@ -11026,7 +10913,7 @@ snapshots: dependencies: basic-ftp: 5.0.5 data-uri-to-buffer: 6.0.2 - debug: 4.3.6 + debug: 4.3.7 fs-extra: 11.2.0 transitivePeerDependencies: - supports-color @@ -11111,15 +10998,6 @@ snapshots: merge2: 1.4.1 slash: 3.0.0 - globby@11.1.0: - dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.2 - ignore: 5.3.2 - merge2: 1.4.1 - slash: 3.0.0 - globby@14.0.2: dependencies: '@sindresorhus/merge-streams': 2.3.0 @@ -11342,7 +11220,7 @@ snapshots: importx@0.4.3: dependencies: bundle-require: 5.0.0(esbuild@0.23.1) - debug: 4.3.6 + debug: 4.3.7 esbuild: 0.23.1 jiti: 2.0.0-beta.2 jiti-v1: jiti@1.21.6 @@ -12219,7 +12097,7 @@ snapshots: micromark@4.0.0: dependencies: '@types/debug': 4.1.12 - debug: 4.3.6 + debug: 4.3.7 decode-named-character-reference: 1.0.2 devlop: 1.1.0 micromark-core-commonmark: 2.0.1 @@ -13095,8 +12973,6 @@ snapshots: require-from-string@2.0.2: {} - requireindex@1.2.0: {} - resolve-from@4.0.0: {} resolve-from@5.0.0: {} @@ -13325,9 +13201,24 @@ snapshots: stdin-discarder@0.2.2: {} - storybook@8.4.1: + storybook-dark-mode@4.0.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.2): dependencies: - '@storybook/core': 8.4.1 + '@storybook/components': 8.4.1(storybook@8.4.2) + '@storybook/core-events': 8.4.1(storybook@8.4.2) + '@storybook/global': 5.0.0 + '@storybook/icons': 1.2.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/manager-api': 8.4.2(storybook@8.4.2) + '@storybook/theming': 8.4.2(storybook@8.4.2) + fast-deep-equal: 3.1.3 + memoizerific: 1.11.3 + transitivePeerDependencies: + - react + - react-dom + - storybook + + storybook@8.4.2: + dependencies: + '@storybook/core': 8.4.2 transitivePeerDependencies: - bufferutil - supports-color @@ -13520,8 +13411,6 @@ snapshots: tinyrainbow@1.2.0: {} - tinyspy@3.0.0: {} - tinyspy@3.0.2: {} titleize@3.0.0: {} @@ -13581,15 +13470,8 @@ snapshots: minimist: 1.2.8 strip-bom: 3.0.0 - tslib@1.14.1: {} - tslib@2.7.0: {} - tsutils@3.21.0(typescript@5.6.3): - dependencies: - tslib: 1.14.1 - typescript: 5.6.3 - tsx@4.19.0: dependencies: esbuild: 0.23.1 @@ -13708,7 +13590,7 @@ snapshots: unplugin@1.12.3: dependencies: - acorn: 8.12.1 + acorn: 8.14.0 webpack-sources: 3.2.3 webpack-virtual-modules: 0.6.2 diff --git a/public/avatars/01.png b/public/avatars/01.png new file mode 100644 index 0000000000000000000000000000000000000000..c19010109235ce8258c1c95c1f4c3b216d3167a0 GIT binary patch literal 13920 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 literal 0 HcmV?d00001 diff --git a/public/avatars/02.png b/public/avatars/02.png new file mode 100644 index 0000000000000000000000000000000000000000..b2aae01dd3cefd574c5d07c1f4438068017512da GIT binary patch literal 15326 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 literal 0 HcmV?d00001 diff --git a/public/avatars/03.png b/public/avatars/03.png new file mode 100644 index 0000000000000000000000000000000000000000..f04b6b0b0610c62c64bc54b1890a9f62c09caff1 GIT binary patch literal 14526 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 literal 0 HcmV?d00001 diff --git a/public/avatars/05.png b/public/avatars/05.png new file mode 100644 index 0000000000000000000000000000000000000000..e73aabf6dbda30693bfc15e198337f71ac8586f5 GIT binary patch literal 14821 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 NL{3T>Rv~E`_&-Y~ZU6uP literal 0 HcmV?d00001 diff --git a/public/avatars/shadcn.jpg b/public/avatars/shadcn.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7d3b7a4dab848d8c6a7b289d6e8b6ca04896ce0c GIT binary patch literal 23707 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 VA { + table: Table | null + isLoading?: boolean + onRefresh?: () => void + pagination?: PaginationProps + data?: TData[] +} + +export const ProTableContext = React.createContext>({ + table: null, +}) + +export function useProTable() { + return React.useContext(ProTableContext) as ProTableContextValue +} diff --git a/src/pages/(admin)/(with-layout)/list/components/data-table-column-header.tsx b/src/components/data-table/data-table-column-header.tsx similarity index 100% rename from src/pages/(admin)/(with-layout)/list/components/data-table-column-header.tsx rename to src/components/data-table/data-table-column-header.tsx diff --git a/src/pages/(admin)/(with-layout)/list/components/data-table-faceted-filter.tsx b/src/components/data-table/data-table-faceted-filter.tsx similarity index 100% rename from src/pages/(admin)/(with-layout)/list/components/data-table-faceted-filter.tsx rename to src/components/data-table/data-table-faceted-filter.tsx diff --git a/src/components/data-table/data-table-pagination.stories.tsx b/src/components/data-table/data-table-pagination.stories.tsx new file mode 100644 index 0000000..8bc8d49 --- /dev/null +++ b/src/components/data-table/data-table-pagination.stories.tsx @@ -0,0 +1,92 @@ +import type { Meta, StoryObj } from "@storybook/react" +import { getCoreRowModel, useReactTable } from "@tanstack/react-table" +import * as React from "react" + +import { DataTablePagination } from "./data-table-pagination" + +// 创建一个包装组件来使用 Hook +function PaginationWrapper(props: Omit, "table">) { + // 模拟数据和列 + const data = React.useMemo(() => Array.from({ length: 100 }).fill(0).map((_, index) => ({ id: index })), []) + const columns = React.useMemo(() => [{ accessorKey: "id" }], []) + + const table = useReactTable({ + data, + columns, + getCoreRowModel: getCoreRowModel(), + pageCount: Math.ceil(data.length / (props.pagination?.pageSize || 10)), + state: { + pagination: { + pageIndex: props.pagination?.pageIndex || 0, + pageSize: props.pagination?.pageSize || 10, + }, + }, + manualPagination: true, + }) + + return +} + +const meta = { + title: "Components/ProTable/Pagination", + component: PaginationWrapper, + parameters: { + layout: "centered", + }, + tags: ["autodocs"], +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Default: Story = { + args: { + pagination: { + pageIndex: 0, + pageSize: 10, + total: 100, + }, + }, +} + +export const CustomPageSize: Story = { + args: { + pagination: { + pageIndex: 0, + pageSize: 20, + total: 100, + }, + }, +} + +export const MidPage: Story = { + args: { + pagination: { + pageIndex: 5, + pageSize: 10, + total: 100, + }, + }, +} + +export const LastPage: Story = { + args: { + pagination: { + pageIndex: 9, + pageSize: 10, + + total: 100, + }, + }, +} + +export const SmallDataSet: Story = { + args: { + pagination: { + pageIndex: 0, + pageSize: 10, + + total: 30, + }, + }, +} diff --git a/src/components/data-table/data-table-pagination.tsx b/src/components/data-table/data-table-pagination.tsx new file mode 100644 index 0000000..06c4e04 --- /dev/null +++ b/src/components/data-table/data-table-pagination.tsx @@ -0,0 +1,198 @@ +import { ChevronLeftIcon, ChevronRightIcon } from "@radix-ui/react-icons" +import type { PaginationState, Table } from "@tanstack/react-table" +import * as React from "react" + +import { Button } from "@/ui/button" +import { Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink } from "@/ui/pagination" +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/ui/select" + +import { DEFAULT_PAGE_INDEX, DEFAULT_PAGE_SIZE, DEFAULT_PAGINATION_STEP } from "./data-table-util" + +export interface PaginationProps { + pageIndex?: number + pageSize?: number + onPaginationChange?: (pagination: PaginationState) => void + total?: number + quickJump?: boolean +} +interface DataTablePaginationProps { + table: Table + pagination?: PaginationProps +} + +export function DataTablePagination({ table, pagination }: DataTablePaginationProps) { + const [paginationState, setPaginationState] = React.useState({ + pageIndex: pagination?.pageIndex ?? DEFAULT_PAGE_INDEX, + pageSize: pagination?.pageSize ?? DEFAULT_PAGE_SIZE, + }) + + // when change page size, reset page index to 0 + const handlePageSizeChange = (_pageSize: string) => { + const newPaginationState = { pageIndex: 0, pageSize: Number(_pageSize) } + setPaginationState(newPaginationState) + pagination?.onPaginationChange?.(newPaginationState) + } + const handlePageIndexChange = (_pageIndex: number) => { + const newPaginationState = { ...paginationState, pageIndex: _pageIndex } + setPaginationState(newPaginationState) + pagination?.onPaginationChange?.(newPaginationState) + } + const handlePreviousPage = () => { + table.previousPage() + const newPaginationState = { ...paginationState, pageIndex: paginationState.pageIndex - 1 } + setPaginationState(newPaginationState) + pagination?.onPaginationChange?.(newPaginationState) + } + const handleNextPage = () => { + table.nextPage() + const newPaginationState = { ...paginationState, pageIndex: paginationState.pageIndex + 1 } + setPaginationState(newPaginationState) + pagination?.onPaginationChange?.(newPaginationState) + } + return ( +
+ {table.getPageCount() > 1 && ( +
+
+ Page + {" "} + {table.getState().pagination.pageIndex + 1} + {" "} + of + {" "} + {table.getPageCount() ? table.getPageCount().toLocaleString() : "-"} +
+
+ + + + + + + {pagination?.quickJump && ( + <> + {(() => { + const currentPage = table.getState().pagination.pageIndex + const totalPages = table.getPageCount() + const visiblePages = [] + const addPage = (index: number) => { + visiblePages.push( + + { + handlePageIndexChange(index) + }} + isActive={currentPage === index} + > + {String(index + 1)} + + , + ) + } + + // Always show first page + addPage(0) + + if (totalPages <= 7) { + // If total pages are 7 or less, show all pages + for (let i = 1; i < totalPages; i++) { + addPage(i) + } + } else { + let startPage = Math.max(1, currentPage - 1) + let endPage = Math.min(totalPages - 2, currentPage + 1) + + // Adjust start and end page to always show 3 pages when possible + if (startPage === 1) { + endPage = Math.min(3, totalPages - 2) + } else if (endPage === totalPages - 2) { + startPage = Math.max(1, totalPages - 4) + } + + // Show ellipsis at the start if needed + if (startPage > 1) { + visiblePages.push( + handlePageIndexChange(Math.max(0, currentPage - DEFAULT_PAGINATION_STEP))} + />, + ) + } + + // Add visible pages + for (let i = startPage; i <= endPage; i++) { + addPage(i) + } + + // Show ellipsis at the end if needed + if (endPage < totalPages - 2) { + visiblePages.push( + { + handlePageIndexChange(Math.min(totalPages - 1, currentPage + DEFAULT_PAGINATION_STEP)) + }} + />, + ) + } + + // Always show last page + addPage(totalPages - 1) + } + + return visiblePages + })()} + + )} + + + + + + + + + +
+
+ )} +
+ ) +} diff --git a/src/components/data-table/data-table-search.tsx b/src/components/data-table/data-table-search.tsx new file mode 100644 index 0000000..9091808 --- /dev/null +++ b/src/components/data-table/data-table-search.tsx @@ -0,0 +1,164 @@ +import { zodResolver } from "@hookform/resolvers/zod" +import type { Table } from "@tanstack/react-table" +import { ChevronDown, ChevronUp } from "lucide-react" +import * as React from "react" +import { useForm } from "react-hook-form" +import * as z from "zod" + +import { Button } from "@/components/ui/button" +import { Form, FormControl, FormField, FormItem } from "@/components/ui/form" +import { Input } from "@/components/ui/input" + +import type { ColumnDef, SearchConfig, SearchType } from "./data-table-types" + +interface DataTableSearchProps { + table: Table + searchValues?: Record + onSearchChange?: (field: string, value: string) => void + onSubmit?: (value: Record) => void +} + +function getSearchPlaceholder(search: SearchType, columnName: string): string { + if (typeof search === "object" && !React.isValidElement(search)) { + return (search as SearchConfig).placeholder ?? `Search ${columnName}` + } + return `Search ${columnName}` +} + +type SearchSchemaType = z.ZodObject> + +const createSearchSchema = (columns: string[]): SearchSchemaType => { + const shape = columns.reduce>((acc, column) => { + acc[column] = z.string().optional().unwrap() + return acc + }, {}) + return z.object(shape) +} + +export function DataTableSearch({ + table, + searchValues, + onSubmit, +}: DataTableSearchProps) { + const [expanded, setExpanded] = React.useState(false) + const [searchSchema] = React.useState(() => + createSearchSchema( + table.getAllColumns() + .filter((column) => (column.columnDef as ColumnDef).search) + .map((col) => col.id), + ), + ) + + const form = useForm>({ + resolver: zodResolver(searchSchema), + defaultValues: searchValues, + values: searchValues && Object.keys(searchSchema.shape).reduce((acc, key) => { + acc[key] = searchValues[key] || "" + return acc + }, {} as Record), + }) + + const searchableColumns = table.getAllColumns().filter((column) => { + const columnDef = column.columnDef as ColumnDef + return columnDef.search + }) + + const visibleColumns = expanded ? + searchableColumns : + searchableColumns.slice(0, 3) + + if (searchableColumns.length === 0) { + return null + } + const handleSubmit = (value: Record) => { + onSubmit?.(value) + } + + return ( +
+ +
+
+ +
+ {visibleColumns.map((column) => { + const columnDef = column.columnDef as ColumnDef + const columnName = String(columnDef.header || column.id) + + return ( +
+ + {columnName} + + ( + + + {typeof columnDef.search === "object" && + (columnDef?.search as SearchConfig)?.render ? ( + (columnDef?.search as SearchConfig).render?.({ + value: field.value || "", + onChange: field.onChange, + placeholder: getSearchPlaceholder(columnDef.search, columnName), + }) + ) : ( + + )} + + + )} + /> + +
+ ) + })} +
+ +
+ {searchableColumns.length > 3 && ( + + )} + + +
+
+
+
+ + ) +} diff --git a/src/components/data-table/data-table-skeleton.stories.tsx b/src/components/data-table/data-table-skeleton.stories.tsx new file mode 100644 index 0000000..eae6bf7 --- /dev/null +++ b/src/components/data-table/data-table-skeleton.stories.tsx @@ -0,0 +1,67 @@ +import type { Meta, StoryObj } from "@storybook/react" + +import { Table, TableBody } from "@/components/ui/table" + +import { DataTableSkeleton } from "./data-table-skeleton" + +const meta = { + title: "Components/ProTable/Loading", + component: DataTableSkeleton, + parameters: { + layout: "padded", + viewport: { + defaultViewport: "desktop", + }, + }, + decorators: [ + (Story) => ( +
+ + + + +
+
+ ), + ], + tags: ["autodocs"], +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Default: Story = { + args: { + pagination: { + pageSize: 10, + }, + columns: 6, + }, +} + +export const LongList: Story = { + args: { + pagination: { + pageSize: 20, + }, + columns: 6, + }, +} + +export const ShortList: Story = { + args: { + pagination: { + pageSize: 5, + }, + columns: 4, + }, +} + +export const ManyColumns: Story = { + args: { + pagination: { + pageSize: 10, + }, + columns: 10, + }, +} diff --git a/src/components/data-table/data-table-skeleton.tsx b/src/components/data-table/data-table-skeleton.tsx new file mode 100644 index 0000000..8039c60 --- /dev/null +++ b/src/components/data-table/data-table-skeleton.tsx @@ -0,0 +1,35 @@ +import { TableCell, TableRow } from "@/components/ui/table" + +import type { PaginationProps } from "./data-table-pagination" + +interface ProTableSkeletonProps { + pagination?: PaginationProps + columns?: number +} + +/** + * 表格骨架屏 + * @param pagination - 分页信息 + * @param columns - 列数,默认为4 + * @returns + */ +export function DataTableSkeleton({ + pagination, + columns = 10, +}: ProTableSkeletonProps) { + return ( + <> + {Array.from({ length: pagination?.pageSize ?? 10 }).map((_, rowIndex) => ( + // eslint-disable-next-line @eslint-react/no-array-index-key + + {Array.from({ length: columns }).map((_, colIndex) => ( + // eslint-disable-next-line @eslint-react/no-array-index-key + +
+ + ))} + + ))} + + ) +} diff --git a/src/components/data-table/data-table-toolbar.stories.tsx b/src/components/data-table/data-table-toolbar.stories.tsx new file mode 100644 index 0000000..45a6b5a --- /dev/null +++ b/src/components/data-table/data-table-toolbar.stories.tsx @@ -0,0 +1,57 @@ +import type { Meta, StoryObj } from "@storybook/react" +import { getCoreRowModel, useReactTable } from "@tanstack/react-table" + +import { Button } from "@/ui/button" + +import { DataTableToolbar } from "./data-table-toolbar" + +// 创建一个包装组件来使用 Hook +function ToolbarWrapper(props: Omit, "table">) { + const table = useReactTable({ + data: [], + columns: [], + getCoreRowModel: getCoreRowModel(), + }) + + return +} + +const meta = { + title: "Components/ProTable/Toolbar", + component: ToolbarWrapper, + parameters: { + layout: "centered", + }, + tags: ["autodocs"], +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Default: Story = { + args: { + isLoading: false, + }, +} + +export const WithCustomToolbar: Story = { + args: { + isLoading: false, + toolbar: ( + <> + + + + ), + }, +} + +export const Loading: Story = { + args: { + isLoading: true, + }, +} diff --git a/src/components/data-table/data-table-toolbar.tsx b/src/components/data-table/data-table-toolbar.tsx new file mode 100644 index 0000000..a59111d --- /dev/null +++ b/src/components/data-table/data-table-toolbar.tsx @@ -0,0 +1,53 @@ +import type { Table } from "@tanstack/react-table" +import { RefreshCcw } from "lucide-react" +import * as React from "react" + +import { cn } from "@/lib/utils" +import { Button } from "@/ui/button" + +import { DataTableViewOptions } from "./data-table-view-options" + +interface DataTableToolbarProps { + table: Table + onRefresh?: () => void + isLoading?: boolean + toolbar?: React.ReactNode +} + +export function DataTableToolbar({ + table, + onRefresh, + isLoading, + toolbar, +}: DataTableToolbarProps) { + const handleRefresh = async () => { + if (!onRefresh || isLoading) return + onRefresh() + } + + return ( +
+
+ {toolbar} +
+
+ + + + +
+
+ ) +} diff --git a/src/components/data-table/data-table-types.ts b/src/components/data-table/data-table-types.ts new file mode 100644 index 0000000..b60e355 --- /dev/null +++ b/src/components/data-table/data-table-types.ts @@ -0,0 +1,132 @@ +import type { + ColumnDef as TanstackColumnDef, + Table, + TableOptions, +} from "@tanstack/react-table" + +import type { PaginationProps } from "./data-table-pagination" + +/** + * Configuration options for the search functionality + * 搜索功能的配置选项 + * @interface SearchConfig + */ +export interface SearchConfig { + /** + * Placeholder text for the search input + * 搜索输入框的占位文本 + */ + placeholder?: string + /** + * Custom render function for the search input + * 自定义搜索输入框的渲染函数 + */ + render?: (props: { + value: string + onChange: (value: string) => void + placeholder?: string + }) => React.ReactNode +} + +/** + * Search type can be either a boolean or a SearchConfig object + * 搜索类型可以是布尔值或 SearchConfig 对象 + * @typedef {boolean | SearchConfig} SearchType + */ +export type SearchType = boolean | SearchConfig + +/** + * Common extensions for table columns + * 表格列的通用扩展属性 + * @interface ColumnExtensions + */ +interface ColumnExtensions { + /** + * Enable column search functionality + * 启用列搜索功能 + * @default false + */ + search?: SearchType + /** + * Column width in pixels + * 列宽度(像素) + * @default auto + */ + width?: number +} + +/** + * Extended column definition that combines TanStack's ColumnDef with custom properties + * 扩展的列定义,结合了 TanStack 的 ColumnDef 和自定义属性 + * @template TData The type of data in the table / 表格数据的类型 + * @template TValue The type of value in the column / 列值的类型 + */ +export type ColumnDef = + | (TanstackColumnDef & ColumnExtensions & { + /** + * Optional pin position. When undefined, id is optional + * 可选的固定位置。当未定义时,id 是可选的 + */ + pinned?: undefined + }) + | (TanstackColumnDef & ColumnExtensions & { + /** + * Pin position of the column. When set, id is required + * 列的固定位置。设置时,id 是必需的 + */ + pinned: "left" | "right" + /** + * Required column identifier when pinned is set + * 当设置 pinned 时,必需的列标识符 + */ + id: string + }) + +/** + * Search parameters type + * 搜索参数类型 + * @typedef {Record} SearchParams + */ +export type SearchParams = Record + +/** + * Props for the ProTable component + * ProTable 组件的属性 + * @interface DataTableProps + * @template TData The type of data in the table / 表格数据的类型 + * @template TValue The type of value in the columns / 列值的类型 + */ +export interface DataTableProps { + + /** + * Loading state of the table + * 表格的加载状态 + */ + isLoading: boolean + /** + * Optional toolbar component to render above the table + * 可选的工具栏组件,渲染在表格上方 + */ + toolbar?: React.ReactNode + /** + * Pagination configuration and callbacks + * 分页配置和回调 + */ + pagination?: PaginationProps + /** + * Initial state configuration for the table + * 表格的初始状态配置 + */ + initialState?: TableOptions["initialState"] + /** + * Callback function to refresh table data + * 刷新表格数据的回调函数 + */ + onRefresh?: () => void + /** + * Callback function when search is performed + * 执行搜索时的回调函数 + */ + onSearch?: (params: SearchParams) => void + table: Table +} diff --git a/src/components/data-table/data-table-util.ts b/src/components/data-table/data-table-util.ts new file mode 100644 index 0000000..cf654ee --- /dev/null +++ b/src/components/data-table/data-table-util.ts @@ -0,0 +1,27 @@ +import type { Column } from "@tanstack/react-table" +import type { CSSProperties } from "react" + +export const DEFAULT_PAGINATION_STEP = 3 +export const DEFAULT_PAGE_INDEX = 0 +export const DEFAULT_PAGE_SIZE = 10 +export function getCommonPinningStyles(column: Column): CSSProperties { + const isPinned = column.getIsPinned() + const isLastLeftPinnedColumn = + isPinned === "left" && column.getIsLastColumn("left") + const isFirstRightPinnedColumn = + isPinned === "right" && column.getIsFirstColumn("right") + + return { + boxShadow: isLastLeftPinnedColumn ? + "-4px 0 4px -4px hsl(var(--foreground) / 0.1) inset" : + isFirstRightPinnedColumn ? + "4px 0 4px -4px hsl(var(--foreground) / 0.1) inset" : + undefined, + backgroundColor: isPinned ? "hsl(var(--background))" : undefined, + left: isPinned === "left" ? `${column.getStart("left")}px` : undefined, + right: isPinned === "right" ? `${column.getAfter("right")}px` : undefined, + position: isPinned ? "sticky" : "relative", + width: column.getSize(), + zIndex: isPinned ? 1 : 0, + } +} diff --git a/src/components/data-table/data-table-view-options.stories.tsx b/src/components/data-table/data-table-view-options.stories.tsx new file mode 100644 index 0000000..a2eaf17 --- /dev/null +++ b/src/components/data-table/data-table-view-options.stories.tsx @@ -0,0 +1,188 @@ +import type { Meta, StoryObj } from "@storybook/react" +import type { VisibilityState } from "@tanstack/react-table" +import { getCoreRowModel, useReactTable } from "@tanstack/react-table" +import * as React from "react" + +import { DataTableViewOptions } from "./data-table-view-options" + +// 创建一个包装组件来使用 Hook +function ViewOptionsWrapper() { + const [columnVisibility, setColumnVisibility] = React.useState({}) + + // 模拟数据 + const data = React.useMemo( + () => [ + { + id: 1, + name: "John Doe", + email: "john@example.com", + role: "Admin", + status: "Active", + }, + { + id: 2, + name: "Jane Smith", + email: "jane@example.com", + role: "User", + status: "Inactive", + }, + ], + [], + ) + + // 模拟列配置 + const columns = React.useMemo( + () => [ + { accessorKey: "id", header: "ID" }, + { accessorKey: "name", header: "Name" }, + { accessorKey: "email", header: "Email" }, + { accessorKey: "role", header: "Role" }, + { accessorKey: "status", header: "Status" }, + ], + [], + ) + + const table = useReactTable({ + data, + columns, + getCoreRowModel: getCoreRowModel(), + state: { + columnVisibility, + }, + onColumnVisibilityChange: setColumnVisibility, + }) + + return ( +
+ +
+ + + + {table.getHeaderGroups().at(0)?.headers.map((header) => ( + + ))} + + + + {table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + ))} + + ))} + +
+ {header.column.columnDef.header?.toString()} +
+ {cell.getValue() as React.ReactNode} +
+
+
+ ) +} + +// 创建一个带有隐藏列的包装组件 +function ViewOptionsWrapperWithHidden() { + const [columnVisibility, setColumnVisibility] = React.useState({ + email: false, + role: false, + }) + + // 模拟数据 + const data = React.useMemo( + () => [ + { + id: 1, + name: "John Doe", + email: "john@example.com", + role: "Admin", + status: "Active", + }, + { + id: 2, + name: "Jane Smith", + email: "jane@example.com", + role: "User", + status: "Inactive", + }, + ], + [], + ) + + const columns = React.useMemo( + () => [ + { accessorKey: "id", header: "ID" }, + { accessorKey: "name", header: "Name" }, + { accessorKey: "email", header: "Email" }, + { accessorKey: "role", header: "Role" }, + { accessorKey: "status", header: "Status" }, + ], + [], + ) + + const table = useReactTable({ + data, + columns, + getCoreRowModel: getCoreRowModel(), + state: { + columnVisibility, + }, + onColumnVisibilityChange: setColumnVisibility, + }) + + return ( +
+ +
+ + + + {table.getHeaderGroups().at(0)?.headers.map((header) => ( + + ))} + + + + {table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + ))} + + ))} + +
+ {header.column.columnDef.header?.toString()} +
+ {cell.getValue() as React.ReactNode} +
+
+
+ ) +} + +const meta = { + title: "Components/ProTable/ViewOptions", + component: ViewOptionsWrapper, + parameters: { + layout: "centered", + }, + tags: ["autodocs"], +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Default: Story = {} + +export const WithHiddenColumns: Story = { + render: () => , +} diff --git a/src/pages/(admin)/(with-layout)/list/components/data-table-view-options.tsx b/src/components/data-table/data-table-view-options.tsx similarity index 86% rename from src/pages/(admin)/(with-layout)/list/components/data-table-view-options.tsx rename to src/components/data-table/data-table-view-options.tsx index 14b33e0..2ad0f35 100644 --- a/src/pages/(admin)/(with-layout)/list/components/data-table-view-options.tsx +++ b/src/components/data-table/data-table-view-options.tsx @@ -2,14 +2,14 @@ import { DropdownMenuTrigger } from "@radix-ui/react-dropdown-menu" import { MixerHorizontalIcon } from "@radix-ui/react-icons" import type { Table } from "@tanstack/react-table" -import { Button } from "@/components/ui/button" +import { Button } from "@/ui/button" import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuLabel, DropdownMenuSeparator, -} from "@/components/ui/dropdown-menu" +} from "@/ui/dropdown-menu" interface DataTableViewOptionsProps { table: Table @@ -24,7 +24,7 @@ export function DataTableViewOptions({ - - - - - - No team found. - {groups.map((group) => ( - - {group.teams.map((team) => ( - { - setSelectedTeam(team) - setOpen(false) - }} - className="text-sm" - > - - - SC - - {team.label} - - - ))} - - ))} - - - - - - { - setOpen(false) - setShowNewTeamDialog(true) - }} - > - - Create Team - - - - - - - - - - Create team - - Add a new team to manage products and customers. - - -
-
-
- - -
-
- - -
-
-
- - - - -
- - ) -} diff --git a/src/hooks/query/use-album.ts b/src/hooks/query/use-album.ts index bde854d..2eff507 100644 --- a/src/hooks/query/use-album.ts +++ b/src/hooks/query/use-album.ts @@ -1,13 +1,31 @@ import { useQuery } from "@tanstack/react-query" +import type { PaginationState } from "@tanstack/react-table" import { apiFetch } from "@/lib/api-fetch" import type { IAlbum } from "@/schema/album" -export function useAlbums() { - return useQuery({ - queryKey: ["albums"], - queryFn: async () => apiFetch<{ - list: IAlbum[] - }>("/api/albums"), +export function useAlbums(pagination?: PaginationState, searchParams?: Partial) { + const { pageIndex = 0, pageSize = 10 } = pagination || {} + const { data, isPending, isFetching, refetch } = useQuery({ + queryKey: ["albums", pageIndex, pageSize, ...Object.entries(searchParams || {})], + queryFn: async () => apiFetch("/api/albums", { + params: { + page: pageIndex, + pageSize, + ...searchParams, + }, + }), }) + + return { + isPending, + isFetching, + refetch, + data: { + list: data?.list || [], + total: data?.total || 0, + page: data?.page || 0, + pageSize: data?.pageSize || 0, + }, + } } diff --git a/src/hooks/query/use-tasks.ts b/src/hooks/query/use-tasks.ts new file mode 100644 index 0000000..be31272 --- /dev/null +++ b/src/hooks/query/use-tasks.ts @@ -0,0 +1,33 @@ +import { keepPreviousData, useQuery } from "@tanstack/react-query" +import type { PaginationState } from "@tanstack/react-table" + +import { apiFetch } from "@/lib/api-fetch" +import type { ITask } from "@/schema/task" + +export function useTasks(pagination?: PaginationState, searchParams?: Partial) { + const { pageIndex = 0, pageSize = 10 } = pagination || {} + const { data, isPending, isFetching, refetch } = useQuery({ + + queryKey: ["use-tasks", pageIndex, pageSize, ...Object.entries(searchParams || {})], + queryFn: () => apiFetch("/api/tasks", { + params: { + page: pageIndex, + pageSize, + ...searchParams, + }, + }), + placeholderData: keepPreviousData, + }) + + return { + isPending, + isFetching, + refetch, + data: { + list: data?.list || [], + total: data?.total || 0, + page: data?.page || 0, + pageSize: data?.pageSize || 0, + }, + } +} diff --git a/src/hooks/query/use-user.test.tsx b/src/hooks/query/use-user.test.tsx index caf1d15..ddf960b 100644 --- a/src/hooks/query/use-user.test.tsx +++ b/src/hooks/query/use-user.test.tsx @@ -122,7 +122,7 @@ describe("User Hooks", () => { expect(result.current.isPending).toBe(false) }) - expect(apiFetch).toHaveBeenCalledWith("/api/team-users", { + expect(apiFetch).toHaveBeenCalledWith("/api/users", { params: { page: pagination.pageIndex, pageSize: pagination.pageSize, diff --git a/src/hooks/query/use-user.ts b/src/hooks/query/use-user.ts index 43da5af..91b28f6 100644 --- a/src/hooks/query/use-user.ts +++ b/src/hooks/query/use-user.ts @@ -3,6 +3,7 @@ import { queryOptions, useMutation, useQuery, + useQueryClient, useSuspenseQuery, } from "@tanstack/react-query" import type { PaginationState } from "@tanstack/react-table" @@ -13,13 +14,15 @@ import type { ILoginForm, IUserProfile, IUsers } from "@/schema/user" export const queryUser = () => queryOptions({ queryKey: ["userInfo"], - queryFn: async () => apiFetch("/api/user"), + queryFn: async () => apiFetch("/api/users"), }) export const queryUserInfo = () => queryOptions({ queryKey: ["user-info"], - queryFn: async () => apiFetch(`/api/user/info`), + queryFn: async () => apiFetch<{ + data: IUserProfile + }>(`/api/users/info`), }) export function useUser() { @@ -49,18 +52,20 @@ export function useUserLogoutMutation() { }) } -export function useUsers(pagination: PaginationState) { - const { data, isPending } = useQuery({ - queryKey: ["users", pagination.pageIndex, pagination.pageSize], +export function useUsers(pagination?: PaginationState, searchParams?: Partial) { + const { pageIndex = 1, pageSize = 10 } = pagination || {} + const { data, isPending, isFetching, refetch } = useQuery({ + queryKey: ["users", pageIndex, pageSize, ...Object.entries(searchParams || {})], queryFn: async () => apiFetch<{ list: IUsers[] total: number page: number pageSize: number - }>("/api/team-users", { + }>("/api/users", { params: { - page: pagination.pageIndex, - pageSize: pagination.pageSize, + page: pageIndex, + pageSize, + ...searchParams, }, }), placeholderData: keepPreviousData, @@ -68,6 +73,8 @@ export function useUsers(pagination: PaginationState) { return { isPending, + isLoading: isFetching, + refetch, data: { list: data?.list || [], total: data?.total || 0, @@ -76,3 +83,19 @@ export function useUsers(pagination: PaginationState) { }, } } + +export function useUpdateUser() { + const queryClient = useQueryClient() + + return useMutation({ + mutationFn: async (user: IUsers) => + await apiFetch(`/api/${user.id}`, { + method: "PUT", + body: user, + }), + onSuccess: () => { + // 更新用户列表缓存 + queryClient.invalidateQueries({ queryKey: ["users"] }) + }, + }) +} diff --git a/src/hooks/query/user-memu.ts b/src/hooks/query/user-memu.ts index 7ca2086..706de50 100644 --- a/src/hooks/query/user-memu.ts +++ b/src/hooks/query/user-memu.ts @@ -97,10 +97,15 @@ export const menus: IMenu[] = [ icon: Table, children: [ { - title: "basic_list", + title: "data_table", label: "128", icon: List, - to: "/list/basic-list", + to: "/list/data-table", + }, + { + title: "pro_table", + icon: TableProperties, + to: "/list/pro-table", }, { title: "table_list", diff --git a/src/pages/(admin)/(with-layout)/list/data/data.tsx b/src/lib/data-dictionary.ts similarity index 100% rename from src/pages/(admin)/(with-layout)/list/data/data.tsx rename to src/lib/data-dictionary.ts diff --git a/src/pages/(admin)/(with-layout)/list/card-list.tsx b/src/pages/(admin)/(with-layout)/list/card-list.tsx index feb95e7..9ec2efb 100644 --- a/src/pages/(admin)/(with-layout)/list/card-list.tsx +++ b/src/pages/(admin)/(with-layout)/list/card-list.tsx @@ -1,6 +1,7 @@ import { useAlbums } from "@/hooks/query/use-album" +import type { IAlbum } from "@/schema/album" -import { AlbumCard } from "./components/album-card" +import { AlbumCard } from "./table-list/components/album-card" export function Component() { const { data } = useAlbums() @@ -8,7 +9,7 @@ export function Component() { return (
- {data?.list?.map((album) => ( + {data?.list?.map((album: IAlbum) => ( ))}
diff --git a/src/pages/(admin)/(with-layout)/list/components/columns.tsx b/src/pages/(admin)/(with-layout)/list/components/columns.tsx deleted file mode 100644 index 490796e..0000000 --- a/src/pages/(admin)/(with-layout)/list/components/columns.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import type { ColumnDef } from "@tanstack/react-table" - -import { Badge } from "@/components/ui/badge" -import { Checkbox } from "@/components/ui/checkbox" - -import { labels, priorities, statuses } from "../data/data" -import type { Task } from "../data/schema" -import { DataTableColumnHeader } from "./data-table-column-header" -import { DataTableRowActions } from "./data-table-row-actions" - -export const columns: ColumnDef[] = [ - { - id: "select", - header: ({ table }) => ( - table.toggleAllPageRowsSelected(!!value)} - aria-label="Select all" - className="translate-y-[2px]" - /> - ), - cell: ({ row }) => ( - row.toggleSelected(!!value)} - aria-label="Select row" - className="translate-y-[2px]" - /> - ), - enableSorting: false, - enableHiding: false, - }, - { - accessorKey: "id", - header: ({ column }) => ( - - ), - cell: ({ row }) =>
{row.getValue("id")}
, - enableSorting: false, - enableHiding: false, - }, - { - accessorKey: "title", - header: ({ column }) => ( - - ), - cell: ({ row }) => { - const label = labels.find((label) => label.value === row.original.label) - - return ( -
- {label && {label.label}} - - {row.getValue("title")} - -
- ) - }, - }, - { - accessorKey: "status", - header: ({ column }) => ( - - ), - cell: ({ row }) => { - const status = statuses.find( - (status) => status.value === row.getValue("status"), - ) - - if (!status) { - return null - } - - return ( -
- {status.icon && ( - - )} - {status.label} -
- ) - }, - filterFn: (row, id, value) => value.includes(row.getValue(id)), - }, - { - accessorKey: "priority", - header: ({ column }) => ( - - ), - cell: ({ row }) => { - const priority = priorities.find( - (priority) => priority.value === row.getValue("priority"), - ) - - if (!priority) { - return null - } - - return ( -
- {priority.icon && ( - - )} - {priority.label} -
- ) - }, - filterFn: (row, id, value) => value.includes(row.getValue(id)), - }, - { - id: "actions", - cell: ({ row }) => , - }, -] diff --git a/src/pages/(admin)/(with-layout)/list/components/data-table-pagination.tsx b/src/pages/(admin)/(with-layout)/list/components/data-table-pagination.tsx deleted file mode 100644 index 3081d87..0000000 --- a/src/pages/(admin)/(with-layout)/list/components/data-table-pagination.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import { - ChevronLeftIcon, - ChevronRightIcon, - DoubleArrowLeftIcon, - DoubleArrowRightIcon, -} from "@radix-ui/react-icons" -import type { Table } from "@tanstack/react-table" - -import { Button } from "@/components/ui/button" -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select" - -interface DataTablePaginationProps { - table: Table -} - -export function DataTablePagination({ - table, -}: DataTablePaginationProps) { - return ( -
-
- {table.getFilteredSelectedRowModel().rows.length} - {" "} - of - {" "} - {table.getFilteredRowModel().rows.length} - {" "} - row(s) selected. -
-
-
-

Rows per page

- -
-
- Page - {" "} - {table.getState().pagination.pageIndex + 1} - {" "} - of - {" "} - {table.getPageCount()} -
-
- - - - -
-
-
- ) -} diff --git a/src/pages/(admin)/(with-layout)/list/components/data-table-row-actions.tsx b/src/pages/(admin)/(with-layout)/list/components/data-table-row-actions.tsx deleted file mode 100644 index ad32446..0000000 --- a/src/pages/(admin)/(with-layout)/list/components/data-table-row-actions.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { DotsHorizontalIcon } from "@radix-ui/react-icons" -import type { Row } from "@tanstack/react-table" - -import { Button } from "@/components/ui/button" -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuRadioGroup, - DropdownMenuRadioItem, - DropdownMenuSeparator, - DropdownMenuShortcut, - DropdownMenuSub, - DropdownMenuSubContent, - DropdownMenuSubTrigger, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu" - -import { labels } from "../data/data" -import { taskSchema } from "../data/schema" - -interface DataTableRowActionsProps { - row: Row -} - -export function DataTableRowActions({ - row, -}: DataTableRowActionsProps) { - const task = taskSchema.parse(row.original) - - return ( - - - - - - Edit - Make a copy - Favorite - - - Labels - - - {labels.map((label) => ( - - {label.label} - - ))} - - - - - - Delete - ⌘⌫ - - - - ) -} diff --git a/src/pages/(admin)/(with-layout)/list/components/data-table-toolbar.tsx b/src/pages/(admin)/(with-layout)/list/components/data-table-toolbar.tsx deleted file mode 100644 index bdce41d..0000000 --- a/src/pages/(admin)/(with-layout)/list/components/data-table-toolbar.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import { Cross2Icon } from "@radix-ui/react-icons" -import type { Table } from "@tanstack/react-table" - -import { Button } from "@/components/ui/button" -import { Input } from "@/components/ui/input" - -import { priorities, statuses } from "../data/data" -import { DataTableFacetedFilter } from "./data-table-faceted-filter" -import { DataTableViewOptions } from "./data-table-view-options" - -interface DataTableToolbarProps { - table: Table -} - -export function DataTableToolbar({ - table, -}: DataTableToolbarProps) { - const isFiltered = table.getState().columnFilters.length > 0 - - return ( -
-
- - table.getColumn("title")?.setFilterValue(event.target.value)} - className="h-8 w-[150px] lg:w-[250px]" - /> - {table.getColumn("status") && ( - - )} - {table.getColumn("priority") && ( - - )} - {isFiltered && ( - - )} -
- -
- ) -} diff --git a/src/pages/(admin)/(with-layout)/list/components/data-table.tsx b/src/pages/(admin)/(with-layout)/list/components/data-table.tsx deleted file mode 100644 index eabb3df..0000000 --- a/src/pages/(admin)/(with-layout)/list/components/data-table.tsx +++ /dev/null @@ -1,124 +0,0 @@ -import type { - ColumnDef, - ColumnFiltersState, - SortingState, - VisibilityState, -} from "@tanstack/react-table" -import { - flexRender, - getCoreRowModel, - getFacetedRowModel, - getFacetedUniqueValues, - getFilteredRowModel, - getPaginationRowModel, - getSortedRowModel, - useReactTable, -} from "@tanstack/react-table" -import * as React from "react" - -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table" - -import { DataTablePagination } from "./data-table-pagination" -import { DataTableToolbar } from "./data-table-toolbar" - -interface DataTableProps { - columns: ColumnDef[] - data: TData[] -} - -export function DataTable({ - columns, - data, -}: DataTableProps) { - const [rowSelection, setRowSelection] = React.useState({}) - const [columnVisibility, setColumnVisibility] = - React.useState({}) - const [columnFilters, setColumnFilters] = React.useState( - [], - ) - const [sorting, setSorting] = React.useState([]) - - const table = useReactTable({ - data, - columns, - state: { - sorting, - columnVisibility, - rowSelection, - columnFilters, - }, - enableRowSelection: true, - onRowSelectionChange: setRowSelection, - onSortingChange: setSorting, - onColumnFiltersChange: setColumnFilters, - onColumnVisibilityChange: setColumnVisibility, - getCoreRowModel: getCoreRowModel(), - getFilteredRowModel: getFilteredRowModel(), - getPaginationRowModel: getPaginationRowModel(), - getSortedRowModel: getSortedRowModel(), - getFacetedRowModel: getFacetedRowModel(), - getFacetedUniqueValues: getFacetedUniqueValues(), - }) - - return ( -
- -
- - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => ( - - {header.isPlaceholder ? - null : - flexRender( - header.column.columnDef.header, - header.getContext(), - )} - - ))} - - ))} - - - {table.getRowModel().rows?.length ? ( - table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext(), - )} - - ))} - - )) - ) : ( - - - No results. - - - )} - -
-
- -
- ) -} diff --git a/src/pages/(admin)/(with-layout)/list/components/user-nav.tsx b/src/pages/(admin)/(with-layout)/list/components/user-nav.tsx deleted file mode 100644 index 21c57ee..0000000 --- a/src/pages/(admin)/(with-layout)/list/components/user-nav.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { - Avatar, - AvatarFallback, - AvatarImage, -} from "@/components/ui/avatar" -import { Button } from "@/components/ui/button" -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuGroup, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuShortcut, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu" - -export function UserNav() { - return ( - - - - - - -
-

shadcn

-

- m@example.com -

-
-
- - - - Profile - ⇧⌘P - - - Billing - ⌘B - - - Settings - ⌘S - - New Team - - - - Log out - ⇧⌘Q - -
-
- ) -} diff --git a/src/pages/(admin)/(with-layout)/list/components/view-user.tsx b/src/pages/(admin)/(with-layout)/list/components/view-user.tsx deleted file mode 100644 index 0ebc042..0000000 --- a/src/pages/(admin)/(with-layout)/list/components/view-user.tsx +++ /dev/null @@ -1,143 +0,0 @@ -import { zodResolver } from "@hookform/resolvers/zod" -import { useForm } from "react-hook-form" -import type { z } from "zod" - -import { Button } from "@/components/ui/button" -import { DropdownMenuItem } from "@/components/ui/dropdown-menu" -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, -} from "@/components/ui/form" -import { Input } from "@/components/ui/input" -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select" -import { - Sheet, - SheetClose, - SheetContent, - SheetDescription, - SheetFooter, - SheetHeader, - SheetTitle, - SheetTrigger, -} from "@/components/ui/sheet" -import { toast } from "@/components/ui/use-toast" -import type { IUsers } from "@/schema/user" -import { userRoles, userSchema } from "@/schema/user" - -export function ViewUser({ user }: { user: IUsers }) { - const form = useForm({ - resolver: zodResolver(userSchema), - defaultValues: user, - }) - - function onSubmit(values: z.infer) { - toast({ - title: "You submitted the following values:", - description: ( -
-          {JSON.stringify(values, null, 2)}
-        
- ), - }) - } - return ( - <> - - - { - event.preventDefault() - }} - > - View customer - - - - - View User - - View user details here. - - - -
- -
- ( - - Name - - - - - )} - /> - ( - - Email - - - - - )} - /> - ( - - Role - - - )} - /> - ( - - Avatar - - - - - )} - /> -
-
- - - - - - -
-
- - ) -} diff --git a/src/pages/(admin)/(with-layout)/list/data-table/components/view-user.tsx b/src/pages/(admin)/(with-layout)/list/data-table/components/view-user.tsx new file mode 100644 index 0000000..0bbccff --- /dev/null +++ b/src/pages/(admin)/(with-layout)/list/data-table/components/view-user.tsx @@ -0,0 +1,252 @@ +import { zodResolver } from "@hookform/resolvers/zod" +import { useRef, useState } from "react" +import { useForm } from "react-hook-form" +import type { z } from "zod" + +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" +import { Button } from "@/components/ui/button" +import { DropdownMenuItem } from "@/components/ui/dropdown-menu" +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form" +import { Input } from "@/components/ui/input" +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select" +import { + Sheet, + SheetClose, + SheetContent, + SheetDescription, + SheetFooter, + SheetHeader, + SheetTitle, + SheetTrigger, +} from "@/components/ui/sheet" +import { toast } from "@/components/ui/use-toast" +import { useUpdateUser } from "@/hooks/query/use-user" +import type { IUsers } from "@/schema/user" +import { userRoles, userSchema, userStatus } from "@/schema/user" + +export function ViewUser({ user }: { user: IUsers }) { + const [state, setState] = useState(false) + const sheetCloseRef = useRef(null) + const form = useForm({ + resolver: zodResolver(userSchema), + defaultValues: user, + }) + + const { mutate: updateUser, isPending } = useUpdateUser() + + function onSubmit(values: z.infer) { + updateUser(values, { + onSuccess: () => { + toast({ + title: "Success", + description: "User information updated successfully", + }) + }, + onError: (error) => { + toast({ + title: "Error", + description: error.message || "Failed to update user information", + variant: "destructive", + }) + }, + }) + } + + return ( + + + { + event.preventDefault() + setState(true) + }} + > + View customer + + + + + User Profile + + View and edit user information + + + +
+ +
+ +
+ + + + {user.name.charAt(0)} + + +
+

{user.name}

+

{user.email}

+
+
+ +
+ ( + + Name + + + + + + )} + /> + + ( + + Email + + + + + + )} + /> + + ( + + Role + + + + )} + /> + + ( + + Status + + + + )} + /> + + ( + + Avatar URL + + + + + + )} + /> + + ( + + Amount + + + + + + )} + /> + +
+
+

User ID

+

{user.id}

+
+
+

Member Since

+

+ {new Date(user.createdAt).toLocaleDateString()} +

+
+
+

Status

+

{user.status}

+
+
+

Total Spent

+

+ {new Intl.NumberFormat("en-US", { + style: "currency", + currency: "USD", + }).format(Number(user.amount))} +

+
+
+
+
+ + + + + + + +
+ +
+
+ ) +} diff --git a/src/pages/(admin)/(with-layout)/list/basic-list.tsx b/src/pages/(admin)/(with-layout)/list/data-table/index.tsx similarity index 52% rename from src/pages/(admin)/(with-layout)/list/basic-list.tsx rename to src/pages/(admin)/(with-layout)/list/data-table/index.tsx index 5a59654..39391a3 100644 --- a/src/pages/(admin)/(with-layout)/list/basic-list.tsx +++ b/src/pages/(admin)/(with-layout)/list/data-table/index.tsx @@ -1,6 +1,5 @@ import { CaretSortIcon, - ChevronDownIcon, DotsHorizontalIcon, } from "@radix-ui/react-icons" import type { @@ -20,6 +19,8 @@ import { } from "@tanstack/react-table" import * as React from "react" +import { DataTablePagination } from "@/components/data-table/data-table-pagination" +import { DataTableSearch } from "@/components/data-table/data-table-search" import { Empty } from "@/components/empty" import { Loading } from "@/components/loading" import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" @@ -27,29 +28,11 @@ import { Button } from "@/components/ui/button" import { Checkbox } from "@/components/ui/checkbox" import { DropdownMenu, - DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" -import { Input } from "@/components/ui/input" -import { - Pagination, - PaginationContent, - PaginationEllipsis, - PaginationItem, - PaginationLink, - PaginationNext, - PaginationPrevious, -} from "@/components/ui/pagination" -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select" import { Table, TableBody, @@ -160,6 +143,7 @@ const columns: ColumnDef[] = [ { id: "actions", enableHiding: false, + header: "Action", cell: ({ row }) => { const user = row.original return ( @@ -192,18 +176,25 @@ export function Component() { ) const [pagination, setPagination] = React.useState({ pageIndex: 0, - pageSize: 50, + pageSize: 10, }) const [columnVisibility, setColumnVisibility] = React.useState({}) const [rowSelection, setRowSelection] = React.useState({}) const { data: users, isPending } = useUsers(pagination) - const PAGINATION_STEP = 3 // You can easily change this value to adjust the pagination step - const table = useReactTable({ data: users.list, columns, + rowCount: users.total, + manualPagination: true, + state: { + sorting, + columnFilters, + columnVisibility, + rowSelection, + pagination, + }, onSortingChange: setSorting, onColumnFiltersChange: setColumnFilters, getCoreRowModel: getCoreRowModel(), @@ -213,54 +204,13 @@ export function Component() { onColumnVisibilityChange: setColumnVisibility, onRowSelectionChange: setRowSelection, onPaginationChange: setPagination, - manualPagination: true, - rowCount: users.total, - state: { - sorting, - columnFilters, - columnVisibility, - rowSelection, - pagination: { - pageIndex: users.page, // Set the starting page to 1 instead of 0 - pageSize: users.pageSize, - }, - }, }) return (
-
- - table.getColumn("email")?.setFilterValue(event.target.value)} - className="max-w-sm" - /> - - - - - - {table - .getAllColumns() - .filter((column) => column.getCanHide()) - .map((column) => ( - - column.toggleVisibility(!!value)} - > - {column.id} - - ))} - - -
+
@@ -311,121 +261,17 @@ export function Component() {
- - {table.getPageCount() > 1 && ( -
-
- Page - {" "} - {table.getState().pagination.pageIndex + 1} - {" "} - of - {" "} - {table.getPageCount() ? table.getPageCount().toLocaleString() : "-"} -
-
- - - - table.previousPage()} disabled={!table.getCanPreviousPage()} /> - - - {(() => { - const currentPage = table.getState().pagination.pageIndex - const totalPages = table.getPageCount() - const visiblePages = [] - const addPage = (index: number) => { - visiblePages.push( - - { - setPagination({ - ...pagination, - pageIndex: index, - }) - }} - isActive={currentPage === index} - > - - {String(index + 1)} - - , - ) - } - - // Always show first page - addPage(0) - - if (totalPages <= 7) { - // If total pages are 7 or less, show all pages - for (let i = 1; i < totalPages; i++) { - addPage(i) - } - } else { - let startPage = Math.max(1, currentPage - 1) - let endPage = Math.min(totalPages - 2, currentPage + 1) - - // Adjust start and end page to always show 3 pages when possible - if (startPage === 1) { - endPage = Math.min(3, totalPages - 2) - } else if (endPage === totalPages - 2) { - startPage = Math.max(1, totalPages - 4) - } - - // Show ellipsis at the start if needed - if (startPage > 1) { - visiblePages.push( - setPagination({ ...pagination, pageIndex: Math.max(0, currentPage - PAGINATION_STEP) })} - />, - ) - } - - // Add visible pages - for (let i = startPage; i <= endPage; i++) { - addPage(i) - } - - // Show ellipsis at the end if needed - if (endPage < totalPages - 2) { - visiblePages.push( - setPagination({ ...pagination, pageIndex: Math.min(totalPages - 1, currentPage + PAGINATION_STEP) })} - />, - ) - } - - // Always show last page - addPage(totalPages - 1) - } - - return visiblePages - })()} - - - table.nextPage()} disabled={!table.getCanNextPage()} /> - - - - - - -
-
- )} + { + setPagination(pagination) + }, + quickJump: true, + }} + />
) } diff --git a/src/pages/(admin)/(with-layout)/list/data/seed.ts b/src/pages/(admin)/(with-layout)/list/data/seed.ts deleted file mode 100755 index 9f77518..0000000 --- a/src/pages/(admin)/(with-layout)/list/data/seed.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { faker } from "@faker-js/faker" - -import { labels, priorities, statuses } from "./data" - -export const tasks = Array.from({ length: 100 }, () => ({ - id: `TASK-${faker.number.int({ min: 1000, max: 9999 })}`, - title: faker.hacker.phrase().replace(/^./, (letter) => letter.toUpperCase()), - status: faker.helpers.arrayElement(statuses).value, - label: faker.helpers.arrayElement(labels).value, - priority: faker.helpers.arrayElement(priorities).value, -})) diff --git a/src/pages/(admin)/(with-layout)/list/data/tasks.json b/src/pages/(admin)/(with-layout)/list/data/tasks.json deleted file mode 100644 index 2d10a4a..0000000 --- a/src/pages/(admin)/(with-layout)/list/data/tasks.json +++ /dev/null @@ -1,702 +0,0 @@ -[ - { - "id": "TASK-8782", - "title": "You can't compress the program without quantifying the open-source SSD pixel!", - "status": "in progress", - "label": "documentation", - "priority": "medium" - }, - { - "id": "TASK-7878", - "title": "Try to calculate the EXE feed, maybe it will index the multi-byte pixel!", - "status": "backlog", - "label": "documentation", - "priority": "medium" - }, - { - "id": "TASK-7839", - "title": "We need to bypass the neural TCP card!", - "status": "todo", - "label": "bug", - "priority": "high" - }, - { - "id": "TASK-5562", - "title": "The SAS interface is down, bypass the open-source pixel so we can back up the PNG bandwidth!", - "status": "backlog", - "label": "feature", - "priority": "medium" - }, - { - "id": "TASK-8686", - "title": "I'll parse the wireless SSL protocol, that should driver the API panel!", - "status": "canceled", - "label": "feature", - "priority": "medium" - }, - { - "id": "TASK-1280", - "title": "Use the digital TLS panel, then you can transmit the haptic system!", - "status": "done", - "label": "bug", - "priority": "high" - }, - { - "id": "TASK-7262", - "title": "The UTF8 application is down, parse the neural bandwidth so we can back up the PNG firewall!", - "status": "done", - "label": "feature", - "priority": "high" - }, - { - "id": "TASK-1138", - "title": "Generating the driver won't do anything, we need to quantify the 1080p SMTP bandwidth!", - "status": "in progress", - "label": "feature", - "priority": "medium" - }, - { - "id": "TASK-7184", - "title": "We need to program the back-end THX pixel!", - "status": "todo", - "label": "feature", - "priority": "low" - }, - { - "id": "TASK-5160", - "title": "Calculating the bus won't do anything, we need to navigate the back-end JSON protocol!", - "status": "in progress", - "label": "documentation", - "priority": "high" - }, - { - "id": "TASK-5618", - "title": "Generating the driver won't do anything, we need to index the online SSL application!", - "status": "done", - "label": "documentation", - "priority": "medium" - }, - { - "id": "TASK-6699", - "title": "I'll transmit the wireless JBOD capacitor, that should hard drive the SSD feed!", - "status": "backlog", - "label": "documentation", - "priority": "medium" - }, - { - "id": "TASK-2858", - "title": "We need to override the online UDP bus!", - "status": "backlog", - "label": "bug", - "priority": "medium" - }, - { - "id": "TASK-9864", - "title": "I'll reboot the 1080p FTP panel, that should matrix the HEX hard drive!", - "status": "done", - "label": "bug", - "priority": "high" - }, - { - "id": "TASK-8404", - "title": "We need to generate the virtual HEX alarm!", - "status": "in progress", - "label": "bug", - "priority": "low" - }, - { - "id": "TASK-5365", - "title": "Backing up the pixel won't do anything, we need to transmit the primary IB array!", - "status": "in progress", - "label": "documentation", - "priority": "low" - }, - { - "id": "TASK-1780", - "title": "The CSS feed is down, index the bluetooth transmitter so we can compress the CLI protocol!", - "status": "todo", - "label": "documentation", - "priority": "high" - }, - { - "id": "TASK-6938", - "title": "Use the redundant SCSI application, then you can hack the optical alarm!", - "status": "todo", - "label": "documentation", - "priority": "high" - }, - { - "id": "TASK-9885", - "title": "We need to compress the auxiliary VGA driver!", - "status": "backlog", - "label": "bug", - "priority": "high" - }, - { - "id": "TASK-3216", - "title": "Transmitting the transmitter won't do anything, we need to compress the virtual HDD sensor!", - "status": "backlog", - "label": "documentation", - "priority": "medium" - }, - { - "id": "TASK-9285", - "title": "The IP monitor is down, copy the haptic alarm so we can generate the HTTP transmitter!", - "status": "todo", - "label": "bug", - "priority": "high" - }, - { - "id": "TASK-1024", - "title": "Overriding the microchip won't do anything, we need to transmit the digital OCR transmitter!", - "status": "in progress", - "label": "documentation", - "priority": "low" - }, - { - "id": "TASK-7068", - "title": "You can't generate the capacitor without indexing the wireless HEX pixel!", - "status": "canceled", - "label": "bug", - "priority": "low" - }, - { - "id": "TASK-6502", - "title": "Navigating the microchip won't do anything, we need to bypass the back-end SQL bus!", - "status": "todo", - "label": "bug", - "priority": "high" - }, - { - "id": "TASK-5326", - "title": "We need to hack the redundant UTF8 transmitter!", - "status": "todo", - "label": "bug", - "priority": "low" - }, - { - "id": "TASK-6274", - "title": "Use the virtual PCI circuit, then you can parse the bluetooth alarm!", - "status": "canceled", - "label": "documentation", - "priority": "low" - }, - { - "id": "TASK-1571", - "title": "I'll input the neural DRAM circuit, that should protocol the SMTP interface!", - "status": "in progress", - "label": "feature", - "priority": "medium" - }, - { - "id": "TASK-9518", - "title": "Compressing the interface won't do anything, we need to compress the online SDD matrix!", - "status": "canceled", - "label": "documentation", - "priority": "medium" - }, - { - "id": "TASK-5581", - "title": "I'll synthesize the digital COM pixel, that should transmitter the UTF8 protocol!", - "status": "backlog", - "label": "documentation", - "priority": "high" - }, - { - "id": "TASK-2197", - "title": "Parsing the feed won't do anything, we need to copy the bluetooth DRAM bus!", - "status": "todo", - "label": "documentation", - "priority": "low" - }, - { - "id": "TASK-8484", - "title": "We need to parse the solid state UDP firewall!", - "status": "in progress", - "label": "bug", - "priority": "low" - }, - { - "id": "TASK-9892", - "title": "If we back up the application, we can get to the UDP application through the multi-byte THX capacitor!", - "status": "done", - "label": "documentation", - "priority": "high" - }, - { - "id": "TASK-9616", - "title": "We need to synthesize the cross-platform ASCII pixel!", - "status": "in progress", - "label": "feature", - "priority": "medium" - }, - { - "id": "TASK-9744", - "title": "Use the back-end IP card, then you can input the solid state hard drive!", - "status": "done", - "label": "documentation", - "priority": "low" - }, - { - "id": "TASK-1376", - "title": "Generating the alarm won't do anything, we need to generate the mobile IP capacitor!", - "status": "backlog", - "label": "documentation", - "priority": "low" - }, - { - "id": "TASK-7382", - "title": "If we back up the firewall, we can get to the RAM alarm through the primary UTF8 pixel!", - "status": "todo", - "label": "feature", - "priority": "low" - }, - { - "id": "TASK-2290", - "title": "I'll compress the virtual JSON panel, that should application the UTF8 bus!", - "status": "canceled", - "label": "documentation", - "priority": "high" - }, - { - "id": "TASK-1533", - "title": "You can't input the firewall without overriding the wireless TCP firewall!", - "status": "done", - "label": "bug", - "priority": "high" - }, - { - "id": "TASK-4920", - "title": "Bypassing the hard drive won't do anything, we need to input the bluetooth JSON program!", - "status": "in progress", - "label": "bug", - "priority": "high" - }, - { - "id": "TASK-5168", - "title": "If we synthesize the bus, we can get to the IP panel through the virtual TLS array!", - "status": "in progress", - "label": "feature", - "priority": "low" - }, - { - "id": "TASK-7103", - "title": "We need to parse the multi-byte EXE bandwidth!", - "status": "canceled", - "label": "feature", - "priority": "low" - }, - { - "id": "TASK-4314", - "title": "If we compress the program, we can get to the XML alarm through the multi-byte COM matrix!", - "status": "in progress", - "label": "bug", - "priority": "high" - }, - { - "id": "TASK-3415", - "title": "Use the cross-platform XML application, then you can quantify the solid state feed!", - "status": "todo", - "label": "feature", - "priority": "high" - }, - { - "id": "TASK-8339", - "title": "Try to calculate the DNS interface, maybe it will input the bluetooth capacitor!", - "status": "in progress", - "label": "feature", - "priority": "low" - }, - { - "id": "TASK-6995", - "title": "Try to hack the XSS bandwidth, maybe it will override the bluetooth matrix!", - "status": "todo", - "label": "feature", - "priority": "high" - }, - { - "id": "TASK-8053", - "title": "If we connect the program, we can get to the UTF8 matrix through the digital UDP protocol!", - "status": "todo", - "label": "feature", - "priority": "medium" - }, - { - "id": "TASK-4336", - "title": "If we synthesize the microchip, we can get to the SAS sensor through the optical UDP program!", - "status": "todo", - "label": "documentation", - "priority": "low" - }, - { - "id": "TASK-8790", - "title": "I'll back up the optical COM alarm, that should alarm the RSS capacitor!", - "status": "done", - "label": "bug", - "priority": "medium" - }, - { - "id": "TASK-8980", - "title": "Try to navigate the SQL transmitter, maybe it will back up the virtual firewall!", - "status": "canceled", - "label": "bug", - "priority": "low" - }, - { - "id": "TASK-7342", - "title": "Use the neural CLI card, then you can parse the online port!", - "status": "backlog", - "label": "documentation", - "priority": "low" - }, - { - "id": "TASK-5608", - "title": "I'll hack the haptic SSL program, that should bus the UDP transmitter!", - "status": "canceled", - "label": "documentation", - "priority": "low" - }, - { - "id": "TASK-1606", - "title": "I'll generate the bluetooth PNG firewall, that should pixel the SSL driver!", - "status": "done", - "label": "feature", - "priority": "medium" - }, - { - "id": "TASK-7872", - "title": "Transmitting the circuit won't do anything, we need to reboot the 1080p RSS monitor!", - "status": "canceled", - "label": "feature", - "priority": "medium" - }, - { - "id": "TASK-4167", - "title": "Use the cross-platform SMS circuit, then you can synthesize the optical feed!", - "status": "canceled", - "label": "bug", - "priority": "medium" - }, - { - "id": "TASK-9581", - "title": "You can't index the port without hacking the cross-platform XSS monitor!", - "status": "backlog", - "label": "documentation", - "priority": "low" - }, - { - "id": "TASK-8806", - "title": "We need to bypass the back-end SSL panel!", - "status": "done", - "label": "bug", - "priority": "medium" - }, - { - "id": "TASK-6542", - "title": "Try to quantify the RSS firewall, maybe it will quantify the open-source system!", - "status": "done", - "label": "feature", - "priority": "low" - }, - { - "id": "TASK-6806", - "title": "The VGA protocol is down, reboot the back-end matrix so we can parse the CSS panel!", - "status": "canceled", - "label": "documentation", - "priority": "low" - }, - { - "id": "TASK-9549", - "title": "You can't bypass the bus without connecting the neural JBOD bus!", - "status": "todo", - "label": "feature", - "priority": "high" - }, - { - "id": "TASK-1075", - "title": "Backing up the driver won't do anything, we need to parse the redundant RAM pixel!", - "status": "done", - "label": "feature", - "priority": "medium" - }, - { - "id": "TASK-1427", - "title": "Use the auxiliary PCI circuit, then you can calculate the cross-platform interface!", - "status": "done", - "label": "documentation", - "priority": "high" - }, - { - "id": "TASK-1907", - "title": "Hacking the circuit won't do anything, we need to back up the online DRAM system!", - "status": "todo", - "label": "documentation", - "priority": "high" - }, - { - "id": "TASK-4309", - "title": "If we generate the system, we can get to the TCP sensor through the optical GB pixel!", - "status": "backlog", - "label": "bug", - "priority": "medium" - }, - { - "id": "TASK-3973", - "title": "I'll parse the back-end ADP array, that should bandwidth the RSS bandwidth!", - "status": "todo", - "label": "feature", - "priority": "medium" - }, - { - "id": "TASK-7962", - "title": "Use the wireless RAM program, then you can hack the cross-platform feed!", - "status": "canceled", - "label": "bug", - "priority": "low" - }, - { - "id": "TASK-3360", - "title": "You can't quantify the program without synthesizing the neural OCR interface!", - "status": "done", - "label": "feature", - "priority": "medium" - }, - { - "id": "TASK-9887", - "title": "Use the auxiliary ASCII sensor, then you can connect the solid state port!", - "status": "backlog", - "label": "bug", - "priority": "medium" - }, - { - "id": "TASK-3649", - "title": "I'll input the virtual USB system, that should circuit the DNS monitor!", - "status": "in progress", - "label": "feature", - "priority": "medium" - }, - { - "id": "TASK-3586", - "title": "If we quantify the circuit, we can get to the CLI feed through the mobile SMS hard drive!", - "status": "in progress", - "label": "bug", - "priority": "low" - }, - { - "id": "TASK-5150", - "title": "I'll hack the wireless XSS port, that should transmitter the IP interface!", - "status": "canceled", - "label": "feature", - "priority": "medium" - }, - { - "id": "TASK-3652", - "title": "The SQL interface is down, override the optical bus so we can program the ASCII interface!", - "status": "backlog", - "label": "feature", - "priority": "low" - }, - { - "id": "TASK-6884", - "title": "Use the digital PCI circuit, then you can synthesize the multi-byte microchip!", - "status": "canceled", - "label": "feature", - "priority": "high" - }, - { - "id": "TASK-1591", - "title": "We need to connect the mobile XSS driver!", - "status": "in progress", - "label": "feature", - "priority": "high" - }, - { - "id": "TASK-3802", - "title": "Try to override the ASCII protocol, maybe it will parse the virtual matrix!", - "status": "in progress", - "label": "feature", - "priority": "low" - }, - { - "id": "TASK-7253", - "title": "Programming the capacitor won't do anything, we need to bypass the neural IB hard drive!", - "status": "backlog", - "label": "bug", - "priority": "high" - }, - { - "id": "TASK-9739", - "title": "We need to hack the multi-byte HDD bus!", - "status": "done", - "label": "documentation", - "priority": "medium" - }, - { - "id": "TASK-4424", - "title": "Try to hack the HEX alarm, maybe it will connect the optical pixel!", - "status": "in progress", - "label": "documentation", - "priority": "medium" - }, - { - "id": "TASK-3922", - "title": "You can't back up the capacitor without generating the wireless PCI program!", - "status": "backlog", - "label": "bug", - "priority": "low" - }, - { - "id": "TASK-4921", - "title": "I'll index the open-source IP feed, that should system the GB application!", - "status": "canceled", - "label": "bug", - "priority": "low" - }, - { - "id": "TASK-5814", - "title": "We need to calculate the 1080p AGP feed!", - "status": "backlog", - "label": "bug", - "priority": "high" - }, - { - "id": "TASK-2645", - "title": "Synthesizing the system won't do anything, we need to navigate the multi-byte HDD firewall!", - "status": "todo", - "label": "documentation", - "priority": "medium" - }, - { - "id": "TASK-4535", - "title": "Try to copy the JSON circuit, maybe it will connect the wireless feed!", - "status": "in progress", - "label": "feature", - "priority": "low" - }, - { - "id": "TASK-4463", - "title": "We need to copy the solid state AGP monitor!", - "status": "done", - "label": "documentation", - "priority": "low" - }, - { - "id": "TASK-9745", - "title": "If we connect the protocol, we can get to the GB system through the bluetooth PCI microchip!", - "status": "canceled", - "label": "feature", - "priority": "high" - }, - { - "id": "TASK-2080", - "title": "If we input the bus, we can get to the RAM matrix through the auxiliary RAM card!", - "status": "todo", - "label": "bug", - "priority": "medium" - }, - { - "id": "TASK-3838", - "title": "I'll bypass the online TCP application, that should panel the AGP system!", - "status": "backlog", - "label": "bug", - "priority": "high" - }, - { - "id": "TASK-1340", - "title": "We need to navigate the virtual PNG circuit!", - "status": "todo", - "label": "bug", - "priority": "medium" - }, - { - "id": "TASK-6665", - "title": "If we parse the monitor, we can get to the SSD hard drive through the cross-platform AGP alarm!", - "status": "canceled", - "label": "feature", - "priority": "low" - }, - { - "id": "TASK-7585", - "title": "If we calculate the hard drive, we can get to the SSL program through the multi-byte CSS microchip!", - "status": "backlog", - "label": "feature", - "priority": "low" - }, - { - "id": "TASK-6319", - "title": "We need to copy the multi-byte SCSI program!", - "status": "backlog", - "label": "bug", - "priority": "high" - }, - { - "id": "TASK-4369", - "title": "Try to input the SCSI bus, maybe it will generate the 1080p pixel!", - "status": "backlog", - "label": "bug", - "priority": "high" - }, - { - "id": "TASK-9035", - "title": "We need to override the solid state PNG array!", - "status": "canceled", - "label": "documentation", - "priority": "low" - }, - { - "id": "TASK-3970", - "title": "You can't index the transmitter without quantifying the haptic ASCII card!", - "status": "todo", - "label": "documentation", - "priority": "medium" - }, - { - "id": "TASK-4473", - "title": "You can't bypass the protocol without overriding the neural RSS program!", - "status": "todo", - "label": "documentation", - "priority": "low" - }, - { - "id": "TASK-4136", - "title": "You can't hack the hard drive without hacking the primary JSON program!", - "status": "canceled", - "label": "bug", - "priority": "medium" - }, - { - "id": "TASK-3939", - "title": "Use the back-end SQL firewall, then you can connect the neural hard drive!", - "status": "done", - "label": "feature", - "priority": "low" - }, - { - "id": "TASK-2007", - "title": "I'll input the back-end USB protocol, that should bandwidth the PCI system!", - "status": "backlog", - "label": "bug", - "priority": "high" - }, - { - "id": "TASK-7516", - "title": "Use the primary SQL program, then you can generate the auxiliary transmitter!", - "status": "done", - "label": "documentation", - "priority": "medium" - }, - { - "id": "TASK-6906", - "title": "Try to back up the DRAM system, maybe it will reboot the online transmitter!", - "status": "done", - "label": "feature", - "priority": "high" - }, - { - "id": "TASK-5207", - "title": "The SMS interface is down, copy the bluetooth bus so we can quantify the VGA card!", - "status": "in progress", - "label": "bug", - "priority": "low" - } -] diff --git a/src/pages/(admin)/(with-layout)/list/index.tsx b/src/pages/(admin)/(with-layout)/list/index.tsx index 1d4f239..2e904ae 100644 --- a/src/pages/(admin)/(with-layout)/list/index.tsx +++ b/src/pages/(admin)/(with-layout)/list/index.tsx @@ -1,6 +1,6 @@ import { redirect } from "react-router-dom" -export const loader = () => redirect(`/list/basic-list`) +export const loader = () => redirect(`/list/data-table`) export function Component() { return null diff --git a/src/pages/(admin)/(with-layout)/list/pro-table/index.tsx b/src/pages/(admin)/(with-layout)/list/pro-table/index.tsx new file mode 100644 index 0000000..edc4734 --- /dev/null +++ b/src/pages/(admin)/(with-layout)/list/pro-table/index.tsx @@ -0,0 +1,233 @@ +import { + DotsHorizontalIcon, +} from "@radix-ui/react-icons" +import type { + PaginationState, +} from "@tanstack/react-table" +import * as React from "react" + +import { ProTable } from "@/components/pro-table" +import type { ColumnDef, SearchParams } from "@/components/pro-table/types" +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" +import { Button } from "@/components/ui/button" +import { Checkbox } from "@/components/ui/checkbox" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" +import { Textarea } from "@/components/ui/textarea" +import { useUsers } from "@/hooks/query/use-user" +import type { IUsers } from "@/schema/user" + +const columns: ColumnDef[] = [ + { + id: "select", + header: ({ table }) => ( + table.toggleAllPageRowsSelected(!!value)} + aria-label="Select all" + /> + ), + cell: ({ row }) => ( + row.toggleSelected(!!value)} + aria-label="Select row" + /> + ), + enableSorting: false, + enableHiding: false, + }, + { + accessorKey: "id", + header: "ID", + cell: ({ row }) =>
{row.getValue("id")}
, + search: { + placeholder: "Search by ID", + }, + }, + { + accessorKey: "name", + header: "Name", + cell: ({ row }) =>
{row.getValue("name")}
, + search: { + placeholder: "Search by name", + }, + }, + { + accessorKey: "role", + header: "Role", + cell: ({ row }) =>
{row.getValue("role")}
, + search: { + render: ({ value, onChange }) => ( + + ), + }, + }, + { + accessorKey: "avatar", + header: "Avatar", + cell: ({ row }) => ( +
+ + + + {row.original.name.charAt(0)} + + +
+ ), + }, + { + accessorKey: "createdAt", + header: "Created At", + cell: ({ row }) => ( +
+ {new Date(row.getValue("createdAt")).toLocaleDateString()} +
+ ), + search: { + placeholder: "Search by date", + render: ({ value, onChange }) => ( + onChange(e.target.value)} + className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50" + /> + ), + }, + }, + { + accessorKey: "status", + header: "Status", + cell: ({ row }) => ( +
{row.getValue("status")}
+ ), + search: { + placeholder: "Search by status", + render: ({ value, onChange }) => ( + + ), + }, + }, + { + accessorKey: "email", + header: "Email", + cell: ({ row }) =>
{row.getValue("email")}
, + search: { + render: ({ value, onChange }) => ( +