nexstruct 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +122 -0
- package/LICENSE +21 -0
- package/README.md +103 -0
- package/package.json +99 -0
- package/scaffold/generator.js +409 -0
- package/scaffold/index.js +20 -0
- package/scaffold/prompts.js +108 -0
- package/templates/api/axios/src/api/axios/client.api.ts +30 -0
- package/templates/api/axios/src/api/axios/users.api.ts +15 -0
- package/templates/api/fetch/src/api/fetch/client.api.ts +68 -0
- package/templates/api/fetch/src/api/fetch/users.api.ts +15 -0
- package/templates/api/trpc/src/api/trpc/client.api.ts +4 -0
- package/templates/api/trpc/src/api/trpc/router.api.ts +15 -0
- package/templates/api/trpc/src/api/trpc/server.client.api.ts +4 -0
- package/templates/api/trpc/src/providers/trpc.provider.tsx +24 -0
- package/templates/auth/clerk/src/auth/clerk/auth.service.ts +4 -0
- package/templates/auth/clerk/src/hooks/use-auth.hook.ts +13 -0
- package/templates/auth/clerk/src/middleware.ts +7 -0
- package/templates/auth/clerk/src/providers/auth.provider.tsx +6 -0
- package/templates/auth/next-auth/src/app/api/auth/[...nextauth]/route.ts +5 -0
- package/templates/auth/next-auth/src/auth/next-auth/auth.service.ts +45 -0
- package/templates/auth/next-auth/src/hooks/use-session.hook.ts +13 -0
- package/templates/auth/next-auth/src/providers/session.provider.tsx +6 -0
- package/templates/forms/formik/src/components/forms/login-form.component.tsx +30 -0
- package/templates/forms/formik/src/forms/formik/hooks/use-form-config.hook.ts +7 -0
- package/templates/forms/formik/src/forms/formik/schemas/example.schema.ts +8 -0
- package/templates/forms/react-hook-form/src/components/forms/login-form.component.tsx +27 -0
- package/templates/forms/react-hook-form/src/forms/react-hook-form/hooks/use-form.hook.ts +13 -0
- package/templates/forms/react-hook-form/src/forms/react-hook-form/schemas/example.schema.ts +15 -0
- package/templates/nextjs-base/next.config.ts +5 -0
- package/templates/nextjs-base/postcss.config.mjs +9 -0
- package/templates/nextjs-base/src/app/_components/navbar.tsx +88 -0
- package/templates/nextjs-base/src/app/_components/sidebar.tsx +223 -0
- package/templates/nextjs-base/src/app/error.tsx +39 -0
- package/templates/nextjs-base/src/app/globals.css +71 -0
- package/templates/nextjs-base/src/app/layout.tsx +21 -0
- package/templates/nextjs-base/src/app/loading.tsx +13 -0
- package/templates/nextjs-base/src/app/not-found.tsx +22 -0
- package/templates/nextjs-base/src/app/page.tsx +10 -0
- package/templates/nextjs-base/tailwind.config.ts +69 -0
- package/templates/shared/src/components/common/theme-toggle.component.tsx +31 -0
- package/templates/shared/src/components/common/toast/custom-message.component.tsx +18 -0
- package/templates/shared/src/components/common/toast/index.ts +8 -0
- package/templates/shared/src/components/common/toast/toast-message.component.tsx +112 -0
- package/templates/shared/src/hooks/use-debounce.hook.ts +12 -0
- package/templates/shared/src/hooks/use-fetch.hook.ts +42 -0
- package/templates/shared/src/hooks/use-intersection-observer.hook.ts +39 -0
- package/templates/shared/src/hooks/use-local-storage.hook.ts +30 -0
- package/templates/shared/src/hooks/use-media-query.hook.ts +26 -0
- package/templates/shared/src/hooks/use-toggle.hook.ts +12 -0
- package/templates/shared/src/lib/utils.util.ts +361 -0
- package/templates/shared/src/providers/theme.provider.tsx +17 -0
- package/templates/shared/src/providers/toast.provider.tsx +32 -0
- package/templates/shared/src/types/common.type.ts +34 -0
- package/templates/state/context/src/store/context/auth.context.tsx +47 -0
- package/templates/state/context/src/store/context/counter.context.tsx +41 -0
- package/templates/state/context/src/store/context/index.ts +2 -0
- package/templates/state/redux/src/providers/redux.provider.tsx +7 -0
- package/templates/state/redux/src/store/redux/hooks.store.ts +5 -0
- package/templates/state/redux/src/store/redux/index.ts +4 -0
- package/templates/state/redux/src/store/redux/slices/api.slice.ts +8 -0
- package/templates/state/redux/src/store/redux/slices/counter.slice.ts +24 -0
- package/templates/state/redux/src/store/redux/store.store.ts +13 -0
- package/templates/state/zustand/src/store/zustand/counter.store.ts +15 -0
- package/templates/state/zustand/src/store/zustand/index.ts +2 -0
- package/templates/state/zustand/src/store/zustand/user.store.ts +32 -0
- package/templates/ui/antd/COMPONENT_GUIDE.md +326 -0
- package/templates/ui/antd/src/app/examples/dialog/page.tsx +205 -0
- package/templates/ui/antd/src/app/examples/form/page.tsx +160 -0
- package/templates/ui/antd/src/app/examples/layout.tsx +125 -0
- package/templates/ui/antd/src/app/examples/page.tsx +64 -0
- package/templates/ui/antd/src/app/examples/table/page.tsx +118 -0
- package/templates/ui/antd/src/app/page.tsx +283 -0
- package/templates/ui/antd/src/components/common/DynamicTable/dynamic-table.component.tsx +79 -0
- package/templates/ui/antd/src/components/common/button/action-button.component.tsx +63 -0
- package/templates/ui/antd/src/components/common/dialog/dialog-wrapper.component.tsx +63 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/check-field.component.tsx +55 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/date-picker-field.component.tsx +80 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/limit-field.component.tsx +26 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/multi-check-field.component.tsx +56 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/number-field.component.tsx +100 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/otp-field.component.tsx +63 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/password-field.component.tsx +106 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/phone-number-field.component.tsx +78 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/radio-field.component.tsx +55 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/range-date-picker.component.tsx +66 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/search-field.component.tsx +24 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/select-field.component.tsx +82 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/single-check-field.component.tsx +50 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/single-select-field.component.tsx +86 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/string-number-field.component.tsx +80 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/switch-field.component.tsx +62 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/text-area-field.component.tsx +85 -0
- package/templates/ui/antd/src/components/common/fields/assets/components/text-field.component.tsx +88 -0
- package/templates/ui/antd/src/components/common/fields/assets/interface/input-props.type.ts +233 -0
- package/templates/ui/antd/src/components/common/fields/cusInputField.component.tsx +40 -0
- package/templates/ui/antd/src/components/common/pagination/pagination.component.tsx +27 -0
- package/templates/ui/antd/src/components/ui/avatar.component.tsx +8 -0
- package/templates/ui/antd/src/components/ui/badge.component.tsx +8 -0
- package/templates/ui/antd/src/components/ui/button.component.tsx +8 -0
- package/templates/ui/antd/src/components/ui/card.component.tsx +8 -0
- package/templates/ui/antd/src/components/ui/checkbox.component.tsx +8 -0
- package/templates/ui/antd/src/components/ui/dialog.component.tsx +9 -0
- package/templates/ui/antd/src/components/ui/dropdown-menu.component.tsx +10 -0
- package/templates/ui/antd/src/components/ui/form.component.tsx +12 -0
- package/templates/ui/antd/src/components/ui/input.component.tsx +13 -0
- package/templates/ui/antd/src/components/ui/label.component.tsx +18 -0
- package/templates/ui/antd/src/components/ui/popover.component.tsx +8 -0
- package/templates/ui/antd/src/components/ui/progress.component.tsx +8 -0
- package/templates/ui/antd/src/components/ui/radio-group.component.tsx +10 -0
- package/templates/ui/antd/src/components/ui/scroll-area.component.tsx +25 -0
- package/templates/ui/antd/src/components/ui/select.component.tsx +8 -0
- package/templates/ui/antd/src/components/ui/separator.component.tsx +8 -0
- package/templates/ui/antd/src/components/ui/sheet.component.tsx +8 -0
- package/templates/ui/antd/src/components/ui/switch.component.tsx +8 -0
- package/templates/ui/antd/src/components/ui/table.component.tsx +8 -0
- package/templates/ui/antd/src/components/ui/tabs.component.tsx +8 -0
- package/templates/ui/antd/src/components/ui/textarea.component.tsx +9 -0
- package/templates/ui/antd/src/components/ui/tooltip.component.tsx +8 -0
- package/templates/ui/antd/src/lib/theme.util.ts +40 -0
- package/templates/ui/antd/src/providers/antd.provider.tsx +13 -0
- package/templates/ui/mui/src/app/examples/layout.tsx +113 -0
- package/templates/ui/mui/src/app/examples/page.tsx +716 -0
- package/templates/ui/mui/src/app/page.tsx +298 -0
- package/templates/ui/mui/src/components/common/DynamicTable/dynamic-table.component.tsx +131 -0
- package/templates/ui/mui/src/components/common/button/action-button.component.tsx +57 -0
- package/templates/ui/mui/src/components/common/dialog/dialog-wrapper.component.tsx +55 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/check-field.component.tsx +51 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/date-picker-field.component.tsx +50 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/multi-check-field.component.tsx +14 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/number-field.component.tsx +59 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/password-field.component.tsx +87 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/phone-number-field.component.tsx +48 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/radio-field.component.tsx +37 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/search-field.component.tsx +41 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/select-field.component.tsx +77 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/single-check-field.component.tsx +39 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/single-select-field.component.tsx +56 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/string-number-field.component.tsx +52 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/switch-field.component.tsx +35 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/text-area-field.component.tsx +46 -0
- package/templates/ui/mui/src/components/common/fields/assets/components/text-field.component.tsx +51 -0
- package/templates/ui/mui/src/components/common/fields/assets/interface/input-props.type.ts +193 -0
- package/templates/ui/mui/src/components/common/fields/cusInputField.component.tsx +34 -0
- package/templates/ui/mui/src/components/common/pagination/pagination.component.tsx +59 -0
- package/templates/ui/mui/src/components/ui/avatar.component.tsx +19 -0
- package/templates/ui/mui/src/components/ui/badge.component.tsx +18 -0
- package/templates/ui/mui/src/components/ui/button.component.tsx +22 -0
- package/templates/ui/mui/src/components/ui/card.component.tsx +39 -0
- package/templates/ui/mui/src/components/ui/checkbox.component.tsx +21 -0
- package/templates/ui/mui/src/components/ui/dialog.component.tsx +38 -0
- package/templates/ui/mui/src/components/ui/dropdown-menu.component.tsx +43 -0
- package/templates/ui/mui/src/components/ui/form.component.tsx +98 -0
- package/templates/ui/mui/src/components/ui/input.component.tsx +15 -0
- package/templates/ui/mui/src/components/ui/label.component.tsx +15 -0
- package/templates/ui/mui/src/components/ui/popover.component.tsx +20 -0
- package/templates/ui/mui/src/components/ui/progress.component.tsx +19 -0
- package/templates/ui/mui/src/components/ui/radio-group.component.tsx +25 -0
- package/templates/ui/mui/src/components/ui/scroll-area.component.tsx +27 -0
- package/templates/ui/mui/src/components/ui/select.component.tsx +26 -0
- package/templates/ui/mui/src/components/ui/separator.component.tsx +11 -0
- package/templates/ui/mui/src/components/ui/sheet.component.tsx +44 -0
- package/templates/ui/mui/src/components/ui/switch.component.tsx +23 -0
- package/templates/ui/mui/src/components/ui/table.component.tsx +34 -0
- package/templates/ui/mui/src/components/ui/tabs.component.tsx +38 -0
- package/templates/ui/mui/src/components/ui/textarea.component.tsx +18 -0
- package/templates/ui/mui/src/components/ui/tooltip.component.tsx +24 -0
- package/templates/ui/mui/src/lib/theme.util.ts +73 -0
- package/templates/ui/mui/src/providers/mui.provider.tsx +13 -0
- package/templates/ui/shadcn/COMPONENT_GUIDE.md +306 -0
- package/templates/ui/shadcn/src/app/examples/dialog/page.tsx +122 -0
- package/templates/ui/shadcn/src/app/examples/form/page.tsx +107 -0
- package/templates/ui/shadcn/src/app/examples/layout.tsx +24 -0
- package/templates/ui/shadcn/src/app/examples/page.tsx +30 -0
- package/templates/ui/shadcn/src/app/examples/table/page.tsx +77 -0
- package/templates/ui/shadcn/src/app/page.tsx +20 -0
- package/templates/ui/shadcn/src/components/common/DynamicTable/dynamic-table.component.tsx +136 -0
- package/templates/ui/shadcn/src/components/common/button/action-button.component.tsx +68 -0
- package/templates/ui/shadcn/src/components/common/dialog/dialog-wrapper.component.tsx +58 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/check-field.component.tsx +52 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/date-picker-field.component.tsx +62 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/dynamic-file-upload-field.component.tsx +152 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/limit-field.component.tsx +73 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/multi-check-field.component.tsx +46 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/number-field.component.tsx +124 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/otp-field.component.tsx +61 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/password-field.component.tsx +110 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/phone-number-field.component.tsx +90 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/radio-field.component.tsx +41 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/range-date-picker.component.tsx +71 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/rich-text-editor.component.tsx +91 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/search-field.component.tsx +34 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/select-field.component.tsx +231 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/single-check-field.component.tsx +42 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/single-select-field.component.tsx +82 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/string-number-field.component.tsx +68 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/switch-field.component.tsx +61 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/text-area-field.component.tsx +62 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/text-area-with-file.component.tsx +142 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/text-field.component.tsx +80 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/tiny-editor.component.tsx +51 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/upload-profile-picture.component.tsx +103 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/components/upload-video-file.component.tsx +86 -0
- package/templates/ui/shadcn/src/components/common/fields/assets/interface/input-props.type.ts +198 -0
- package/templates/ui/shadcn/src/components/common/fields/cusInputField.component.tsx +52 -0
- package/templates/ui/shadcn/src/components/common/pagination/pagination.component.tsx +68 -0
- package/templates/ui/shadcn/src/components/ui/avatar.component.tsx +37 -0
- package/templates/ui/shadcn/src/components/ui/badge.component.tsx +28 -0
- package/templates/ui/shadcn/src/components/ui/button.component.tsx +52 -0
- package/templates/ui/shadcn/src/components/ui/card.component.tsx +46 -0
- package/templates/ui/shadcn/src/components/ui/checkbox.component.tsx +25 -0
- package/templates/ui/shadcn/src/components/ui/dialog.component.tsx +98 -0
- package/templates/ui/shadcn/src/components/ui/dropdown-menu.component.tsx +163 -0
- package/templates/ui/shadcn/src/components/ui/form.component.tsx +110 -0
- package/templates/ui/shadcn/src/components/ui/input-otp.component.tsx +64 -0
- package/templates/ui/shadcn/src/components/ui/input.component.tsx +23 -0
- package/templates/ui/shadcn/src/components/ui/label.component.tsx +23 -0
- package/templates/ui/shadcn/src/components/ui/popover.component.tsx +27 -0
- package/templates/ui/shadcn/src/components/ui/progress.component.tsx +22 -0
- package/templates/ui/shadcn/src/components/ui/radio-group.component.tsx +33 -0
- package/templates/ui/shadcn/src/components/ui/scroll-area.component.tsx +37 -0
- package/templates/ui/shadcn/src/components/ui/select.component.tsx +139 -0
- package/templates/ui/shadcn/src/components/ui/separator.component.tsx +23 -0
- package/templates/ui/shadcn/src/components/ui/sheet.component.tsx +89 -0
- package/templates/ui/shadcn/src/components/ui/switch.component.tsx +26 -0
- package/templates/ui/shadcn/src/components/ui/table.component.tsx +71 -0
- package/templates/ui/shadcn/src/components/ui/tabs.component.tsx +52 -0
- package/templates/ui/shadcn/src/components/ui/textarea.component.tsx +20 -0
- package/templates/ui/shadcn/src/components/ui/tooltip.component.tsx +25 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import Link from 'next/link';
|
|
5
|
+
import {
|
|
6
|
+
Layout, Typography, Button, Space, Drawer, List, Divider, Grid, theme,
|
|
7
|
+
} from 'antd';
|
|
8
|
+
import {
|
|
9
|
+
MenuOutlined, CloseOutlined, HomeOutlined, GithubOutlined, AppstoreOutlined,
|
|
10
|
+
} from '@ant-design/icons';
|
|
11
|
+
|
|
12
|
+
const { Header, Content, Footer } = Layout;
|
|
13
|
+
const { Text } = Typography;
|
|
14
|
+
const { useBreakpoint } = Grid;
|
|
15
|
+
|
|
16
|
+
export default function ExamplesLayout({ children }: { children: React.ReactNode }) {
|
|
17
|
+
const [mobileOpen, setMobileOpen] = useState(false);
|
|
18
|
+
const screens = useBreakpoint();
|
|
19
|
+
const { token } = theme.useToken();
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<Layout style={{ minHeight: '100vh', background: token.colorBgContainer }}>
|
|
23
|
+
{/* Navbar */}
|
|
24
|
+
<Header style={{
|
|
25
|
+
position: 'sticky', top: 0, zIndex: 100,
|
|
26
|
+
background: 'rgba(255,255,255,0.9)', backdropFilter: 'blur(16px)',
|
|
27
|
+
borderBottom: `1px solid ${token.colorBorderSecondary}`,
|
|
28
|
+
display: 'flex', alignItems: 'center', justifyContent: 'space-between',
|
|
29
|
+
padding: '0 24px', height: 64,
|
|
30
|
+
}}>
|
|
31
|
+
<Space>
|
|
32
|
+
<Link href="/" passHref legacyBehavior>
|
|
33
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: 8, cursor: 'pointer' }}>
|
|
34
|
+
<div style={{
|
|
35
|
+
width: 28, height: 28, borderRadius: 6,
|
|
36
|
+
background: token.colorPrimary, display: 'flex',
|
|
37
|
+
alignItems: 'center', justifyContent: 'center',
|
|
38
|
+
}}>
|
|
39
|
+
<Text strong style={{ color: '#fff', fontSize: 14 }}>F</Text>
|
|
40
|
+
</div>
|
|
41
|
+
<Text strong style={{ display: screens.sm ? 'block' : 'none' }}>Nexstruct</Text>
|
|
42
|
+
</div>
|
|
43
|
+
</Link>
|
|
44
|
+
<Divider type="vertical" />
|
|
45
|
+
<Space size={4}>
|
|
46
|
+
<AppstoreOutlined style={{ color: token.colorPrimary, fontSize: 14 }} />
|
|
47
|
+
<Text style={{ color: token.colorPrimary, fontWeight: 500 }}>Components</Text>
|
|
48
|
+
</Space>
|
|
49
|
+
</Space>
|
|
50
|
+
|
|
51
|
+
{screens.md && (
|
|
52
|
+
<Space>
|
|
53
|
+
<Link href="/" passHref legacyBehavior>
|
|
54
|
+
<Button type="text" size="small" icon={<HomeOutlined />}>Home</Button>
|
|
55
|
+
</Link>
|
|
56
|
+
<Button type="text" size="small" icon={<GithubOutlined />} href="https://github.com" target="_blank" />
|
|
57
|
+
</Space>
|
|
58
|
+
)}
|
|
59
|
+
|
|
60
|
+
{!screens.md && (
|
|
61
|
+
<Button type="text" icon={<MenuOutlined />} onClick={() => setMobileOpen(true)} />
|
|
62
|
+
)}
|
|
63
|
+
</Header>
|
|
64
|
+
|
|
65
|
+
{/* Mobile Drawer */}
|
|
66
|
+
<Drawer
|
|
67
|
+
title="Navigate"
|
|
68
|
+
placement="right"
|
|
69
|
+
onClose={() => setMobileOpen(false)}
|
|
70
|
+
open={mobileOpen}
|
|
71
|
+
closeIcon={<CloseOutlined />}
|
|
72
|
+
width={280}
|
|
73
|
+
>
|
|
74
|
+
<List
|
|
75
|
+
dataSource={[
|
|
76
|
+
{ label: 'Home', href: '/' },
|
|
77
|
+
{ label: 'Components', href: '/examples' },
|
|
78
|
+
]}
|
|
79
|
+
renderItem={(item) => (
|
|
80
|
+
<List.Item>
|
|
81
|
+
<Link href={item.href} passHref legacyBehavior>
|
|
82
|
+
<Button type="link" onClick={() => setMobileOpen(false)}>
|
|
83
|
+
{item.label}
|
|
84
|
+
</Button>
|
|
85
|
+
</Link>
|
|
86
|
+
</List.Item>
|
|
87
|
+
)}
|
|
88
|
+
/>
|
|
89
|
+
</Drawer>
|
|
90
|
+
|
|
91
|
+
{/* Content */}
|
|
92
|
+
<Content style={{ minHeight: 'calc(100vh - 128px)' }}>
|
|
93
|
+
{children}
|
|
94
|
+
</Content>
|
|
95
|
+
|
|
96
|
+
{/* Footer */}
|
|
97
|
+
<Footer style={{
|
|
98
|
+
background: token.colorBgElevated,
|
|
99
|
+
borderTop: `1px solid ${token.colorBorderSecondary}`,
|
|
100
|
+
padding: '16px 24px',
|
|
101
|
+
}}>
|
|
102
|
+
<div style={{
|
|
103
|
+
display: 'flex', justifyContent: 'space-between',
|
|
104
|
+
alignItems: 'center', flexWrap: 'wrap', gap: 8,
|
|
105
|
+
maxWidth: 1200, margin: '0 auto',
|
|
106
|
+
}}>
|
|
107
|
+
<Text type="secondary" style={{ fontSize: 12, opacity: 0.6 }}>
|
|
108
|
+
Ant Design Component System — Scaffolded with Nexstruct
|
|
109
|
+
</Text>
|
|
110
|
+
<Space size="middle">
|
|
111
|
+
<Link href="/" passHref legacyBehavior>
|
|
112
|
+
<Text style={{ fontSize: 12, opacity: 0.6, cursor: 'pointer' }}>Home</Text>
|
|
113
|
+
</Link>
|
|
114
|
+
<Text
|
|
115
|
+
style={{ fontSize: 12, opacity: 0.6, cursor: 'pointer' }}
|
|
116
|
+
onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })}
|
|
117
|
+
>
|
|
118
|
+
Back to Top
|
|
119
|
+
</Text>
|
|
120
|
+
</Space>
|
|
121
|
+
</div>
|
|
122
|
+
</Footer>
|
|
123
|
+
</Layout>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import Link from 'next/link';
|
|
4
|
+
import { Card, Row, Col, Typography, Space, theme } from 'antd';
|
|
5
|
+
import {
|
|
6
|
+
FormOutlined, TableOutlined, AppstoreOutlined,
|
|
7
|
+
} from '@ant-design/icons';
|
|
8
|
+
|
|
9
|
+
const { Title, Text, Paragraph } = Typography;
|
|
10
|
+
|
|
11
|
+
const examples = [
|
|
12
|
+
{
|
|
13
|
+
href: '/examples/form',
|
|
14
|
+
title: 'Form Components',
|
|
15
|
+
desc: 'All CustomField field types with react-hook-form validation and Zod schemas.',
|
|
16
|
+
icon: <FormOutlined style={{ fontSize: 40, color: '#1677ff' }} />,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
href: '/examples/table',
|
|
20
|
+
title: 'DynamicTable',
|
|
21
|
+
desc: 'Config-driven table with loading, empty, and checkbox selection states using Ant Design Table.',
|
|
22
|
+
icon: <TableOutlined style={{ fontSize: 40, color: '#13c2c2' }} />,
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
href: '/examples/dialog',
|
|
26
|
+
title: 'Dialog, ActionButton & Pagination',
|
|
27
|
+
desc: 'Reusable DialogWrapper, action button variants with tooltips, and Ant Design pagination.',
|
|
28
|
+
icon: <AppstoreOutlined style={{ fontSize: 40, color: '#722ed1' }} />,
|
|
29
|
+
},
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
export default function ExamplesPage() {
|
|
33
|
+
const { token } = theme.useToken();
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<div style={{ padding: 48, maxWidth: 960, margin: '0 auto' }}>
|
|
37
|
+
<div style={{ marginBottom: 32 }}>
|
|
38
|
+
<Title level={2} style={{ fontWeight: 800, margin: 0 }}>Component Examples</Title>
|
|
39
|
+
<Text type="secondary" style={{ fontSize: 16, display: 'block', marginTop: 4 }}>
|
|
40
|
+
Interactive demos of the Ant Design custom component system.
|
|
41
|
+
</Text>
|
|
42
|
+
</div>
|
|
43
|
+
<Row gutter={[24, 24]}>
|
|
44
|
+
{examples.map((ex) => (
|
|
45
|
+
<Col xs={24} sm={12} lg={8} key={ex.href}>
|
|
46
|
+
<Link href={ex.href} passHref legacyBehavior>
|
|
47
|
+
<Card
|
|
48
|
+
hoverable
|
|
49
|
+
style={{ height: '100%', borderRadius: 12, cursor: 'pointer' }}
|
|
50
|
+
styles={{ body: { padding: 24 } }}
|
|
51
|
+
>
|
|
52
|
+
<div style={{ marginBottom: 16 }}>{ex.icon}</div>
|
|
53
|
+
<Title level={4} style={{ fontWeight: 700, margin: 0 }}>{ex.title}</Title>
|
|
54
|
+
<Paragraph type="secondary" style={{ marginTop: 8, lineHeight: 1.7, marginBottom: 0 }}>
|
|
55
|
+
{ex.desc}
|
|
56
|
+
</Paragraph>
|
|
57
|
+
</Card>
|
|
58
|
+
</Link>
|
|
59
|
+
</Col>
|
|
60
|
+
))}
|
|
61
|
+
</Row>
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { Typography, Space, Tag, theme } from 'antd';
|
|
5
|
+
import { DynamicTable, type TableColumn } from '@/components/common/DynamicTable/dynamic-table.component';
|
|
6
|
+
import { LimitField } from '@/components/common/fields/assets/components/limit-field.component';
|
|
7
|
+
import { ActionButton } from '@/components/common/button/action-button.component';
|
|
8
|
+
import { Pagination } from '@/components/common/pagination/pagination.component';
|
|
9
|
+
|
|
10
|
+
const { Title, Text } = Typography;
|
|
11
|
+
|
|
12
|
+
interface User {
|
|
13
|
+
id: string;
|
|
14
|
+
name: string;
|
|
15
|
+
email: string;
|
|
16
|
+
role: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const allUsers: User[] = Array.from({ length: 53 }, (_, i) => ({
|
|
20
|
+
id: String(i + 1),
|
|
21
|
+
name: `User ${i + 1}`,
|
|
22
|
+
email: `user${i + 1}@example.com`,
|
|
23
|
+
role: i % 3 === 0 ? 'Admin' : i % 3 === 1 ? 'Editor' : 'Viewer',
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
const columns: TableColumn[] = [
|
|
27
|
+
{ key: 'name', header: 'Name' },
|
|
28
|
+
{ key: 'email', header: 'Email' },
|
|
29
|
+
{
|
|
30
|
+
key: 'role',
|
|
31
|
+
header: 'Role',
|
|
32
|
+
render: (item: User) => {
|
|
33
|
+
const color = item.role === 'Admin' ? 'blue' : item.role === 'Editor' ? 'purple' : 'cyan';
|
|
34
|
+
return <Tag color={color} style={{ borderRadius: 6 }}>{item.role}</Tag>;
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
export default function TableExamplePage() {
|
|
40
|
+
const { token } = theme.useToken();
|
|
41
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
42
|
+
const [currentPage, setCurrentPage] = useState(1);
|
|
43
|
+
const [limit, setLimit] = useState('10');
|
|
44
|
+
const [selectedIds, setSelectedIds] = useState<string[]>([]);
|
|
45
|
+
|
|
46
|
+
const perPage = Number(limit);
|
|
47
|
+
const totalPages = Math.ceil(allUsers.length / perPage);
|
|
48
|
+
const paginatedData = allUsers.slice((currentPage - 1) * perPage, currentPage * perPage);
|
|
49
|
+
|
|
50
|
+
const refresh = () => {
|
|
51
|
+
setIsLoading(true);
|
|
52
|
+
setTimeout(() => setIsLoading(false), 1000);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<div style={{ maxWidth: 960, margin: '0 auto', padding: 32 }}>
|
|
57
|
+
<div style={{ marginBottom: 24 }}>
|
|
58
|
+
<Title level={2} style={{ fontWeight: 800, margin: 0 }}>DynamicTable Demo</Title>
|
|
59
|
+
<Text type="secondary" style={{ fontSize: 15, display: 'block', marginTop: 4 }}>
|
|
60
|
+
Config-driven Ant Design Table with loading state, checkbox selection, and pagination.
|
|
61
|
+
</Text>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<div style={{
|
|
65
|
+
background: token.colorBgContainer,
|
|
66
|
+
borderRadius: 12,
|
|
67
|
+
border: `1px solid ${token.colorBorderSecondary}`,
|
|
68
|
+
padding: 24,
|
|
69
|
+
}}>
|
|
70
|
+
<div style={{
|
|
71
|
+
display: 'flex', alignItems: 'center',
|
|
72
|
+
justifyContent: 'space-between', marginBottom: 16,
|
|
73
|
+
flexWrap: 'wrap', gap: 12,
|
|
74
|
+
}}>
|
|
75
|
+
<Space size="middle">
|
|
76
|
+
<LimitField
|
|
77
|
+
limit={limit}
|
|
78
|
+
setLimit={(v) => { setLimit(v); setCurrentPage(1); }}
|
|
79
|
+
totalItems={allUsers.length}
|
|
80
|
+
/>
|
|
81
|
+
<ActionButton
|
|
82
|
+
buttonContent="Refresh"
|
|
83
|
+
variant="default"
|
|
84
|
+
handleOpen={refresh}
|
|
85
|
+
btnSize="small"
|
|
86
|
+
/>
|
|
87
|
+
</Space>
|
|
88
|
+
{selectedIds.length > 0 && (
|
|
89
|
+
<Text type="secondary" style={{ fontSize: 13 }}>
|
|
90
|
+
{selectedIds.length} selected
|
|
91
|
+
</Text>
|
|
92
|
+
)}
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<DynamicTable
|
|
96
|
+
data={paginatedData}
|
|
97
|
+
isLoading={isLoading}
|
|
98
|
+
config={{ columns }}
|
|
99
|
+
isCheckBox
|
|
100
|
+
selectedIds={selectedIds}
|
|
101
|
+
setSelectedIds={setSelectedIds}
|
|
102
|
+
rowKey="id"
|
|
103
|
+
/>
|
|
104
|
+
|
|
105
|
+
{totalPages > 1 && (
|
|
106
|
+
<div style={{ marginTop: 20 }}>
|
|
107
|
+
<Pagination
|
|
108
|
+
currentPage={currentPage}
|
|
109
|
+
totalPages={totalPages}
|
|
110
|
+
setCurrentPage={setCurrentPage}
|
|
111
|
+
total={allUsers.length}
|
|
112
|
+
/>
|
|
113
|
+
</div>
|
|
114
|
+
)}
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import Link from 'next/link';
|
|
5
|
+
import {
|
|
6
|
+
Layout, Typography, Button, Space, Card, Row, Col, Divider,
|
|
7
|
+
Tag, Drawer, List, Grid, App, theme,
|
|
8
|
+
} from 'antd';
|
|
9
|
+
import {
|
|
10
|
+
MenuOutlined, CloseOutlined, GithubOutlined,
|
|
11
|
+
ArrowRightOutlined, AppstoreOutlined, FormOutlined,
|
|
12
|
+
TableOutlined, CodeOutlined, StarOutlined,
|
|
13
|
+
} from '@ant-design/icons';
|
|
14
|
+
|
|
15
|
+
const { Header, Content, Footer } = Layout;
|
|
16
|
+
const { Title, Text, Paragraph } = Typography;
|
|
17
|
+
const { useBreakpoint } = Grid;
|
|
18
|
+
|
|
19
|
+
const features = [
|
|
20
|
+
{
|
|
21
|
+
icon: <AppstoreOutlined style={{ fontSize: 32, color: '#1677ff' }} />,
|
|
22
|
+
title: '22 UI Primitives',
|
|
23
|
+
desc: 'Button, Card, Modal, Table, Tabs, Avatar, Select, Switch, Tooltip, Drawer, Dropdown, and more — all pre-styled with Ant Design.',
|
|
24
|
+
color: '#1677ff',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
icon: <FormOutlined style={{ fontSize: 32, color: '#722ed1' }} />,
|
|
28
|
+
title: 'CustomField System',
|
|
29
|
+
desc: '17 field types with dual-mode: react-hook-form integration or standalone value/setValue.',
|
|
30
|
+
color: '#722ed1',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
icon: <TableOutlined style={{ fontSize: 32, color: '#13c2c2' }} />,
|
|
34
|
+
title: 'DynamicTable',
|
|
35
|
+
desc: 'Ant Design Table wrapper with loading states, empty states, and checkbox selection.',
|
|
36
|
+
color: '#13c2c2',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
icon: <CodeOutlined style={{ fontSize: 32, color: '#eb2f96' }} />,
|
|
40
|
+
title: 'Form Validation',
|
|
41
|
+
desc: 'React Hook Form + Zod schema validation with live error messages and form state tracking.',
|
|
42
|
+
color: '#eb2f96',
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
const techStack = [
|
|
47
|
+
'Ant Design 5', 'React Hook Form', 'Zod', 'Next.js 15', 'TypeScript',
|
|
48
|
+
'@ant-design/icons', 'dayjs',
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
const navLinks = [
|
|
52
|
+
{ label: 'Home', href: '/' },
|
|
53
|
+
{ label: 'Components', href: '/examples' },
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
export default function Home() {
|
|
57
|
+
const [mobileOpen, setMobileOpen] = useState(false);
|
|
58
|
+
const screens = useBreakpoint();
|
|
59
|
+
const { token } = theme.useToken();
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<Layout style={{ minHeight: '100vh', background: token.colorBgContainer }}>
|
|
63
|
+
{/* Navbar */}
|
|
64
|
+
<Header style={{
|
|
65
|
+
position: 'sticky', top: 0, zIndex: 100,
|
|
66
|
+
background: 'rgba(255,255,255,0.9)', backdropFilter: 'blur(16px)',
|
|
67
|
+
borderBottom: `1px solid ${token.colorBorderSecondary}`,
|
|
68
|
+
display: 'flex', alignItems: 'center', justifyContent: 'space-between',
|
|
69
|
+
padding: '0 24px', height: 64,
|
|
70
|
+
}}>
|
|
71
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
|
72
|
+
<div style={{
|
|
73
|
+
width: 32, height: 32, borderRadius: 6,
|
|
74
|
+
background: token.colorPrimary, display: 'flex',
|
|
75
|
+
alignItems: 'center', justifyContent: 'center',
|
|
76
|
+
}}>
|
|
77
|
+
<Text strong style={{ color: '#fff', fontSize: 16 }}>F</Text>
|
|
78
|
+
</div>
|
|
79
|
+
<Text strong style={{ fontSize: 16, letterSpacing: '-0.02em' }}>Nexstruct</Text>
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
{screens.md && (
|
|
83
|
+
<Space size="small">
|
|
84
|
+
{navLinks.map((link) => (
|
|
85
|
+
<Link key={link.href} href={link.href} passHref legacyBehavior>
|
|
86
|
+
<Button type={link.href === '/' ? 'primary' : 'text'} size="small">
|
|
87
|
+
{link.label}
|
|
88
|
+
</Button>
|
|
89
|
+
</Link>
|
|
90
|
+
))}
|
|
91
|
+
<Divider type="vertical" />
|
|
92
|
+
<Button type="text" icon={<GithubOutlined />} size="small" href="https://github.com" target="_blank" />
|
|
93
|
+
</Space>
|
|
94
|
+
)}
|
|
95
|
+
|
|
96
|
+
{!screens.md && (
|
|
97
|
+
<Button type="text" icon={<MenuOutlined />} onClick={() => setMobileOpen(true)} />
|
|
98
|
+
)}
|
|
99
|
+
</Header>
|
|
100
|
+
|
|
101
|
+
{/* Mobile Drawer */}
|
|
102
|
+
<Drawer
|
|
103
|
+
title="Menu"
|
|
104
|
+
placement="right"
|
|
105
|
+
onClose={() => setMobileOpen(false)}
|
|
106
|
+
open={mobileOpen}
|
|
107
|
+
closeIcon={<CloseOutlined />}
|
|
108
|
+
width={280}
|
|
109
|
+
>
|
|
110
|
+
<List
|
|
111
|
+
dataSource={navLinks}
|
|
112
|
+
renderItem={(link) => (
|
|
113
|
+
<List.Item>
|
|
114
|
+
<Link href={link.href} passHref legacyBehavior>
|
|
115
|
+
<Button type="link" onClick={() => setMobileOpen(false)}>
|
|
116
|
+
{link.label}
|
|
117
|
+
</Button>
|
|
118
|
+
</Link>
|
|
119
|
+
</List.Item>
|
|
120
|
+
)}
|
|
121
|
+
/>
|
|
122
|
+
</Drawer>
|
|
123
|
+
|
|
124
|
+
<Content>
|
|
125
|
+
{/* Hero Section */}
|
|
126
|
+
<div style={{
|
|
127
|
+
background: 'linear-gradient(135deg, #141414 0%, #1a1a2e 50%, #16213e 100%)',
|
|
128
|
+
padding: screens.md ? '100px 48px' : '60px 24px',
|
|
129
|
+
textAlign: 'center',
|
|
130
|
+
}}>
|
|
131
|
+
<Space direction="vertical" size="middle" style={{ width: '100%', maxWidth: 720 }}>
|
|
132
|
+
<Space wrap size="small" justify="center">
|
|
133
|
+
<Tag color="blue" style={{ borderRadius: 12 }}>Ant Design 5</Tag>
|
|
134
|
+
<Tag color="purple" style={{ borderRadius: 12 }}>TypeScript</Tag>
|
|
135
|
+
<Tag color="cyan" style={{ borderRadius: 12 }}>Next.js 15</Tag>
|
|
136
|
+
</Space>
|
|
137
|
+
<Title level={1} style={{
|
|
138
|
+
color: '#fff', fontSize: screens.md ? 52 : 32,
|
|
139
|
+
fontWeight: 800, letterSpacing: '-0.03em', margin: 0,
|
|
140
|
+
}}>
|
|
141
|
+
Build Beautiful Apps with{' '}
|
|
142
|
+
<Text style={{
|
|
143
|
+
background: 'linear-gradient(135deg, #1677ff, #9254de)',
|
|
144
|
+
WebkitBackgroundClip: 'text', WebkitTextFillColor: 'transparent',
|
|
145
|
+
}}>
|
|
146
|
+
Ant Design Components
|
|
147
|
+
</Text>
|
|
148
|
+
</Title>
|
|
149
|
+
<Paragraph style={{
|
|
150
|
+
color: 'rgba(255,255,255,0.75)', fontSize: 18,
|
|
151
|
+
maxWidth: 600, margin: '0 auto', lineHeight: 1.6,
|
|
152
|
+
}}>
|
|
153
|
+
A production-ready component system built on Ant Design — with form validation,
|
|
154
|
+
dynamic tables, dialogs, and 22+ UI primitives.
|
|
155
|
+
</Paragraph>
|
|
156
|
+
<Space size="middle" wrap justify="center">
|
|
157
|
+
<Link href="/examples" passHref legacyBehavior>
|
|
158
|
+
<Button type="primary" size="large" icon={<ArrowRightOutlined />}>
|
|
159
|
+
Explore Components
|
|
160
|
+
</Button>
|
|
161
|
+
</Link>
|
|
162
|
+
<Button size="large" ghost icon={<StarOutlined />} href="#features">
|
|
163
|
+
Learn More
|
|
164
|
+
</Button>
|
|
165
|
+
</Space>
|
|
166
|
+
</Space>
|
|
167
|
+
</div>
|
|
168
|
+
|
|
169
|
+
{/* Feature Cards */}
|
|
170
|
+
<div id="features" style={{ padding: screens.md ? '80px 48px' : '48px 24px', scrollMarginTop: 80 }}>
|
|
171
|
+
<div style={{ textAlign: 'center', marginBottom: 48 }}>
|
|
172
|
+
<Title level={2} style={{ fontWeight: 800, margin: 0 }}>What's Included</Title>
|
|
173
|
+
<Text type="secondary" style={{ fontSize: 16, display: 'block', marginTop: 8 }}>
|
|
174
|
+
A complete component ecosystem — every piece is pre-built, pre-styled, and ready for production.
|
|
175
|
+
</Text>
|
|
176
|
+
<Divider style={{
|
|
177
|
+
width: 80, minWidth: 80, margin: '16px auto',
|
|
178
|
+
borderTopWidth: 3, borderColor: token.colorPrimary,
|
|
179
|
+
borderRadius: 4,
|
|
180
|
+
}} />
|
|
181
|
+
</div>
|
|
182
|
+
<Row gutter={[24, 24]} justify="center">
|
|
183
|
+
{features.map((f) => (
|
|
184
|
+
<Col xs={24} sm={12} lg={6} key={f.title}>
|
|
185
|
+
<Card
|
|
186
|
+
hoverable
|
|
187
|
+
style={{ height: '100%', borderRadius: 12 }}
|
|
188
|
+
styles={{ body: { padding: 24 } }}
|
|
189
|
+
>
|
|
190
|
+
<div style={{ marginBottom: 16 }}>{f.icon}</div>
|
|
191
|
+
<Title level={4} style={{ fontWeight: 700, margin: 0 }}>{f.title}</Title>
|
|
192
|
+
<Paragraph type="secondary" style={{ marginTop: 8, lineHeight: 1.7 }}>
|
|
193
|
+
{f.desc}
|
|
194
|
+
</Paragraph>
|
|
195
|
+
</Card>
|
|
196
|
+
</Col>
|
|
197
|
+
))}
|
|
198
|
+
</Row>
|
|
199
|
+
</div>
|
|
200
|
+
|
|
201
|
+
{/* Tech Stack */}
|
|
202
|
+
<div style={{
|
|
203
|
+
padding: screens.md ? '64px 48px' : '40px 24px',
|
|
204
|
+
background: token.colorBgLayout,
|
|
205
|
+
}}>
|
|
206
|
+
<div style={{ textAlign: 'center', maxWidth: 600, margin: '0 auto' }}>
|
|
207
|
+
<Title level={3} style={{ fontWeight: 700, margin: 0 }}>Powered By</Title>
|
|
208
|
+
<Text type="secondary" style={{ display: 'block', margin: '8px 0 24px' }}>
|
|
209
|
+
Built on battle-tested libraries you already trust.
|
|
210
|
+
</Text>
|
|
211
|
+
<Space wrap size="small" justify="center">
|
|
212
|
+
{techStack.map((t) => (
|
|
213
|
+
<Tag key={t} style={{ borderRadius: 12, padding: '4px 12px', fontSize: 13 }}>
|
|
214
|
+
{t}
|
|
215
|
+
</Tag>
|
|
216
|
+
))}
|
|
217
|
+
</Space>
|
|
218
|
+
</div>
|
|
219
|
+
</div>
|
|
220
|
+
|
|
221
|
+
{/* CTA */}
|
|
222
|
+
<div style={{ padding: screens.md ? '80px 48px' : '48px 24px', textAlign: 'center' }}>
|
|
223
|
+
<Title level={2} style={{ fontWeight: 800 }}>Ready to Explore?</Title>
|
|
224
|
+
<Paragraph type="secondary" style={{ fontSize: 16, marginBottom: 32 }}>
|
|
225
|
+
See every component in action — buttons, forms, tables, dialogs, and more.
|
|
226
|
+
</Paragraph>
|
|
227
|
+
<Link href="/examples" passHref legacyBehavior>
|
|
228
|
+
<Button type="primary" size="large" icon={<ArrowRightOutlined />}>
|
|
229
|
+
View Component Showcase
|
|
230
|
+
</Button>
|
|
231
|
+
</Link>
|
|
232
|
+
</div>
|
|
233
|
+
</Content>
|
|
234
|
+
|
|
235
|
+
{/* Footer */}
|
|
236
|
+
<Footer style={{
|
|
237
|
+
background: token.colorBgElevated,
|
|
238
|
+
borderTop: `1px solid ${token.colorBorderSecondary}`,
|
|
239
|
+
padding: '48px 24px 24px',
|
|
240
|
+
}}>
|
|
241
|
+
<Row gutter={[24, 24]} style={{ maxWidth: 1200, margin: '0 auto' }}>
|
|
242
|
+
<Col xs={24} md={12}>
|
|
243
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8 }}>
|
|
244
|
+
<div style={{
|
|
245
|
+
width: 28, height: 28, borderRadius: 6,
|
|
246
|
+
background: token.colorPrimary, display: 'flex',
|
|
247
|
+
alignItems: 'center', justifyContent: 'center',
|
|
248
|
+
}}>
|
|
249
|
+
<Text strong style={{ color: '#fff', fontSize: 14 }}>F</Text>
|
|
250
|
+
</div>
|
|
251
|
+
<Text strong>Nexstruct</Text>
|
|
252
|
+
</div>
|
|
253
|
+
<Text type="secondary" style={{ display: 'block', maxWidth: 360 }}>
|
|
254
|
+
Scaffolding production-ready Next.js applications with composable, framework-specific component systems.
|
|
255
|
+
</Text>
|
|
256
|
+
</Col>
|
|
257
|
+
<Col xs={12} md={6}>
|
|
258
|
+
<Text strong style={{ opacity: 0.5, textTransform: 'uppercase', fontSize: 12, letterSpacing: '0.05em' }}>Navigate</Text>
|
|
259
|
+
<div style={{ marginTop: 8, display: 'flex', flexDirection: 'column', gap: 4 }}>
|
|
260
|
+
{['Home', 'Components', 'GitHub'].map((l) => (
|
|
261
|
+
<Link key={l} href={l === 'Home' ? '/' : l === 'Components' ? '/examples' : '#'} passHref legacyBehavior>
|
|
262
|
+
<Text style={{ cursor: 'pointer' }} type="secondary">{l}</Text>
|
|
263
|
+
</Link>
|
|
264
|
+
))}
|
|
265
|
+
</div>
|
|
266
|
+
</Col>
|
|
267
|
+
<Col xs={12} md={6}>
|
|
268
|
+
<Text strong style={{ opacity: 0.5, textTransform: 'uppercase', fontSize: 12, letterSpacing: '0.05em' }}>Tech</Text>
|
|
269
|
+
<div style={{ marginTop: 8, display: 'flex', flexDirection: 'column', gap: 4 }}>
|
|
270
|
+
{['Ant Design 5', 'Next.js 15', 'TypeScript', 'React Hook Form'].map((t) => (
|
|
271
|
+
<Text key={t} type="secondary">{t}</Text>
|
|
272
|
+
))}
|
|
273
|
+
</div>
|
|
274
|
+
</Col>
|
|
275
|
+
</Row>
|
|
276
|
+
<Divider style={{ borderColor: token.colorBorderSecondary, margin: '24px 0 16px' }} />
|
|
277
|
+
<Text type="secondary" style={{ display: 'block', textAlign: 'center', fontSize: 12, opacity: 0.6 }}>
|
|
278
|
+
Scaffolded with Nexstruct — {new Date().getFullYear()}
|
|
279
|
+
</Text>
|
|
280
|
+
</Footer>
|
|
281
|
+
</Layout>
|
|
282
|
+
);
|
|
283
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Table, Typography } from 'antd';
|
|
4
|
+
import type { ColumnsType, TableRowSelection } from 'antd/es/table/interface';
|
|
5
|
+
|
|
6
|
+
const { Text } = Typography;
|
|
7
|
+
|
|
8
|
+
export type TableColumn = {
|
|
9
|
+
key: string;
|
|
10
|
+
header: string;
|
|
11
|
+
className?: string;
|
|
12
|
+
render?: (item: any, index: number) => React.ReactNode;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type TableConfig = {
|
|
16
|
+
columns: TableColumn[];
|
|
17
|
+
emptyMessage?: string;
|
|
18
|
+
rowClassName?: (item: any) => string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
interface DynamicTableProps {
|
|
22
|
+
isLoading: boolean;
|
|
23
|
+
config: TableConfig;
|
|
24
|
+
data: any[];
|
|
25
|
+
isCheckBox?: boolean;
|
|
26
|
+
selectedIds?: string[];
|
|
27
|
+
setSelectedIds?: (ids: string[]) => void;
|
|
28
|
+
setSelectObject?: (data: any[]) => void;
|
|
29
|
+
rowKey?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function DynamicTable({
|
|
33
|
+
data, isLoading, config, isCheckBox = false,
|
|
34
|
+
selectedIds = [], setSelectedIds = () => {}, setSelectObject = () => {},
|
|
35
|
+
rowKey = 'id',
|
|
36
|
+
}: DynamicTableProps) {
|
|
37
|
+
const columns: ColumnsType<any> = config.columns.map((col) => ({
|
|
38
|
+
key: col.key,
|
|
39
|
+
title: col.header,
|
|
40
|
+
dataIndex: col.key,
|
|
41
|
+
className: col.className,
|
|
42
|
+
render: col.render ? (_val: any, record: any, index: number) => col.render!(record, index) : undefined,
|
|
43
|
+
ellipsis: true,
|
|
44
|
+
}));
|
|
45
|
+
|
|
46
|
+
const rowSelection: TableRowSelection<any> | undefined = isCheckBox
|
|
47
|
+
? {
|
|
48
|
+
selectedRowKeys: selectedIds,
|
|
49
|
+
onChange: (selectedRowKeys: React.Key[], selectedRows: any[]) => {
|
|
50
|
+
setSelectedIds(selectedRowKeys as string[]);
|
|
51
|
+
setSelectObject(selectedRows);
|
|
52
|
+
},
|
|
53
|
+
preserveSelectedRowKeys: true,
|
|
54
|
+
}
|
|
55
|
+
: undefined;
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<div className="antd-dynamic-table">
|
|
59
|
+
<Table
|
|
60
|
+
columns={columns}
|
|
61
|
+
dataSource={data}
|
|
62
|
+
loading={isLoading}
|
|
63
|
+
rowKey={rowKey}
|
|
64
|
+
rowClassName={(record) => config.rowClassName?.(record) || ''}
|
|
65
|
+
rowSelection={rowSelection}
|
|
66
|
+
pagination={false}
|
|
67
|
+
locale={{
|
|
68
|
+
emptyText: isLoading ? null : (
|
|
69
|
+
<div style={{ padding: 48, textAlign: 'center' }}>
|
|
70
|
+
<Text type="secondary">{config.emptyMessage || 'No data available'}</Text>
|
|
71
|
+
</div>
|
|
72
|
+
),
|
|
73
|
+
}}
|
|
74
|
+
size="middle"
|
|
75
|
+
scroll={{ x: 'max-content' }}
|
|
76
|
+
/>
|
|
77
|
+
</div>
|
|
78
|
+
);
|
|
79
|
+
}
|