Skip to content

Commit dcb0019

Browse files
CopilotTechQuery
andauthored
[add] 5 MobX-RESTful form components with Shadcn UI (#3)
Co-authored-by: TechQuery <shiy2008@gmail.com>
1 parent 2875c6d commit dcb0019

15 files changed

Lines changed: 957 additions & 146 deletions

File tree

app/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export default function RootLayout({
1414
children: React.ReactNode;
1515
}>) {
1616
return (
17-
<html lang="en">
17+
<html lang="en-US">
1818
<head>
1919
<link rel="preconnect" href="https://fonts.googleapis.com" />
2020
<link

app/page.tsx

Lines changed: 102 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { OpenInV0Button } from "@/components/open-in-v0-button";
1+
import { ComponentCard } from "@/components/component-card";
22
import { HelloWorld } from "@/registry/new-york/blocks/hello-world/hello-world";
33
import { ExampleForm } from "@/registry/new-york/blocks/example-form/example-form";
44
import PokemonPage from "@/registry/new-york/blocks/complex-component/page";
@@ -9,8 +9,11 @@ import { ImagePreviewExample } from "@/registry/new-york/blocks/image-preview/ex
99
import { FilePreviewExample } from "@/registry/new-york/blocks/file-preview/example";
1010
import { ScrollBoundaryExample } from "@/registry/new-york/blocks/scroll-boundary/example";
1111
import { ScrollListExample } from "@/registry/new-york/blocks/scroll-list/example";
12-
// This page displays items from the custom registry.
13-
// You are free to implement this with your own design as needed.
12+
import { ArrayFieldExample } from "@/registry/new-york/blocks/array-field/example";
13+
import { BadgeInputExample } from "@/registry/new-york/blocks/badge-input/example";
14+
import { RangeInputExample } from "@/registry/new-york/blocks/range-input/example";
15+
import { FilePickerExample } from "@/registry/new-york/blocks/file-picker/example";
16+
import { FormFieldExample } from "@/registry/new-york/blocks/form-field/example";
1417

1518
export default function Home() {
1619
return (
@@ -22,129 +25,111 @@ export default function Home() {
2225
</p>
2326
</header>
2427
<main className="flex flex-col flex-1 gap-8">
25-
<div className="flex flex-col gap-4 border rounded-lg p-4 min-h-[450px] relative">
26-
<div className="flex items-center justify-between">
27-
<h2 className="text-sm text-muted-foreground sm:pl-3">
28-
A simple hello world component
29-
</h2>
30-
<OpenInV0Button name="hello-world" className="w-fit" />
31-
</div>
32-
<div className="flex items-center justify-center min-h-[400px] relative">
33-
<HelloWorld />
34-
</div>
35-
</div>
28+
<ComponentCard
29+
name="hello-world"
30+
description="A simple hello world component"
31+
>
32+
<HelloWorld />
33+
</ComponentCard>
3634

37-
<div className="flex flex-col gap-4 border rounded-lg p-4 min-h-[450px] relative">
38-
<div className="flex items-center justify-between">
39-
<h2 className="text-sm text-muted-foreground sm:pl-3">
40-
A contact form with Zod validation.
41-
</h2>
42-
<OpenInV0Button name="example-form" className="w-fit" />
43-
</div>
44-
<div className="flex items-center justify-center min-h-[500px] relative">
45-
<ExampleForm />
46-
</div>
47-
</div>
35+
<ComponentCard
36+
name="example-form"
37+
description="A contact form with Zod validation."
38+
minHeight="min-h-[500px]"
39+
>
40+
<ExampleForm />
41+
</ComponentCard>
4842

49-
<div className="flex flex-col gap-4 border rounded-lg p-4 min-h-[450px] relative">
50-
<div className="flex items-center justify-between">
51-
<h2 className="text-sm text-muted-foreground sm:pl-3">
52-
A complex component showing hooks, libs and components.
53-
</h2>
54-
<OpenInV0Button name="complex-component" className="w-fit" />
55-
</div>
56-
<div className="flex items-center justify-center min-h-[400px] relative">
57-
<PokemonPage />
58-
</div>
59-
</div>
43+
<ComponentCard
44+
name="complex-component"
45+
description="A complex component showing hooks, libs and components."
46+
>
47+
<PokemonPage />
48+
</ComponentCard>
6049

61-
<div className="flex flex-col gap-4 border rounded-lg p-4 min-h-[450px] relative">
62-
<div className="flex items-center justify-between">
63-
<h2 className="text-sm text-muted-foreground sm:pl-3">
64-
A login form with a CSS file.
65-
</h2>
66-
<OpenInV0Button name="example-with-css" className="w-fit" />
67-
</div>
68-
<div className="flex items-center justify-center min-h-[400px] relative">
69-
<ExampleCard />
70-
</div>
71-
</div>
50+
<ComponentCard
51+
name="example-with-css"
52+
description="A login form with a CSS file."
53+
>
54+
<ExampleCard />
55+
</ComponentCard>
7256

73-
<div className="flex flex-col gap-4 border rounded-lg p-4 min-h-[450px] relative">
74-
<div className="flex items-center justify-between">
75-
<h2 className="text-sm text-muted-foreground sm:pl-3">
76-
A component for displaying a list of badges with optional click
77-
and delete handlers.
78-
</h2>
79-
<OpenInV0Button name="badge-bar" className="w-fit" />
80-
</div>
81-
<div className="flex items-center justify-center min-h-[400px] relative">
82-
<BadgeBarExample />
83-
</div>
84-
</div>
57+
<ComponentCard
58+
name="badge-bar"
59+
description="A component for displaying a list of badges with optional click and delete handlers."
60+
>
61+
<BadgeBarExample />
62+
</ComponentCard>
8563

86-
<div className="flex flex-col gap-4 border rounded-lg p-4 min-h-[450px] relative">
87-
<div className="flex items-center justify-between">
88-
<h2 className="text-sm text-muted-foreground sm:pl-3">
89-
A pagination component with page size and page index controls.
90-
</h2>
91-
<OpenInV0Button name="pager" className="w-fit" />
92-
</div>
93-
<div className="flex items-center justify-center min-h-[400px] relative">
94-
<PagerExample />
95-
</div>
96-
</div>
64+
<ComponentCard
65+
name="pager"
66+
description="A pagination component with page size and page index controls."
67+
>
68+
<PagerExample />
69+
</ComponentCard>
9770

98-
<div className="flex flex-col gap-4 border rounded-lg p-4 min-h-[450px] relative">
99-
<div className="flex items-center justify-between">
100-
<h2 className="text-sm text-muted-foreground sm:pl-3">
101-
An image preview component with modal viewing and download
102-
functionality.
103-
</h2>
104-
<OpenInV0Button name="image-preview" className="w-fit" />
105-
</div>
106-
<div className="flex items-center justify-center min-h-[400px] relative">
107-
<ImagePreviewExample />
108-
</div>
109-
</div>
71+
<ComponentCard
72+
name="image-preview"
73+
description="An image preview component with modal viewing and download functionality."
74+
>
75+
<ImagePreviewExample />
76+
</ComponentCard>
11077

111-
<div className="flex flex-col gap-4 border rounded-lg p-4 min-h-[450px] relative">
112-
<div className="flex items-center justify-between">
113-
<h2 className="text-sm text-muted-foreground sm:pl-3">
114-
A file preview component supporting images, audio, video, and
115-
documents.
116-
</h2>
117-
<OpenInV0Button name="file-preview" className="w-fit" />
118-
</div>
119-
<div className="flex items-center justify-center min-h-[400px] relative">
120-
<FilePreviewExample />
121-
</div>
122-
</div>
78+
<ComponentCard
79+
name="file-preview"
80+
description="A file preview component supporting images, audio, video, and documents."
81+
>
82+
<FilePreviewExample />
83+
</ComponentCard>
12384

124-
<div className="flex flex-col gap-4 border rounded-lg p-4 min-h-[450px] relative">
125-
<div className="flex items-center justify-between">
126-
<h2 className="text-sm text-muted-foreground sm:pl-3">
127-
A component that detects when scroll reaches edges using
128-
IntersectionObserver.
129-
</h2>
130-
<OpenInV0Button name="scroll-boundary" className="w-fit" />
131-
</div>
132-
<div className="flex items-center justify-center min-h-[400px] relative">
133-
<ScrollBoundaryExample />
134-
</div>
135-
</div>
85+
<ComponentCard
86+
name="scroll-boundary"
87+
description="A component that detects when scroll reaches edges using IntersectionObserver."
88+
>
89+
<ScrollBoundaryExample />
90+
</ComponentCard>
13691

137-
<div className="flex flex-col gap-4 border rounded-lg p-4 min-h-[450px] relative">
138-
<div className="flex items-center justify-between">
139-
<h2 className="text-sm text-muted-foreground sm:pl-3">
140-
An infinite scroll list component using MobX for state management.
141-
</h2>
142-
<OpenInV0Button name="scroll-list" className="w-fit" />
143-
</div>
144-
<div className="flex items-center justify-center min-h-[400px] relative">
145-
<ScrollListExample />
146-
</div>
147-
</div>
92+
<ComponentCard
93+
name="scroll-list"
94+
description="An infinite scroll list component using MobX for state management."
95+
>
96+
<ScrollListExample />
97+
</ComponentCard>
98+
99+
<ComponentCard
100+
name="array-field"
101+
description="A dynamic array field component with add/remove functionality for form arrays."
102+
>
103+
<ArrayFieldExample />
104+
</ComponentCard>
105+
106+
<ComponentCard
107+
name="badge-input"
108+
description="An input component that displays values as removable badges, supporting multiple entries."
109+
>
110+
<BadgeInputExample />
111+
</ComponentCard>
112+
113+
<ComponentCard
114+
name="range-input"
115+
description="A range slider input with optional custom icon display for each step."
116+
>
117+
<RangeInputExample />
118+
</ComponentCard>
119+
120+
<ComponentCard
121+
name="file-picker"
122+
description="A file picker component with preview and remove functionality."
123+
>
124+
<FilePickerExample />
125+
</ComponentCard>
126+
127+
<ComponentCard
128+
name="form-field"
129+
description="A unified form field component supporting input, textarea, and select elements with labels."
130+
>
131+
<FormFieldExample />
132+
</ComponentCard>
148133
</main>
149134
</div>
150135
);

components/component-card.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { FC, PropsWithChildren } from "react";
2+
3+
import { OpenInV0Button } from "./open-in-v0-button";
4+
5+
export type ComponentCardProps = PropsWithChildren<{
6+
name: string;
7+
description: string;
8+
minHeight?: string;
9+
}>;
10+
11+
export const ComponentCard: FC<ComponentCardProps> = ({
12+
name,
13+
description,
14+
children,
15+
minHeight = "min-h-[400px]",
16+
}) => (
17+
<div className="flex flex-col gap-4 border rounded-lg p-4 min-h-[450px] relative">
18+
<div className="flex items-center justify-between">
19+
<h2 className="text-sm text-muted-foreground sm:pl-3">{description}</h2>
20+
<OpenInV0Button name={name} className="w-fit" />
21+
</div>
22+
<div className={`flex items-center justify-center ${minHeight} relative`}>
23+
{children}
24+
</div>
25+
</div>
26+
);

components/index.ini

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
badge
22
button
33
dialog
4-
input
4+
input
5+
label

0 commit comments

Comments
 (0)