106 lines
7.4 KiB
TypeScript
106 lines
7.4 KiB
TypeScript
"use client";
|
||
|
||
import Link from "next/link";
|
||
import { useEffect, useMemo, useState } from "react";
|
||
import data from "../data/content-templates.json";
|
||
import styles from "./SimpleList.module.css";
|
||
|
||
const categories = ["全部", "世界观", "制作资料", "角色", "音乐", "品牌", "运营"];
|
||
const statusStyles: Record<string, string> = {
|
||
"已发布": "statusPublished",
|
||
"评审中": "statusReview",
|
||
"草稿": "statusDraft",
|
||
"已归档": "statusArchived",
|
||
};
|
||
|
||
export default function SimpleListPage() {
|
||
const [query, setQuery] = useState("");
|
||
const [category, setCategory] = useState("全部");
|
||
const [status, setStatus] = useState("全部状态");
|
||
const [selected, setSelected] = useState<string[]>([]);
|
||
const [favorites, setFavorites] = useState<string[]>(data.listItems.filter((item) => item.favorite).map((item) => item.id));
|
||
const [toast, setToast] = useState("");
|
||
const [compact, setCompact] = useState(false);
|
||
|
||
useEffect(() => {
|
||
const saved = window.localStorage.getItem("orbit-simple-list-favorites");
|
||
if (saved) {
|
||
try { setFavorites(JSON.parse(saved)); } catch { /* use JSON defaults */ }
|
||
}
|
||
}, []);
|
||
|
||
useEffect(() => {
|
||
window.localStorage.setItem("orbit-simple-list-favorites", JSON.stringify(favorites));
|
||
}, [favorites]);
|
||
|
||
const items = useMemo(() => data.listItems.filter((item) => {
|
||
const matchQuery = `${item.title}${item.description}${item.id}${item.tags.join("")}`.toLowerCase().includes(query.toLowerCase());
|
||
return matchQuery && (category === "全部" || item.category === category) && (status === "全部状态" || item.status === status);
|
||
}), [query, category, status]);
|
||
|
||
const notify = (message: string) => {
|
||
setToast(message);
|
||
window.setTimeout(() => setToast(""), 2000);
|
||
};
|
||
|
||
const toggleAll = () => setSelected(selected.length === items.length ? [] : items.map((item) => item.id));
|
||
|
||
return (
|
||
<div className={styles.page}>
|
||
<header className={styles.topbar}>
|
||
<Link className={styles.brand} href="/"><span>O</span><strong>Orbit Docs</strong></Link>
|
||
<nav><Link className={styles.active} href="/simple-list">简单列表</Link><Link href="/character">角色详情</Link><Link href="/markdown">Markdown 编辑器</Link></nav>
|
||
<div className={styles.topActions}><button onClick={() => notify("帮助中心为模板占位")}>?</button><span>林</span></div>
|
||
</header>
|
||
|
||
<main className={styles.content}>
|
||
<div className={styles.heading}>
|
||
<div><p>CONTENT LIBRARY</p><h1>内容资料库</h1><span>轻量、清晰的通用列表模板,适合文档、项目或数据记录。</span></div>
|
||
<button className={styles.createButton} onClick={() => notify("新建资料表单为模板占位")}>+ 新建资料</button>
|
||
</div>
|
||
|
||
<section className={styles.summary}>
|
||
<div><span className={styles.iconPurple}>▤</span><p><small>全部资料</small><strong>{data.listItems.length}</strong></p></div>
|
||
<div><span className={styles.iconGreen}>✓</span><p><small>已发布</small><strong>{data.listItems.filter((item) => item.status === "已发布").length}</strong></p></div>
|
||
<div><span className={styles.iconOrange}>◷</span><p><small>等待评审</small><strong>{data.listItems.filter((item) => item.status === "评审中").length}</strong></p></div>
|
||
<div><span className={styles.iconBlue}>★</span><p><small>我的收藏</small><strong>{favorites.length}</strong></p></div>
|
||
</section>
|
||
|
||
<section className={styles.listPanel}>
|
||
<div className={styles.categoryTabs}>
|
||
{categories.map((item) => <button key={item} className={category === item ? styles.tabActive : ""} onClick={() => setCategory(item)}>{item}</button>)}
|
||
</div>
|
||
<div className={styles.toolbar}>
|
||
<label className={styles.search}><span>⌕</span><input value={query} onChange={(event) => setQuery(event.target.value)} placeholder="搜索标题、编号或标签" />{query && <button onClick={() => setQuery("")}>×</button>}</label>
|
||
<select value={status} onChange={(event) => setStatus(event.target.value)}><option>全部状态</option><option>已发布</option><option>评审中</option><option>草稿</option><option>已归档</option></select>
|
||
<button className={styles.filterButton} onClick={() => { setQuery(""); setCategory("全部"); setStatus("全部状态"); }}>清除筛选</button>
|
||
<div className={styles.viewToggle}><button className={!compact ? styles.viewActive : ""} onClick={() => setCompact(false)}>☷</button><button className={compact ? styles.viewActive : ""} onClick={() => setCompact(true)}>☰</button></div>
|
||
</div>
|
||
|
||
{selected.length > 0 && <div className={styles.bulkBar}><strong>已选择 {selected.length} 项</strong><button onClick={() => notify("已添加到收藏")}>收藏</button><button onClick={() => notify("已移动到归档")}>归档</button><button onClick={() => setSelected([])}>取消选择</button></div>}
|
||
|
||
<div className={`${styles.list} ${compact ? styles.compact : ""}`}>
|
||
<div className={styles.listHeader}><input type="checkbox" checked={items.length > 0 && selected.length === items.length} onChange={toggleAll} aria-label="全选" /><span>资料名称</span><span>分类</span><span>状态</span><span>负责人</span><span>更新时间</span><span /></div>
|
||
{items.map((item) => {
|
||
const checked = selected.includes(item.id);
|
||
const favorite = favorites.includes(item.id);
|
||
return <article key={item.id} className={checked ? styles.rowSelected : ""}>
|
||
<input type="checkbox" checked={checked} onChange={() => setSelected((current) => checked ? current.filter((id) => id !== item.id) : [...current, item.id])} aria-label={`选择 ${item.title}`} />
|
||
<button className={styles.titleCell} onClick={() => notify(`打开:${item.title}`)}><span>{item.category.slice(0, 1)}</span><div><strong>{item.title}</strong><p>{item.description}</p><small>{item.id} {item.tags.map((tag) => <i key={tag}>#{tag}</i>)}</small></div></button>
|
||
<span className={styles.category}>{item.category}</span>
|
||
<span className={`${styles.status} ${styles[statusStyles[item.status]]}`}><i />{item.status}</span>
|
||
<span className={styles.owner}><i>{item.initial}</i>{item.owner}</span>
|
||
<time>{item.updated}</time>
|
||
<div className={styles.rowActions}><button className={favorite ? styles.favorite : ""} onClick={() => setFavorites((current) => favorite ? current.filter((id) => id !== item.id) : [...current, item.id])}>★</button><button onClick={() => notify("更多操作:复制、移动、归档")}>•••</button></div>
|
||
</article>;
|
||
})}
|
||
{items.length === 0 && <div className={styles.empty}><span>⌕</span><strong>没有找到匹配资料</strong><p>调整关键词或筛选条件后再试试。</p><button onClick={() => { setQuery(""); setCategory("全部"); setStatus("全部状态"); }}>重置筛选</button></div>}
|
||
</div>
|
||
<footer className={styles.pagination}><span>显示 {items.length} 条,共 {data.listItems.length} 条</span><div><button disabled>←</button><button className={styles.pageActive}>1</button><button>2</button><button>→</button></div></footer>
|
||
</section>
|
||
</main>
|
||
{toast && <div className={styles.toast}>✓ {toast}</div>}
|
||
</div>
|
||
);
|
||
}
|