From 32065d99e1116495eeb1ba81516e0b6bf23de98a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?He=CC=84sperus?= Date: Fri, 16 Jan 2026 23:05:03 +0800 Subject: [PATCH] refactor(layout, i18n): remove sidebar component and related logic - Remove VPSidebar component from Layout.vue - Remove useSidebarControl composable from Layout.vue - Remove hasSidebar flag from VPContent and VPDoc components - Update VPDocAsideOutline to use useTemplateRef and useI18n - Refactor i18n logic - Remove i18n related config since it's handled internally --- .github/workflows/ci.yml | 40 ++ .vitepress/config.ts | 59 ++- biome.json | 11 +- package.json | 3 +- pages/{ => en}/components/landingCards.vue | 6 +- pages/{ => en}/components/landingCarousel.vue | 10 +- pages/en/index.md | 2 +- pages/zh-Hans/components/landingCards.vue | 418 ++++++++++++++++++ pages/zh-Hans/components/landingCarousel.vue | 133 ++++++ pages/zh-Hans/index.md | 16 + pages/zh-Hans/json-canvas-viewer.md | 96 ++++ pages/zh-Hans/pointeract.md | 72 +++ src/Layout.vue | 18 +- src/NotFound.vue | 8 +- src/components/VPAlgoliaSearchBox.vue | 6 +- src/components/VPBadge.vue | 8 +- src/components/VPCarbonAds.vue | 4 +- src/components/VPContent.vue | 15 +- src/components/VPDoc.vue | 22 +- src/components/VPDocAsideCarbonAds.vue | 4 +- src/components/VPDocAsideOutline.vue | 15 +- src/components/VPDocFooter.vue | 6 +- src/components/VPDocFooterLastUpdated.vue | 9 +- src/components/VPDocOutlineItem.vue | 4 +- src/components/VPFeature.vue | 4 +- src/components/VPFeatures.vue | 4 +- src/components/VPFlyout.vue | 4 +- src/components/VPFooter.vue | 7 +- src/components/VPHero.vue | 4 +- src/components/VPHome.vue | 2 +- src/components/VPHomeSponsors.vue | 4 +- src/components/VPImage.vue | 4 +- src/components/VPLocalNav.vue | 50 +-- src/components/VPLocalNavOutlineDropdown.vue | 19 +- src/components/VPLocalSearchBox.vue | 4 +- src/components/VPMenu.vue | 4 +- src/components/VPMenuGroup.vue | 4 +- src/components/VPMenuLink.vue | 16 +- src/components/VPNavBar.vue | 50 +-- src/components/VPNavBarExtra.vue | 4 +- src/components/VPNavBarHamburger.vue | 4 +- src/components/VPNavBarMenuGroup.vue | 6 +- src/components/VPNavBarMenuLink.vue | 4 +- src/components/VPNavBarSearch.vue | 4 +- src/components/VPNavBarTitle.vue | 28 +- src/components/VPNavBarTranslations.vue | 6 +- src/components/VPNavScreenAppearance.vue | 12 +- src/components/VPNavScreenMenuGroupLink.vue | 4 +- .../VPNavScreenMenuGroupSection.vue | 4 +- src/components/VPNavScreenMenuLink.vue | 4 +- src/components/VPSidebar.vue | 124 ------ src/components/VPSidebarGroup.vue | 51 --- src/components/VPSidebarItem.vue | 235 ---------- src/components/VPSocialLink.vue | 5 +- src/components/VPSocialLinks.vue | 6 +- src/components/VPSwitch.vue | 8 +- src/components/VPSwitchAppearance.vue | 11 +- src/components/VPTeamMembers.vue | 4 +- src/components/VPTeamMembersItem.vue | 4 +- src/components/contextMenu.vue | 27 +- src/components/loadingView.vue | 4 +- src/composables/aside.ts | 8 +- src/composables/contextMenuActions.ts | 2 +- src/composables/data.ts | 4 +- src/composables/edit-link.ts | 13 +- src/composables/flyout.ts | 8 +- src/composables/i18n.ts | 55 +++ src/composables/layout.ts | 64 +-- src/composables/outline.ts | 35 +- src/composables/prev-next.ts | 42 +- src/composables/sidebar.ts | 122 ----- src/composables/sponsor-grid.ts | 7 +- src/composables/themeToggleTransition.ts | 6 +- src/index.ts | 1 + src/shared/index.ts | 12 +- src/shared/types.ts | 5 +- src/store.ts | 9 - src/styles/posts.scss | 7 + src/styles/vars.scss | 10 - src/support/lru.ts | 5 +- src/support/sidebar.ts | 107 ----- src/support/translation.ts | 2 + src/support/utils.ts | 2 +- src/{shared => }/theme-config.ts | 175 +------- tsconfig.json | 1 + 85 files changed, 1138 insertions(+), 1288 deletions(-) create mode 100644 .github/workflows/ci.yml rename pages/{ => en}/components/landingCards.vue (98%) rename pages/{ => en}/components/landingCarousel.vue (95%) create mode 100644 pages/zh-Hans/components/landingCards.vue create mode 100644 pages/zh-Hans/components/landingCarousel.vue create mode 100644 pages/zh-Hans/index.md create mode 100644 pages/zh-Hans/json-canvas-viewer.md create mode 100644 pages/zh-Hans/pointeract.md delete mode 100644 src/components/VPSidebar.vue delete mode 100644 src/components/VPSidebarGroup.vue delete mode 100644 src/components/VPSidebarItem.vue create mode 100644 src/composables/i18n.ts delete mode 100644 src/composables/sidebar.ts delete mode 100644 src/store.ts delete mode 100644 src/support/sidebar.ts rename src/{shared => }/theme-config.ts (71%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..4b86752 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,40 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + types: [opened, synchronize, reopened, ready_for_review] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true # Cancel previous runs for same PR/branch + +jobs: + ci: + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Set up pnpm + uses: pnpm/action-setup@v4.2.0 + + - name: Set up Node.js + uses: actions/setup-node@v6 + with: + node-version: latest + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install + + - name: Run checks + run: pnpm check + + - name: Run test build + run: pnpm build \ No newline at end of file diff --git a/.vitepress/config.ts b/.vitepress/config.ts index c5baf44..e7464f9 100644 --- a/.vitepress/config.ts +++ b/.vitepress/config.ts @@ -12,32 +12,59 @@ export default defineConfig({ cleanUrls: true, lastUpdated: true, title: 'HESPERI', - description: "Hēsperus' (hesprs) portfolio, including information about Hēsperus' personalities, hobbies, and project introductions and demos.", rewrites: { 'en/:rest*': ':rest*' }, locales: { - root: { label: 'English', lang: 'en' }, - ja: { label: '日本語', lang: 'ja' }, + root: { + description: + "Hēsperus' (hesprs) portfolio, including information about Hēsperus' personalities, hobbies, and project introductions and demos.", + label: 'English', + lang: 'en', + themeConfig: { + nav: [ + { text: 'Home', link: '/' }, + { text: 'Pointeract', link: '/pointeract' }, + { text: 'Canvas Viewer', link: '/json-canvas-viewer' }, + ], + }, + head: [ + [ + 'meta', + { + name: 'keywords', + content: 'hesprs,hesperus,pointeract,projects,portfolio,json canvas viewer', + }, + ], + ], + }, + 'zh-Hans': { + description: 'Hēsperus(hesprs)的作品集,包含有关 Hēsperus 的个性、爱好以及项目介绍和演示。', + label: '简体中文', + lang: 'zh-Hans', + themeConfig: { + nav: [ + { text: '首页', link: '/zh-Hans/' }, + { text: 'Pointeract', link: '/zh-Hans/pointeract' }, + { text: 'Canvas Viewer', link: '/zh-Hans/json-canvas-viewer' }, + ], + }, + head: [ + [ + 'meta', + { + name: 'keywords', + content: 'hesprs,hesperus,pointeract,projects,portfolio,json canvas viewer', + }, + ], + ], + }, }, head: [ ['link', { rel: 'icon', href: '/favicon.ico' }], ['meta', { name: 'color-scheme', content: 'dark light' }], - [ - 'meta', - { - name: 'keywords', - content: 'hesprs,hesperus,pointeract,projects,portfolio,json canvas viewer', - }, - ], ], sitemap: { hostname: 'https://hesprs.github.io' }, themeConfig: { - nav: [ - { text: 'Home', link: '/' }, - { text: 'Pointeract', link: '/pointeract' }, - { text: 'Canvas Viewer', link: '/json-canvas-viewer' }, - ], logo: { src: '/logo-flat.svg', alt: 'Website logo' }, - search: { provider: 'local' }, socialLinks: [ { icon: 'npm', link: 'https://www.npmjs.com/~hesprs' }, diff --git a/biome.json b/biome.json index 6724efd..b97409d 100644 --- a/biome.json +++ b/biome.json @@ -1,7 +1,7 @@ { "$schema": "https://biomejs.dev/schemas/2.3.11/schema.json", "vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true }, - "files": { "includes": ["**", "!!**/dist", "!!docs/.vitepress/theme", "!package.json"] }, + "files": { "includes": ["**", "!!**/dist", "!!docs/.vitepress/theme", "!package.json", "!!**/public"] }, "formatter": { "enabled": true, "formatWithErrors": false, @@ -17,11 +17,12 @@ "rules": { "recommended": true, "complexity": { - "noImportantStyles": "off" + "noImportantStyles": "off", + "noBannedTypes": "off" }, - "correctness": { - "noUnknownPseudoClass": "off" - } + "correctness": { + "noUnknownPseudoClass": "off" + } }, "domains": { "vue": "recommended" diff --git a/package.json b/package.json index 45ec82b..9147437 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "dev": "vitepress dev", "build": "vitepress build", "preview": "vitepress preview", - "lint": "biome check --write" + "lint": "biome check --write", + "check": "tsc && biome check" }, "keywords": [], "author": "", diff --git a/pages/components/landingCards.vue b/pages/en/components/landingCards.vue similarity index 98% rename from pages/components/landingCards.vue rename to pages/en/components/landingCards.vue index ef0c1d6..0da7022 100644 --- a/pages/components/landingCards.vue +++ b/pages/en/components/landingCards.vue @@ -5,7 +5,7 @@ >Hello 👋
I am Hēsperus, - High school student • Open-source developer + High school student • OSS developer
Futuristic visionary • Classics enthusiast
@@ -74,7 +74,7 @@
-
+
Favorite Art Styles
Neo-Classicism @@ -344,7 +344,7 @@ const perspectives = [ > .icon { margin-right: 6px } } } - &.architecture::before { + &.art::before { background-image: url('https://img1.tucang.cc/api/image/show/e9287e92d561e0a07289663a3076bcbc'); } &.like { diff --git a/pages/components/landingCarousel.vue b/pages/en/components/landingCarousel.vue similarity index 95% rename from pages/components/landingCarousel.vue rename to pages/en/components/landingCarousel.vue index a229c2c..6d040de 100644 --- a/pages/components/landingCarousel.vue +++ b/pages/en/components/landingCarousel.vue @@ -1,14 +1,14 @@ \ No newline at end of file diff --git a/pages/zh-Hans/components/landingCards.vue b/pages/zh-Hans/components/landingCards.vue new file mode 100644 index 0000000..a7e8470 --- /dev/null +++ b/pages/zh-Hans/components/landingCards.vue @@ -0,0 +1,418 @@ + + + + + diff --git a/pages/zh-Hans/components/landingCarousel.vue b/pages/zh-Hans/components/landingCarousel.vue new file mode 100644 index 0000000..4c799a3 --- /dev/null +++ b/pages/zh-Hans/components/landingCarousel.vue @@ -0,0 +1,133 @@ + + + + + diff --git a/pages/zh-Hans/index.md b/pages/zh-Hans/index.md new file mode 100644 index 0000000..cb295cb --- /dev/null +++ b/pages/zh-Hans/index.md @@ -0,0 +1,16 @@ +--- +layout: home + +hero: + name: HESPERI + tagline: 关于 Hēsperus + image: + light: /logo.svg + dark: /logo-dark.svg + alt: 网站 Logo +--- + + + \ No newline at end of file diff --git a/pages/zh-Hans/json-canvas-viewer.md b/pages/zh-Hans/json-canvas-viewer.md new file mode 100644 index 0000000..a0e4920 --- /dev/null +++ b/pages/zh-Hans/json-canvas-viewer.md @@ -0,0 +1,96 @@ +--- +title: JSON Canvas Viewer +description: 一个前端库,提供可扩展的 JSON Canvas 查看器,能够轻松集成到任何现有框架和范式中。 +--- + + + + +## 演示 + + + +上方展示 JSON Canvas Viewer 架构的插图即为该查看器自身的实例,已加载 [`Minimap`](https://github.com/hesprs/json-canvas-viewer/wiki/3-%F0%9F%A7%A9-Modules#minimap )、[`Controls`](https://github.com/hesprs/json-canvas-viewer/wiki/3-%F0%9F%A7%A9-Modules#controls ) 和 [`MistouchPreventer`](https://github.com/hesprs/json-canvas-viewer/wiki/3-%F0%9F%A7%A9-Modules#mistouch-preventer ) 模块。 + +## 简介 + +[Obsidian](https://obsidian.md ) 提供了一款名为 [JSON Canvas](https://jsoncanvas.org ) 的强大工具,它使我能够以非线性方式思考,非常适合用于复杂状态机或依赖关系图等场景。虽然它在个人使用上已足够,但很难与他人分享,因为目前尚无成熟的方法可在 Obsidian 外部查看这些内容。 + +`JSON Canvas Viewer` 正是为解决此问题而生。它是一个基于 TypeScript 的 JSON Canvas 文件查看器,使用户可以直接在浏览器中查看和交互画布,或轻松将查看器嵌入网站。它不依赖任何特定框架构建,因此可轻易集成至任意框架中。 + +## 特性 + +- 在网页浏览器中查看 JSON Canvas 文件(`.canvas`) +- 可轻松嵌入网站 +- 支持交互式的平移与缩放功能 +- 能够完整显示 [官方规范](https://jsoncanvas.org/spec/1.0/ ) 中描述的所有画布特性 +- 响应式设计,适配移动端与触控板操作 +- 支持懒加载 +- 原生支持 TypeScript +- 🔥 性能优于在 Obsidian 中渲染画布! +- 🧩 开箱即用的可扩展性与摇树优化(tree-shaking),当前可选模块包括: + - [`Minimap`](https://github.com/hesprs/json-canvas-viewer/wiki/3-%F0%9F%A7%A9-Modules#minimap ):便于导航 + - [`Controls`](https://github.com/hesprs/json-canvas-viewer/wiki/3-%F0%9F%A7%A9-Modules#controls ):显示缩放及全屏按钮 + - [`MistouchPreventer`](https://github.com/hesprs/json-canvas-viewer/wiki/3-%F0%9F%A7%A9-Modules#mistouch-preventer ):防止画布干扰页面滚动 + - [`DebugPanel`](https://github.com/hesprs/json-canvas-viewer/wiki/3-%F0%9F%A7%A9-Modules#debug-panel ):显示缩放比例与位置数据 + +## 与现有技术栈的集成 + +JSON Canvas Viewer 目前可无缝集成以下技术栈 / 技术(包括但不限于): + +- ✅ Vanilla JS/TS:天然支持 +- ✅ 预渲染:[`renderToString`](https://github.com/hesprs/json-canvas-viewer/wiki/4-%F0%9F%96%87%EF%B8%8F-Prerendering-and-Bridges#prerendering ) +- ✅ Vite:[Vite 插件](https://github.com/hesprs/json-canvas-viewer/wiki/1-%F0%9F%9A%80-Quick-Start#setup-1 ) +- ✅ Vue:[Vue 组件](https://github.com/hesprs/json-canvas-viewer/wiki/4-%F0%9F%96%87%EF%B8%8F-Prerendering-and-Bridges#vue-component ) +- ✅ React:[React 组件](https://github.com/hesprs/json-canvas-viewer/wiki/4-%F0%9F%96%87%EF%B8%8F-Prerendering-and-Bridges#react-component ) + +了解更多关于 JSON Canvas Viewer 的信息,请访问 [GitHub 仓库](https://github.com/hesprs/json-canvas-viewer )。 + +## 许可证 + +JSON Canvas Viewer 采用 [MIT 许可证](https://mit-license.org/ ) 授权。 \ No newline at end of file diff --git a/pages/zh-Hans/pointeract.md b/pages/zh-Hans/pointeract.md new file mode 100644 index 0000000..6bf9945 --- /dev/null +++ b/pages/zh-Hans/pointeract.md @@ -0,0 +1,72 @@ +--- +title: Pointeract +description: 一个前端库,用于解析用户交互并派发平移缩放事件,是 Hammer.js 的轻量级且可扩展的替代方案。 +--- + + + + + +## 简介 + +Pointeract 是一个专注于处理 DOM 元素用户交互的小型工具库,可作为 [Hammer.js](https://hammerjs.github.io ) 等库的替代品。你只需绑定 DOM 元素并加载一些模块,它便会开始监控用户交互,并派发如 `trueClick` 和 `pan` 这样的事件及其数据。 + +它采用可扩展的架构构建,核心包体积仅 **1KB**(压缩后),功能则来自同样小巧的模块。它完全支持 **摇树优化(tree-shaking)**,使用的模块越少,最终打包体积就越小。 + +主页与文档:[pointeract.consensia.cc](https://pointeract.consensia.cc )。 + +## 优势 + +- **🐣 超小体积**:核心仅 **1KB**(压缩后),常规使用约 **1-2KB**。 +- **💪 强大稳健**:在复杂手势处理上表现出色,而大多数交互库在此类场景下会失败,[原因何在?](https://pointeract.consensia.cc/development/testing#chaotic-testing ) +- **🧩 高度可扩展**:可通过模块 API 轻松扩展 Pointeract 功能。 +- **🔌 运行时灵活**:配置项可响应式更新,可在运行时随时停止或启动任意模块。 +- **🛡️ 安全可靠**:不直接修改 DOM(`PreventDefault` 模块除外),细致的清理机制可防止内存泄漏。 + +## Pointeract 如何脱颖而出? + +市面上已有许多交互库,其中最著名的当属 `Interact.js` 和 `Hammer.js`,但 Pointeract 截然不同。 + +| 判定标准 | Pointeract | [Hammer.js](https://hammerjs.github.io ) | [Interact.js](https://interactjs.io ) | +|:---------------------------------------------------------------------------------------------|:-----------------------------------------------------:|:------------------------------------------------:|:---------------------------------------------------:| +| 使用 TypeScript 编写? | ✅ | ❌ | ✅ | +| 支持摇树优化? | [✅](https://bundlephobia.com/package/pointeract) | [❌](https://bundlephobia.com/package/hammerjs ) | [❌](https://bundlephobia.com/package/interactjs ) | +| 包体积(压缩后) | 👑 [2KB](https://bundlephobia.com/package/pointeract) | [7KB](https://bundlephobia.com/package/hammerjs ) | [28KB](https://bundlephobia.com/package/interactjs ) | +| 最近更新时间 | 👑 持续维护中 | 2015 年 | 2023 年 | +| 功能范围 | 指针及滚轮相关 | 指针相关 | 👑 指针及滚轮相关 + 全面的实用工具 | +| 稳健性?(参见 [测试](https://pointeract.consensia.cc/development/testing#chaotic-testing)) | ✅ | ❌ 元素抖动 | ❌ 忽略第二次触摸 | +| 可扩展性? | ✅ | ❌ | ❌ | + +## 许可证 + +Pointeract 采用 [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0.html) 授权。 \ No newline at end of file diff --git a/src/Layout.vue b/src/Layout.vue index 4277a71..f988d87 100644 --- a/src/Layout.vue +++ b/src/Layout.vue @@ -3,26 +3,20 @@ import { computed, provide, useSlots } from 'vue'; import Background from '@/components/background.vue'; import ContextMenu from '@/components/contextMenu.vue'; import LoadingView from '@/components/loadingView.vue'; -import VPBackdrop from '@/components/VPBackdrop.vue'; import VPContent from '@/components/VPContent.vue'; import VPFooter from '@/components/VPFooter.vue'; import VPNav from '@/components/VPNav.vue'; -import VPSidebar from '@/components/VPSidebar.vue'; import { useData } from '@/composables/data'; import { layoutInfoInjectionKey, registerWatchers } from '@/composables/layout'; -import { useSidebarControl } from '@/composables/sidebar'; import setupTransition from '@/composables/themeToggleTransition'; -const { isOpen: isSidebarOpen, close: closeSidebar } = useSidebarControl(); - -registerWatchers({ closeSidebar }); - const { frontmatter, isDark } = useData(); setupTransition(isDark); const slots = useSlots(); const heroImageSlotExists = computed(() => !!slots['home-hero-image']); +registerWatchers(); provide(layoutInfoInjectionKey, { heroImageSlotExists }); @@ -31,7 +25,6 @@ provide(layoutInfoInjectionKey, { heroImageSlotExists }); - - - - - -