mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/MHSanaei/3x-ui.git
synced 2026-09-20 08:04:05 +08:00
Storybook existed only as an undocumented local tool: 9 of 24 reusable components had stories, autodocs pages were bare prop tables, nothing built or tested the stories, and no contributor doc mentioned the workbench existed. Every reusable component under src/components/ now has a co-located story with enriched autodocs (component descriptions plus per-prop argTypes, kept as string metadata since the repo bans line comments). Stories double as headless Chromium tests through the Storybook vitest addon, with axe accessibility checks enforced as errors and play-function interaction tests covering the modals, the RHF field bridge, the config block, and the select-all buttons. The preview now mirrors the panel's real theme DOM (body class, shared AntD theme config, seeded theme storage) so what stories render matches production. CI and make verify gain a static Storybook build as a compile gate, and the frontend test job installs Chromium so story tests run on every PR. Contributor docs (frontend README, CONTRIBUTING, agent guides) document the workbench, the story conventions, and the Controls setup. Node engines move to 24 LTS and gen:api drops the type-stripping flags that Node 24 makes default.
97 lines
3.0 KiB
TypeScript
97 lines
3.0 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
import { Typography } from 'antd';
|
|
import dayjs from 'dayjs';
|
|
import type { Dayjs } from 'dayjs';
|
|
|
|
import { setDatepicker } from '@/hooks/useDatepicker';
|
|
import { ThemeProvider } from '@/hooks/useTheme';
|
|
|
|
import DateTimePicker from './DateTimePicker';
|
|
|
|
setDatepicker('gregorian');
|
|
|
|
function ClientExpiryDemo() {
|
|
const [value, setValue] = useState<Dayjs | null>(dayjs('2026-12-31 23:59:59'));
|
|
return (
|
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
|
|
<DateTimePicker value={value} onChange={setValue} placeholder="Expiry date" />
|
|
<Typography.Text type="secondary">
|
|
{value ? `user1@node-de expiryTime: ${value.valueOf()}` : 'user1@node-de expiryTime: 0 (never expires)'}
|
|
</Typography.Text>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function JalaliDemo() {
|
|
const [value, setValue] = useState<Dayjs | null>(dayjs('2026-12-31 23:59:59'));
|
|
useEffect(() => {
|
|
setDatepicker('jalalian');
|
|
return () => setDatepicker('gregorian');
|
|
}, []);
|
|
return <DateTimePicker value={value} onChange={setValue} placeholder="Expiry date" />;
|
|
}
|
|
|
|
const meta = {
|
|
title: 'Form/DateTimePicker',
|
|
component: DateTimePicker,
|
|
tags: ['autodocs'],
|
|
parameters: {
|
|
layout: 'padded',
|
|
docs: {
|
|
description: {
|
|
component:
|
|
'Calendar-aware date/time picker used for client and inbound expiry dates. Renders an AntD DatePicker by default and switches to a Persian (Jalali) calendar — with theme-matched colors and an overlaid clear button — when the panel datepicker setting is jalalian.',
|
|
},
|
|
},
|
|
},
|
|
decorators: [
|
|
(Story) => (
|
|
<ThemeProvider>
|
|
<Story />
|
|
</ThemeProvider>
|
|
),
|
|
],
|
|
argTypes: {
|
|
value: { description: 'Selected moment as a Dayjs instance, or null when unset.' },
|
|
onChange: { description: 'Called with the picked Dayjs value, or null when cleared.' },
|
|
showTime: { description: 'Include an hour/minute/second selector alongside the date.' },
|
|
format: { description: 'Display format for the Gregorian picker input.' },
|
|
placeholder: { description: 'Input placeholder shown while no value is set.' },
|
|
disabled: { description: 'Disables the input and hides the clear button.' },
|
|
},
|
|
} satisfies Meta<typeof DateTimePicker>;
|
|
|
|
export default meta;
|
|
|
|
type Story = StoryObj<typeof meta>;
|
|
|
|
export const Empty: Story = {
|
|
args: {
|
|
value: null,
|
|
onChange: () => undefined,
|
|
placeholder: 'Leave blank to never expire',
|
|
},
|
|
};
|
|
|
|
export const ClientExpiry: Story = {
|
|
args: { value: null, onChange: () => undefined },
|
|
render: () => <ClientExpiryDemo />,
|
|
};
|
|
|
|
export const DateOnly: Story = {
|
|
args: {
|
|
value: dayjs('2026-08-01'),
|
|
onChange: () => undefined,
|
|
showTime: false,
|
|
format: 'YYYY-MM-DD',
|
|
placeholder: 'Start date',
|
|
},
|
|
};
|
|
|
|
export const JalaliCalendar: Story = {
|
|
args: { value: null, onChange: () => undefined },
|
|
parameters: { docs: { disable: true } },
|
|
render: () => <JalaliDemo />,
|
|
};
|