All checks were successful
Build and Deploy (tool.xpcool.com) / build-and-deploy (push) Successful in 1m6s
视觉体系(核心是「令牌 → TDesign 桥接」) - 新增 tokens.scss:--tk-* 设计令牌(青玉 Jade 单一强调色、冷调中性色阶、 圆角/间距/字号/z-index/动效规范、按语言切换字体栈) - 新增 tdesign-theme.scss:--tk-* → --td-* 桥接(含完整冷调灰阶 1-14) → 60+ 个未改动的存量工具页零成本继承新配色与圆角 - index.scss 重写:只过渡颜色、统一 focus-visible、reduced-motion 降级 - 新增 v-reveal 滚动进入指令 布局与交互 - MainLayout 重写:毛玻璃 sticky 顶栏 + 三区布局 + 页脚(含备案号) - 新增 CommandPalette(⌘K/Ctrl+K)、LocaleSwitch(显示语言代码不用国旗)、 ThemeSwitch(三态;图标显示生效 mode、菜单勾选用户偏好 preference) - SideNav 重写:内联筛选、可折叠分组持久化、活动态指示条、需联网标记 - HomeView 重写:左对齐 Hero + 真实可用搜索 + 概览数字条 + 服务端工具专区 国际化与主题 - vue-i18n 11 + zh-CN/en-US/ja-JP/ko-KR 完整语言包(58 个工具名与描述全译) - helpers 取词带中文兜底;index.html 防闪烁内联脚本与 store 三处同步 - 主题三态 light/dark/auto,preference 与 mode 分离 服务端对接(service.xpcool.com /api/service/open/tools/*) - 新增 openTools.ts:接口元数据与调用函数共用同一份路径定义 - 改造/新建 6 页:ip-info、uuid、hash(服务端 MD5 两端口径对比)、 timestamp(服务端时钟 + 时钟偏移)、random-string、api-status - 均为「本机 / 服务端」双模式,默认本机、不自动打网络请求 - 后端未实现的 5 个接口用 BackendPending 如实标注,不伪装可用 修复 - 空分类渲染缺陷(health/study/travel 无工具却渲染空区块),分类 9 → 6 - UnoCSS panel 快捷类补内边距;IpInfoView 漏 onBeforeUnmount; SideNav 末尾 import;HomeView 错误导入 SUPPORTED_LOCALES 其他 - 新增 src/config.ts 集中站点常量,页脚展示备案号并链工信部核验 - docs/api-contract.md 按线上实际重写;PROJECT_STATE.md 全面更新 - 构建通过:vue-tsc --noEmit + vite build
70 lines
2.4 KiB
TypeScript
70 lines
2.4 KiB
TypeScript
import { createRouter, createWebHistory } from 'vue-router'
|
||
import type { RouteRecordRaw } from 'vue-router'
|
||
import MainLayout from '@/layout/MainLayout.vue'
|
||
import { tools } from './tools'
|
||
import { i18n } from '@/i18n'
|
||
import { toolName } from '@/i18n/helpers'
|
||
|
||
/**
|
||
* 路由约定:每个工具对应一个独立路由,路径与 tools.ts 中的 path 一致。
|
||
* 所有工具页面均嵌套在 MainLayout 下,共享侧边导航与主题/语言切换。
|
||
* 未匹配路径统一重定向到首页。
|
||
*
|
||
* 标题本地化:meta 里存的是「取词用的 key」而不是写死的标题文案,
|
||
* 这样切换语言后重新计算即可得到对应语言的标题,无需重建路由表。
|
||
*/
|
||
const routes: RouteRecordRaw[] = [
|
||
{
|
||
path: '/',
|
||
component: MainLayout,
|
||
children: [
|
||
{
|
||
path: '',
|
||
name: 'home',
|
||
component: () => import('@/views/HomeView.vue'),
|
||
// 首页标题直接取站点名,避免出现「首页 · 在线工具箱」这类冗余
|
||
meta: { titleKey: 'app.name' },
|
||
},
|
||
// 由工具注册表自动生成路由,无需手动维护
|
||
...tools.map((t) => ({
|
||
path: t.path,
|
||
name: t.path,
|
||
component: t.component,
|
||
meta: { titleKey: `tool.${t.path}.name`, toolPath: t.path, fallbackName: t.name },
|
||
})),
|
||
],
|
||
},
|
||
{ path: '/:pathMatch(.*)*', redirect: '/' },
|
||
]
|
||
|
||
const router = createRouter({
|
||
// HTML5 History 模式(部署到 Nginx 等需配置 try_files 回退,见 README)
|
||
history: createWebHistory(),
|
||
routes,
|
||
})
|
||
|
||
/** 按当前语言把 meta 转成页面标题 */
|
||
function resolveTitle(meta: Record<string, unknown>): string {
|
||
const key = meta.titleKey as string | undefined
|
||
if (key === 'app.name') return i18n.global.t('app.name')
|
||
if (key && i18n.global.te(key)) return i18n.global.t(key)
|
||
const toolPath = meta.toolPath as string | undefined
|
||
if (toolPath) return toolName(toolPath, (meta.fallbackName as string | undefined) ?? '')
|
||
return i18n.global.t('app.name')
|
||
}
|
||
|
||
/**
|
||
* 同步浏览器标题。
|
||
* 除路由切换外,切换语言时也需要调用一次,否则标题会停留在旧语言。
|
||
*/
|
||
export function syncDocumentTitle() {
|
||
const meta = (router.currentRoute.value.meta ?? {}) as Record<string, unknown>
|
||
document.title = `${resolveTitle(meta)} · ${i18n.global.t('app.short')}`
|
||
}
|
||
|
||
router.afterEach(() => {
|
||
syncDocumentTitle()
|
||
})
|
||
|
||
export default router
|