feat(font): 添加本地字体选择功能(not done) #96

This commit is contained in:
log1997
2025-12-10 17:54:59 +08:00
parent 9dece20aa8
commit 3cd7788517
6 changed files with 161 additions and 43 deletions

View File

@@ -0,0 +1,51 @@
import { onMounted, ref } from 'vue'
export function useLocalFonts() {
const fonts = ref<Map<string, { name: string, value: string }[]>>(new Map())
const disabled = ref(false)
const formatFonts = (list: FontData[]): Map<string, { name: string, value: string }[]> => {
const res: Map<string, { name: string, value: string }[]> = new Map()
for (const item of list) {
if (!res.has(item.family)) {
res.set(item.family, [])
}
const fontArray = res.get(item.family)
if (!Array.isArray(fontArray)) {
continue
}
if (item.family === item.fullName) {
fontArray.push({ name: item.style, value: item.fullName })
continue
}
const name = item.fullName.replace(item.family, '').trim()
const value = item.fullName
fontArray.push({ name, value })
}
return res
}
const getFonts = async () => {
if (!window.queryLocalFonts) {
return
}
const list = await window.queryLocalFonts()
console.log('list', list)
const res = formatFonts(list)
console.log('fontlist', res)
fonts.value = res
// 对比family相同则移入第一个元素的children里面
}
onMounted(() => {
if (!window.queryLocalFonts) {
disabled.value = true
}
})
return {
disabled,
fonts,
getFonts,
}
}

View File

@@ -24,6 +24,7 @@ export const useGlobalConfig = defineStore('global', {
patternColor: '#1b66c9',
patternList: defaultPatternList as number[],
background: {}, // 背景颜色或图片
font: '',
},
musicList: defaultMusicList as IMusic[],
imageList: defaultImageList as IImage[],
@@ -106,6 +107,10 @@ export const useGlobalConfig = defineStore('global', {
getBackground(state) {
return state.globalConfig.theme.background
},
// 获取字体
getFont(state) {
return state.globalConfig.theme.font
},
// 获取是否显示头像
getIsShowAvatar(state) {
return state.globalConfig.isShowAvatar
@@ -232,6 +237,10 @@ export const useGlobalConfig = defineStore('global', {
setBackground(background: any) {
this.globalConfig.theme.background = background
},
// 设置字体
setFont(font: any) {
this.globalConfig.theme.font = font
},
// 设置是否显示头像
setIsShowAvatar(isShowAvatar: boolean) {
this.globalConfig.isShowAvatar = isShowAvatar
@@ -256,6 +265,7 @@ export const useGlobalConfig = defineStore('global', {
patternColor: '#1b66c9',
patternList: defaultPatternList as number[],
background: {}, // 背景颜色或图片
font: '',
},
musicList: defaultMusicList as IMusic[],
imageList: defaultImageList as IImage[],

3
src/utils/format/tree.ts Normal file
View File

@@ -0,0 +1,3 @@
/**
* @description 用于将平铺的数组组合到树形数组中
*/

View File

@@ -6,6 +6,7 @@ import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router'
import { z as zod } from 'zod'
import { daisyuiThemes } from '@/constant/theme'
import { useLocalFonts } from '@/hooks/useLocalFonts'
import i18n, { languageList } from '@/locales/i18n'
import useStore from '@/store'
import { themeChange } from '@/utils'
@@ -18,9 +19,10 @@ const { t } = useI18n()
const globalConfig = useStore().globalConfig
const personConfig = useStore().personConfig
const prizeConfig = useStore().prizeConfig
const { getTopTitle: topTitle, getTheme: localTheme, getPatterColor: patternColor, getPatternList: patternList, getCardColor: cardColor, getLuckyColor: luckyCardColor, getTextColor: textColor, getCardSize: cardSize, getTextSize: textSize, getRowCount: rowCount, getIsShowPrizeList: isShowPrizeList, getLanguage: userLanguage, getBackground: backgroundImage, getImageList: imageList, getIsShowAvatar: isShowAvatar,
const { getTopTitle: topTitle, getTheme: localTheme, getPatterColor: patternColor, getPatternList: patternList, getCardColor: cardColor, getLuckyColor: luckyCardColor, getTextColor: textColor, getCardSize: cardSize, getTextSize: textSize, getRowCount: rowCount, getIsShowPrizeList: isShowPrizeList, getLanguage: userLanguage, getBackground: backgroundImage, getFont: currentFont, getImageList: imageList, getIsShowAvatar: isShowAvatar,
} = storeToRefs(globalConfig)
const { getAlreadyPersonList: alreadyPersonList, getNotPersonList: notPersonList } = storeToRefs(personConfig)
const { getFonts, disabled: disabledFonts, fonts } = useLocalFonts()
const colorPickerRef = ref()
const resetDataDialogRef = ref()
interface ThemeDaType {
@@ -42,6 +44,7 @@ const patternColorValue = ref(structuredClone(patternColor.value))
const themeList = ref(daisyuiThemes)
const daisyuiThemeList = ref<ThemeDaType>(daisyuiThemes)
const backgroundImageValue = ref(backgroundImage.value)
const currentFontValue = ref(currentFont.value)
const formData = ref({
rowCount: rowCountValue,
})
@@ -150,6 +153,10 @@ watch(isShowPrizeListValue, () => {
watch(backgroundImageValue, (val) => {
globalConfig.setBackground(val)
})
watch(currentFontValue, (val) => {
console.log('currentFontValue', val)
globalConfig.setFont(val)
})
watch(languageValue, (val: string) => {
globalConfig.setLanguage(val)
})
@@ -225,6 +232,16 @@ onMounted(() => {
class="w-full max-w-xs input input-bordered"
>
</label>
<label class="w-full max-w-xs form-control">
<div class="label">
<span class="label-text">字体</span>
</div>
<select v-model="currentFontValue" class="w-full max-w-xs border-solid select border-1" @click="getFonts">
<option disabled selected>选择字体</option>
<option v-for="item in fonts" :key="item.fullName" :style="{ fontFamily: `${item.fullName}`, fontSize: 'normal', fontWeight: 'normal' }" :value="item.fullName">{{ item.fullName }}</option>
</select>
</label>
</fieldset>
<!-- 布局设置列数卡片宽度卡片高度 -->
<fieldset class="p-4 border text-setting fieldset bg-base-200 border-base-300 rounded-box w-xs">

View File

@@ -1,51 +1,76 @@
<script setup lang='ts'>
import { Grip } from 'lucide-vue-next'
import { onMounted, ref, watch } from 'vue'
import { VueDraggable } from 'vue-draggable-plus'
import { ChevronDown, ChevronUp } from 'lucide-vue-next'
import { ref } from 'vue'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
import { useLocalFonts } from '@/hooks/useLocalFonts'
const list = ref([
{
name: 'Joao',
id: '1',
},
{
name: 'Jean',
id: '2',
},
{
name: 'Johanna',
id: '3',
},
{
name: 'Juan',
id: '4',
},
])
onMounted(() => {
const inputRef = ref()
})
const { getFonts, disabled, fonts } = useLocalFonts()
</script>
<template>
<div>
<button class="btn btn-error">
打印
</button>
<VueDraggable
v-model="list"
:animation="150"
handle=".handle"
class="flex flex-col gap-2 p-4 w-300px bg-gray-500/5 rounded"
>
<div
v-for="(item, index) in list"
:key="item.id"
class="h-50px bg-gray-500/5 px-2 rounded flex items-center justify-between"
>
<Grip class="handle cursor-move" />
<input v-model="item.name" type="text">
</div>
</VueDraggable>
<div class="flex flex-col gap-4">
<div class="text-2xl">
code
</div>
<div class="text-2xl" style="font-family: 'Consolas Bold Italic';">
code
</div>
<font-select id="font-select-1" value="" style="display: initial;" />
</div>
<div class="w-full h-full flex justify-center items-center">
<DropdownMenu>
<DropdownMenuTrigger as-child>
<label class="input cursor-default!" @click="getFonts">
<input ref="inputRef" type="search" class="grow" placeholder="Search">
<ChevronDown class="cursor-default" @click="inputRef.focus()" />
<ChevronUp class="cursor-default" @click="inputRef.focus()" />
</label>
</DropdownMenuTrigger>
<DropdownMenuContent class="w-56" align="start">
<DropdownMenuLabel>My Account</DropdownMenuLabel>
<DropdownMenuGroup>
<!-- <DropdownMenuItem v-for="[key, value] in Array.from(fonts)" :key="key" :style="{ fontFamily: `${key}` }">
{{ key }}
</DropdownMenuItem> -->
<DropdownMenuSub v-for="[key, children] in Array.from(fonts)" :key="key">
<DropdownMenuSubTrigger>
<span :style="{ fontFamily: `${key}` }">{{ key }}</span>
</DropdownMenuSubTrigger>
<DropdownMenuPortal>
<DropdownMenuSubContent>
<DropdownMenuItem v-for="child in children" :key="child.value">
<span :style="{ fontFamily: `${child.value}` }">{{ child.name }}</span>
</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuPortal>
</DropdownMenuSub>
<DropdownMenuItem>
New Team
<DropdownMenuShortcut>+T</DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuItem>GitHub</DropdownMenuItem>
<DropdownMenuItem>Support</DropdownMenuItem>
<DropdownMenuItem disabled>
API
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem>
Log out
<DropdownMenuShortcut>Q</DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</template>

12
src/window.d.ts vendored Normal file
View File

@@ -0,0 +1,12 @@
// src/types/window.d.ts
interface FontData {
family: string
fullName: string
postscriptName: string
style: string
blob: () => Promise<Blob>
}
interface Window {
queryLocalFonts?: (options?) => Promise<FontData[]>
}