Merge branch 't11-topbar'
This commit is contained in:
+186
-166
@@ -1,66 +1,64 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* 【T7 — 顶部工具栏】
|
||||
* 【T11 — 顶部工具栏】工具组居中,尺寸设置收进「画布编辑」下拉。
|
||||
*
|
||||
* 三段式(grid 1fr auto 1fr,中间严格居中):
|
||||
*
|
||||
* 左 —— 工具组。选择 V / 文字 T / 矩形 R / 图片 Shift+K。
|
||||
* 左 —— 留空(以后放文件名之类)。
|
||||
* 中 —— 工具组五个按钮,这是顶栏的视觉主体:
|
||||
* - 画布编辑:纯下拉(CanvasMenu),点开改预设 / 宽高 / 比例。
|
||||
* - 选择 / 文字:普通按钮,切工具。
|
||||
* - 形状 / 背景:本体切工具 + 右侧小角标开下拉(Figma 的形状工具样式)。
|
||||
* 当前工具高亮读 `useEditor().tool`;切换一律 `runCommand(...)`,不直接写
|
||||
* `tool.value`——工具栏与快捷键共用命令表,抄一份必然走偏。每个按钮的 tooltip
|
||||
* 用 `keyHintOf(commandId)` 显示键位,保证键位只在一处(commands.ts)维护。
|
||||
* 图标从 `@/ui/icons` 取(hugeicons,构建期内联,见那个文件的说明)。
|
||||
* `tool.value`——工具栏与快捷键共用命令表,抄一份必然走偏。tooltip 用
|
||||
* `keyHintOf(commandId)` 拼键位,保证键位只在 commands.ts 里维护。
|
||||
* 右 —— 撤销 / 重做 + 导出入口(导出按钮滚到右栏的导出面板)。
|
||||
*
|
||||
* 中 —— 画布尺寸:预设下拉、比例锁下拉、自定义宽高。预设表直接用
|
||||
* @/editor/canvasSize 的 SIZE_PRESETS / RATIOS / applyRatio。
|
||||
*
|
||||
* 右 —— 撤销 / 重做(useHistory 的 canUndo / canRedo 控制禁用态)+ 导出入口。
|
||||
* 导出按钮只负责把右栏下半的滚动容器(.right-bottom,即 ToolPanels)滚到底,
|
||||
* 面板本体在那里。
|
||||
* 文字工具的光标:这里只往 `document.body.dataset.tool` 写当前工具,
|
||||
* 真正的 `body[data-tool="text"] .stage { cursor: text; }` 规则在 style.css
|
||||
* 里(body 不在本组件的 scoped 作用域内,够不到)。卸载时清掉。
|
||||
*/
|
||||
import { computed, nextTick, ref, watch } from "vue";
|
||||
import { computed, nextTick, onBeforeUnmount, watch } from "vue";
|
||||
import { useEditor } from "@/editor/useEditor";
|
||||
import { useHistory } from "@/editor/useHistory";
|
||||
import { RATIOS, SIZE_PRESETS, applyRatio } from "@/editor/canvasSize";
|
||||
import { runCommand } from "@/editor/commands";
|
||||
import { keyHintOf } from "@/editor/useShortcuts";
|
||||
import type { ToolId } from "@/types";
|
||||
import { shapeMeta } from "@/editor/shapes";
|
||||
import {
|
||||
IconSelect,
|
||||
IconText,
|
||||
IconRect,
|
||||
IconImage,
|
||||
IconUndo,
|
||||
IconRedo,
|
||||
IconBackgroundTool,
|
||||
IconCanvasEdit,
|
||||
IconChevronDown,
|
||||
IconExport,
|
||||
IconRedo,
|
||||
IconSelect,
|
||||
IconTextTool,
|
||||
IconUndo,
|
||||
} from "@/ui/icons";
|
||||
import { openToolGroup } from "@/ui/toolGroups";
|
||||
import Dropdown from "@/components/ui/Dropdown.vue";
|
||||
import CanvasMenu from "@/components/topbar/CanvasMenu.vue";
|
||||
import ShapeMenu from "@/components/topbar/ShapeMenu.vue";
|
||||
import BackgroundMenu from "@/components/topbar/BackgroundMenu.vue";
|
||||
|
||||
const { tool, size, setSize } = useEditor();
|
||||
const { tool, shapeKind } = useEditor();
|
||||
const { canUndo, canRedo } = useHistory();
|
||||
|
||||
/* ================================================================ 工具组 */
|
||||
/** 形状按钮的图标跟着当前形状走(和 Figma 一致)。 */
|
||||
const shapeIcon = computed(() => shapeMeta(shapeKind.value).icon);
|
||||
|
||||
/**
|
||||
* `cmd` 是命令表里的 id(字符串**原样**写在文件里,scripts 侧的 Node 断言会
|
||||
* 核对每个 id 都存在于 COMMANDS——拼错一个就是「按钮点了没反应」)。active 态
|
||||
* 由 `toolOf(cmd)` 映射回 useEditor().tool 的值来判定。
|
||||
* 形状 / 背景是「本体 + 角标」的组合:点本体切工具,点角标开下拉。
|
||||
* 本体点击时若下拉正开着,顺手关掉——本体在 Dropdown 的 root 里,外壳的
|
||||
* 「点外面关」管不到它,这里用 slot 给的 `toggle` 在 open 时再翻一次。
|
||||
*/
|
||||
const TOOLS = [
|
||||
{ cmd: "toolSelect", label: "选择工具", icon: IconSelect },
|
||||
{ cmd: "toolText", label: "文字工具", icon: IconText },
|
||||
{ cmd: "toolShape", label: "形状工具", icon: IconRect },
|
||||
{ cmd: "toolBackground", label: "背景工具", icon: IconImage },
|
||||
] as const;
|
||||
function pickShapeTool(open: boolean, toggle: () => void) {
|
||||
runCommand("toolShape");
|
||||
if (open) toggle();
|
||||
}
|
||||
|
||||
const TOOL_OF: Record<string, ToolId> = {
|
||||
toolSelect: "select",
|
||||
toolText: "text",
|
||||
toolShape: "shape",
|
||||
toolBackground: "background",
|
||||
};
|
||||
|
||||
function toolOf(cmd: string): ToolId {
|
||||
return TOOL_OF[cmd] ?? "select";
|
||||
function pickBackgroundTool(open: boolean, toggle: () => void) {
|
||||
runCommand("toolBackground");
|
||||
if (open) toggle();
|
||||
}
|
||||
|
||||
function tip(cmd: string, label: string): string {
|
||||
@@ -68,57 +66,28 @@ function tip(cmd: string, label: string): string {
|
||||
return k ? `${label}(${k})` : label;
|
||||
}
|
||||
|
||||
/* ================================================================ 画布尺寸(中) */
|
||||
/* ---------------------------------------------------------------- 光标 */
|
||||
|
||||
/** 选中预设后,任何一边宽高的改动都会把下拉弹回「自定义」。 */
|
||||
const presetId = ref<string>("custom");
|
||||
/** 比例锁。改宽高时另一侧按这个比例联动;"free"(0)表示不锁。 */
|
||||
const ratioId = ref<string>("free");
|
||||
|
||||
const ratio = computed(() => RATIOS.find((r) => r.id === ratioId.value)?.value ?? 0);
|
||||
|
||||
const currentPreset = computed(() => SIZE_PRESETS.find((p) => p.id === presetId.value));
|
||||
|
||||
/** 尺寸可能被别处改掉(模板加载、别的面板),下拉常驻,要跟着真值走。 */
|
||||
/**
|
||||
* 文字 / 形状工具的鼠标指针。规则在 style.css(body 够不到 scoped),
|
||||
* 这里只负责同步 data 属性。`immediate` 让初始工具也写一次。
|
||||
*/
|
||||
watch(
|
||||
() => size.value,
|
||||
(s) => {
|
||||
const p = SIZE_PRESETS.find((x) => x.width === s.width && x.height === s.height);
|
||||
presetId.value = p ? p.id : "custom";
|
||||
tool,
|
||||
(t) => {
|
||||
document.body.dataset.tool = t;
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
function pickPreset(id: string) {
|
||||
presetId.value = id;
|
||||
const p = SIZE_PRESETS.find((s) => s.id === id);
|
||||
if (p) setSize({ width: p.width, height: p.height });
|
||||
}
|
||||
|
||||
/** 手动改宽/高。带比例锁时另一侧按 applyRatio 联动。 */
|
||||
function edit(dimension: "width" | "height", raw: string) {
|
||||
const n = Number(raw);
|
||||
if (!Number.isFinite(n) || n < 16) return;
|
||||
presetId.value = "custom";
|
||||
setSize(applyRatio({ ...size.value, [dimension]: n }, ratio.value, dimension));
|
||||
}
|
||||
|
||||
/** 预设下拉里只放短名,完整「名字(宽×高)」放 title,随鼠标悬停可见。 */
|
||||
function shortPresetLabel(label: string): string {
|
||||
return label.split("(")[0].trim();
|
||||
}
|
||||
|
||||
const presetTitle = computed(() => {
|
||||
const p = currentPreset.value;
|
||||
return p ? `${p.label}(${p.width}×${p.height})` : "自定义尺寸";
|
||||
onBeforeUnmount(() => {
|
||||
delete document.body.dataset.tool;
|
||||
});
|
||||
|
||||
/* ================================================================ 导出入口(右) */
|
||||
/* ---------------------------------------------------------------- 导出 */
|
||||
|
||||
/**
|
||||
* 右栏下半是滚动容器,「导出与模板」是最后一组。
|
||||
* 先展开那一组再滚——四个组默认全收,只滚不展开的话滚到底看到的还是一行标题。
|
||||
* `nextTick` 是等展开后的内容渲染进 DOM,`scrollHeight` 才是最终高度。
|
||||
* 右栏下半是滚动容器,「导出与模板」是最后一组。先展开再滚,否则滚到底
|
||||
* 看到的还是一行标题。`nextTick` 等展开内容渲染进 DOM,`scrollHeight` 才是最终高度。
|
||||
*/
|
||||
async function scrollToExport() {
|
||||
openToolGroup("export");
|
||||
@@ -131,68 +100,107 @@ async function scrollToExport() {
|
||||
|
||||
<template>
|
||||
<header class="topbar">
|
||||
<!-- 左:工具组 -->
|
||||
<div class="zone left">
|
||||
<button
|
||||
v-for="t in TOOLS"
|
||||
:key="t.cmd"
|
||||
class="tbtn"
|
||||
:class="{ active: toolOf(t.cmd) === tool }"
|
||||
:title="tip(t.cmd, t.label)"
|
||||
:aria-label="t.label"
|
||||
@click="runCommand(t.cmd)"
|
||||
>
|
||||
<component :is="t.icon" />
|
||||
</button>
|
||||
</div>
|
||||
<!-- 左:留空(以后放文件名之类) -->
|
||||
<div class="zone left"></div>
|
||||
|
||||
<!-- 中:画布尺寸(预设 + 比例锁 + 自定义宽高) -->
|
||||
<!-- 中:工具组 -->
|
||||
<div class="zone mid">
|
||||
<select
|
||||
class="preset"
|
||||
:value="presetId"
|
||||
:title="presetTitle"
|
||||
aria-label="画布尺寸预设"
|
||||
@change="pickPreset(($event.target as HTMLSelectElement).value)"
|
||||
<Dropdown :min-width="240">
|
||||
<template #trigger="{ open, toggle }">
|
||||
<button
|
||||
class="tbtn"
|
||||
:class="{ active: open }"
|
||||
title="画布编辑"
|
||||
aria-label="画布编辑"
|
||||
:aria-expanded="open"
|
||||
@click="toggle"
|
||||
>
|
||||
<option v-for="p in SIZE_PRESETS" :key="p.id" :value="p.id" :title="`${p.width}×${p.height}px`">
|
||||
{{ shortPresetLabel(p.label) }}
|
||||
</option>
|
||||
<option value="custom">自定义</option>
|
||||
</select>
|
||||
<IconCanvasEdit />
|
||||
<IconChevronDown class="caret" />
|
||||
</button>
|
||||
</template>
|
||||
<template #panel="{ close }">
|
||||
<CanvasMenu :close="close" />
|
||||
</template>
|
||||
</Dropdown>
|
||||
|
||||
<div class="dims">
|
||||
<input
|
||||
type="number"
|
||||
min="16"
|
||||
class="num"
|
||||
:value="size.width"
|
||||
title="宽度(px)"
|
||||
aria-label="画布宽度"
|
||||
@change="edit('width', ($event.target as HTMLInputElement).value)"
|
||||
/>
|
||||
<span class="times" aria-hidden="true">×</span>
|
||||
<input
|
||||
type="number"
|
||||
min="16"
|
||||
class="num"
|
||||
:value="size.height"
|
||||
title="高度(px)"
|
||||
aria-label="画布高度"
|
||||
@change="edit('height', ($event.target as HTMLInputElement).value)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<select
|
||||
v-model="ratioId"
|
||||
class="ratio"
|
||||
title="比例锁:编辑宽高时另一侧按此比例联动"
|
||||
aria-label="锁定比例"
|
||||
<button
|
||||
class="tbtn"
|
||||
:class="{ active: tool === 'select' }"
|
||||
:title="tip('toolSelect', '选择工具')"
|
||||
aria-label="选择工具"
|
||||
@click="runCommand('toolSelect')"
|
||||
>
|
||||
<option v-for="r in RATIOS" :key="r.id" :value="r.id" :title="r.label">
|
||||
{{ shortPresetLabel(r.label) }}
|
||||
</option>
|
||||
</select>
|
||||
<IconSelect />
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="tbtn"
|
||||
:class="{ active: tool === 'text' }"
|
||||
:title="tip('toolText', '文字工具')"
|
||||
aria-label="文字工具"
|
||||
@click="runCommand('toolText')"
|
||||
>
|
||||
<IconTextTool />
|
||||
</button>
|
||||
|
||||
<Dropdown :min-width="200">
|
||||
<template #trigger="{ open, toggle }">
|
||||
<span class="combo">
|
||||
<button
|
||||
class="tbtn combo-body"
|
||||
:class="{ active: tool === 'shape' || open }"
|
||||
:title="tip('toolShape', '形状工具')"
|
||||
aria-label="形状工具"
|
||||
@click="pickShapeTool(open, toggle)"
|
||||
>
|
||||
<component :is="shapeIcon" />
|
||||
</button>
|
||||
<button
|
||||
class="tbtn combo-caret"
|
||||
:class="{ active: tool === 'shape' || open }"
|
||||
title="形状类型"
|
||||
aria-label="选择形状类型"
|
||||
:aria-expanded="open"
|
||||
@click="toggle"
|
||||
>
|
||||
<IconChevronDown />
|
||||
</button>
|
||||
</span>
|
||||
</template>
|
||||
<template #panel>
|
||||
<ShapeMenu />
|
||||
</template>
|
||||
</Dropdown>
|
||||
|
||||
<Dropdown :min-width="200">
|
||||
<template #trigger="{ open, toggle }">
|
||||
<span class="combo">
|
||||
<button
|
||||
class="tbtn combo-body"
|
||||
:class="{ active: tool === 'background' || open }"
|
||||
:title="tip('toolBackground', '背景工具')"
|
||||
aria-label="背景工具"
|
||||
@click="pickBackgroundTool(open, toggle)"
|
||||
>
|
||||
<IconBackgroundTool />
|
||||
</button>
|
||||
<button
|
||||
class="tbtn combo-caret"
|
||||
:class="{ active: tool === 'background' || open }"
|
||||
title="背景来源"
|
||||
aria-label="选择背景来源"
|
||||
:aria-expanded="open"
|
||||
@click="toggle"
|
||||
>
|
||||
<IconChevronDown />
|
||||
</button>
|
||||
</span>
|
||||
</template>
|
||||
<template #panel>
|
||||
<BackgroundMenu />
|
||||
</template>
|
||||
</Dropdown>
|
||||
</div>
|
||||
|
||||
<!-- 右:撤销 / 重做 / 导出 -->
|
||||
@@ -218,7 +226,7 @@ async function scrollToExport() {
|
||||
<span class="vr" aria-hidden="true"></span>
|
||||
<button
|
||||
class="tbtn"
|
||||
title="导出(面板在右侧,点了滚过去)"
|
||||
:title="tip('export', '导出')"
|
||||
aria-label="导出"
|
||||
@click="scrollToExport"
|
||||
>
|
||||
@@ -263,6 +271,7 @@ async function scrollToExport() {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 2px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
padding: 0;
|
||||
@@ -289,36 +298,47 @@ async function scrollToExport() {
|
||||
color: var(--fg-dim);
|
||||
}
|
||||
|
||||
/* 画布编辑按钮里的下角标,比工具图标小一档。 */
|
||||
.tbtn .caret {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* ---- 形状 / 背景的「本体 + 角标」组合 ---- */
|
||||
.combo {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
.combo .tbtn {
|
||||
border-radius: 0;
|
||||
}
|
||||
.combo .combo-body {
|
||||
border-radius: var(--radius) 0 0 var(--radius);
|
||||
}
|
||||
.combo .combo-caret {
|
||||
width: 18px;
|
||||
border-radius: 0 var(--radius) var(--radius) 0;
|
||||
}
|
||||
.combo-caret .icon {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* 组合按钮整块一起亮:hover 与 active 都作用到两个按钮,不分家。
|
||||
* `.combo:hover .tbtn:not(.active)` 管非激活时的悬停(光靠单个 .tbtn:hover
|
||||
* 只会亮鼠标底下那一半);`.combo .tbtn.active` 保证激活态在悬停时也不被
|
||||
* .tbtn:hover 的 color 盖回 fg。 */
|
||||
.combo:hover .tbtn:not(.active) {
|
||||
background: var(--bg3);
|
||||
color: var(--fg);
|
||||
}
|
||||
.combo .tbtn.active {
|
||||
background: var(--bg3);
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.vr {
|
||||
width: 1px;
|
||||
height: 20px;
|
||||
background: var(--line);
|
||||
margin: 0 6px;
|
||||
}
|
||||
|
||||
/* ---- 画布尺寸 ---- */
|
||||
.preset {
|
||||
width: 112px;
|
||||
}
|
||||
.ratio {
|
||||
width: 84px;
|
||||
}
|
||||
|
||||
.dims {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
||||
/* 覆盖全局 input/select 的 width:100%,顶栏里宽度要收敛。 */
|
||||
.num {
|
||||
width: 58px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.times {
|
||||
color: var(--fg-dim);
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,147 @@
|
||||
<script setup lang="ts">
|
||||
/** 【占位】CanvasMenu 的内容由对应开发线实现。见任务书。 */
|
||||
/**
|
||||
* 画布编辑下拉:预设 / 分辨率 / 比例。
|
||||
*
|
||||
* 逻辑照搬旧 TopBar 中间那组,不另起一套:尺寸写回一律 `useEditor().setSize()`,
|
||||
* 预设表来自 `@/editor/canvasSize` 的 `SIZE_PRESETS`,比例锁用 `applyRatio`。
|
||||
* `size` 是响应式真值——模板加载、别的面板改尺寸都会反映到这里,所以下拉里的
|
||||
* 显示和命中预设都 watch 真值,而不是只在打开时读一次。
|
||||
*/
|
||||
import { computed, ref, watch } from "vue";
|
||||
import { useEditor } from "@/editor/useEditor";
|
||||
import { RATIOS, SIZE_PRESETS, applyRatio } from "@/editor/canvasSize";
|
||||
import { IconCheck } from "@/ui/icons";
|
||||
|
||||
/** 选中一行后要顺手关面板,由 TopBar 通过插槽的 `close` 传进来。 */
|
||||
const props = defineProps<{ close: () => void }>();
|
||||
|
||||
const { size, setSize } = useEditor();
|
||||
|
||||
/** 选中预设后,任何一边宽高的改动都会把它弹回「自定义」。 */
|
||||
const presetId = ref<string>("custom");
|
||||
/** 比例锁。改宽高时另一侧按这个比例联动;"free"(0)表示不锁。 */
|
||||
const ratioId = ref<string>("free");
|
||||
|
||||
const ratio = computed(() => RATIOS.find((r) => r.id === ratioId.value)?.value ?? 0);
|
||||
|
||||
/** 尺寸可能被别处改掉(模板加载、别的面板),要跟着真值走。 */
|
||||
watch(
|
||||
() => size.value,
|
||||
(s) => {
|
||||
const p = SIZE_PRESETS.find((x) => x.width === s.width && x.height === s.height);
|
||||
presetId.value = p ? p.id : "custom";
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
function pickPreset(id: string) {
|
||||
presetId.value = id;
|
||||
const p = SIZE_PRESETS.find((s) => s.id === id);
|
||||
if (p) setSize({ width: p.width, height: p.height });
|
||||
props.close();
|
||||
}
|
||||
|
||||
/** 比例锁只记当前锁定,不立刻改尺寸——改宽高时才用 applyRatio 联动。 */
|
||||
function pickRatio(id: string) {
|
||||
ratioId.value = id;
|
||||
}
|
||||
|
||||
/** 手动改宽/高。带比例锁时另一侧按 applyRatio 联动。 */
|
||||
function edit(dimension: "width" | "height", raw: string) {
|
||||
const n = Number(raw);
|
||||
if (!Number.isFinite(n) || n < 16) return;
|
||||
presetId.value = "custom";
|
||||
setSize(applyRatio({ ...size.value, [dimension]: n }, ratio.value, dimension));
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="menu-block">(CanvasMenu 待实现)</div>
|
||||
<div class="canvas-menu">
|
||||
<div class="menu-title">预设</div>
|
||||
<button
|
||||
v-for="p in SIZE_PRESETS"
|
||||
:key="p.id"
|
||||
class="menu-row"
|
||||
:class="{ on: presetId === p.id }"
|
||||
@click="pickPreset(p.id)"
|
||||
>
|
||||
<span class="name">{{ p.label }}</span>
|
||||
<span class="menu-aside">{{ p.width }}×{{ p.height }}</span>
|
||||
<IconCheck v-if="presetId === p.id" class="check" />
|
||||
</button>
|
||||
|
||||
<div class="menu-sep"></div>
|
||||
|
||||
<div class="menu-title">分辨率</div>
|
||||
<div class="menu-block">
|
||||
<div class="dims">
|
||||
<input
|
||||
type="number"
|
||||
min="16"
|
||||
class="num"
|
||||
:value="size.width"
|
||||
title="宽度(px)"
|
||||
aria-label="画布宽度"
|
||||
@change="edit('width', ($event.target as HTMLInputElement).value)"
|
||||
/>
|
||||
<span class="times" aria-hidden="true">×</span>
|
||||
<input
|
||||
type="number"
|
||||
min="16"
|
||||
class="num"
|
||||
:value="size.height"
|
||||
title="高度(px)"
|
||||
aria-label="画布高度"
|
||||
@change="edit('height', ($event.target as HTMLInputElement).value)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="menu-sep"></div>
|
||||
|
||||
<div class="menu-title">比例</div>
|
||||
<button
|
||||
v-for="r in RATIOS"
|
||||
:key="r.id"
|
||||
class="menu-row"
|
||||
:class="{ on: ratioId === r.id }"
|
||||
title="锁定比例:改宽高时另一侧按此联动"
|
||||
@click="pickRatio(r.id)"
|
||||
>
|
||||
<span class="name">{{ r.label }}</span>
|
||||
<IconCheck v-if="ratioId === r.id" class="check" />
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* 名字占满剩余空间,把右侧的尺寸 / 勾推到行尾。 */
|
||||
.name {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* 选中行的勾。图标走 currentColor,`.menu-row.on` 已把颜色置成 accent。 */
|
||||
.check {
|
||||
flex: none;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.dims {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.num {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.times {
|
||||
color: var(--fg-dim);
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user