feat: 迁移到 shadcn base-nova (Base UI) 4.22.1, 50 组件 + DatePicker, 同步脚本
This commit is contained in:
@@ -2,8 +2,8 @@
|
||||
import { execSync } from "node:child_process"
|
||||
import { readFileSync } from "node:fs"
|
||||
|
||||
const MAX_PACKED_KB = 150, MAX_UNPACKED_KB = 600, MAX_FILES = 60
|
||||
const ALLOWED = [/^package\.json$/, /^README\.md$/, /^src\/.+\.(tsx?|css)$/]
|
||||
const MAX_PACKED_KB = 150, MAX_UNPACKED_KB = 600, MAX_FILES = 80
|
||||
const ALLOWED = [/^package\.json$/, /^README\.md$/, /^src\/.+\.(tsx?|css)$/, /^src\/UPSTREAM\.json$/]
|
||||
const SECRET_PATTERNS = [
|
||||
[/-----BEGIN [A-Z ]*PRIVATE KEY-----/, "私钥"],
|
||||
[/\b[0-9a-f]{40}\b/i, "40位hex(疑似 Gitea/GitHub token)"],
|
||||
|
||||
75
scripts/sync-shadcn.py
Normal file
75
scripts/sync-shadcn.py
Normal file
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env python3
|
||||
"""用官方 shadcn CLI 同步组件到 src/components/ui, 并把 import 改写成包内相对路径。
|
||||
用法: python3 scripts/sync-shadcn.py (style 固定 base-nova = Base UI)
|
||||
升级流程: 跑本脚本 → git diff 审查 → npx tsc → 改版本号 → npm publish。
|
||||
依赖: node + npm 可联网 (registry 用 $NPM_REGISTRY, 默认 npmmirror)。"""
|
||||
import json, os, re, shutil, subprocess, sys, tempfile
|
||||
|
||||
STYLE = "base-nova"
|
||||
REG = os.environ.get("NPM_REGISTRY", "https://registry.npmmirror.com")
|
||||
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
UI = os.path.join(ROOT, "src/components/ui")
|
||||
HOOKS = os.path.join(ROOT, "src/hooks")
|
||||
|
||||
COMPONENTS = """accordion alert alert-dialog aspect-ratio avatar badge breadcrumb button button-group
|
||||
calendar card carousel chart checkbox collapsible combobox command dialog drawer dropdown-menu empty
|
||||
field hover-card input input-group input-otp item kbd label native-select pagination popover progress
|
||||
radio-group scroll-area select separator sheet sidebar skeleton slider sonner spinner switch table
|
||||
tabs textarea toggle toggle-group tooltip""".split()
|
||||
|
||||
|
||||
def run(cmd, cwd):
|
||||
r = subprocess.run(cmd, cwd=cwd, capture_output=True, text=True, timeout=280)
|
||||
return r.returncode, (r.stdout + r.stderr)[-1500:]
|
||||
|
||||
|
||||
def rewrite(c):
|
||||
c = c.replace('from "cn"', 'from "../../lib/utils"')
|
||||
c = c.replace('from "@/lib/utils"', 'from "../../lib/utils"')
|
||||
c = re.sub(r'from "@/components/ui/([\w-]+)"', r'from "./\1"', c)
|
||||
c = re.sub(r'from "@/hooks/([\w-]+)"', r'from "../../hooks/\1"', c)
|
||||
return c
|
||||
|
||||
|
||||
def main():
|
||||
tmp = tempfile.mkdtemp(prefix="shsync-", dir=os.environ.get("TMPDIR"))
|
||||
open(f"{tmp}/package.json", "w").write(json.dumps({
|
||||
"name": "scaf", "private": True, "type": "module",
|
||||
"dependencies": {"react": "^19.0.0", "react-dom": "^19.0.0"},
|
||||
"devDependencies": {"tailwindcss": "^4.1.0", "typescript": "^5.9.0", "shadcn": "latest"}}))
|
||||
os.makedirs(f"{tmp}/src")
|
||||
open(f"{tmp}/src/index.css", "w").write('@import "tailwindcss";\n')
|
||||
open(f"{tmp}/tsconfig.json", "w").write(json.dumps({"compilerOptions": {
|
||||
"jsx": "react-jsx", "baseUrl": ".", "paths": {"@/*": ["./src/*"]}}}))
|
||||
open(f"{tmp}/components.json", "w").write(json.dumps({
|
||||
"$schema": "https://ui.shadcn.com/schema.json", "style": STYLE, "rsc": False, "tsx": True,
|
||||
"tailwind": {"config": "", "css": "src/index.css", "baseColor": "neutral", "cssVariables": True, "prefix": ""},
|
||||
"iconLibrary": "lucide",
|
||||
"aliases": {"components": "@/components", "utils": "@/lib/utils", "ui": "@/components/ui",
|
||||
"lib": "@/lib", "hooks": "@/hooks"}}))
|
||||
print("npm i:", run(["npm", "i", "--registry", REG, "--no-audit", "--no-fund"], tmp)[0])
|
||||
code, out = run(["npx", "shadcn", "add", *COMPONENTS, "--yes", "--overwrite"], tmp)
|
||||
print("shadcn add:", code)
|
||||
src_ui = f"{tmp}/src/components/ui"
|
||||
if not os.path.isdir(src_ui):
|
||||
sys.exit("CLI 未产出组件, 中止 (未改动包内文件)")
|
||||
|
||||
shutil.rmtree(UI, ignore_errors=True)
|
||||
os.makedirs(UI)
|
||||
os.makedirs(HOOKS, exist_ok=True)
|
||||
for f in os.listdir(src_ui):
|
||||
open(f"{UI}/{f}", "w").write(rewrite(open(f"{src_ui}/{f}").read()))
|
||||
if os.path.isdir(f"{tmp}/src/hooks"):
|
||||
for f in os.listdir(f"{tmp}/src/hooks"):
|
||||
open(f"{HOOKS}/{f}", "w").write(rewrite(open(f"{tmp}/src/hooks/{f}").read()))
|
||||
pkg = json.load(open(f"{tmp}/node_modules/shadcn/package.json"))
|
||||
json.dump({"shadcn": pkg["version"], "style": STYLE},
|
||||
open(f"{ROOT}/src/UPSTREAM.json", "w"), indent=2)
|
||||
left = []
|
||||
for f in os.listdir(UI):
|
||||
left += re.findall(r'from "(@/[^"]+)"', open(f"{UI}/{f}").read())
|
||||
print("components:", len(os.listdir(UI)), "| shadcn", pkg["version"], "| unresolved @/ imports:", left)
|
||||
shutil.rmtree(tmp, ignore_errors=True)
|
||||
|
||||
|
||||
main()
|
||||
Reference in New Issue
Block a user