feat(settings): 侧边卡片设置页 UI/UX 现代化——卡片底部设置条替代隐形齿轮 (#300)
* feat(settings): 侧边卡片设置页 UI/UX 现代化——卡片底部设置条替代隐形齿轮,协调双色启用态 - 二级设置入口:卡片右下 16px 幽灵齿轮(tertiary 色、像素钉位)改为 卡片底缘全宽设置条(hairline 分隔 + 齿轮图标 + 「功能设置」文字 标签),常态可发现;hover 换品牌淡底 + brand 字色引导。可见性条件 与 aria-label 契约不变(仅父级启用且声明 settings) - 常规行齿轮升级为带 border-l2 边框的 22px 芯片按钮,hover 同样 accent 引导 - 启用卡片:品牌描边柔化为 color-mix(45%),勾选徽标改用 state-success-primary(绿=已开启确认,brand=激活强调的协调双色) - 节奏:section gap 16 / group padding 20 / 网格 minmax(180px) gap 12; 计数徽章改为 accent-soft 淡底 pill;开关关态 thumb 降档 + track 底 layer-2 - 动效纪律:全部过渡 ≤160ms 且仅颜色属性;prefers-reduced-motion 扩展覆盖设置条/行齿轮/弹窗行 - 清理:合并 .pluginEntries 重复定义;文档同步(AGENTS.md §5 + 设计文档新增 §9 偏差记录) * feat(settings): 按反馈迭代——卡片开关滑块、二级弹窗长列表滚动、卡片等高 - 勾选徽标 → 紧凑品牌开关滑块(30×16 track + 10px thumb,开=品牌填充 反色拇指,关=中性且不渲染;纯视觉指示,卡片本身仍是 aria-pressed 开关,语义契约不变) - 二级弹窗长列表:popupRows 内部滚动 max-height min(52vh,440px) + 细滚动条(--dsw-alias-scrollbar-* 令牌),终端 6 行场景弹窗壳体与 Done 固定、仅行区滚动;行密度收紧(padding 12/14、gap 8) - 卡片等高:.card min-height 106px + .cardMain flex:1 + .cardTop min-height 28px——带设置条/不带设置条/无图标卡片全部等高 - prefers-reduced-motion 覆盖 cardSwitch 过渡;文档同步(AGENTS.md §5 + 设计文档 §9 迭代记录) * fix(settings): 二级设置弹窗行区取消横向滚动——box-sizing:border-box + overflow-x:hidden popupRows 的 width:100% 配 content-box 会在 padding-right:4px 时把 内容盒撑宽 4px,overflow-y:auto 隐式启用的 overflow-x 因此出现横向 滚动条;改为 border-box 并显式 overflow-x:hidden(minifier 输出 overflow:hidden auto),行区始终填满弹窗宽度、无左右滑动。add-plugin 弹窗的 pluginEntries 同步加 overflow-x:hidden。
This commit is contained in:
@@ -21,13 +21,15 @@
|
||||
* one-line intro (the DSH section heading+intro recipe).
|
||||
*
|
||||
* A card's on/off state is its VISUAL STATE: enabled = highlighted (brand
|
||||
* border + tinted fill + a circular check badge pinned to the card's far
|
||||
* right), disabled = neutral and dimmed. Features that declare
|
||||
* `settings.toggles` carry a gear corner button that opens a native Modal
|
||||
* (wider than the primitive default) with the related settings as
|
||||
* title/desc + custom-switch rows and a Done footer. The toggles
|
||||
* themselves are custom switches: a real checkbox (native semantics and
|
||||
* focus) driving a styled track/thumb.
|
||||
* border + tinted fill + a compact switch knob at the card's far right),
|
||||
* disabled = neutral and dimmed. Features that declare
|
||||
* `settings.toggles` carry a labeled settings strip at the card's bottom
|
||||
* edge that opens a native Modal (wider than the primitive default) with
|
||||
* the related settings as title/desc + custom-switch rows and a Done
|
||||
* footer; the popup body scrolls internally when a feature declares many
|
||||
* rows (e.g. Terminal's six). The toggles themselves are custom
|
||||
* switches: a real checkbox (native semantics and focus) driving a styled
|
||||
* track/thumb.
|
||||
*
|
||||
* Writes ride the plugin's own fenced settings route (the host calls the
|
||||
* settings seam in-process — the DSH settings RPC domain does not serve
|
||||
@@ -40,7 +42,6 @@
|
||||
*/
|
||||
import { Fragment, useEffect, useMemo, useRef, useState, type ReactNode } from 'react'
|
||||
import {
|
||||
IconCheckOutline16,
|
||||
IconChevronDownOutline14,
|
||||
IconPlusOutline16,
|
||||
IconSettingsOutline16,
|
||||
@@ -793,8 +794,9 @@ export function SideCardSection({ store, service }: SideCardSectionProps) {
|
||||
* One SMALL toggle card for the responsive inventory grid: the card's main
|
||||
* area is the switch (click to flips, visual state IS the state), the icon
|
||||
* sits in a rounded chip, the check badge pins to the far right, and a
|
||||
* feature that declares related settings carries a gear corner button
|
||||
* opening its settings popup.
|
||||
* feature that declares related settings gets a labeled SETTINGS STRIP
|
||||
* across the card's bottom edge (gear icon + text) opening its settings
|
||||
* popup — discoverable at rest, not a hover-only ghost corner button.
|
||||
*/
|
||||
const renderCard = (props: {
|
||||
title: string
|
||||
@@ -802,13 +804,13 @@ export function SideCardSection({ store, service }: SideCardSectionProps) {
|
||||
icon?: ReactNode
|
||||
enabled: boolean
|
||||
onToggle: (next: boolean) => void
|
||||
/** A feature with declared related settings shows the gear corner button. */
|
||||
/** A feature with declared related settings shows the settings strip. */
|
||||
onOpenSettings?: () => void
|
||||
}) => {
|
||||
const hasSettings = props.onOpenSettings !== undefined
|
||||
return (
|
||||
<div
|
||||
className={clsx(css.card, props.enabled && css.cardOn, hasSettings && css.cardWithGear)}
|
||||
className={clsx(css.card, props.enabled && css.cardOn)}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
@@ -823,8 +825,10 @@ export function SideCardSection({ store, service }: SideCardSectionProps) {
|
||||
)}
|
||||
<span className={css.cardTitle}>{props.title}</span>
|
||||
{props.enabled && (
|
||||
<span className={css.cardCheck}>
|
||||
<IconCheckOutline16 size={12} />
|
||||
<span className={css.cardSwitch} aria-hidden="true">
|
||||
<span className={css.cardSwitchTrack}>
|
||||
<span className={css.cardSwitchThumb} />
|
||||
</span>
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
@@ -833,12 +837,12 @@ export function SideCardSection({ store, service }: SideCardSectionProps) {
|
||||
{hasSettings && (
|
||||
<button
|
||||
type="button"
|
||||
className={css.cardGear}
|
||||
className={css.cardSettings}
|
||||
aria-label={`${props.title} ${t('settingsPopup')}`}
|
||||
title={t('settingsPopup')}
|
||||
onClick={props.onOpenSettings}
|
||||
>
|
||||
<IconSettingsOutline16 size={12} />
|
||||
<span>{t('settingsPopup')}</span>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user