update at 2026-02-07 12:55:25

This commit is contained in:
douboer
2026-02-07 12:55:25 +08:00
parent eb2ad134d3
commit 5036daea3e
38 changed files with 56 additions and 31 deletions

View File

@@ -2,7 +2,7 @@
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/assets/webicon.svg" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Font2SVG - 字体转SVG工具</title>
</head>

View File

Before

Width:  |  Height:  |  Size: 170 KiB

After

Width:  |  Height:  |  Size: 170 KiB

View File

@@ -62,9 +62,15 @@ async function handleExport(format: ExportFormat) {
if (selectedItems.length === 1) {
// 单个字体,直接下载 SVG
const item = selectedItems[0]
if (!item?.fontInfo.font) {
alert('选中字体未加载完成,请稍后重试')
return
}
const font = item.fontInfo.font
const svgResult = await generateSvg({
text: inputText,
font: item.fontInfo.font,
font,
fontSize: uiStore.fontSize,
fillColor: uiStore.textColor,
letterSpacing: 0
@@ -87,9 +93,15 @@ async function handleExport(format: ExportFormat) {
for (const item of selectedItems) {
try {
const font = item.fontInfo.font
if (!font) {
console.warn(`字体 ${item.fontInfo.name} 尚未加载,已跳过导出`)
continue
}
const svgResult = await generateSvg({
text: inputText,
font: item.fontInfo.font,
font,
fontSize: uiStore.fontSize,
fillColor: uiStore.textColor,
letterSpacing: 0
@@ -161,12 +173,12 @@ console.log('App.vue: script setup completed')
<div class="flex gap-2 items-center shrink-0 h-24 px-2 py-1">
<!-- webicon - 48x48 -->
<div class="w-12 h-12 rounded-xl overflow-hidden shrink-0">
<img src="/assets/webicon.svg" alt="logo" class="w-full h-full object-cover" />
<img src="./assets/webicon.svg" alt="logo" class="w-full h-full object-cover" />
</div>
<!-- 星程字体转换 - 弹性宽度 -->
<div class="shrink-0 max-w-[225px] min-w-[120px]" style="height: 72px;">
<img src="/assets/icons/星程字体转换.svg" alt="星程SVG文字生成 TEXT to SVG" class="w-full h-full object-contain" />
<img src="./assets/icons/星程字体转换.svg" alt="星程SVG文字生成 TEXT to SVG" class="w-full h-full object-contain" />
</div>
<!-- slider - 增加宽度 -->
@@ -176,7 +188,7 @@ console.log('App.vue: script setup completed')
class="w-4 h-4 shrink-0 cursor-pointer hover:opacity-70 transition-opacity flex items-center justify-center p-0 border-0 bg-transparent"
title="减小字体"
>
<img src="/assets/icons/icons_idx%20_38.svg" alt="A-" class="w-4 h-4 object-contain" />
<img src="./assets/icons/icons_idx%20_38.svg" alt="A-" class="w-4 h-4 object-contain" />
</button>
<div class="flex-1 h-6 flex items-center relative">
<input
@@ -204,14 +216,14 @@ console.log('App.vue: script setup completed')
class="w-6 h-6 shrink-0 cursor-pointer hover:opacity-70 transition-opacity flex items-center justify-center p-0 border-0 bg-transparent"
title="增大字体"
>
<img src="/assets/icons/icons_idx%20_33.svg" alt="A+" class="w-6 h-6 object-contain" />
<img src="./assets/icons/icons_idx%20_33.svg" alt="A+" class="w-6 h-6 object-contain" />
</button>
</div>
<!-- 文字颜色选择 -->
<div class="shrink-0 relative w-9 h-9">
<label class="w-full h-full flex items-center justify-center cursor-pointer">
<img src="/assets/icons/choose-color.svg" alt="颜色" class="w-9 h-9 object-contain" />
<img src="./assets/icons/choose-color.svg" alt="颜色" class="w-9 h-9 object-contain" />
<input
type="color"
:value="uiStore.textColor"
@@ -235,7 +247,7 @@ console.log('App.vue: script setup completed')
<!-- Export Group -->
<div class="flex items-center gap-1 shrink-0 border border-[#8552A1] rounded-lg px-1 py-1 bg-[#f7f8fa] shadow-sm">
<div class="w-[18px] h-[42px] shrink-0 pointer-events-none">
<img src="/assets/icons/export.svg" alt="导出" class="w-full h-full object-contain" />
<img src="./assets/icons/export.svg" alt="导出" class="w-full h-full object-contain" />
</div>
<button
@@ -243,7 +255,7 @@ console.log('App.vue: script setup completed')
class="w-12 h-12 shrink-0 cursor-pointer hover:opacity-85 transition-opacity flex items-center justify-center p-0 border-0 bg-transparent"
title="导出 SVG"
>
<img src="/assets/icons/export-svg.svg" alt="导出SVG" class="w-12 h-12 object-contain" />
<img src="./assets/icons/export-svg.svg" alt="导出SVG" class="w-12 h-12 object-contain" />
</button>
<button
@@ -251,7 +263,7 @@ console.log('App.vue: script setup completed')
class="w-12 h-12 shrink-0 cursor-pointer hover:opacity-85 transition-opacity flex items-center justify-center p-0 border-0 bg-transparent"
title="导出 PNG"
>
<img src="/assets/icons/export-png.svg" alt="导出PNG" class="w-12 h-12 object-contain" />
<img src="./assets/icons/export-png.svg" alt="导出PNG" class="w-12 h-12 object-contain" />
</button>
</div>
</div>

View File

Before

Width:  |  Height:  |  Size: 989 B

After

Width:  |  Height:  |  Size: 989 B

View File

Before

Width:  |  Height:  |  Size: 488 B

After

Width:  |  Height:  |  Size: 488 B

View File

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

Before

Width:  |  Height:  |  Size: 330 B

After

Width:  |  Height:  |  Size: 330 B

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 749 B

After

Width:  |  Height:  |  Size: 749 B

View File

Before

Width:  |  Height:  |  Size: 403 B

After

Width:  |  Height:  |  Size: 403 B

View File

Before

Width:  |  Height:  |  Size: 404 B

After

Width:  |  Height:  |  Size: 404 B

View File

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 304 B

View File

Before

Width:  |  Height:  |  Size: 755 B

After

Width:  |  Height:  |  Size: 755 B

View File

Before

Width:  |  Height:  |  Size: 585 B

After

Width:  |  Height:  |  Size: 585 B

View File

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 304 B

View File

Before

Width:  |  Height:  |  Size: 749 B

After

Width:  |  Height:  |  Size: 749 B

View File

Before

Width:  |  Height:  |  Size: 437 B

After

Width:  |  Height:  |  Size: 437 B

View File

Before

Width:  |  Height:  |  Size: 392 B

After

Width:  |  Height:  |  Size: 392 B

View File

Before

Width:  |  Height:  |  Size: 198 B

After

Width:  |  Height:  |  Size: 198 B

View File

Before

Width:  |  Height:  |  Size: 392 B

After

Width:  |  Height:  |  Size: 392 B

View File

Before

Width:  |  Height:  |  Size: 392 B

After

Width:  |  Height:  |  Size: 392 B

View File

Before

Width:  |  Height:  |  Size: 383 B

After

Width:  |  Height:  |  Size: 383 B

View File

Before

Width:  |  Height:  |  Size: 279 B

After

Width:  |  Height:  |  Size: 279 B

View File

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

Before

Width:  |  Height:  |  Size: 473 KiB

After

Width:  |  Height:  |  Size: 473 KiB

View File

Before

Width:  |  Height:  |  Size: 496 B

After

Width:  |  Height:  |  Size: 496 B

View File

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 128 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 170 KiB

View File

@@ -38,7 +38,7 @@ function isInPreview(fontId: string): boolean {
>
<!-- 字体图标 -->
<div class="w-4 h-4 shrink-0">
<img src="/assets/icons/icons_idx%20_18.svg" alt="font" class="w-full h-full" />
<img src="../assets/icons/icons_idx%20_18.svg" alt="font" class="w-full h-full" />
</div>
<!-- 字体名称 -->
@@ -52,7 +52,7 @@ function isInPreview(fontId: string): boolean {
class="w-[18px] h-[18px] shrink-0 border rounded-full flex items-center justify-center p-0 bg-transparent"
:class="isInPreview(font.id) ? 'bg-[#9b6bc2] border-[#9b6bc2]' : 'border-[#c9cdd4]'"
>
<img v-if="isInPreview(font.id)" src="/assets/icons/checkbox.svg" alt="选中" class="w-[11px] h-[9px]" />
<img v-if="isInPreview(font.id)" src="../assets/icons/checkbox.svg" alt="选中" class="w-[11px] h-[9px]" />
</button>
<!-- 收藏按钮 -->
@@ -61,7 +61,7 @@ function isInPreview(fontId: string): boolean {
class="w-[18px] h-[17px] shrink-0 p-0 border-0 bg-transparent"
>
<img
src="/assets/icons/icons_idx%20_19.svg"
src="../assets/icons/icons_idx%20_19.svg"
alt="收藏"
class="w-full h-full"
:class="isFavorite(font.id) ? 'favorite-active' : ''"

View File

@@ -51,13 +51,13 @@ function isInPreview(node: FontTreeNode): boolean {
>
<img
v-if="node.expanded"
src="/assets/icons/zhedie.svg"
src="../assets/icons/zhedie.svg"
alt="收起"
class="w-[15px] h-[15px]"
/>
<img
v-else
src="/assets/icons/icons_idx%20_12.svg"
src="../assets/icons/icons_idx%20_12.svg"
alt="展开"
class="w-[15px] h-[15px]"
/>
@@ -79,7 +79,7 @@ function isInPreview(node: FontTreeNode): boolean {
<!-- 字体列表 -->
<div v-if="node.expanded && node.children" class="flex flex-col gap-3 mt-3">
<div
v-for="(child, index) in node.children"
v-for="child in node.children"
:key="child.name"
class="flex items-center gap-2 border-b border-[#c9cdd4] pb-2 relative"
>
@@ -88,7 +88,7 @@ function isInPreview(node: FontTreeNode): boolean {
<!-- 字体图标 -->
<div class="w-4 h-4 shrink-0 ml-[17px]">
<img src="/assets/icons/icons_idx%20_18.svg" alt="font" class="w-full h-full" />
<img src="../assets/icons/icons_idx%20_18.svg" alt="font" class="w-full h-full" />
</div>
<!-- 字体名称 -->
@@ -102,7 +102,7 @@ function isInPreview(node: FontTreeNode): boolean {
class="w-[18px] h-[18px] shrink-0 border rounded-full flex items-center justify-center p-0 bg-transparent"
:class="isInPreview(child) ? 'bg-[#9b6bc2] border-[#9b6bc2]' : 'border-[#c9cdd4]'"
>
<img v-if="isInPreview(child)" src="/assets/icons/checkbox.svg" alt="选中" class="w-[11px] h-[9px]" />
<img v-if="isInPreview(child)" src="../assets/icons/checkbox.svg" alt="选中" class="w-[11px] h-[9px]" />
</button>
<!-- 收藏按钮 -->
@@ -111,7 +111,7 @@ function isInPreview(node: FontTreeNode): boolean {
class="w-[18px] h-[17px] shrink-0 p-0 border-0 bg-transparent"
>
<img
src="/assets/icons/icons_idx%20_19.svg"
src="../assets/icons/icons_idx%20_19.svg"
alt="收藏"
class="w-full h-full"
:class="isFavorite(child) ? 'favorite-active' : ''"

View File

@@ -97,7 +97,7 @@ function toggleSelectItem(item: PreviewItemType) {
>
<div class="flex items-center gap-[8px] border-b border-[#c9cdd4] pb-[8px] pr-[8px]">
<div class="w-[24px] h-[24px] shrink-0">
<img src="/assets/icons/icons_idx%20_32.svg" alt="字体" class="w-full h-full" />
<img src="../assets/icons/icons_idx%20_32.svg" alt="字体" class="w-full h-full" />
</div>
<div class="flex-1 text-xs text-[#86909c]">
@@ -109,7 +109,7 @@ function toggleSelectItem(item: PreviewItemType) {
class="w-[18px] h-[18px] shrink-0 border rounded-full flex items-center justify-center p-0 bg-transparent"
:class="item.selected ? 'bg-[#9b6bc2] border-[#9b6bc2]' : 'border-[#c9cdd4]'"
>
<img v-if="item.selected" src="/assets/icons/checkbox.svg" alt="选中" class="w-[11px] h-[9px]" />
<img v-if="item.selected" src="../assets/icons/checkbox.svg" alt="选中" class="w-[11px] h-[9px]" />
</button>
</div>

View File

@@ -48,4 +48,14 @@ declare module 'opentype.js' {
declare module 'harfbuzzjs' {
export default function (): Promise<any>
}
}
declare module 'harfbuzzjs/hb.js' {
const createHarfBuzz: any
export default createHarfBuzz
}
declare module 'harfbuzzjs/hbjs.js' {
const bindHarfBuzz: any
export default bindHarfBuzz
}

View File

@@ -2,9 +2,6 @@ import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import UnoCSS from 'unocss/vite'
import wasm from 'vite-plugin-wasm'
import fs from 'fs'
import path from 'path'
import { homedir } from 'os'
// https://vite.dev/config/
export default defineConfig({
@@ -18,9 +15,5 @@ export default defineConfig({
server: {
host: '0.0.0.0',
port: 5174,
https: {
key: fs.readFileSync(path.join(homedir(), 'mac.biboer.cn_ecc/mac.biboer.cn.key')),
cert: fs.readFileSync(path.join(homedir(), 'mac.biboer.cn_ecc/fullchain.cer'))
}
}
})