style(admin): 分组管理表格整理
- 折叠箭头改成和前台侧栏 Menu 一样的 CSS 角标(6px 折角,展开/收起旋转) - 分组默认全部收起,首次拿到数据时统一折叠 - 操作列:加子分组 -> 新建子分组,并与编辑、删除一起配上图标 - 表格上方说明前加「说明:」
This commit is contained in:
+36
-3
@@ -975,22 +975,51 @@
|
|||||||
gap: var(--su-space-2);
|
gap: var(--su-space-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 折叠箭头:与前台侧栏 Menu 的 caret 同一套画法(CSS 画的 6px 角标) */
|
||||||
.group-caret {
|
.group-caret {
|
||||||
width: 20px;
|
display: inline-flex;
|
||||||
flex: none;
|
flex: none;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border: none;
|
border: none;
|
||||||
background: none;
|
background: none;
|
||||||
color: var(--su-text-muted);
|
color: var(--su-text-muted);
|
||||||
font-size: var(--su-font-size-sm);
|
|
||||||
line-height: 1;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.group-caret::before {
|
||||||
|
content: '';
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
border-left: 1px solid currentColor;
|
||||||
|
border-bottom: 1px solid currentColor;
|
||||||
|
opacity: 0.4;
|
||||||
|
transform: rotate(315deg);
|
||||||
|
transition:
|
||||||
|
transform var(--su-duration-base) var(--su-ease-in-out),
|
||||||
|
opacity var(--su-duration-base) var(--su-ease-in-out);
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-caret:hover::before {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-caret-open::before {
|
||||||
|
opacity: 0.7;
|
||||||
|
transform: rotate(135deg);
|
||||||
|
}
|
||||||
|
|
||||||
.group-caret-empty {
|
.group-caret-empty {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.group-caret-empty::before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* 分组图标选择:搜索 + 图标网格 */
|
/* 分组图标选择:搜索 + 图标网格 */
|
||||||
.icon-picker {
|
.icon-picker {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -1080,12 +1109,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.group-action {
|
.group-action {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--su-space-1);
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border: none;
|
border: none;
|
||||||
background: none;
|
background: none;
|
||||||
color: var(--su-color-primary);
|
color: var(--su-color-primary);
|
||||||
font-size: var(--su-font-size-sm);
|
font-size: var(--su-font-size-sm);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.group-action:hover {
|
.group-action:hover {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import {
|
|||||||
toast,
|
toast,
|
||||||
type IconName,
|
type IconName,
|
||||||
} from '@stash/ui'
|
} from '@stash/ui'
|
||||||
import { useEffect, useMemo, useState } from 'react'
|
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import { changePassword, fetchSession, logout, type SessionState } from '../../auth'
|
import { changePassword, fetchSession, logout, type SessionState } from '../../auth'
|
||||||
import { LoginDialog } from '../auth/LoginDialog'
|
import { LoginDialog } from '../auth/LoginDialog'
|
||||||
import { GroupMark as GroupGlyph } from '../common/GroupMark'
|
import { GroupMark as GroupGlyph } from '../common/GroupMark'
|
||||||
@@ -495,6 +495,24 @@ function GroupsPanel({
|
|||||||
const [collapsed, setCollapsed] = useState<Set<string>>(new Set())
|
const [collapsed, setCollapsed] = useState<Set<string>>(new Set())
|
||||||
const [dialog, setDialog] = useState<GroupDialogState>(null)
|
const [dialog, setDialog] = useState<GroupDialogState>(null)
|
||||||
|
|
||||||
|
// 默认全部收起:数据第一次到位时,把所有有子节点的分组塞进 collapsed
|
||||||
|
const seeded = useRef(false)
|
||||||
|
useEffect(() => {
|
||||||
|
if (seeded.current || groups.length === 0) return
|
||||||
|
seeded.current = true
|
||||||
|
const keys = new Set<string>()
|
||||||
|
const walk = (nodes: GroupNode[]) => {
|
||||||
|
for (const node of nodes) {
|
||||||
|
if (node.children.length > 0) {
|
||||||
|
keys.add(node.key)
|
||||||
|
walk(node.children)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
walk(groups)
|
||||||
|
setCollapsed(keys)
|
||||||
|
}, [groups])
|
||||||
|
|
||||||
const rows = useMemo(() => {
|
const rows = useMemo(() => {
|
||||||
const result: { node: GroupNode; level: number }[] = []
|
const result: { node: GroupNode; level: number }[] = []
|
||||||
const walk = (nodes: GroupNode[], level: number) => {
|
const walk = (nodes: GroupNode[], level: number) => {
|
||||||
@@ -529,7 +547,7 @@ function GroupsPanel({
|
|||||||
return (
|
return (
|
||||||
<Space direction="column" gap="md" align="stretch" className="admin-form">
|
<Space direction="column" gap="md" align="stretch" className="admin-form">
|
||||||
<Text size="sm" tone="muted">
|
<Text size="sm" tone="muted">
|
||||||
分组用于控制前台侧边栏与卡片;可多层嵌套,根分组决定格式。内容(条目)只挂在分组上。
|
说明:分组用于控制前台侧边栏与卡片;可多层嵌套,根分组决定格式。内容(条目)只挂在分组上。
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<div className="group-toolbar">
|
<div className="group-toolbar">
|
||||||
@@ -563,12 +581,11 @@ function GroupsPanel({
|
|||||||
{hasChildren ? (
|
{hasChildren ? (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="group-caret"
|
className={`group-caret${open ? ' group-caret-open' : ''}`}
|
||||||
aria-label={open ? `折叠 ${node.title}` : `展开 ${node.title}`}
|
aria-label={open ? `折叠 ${node.title}` : `展开 ${node.title}`}
|
||||||
|
aria-expanded={open}
|
||||||
onClick={() => toggle(node.key)}
|
onClick={() => toggle(node.key)}
|
||||||
>
|
/>
|
||||||
{open ? '▾' : '▸'}
|
|
||||||
</button>
|
|
||||||
) : (
|
) : (
|
||||||
<span className="group-caret group-caret-empty" aria-hidden="true" />
|
<span className="group-caret group-caret-empty" aria-hidden="true" />
|
||||||
)}
|
)}
|
||||||
@@ -593,13 +610,15 @@ function GroupsPanel({
|
|||||||
className="group-action"
|
className="group-action"
|
||||||
onClick={() => setDialog({ mode: 'child', parent: node })}
|
onClick={() => setDialog({ mode: 'child', parent: node })}
|
||||||
>
|
>
|
||||||
加子分组
|
<Icon name="add_line" />
|
||||||
|
新建子分组
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="group-action"
|
className="group-action"
|
||||||
onClick={() => setDialog({ mode: 'edit', group: node })}
|
onClick={() => setDialog({ mode: 'edit', group: node })}
|
||||||
>
|
>
|
||||||
|
<Icon name="edit_4_line" />
|
||||||
编辑
|
编辑
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@@ -607,6 +626,7 @@ function GroupsPanel({
|
|||||||
className="group-action group-action-danger"
|
className="group-action group-action-danger"
|
||||||
onClick={() => onDelete(node.key, node.title)}
|
onClick={() => onDelete(node.key, node.title)}
|
||||||
>
|
>
|
||||||
|
<Icon name="delete_2_line" />
|
||||||
删除
|
删除
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user