vitepress-allyouneed 0.3.0-beta.0 → 0.3.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,21 @@
2
2
 
3
3
  本项目遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/);版本号遵循 [SemVer](https://semver.org/lang/zh-CN/)。
4
4
 
5
+ ## [0.3.0-beta.2] - 2026-05-20
6
+ ### Fixed
7
+ - **build-mode base 双重 prefix bug**:`
8
+
9
+ ## [0.3.0-beta.1] - 2026-05-20
10
+
11
+ ### Fixed
12
+ - **i18n nav 注入丢失**
13
+ - **跨 locale nav 链接 404**
14
+
15
+ ### Added
16
+ - 11 篇 EN 翻译 — `en/guide/{overview, docs×6, advanced×4}`
17
+ - VitePress 原生 i18n 集成:wrapper 自动识别 `themeConfig.locales`,给每个 non-root locale 自动用 `includePrefix` 生成对应 sidebar;root locale 自动用 `excludePrefixes` 排除其它 locale 子树。
18
+ - `sidebarAuto.includePrefix` / `excludePrefixes` 公开选项 — 手动控制 i18n sidebar 范围。
19
+
5
20
  ## [0.3.0-beta.0] - Unreleased
6
21
 
7
22
  v0.3 把"接管 Obsidian 仓库"从能跑变成好用。补齐了 13 种 callouts、Pandoc footnotes、`==高亮==`、`%%注释%%`、`^block-ref`、`![[audio|video|pdf]]` 媒体嵌入;sidebar 不再需要手写(三种 layout + nav 自动生成 + `_sidebar.md` 手动覆盖);文档顶部加了 banner-style `DocHeader`(cover/dates/tags/word-count);Perspectives 视图组挪到 nav 下拉,不再污染各 tab sidebar;补全 11 篇用户文档 + 完整 frontmatter 字段表。
package/dist/index.cjs CHANGED
@@ -2426,12 +2426,15 @@ function injectViewsSidebar(sidebar, options) {
2426
2426
  }
2427
2427
  }
2428
2428
  }
2429
- const base = options.base.endsWith("/") ? options.base : options.base + "/";
2430
2429
  const prefix = options.views.urlPrefix ? options.views.urlPrefix.replace(/^\/+|\/+$/g, "") : "";
2431
2430
  if (prefix) {
2432
- const persPath = `${base}${prefix}/`;
2431
+ const persPath = `/${prefix}/`;
2433
2432
  if (!sidebar[persPath]) {
2434
- sidebar[persPath] = buildPerspectivesFallbackSidebar(sidebar, group, base);
2433
+ sidebar[persPath] = buildPerspectivesFallbackSidebar(
2434
+ sidebar,
2435
+ group,
2436
+ options.base.endsWith("/") ? options.base : options.base + "/"
2437
+ );
2435
2438
  }
2436
2439
  }
2437
2440
  return sidebar;
@@ -2439,40 +2442,32 @@ function injectViewsSidebar(sidebar, options) {
2439
2442
  return [group];
2440
2443
  }
2441
2444
  function buildPerspectivesFallbackSidebar(allSidebars, group, base) {
2442
- const out = [{ text: "Home", link: base }];
2445
+ const out = [{ text: "Home", link: "/" }];
2443
2446
  const topPaths = Object.keys(allSidebars).filter(
2444
2447
  (p) => p !== base && !p.endsWith("/_perspectives_/")
2445
2448
  );
2446
2449
  for (const p of topPaths) {
2447
2450
  const seg = p.replace(/^\/|\/$/g, "").split("/").filter(Boolean).pop() ?? p;
2448
2451
  const text = seg.charAt(0).toUpperCase() + seg.slice(1);
2449
- out.push({ text, link: p });
2452
+ const b = base.endsWith("/") ? base : base + "/";
2453
+ const stripped = b !== "/" && p.startsWith(b) ? "/" + p.slice(b.length) : p;
2454
+ out.push({ text, link: stripped });
2450
2455
  }
2451
2456
  out.push(group);
2452
2457
  return out;
2453
2458
  }
2454
2459
  function buildViewsGroup(options) {
2455
2460
  const { enabled, names, sidebarText, urlPrefix } = options.views;
2456
- const base = options.base.endsWith("/") ? options.base.slice(0, -1) : options.base;
2457
2461
  const prefixSeg = urlPrefix ? `/${urlPrefix}` : "";
2458
2462
  const items = [];
2459
2463
  if (enabled.graph) {
2460
- items.push({
2461
- text: sidebarText.graph,
2462
- link: `${base}${prefixSeg}/${names.graph}`
2463
- });
2464
+ items.push({ text: sidebarText.graph, link: `${prefixSeg}/${names.graph}` });
2464
2465
  }
2465
2466
  if (enabled.stats) {
2466
- items.push({
2467
- text: sidebarText.stats,
2468
- link: `${base}${prefixSeg}/${names.stats}`
2469
- });
2467
+ items.push({ text: sidebarText.stats, link: `${prefixSeg}/${names.stats}` });
2470
2468
  }
2471
2469
  if (enabled.tags) {
2472
- items.push({
2473
- text: sidebarText.tags,
2474
- link: `${base}${prefixSeg}/${names.tags}`
2475
- });
2470
+ items.push({ text: sidebarText.tags, link: `${prefixSeg}/${names.tags}` });
2476
2471
  }
2477
2472
  if (items.length === 0) return null;
2478
2473
  return {
@@ -2665,7 +2660,9 @@ function resolveSidebarAutoOptions(user = {}) {
2665
2660
  stripNumericPrefix: strip,
2666
2661
  groupOrder: user.groupOrder ?? [],
2667
2662
  maxDepth: user.maxDepth,
2668
- groupLink: user.groupLink ?? "all"
2663
+ groupLink: user.groupLink ?? "all",
2664
+ includePrefix: user.includePrefix,
2665
+ excludePrefixes: user.excludePrefixes ?? []
2669
2666
  };
2670
2667
  }
2671
2668
  function defaultItemTitle(entry, strip) {
@@ -2696,13 +2693,34 @@ function generateSidebar(index, options, autoOptions = {}) {
2696
2693
  }
2697
2694
  const root = buildTree2(visible);
2698
2695
  const layout = autoOptions.layout ?? "tree";
2696
+ let result;
2699
2697
  if (layout === "per-folder") {
2700
- return toPerFolderSidebar(root, opts, options, index);
2698
+ result = toPerFolderSidebar(root, opts, options, index);
2699
+ } else if (layout === "flat") {
2700
+ result = toFlatSidebar(root, opts);
2701
+ } else {
2702
+ result = toTreeSidebar(root, opts, index, options);
2703
+ }
2704
+ stripBaseFromConfig(result, options.base);
2705
+ return result;
2706
+ }
2707
+ function stripBaseFromConfig(cfg, base) {
2708
+ if (Array.isArray(cfg)) {
2709
+ stripBaseFromItems(cfg, base);
2710
+ } else {
2711
+ for (const k of Object.keys(cfg)) {
2712
+ stripBaseFromItems(cfg[k], base);
2713
+ }
2701
2714
  }
2702
- if (layout === "flat") {
2703
- return toFlatSidebar(root, opts);
2715
+ }
2716
+ function stripBaseFromItems(items, base) {
2717
+ const b = base.endsWith("/") ? base : base + "/";
2718
+ for (const it of items) {
2719
+ if (it.link && b !== "/" && it.link.startsWith(b)) {
2720
+ it.link = "/" + it.link.slice(b.length);
2721
+ }
2722
+ if (it.items) stripBaseFromItems(it.items, base);
2704
2723
  }
2705
- return toTreeSidebar(root, opts, index, options);
2706
2724
  }
2707
2725
  function buildTree2(files) {
2708
2726
  const root = newNode("");
@@ -2903,7 +2921,6 @@ function walkDirs(node, out) {
2903
2921
  }
2904
2922
  function toPerFolderSidebar(root, opts, options, index) {
2905
2923
  const out = {};
2906
- const base = options.base.endsWith("/") ? options.base : options.base + "/";
2907
2924
  const rootItems = [];
2908
2925
  const sortedRootFiles = [...root.files].sort((a, b) => compareEntries(a, b, opts));
2909
2926
  for (const f of sortedRootFiles) {
@@ -2921,13 +2938,13 @@ function toPerFolderSidebar(root, opts, options, index) {
2921
2938
  /* isTopLevel */
2922
2939
  true
2923
2940
  )) {
2924
- const firstUrl = child.dirIndex && !child.dirIndexEmpty ? child.dirIndex.url : findFirstPageUrl(child, opts) ?? `${base}${key}/`;
2941
+ const firstUrl = child.dirIndex && !child.dirIndexEmpty ? child.dirIndex.url : findFirstPageUrl(child, opts) ?? `/${key}/`;
2925
2942
  rootItems.push({ text: labelText, link: firstUrl });
2926
2943
  } else {
2927
2944
  rootItems.push({ text: labelText });
2928
2945
  }
2929
2946
  }
2930
- if (rootItems.length > 0) out[base] = rootItems;
2947
+ if (rootItems.length > 0) out["/"] = rootItems;
2931
2948
  for (const key of topKeys) {
2932
2949
  const child = root.children.get(key);
2933
2950
  const items = renderNode(
@@ -2954,7 +2971,7 @@ function toPerFolderSidebar(root, opts, options, index) {
2954
2971
  });
2955
2972
  }
2956
2973
  sidebar.push(...items);
2957
- out[`${base}${key}/`] = sidebar;
2974
+ out[`/${key}/`] = sidebar;
2958
2975
  }
2959
2976
  return out;
2960
2977
  }
@@ -2968,7 +2985,7 @@ function generateNav(index, options, autoOptions = {}) {
2968
2985
  }
2969
2986
  const root = buildTree2(visible);
2970
2987
  const base = options.base.endsWith("/") ? options.base : options.base + "/";
2971
- const out = [{ text: opts.homeNavText, link: base }];
2988
+ const out = [{ text: opts.homeNavText, link: "/" }];
2972
2989
  const topKeys = [...root.children.keys()].sort();
2973
2990
  for (const key of topKeys) {
2974
2991
  const child = root.children.get(key);
@@ -2976,16 +2993,22 @@ function generateNav(index, options, autoOptions = {}) {
2976
2993
  continue;
2977
2994
  }
2978
2995
  const text = computeGroupText(child.path, child.dirIndex, opts);
2979
- const link = child.dirIndex?.url ?? `${base}${key}/`;
2980
- const escapedPrefix = `${base}${key}/`.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2981
- out.push({
2982
- text,
2983
- link,
2984
- activeMatch: "^" + escapedPrefix
2985
- });
2996
+ let link;
2997
+ if (child.dirIndex) {
2998
+ link = stripBase(child.dirIndex.url, base);
2999
+ } else {
3000
+ link = `/${key}/`;
3001
+ }
3002
+ const escapedPrefix = `/${key}/`.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3003
+ out.push({ text, link, activeMatch: "^" + escapedPrefix });
2986
3004
  }
2987
3005
  return out;
2988
3006
  }
3007
+ function stripBase(url, base) {
3008
+ const b = base.endsWith("/") ? base : base + "/";
3009
+ if (b === "/" || !url.startsWith(b)) return url;
3010
+ return "/" + url.slice(b.length);
3011
+ }
2989
3012
  function compareEntries(a, b, opts) {
2990
3013
  if (opts.sortBy === "title") {
2991
3014
  return opts.formatItemTitle(a).localeCompare(opts.formatItemTitle(b));
@@ -3018,6 +3041,18 @@ function resolveGroupCollapsed(dirIndex, opts) {
3018
3041
  function shouldExclude(entry, opts, viewsPrefix) {
3019
3042
  if (entry.frontmatter[opts.hiddenKey] === true) return true;
3020
3043
  if (viewsPrefix && entry.relativePath.startsWith(viewsPrefix + "/")) return true;
3044
+ if (opts.includePrefix) {
3045
+ const ip = opts.includePrefix.replace(/^\/+|\/+$/g, "");
3046
+ if (!entry.relativePath.startsWith(ip + "/") && entry.relativePath !== ip) {
3047
+ return true;
3048
+ }
3049
+ }
3050
+ for (const ex of opts.excludePrefixes) {
3051
+ const xp = ex.replace(/^\/+|\/+$/g, "");
3052
+ if (entry.relativePath.startsWith(xp + "/") || entry.relativePath === xp) {
3053
+ return true;
3054
+ }
3055
+ }
3021
3056
  const segs = entry.relativePath.split("/");
3022
3057
  for (const seg of segs.slice(0, -1)) {
3023
3058
  if (seg.startsWith("_")) return true;
@@ -3400,11 +3435,29 @@ function defineConfigWithAllYouNeed(config, pluginOptions = {}) {
3400
3435
  logDeadLinks(report, resolvedForWrapper.deadLink);
3401
3436
  } catch {
3402
3437
  }
3403
- themeConfig.sidebar = generateSidebar(
3404
- index,
3405
- resolvedForWrapper,
3406
- sidebarAuto
3407
- );
3438
+ const localesObj = config.locales;
3439
+ const localeKeys = localesObj ? Object.keys(localesObj).filter((k) => k !== "root") : [];
3440
+ themeConfig.sidebar = generateSidebar(index, resolvedForWrapper, {
3441
+ ...sidebarAuto,
3442
+ excludePrefixes: [
3443
+ ...sidebarAuto.excludePrefixes ?? [],
3444
+ ...localeKeys
3445
+ // 根 sidebar 排除掉所有 locale 子树
3446
+ ]
3447
+ });
3448
+ if (localesObj) {
3449
+ for (const lang of localeKeys) {
3450
+ const localeCfg = localesObj[lang];
3451
+ if (!localeCfg.themeConfig) localeCfg.themeConfig = {};
3452
+ if (localeCfg.themeConfig.sidebar === void 0) {
3453
+ localeCfg.themeConfig.sidebar = generateSidebar(
3454
+ index,
3455
+ resolvedForWrapper,
3456
+ { ...sidebarAuto, includePrefix: lang }
3457
+ );
3458
+ }
3459
+ }
3460
+ }
3408
3461
  if (sidebarAuto.autoNav && themeConfig.nav === void 0) {
3409
3462
  themeConfig.nav = generateNav(
3410
3463
  index,
@@ -3429,6 +3482,19 @@ function defineConfigWithAllYouNeed(config, pluginOptions = {}) {
3429
3482
  themeConfig.nav,
3430
3483
  resolvedForWrapper
3431
3484
  );
3485
+ const localesForNav = config.locales;
3486
+ if (localesForNav) {
3487
+ for (const lang of Object.keys(localesForNav)) {
3488
+ const lc = localesForNav[lang];
3489
+ if (!lc.themeConfig) continue;
3490
+ if (lc.themeConfig.nav !== void 0) {
3491
+ lc.themeConfig.nav = injectViewsNav(
3492
+ lc.themeConfig.nav,
3493
+ resolvedForWrapper
3494
+ );
3495
+ }
3496
+ }
3497
+ }
3432
3498
  }
3433
3499
  return {
3434
3500
  ...config,