This repository has been archived on 2026-08-27. You can view files and clone it, but cannot push or open issues or pull requests.
Files
RECS-WEB-MODLE-REACT/app/TemplateHub.tsx
2026-08-27 20:15:24 +08:00

124 lines
11 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import Link from "next/link";
import { CSSProperties, useMemo, useState } from "react";
import styles from "./TemplateHub.module.css";
type Category = "全部模板" | "后台业务" | "内容资料" | "可视化工具";
type TemplateItem = {
title: string;
english: string;
href: string;
category: Exclude<Category, "全部模板">;
icon: string;
description: string;
tags: string[];
color: string;
soft: string;
cover?: string;
featured?: boolean;
};
const categories: Category[] = ["全部模板", "后台业务", "内容资料", "可视化工具"];
const templates: TemplateItem[] = [
{ title: "后台组件总览", english: "ADMIN FOUNDATION", href: "/admin", category: "后台业务", icon: "▦", description: "标签、菜单、按钮、图文列表、定时任务等后台基础组件。", tags: ["组件库", "定时任务", "菜单"], color: "#356df3", soft: "#eaf1ff", featured: true },
{ title: "审批流程设计", english: "APPROVAL FLOW", href: "/approval", category: "后台业务", icon: "⌘", description: "类似飞书的前端审批流程图编辑器,支持节点配置。", tags: ["流程图", "节点编辑", "JSON"], color: "#7b61e8", soft: "#f0edff", featured: true },
{ title: "多级工作列表", english: "WORK LIST", href: "/worklist", category: "后台业务", icon: "☷", description: "树形多级表格、展开收起、状态筛选和批量操作。", tags: ["树形表格", "筛选", "批量操作"], color: "#315779", soft: "#eaf1f6" },
{ title: "泳道任务看板", english: "SWIMLANE KANBAN", href: "/kanban", category: "后台业务", icon: "▥", description: "卡片可在不同泳道之间拖动并即时更新状态。", tags: ["拖拽", "泳道", "任务卡片"], color: "#2d8a65", soft: "#e6f6ef" },
{ title: "响应式图床", english: "IMAGE HOST", href: "/image-host", category: "内容资料", icon: "▣", description: "瀑布流图片、三秒大图预览、单图详情与图集浏览。", tags: ["瀑布流", "图集", "悬停预览"], color: "#ef7955", soft: "#fff0e9", cover: "/anime/star-echoes-hero.png", featured: true },
{ title: "视频播放器", english: "VIDEO PLAYER", href: "/media-player", category: "内容资料", icon: "▶", description: "自定义视频控制器,支持进度、倍速、画中画与全屏。", tags: ["视频", "画中画", "本地文件"], color: "#5e63ef", soft: "#eeefff" },
{ title: "音乐播放器", english: "MUSIC PLAYER", href: "/music-player", category: "内容资料", icon: "♫", description: "独立音乐播放页,包含播放列表、波形进度和同步歌词。", tags: ["音乐", "歌词", "播放列表"], color: "#9a59df", soft: "#f5ecff" },
{ title: "时令事件日历", english: "SEASONAL CALENDAR", href: "/calendar", category: "内容资料", icon: "历", description: "按日期查看水果、海鲜应季期与阶段性事项,点击日期同步显示当天详情。", tags: ["日历", "应季时间", "事件详情"], color: "#d96246", soft: "#fff0e9" },
{ title: "全球产物地图", english: "GLOBAL PRODUCE MAP", href: "/produce-map", category: "可视化工具", icon: "地", description: "按中国、日本、中东、欧美等地区切换地图,高亮一级行政区并查看主要作物。", tags: ["地图", "行政区域", "主要产物"], color: "#2f8468", soft: "#e8f5ef" },
{ title: "动漫作品详情", english: "ANIME DETAIL", href: "/anime", category: "内容资料", icon: "星", description: "作品信息、商品展示、剧集列表和评论展示模板。", tags: ["作品", "商品", "评论"], color: "#6f57c9", soft: "#f0edfa", cover: "/anime/star-echoes-hero.png" },
{ title: "角色详情页", english: "CHARACTER PROFILE", href: "/character", category: "内容资料", icon: "人", description: "角色标签、关系、基本档案与剧情轨迹集中展示。", tags: ["角色", "标签", "关系"], color: "#9a5cc5", soft: "#f6edfb" },
{ title: "可重复表单", english: "REPEATABLE FORM", href: "/repeatable-form", category: "内容资料", icon: "F+", description: "可重复添加表单明细,并为每项配置图片和文件列表。", tags: ["动态表单", "图片", "文件"], color: "#3c72d9", soft: "#ebf2ff" },
{ title: "Markdown 编辑器", english: "MARKDOWN EDITOR", href: "/markdown", category: "内容资料", icon: "M↓", description: "Markdown 文档编辑、实时预览和浏览器本地保存。", tags: ["文档", "实时预览", "本地保存"], color: "#51586b", soft: "#eff1f5" },
{ title: "简单列表", english: "SIMPLE LIST", href: "/simple-list", category: "内容资料", icon: "≡", description: "轻量搜索、标签筛选、分页与批量操作列表。", tags: ["列表", "搜索", "标签"], color: "#625cb5", soft: "#eeedfa" },
{ title: "数据大屏", english: "DATA WALL", href: "/bigscreen", category: "可视化工具", icon: "◫", description: "适用于经营数据、实时指标和趋势图表的大屏模板。", tags: ["大屏", "指标", "图表"], color: "#16869a", soft: "#e5f6f8" },
{ title: "星空关系网络", english: "STAR GRAPH", href: "/stargraph", category: "可视化工具", icon: "✦", description: "星空超图节点、直线关联、悬停详情和 JSON 导入导出。", tags: ["关系图", "节点", "Canvas"], color: "#7063db", soft: "#efedff" },
{ title: "网页图标库", english: "WEB ICON LIBRARY", href: "/icons", category: "可视化工具", icon: "◇", description: "分类搜索、预览和复制代码的网页原生图标选择库。", tags: ["图标", "搜索", "代码复制"], color: "#38445b", soft: "#edf0f5" },
];
export default function TemplateHub() {
const [activeCategory, setActiveCategory] = useState<Category>("全部模板");
const [query, setQuery] = useState("");
const filtered = useMemo(() => templates.filter((item) => {
const matchesCategory = activeCategory === "全部模板" || item.category === activeCategory;
const searchable = `${item.title} ${item.english} ${item.description} ${item.tags.join(" ")}`.toLowerCase();
return matchesCategory && searchable.includes(query.trim().toLowerCase());
}), [activeCategory, query]);
const visibleGroups = categories.slice(1).map((category) => ({
category: category as Exclude<Category, "全部模板">,
items: filtered.filter((item) => item.category === category),
})).filter((group) => group.items.length > 0);
return (
<div className={styles.page}>
<header className={styles.header}>
<div className={styles.brand}><span>W</span><div><strong>WBBR</strong><small>AI FRONTEND STYLE SYSTEM</small></div></div>
<nav><a href="#templates"></a><a href="#about">使</a></nav>
<div className={styles.version}><i /> <b>v1.0</b></div>
</header>
<main>
<section className={styles.hero}>
<div className={styles.heroCopy}>
<p>AI FRONTEND STYLE REFERENCE</p>
<h1> AI <br /><em></em></h1>
<span>使 JSON </span>
<div className={styles.heroActions}><a href="#templates"> </a><Link href="/admin"> </Link></div>
</div>
<div className={styles.heroVisual} aria-hidden="true">
<div className={styles.visualWindow}><span><i /><i /><i /><b>wbbr.local/templates</b></span><div className={styles.visualBody}><aside><i /><i /><i /><i /></aside><main><p /><section><b /><b /><b /></section><div><i /><i /><i /><i /><i /><i /></div></main></div></div>
<div className={styles.floatingCard}><span></span><p><strong>{templates.length} </strong><small></small></p></div>
</div>
</section>
<section className={styles.featured} aria-label="精选模板">
{templates.filter((item) => item.featured).map((item, index) => <Link href={item.href} key={item.href} className={styles.featuredCard} style={{ "--accent": item.color, "--soft": item.soft } as CSSProperties}><span>0{index + 1}</span><div><small>{item.english}</small><strong>{item.title}</strong><p>{item.description}</p></div><b></b></Link>)}
</section>
<section className={styles.templates} id="templates">
<div className={styles.sectionHeading}><div><p>ALL TEMPLATES</p><h2></h2><span></span></div><label><span></span><input value={query} onChange={(event) => setQuery(event.target.value)} placeholder="搜索模板或功能" />{query && <button onClick={() => setQuery("")}>×</button>}</label></div>
<div className={styles.filters}>{categories.map((category) => <button key={category} className={activeCategory === category ? styles.filterActive : ""} onClick={() => setActiveCategory(category)}>{category}<b>{category === "全部模板" ? templates.length : templates.filter((item) => item.category === category).length}</b></button>)}</div>
{visibleGroups.map((group) => <section className={styles.group} key={group.category}>
<div className={styles.groupTitle}><span>{categoryIcon(group.category)}</span><div><h3>{group.category}</h3><p>{categoryDescription(group.category)}</p></div><b>{group.items.length}</b></div>
<div className={styles.grid}>{group.items.map((item) => <TemplateCard key={item.href} item={item} />)}</div>
</section>)}
{filtered.length === 0 && <div className={styles.empty}><span></span><h3></h3><p></p><button onClick={() => { setQuery(""); setActiveCategory("全部模板"); }}></button></div>}
</section>
<section className={styles.about} id="about"><div><p>LOCAL JSON · NO BACKEND</p><h2>便</h2></div><span> JSON </span><Link href="/admin"> </Link></section>
</main>
<footer><div><span>W</span><strong>WBBR</strong></div><p>AI · React JSON </p><a href="#templates"> </a></footer>
</div>
);
}
function TemplateCard({ item }: { item: TemplateItem }) {
const style = {
"--accent": item.color,
"--soft": item.soft,
...(item.cover ? { backgroundImage: `linear-gradient(135deg, rgba(12,18,32,.16), rgba(12,18,32,.62)), url(${item.cover})` } : {}),
} as CSSProperties;
return <Link href={item.href} className={`${styles.card} ${item.cover ? styles.cardWithCover : ""}`} style={style}>
<div className={styles.cardPreview}><span>{item.icon}</span><small>{item.english}</small><div><i /><i /><i /></div></div>
<div className={styles.cardBody}><div><strong>{item.title}</strong><b> </b></div><p>{item.description}</p><span>{item.tags.map((tag) => <i key={tag}>{tag}</i>)}</span></div>
</Link>;
}
function categoryIcon(category: Exclude<Category, "全部模板">) {
return category === "后台业务" ? "▦" : category === "内容资料" ? "◫" : "✦";
}
function categoryDescription(category: Exclude<Category, "全部模板">) {
return category === "后台业务" ? "流程、任务与管理工作台" : category === "内容资料" ? "列表、文档与内容展示" : "数据、关系与辅助工具";
}