update at 2026-02-07 15:51:08
This commit is contained in:
@@ -9,26 +9,45 @@ const searchKeyword = ref('')
|
||||
|
||||
const fontTree = computed(() => fontStore.fontTree)
|
||||
const normalizedSearchKeyword = computed(() => searchKeyword.value.trim().toLowerCase())
|
||||
const isSelectedOnlyMode = computed(() => {
|
||||
const keyword = normalizedSearchKeyword.value
|
||||
return keyword.includes('选中') || keyword.includes('选择') || keyword.includes('已选')
|
||||
})
|
||||
const normalizedNameSearchKeyword = computed(() => {
|
||||
return isSelectedOnlyMode.value ? '' : normalizedSearchKeyword.value
|
||||
})
|
||||
const hasSearchKeyword = computed(() => normalizedSearchKeyword.value.length > 0)
|
||||
|
||||
function nodeHasMatch(node: (typeof fontTree.value)[number]): boolean {
|
||||
if (node.type !== 'category') {
|
||||
return false
|
||||
}
|
||||
|
||||
const fontChildren = (node.children ?? []).filter((child) => {
|
||||
return child.type === 'font' && !!child.fontInfo
|
||||
})
|
||||
const selectedFilteredChildren = isSelectedOnlyMode.value
|
||||
? fontChildren.filter(child => !!child.fontInfo && fontStore.previewFontIds.has(child.fontInfo.id))
|
||||
: fontChildren
|
||||
|
||||
if (normalizedNameSearchKeyword.value.length === 0) {
|
||||
return selectedFilteredChildren.length > 0
|
||||
}
|
||||
|
||||
const keyword = normalizedNameSearchKeyword.value
|
||||
if (node.name.toLowerCase().includes(keyword)) {
|
||||
return selectedFilteredChildren.length > 0
|
||||
}
|
||||
|
||||
return selectedFilteredChildren.some(child => child.name.toLowerCase().includes(keyword))
|
||||
}
|
||||
|
||||
const hasMatchedFonts = computed(() => {
|
||||
if (!hasSearchKeyword.value) {
|
||||
return fontTree.value.length > 0
|
||||
}
|
||||
|
||||
const keyword = normalizedSearchKeyword.value
|
||||
return fontTree.value.some((node) => {
|
||||
if (node.type !== 'category') {
|
||||
return false
|
||||
}
|
||||
|
||||
if (node.name.toLowerCase().includes(keyword)) {
|
||||
return true
|
||||
}
|
||||
|
||||
return (node.children ?? []).some(child => {
|
||||
return child.type === 'font' && child.name.toLowerCase().includes(keyword)
|
||||
})
|
||||
})
|
||||
return fontTree.value.some(node => nodeHasMatch(node))
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -66,7 +85,8 @@ const hasMatchedFonts = computed(() => {
|
||||
<FontTree
|
||||
v-else
|
||||
:nodes="fontTree"
|
||||
:search-keyword="normalizedSearchKeyword"
|
||||
:search-keyword="normalizedNameSearchKeyword"
|
||||
:selected-only="isSelectedOnlyMode"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -8,11 +8,13 @@ import { useFontStore } from '../stores/fontStore'
|
||||
const props = defineProps<{
|
||||
nodes: FontTreeNode[]
|
||||
searchKeyword?: string
|
||||
selectedOnly?: boolean
|
||||
}>()
|
||||
|
||||
const fontStore = useFontStore()
|
||||
const normalizedSearchKeyword = computed(() => (props.searchKeyword ?? '').trim().toLowerCase())
|
||||
const isSearchMode = computed(() => normalizedSearchKeyword.value.length > 0)
|
||||
const isFilterMode = computed(() => isSearchMode.value || props.selectedOnly === true)
|
||||
|
||||
type FontLeafNode = FontTreeNode & { fontInfo: NonNullable<FontTreeNode['fontInfo']> }
|
||||
|
||||
@@ -24,16 +26,20 @@ function getVisibleChildren(node: FontTreeNode): FontLeafNode[] {
|
||||
const fontChildren = node.children.filter(
|
||||
(child): child is FontLeafNode => child.type === 'font' && !!child.fontInfo,
|
||||
)
|
||||
const selectedFilteredChildren = props.selectedOnly
|
||||
? fontChildren.filter(child => fontStore.previewFontIds.has(child.fontInfo.id))
|
||||
: fontChildren
|
||||
|
||||
if (!isSearchMode.value) {
|
||||
return fontChildren
|
||||
return selectedFilteredChildren
|
||||
}
|
||||
|
||||
const keyword = normalizedSearchKeyword.value
|
||||
if (node.name.toLowerCase().includes(keyword)) {
|
||||
return fontChildren
|
||||
return selectedFilteredChildren
|
||||
}
|
||||
|
||||
return fontChildren.filter(child => child.name.toLowerCase().includes(keyword))
|
||||
return selectedFilteredChildren.filter(child => child.name.toLowerCase().includes(keyword))
|
||||
}
|
||||
|
||||
function shouldRenderCategory(node: FontTreeNode): boolean {
|
||||
@@ -41,11 +47,11 @@ function shouldRenderCategory(node: FontTreeNode): boolean {
|
||||
}
|
||||
|
||||
function isCategoryExpanded(node: FontTreeNode): boolean {
|
||||
return isSearchMode.value ? true : !!node.expanded
|
||||
return isFilterMode.value ? true : !!node.expanded
|
||||
}
|
||||
|
||||
function toggleExpand(node: FontTreeNode) {
|
||||
if (isSearchMode.value) {
|
||||
if (isFilterMode.value) {
|
||||
return
|
||||
}
|
||||
const next = !node.expanded
|
||||
@@ -115,14 +121,14 @@ function handleCategorySelectAll(node: FontTreeNode, event: Event) {
|
||||
<button
|
||||
@click="toggleExpand(node)"
|
||||
class="tree-toggle"
|
||||
:disabled="isSearchMode"
|
||||
:disabled="isFilterMode"
|
||||
>
|
||||
<img
|
||||
v-if="isCategoryExpanded(node)"
|
||||
src="../assets/icons/zhedie.svg"
|
||||
alt="收起"
|
||||
class="w-[15px] h-[15px]"
|
||||
:class="{ 'opacity-70': isSearchMode }"
|
||||
:class="{ 'opacity-70': isFilterMode }"
|
||||
/>
|
||||
<img
|
||||
v-else
|
||||
@@ -137,7 +143,7 @@ function handleCategorySelectAll(node: FontTreeNode, event: Event) {
|
||||
<div
|
||||
@click="toggleExpand(node)"
|
||||
class="text-base font-medium text-black flex-1 ml-2"
|
||||
:class="isSearchMode ? 'cursor-default' : 'cursor-pointer'"
|
||||
:class="isFilterMode ? 'cursor-default' : 'cursor-pointer'"
|
||||
>
|
||||
{{ node.name }}({{ getCategoryFontCount(node) }}字体)
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user