ai

Shadcn UI กับ Automation Script — วิธีสร้าง UI

shadcn ui automation script
Shadcn UI กับ Automation Script — วิธีสร้าง UI

Shadcn UI คืออะไร

Shadcn UI กับ Automation Script — วิธีสร้าง UI

Shadcn UI เป็น Component Library แนวใหม่ที่ไม่ได้ติดตั้งเป็น npm package แต่ Copy Source Code ลงในโปรเจคโดยตรง ทำให้ Developer มี Full Control สามารถปรับแต่ง Component ได้ตามต้องการ สร้างบน Radix UI Primitives (Accessible) และ Tailwind CSS (Styling)

การใช้ Automation Scripts ร่วมกับ Shadcn UI ช่วยเพิ่มประสิทธิภาพในการ Setup Project, Generate Components หลายตัวพร้อมกัน, Customize Theme อัตโนมัติ และสร้าง Documentation จาก Components

เนื้อหาเกี่ยวข้อง — ทำความเข้าใจ LLM Inference vLLM Event Driven Design —

Python Script — Component Generator

# shadcn_generator.py — Generate Custom Components จาก Template import os import json import subprocess from pathlib import Path from dataclasses import dataclass from typing import List, Optional @dataclass class ComponentSpec: name: str description: str props: dict shadcn_deps: List[str] template: str = "default" class ShadcnComponentGenerator: """Generate Custom Components บน Shadcn UI""" def __init__(self, project_path): self.project_path = Path(project_path) self.components_dir = self.project_path / "src" / "components" self.ui_dir = self.components_dir / "ui" def ensure_shadcn_deps(self, deps: List[str]): """ติดตั้ง Shadcn Components ที่จำเป็น""" for dep in deps: dep_file = self.ui_dir / f"{dep}.tsx" if not dep_file.exists(): print(f" Installing shadcn component: {dep}") subprocess.run( ["npx", "shadcn-ui@latest", "add", dep, "-y"], cwd=str(self.project_path), capture_output=True, ) def generate_data_table(self, name="data-table", columns=None): """Generate Data Table Component""" self.ensure_shadcn_deps(["table", "button", "input", "dropdown-menu", "badge"]) component_code = ''' "use client" import * as React from "react" import { ColumnDef, ColumnFiltersState, SortingState, VisibilityState, flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable, } from "@tanstack/react-table" import { ArrowUpDown, ChevronDown, MoreHorizontal } from "lucide-react" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table" import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" interface DataTableProps { columns: ColumnDef[] data: TData[] searchKey?: string searchPlaceholder?: string } export function DataTable({ columns, data, searchKey, searchPlaceholder = "Search...", }: DataTableProps) { const [sorting, setSorting] = React.useState([]) const [columnFilters, setColumnFilters] = React.useState([]) const [columnVisibility, setColumnVisibility] = React.useState({}) const [rowSelection, setRowSelection] = React.useState({}) const table = useReactTable({ data, columns, onSortingChange: setSorting, onColumnFiltersChange: setColumnFilters, getCoreRowModel: getCoreRowModel(), getPaginationRowModel: getPaginationRowModel(), getSortedRowModel: getSortedRowModel(), getFilteredRowModel: getFilteredRowModel(), onColumnVisibilityChange: setColumnVisibility, onRowSelectionChange: setRowSelection, state: { sorting, columnFilters, columnVisibility, rowSelection }, }) return (
{searchKey && ( table.getColumn(searchKey) ?.setFilterValue(e.target.value)} className="max-w-sm" /> )} {table.getAllColumns() .filter((col) => col.getCanHide()) .map((col) => ( col.toggleVisibility(!!v)} > {col.id} ))}
{table.getHeaderGroups().map((hg) => ( {hg.headers.map((h) => ( {h.isPlaceholder ? null : flexRender(h.column.columnDef.header, h.getContext())} ))} ))} {table.getRowModel().rows?.length ? ( table.getRowModel().rows.map((row) => ( {row.getVisibleCells().map((cell) => ( {flexRender(cell.column.columnDef.cell, cell.getContext())} ))} )) ) : ( No results. )}
{table.getFilteredSelectedRowModel().rows.length} of{" "} {table.getFilteredRowModel().rows.length} row(s) selected.
) } ''' output_path = self.components_dir / f"{name}.tsx" output_path.write_text(component_code.strip(), encoding="utf-8") print(f"Generated: {output_path}") def generate_component_index(self): """สร้าง Index File สำหรับ Export ทุก Components""" ui_files = sorted(self.ui_dir.glob("*.tsx")) exports = [] for f in ui_files: name = f.stem exports.append(f'export * from "./ui/{name}"') index_path = self.components_dir / "index.ts" index_path.write_text("\n".join(exports), encoding="utf-8") print(f"Generated index: {index_path} ({len(exports)} exports)") def audit_accessibility(self): """ตรวจสอบ Accessibility ของ Components""" issues = [] for f in self.ui_dir.glob("*.tsx"): content = f.read_text(encoding="utf-8", errors="ignore") # Check for aria labels if "
XM Legend · เทรดเดอร์ & ผู้สอน Forex 13 ปี

ผู้ก่อตั้ง SiamCafe ตั้งแต่ปี 1997 · เทรดเดอร์สาย Forex มากกว่า 13 ปี ได้รับการยกย่องเป็น XM Legend · แบ่งปันความรู้ Forex, ไอที, AI และการเทรด จากประสบการณ์จริงในตลาดจริง