@deot/docs-client 1.0.4 → 1.0.6

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/README.md CHANGED
@@ -19,6 +19,15 @@ pnpm add @deot/docs-client
19
19
  window.$docs = {
20
20
  base: new URL('./', document.baseURI).href,
21
21
  namespace: 'my-docs',
22
+ layout: {
23
+ header: {
24
+ brand: {
25
+ logo: './logo.svg',
26
+ label: { 'zh-CN': '组件文档', 'en-US': 'Component Docs' },
27
+ value: '/guide'
28
+ }
29
+ }
30
+ },
22
31
  locales: {
23
32
  'zh-CN': {
24
33
  label: '简体中文',
@@ -73,6 +82,7 @@ const { app, router, disconnect } = await bootstrap(window.$docs);
73
82
  | `styles` | 站点级预览 CSS 默认地址;同名 key 覆盖内置样式表,也可追加。管理页 `/:lang/__docs/playground-resource` 与 `modules` 同一张表管理。 |
74
83
  | `prefetch` | 空闲预加载开关或 `{ batchSize, idleTimeout }` 配置,默认开启。 |
75
84
  | `theme` | 主题开关或 `{ default: 'system' \| 'light' \| 'dark' }`,默认跟随系统。 |
85
+ | `layout.header` | 内置 Header 配置;`brand.logo`、`brand.label` 和 `brand.value` 均支持固定值或按语言配置。文案未配置时回退到 `namespace` 和内置翻译,链接未配置时指向当前语言首页。站内链接自动补语言前缀,外链在新窗口打开。 |
76
86
  | `layout.footer` | Footer 内容;未配置或 `default` 使用内置分组,`false` 全局隐藏,也可配置 `{ groups, poweredBy }`。两项均支持按语言代码配置,`groups` 复用 Sidebar 的 `{ label, value?, children? }` 结构。 |
77
87
  | `home` | 可选的 `{ locales }` 首页配置;语言值是 Renderer 文档或 `.page.json` 地址。未配置时首页为空。 |
78
88
  | `renderers` | 业务自定义 Renderer 模块注册项;type 必须使用非 `docs:` 的命名空间。 |
package/dist/index.cjs CHANGED
@@ -251,7 +251,7 @@ var _hoisted_4$9 = {
251
251
  };
252
252
  var _hoisted_5$7 = ["href"];
253
253
  var _hoisted_6$5 = { key: 2 };
254
- var _hoisted_7$3 = {
254
+ var _hoisted_7$4 = {
255
255
  key: 1,
256
256
  class: "docs-footer__powered-by"
257
257
  };
@@ -379,7 +379,7 @@ var default_footer_default = /* @__PURE__ */ (0, vue.defineComponent)({
379
379
  _: 2
380
380
  }, 1032, ["to"])) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_6$5, (0, vue.toDisplayString)(item.label), 1))]);
381
381
  }), 128))])) : (0, vue.createCommentVNode)("v-if", true)]);
382
- }), 128))])) : (0, vue.createCommentVNode)("v-if", true), poweredBy.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_7$3, (0, vue.toDisplayString)(poweredBy.value), 1)) : (0, vue.createCommentVNode)("v-if", true)])) : (0, vue.createCommentVNode)("v-if", true);
382
+ }), 128))])) : (0, vue.createCommentVNode)("v-if", true), poweredBy.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_7$4, (0, vue.toDisplayString)(poweredBy.value), 1)) : (0, vue.createCommentVNode)("v-if", true)])) : (0, vue.createCommentVNode)("v-if", true);
383
383
  };
384
384
  }
385
385
  });
@@ -1389,6 +1389,19 @@ var localizeRoutePath = (lang, pathname) => {
1389
1389
  return `/${lang}${normalized === "/" ? "" : normalized}`;
1390
1390
  };
1391
1391
  /**
1392
+ * 给站内地址补语言前缀;外链和已带已配置语言的地址保持不变。
1393
+ * @param config 文档配置,用于识别语言路径段。
1394
+ * @param lang 当前语言。
1395
+ * @param target 原始跳转地址。
1396
+ * @returns 可直接交给 RouterLink 的地址。
1397
+ */
1398
+ var localizePath = (config, lang, target) => {
1399
+ const language = target.split(/[?#]/u, 1)[0].split("/").filter(Boolean)[0];
1400
+ const configuredLanguages = Object.keys(config.locales);
1401
+ const hasLanguage = Boolean(language && (Object.prototype.hasOwnProperty.call(config.locales, language) || !configuredLanguages.length && language === lang));
1402
+ return isExternalLink(target) || hasLanguage ? target : localizeRoutePath(lang, target);
1403
+ };
1404
+ /**
1392
1405
  * 按显式 value、动态参数和路径末段的顺序确定当前文档值。
1393
1406
  * 该纯函数独立于 Router 注册模块,避免布局组件反向导入 Router 时形成循环依赖。
1394
1407
  * @param route 当前标准化路由,或资源计划合成的等价 route shape。
@@ -3619,12 +3632,12 @@ var _hoisted_3$12 = ["placeholder", "aria-label"];
3619
3632
  var _hoisted_4$7 = { class: "docs-search__actions" };
3620
3633
  var _hoisted_5$6 = ["aria-label"];
3621
3634
  var _hoisted_6$4 = { class: "docs-search__body" };
3622
- var _hoisted_7$2 = { class: "docs-search__content" };
3623
- var _hoisted_8$2 = {
3635
+ var _hoisted_7$3 = { class: "docs-search__content" };
3636
+ var _hoisted_8$3 = {
3624
3637
  key: 0,
3625
3638
  class: "docs-search__state"
3626
3639
  };
3627
- var _hoisted_9$2 = {
3640
+ var _hoisted_9$3 = {
3628
3641
  key: 1,
3629
3642
  class: "docs-search__state docs-search__state--error"
3630
3643
  };
@@ -3913,7 +3926,7 @@ var search_default = /* @__PURE__ */ (0, vue.defineComponent)({
3913
3926
  height: "100%",
3914
3927
  "wrapper-style": "overflow-x: hidden;"
3915
3928
  }, {
3916
- default: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("div", _hoisted_7$2, [loading.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_8$2, (0, vue.toDisplayString)((0, vue.unref)(t)("client.search.searching")), 1)) : error.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_9$2, (0, vue.toDisplayString)(error.value), 1)) : keyword.value.trim() ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 2 }, [
3929
+ default: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("div", _hoisted_7$3, [loading.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_8$3, (0, vue.toDisplayString)((0, vue.unref)(t)("client.search.searching")), 1)) : error.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_9$3, (0, vue.toDisplayString)(error.value), 1)) : keyword.value.trim() ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 2 }, [
3917
3930
  (0, vue.createElementVNode)("div", _hoisted_10$2, (0, vue.toDisplayString)((0, vue.unref)(t)("client.search.documentation")), 1),
3918
3931
  ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(results.value, (item, index) => {
3919
3932
  return (0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
@@ -4527,18 +4540,21 @@ var takeInlineRendererDocument = (from) => {
4527
4540
  //#endregion
4528
4541
  //#region packages/client/src/components/layout/default-header.vue?vue&type=script&setup=true&lang.ts
4529
4542
  var _hoisted_1$15 = { class: "docs-header" };
4530
- var _hoisted_2$13 = { class: "docs-header__search" };
4531
- var _hoisted_3$11 = { class: "docs-header__actions" };
4532
- var _hoisted_4$6 = {
4543
+ var _hoisted_2$13 = ["href"];
4544
+ var _hoisted_3$11 = ["src"];
4545
+ var _hoisted_4$6 = ["src"];
4546
+ var _hoisted_5$5 = { class: "docs-header__search" };
4547
+ var _hoisted_6$3 = { class: "docs-header__actions" };
4548
+ var _hoisted_7$2 = {
4533
4549
  key: 0,
4534
4550
  class: "docs-header__locales"
4535
4551
  };
4536
- var _hoisted_5$5 = [
4552
+ var _hoisted_8$2 = [
4537
4553
  "title",
4538
4554
  "aria-label",
4539
4555
  "aria-expanded"
4540
4556
  ];
4541
- var _hoisted_6$3 = ["title", "aria-label"];
4557
+ var _hoisted_9$2 = ["title", "aria-label"];
4542
4558
  //#endregion
4543
4559
  //#region packages/client/src/components/layout/default-header.vue
4544
4560
  var default_header_default = /* @__PURE__ */ (0, vue.defineComponent)({
@@ -4550,6 +4566,21 @@ var default_header_default = /* @__PURE__ */ (0, vue.defineComponent)({
4550
4566
  const { t } = (0, _deot_docs_locale.useLocale)();
4551
4567
  const localeMenuVisible = (0, vue.ref)(false);
4552
4568
  const lang = (0, vue.computed)(() => String(route.params.lang));
4569
+ /**
4570
+ * 按当前语言和站点默认语言选择 Header 配置。
4571
+ * @param value 固定配置或语言映射。
4572
+ * @returns 当前语言、站点默认语言或空值。
4573
+ */
4574
+ function resolveLocalized(value) {
4575
+ if (!value || typeof value !== "object" || Array.isArray(value)) return value;
4576
+ return findLanguageValue(value, lang.value) ?? findLanguageValue(value, getDefaultLanguage(config));
4577
+ }
4578
+ const brandOptions = config.layout?.header?.brand;
4579
+ const brandLogo = (0, vue.computed)(() => resolveLocalized(brandOptions?.logo) || "");
4580
+ const brandLabel = (0, vue.computed)(() => resolveLocalized(brandOptions?.label) || config.namespace || t("client.header.brand"));
4581
+ const brandValue = (0, vue.computed)(() => resolveLocalized(brandOptions?.value) || `/${lang.value}`);
4582
+ const brandExternal = (0, vue.computed)(() => isExternalLink(brandValue.value));
4583
+ const brandPath = (0, vue.computed)(() => localizePath(config, lang.value, brandValue.value));
4553
4584
  const databasePath = (0, vue.computed)(() => `/${lang.value}/__docs/database`);
4554
4585
  const playgroundResourcePath = (0, vue.computed)(() => `/${lang.value}/__docs/playground-resource`);
4555
4586
  const localeOptions = (0, vue.computed)(() => Object.entries(config.locales).map(([value, item]) => ({
@@ -4610,17 +4641,34 @@ var default_header_default = /* @__PURE__ */ (0, vue.defineComponent)({
4610
4641
  };
4611
4642
  return (_ctx, _cache) => {
4612
4643
  return (0, vue.openBlock)(), (0, vue.createElementBlock)("header", _hoisted_1$15, [
4613
- (0, vue.createVNode)((0, vue.unref)(vue_router.RouterLink), {
4644
+ brandExternal.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("a", {
4645
+ key: 0,
4646
+ class: "docs-header__brand",
4647
+ href: brandValue.value,
4648
+ target: "_blank",
4649
+ rel: "noopener noreferrer"
4650
+ }, [brandLogo.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("img", {
4651
+ key: 0,
4652
+ class: "docs-header__brand-logo",
4653
+ src: brandLogo.value,
4654
+ alt: ""
4655
+ }, null, 8, _hoisted_3$11)) : (0, vue.createCommentVNode)("v-if", true), (0, vue.createTextVNode)(" " + (0, vue.toDisplayString)(brandLabel.value), 1)], 8, _hoisted_2$13)) : ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(vue_router.RouterLink), {
4656
+ key: 1,
4614
4657
  class: "docs-header__brand",
4615
- to: `/${lang.value}`
4658
+ to: brandPath.value
4616
4659
  }, {
4617
- default: (0, vue.withCtx)(() => [(0, vue.createTextVNode)((0, vue.toDisplayString)((0, vue.unref)(t)("client.header.brand")), 1)]),
4660
+ default: (0, vue.withCtx)(() => [brandLogo.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("img", {
4661
+ key: 0,
4662
+ class: "docs-header__brand-logo",
4663
+ src: brandLogo.value,
4664
+ alt: ""
4665
+ }, null, 8, _hoisted_4$6)) : (0, vue.createCommentVNode)("v-if", true), (0, vue.createTextVNode)(" " + (0, vue.toDisplayString)(brandLabel.value), 1)]),
4618
4666
  _: 1
4619
- }, 8, ["to"]),
4620
- (0, vue.createElementVNode)("div", _hoisted_2$13, [(0, vue.createVNode)((0, vue.unref)(trigger_default))]),
4621
- (0, vue.createElementVNode)("div", _hoisted_3$11, [
4667
+ }, 8, ["to"])),
4668
+ (0, vue.createElementVNode)("div", _hoisted_5$5, [(0, vue.createVNode)((0, vue.unref)(trigger_default))]),
4669
+ (0, vue.createElementVNode)("div", _hoisted_6$3, [
4622
4670
  (0, vue.createVNode)((0, vue.unref)(theme_toggler_default), { class: "docs-header__theme" }),
4623
- localeOptions.value.length > 1 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("nav", _hoisted_4$6, [(0, vue.createVNode)((0, vue.unref)(_deot_vc.Dropdown), {
4671
+ localeOptions.value.length > 1 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("nav", _hoisted_7$2, [(0, vue.createVNode)((0, vue.unref)(_deot_vc.Dropdown), {
4624
4672
  modelValue: localeMenuVisible.value,
4625
4673
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => localeMenuVisible.value = $event),
4626
4674
  class: "docs-header__locale-dropdown",
@@ -4660,7 +4708,7 @@ var default_header_default = /* @__PURE__ */ (0, vue.defineComponent)({
4660
4708
  "aria-label": (0, vue.unref)(t)("client.header.language"),
4661
4709
  "aria-expanded": localeMenuVisible.value,
4662
4710
  "aria-haspopup": "menu"
4663
- }, [(0, vue.createVNode)((0, vue.unref)(icon_default), { name: "language" })], 8, _hoisted_5$5)]),
4711
+ }, [(0, vue.createVNode)((0, vue.unref)(icon_default), { name: "language" })], 8, _hoisted_8$2)]),
4664
4712
  _: 1
4665
4713
  }, 8, ["modelValue"])])) : (0, vue.createCommentVNode)("v-if", true),
4666
4714
  (0, vue.createElementVNode)("button", {
@@ -4669,7 +4717,7 @@ var default_header_default = /* @__PURE__ */ (0, vue.defineComponent)({
4669
4717
  title: (0, vue.unref)(t)("client.header.editor"),
4670
4718
  "aria-label": (0, vue.unref)(t)("client.header.editor"),
4671
4719
  onClick: handleEditor
4672
- }, [(0, vue.createVNode)((0, vue.unref)(icon_default), { name: "editor" })], 8, _hoisted_6$3),
4720
+ }, [(0, vue.createVNode)((0, vue.unref)(icon_default), { name: "editor" })], 8, _hoisted_9$2),
4673
4721
  (0, vue.createVNode)((0, vue.unref)(vue_router.RouterLink), {
4674
4722
  class: "docs-header__action docs-header__playground-resource",
4675
4723
  to: playgroundResourcePath.value,
@@ -8519,11 +8567,6 @@ var slotProps = {
8519
8567
  extra: { name: "extra" }
8520
8568
  };
8521
8569
  var hasConfiguredLanguage = (config, language) => Object.prototype.hasOwnProperty.call(config.locales, language);
8522
- var hasLanguage = (config, path) => {
8523
- const language = path.split(/[?#]/u, 1)[0].split("/").filter(Boolean)[0];
8524
- const configuredLanguages = Object.keys(config.locales);
8525
- return Boolean(language && (hasConfiguredLanguage(config, language) || !configuredLanguages.length && language === getDefaultLanguage(config)));
8526
- };
8527
8570
  var matchesConfiguredPath = (config, pathname) => {
8528
8571
  const target = pathname.split("/").filter(Boolean);
8529
8572
  return Object.keys(config.routes).some((path) => {
@@ -8549,10 +8592,6 @@ var normalizeInvalidLanguage = (config, defaultLanguage, to, languageRoot = fals
8549
8592
  };
8550
8593
  return replaceLanguage(defaultLanguage, to);
8551
8594
  };
8552
- var localizePath = (config, lang, target) => {
8553
- if (isExternalLink(target) || hasLanguage(config, target)) return target;
8554
- return localizeRoutePath(lang, target);
8555
- };
8556
8595
  var resolveRedirect = (config, target, to) => localizePath(config, String(to.params.lang || getDefaultLanguage(config)), typeof target === "function" ? target(to) : target);
8557
8596
  var createRouteRecord = (config, path, routeConfig, options = {}) => {
8558
8597
  if (typeof routeConfig === "string" || typeof routeConfig === "function") return {
package/dist/index.d.ts CHANGED
@@ -56,11 +56,22 @@ export declare interface DocsFooterOptions {
56
56
 
57
57
  export declare type DocsFooterPoweredBy = 'default' | string | false;
58
58
 
59
+ export declare interface DocsHeaderBrandOptions {
60
+ logo?: DocsLocalized<string>;
61
+ label?: DocsLocalized<string>;
62
+ value?: DocsLocalized<string>;
63
+ }
64
+
65
+ export declare interface DocsHeaderOptions {
66
+ brand?: DocsHeaderBrandOptions;
67
+ }
68
+
59
69
  export declare interface DocsHomeOptions {
60
70
  locales: Record<string, RendererDocument | string>;
61
71
  }
62
72
 
63
73
  export declare interface DocsLayoutOptions {
74
+ header?: DocsHeaderOptions;
64
75
  footer?: 'default' | DocsFooterOptions | false;
65
76
  }
66
77