@done-coding/admin-core 0.26.1 → 0.27.0

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.
Files changed (32) hide show
  1. package/es/bridge/badge.mjs +5 -0
  2. package/es/bridge/index.mjs +2 -0
  3. package/es/bridge/theme/index.mjs +6 -1
  4. package/es/components/app-layout/AppHeader.vue.mjs +1 -1
  5. package/es/components/app-layout/AppHeader.vue2.mjs +2 -1
  6. package/es/components/display/ActionBtn.vue.mjs +6 -2
  7. package/es/components/display/BadgeMark.vue.mjs +1 -1
  8. package/es/components/display/BadgeMark.vue2.mjs +39 -6
  9. package/es/components/display/TabsTile.vue.mjs +1 -1
  10. package/es/components/display/TabsTile.vue2.mjs +1 -0
  11. package/es/components/display/use-badge-mask.mjs +83 -0
  12. package/es/components/display/use-badge.mjs +32 -5
  13. package/es/components/icon/IconHammer.vue.mjs +26 -0
  14. package/es/components/icon/IconHammer.vue2.mjs +4 -0
  15. package/es/components/menu/MenuItemSub.vue.mjs +4 -2
  16. package/es/components/menu/MenuTree.vue.mjs +4 -2
  17. package/es/index.mjs +120 -116
  18. package/es/style.css +25 -20
  19. package/package.json +2 -2
  20. package/src/bridge/docs/README.md +22 -0
  21. package/src/components/icon/README.md +38 -0
  22. package/types/bridge/badge.d.ts +29 -1
  23. package/types/bridge/index.d.ts +1 -0
  24. package/types/bridge/theme/types.d.ts +11 -0
  25. package/types/components/display/BadgeMark.vue.d.ts +153 -2
  26. package/types/components/display/TabsTile.vue.d.ts +2 -2
  27. package/types/components/display/use-badge-mask.d.ts +8 -0
  28. package/types/components/display/use-badge.d.ts +13 -1
  29. package/types/components/icon/IconHammer.vue.d.ts +2 -0
  30. package/types/components/icon/index.d.ts +7 -0
  31. package/types/index.d.ts +1 -0
  32. package/types/injectInfo.json.d.ts +1 -1
@@ -1,4 +1,8 @@
1
1
  import { shallowRef, readonly } from "vue";
2
+ const BADGE_MASK_KINDS = [
3
+ "wip",
4
+ "locked"
5
+ ];
2
6
  function createBridgeBadgeHook(init = {}) {
3
7
  const marks = shallowRef({ ...init.marks ?? {} });
4
8
  const setAll = (next) => {
@@ -23,5 +27,6 @@ function createBridgeBadgeHook(init = {}) {
23
27
  };
24
28
  }
25
29
  export {
30
+ BADGE_MASK_KINDS,
26
31
  createBridgeBadgeHook
27
32
  };
@@ -7,6 +7,7 @@ import { createBridgePluginHost } from "./plugin.mjs";
7
7
  import { createBridgeThemeHook } from "./theme/index.mjs";
8
8
  import { createBridgeLayoutHook } from "./layout.mjs";
9
9
  import { createBridgeBadgeHook } from "./badge.mjs";
10
+ import { BADGE_MASK_KINDS } from "./badge.mjs";
10
11
  import { CORE_BRIDGE_KEY } from "../inject/key.mjs";
11
12
  function createCoreBridge(options) {
12
13
  const rawNs = options.APP_CACHE_CONFIG.namespace;
@@ -294,6 +295,7 @@ function createCoreBridge(options) {
294
295
  return bridgeInstance;
295
296
  }
296
297
  export {
298
+ BADGE_MASK_KINDS,
297
299
  createCoreBridge,
298
300
  createGenerateRouteMetaRawTree,
299
301
  createStorageWithNamespace,
@@ -20,8 +20,9 @@ function createBridgeThemeHook(init) {
20
20
  const themeStyle = ref(DEFAULT_STYLE);
21
21
  const themeMode = ref(init.defaultMode ?? DEFAULT_MODE);
22
22
  const systemPrefersDark = ref(readSystemPrefersDark());
23
+ const themeDarkOverride = ref(void 0);
23
24
  const themeIsDark = computed(
24
- () => themeMode.value === "system" ? systemPrefersDark.value : themeMode.value === "dark"
25
+ () => themeDarkOverride.value ?? (themeMode.value === "system" ? systemPrefersDark.value : themeMode.value === "dark")
25
26
  );
26
27
  watchSystemPrefersDark((isDark) => {
27
28
  systemPrefersDark.value = isDark;
@@ -125,6 +126,9 @@ function createBridgeThemeHook(init) {
125
126
  const setDark = (isDark) => {
126
127
  setMode(isDark ? "dark" : "light");
127
128
  };
129
+ const setDarkOverride = (isDark) => {
130
+ themeDarkOverride.value = isDark;
131
+ };
128
132
  const setDensity = (density) => {
129
133
  themeDensity.value = density;
130
134
  };
@@ -200,6 +204,7 @@ function createBridgeThemeHook(init) {
200
204
  setStyle,
201
205
  setMode,
202
206
  setDark,
207
+ setDarkOverride,
203
208
  setDensity,
204
209
  setMotion,
205
210
  list: readonly(themeList),
@@ -1,7 +1,7 @@
1
1
  import _sfc_main from "./AppHeader.vue2.mjs";
2
2
  /* empty css */
3
3
  import _export_sfc from "../../_virtual/_plugin-vue_export-helper.mjs";
4
- const AppHeader = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-40b13903"]]);
4
+ const AppHeader = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-d887bc4c"]]);
5
5
  export {
6
6
  AppHeader as default
7
7
  };
@@ -17,7 +17,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
17
17
  },
18
18
  setup(__props) {
19
19
  useCssVars((_ctx) => ({
20
- "v05959ac0": themeColors.value.primaryColor
20
+ "v7733782f": themeColors.value.primaryColor
21
21
  }));
22
22
  const props = __props;
23
23
  const appStore = inject(APP_LAYOUT_APP_STORE_KEY);
@@ -77,6 +77,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
77
77
  "app-header-module-item",
78
78
  activeModulePath.value === menu.path ? "app-header-module-item_active" : ""
79
79
  ]),
80
+ "data-dc-badge-host": "",
80
81
  onClick: ($event) => activeModulePath.value = menu.path
81
82
  }, [
82
83
  menu.menuIcon ? (openBlock(), createBlock(unref(ElIcon), {
@@ -134,7 +134,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
134
134
  onClose: onConfirmClose
135
135
  }, {
136
136
  default: withCtx(() => [
137
- createVNode(unref(ElButton), mergeProps({ class: "dc-action-btn" }, passthrough.value, {
137
+ createVNode(unref(ElButton), mergeProps({
138
+ class: "dc-action-btn",
139
+ "data-dc-badge-host": ""
140
+ }, passthrough.value, {
138
141
  loading: innerLoading.value,
139
142
  onClick: onInnerClick
140
143
  }), {
@@ -155,7 +158,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
155
158
  _: 3
156
159
  }, 8, ["show", "mode", "title", "content", "confirm-text", "cancel-text", "type"])) : (openBlock(), createBlock(unref(ElButton), mergeProps({
157
160
  key: 1,
158
- class: "dc-action-btn"
161
+ class: "dc-action-btn",
162
+ "data-dc-badge-host": ""
159
163
  }, passthrough.value, {
160
164
  loading: innerLoading.value,
161
165
  onClick: onInnerClick
@@ -1,7 +1,7 @@
1
1
  import _sfc_main from "./BadgeMark.vue2.mjs";
2
2
  /* empty css */
3
3
  import _export_sfc from "../../_virtual/_plugin-vue_export-helper.mjs";
4
- const BadgeMark = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-12868883"]]);
4
+ const BadgeMark = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-4116ac36"]]);
5
5
  export {
6
6
  BadgeMark as default
7
7
  };
@@ -1,6 +1,7 @@
1
- import { defineComponent, unref, openBlock, createBlock, normalizeClass, withCtx, renderSlot } from "vue";
2
- import { ElBadge } from "element-plus";
3
- import { useBadgeResolved } from "./use-badge.mjs";
1
+ import { defineComponent, useTemplateRef, unref, openBlock, createBlock, normalizeClass, createSlots, withCtx, renderSlot, createVNode, resolveDynamicComponent } from "vue";
2
+ import { ElBadge, ElTooltip, ElIcon } from "element-plus";
3
+ import { useBadgeResolved, useBadgeEntry } from "./use-badge.mjs";
4
+ import { useBadgeMask } from "./use-badge-mask.mjs";
4
5
  const _sfc_main = /* @__PURE__ */ defineComponent({
5
6
  __name: "BadgeMark",
6
7
  props: {
@@ -10,19 +11,51 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
10
11
  setup(__props) {
11
12
  const props = __props;
12
13
  const resolved = useBadgeResolved(() => props.badgeKey);
14
+ const badgeRef = useTemplateRef("badgeRef");
15
+ const entry = useBadgeEntry(() => props.badgeKey);
16
+ useBadgeMask(
17
+ () => {
18
+ var _a;
19
+ return ((_a = badgeRef.value) == null ? void 0 : _a.$el) ?? void 0;
20
+ },
21
+ () => entry.value
22
+ );
13
23
  return (_ctx, _cache) => {
14
24
  return unref(resolved) ? (openBlock(), createBlock(unref(ElBadge), {
15
25
  key: 0,
26
+ ref_key: "badgeRef",
27
+ ref: badgeRef,
16
28
  class: normalizeClass(["dc-badge-mark badge-mark", `badge-mark_${__props.align ?? "middle"}`]),
17
29
  value: unref(resolved).value,
18
30
  max: unref(resolved).max,
19
31
  type: unref(resolved).type
20
- }, {
32
+ }, createSlots({
21
33
  default: withCtx(() => [
22
34
  renderSlot(_ctx.$slots, "default", {}, void 0, true)
23
35
  ]),
24
- _: 3
25
- }, 8, ["class", "value", "max", "type"])) : renderSlot(_ctx.$slots, "default", { key: 1 }, void 0, true);
36
+ _: 2
37
+ }, [
38
+ unref(resolved).icon ? {
39
+ name: "content",
40
+ fn: withCtx(() => [
41
+ createVNode(unref(ElTooltip), {
42
+ content: unref(resolved).label,
43
+ placement: "top"
44
+ }, {
45
+ default: withCtx(() => [
46
+ createVNode(unref(ElIcon), { class: "badge-mark__icon" }, {
47
+ default: withCtx(() => [
48
+ (openBlock(), createBlock(resolveDynamicComponent(unref(resolved).icon)))
49
+ ]),
50
+ _: 1
51
+ })
52
+ ]),
53
+ _: 1
54
+ }, 8, ["content"])
55
+ ]),
56
+ key: "0"
57
+ } : void 0
58
+ ]), 1032, ["class", "value", "max", "type"])) : renderSlot(_ctx.$slots, "default", { key: 1 }, void 0, true);
26
59
  };
27
60
  }
28
61
  });
@@ -1,7 +1,7 @@
1
1
  import _sfc_main from "./TabsTile.vue2.mjs";
2
2
  /* empty css */
3
3
  import _export_sfc from "../../_virtual/_plugin-vue_export-helper.mjs";
4
- const TabsTile = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-acb4bb13"]]);
4
+ const TabsTile = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-9b8e85b8"]]);
5
5
  export {
6
6
  TabsTile as default
7
7
  };
@@ -182,6 +182,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
182
182
  id: paneId(index),
183
183
  key: tab.key,
184
184
  class: "dc-tabs-tile__item",
185
+ "data-dc-badge-host": "",
185
186
  "data-tab-key": tab.key,
186
187
  "data-dc-slot": unref(SlotRegion).TabsMain_Item
187
188
  }, [
@@ -0,0 +1,83 @@
1
+ import { watch } from "vue";
2
+ import { ElMessage } from "element-plus";
3
+ import { useActivated } from "../../hooks/activated.mjs";
4
+ import { BADGE_MASK_KINDS } from "../../bridge/badge.mjs";
5
+ const BADGE_HOST_ATTR = "data-dc-badge-host";
6
+ const BADGE_VEIL_CLASS = "dc-badge-mask__veil";
7
+ const BADGE_MASK_DEFAULT_TIP = {
8
+ locked: "请联系平台开通功能",
9
+ wip: "功能正在加紧开发中"
10
+ };
11
+ const badgeMaskKindSet = new Set(BADGE_MASK_KINDS);
12
+ const useBadgeMask = (getAnchor, getEntry) => {
13
+ let applied;
14
+ const handleVeilClick = (event) => {
15
+ event.stopPropagation();
16
+ event.preventDefault();
17
+ const entry = getEntry();
18
+ if (!entry) return;
19
+ if (entry.onTrigger) {
20
+ entry.onTrigger(entry);
21
+ return;
22
+ }
23
+ const tip = BADGE_MASK_DEFAULT_TIP[entry.kind];
24
+ if (tip) ElMessage.info(tip);
25
+ };
26
+ const restore = () => {
27
+ if (!applied) return;
28
+ const { host, veil, prevTabIndex, prevAriaDisabled, positionSetByUs } = applied;
29
+ veil.removeEventListener("click", handleVeilClick);
30
+ veil.remove();
31
+ if (prevTabIndex === null) {
32
+ host.removeAttribute("tabindex");
33
+ } else {
34
+ host.setAttribute("tabindex", prevTabIndex);
35
+ }
36
+ if (prevAriaDisabled === null) {
37
+ host.removeAttribute("aria-disabled");
38
+ } else {
39
+ host.setAttribute("aria-disabled", prevAriaDisabled);
40
+ }
41
+ if (positionSetByUs) host.style.removeProperty("position");
42
+ applied = void 0;
43
+ };
44
+ const apply = () => {
45
+ const entry = getEntry();
46
+ if (!entry || !badgeMaskKindSet.has(entry.kind)) return;
47
+ const anchor = getAnchor();
48
+ const host = anchor == null ? void 0 : anchor.closest(`[${BADGE_HOST_ATTR}]`);
49
+ if (!host) return;
50
+ const hostPosition = getComputedStyle(host).position;
51
+ const positionSetByUs = (!hostPosition || hostPosition === "static") && !host.style.position;
52
+ if (positionSetByUs) host.style.position = "relative";
53
+ const veil = document.createElement("div");
54
+ veil.className = BADGE_VEIL_CLASS;
55
+ veil.style.cssText = "position:absolute;inset:0;z-index:1;background:transparent;cursor:not-allowed;";
56
+ veil.addEventListener("click", handleVeilClick);
57
+ host.appendChild(veil);
58
+ applied = {
59
+ host,
60
+ veil,
61
+ prevTabIndex: host.getAttribute("tabindex"),
62
+ prevAriaDisabled: host.getAttribute("aria-disabled"),
63
+ positionSetByUs
64
+ };
65
+ host.setAttribute("tabindex", "-1");
66
+ host.setAttribute("aria-disabled", "true");
67
+ };
68
+ const sync = () => {
69
+ restore();
70
+ apply();
71
+ };
72
+ useActivated((info) => {
73
+ if (info.isActivated) {
74
+ sync();
75
+ } else {
76
+ restore();
77
+ }
78
+ });
79
+ watch(getEntry, sync, { flush: "post" });
80
+ };
81
+ export {
82
+ useBadgeMask
83
+ };
@@ -1,12 +1,20 @@
1
- import { inject, computed, onScopeDispose, ref } from "vue";
1
+ import { inject, computed, onScopeDispose, markRaw, ref } from "vue";
2
+ import { Lock, Warning } from "@element-plus/icons-vue";
3
+ import _sfc_main from "../icon/IconHammer.vue.mjs";
2
4
  import { CORE_BRIDGE_KEY } from "../../inject/key.mjs";
3
5
  const BADGE_BUILTIN_PRESET = {
4
6
  new: { text: "新", type: "success" },
5
7
  updated: { text: "更新", type: "primary" },
6
8
  beta: { text: "内测", type: "warning" },
7
- // [MUST] ≤2 汉字:绝对定位下角标必然逃逸出宿主,逃逸量=角标宽−13px;
8
- // 3 字的「开发中」宽 50px、逃逸 36px 会顶到下一个按钮,2 字「开发」宽 38px、逃逸 24px 安全。
9
- wip: { text: "开发", type: "info" }
9
+ // 锤子走 core 自带(EP 无锤子,其 Tools 是扳手+齿轮、被读成「设置」)
10
+ wip: { text: "开发中", type: "info", icon: markRaw(_sfc_main) },
11
+ // 待下线:danger(红)——「要迁走」是需要用户采取行动的信号,强度高于 beta
12
+ // 「谨慎用」。与 count 的红撞色顾虑较弱:一个 key 只能挂一条 entry,同一位置不会
13
+ // 同时出现数字标与文字标,且形态(数字 vs 三字)扫视即可分。
14
+ deprecated: { text: "待下线", type: "danger", icon: markRaw(Warning) },
15
+ // 未开通:warning(橙)——与 beta 同档。EP 只有五档语义色而内置标已六个,必然有撞;
16
+ // 选 warning 因语义最近(都是「有条件可用」),文案完全不同足以区分。
17
+ locked: { text: "未开通", type: "warning", icon: markRaw(Lock) }
10
18
  };
11
19
  const BADGE_TICK_INTERVAL = 6e4;
12
20
  const badgeNow = ref(Date.now());
@@ -32,6 +40,19 @@ function useBadgeNow() {
32
40
  });
33
41
  return badgeNow;
34
42
  }
43
+ function useBadgeEntry(getKey) {
44
+ const bridge = inject(CORE_BRIDGE_KEY, void 0);
45
+ const now = useBadgeNow();
46
+ return computed(() => {
47
+ const key = getKey();
48
+ if (!key || !bridge) return void 0;
49
+ const hit = bridge.badge.marks.value[key];
50
+ if (!hit) return void 0;
51
+ if (!hit.expireAt) return hit;
52
+ if (hit.expireAt <= Math.max(now.value, Date.now())) return void 0;
53
+ return hit;
54
+ });
55
+ }
35
56
  function useBadgeResolved(getKey) {
36
57
  const bridge = inject(CORE_BRIDGE_KEY, void 0);
37
58
  const now = useBadgeNow();
@@ -54,9 +75,15 @@ function useBadgeResolved(getKey) {
54
75
  return { value: hit.text, type: hit.type ?? "primary" };
55
76
  }
56
77
  const preset = BADGE_BUILTIN_PRESET[hit.kind];
57
- return { value: preset.text, type: preset.type };
78
+ return {
79
+ value: preset.text,
80
+ type: preset.type,
81
+ icon: preset.icon,
82
+ label: preset.text
83
+ };
58
84
  });
59
85
  }
60
86
  export {
87
+ useBadgeEntry,
61
88
  useBadgeResolved
62
89
  };
@@ -0,0 +1,26 @@
1
+ import { defineComponent, openBlock, createElementBlock, createElementVNode } from "vue";
2
+ const _hoisted_1 = {
3
+ class: "dc-icon-hammer icon-hammer",
4
+ viewBox: "0 0 16 16",
5
+ width: "1em",
6
+ height: "1em",
7
+ xmlns: "http://www.w3.org/2000/svg",
8
+ "aria-hidden": "true",
9
+ focusable: "false"
10
+ };
11
+ const _sfc_main = /* @__PURE__ */ defineComponent({
12
+ __name: "IconHammer",
13
+ setup(__props) {
14
+ return (_ctx, _cache) => {
15
+ return openBlock(), createElementBlock("svg", _hoisted_1, [..._cache[0] || (_cache[0] = [
16
+ createElementVNode("path", {
17
+ fill: "currentColor",
18
+ d: "M9.972 2.508a.5.5 0 0 0-.16-.556l-.178-.129a5 5 0 0 0-2.076-.783C6.215.862 4.504 1.229 2.84 3.133H1.786a.5.5 0 0 0-.354.147L.146 4.567a.5.5 0 0 0 0 .706l2.571 2.579a.5.5 0 0 0 .708 0l1.286-1.29a.5.5 0 0 0 .146-.353V5.57l8.387 8.873A.5.5 0 0 0 14 14.5l1.5-1.5a.5.5 0 0 0 .017-.689l-9.129-8.63c.747-.456 1.772-.839 3.112-.839a.5.5 0 0 0 .472-.334"
19
+ }, null, -1)
20
+ ])]);
21
+ };
22
+ }
23
+ });
24
+ export {
25
+ _sfc_main as default
26
+ };
@@ -0,0 +1,4 @@
1
+ import _sfc_main from "./IconHammer.vue.mjs";
2
+ export {
3
+ _sfc_main as default
4
+ };
@@ -1,6 +1,7 @@
1
1
  import { defineComponent, openBlock, createBlock, unref, withCtx, createElementBlock, Fragment, renderList, resolveDynamicComponent, createCommentVNode, createElementVNode, createVNode, createTextVNode, toDisplayString } from "vue";
2
2
  import { ElSubMenu, ElMenuItem, ElIcon } from "element-plus";
3
3
  import BadgeMark from "../display/BadgeMark.vue.mjs";
4
+ const _hoisted_1 = { "data-dc-badge-host": "" };
4
5
  const _sfc_main = /* @__PURE__ */ defineComponent({
5
6
  __name: "MenuItemSub",
6
7
  props: {
@@ -20,7 +21,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
20
21
  ]),
21
22
  _: 1
22
23
  })) : createCommentVNode("", true),
23
- createElementVNode("span", null, [
24
+ createElementVNode("span", _hoisted_1, [
24
25
  createVNode(unref(BadgeMark), {
25
26
  badgeKey: __props.menu.path
26
27
  }, {
@@ -42,7 +43,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
42
43
  MenuItemSub: __props.MenuItemSub
43
44
  }, null, 8, ["menu", "MenuItemSub"])) : (openBlock(), createBlock(unref(ElMenuItem), {
44
45
  key: 1,
45
- index: item.path
46
+ index: item.path,
47
+ "data-dc-badge-host": ""
46
48
  }, {
47
49
  default: withCtx(() => [
48
50
  item.menuIcon ? (openBlock(), createBlock(unref(ElIcon), { key: 0 }, {
@@ -96,7 +96,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
96
96
  MenuItemSub: _sfc_main$1
97
97
  }, null, 8, ["menu"])) : (openBlock(), createBlock(unref(ElMenuItem), {
98
98
  key: 1,
99
- index: item.path
99
+ index: item.path,
100
+ "data-dc-badge-host": ""
100
101
  }, {
101
102
  default: withCtx(() => [
102
103
  item.menuIcon ? (openBlock(), createBlock(unref(ElIcon), { key: 0 }, {
@@ -128,7 +129,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
128
129
  MenuItemSub: _sfc_main$1
129
130
  }, null, 8, ["menu"])) : (openBlock(), createBlock(unref(ElMenuItem), {
130
131
  key: 2,
131
- index: menu.path
132
+ index: menu.path,
133
+ "data-dc-badge-host": ""
132
134
  }, {
133
135
  default: withCtx(() => [
134
136
  menu.menuIcon ? (openBlock(), createBlock(unref(ElIcon), { key: 0 }, {