update at 2026-02-07 13:57:01
This commit is contained in:
@@ -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>
|
||||
|
||||
<!-- 竖直连接线 -->
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user