update at 2026-02-07 13:57:01

This commit is contained in:
douboer
2026-02-07 13:57:01 +08:00
parent 951eda9c58
commit d77f7446a2
5 changed files with 124 additions and 4 deletions

View File

@@ -1,4 +1,6 @@
<script setup lang="ts">
import selectAllIcon from '../assets/icons/selectall.svg'
import unselectAllIcon from '../assets/icons/unselectall.svg'
import type { FontTreeNode } from '../types/font'
import { useFontStore } from '../stores/fontStore'
@@ -35,6 +37,36 @@ function isFavorite(node: FontTreeNode): boolean {
function isInPreview(node: FontTreeNode): boolean {
return node.type === 'font' && node.fontInfo ? fontStore.previewFontIds.has(node.fontInfo.id) : false
}
function getCategoryFontIds(node: FontTreeNode): string[] {
if (node.type !== 'category' || !node.children) {
return []
}
return node.children
.filter((child): child is FontTreeNode & { fontInfo: NonNullable<FontTreeNode['fontInfo']> } => child.type === 'font' && !!child.fontInfo)
.map(child => child.fontInfo.id)
}
function isCategoryAllInPreview(node: FontTreeNode): boolean {
const ids = getCategoryFontIds(node)
return ids.length > 0 && ids.every(id => fontStore.previewFontIds.has(id))
}
function handleCategorySelectAll(node: FontTreeNode, event: Event) {
event.stopPropagation()
const ids = getCategoryFontIds(node)
if (ids.length === 0) {
return
}
if (isCategoryAllInPreview(node)) {
ids.forEach(id => fontStore.removeFromPreview(id))
} else {
ids.forEach(id => fontStore.addToPreview(id))
}
}
</script>
<template>
@@ -42,7 +74,7 @@ function isInPreview(node: FontTreeNode): boolean {
<div v-for="node in nodes" :key="node.name">
<!-- 分类节点 -->
<div v-if="node.type === 'category'" class="relative mb-3">
<div class="flex items-center">
<div class="flex items-center gap-2">
<!-- 左侧展开图标 -->
<div class="tree-icon-wrapper">
<button
@@ -71,6 +103,21 @@ function isInPreview(node: FontTreeNode): boolean {
>
{{ node.name }}
</div>
<div class="flex items-center gap-2 shrink-0 mr-[1px]">
<button
@click="handleCategorySelectAll(node, $event)"
class="w-4 h-4 shrink-0 p-0 border-0 bg-transparent cursor-pointer hover:opacity-85 transition-opacity"
title="分类全选/全不选"
>
<img
:src="isCategoryAllInPreview(node) ? unselectAllIcon : selectAllIcon"
alt="分类全选/全不选"
class="w-full h-full"
/>
</button>
<div class="w-[18px] h-[17px] shrink-0" aria-hidden="true"></div>
</div>
</div>
<!-- 竖直连接线 -->

View File

@@ -15,6 +15,9 @@ const previewFonts = computed(() => fontStore.previewFonts)
const inputText = computed(() => uiStore.inputText)
const fontSize = computed(() => uiStore.fontSize)
const fillColor = computed(() => uiStore.textColor)
const isAllPreviewSelected = computed(() => {
return previewItems.value.length > 0 && previewItems.value.every(item => item.selected)
})
watch(
[previewFonts, inputText, fontSize, fillColor],
@@ -81,6 +84,29 @@ function toggleSelectItem(item: PreviewItemType) {
item.selected = !item.selected
uiStore.toggleExportItem(item)
}
function toggleSelectAllPreviewItems() {
if (previewItems.value.length === 0) {
return
}
if (isAllPreviewSelected.value) {
uiStore.clearExportSelection()
previewItems.value.forEach(item => {
item.selected = false
})
return
}
previewItems.value.forEach(item => {
item.selected = true
})
uiStore.selectAllExportItems(previewItems.value)
}
defineExpose({
toggleSelectAllPreviewItems,
})
</script>
<template>