diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b74d5efd..dc527e35 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,10 +1,5 @@ name: Test -env: - NODE_OPTIONS: --max-old-space-size=6144 - PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1' - VITEST_SEGFAULT_RETRY: 3 - on: push: branches: [main] @@ -45,6 +40,8 @@ jobs: - name: Install deps run: pnpm install + env: + PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 - name: Install Playwright run: pnpm playwright install chromium diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bb8681c..ec6ee176 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,90 @@ +## [2.0.0-alpha.3](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.2...v2.0.0-alpha.3) (2025-02-24) + +### Bug Fixes + +- **build:** `--minify` not working as documented ([9b5c037](https://github.com/vuejs/vitepress/commit/9b5c0377cd3474447c84b2901801287f3caf3d82)), closes [#4523](https://github.com/vuejs/vitepress/issues/4523) +- **build:** deterministic code group ids ([#4565](https://github.com/vuejs/vitepress/issues/4565)) ([b930b8d](https://github.com/vuejs/vitepress/commit/b930b8d5310f1691d8d9f009f45b70122e4ce800)) +- **markdown:** include content of all tokens in heading ids ([68dff2a](https://github.com/vuejs/vitepress/commit/68dff2af8547ae70f6622ac826affd76f2f6378e)), closes [#4561](https://github.com/vuejs/vitepress/issues/4561) +- **client:** set correct oldURL and newURL for hashchange ([#4573](https://github.com/vuejs/vitepress/issues/4573)) ([d1f2afd](https://github.com/vuejs/vitepress/commit/d1f2afdf0fbb022f12cc12295723b3b7c7ef5cb1)) +- **theme:** allow interactions behind scroll shadow ([#4537](https://github.com/vuejs/vitepress/issues/4537)) ([091d584](https://github.com/vuejs/vitepress/commit/091d5840ae15b64e04e8c07fbc0263a2749571bd)) +- **theme:** code block contrast ratio ([#4487](https://github.com/vuejs/vitepress/issues/4487)) ([5dccaee](https://github.com/vuejs/vitepress/commit/5dccaeef055beb109919f8990032975a0d630384)) +- **build:** fix flaky embedded languages highlighting ([#4566](https://github.com/vuejs/vitepress/issues/4566)) ([1969cf4](https://github.com/vuejs/vitepress/commit/1969cf4f3b93ad105595e4e2f8b030b04eb1c975)) + +### Features + +- **cli:** support custom `srcDir` ([#4270](https://github.com/vuejs/vitepress/issues/4270)) ([518c094](https://github.com/vuejs/vitepress/commit/518c0945f159aae679ef710bb48ae3ab3891cc9f)) +- **cli:** support custom npm scripts prefix ([#4271](https://github.com/vuejs/vitepress/issues/4271)) ([e5a0ee8](https://github.com/vuejs/vitepress/commit/e5a0ee8161752a77c5bb9546245a940cb5f28fb8)) +- **build:** dynamic routes plugin overhaul ([#4525](https://github.com/vuejs/vitepress/issues/4525)) ([a62ea6a](https://github.com/vuejs/vitepress/commit/a62ea6a832a33b756642b24ad5d38c248e08b554)) +- **build:** update to shiki v3 ([#4571](https://github.com/vuejs/vitepress/issues/4571)) ([52c2aa1](https://github.com/vuejs/vitepress/commit/52c2aa178d4b3fa98b863cf28f0ccf6d2aabcd93)) +- **build:** use `markdown-it-async`, remove `synckit` ([#4507](https://github.com/vuejs/vitepress/issues/4507)) ([8062235](https://github.com/vuejs/vitepress/commit/80622356f1d648577ee47ee3a44b04bb015ee462)) + +### BREAKING CHANGES + +- markdown-it-async is used instead of markdown-it. If you're using custom content renderer for local search, you'll need to do `await md.renderAsync` instead of `md.render`. +- Internals are modified a bit to better support vite 6 and handle HMR more correctly. For most users this won't need any change on their side. +- shiki is upgraded to v3. There shouldn't be any breaking change but if you see any issue, please report it. + +## [2.0.0-alpha.2](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.1...v2.0.0-alpha.2) (2025-01-23) + +### Bug Fixes + +- fix docsearch navigation and rendering ([e035027](https://github.com/vuejs/vitepress/commit/e0350275b39258a61ee867840ce1c6f5b2cecf2a)) +- **types:** support preload built-in shiki languages as string ([#4513](https://github.com/vuejs/vitepress/issues/4513)) ([4f77b4f](https://github.com/vuejs/vitepress/commit/4f77b4fdfdbe945e482348a57731bff5fb4672fc)) + +### Features + +- allow `markdown.config` and `markdown.preConfig` to accept async function ([#4512](https://github.com/vuejs/vitepress/issues/4512)) ([b88ae8d](https://github.com/vuejs/vitepress/commit/b88ae8d4a11a20104b2007c2631eb7aeb123d965)) +- support same page navigation in `router.go` and expose decoded hash and query from the `route` object ([#4511](https://github.com/vuejs/vitepress/issues/4511)) ([23d3281](https://github.com/vuejs/vitepress/commit/23d3281ed6f1111ab15708ca1fd86202674f8ef7)) + +## [2.0.0-alpha.1](https://github.com/vuejs/vitepress/compare/v1.6.2...v2.0.0-alpha.1) (2025-01-22) + +### Features + +- upgrade vite to v6 ([#4504](https://github.com/vuejs/vitepress/issues/4504)) ([6a2efc3](https://github.com/vuejs/vitepress/commit/6a2efc385c90b088241db05f5263b2f3e1f757cf)) + +## [1.6.3](https://github.com/vuejs/vitepress/compare/v1.6.2...v1.6.3) (2025-01-22) + +### Bug Fixes + +- docsearch not rendering properly ([3e4120e](https://github.com/vuejs/vitepress/commit/3e4120e94805156bf63587fd633162433dbaf260)) + +## [1.6.2](https://github.com/vuejs/vitepress/compare/v1.6.1...v1.6.2) (2025-01-22) + +### Bug Fixes + +- fix static content removal for lean chunks due to Vue 3.5 changes ([#4508](https://github.com/vuejs/vitepress/issues/4508)) ([8214cae](https://github.com/vuejs/vitepress/commit/8214cae21bb16842d8870d5867e974146c51fd61)) + +## [1.6.1](https://github.com/vuejs/vitepress/compare/v1.6.0...v1.6.1) (2025-01-20) + +### Bug Fixes + +- **build:** escape `$` in replace pattern in dynamic routes plugin ([e812916](https://github.com/vuejs/vitepress/commit/e8129167c76104d59d31a77b16dff3458e6af5eb)), closes [#4499](https://github.com/vuejs/vitepress/issues/4499) +- **theme/regression:** broken hero heading at certain viewports ([37dbe89](https://github.com/vuejs/vitepress/commit/37dbe895d4cf813e6eb1289f24c637945eec0d1f)) + +# [1.6.0](https://github.com/vuejs/vitepress/compare/v1.5.0...v1.6.0) (2025-01-20) + +### Bug Fixes + +- **build:** out of order css in prod builds ([241d17d](https://github.com/vuejs/vitepress/commit/241d17d9839f06b17c3898b1a8ba0f9fa12da0d1)), closes [#4098](https://github.com/vuejs/vitepress/issues/4098) +- **build:** properly strip vpi-social css declaration in debug mode ([c61182a](https://github.com/vuejs/vitepress/commit/c61182ab278350699b5d50461788478a340790aa)) +- **build:** respect `vite.clearScreen` in build ([8ea776a](https://github.com/vuejs/vitepress/commit/8ea776addc2c3bcabf3c707a9a81d6e0080a8fcb)), closes [#4468](https://github.com/vuejs/vitepress/issues/4468) +- **build:** specify mode for iconify ([8a5e8ea](https://github.com/vuejs/vitepress/commit/8a5e8ea4f5b7cba0a6c909d8949f0c20426104a6)) +- **theme:** apply `externalLinkIcon` option on `VPHome` ([#4492](https://github.com/vuejs/vitepress/issues/4492)) ([fe48943](https://github.com/vuejs/vitepress/commit/fe48943640895d859811b81f86d78c3e510dbe54)) +- **theme:** don't show external link icon for images ([096bba1](https://github.com/vuejs/vitepress/commit/096bba19fb61c4b2f8f527046b4b0fe2e91c6bd6)) +- **theme:** ignore footnote-ref for outline ([1832617](https://github.com/vuejs/vitepress/commit/183261753b04c2c96ddb8c10e520c748c6d3e613)), closes [#4402](https://github.com/vuejs/vitepress/issues/4402) +- **theme:** includes text to h1 tag for hero page ([#4472](https://github.com/vuejs/vitepress/issues/4472)) ([bd896c6](https://github.com/vuejs/vitepress/commit/bd896c638f8046f6546b5b32e8f98f3707aa8d05)), closes [#4453](https://github.com/vuejs/vitepress/issues/4453) + +### Features + +- **build:** export normalize function from shared chunk ([616f63f](https://github.com/vuejs/vitepress/commit/616f63f5f08a57347f2800e2d147d5bcd1cd072d)), closes [#4401](https://github.com/vuejs/vitepress/issues/4401) +- **theme:** allow customizing skip to content label ([ff254dc](https://github.com/vuejs/vitepress/commit/ff254dcbe6f2bcc89c34d2d2f4050229dc094400)), closes [#4288](https://github.com/vuejs/vitepress/issues/4288) +- **theme:** export VPNavBarSearch ([23522ab](https://github.com/vuejs/vitepress/commit/23522ab83ff33802d382fa066578dd87eb06789d)), closes [#4476](https://github.com/vuejs/vitepress/issues/4476) +- **theme:** export VPFeatures ([#4356](https://github.com/vuejs/vitepress/issues/4356)) ([6442e17](https://github.com/vuejs/vitepress/commit/6442e174838aec9668325bb1199419908e7dd728)) + +### Miscellaneous + +- **build:** shiki transformers now use v3 [matching algorithm](https://shiki.style/packages/transformers#matching-algorithm) ([373f9b9](https://github.com/vuejs/vitepress/commit/373f9b933ee44f33a15ebdcfcb6db6dfac52f739)) + # [1.5.0](https://github.com/vuejs/vitepress/compare/v1.4.5...v1.5.0) (2024-11-04) ### Features diff --git a/README.md b/README.md index 2e70a766..134226a4 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![test](https://github.com/vuejs/vitepress/workflows/Test/badge.svg)](https://github.com/vuejs/vitepress/actions) [![npm](https://img.shields.io/npm/v/vitepress)](https://www.npmjs.com/package/vitepress) +[![nightly releases](https://img.shields.io/badge/nightly-releases-orange)](https://nightly.akryum.dev/vuejs/vitepress) [![chat](https://img.shields.io/badge/chat-discord-blue?logo=discord)](https://chat.vuejs.org) --- diff --git a/__tests__/e2e/.vitepress/config.ts b/__tests__/e2e/.vitepress/config.ts index 65f845ab..121761e7 100644 --- a/__tests__/e2e/.vitepress/config.ts +++ b/__tests__/e2e/.vitepress/config.ts @@ -165,13 +165,21 @@ export default defineConfig({ search: { provider: 'local', options: { - _render(src, env, md) { - const html = md.render(src, env) + async _render(src, env, md) { + const html = await md.renderAsync(src, env) if (env.frontmatter?.search === false) return '' if (env.relativePath.startsWith('local-search/excluded')) return '' return html } } } + }, + vite: { + server: { + watch: { + usePolling: true, + interval: 100 + } + } } }) diff --git a/__tests__/e2e/data-loading/basic.data.mts b/__tests__/e2e/data-loading/basic.data.mts index 305551c0..56aab77e 100644 --- a/__tests__/e2e/data-loading/basic.data.mts +++ b/__tests__/e2e/data-loading/basic.data.mts @@ -1,4 +1,4 @@ -import fs from 'fs' +import fs from 'node:fs' import { defineLoader } from 'vitepress' type Data = Record[] diff --git a/__tests__/e2e/data-loading/data.test.ts b/__tests__/e2e/data-loading/data.test.ts index 394ab1d2..fafc403a 100644 --- a/__tests__/e2e/data-loading/data.test.ts +++ b/__tests__/e2e/data-loading/data.test.ts @@ -43,8 +43,7 @@ describe('static data file support in vite 3', () => { `) }) - // TODO: make it `.runIf(!process.env.VITE_TEST_BUILD)` -- it currently works, but is skipped to avoid vite's ecosystem-ci from failing (https://github.com/vitejs/vite/pull/16471#issuecomment-2308437187) - test.skip('hmr works', async () => { + test.runIf(!process.env.VITE_TEST_BUILD)('hmr works', async () => { const a = fileURLToPath(new URL('./data/a.json', import.meta.url)) const b = fileURLToPath(new URL('./data/b.json', import.meta.url)) diff --git a/__tests__/e2e/dynamic-routes/[id].paths.ts b/__tests__/e2e/dynamic-routes/[id].paths.ts index 3eca4d91..12a8bc32 100644 --- a/__tests__/e2e/dynamic-routes/[id].paths.ts +++ b/__tests__/e2e/dynamic-routes/[id].paths.ts @@ -1,8 +1,14 @@ -export default { - async paths() { - return [ - { params: { id: 'foo' }, content: `# Foo` }, - { params: { id: 'bar' }, content: `# Bar` } - ] +import { defineRoutes } from 'vitepress' +import paths from './paths' + +export default defineRoutes({ + async paths(watchedFiles: string[]) { + // console.log('watchedFiles', watchedFiles) + return paths + }, + watch: ['**/data-loading/**/*.json'], + async transformPageData(pageData) { + // console.log('transformPageData', pageData.filePath) + pageData.title += ' - transformed' } -} +}) diff --git a/__tests__/e2e/dynamic-routes/paths.ts b/__tests__/e2e/dynamic-routes/paths.ts new file mode 100644 index 00000000..5adb0ed4 --- /dev/null +++ b/__tests__/e2e/dynamic-routes/paths.ts @@ -0,0 +1,4 @@ +export default [ + { params: { id: 'foo' }, content: `# Foo` }, + { params: { id: 'bar' }, content: `# Bar` } +] diff --git a/__tests__/e2e/vitestGlobalSetup.ts b/__tests__/e2e/vitestGlobalSetup.ts index 97eb114c..74596801 100644 --- a/__tests__/e2e/vitestGlobalSetup.ts +++ b/__tests__/e2e/vitestGlobalSetup.ts @@ -1,8 +1,8 @@ import getPort from 'get-port' +import type { Server } from 'node:net' import { chromium, type BrowserServer } from 'playwright-chromium' -import { build, createServer, serve } from 'vitepress' import type { ViteDevServer } from 'vite' -import type { Server } from 'net' +import { build, createServer, serve } from 'vitepress' let browserServer: BrowserServer let server: ViteDevServer | Server diff --git a/__tests__/init/init.test.ts b/__tests__/init/init.test.ts index f4c9956b..7766b060 100644 --- a/__tests__/init/init.test.ts +++ b/__tests__/init/init.test.ts @@ -1,9 +1,9 @@ import fs from 'fs-extra' import getPort from 'get-port' import { nanoid } from 'nanoid' -import path from 'path' +import path from 'node:path' +import { fileURLToPath, URL } from 'node:url' import { chromium } from 'playwright-chromium' -import { fileURLToPath, URL } from 'url' import { createServer, scaffold, ScaffoldThemeType } from 'vitepress' const tempDir = fileURLToPath(new URL('./.temp', import.meta.url)) diff --git a/__tests__/unit/node/utils/moduleGraph.test.ts b/__tests__/unit/node/utils/moduleGraph.test.ts new file mode 100644 index 00000000..9b3db9e5 --- /dev/null +++ b/__tests__/unit/node/utils/moduleGraph.test.ts @@ -0,0 +1,72 @@ +import { ModuleGraph } from 'node/utils/moduleGraph' + +describe('node/utils/moduleGraph', () => { + let graph: ModuleGraph + + beforeEach(() => { + graph = new ModuleGraph() + }) + + it('should correctly delete a module and its dependents', () => { + graph.add('A', ['B', 'C']) + graph.add('B', ['D']) + graph.add('C', []) + graph.add('D', []) + + expect(graph.delete('D')).toEqual(new Set(['D', 'B', 'A'])) + }) + + it('should handle shared dependencies correctly', () => { + graph.add('A', ['B', 'C']) + graph.add('B', ['D']) + graph.add('C', ['D']) // Shared dependency + graph.add('D', []) + + expect(graph.delete('D')).toEqual(new Set(['A', 'B', 'C', 'D'])) + }) + + it('merges dependencies correctly', () => { + // Add module A with dependency B + graph.add('A', ['B']) + // Merge new dependency C into module A (B should remain) + graph.add('A', ['C']) + + // Deleting B should remove A as well, since A depends on B. + expect(graph.delete('B')).toEqual(new Set(['B', 'A'])) + }) + + it('handles cycles gracefully', () => { + // Create a cycle: A -> B, B -> C, C -> A. + graph.add('A', ['B']) + graph.add('B', ['C']) + graph.add('C', ['A']) + + // Deleting any module in the cycle should delete all modules in the cycle. + expect(graph.delete('A')).toEqual(new Set(['A', 'B', 'C'])) + }) + + it('cleans up dependencies when deletion', () => { + // Setup A -> B relationship. + graph.add('A', ['B']) + graph.add('B', []) + + // Deleting B should remove both B and A from the graph. + expect(graph.delete('B')).toEqual(new Set(['B', 'A'])) + + // After deletion, add modules again. + graph.add('C', []) + graph.add('A', ['C']) // Now A depends only on C. + + expect(graph.delete('C')).toEqual(new Set(['C', 'A'])) + }) + + it('handles independent modules', () => { + // Modules with no dependencies. + graph.add('X', []) + graph.add('Y', []) + + // Deletion of one should only remove that module. + expect(graph.delete('X')).toEqual(new Set(['X'])) + expect(graph.delete('Y')).toEqual(new Set(['Y'])) + }) +}) diff --git a/__tests__/unit/vitest.config.ts b/__tests__/unit/vitest.config.ts index ff26e679..b028d4ee 100644 --- a/__tests__/unit/vitest.config.ts +++ b/__tests__/unit/vitest.config.ts @@ -1,7 +1,7 @@ -import { dirname, resolve } from 'path' -import { fileURLToPath } from 'url' -import { defineConfig } from 'vitest/config' import vue from '@vitejs/plugin-vue' +import { dirname, resolve } from 'node:path' +import { fileURLToPath } from 'node:url' +import { defineConfig } from 'vitest/config' const dir = dirname(fileURLToPath(import.meta.url)) diff --git a/docs/.postcssrc.json b/docs/.postcssrc.json new file mode 100644 index 00000000..edc6a490 --- /dev/null +++ b/docs/.postcssrc.json @@ -0,0 +1,8 @@ +{ + "plugins": { + "postcss-rtlcss": { + "ltrPrefix": ":where([dir=\"ltr\"])", + "rtlPrefix": ":where([dir=\"rtl\"])" + } + } +} diff --git a/docs/.vitepress/config/es.ts b/docs/.vitepress/config/es.ts index d924c5b8..d30fc89f 100644 --- a/docs/.vitepress/config/es.ts +++ b/docs/.vitepress/config/es.ts @@ -48,7 +48,8 @@ export const es = defineConfig({ sidebarMenuLabel: 'Menu Lateral', darkModeSwitchLabel: 'Tema Oscuro', lightModeSwitchTitle: 'Cambiar a modo claro', - darkModeSwitchTitle: 'Cambiar a modo oscuro' + darkModeSwitchTitle: 'Cambiar a modo oscuro', + skipToContentLabel: 'Saltar al contenido' } }) diff --git a/docs/.vitepress/config/fa.ts b/docs/.vitepress/config/fa.ts new file mode 100644 index 00000000..5c91d0bc --- /dev/null +++ b/docs/.vitepress/config/fa.ts @@ -0,0 +1,223 @@ +import { createRequire } from 'module' +import { defineConfig, type DefaultTheme } from 'vitepress' + +const require = createRequire(import.meta.url) +const pkg = require('vitepress/package.json') + +export const fa = defineConfig({ + title: 'ویت‌پرس', + lang: 'fa-IR', + description: 'Vite & Vue powered static site generator.', + dir: 'rtl', + markdown: { + container: { + tipLabel: 'نکته', + warningLabel: 'هشدار', + dangerLabel: 'خطر', + infoLabel: 'اطلاعات', + detailsLabel: 'جزئیات' + } + }, + themeConfig: { + nav: nav(), + sidebar: { + '/fa/guide/': { base: '/fa/guide/', items: sidebarGuide() }, + '/fa/reference/': { base: '/fa/reference/', items: sidebarReference() } + }, + + editLink: { + pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path', + text: 'ویرایش این صفحه در گیت‌هاب' + }, + + footer: { + message: 'انتشار یافته تحت لایسنس MIT', + copyright: 'حق نسخه‌برداری © 2019-کنون Evan You' + }, + + docFooter: { + prev: 'قبلی', + next: 'بعدی' + }, + + outline: { + label: 'در این صفحه' + }, + + lastUpdated: { + text: 'آخرین به‌روزرسانی‌', + formatOptions: { + dateStyle: 'short', + timeStyle: 'medium' + } + }, + + langMenuLabel: 'تغییر زبان', + returnToTopLabel: 'بازگشت به بالا', + sidebarMenuLabel: 'منوی جانبی', + darkModeSwitchLabel: 'تم تاریک', + lightModeSwitchTitle: 'رفتن به حالت روشن', + darkModeSwitchTitle: 'رفتن به حالت تاریک', + notFound: { + linkLabel: 'بازگشت به خانه', + linkText: 'بازگشت به خانه', + title: 'صفحه مورد نظر یافت نشد', + code: '۴۰۴', + quote: + 'اما اگر جهت خود را تغییر ندهید و اگر ادامه دهید به دنبال چیزی که دنبال می‌کنید، ممکن است در نهایت به جایی که در حال رفتن به سمتش هستید، برسید.' + }, + siteTitle: 'ویت‌پرس' + } +}) + +function nav(): DefaultTheme.NavItem[] { + return [ + { + text: 'راهنما', + link: 'fa/guide/what-is-vitepress', + activeMatch: '/guide/' + }, + { + text: 'مرجع', + link: 'fa/reference/site-config', + activeMatch: '/reference/' + }, + { + text: pkg.version, + items: [ + { + text: 'Changelog', + link: 'https://github.com/vuejs/vitepress/blob/main/CHANGELOG.md' + }, + { + text: 'مشارکت', + link: 'https://github.com/vuejs/vitepress/blob/main/.github/contributing.md' + } + ] + } + ] +} + +function sidebarGuide(): DefaultTheme.SidebarItem[] { + return [ + { + text: 'معرفی', + collapsed: false, + items: [ + { text: 'ویت‌پرس چیست؟', link: 'what-is-vitepress' }, + { text: 'شروع کار', link: 'getting-started' }, + { text: 'مسیریابی', link: 'routing' }, + { text: 'استقرار', link: 'deploy' } + ] + }, + { + text: 'نوشتن', + collapsed: false, + items: [ + { text: 'افزونه‌های Markdown', link: 'markdown' }, + { text: 'مدیریت منابع', link: 'asset-handling' }, + { text: 'Frontmatter', link: 'frontmatter' }, + { text: 'استفاده از Vue در Markdown', link: 'using-vue' }, + { text: 'بین‌المللی سازی', link: 'i18n' } + ] + }, + { + text: 'شخصی‌سازی', + collapsed: false, + items: [ + { text: 'استفاده از تم شخصی', link: 'custom-theme' }, + { + text: 'گسترش تم پیش‌فرض', + link: 'extending-default-theme' + }, + { text: 'بارگیری داده در زمان Build', link: 'data-loading' }, + { text: 'سازگاری SSR', link: 'ssr-compat' }, + { text: 'اتصال به CMS', link: 'cms' } + ] + }, + { + text: 'آزمایشی', + collapsed: false, + items: [ + { text: 'حالت MPA', link: 'mpa-mode' }, + { text: 'جنریت کردن Sitemap', link: 'sitemap-generation' } + ] + }, + { text: 'پیکربندی و مرجع API', base: 'fa/reference/', link: 'site-config' } + ] +} + +function sidebarReference(): DefaultTheme.SidebarItem[] { + return [ + { + text: 'مرجع', + base: 'fa/reference/', + items: [ + { text: 'پیکربندی Site', link: 'site-config' }, + { text: 'پیکربندی Frontmatter', link: 'frontmatter-config' }, + { text: 'Runtime API', link: 'runtime-api' }, + { text: 'CLI', link: 'cli' }, + { + text: 'تم پیش‌فرض', + base: 'fa/reference/default-theme-', + items: [ + { text: 'بررسی اجمالی', link: 'config' }, + { text: 'ناوبری', link: 'nav' }, + { text: 'نوار کنار صفحه', link: 'sidebar' }, + { text: 'صفحه اصلی', link: 'home-page' }, + { text: 'پاورقی', link: 'footer' }, + { text: 'طرح', link: 'layout' }, + { text: 'نشان', link: 'badge' }, + { text: 'صفحه تیم', link: 'team-page' }, + { text: 'لینک‌های قبلی / بعدی', link: 'prev-next-links' }, + { text: 'ویرایش لینک', link: 'edit-link' }, + { text: 'Timestamp آخرین به‌روزرسانی', link: 'last-updated' }, + { text: 'جستجو', link: 'search' }, + { text: 'تبلیغات Carbon', link: 'carbon-ads' } + ] + } + ] + } + ] +} + +export const search: DefaultTheme.AlgoliaSearchOptions['locales'] = { + fa: { + placeholder: 'جستجوی مستندات', + translations: { + button: { + buttonText: 'جستجو', + buttonAriaLabel: 'جستجو' + }, + modal: { + searchBox: { + resetButtonTitle: 'آغاز مجدد جستجو', + resetButtonAriaLabel: 'آغاز مجدد جستجو', + cancelButtonText: 'لغو', + cancelButtonAriaLabel: 'لغو' + }, + startScreen: { + recentSearchesTitle: 'جستجو‌های اخیر', + noRecentSearchesText: 'تاریخچه جستجویی یافت نشد.', + saveRecentSearchButtonTitle: 'ذخیره تاریخچه جستجو', + removeRecentSearchButtonTitle: 'حذف تاریخچه جستجو', + favoriteSearchesTitle: 'موارد دلخواه', + removeFavoriteSearchButtonTitle: 'حذف مورد دلخواه' + }, + errorScreen: { + titleText: 'نتیجه‌ای یافت نشد برای', + helpText: 'اتصال شبکه خود را بررسی کنید' + }, + footer: { + selectText: 'انتخاب', + navigateText: 'رفتن', + closeText: 'بستن', + searchByText: ' جستجو با ' + }, + noResultsScreen: { + noResultsText: 'نتیجه‌ای یافت نشد برای' + } + } + } + } +} diff --git a/docs/.vitepress/config/index.ts b/docs/.vitepress/config/index.ts index 2715ccdc..08a81fb9 100644 --- a/docs/.vitepress/config/index.ts +++ b/docs/.vitepress/config/index.ts @@ -6,6 +6,7 @@ import { pt } from './pt' import { ru } from './ru' import { es } from './es' import { ko } from './ko' +import { fa } from './fa' export default defineConfig({ ...shared, @@ -15,6 +16,7 @@ export default defineConfig({ pt: { label: 'Português', ...pt }, ru: { label: 'Русский', ...ru }, es: { label: 'Español', ...es }, - ko: { label: '한국어', ...ko } + ko: { label: '한국어', ...ko }, + fa: { label: 'فارسی', ...fa } } }) diff --git a/docs/.vitepress/config/ko.ts b/docs/.vitepress/config/ko.ts index 906669d3..faebabf4 100644 --- a/docs/.vitepress/config/ko.ts +++ b/docs/.vitepress/config/ko.ts @@ -44,7 +44,8 @@ export const ko = defineConfig({ sidebarMenuLabel: '사이드바 메뉴', darkModeSwitchLabel: '다크 모드', lightModeSwitchTitle: '라이트 모드로 변경', - darkModeSwitchTitle: '다크 모드로 변경' + darkModeSwitchTitle: '다크 모드로 변경', + skipToContentLabel: '본문으로 건너뛰기' } }) diff --git a/docs/.vitepress/config/pt.ts b/docs/.vitepress/config/pt.ts index f8ce02a1..12cb52fa 100644 --- a/docs/.vitepress/config/pt.ts +++ b/docs/.vitepress/config/pt.ts @@ -48,7 +48,8 @@ export const pt = defineConfig({ sidebarMenuLabel: 'Menu Lateral', darkModeSwitchLabel: 'Tema Escuro', lightModeSwitchTitle: 'Mudar para Modo Claro', - darkModeSwitchTitle: 'Mudar para Modo Escuro' + darkModeSwitchTitle: 'Mudar para Modo Escuro', + skipToContentLabel: 'Pular para o Conteúdo' } }) diff --git a/docs/.vitepress/config/ru.ts b/docs/.vitepress/config/ru.ts index 739261a3..b75b1b77 100644 --- a/docs/.vitepress/config/ru.ts +++ b/docs/.vitepress/config/ru.ts @@ -42,7 +42,8 @@ export const ru = defineConfig({ darkModeSwitchTitle: 'Переключить на тёмную тему', sidebarMenuLabel: 'Меню', returnToTopLabel: 'Вернуться к началу', - langMenuLabel: 'Изменить язык' + langMenuLabel: 'Изменить язык', + skipToContentLabel: 'Перейти к содержимому' } }) diff --git a/docs/.vitepress/config/shared.ts b/docs/.vitepress/config/shared.ts index b33ee9ae..1f4961d2 100644 --- a/docs/.vitepress/config/shared.ts +++ b/docs/.vitepress/config/shared.ts @@ -1,9 +1,15 @@ import { defineConfig } from 'vitepress' -import { search as zhSearch } from './zh' -import { search as ptSearch } from './pt' -import { search as ruSearch } from './ru' +import { + groupIconMdPlugin, + groupIconVitePlugin, + localIconLoader +} from 'vitepress-plugin-group-icons' import { search as esSearch } from './es' +import { search as faSearch } from './fa' import { search as koSearch } from './ko' +import { search as ptSearch } from './pt' +import { search as ruSearch } from './ru' +import { search as zhSearch } from './zh' export const shared = defineConfig({ title: 'VitePress', @@ -25,7 +31,37 @@ export const shared = defineConfig({ return code.replace(/\[\!\!code/g, '[!code') } } - ] + ], + config(md) { + // TODO: remove when https://github.com/vuejs/vitepress/issues/4431 is fixed + const fence = md.renderer.rules.fence! + md.renderer.rules.fence = function (tokens, idx, options, env, self) { + const { localeIndex = 'root' } = env + const codeCopyButtonTitle = (() => { + switch (localeIndex) { + case 'es': + return 'Copiar código' + case 'fa': + return 'کپی کد' + case 'ko': + return '코드 복사' + case 'pt': + return 'Copiar código' + case 'ru': + return 'Скопировать код' + case 'zh': + return '复制代码' + default: + return 'Copy code' + } + })() + return fence(tokens, idx, options, env, self).replace( + '', + `` + ) + } + md.use(groupIconMdPlugin) + } }, sitemap: { @@ -67,11 +103,25 @@ export const shared = defineConfig({ ...ptSearch, ...ruSearch, ...esSearch, - ...koSearch + ...koSearch, + ...faSearch } } }, carbonAds: { code: 'CEBDT27Y', placement: 'vuejsorg' } + }, + vite: { + plugins: [ + groupIconVitePlugin({ + customIcon: { + vitepress: localIconLoader( + import.meta.url, + '../../public/vitepress-logo-mini.svg' + ), + firebase: 'logos:firebase' + } + }) + ] } }) diff --git a/docs/.vitepress/config/zh.ts b/docs/.vitepress/config/zh.ts index b7463980..e9d5fbcd 100644 --- a/docs/.vitepress/config/zh.ts +++ b/docs/.vitepress/config/zh.ts @@ -48,7 +48,8 @@ export const zh = defineConfig({ sidebarMenuLabel: '菜单', darkModeSwitchLabel: '主题', lightModeSwitchTitle: '切换到浅色模式', - darkModeSwitchTitle: '切换到深色模式' + darkModeSwitchTitle: '切换到深色模式', + skipToContentLabel: '跳转到内容' } }) diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts new file mode 100644 index 00000000..0e7ba37f --- /dev/null +++ b/docs/.vitepress/theme/index.ts @@ -0,0 +1,5 @@ +import Theme from 'vitepress/theme' +import 'virtual:group-icons.css' +import './styles.css' + +export default Theme diff --git a/docs/.vitepress/theme/styles.css b/docs/.vitepress/theme/styles.css new file mode 100644 index 00000000..1f397744 --- /dev/null +++ b/docs/.vitepress/theme/styles.css @@ -0,0 +1,40 @@ +@import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@100..900&display=swap'); + +:root:where(:lang(fa)) { + --vp-font-family-base: + 'Vazirmatn', 'Inter', ui-sans-serif, system-ui, sans-serif, + 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; +} + +:root { + --vp-home-hero-name-color: transparent; + --vp-home-hero-name-background: -webkit-linear-gradient( + 120deg, + #bd34fe 30%, + #41d1ff + ); + --vp-home-hero-image-background-image: linear-gradient( + -45deg, + #bd34fe 50%, + #47caff 50% + ); + --vp-home-hero-image-filter: blur(44px); +} + +@media (min-width: 640px) { + :root { + --vp-home-hero-image-filter: blur(56px); + } +} + +@media (min-width: 960px) { + :root { + --vp-home-hero-image-filter: blur(68px); + } +} + +/* used in reference/default-theme-search */ +img[src='/search.png'] { + width: 100%; + aspect-ratio: 1 / 1; +} diff --git a/docs/en/guide/custom-theme.md b/docs/en/guide/custom-theme.md index 1d168ce9..96943c9f 100644 --- a/docs/en/guide/custom-theme.md +++ b/docs/en/guide/custom-theme.md @@ -49,8 +49,7 @@ interface EnhanceAppContext { The theme entry file should export the theme as its default export: -```js -// .vitepress/theme/index.js +```js [.vitepress/theme/index.js] // You can directly import Vue files in the theme entry // VitePress is pre-configured with @vitejs/plugin-vue. @@ -72,8 +71,7 @@ Inside your layout component, it works just like a normal Vite + Vue 3 applicati The most basic layout component needs to contain a [``](../reference/runtime-api#content) component: -```vue - +```vue [.vitepress/theme/Layout.vue]