diff --git a/src/db/entries.rs b/src/db/entries.rs index d56cde7..6709633 100644 --- a/src/db/entries.rs +++ b/src/db/entries.rs @@ -31,6 +31,7 @@ pub struct EntryRecord { } #[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct EntryPatch { pub name: String, #[serde(default)] diff --git a/stash-web/src/App.css b/stash-web/src/App.css index b0fc63e..dcb1cb7 100644 --- a/stash-web/src/App.css +++ b/stash-web/src/App.css @@ -1029,7 +1029,7 @@ .admin-entry-row { display: grid; - grid-template-columns: minmax(0, 1fr) 140px auto; + grid-template-columns: minmax(0, 1fr) 140px auto auto; align-items: center; gap: var(--su-space-2); padding: var(--su-space-2) 0; diff --git a/stash-web/src/components/admin/AdminPage.tsx b/stash-web/src/components/admin/AdminPage.tsx index df317f6..ca56bdd 100644 --- a/stash-web/src/components/admin/AdminPage.tsx +++ b/stash-web/src/components/admin/AdminPage.tsx @@ -37,7 +37,7 @@ import { type SettingsTone, type SiteSettings, } from '../../settings' -import { createItem, deleteItem } from '../../items' +import { createItem, deleteItem, fetchItem, saveItem } from '../../items' /** * 站点设置页(/admin):页头滚动信息 + 侧栏顺序/显隐。 @@ -538,6 +538,12 @@ function SidebarForm({ /> ))} + + {category.kind === 'apps' && ( +
+ +
+ )} ) })} @@ -1051,7 +1057,13 @@ function NewGroupRow({ sectionId, onReload }: { sectionId: string; onReload: () ) } -// ---------- 内容(新增条目) ---------- +// ---------- 内容(条目列表 + 新增/编辑弹窗) ---------- + +type EntryRow = EntrySummary & { + groupName?: string + sectionId: string + groupId?: string +} function ContentManager({ categories, @@ -1061,23 +1073,16 @@ function ContentManager({ onReload: () => void }) { const [sectionId, setSectionId] = useState(categories[0]?.id ?? '') - const [groupId, setGroupId] = useState('') - const [key, setKey] = useState('') - const [name, setName] = useState('') - const [href, setHref] = useState('') - const [description, setDescription] = useState('') - const [icon, setIcon] = useState('') - const [cover, setCover] = useState('') - const [tags, setTags] = useState('') - const [comment, setComment] = useState('') - const [body, setBody] = useState('') - const [busy, setBusy] = useState(false) - const [pendingEntry, setPendingEntry] = useState(null) + const [dialog, setDialog] = useState<{ + open: boolean + key: string | null + location: { sectionId: string; groupId?: string } | null + }>({ open: false, key: null, location: null }) + const [pendingEntry, setPendingEntry] = useState(null) const [deleting, setDeleting] = useState(false) const section = categories.find((category) => category.id === sectionId) ?? categories[0] - const groups = section?.kind === 'apps' ? (section.groups ?? []) : [] useEffect(() => { if (categories.length === 0) return @@ -1086,17 +1091,7 @@ function ContentManager({ } }, [categories, sectionId]) - useEffect(() => { - if (section?.kind !== 'apps') return - if (!groups.some((group) => group.id === groupId)) { - setGroupId(groups[0]?.id ?? '') - } - }, [section, groups, groupId]) - - const nodeKey = - section === undefined ? '' : section.kind === 'apps' ? groupId : section.id - - const entries = + const entries: EntryRow[] = section === undefined ? [] : section.kind === 'apps' @@ -1104,56 +1099,15 @@ function ContentManager({ (group.items ?? []).map((item) => ({ ...item, groupName: group.name, + sectionId: section.id, + groupId: group.id, })), ) - : (section.items ?? []).map((item) => ({ ...item, groupName: undefined })) - - const submit = async () => { - if (section === undefined || nodeKey === '') { - toast.error('请先选择分区与分组') - return - } - - setBusy(true) - const result = await createItem({ - key: key.trim(), - nodeKey, - item: { - name: name.trim(), - description, - icon, - tags: tags - .split(/[,,]/) - .map((tag) => tag.trim()) - .filter(Boolean), - badge: '', - comment, - summary: '', - body, - cover, - banner: '', - href, - }, - }) - setBusy(false) - - if (!result.ok) { - toast.error(result.error) - return - } - - toast.success(`已添加「${name.trim()}」`) - setKey('') - setName('') - setHref('') - setDescription('') - setIcon('') - setCover('') - setTags('') - setComment('') - setBody('') - onReload() - } + : (section.items ?? []).map((item) => ({ + ...item, + groupName: undefined, + sectionId: section.id, + })) const removeEntry = async () => { if (pendingEntry === null) return @@ -1172,8 +1126,8 @@ function ContentManager({ return ( - 在下面新增网址 / 海报 / 图文条目,并选择它挂在哪个分区、哪个分组(应用类必须选分组)。 - 新增后,分组出现在侧栏与首页卡片的条件是它被设为显示。 + 新增网址 / 海报 / 图文条目时,选择它挂在哪个分区、哪个分组(应用类必须选分组); + 列表里的条目可以点铅笔修改,包括换分区 / 分组。 @@ -1187,95 +1141,15 @@ function ContentManager({ onChange={setSectionId} /> - - {section?.kind === 'apps' && ( -
- setKey(event.target.value)} - /> - setName(event.target.value)} - /> - setHref(event.target.value)} - /> - setIcon(event.target.value)} - /> - setDescription(event.target.value)} - /> - setCover(event.target.value)} - /> - setTags(event.target.value)} - /> - setComment(event.target.value)} - /> -
-