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
2026-08-27 20:15:24 +08:00

106 lines
7.4 KiB
TypeScript
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 { 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>
);
}