@hlw-uni/mp-vue 1.0.12 → 1.0.14

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.
@@ -0,0 +1,20 @@
1
+ export interface HlwMenuItem {
2
+ /** 图标 class,如 'i-fa6-solid-gear' */
3
+ icon: string;
4
+ /** 图标主题色 */
5
+ iconTheme?: "orange" | "purple" | "cyan" | "emerald" | "slate" | "wechat" | "rose" | "blue" | "red";
6
+ /** 菜单文字 */
7
+ label: string;
8
+ /** 跳转路径,有值则用 navigator 包裹 */
9
+ url?: string;
10
+ /** 右侧标签文字 */
11
+ tag?: string;
12
+ /** 标签主题色 */
13
+ tagTheme?: "orange" | "red" | "wechat" | "rose" | "blue";
14
+ /** 标签是否闪烁 */
15
+ tagPulse?: boolean;
16
+ /** 加载中状态 */
17
+ loading?: boolean;
18
+ /** 是否显示,默认 true */
19
+ visible?: boolean;
20
+ }
package/dist/index.d.ts CHANGED
@@ -7,6 +7,8 @@ export { default as HlwCard } from './components/hlw-card/index.vue';
7
7
  export { default as HlwEmpty } from './components/hlw-empty/index.vue';
8
8
  export { default as HlwHeader } from './components/hlw-header/index.vue';
9
9
  export { default as HlwLoading } from './components/hlw-loading/index.vue';
10
+ export { default as HlwMenu } from './components/hlw-menu/index.vue';
11
+ export type { HlwMenuItem } from './components/hlw-menu/types';
10
12
  export { default as HlwMenuList } from './components/hlw-menu-list/index.vue';
11
13
  export { default as HlwPage } from './components/hlw-page/index.vue';
12
14
  export type { MenuItem } from './components/hlw-menu-list/types';
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("vue")) : typeof define === "function" && define.amd ? define(["exports", "vue"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.HlwUniVue = {}, global.vue));
3
3
  })(this, function(exports2, vue) {
4
4
  "use strict";
5
- const _sfc_main$7 = /* @__PURE__ */ vue.defineComponent({
5
+ const _sfc_main$8 = /* @__PURE__ */ vue.defineComponent({
6
6
  ...{ name: "HlwAd" },
7
7
  __name: "index",
8
8
  props: {
@@ -33,13 +33,13 @@
33
33
  };
34
34
  }
35
35
  });
36
- const _hoisted_1$6 = ["src"];
37
- const _hoisted_2$6 = {
36
+ const _hoisted_1$7 = ["src"];
37
+ const _hoisted_2$7 = {
38
38
  key: 1,
39
39
  class: "hlw-avatar__placeholder"
40
40
  };
41
- const _hoisted_3$4 = { class: "hlw-avatar__initial" };
42
- const _sfc_main$6 = /* @__PURE__ */ vue.defineComponent({
41
+ const _hoisted_3$5 = { class: "hlw-avatar__initial" };
42
+ const _sfc_main$7 = /* @__PURE__ */ vue.defineComponent({
43
43
  __name: "index",
44
44
  props: {
45
45
  src: {},
@@ -64,8 +64,8 @@
64
64
  src: __props.src,
65
65
  mode: "aspectFill",
66
66
  onError: _cache[0] || (_cache[0] = ($event) => loadError.value = true)
67
- }, null, 40, _hoisted_1$6)) : (vue.openBlock(), vue.createElementBlock("view", _hoisted_2$6, [
68
- vue.createElementVNode("text", _hoisted_3$4, vue.toDisplayString(initial.value), 1)
67
+ }, null, 40, _hoisted_1$7)) : (vue.openBlock(), vue.createElementBlock("view", _hoisted_2$7, [
68
+ vue.createElementVNode("text", _hoisted_3$5, vue.toDisplayString(initial.value), 1)
69
69
  ]))
70
70
  ], 2);
71
71
  };
@@ -78,22 +78,22 @@
78
78
  }
79
79
  return target;
80
80
  };
81
- const index$6 = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["__scopeId", "data-v-7e8f98a5"]]);
82
- const _hoisted_1$5 = { class: "hlw-card" };
83
- const _hoisted_2$5 = {
81
+ const index$7 = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["__scopeId", "data-v-7e8f98a5"]]);
82
+ const _hoisted_1$6 = { class: "hlw-card" };
83
+ const _hoisted_2$6 = {
84
84
  key: 0,
85
85
  class: "hlw-card-header"
86
86
  };
87
- const _hoisted_3$3 = { class: "flex items-center justify-between px-5 py-4 border-0 border-b border-dashed border-slate-200 bg-slate-50/30" };
88
- const _hoisted_4$2 = { key: 0 };
89
- const _hoisted_5$1 = { class: "text-sm font-bold text-slate-800 flex items-center gap-2 tracking-wide" };
90
- const _hoisted_6$1 = { key: 1 };
91
- const _hoisted_7$1 = {
87
+ const _hoisted_3$4 = { class: "flex items-center justify-between px-5 py-4 border-0 border-b border-dashed border-slate-200 bg-slate-50/30" };
88
+ const _hoisted_4$3 = { key: 0 };
89
+ const _hoisted_5$2 = { class: "text-sm font-bold text-slate-800 flex items-center gap-2 tracking-wide" };
90
+ const _hoisted_6$2 = { key: 1 };
91
+ const _hoisted_7$2 = {
92
92
  key: 0,
93
93
  class: "text-[10px] text-slate-400 bg-slate-50 px-2 py-1 rounded border border-slate-100 tracking-wide"
94
94
  };
95
- const _hoisted_8 = { class: "hlw-card-body" };
96
- const _sfc_main$5 = /* @__PURE__ */ vue.defineComponent({
95
+ const _hoisted_8$1 = { class: "hlw-card-body" };
96
+ const _sfc_main$6 = /* @__PURE__ */ vue.defineComponent({
97
97
  ...{
98
98
  options: {
99
99
  styleIsolation: "shared",
@@ -109,13 +109,13 @@
109
109
  },
110
110
  setup(__props) {
111
111
  return (_ctx, _cache) => {
112
- return vue.openBlock(), vue.createElementBlock("view", _hoisted_1$5, [
113
- _ctx.$slots.header || __props.title || __props.icon || _ctx.$slots["header-left"] || _ctx.$slots["header-right"] ? (vue.openBlock(), vue.createElementBlock("view", _hoisted_2$5, [
112
+ return vue.openBlock(), vue.createElementBlock("view", _hoisted_1$6, [
113
+ _ctx.$slots.header || __props.title || __props.icon || _ctx.$slots["header-left"] || _ctx.$slots["header-right"] ? (vue.openBlock(), vue.createElementBlock("view", _hoisted_2$6, [
114
114
  vue.renderSlot(_ctx.$slots, "header", {}, () => [
115
- vue.createElementVNode("view", _hoisted_3$3, [
116
- _ctx.$slots["header-left"] || __props.title || __props.icon ? (vue.openBlock(), vue.createElementBlock("view", _hoisted_4$2, [
115
+ vue.createElementVNode("view", _hoisted_3$4, [
116
+ _ctx.$slots["header-left"] || __props.title || __props.icon ? (vue.openBlock(), vue.createElementBlock("view", _hoisted_4$3, [
117
117
  vue.renderSlot(_ctx.$slots, "header-left", {}, () => [
118
- vue.createElementVNode("view", _hoisted_5$1, [
118
+ vue.createElementVNode("view", _hoisted_5$2, [
119
119
  __props.icon ? (vue.openBlock(), vue.createElementBlock("text", {
120
120
  key: 0,
121
121
  class: vue.normalizeClass([__props.icon, __props.iconColor])
@@ -124,30 +124,30 @@
124
124
  ])
125
125
  ], true)
126
126
  ])) : vue.createCommentVNode("", true),
127
- _ctx.$slots["header-right"] || __props.extra ? (vue.openBlock(), vue.createElementBlock("view", _hoisted_6$1, [
127
+ _ctx.$slots["header-right"] || __props.extra ? (vue.openBlock(), vue.createElementBlock("view", _hoisted_6$2, [
128
128
  vue.renderSlot(_ctx.$slots, "header-right", {}, () => [
129
- __props.extra ? (vue.openBlock(), vue.createElementBlock("text", _hoisted_7$1, vue.toDisplayString(__props.extra), 1)) : vue.createCommentVNode("", true)
129
+ __props.extra ? (vue.openBlock(), vue.createElementBlock("text", _hoisted_7$2, vue.toDisplayString(__props.extra), 1)) : vue.createCommentVNode("", true)
130
130
  ], true)
131
131
  ])) : vue.createCommentVNode("", true)
132
132
  ])
133
133
  ], true)
134
134
  ])) : vue.createCommentVNode("", true),
135
- vue.createElementVNode("view", _hoisted_8, [
135
+ vue.createElementVNode("view", _hoisted_8$1, [
136
136
  vue.renderSlot(_ctx.$slots, "default", {}, void 0, true)
137
137
  ])
138
138
  ]);
139
139
  };
140
140
  }
141
141
  });
142
- const index$5 = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__scopeId", "data-v-787fc3a7"]]);
143
- const _hoisted_1$4 = { class: "hlw-empty" };
144
- const _hoisted_2$4 = ["src"];
145
- const _hoisted_3$2 = {
142
+ const index$6 = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["__scopeId", "data-v-787fc3a7"]]);
143
+ const _hoisted_1$5 = { class: "hlw-empty" };
144
+ const _hoisted_2$5 = ["src"];
145
+ const _hoisted_3$3 = {
146
146
  key: 1,
147
147
  class: "hlw-empty__icon"
148
148
  };
149
- const _hoisted_4$1 = { class: "hlw-empty__text" };
150
- const _sfc_main$4 = /* @__PURE__ */ vue.defineComponent({
149
+ const _hoisted_4$2 = { class: "hlw-empty__text" };
150
+ const _sfc_main$5 = /* @__PURE__ */ vue.defineComponent({
151
151
  __name: "index",
152
152
  props: {
153
153
  text: {},
@@ -155,29 +155,29 @@
155
155
  },
156
156
  setup(__props) {
157
157
  return (_ctx, _cache) => {
158
- return vue.openBlock(), vue.createElementBlock("view", _hoisted_1$4, [
158
+ return vue.openBlock(), vue.createElementBlock("view", _hoisted_1$5, [
159
159
  __props.image ? (vue.openBlock(), vue.createElementBlock("image", {
160
160
  key: 0,
161
161
  class: "hlw-empty__image",
162
162
  src: __props.image,
163
163
  mode: "aspectFit"
164
- }, null, 8, _hoisted_2$4)) : (vue.openBlock(), vue.createElementBlock("text", _hoisted_3$2, "📦")),
165
- vue.createElementVNode("text", _hoisted_4$1, vue.toDisplayString(__props.text || "暂无数据"), 1),
164
+ }, null, 8, _hoisted_2$5)) : (vue.openBlock(), vue.createElementBlock("text", _hoisted_3$3, "📦")),
165
+ vue.createElementVNode("text", _hoisted_4$2, vue.toDisplayString(__props.text || "暂无数据"), 1),
166
166
  vue.renderSlot(_ctx.$slots, "default", {}, void 0, true)
167
167
  ]);
168
168
  };
169
169
  }
170
170
  });
171
- const index$4 = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["__scopeId", "data-v-72364322"]]);
172
- const _hoisted_1$3 = {
171
+ const index$5 = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__scopeId", "data-v-72364322"]]);
172
+ const _hoisted_1$4 = {
173
173
  key: 0,
174
174
  class: "header-placeholder"
175
175
  };
176
- const _hoisted_2$3 = {
176
+ const _hoisted_2$4 = {
177
177
  key: 0,
178
178
  class: "header-title header-title--center"
179
179
  };
180
- const _sfc_main$3 = /* @__PURE__ */ vue.defineComponent({
180
+ const _sfc_main$4 = /* @__PURE__ */ vue.defineComponent({
181
181
  __name: "index",
182
182
  props: {
183
183
  extraHeight: { default: 0 },
@@ -264,9 +264,9 @@
264
264
  }, vue.toDisplayString(props.title), 5)
265
265
  ], true)
266
266
  ], 2),
267
- props.titleAlign === "center" ? (vue.openBlock(), vue.createElementBlock("view", _hoisted_1$3)) : vue.createCommentVNode("", true)
267
+ props.titleAlign === "center" ? (vue.openBlock(), vue.createElementBlock("view", _hoisted_1$4)) : vue.createCommentVNode("", true)
268
268
  ], 64)) : vue.renderSlot(_ctx.$slots, "default", { key: 1 }, () => [
269
- props.title ? (vue.openBlock(), vue.createElementBlock("view", _hoisted_2$3, [
269
+ props.title ? (vue.openBlock(), vue.createElementBlock("view", _hoisted_2$4, [
270
270
  vue.createElementVNode("text", {
271
271
  class: "header-title-text",
272
272
  style: vue.normalizeStyle(titleStyle.value)
@@ -278,27 +278,120 @@
278
278
  };
279
279
  }
280
280
  });
281
- const index$3 = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__scopeId", "data-v-9a6c839c"]]);
282
- const _hoisted_1$2 = { class: "hlw-loading" };
283
- const _hoisted_2$2 = {
281
+ const index$4 = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["__scopeId", "data-v-9a6c839c"]]);
282
+ const _hoisted_1$3 = { class: "hlw-loading" };
283
+ const _hoisted_2$3 = {
284
284
  key: 0,
285
285
  class: "hlw-loading__text"
286
286
  };
287
- const _sfc_main$2 = /* @__PURE__ */ vue.defineComponent({
287
+ const _sfc_main$3 = /* @__PURE__ */ vue.defineComponent({
288
288
  __name: "index",
289
289
  props: {
290
290
  text: {}
291
291
  },
292
292
  setup(__props) {
293
293
  return (_ctx, _cache) => {
294
- return vue.openBlock(), vue.createElementBlock("view", _hoisted_1$2, [
294
+ return vue.openBlock(), vue.createElementBlock("view", _hoisted_1$3, [
295
295
  _cache[0] || (_cache[0] = vue.createElementVNode("view", { class: "hlw-loading__spinner" }, null, -1)),
296
- __props.text ? (vue.openBlock(), vue.createElementBlock("text", _hoisted_2$2, vue.toDisplayString(__props.text), 1)) : vue.createCommentVNode("", true)
296
+ __props.text ? (vue.openBlock(), vue.createElementBlock("text", _hoisted_2$3, vue.toDisplayString(__props.text), 1)) : vue.createCommentVNode("", true)
297
+ ]);
298
+ };
299
+ }
300
+ });
301
+ const index$3 = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__scopeId", "data-v-14242381"]]);
302
+ const _hoisted_1$2 = { class: "hlw-menu" };
303
+ const _hoisted_2$2 = { class: "hlw-menu-left" };
304
+ const _hoisted_3$2 = { class: "hlw-menu-label" };
305
+ const _hoisted_4$1 = { class: "hlw-menu-right" };
306
+ const _hoisted_5$1 = ["onClick"];
307
+ const _hoisted_6$1 = { class: "hlw-menu-left" };
308
+ const _hoisted_7$1 = { class: "hlw-menu-label" };
309
+ const _hoisted_8 = { class: "hlw-menu-right" };
310
+ const _hoisted_9 = {
311
+ key: 0,
312
+ class: "i-fa6-solid-circle-notch hlw-menu-spin hlw-menu-muted"
313
+ };
314
+ const _hoisted_10 = {
315
+ key: 2,
316
+ class: "hlw-menu-divider"
317
+ };
318
+ const _sfc_main$2 = /* @__PURE__ */ vue.defineComponent({
319
+ __name: "index",
320
+ props: {
321
+ items: {}
322
+ },
323
+ emits: ["click"],
324
+ setup(__props, { emit: __emit }) {
325
+ const props = __props;
326
+ const emit = __emit;
327
+ const visibleItems = vue.computed(() => props.items.filter((item) => item.visible !== false));
328
+ const handleClick = (item) => {
329
+ emit("click", item);
330
+ };
331
+ return (_ctx, _cache) => {
332
+ const _component_navigator = vue.resolveComponent("navigator");
333
+ return vue.openBlock(), vue.createElementBlock("view", _hoisted_1$2, [
334
+ (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(visibleItems.value, (item, index2) => {
335
+ return vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: index2 }, [
336
+ item.url ? (vue.openBlock(), vue.createBlock(_component_navigator, {
337
+ key: 0,
338
+ url: item.url,
339
+ class: "hlw-menu-item",
340
+ "hover-class": "hlw-menu-item--active"
341
+ }, {
342
+ default: vue.withCtx(() => [
343
+ vue.createElementVNode("view", _hoisted_2$2, [
344
+ vue.createElementVNode("view", {
345
+ class: vue.normalizeClass(["hlw-menu-icon", `hlw-menu-icon--${item.iconTheme || "slate"}`])
346
+ }, [
347
+ vue.createElementVNode("text", {
348
+ class: vue.normalizeClass(item.icon)
349
+ }, null, 2)
350
+ ], 2),
351
+ vue.createElementVNode("text", _hoisted_3$2, vue.toDisplayString(item.label), 1)
352
+ ]),
353
+ vue.createElementVNode("view", _hoisted_4$1, [
354
+ item.tag ? (vue.openBlock(), vue.createElementBlock("text", {
355
+ key: 0,
356
+ class: vue.normalizeClass(["hlw-menu-tag", [`hlw-menu-tag--${item.tagTheme || "rose"}`, item.tagPulse ? "hlw-menu-tag-pulse" : ""]])
357
+ }, vue.toDisplayString(item.tag), 3)) : vue.createCommentVNode("", true),
358
+ _cache[0] || (_cache[0] = vue.createElementVNode("text", { class: "i-fa6-solid-chevron-right hlw-menu-arrow" }, null, -1))
359
+ ])
360
+ ]),
361
+ _: 2
362
+ }, 1032, ["url"])) : (vue.openBlock(), vue.createElementBlock("view", {
363
+ key: 1,
364
+ class: "hlw-menu-item",
365
+ "hover-class": "hlw-menu-item--active",
366
+ onClick: ($event) => handleClick(item)
367
+ }, [
368
+ vue.createElementVNode("view", _hoisted_6$1, [
369
+ vue.createElementVNode("view", {
370
+ class: vue.normalizeClass(["hlw-menu-icon", `hlw-menu-icon--${item.iconTheme || "slate"}`])
371
+ }, [
372
+ vue.createElementVNode("text", {
373
+ class: vue.normalizeClass(item.icon)
374
+ }, null, 2)
375
+ ], 2),
376
+ vue.createElementVNode("text", _hoisted_7$1, vue.toDisplayString(item.label), 1)
377
+ ]),
378
+ vue.createElementVNode("view", _hoisted_8, [
379
+ item.loading ? (vue.openBlock(), vue.createElementBlock("text", _hoisted_9)) : vue.createCommentVNode("", true),
380
+ item.tag ? (vue.openBlock(), vue.createElementBlock("text", {
381
+ key: 1,
382
+ class: vue.normalizeClass(["hlw-menu-tag", [`hlw-menu-tag--${item.tagTheme || "rose"}`, item.tagPulse ? "hlw-menu-tag-pulse" : ""]])
383
+ }, vue.toDisplayString(item.tag), 3)) : vue.createCommentVNode("", true),
384
+ _cache[1] || (_cache[1] = vue.createElementVNode("text", { class: "i-fa6-solid-chevron-right hlw-menu-arrow" }, null, -1))
385
+ ])
386
+ ], 8, _hoisted_5$1)),
387
+ index2 < visibleItems.value.length - 1 ? (vue.openBlock(), vue.createElementBlock("view", _hoisted_10)) : vue.createCommentVNode("", true)
388
+ ], 64);
389
+ }), 128))
297
390
  ]);
298
391
  };
299
392
  }
300
393
  });
301
- const index$2 = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-14242381"]]);
394
+ const index$2 = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-ff3b3322"]]);
302
395
  const _hoisted_1$1 = { class: "hlw-menu-list" };
303
396
  const _hoisted_2$1 = ["onTap"];
304
397
  const _hoisted_3$1 = { class: "hlw-menu-list__left" };
@@ -396,12 +489,13 @@
396
489
  }
397
490
  });
398
491
  const index = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-155bc02a"]]);
399
- exports2.HlwAd = _sfc_main$7;
400
- exports2.HlwAvatar = index$6;
401
- exports2.HlwCard = index$5;
402
- exports2.HlwEmpty = index$4;
403
- exports2.HlwHeader = index$3;
404
- exports2.HlwLoading = index$2;
492
+ exports2.HlwAd = _sfc_main$8;
493
+ exports2.HlwAvatar = index$7;
494
+ exports2.HlwCard = index$6;
495
+ exports2.HlwEmpty = index$5;
496
+ exports2.HlwHeader = index$4;
497
+ exports2.HlwLoading = index$3;
498
+ exports2.HlwMenu = index$2;
405
499
  exports2.HlwMenuList = index$1;
406
500
  exports2.HlwPage = index;
407
501
  Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { defineComponent, resolveComponent, openBlock, createBlock, ref, computed, createElementBlock, normalizeClass, createElementVNode, toDisplayString, renderSlot, createCommentVNode, useSlots, normalizeStyle, unref, Fragment, renderList, createVNode, withCtx } from "vue";
2
- const _sfc_main$7 = /* @__PURE__ */ defineComponent({
1
+ import { defineComponent, resolveComponent, openBlock, createBlock, ref, computed, createElementBlock, normalizeClass, createElementVNode, toDisplayString, renderSlot, createCommentVNode, useSlots, normalizeStyle, unref, Fragment, renderList, withCtx, createVNode } from "vue";
2
+ const _sfc_main$8 = /* @__PURE__ */ defineComponent({
3
3
  ...{ name: "HlwAd" },
4
4
  __name: "index",
5
5
  props: {
@@ -30,13 +30,13 @@ const _sfc_main$7 = /* @__PURE__ */ defineComponent({
30
30
  };
31
31
  }
32
32
  });
33
- const _hoisted_1$6 = ["src"];
34
- const _hoisted_2$6 = {
33
+ const _hoisted_1$7 = ["src"];
34
+ const _hoisted_2$7 = {
35
35
  key: 1,
36
36
  class: "hlw-avatar__placeholder"
37
37
  };
38
- const _hoisted_3$4 = { class: "hlw-avatar__initial" };
39
- const _sfc_main$6 = /* @__PURE__ */ defineComponent({
38
+ const _hoisted_3$5 = { class: "hlw-avatar__initial" };
39
+ const _sfc_main$7 = /* @__PURE__ */ defineComponent({
40
40
  __name: "index",
41
41
  props: {
42
42
  src: {},
@@ -61,8 +61,8 @@ const _sfc_main$6 = /* @__PURE__ */ defineComponent({
61
61
  src: __props.src,
62
62
  mode: "aspectFill",
63
63
  onError: _cache[0] || (_cache[0] = ($event) => loadError.value = true)
64
- }, null, 40, _hoisted_1$6)) : (openBlock(), createElementBlock("view", _hoisted_2$6, [
65
- createElementVNode("text", _hoisted_3$4, toDisplayString(initial.value), 1)
64
+ }, null, 40, _hoisted_1$7)) : (openBlock(), createElementBlock("view", _hoisted_2$7, [
65
+ createElementVNode("text", _hoisted_3$5, toDisplayString(initial.value), 1)
66
66
  ]))
67
67
  ], 2);
68
68
  };
@@ -75,22 +75,22 @@ const _export_sfc = (sfc, props) => {
75
75
  }
76
76
  return target;
77
77
  };
78
- const index$6 = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["__scopeId", "data-v-7e8f98a5"]]);
79
- const _hoisted_1$5 = { class: "hlw-card" };
80
- const _hoisted_2$5 = {
78
+ const index$7 = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["__scopeId", "data-v-7e8f98a5"]]);
79
+ const _hoisted_1$6 = { class: "hlw-card" };
80
+ const _hoisted_2$6 = {
81
81
  key: 0,
82
82
  class: "hlw-card-header"
83
83
  };
84
- const _hoisted_3$3 = { class: "flex items-center justify-between px-5 py-4 border-0 border-b border-dashed border-slate-200 bg-slate-50/30" };
85
- const _hoisted_4$2 = { key: 0 };
86
- const _hoisted_5$1 = { class: "text-sm font-bold text-slate-800 flex items-center gap-2 tracking-wide" };
87
- const _hoisted_6$1 = { key: 1 };
88
- const _hoisted_7$1 = {
84
+ const _hoisted_3$4 = { class: "flex items-center justify-between px-5 py-4 border-0 border-b border-dashed border-slate-200 bg-slate-50/30" };
85
+ const _hoisted_4$3 = { key: 0 };
86
+ const _hoisted_5$2 = { class: "text-sm font-bold text-slate-800 flex items-center gap-2 tracking-wide" };
87
+ const _hoisted_6$2 = { key: 1 };
88
+ const _hoisted_7$2 = {
89
89
  key: 0,
90
90
  class: "text-[10px] text-slate-400 bg-slate-50 px-2 py-1 rounded border border-slate-100 tracking-wide"
91
91
  };
92
- const _hoisted_8 = { class: "hlw-card-body" };
93
- const _sfc_main$5 = /* @__PURE__ */ defineComponent({
92
+ const _hoisted_8$1 = { class: "hlw-card-body" };
93
+ const _sfc_main$6 = /* @__PURE__ */ defineComponent({
94
94
  ...{
95
95
  options: {
96
96
  styleIsolation: "shared",
@@ -106,13 +106,13 @@ const _sfc_main$5 = /* @__PURE__ */ defineComponent({
106
106
  },
107
107
  setup(__props) {
108
108
  return (_ctx, _cache) => {
109
- return openBlock(), createElementBlock("view", _hoisted_1$5, [
110
- _ctx.$slots.header || __props.title || __props.icon || _ctx.$slots["header-left"] || _ctx.$slots["header-right"] ? (openBlock(), createElementBlock("view", _hoisted_2$5, [
109
+ return openBlock(), createElementBlock("view", _hoisted_1$6, [
110
+ _ctx.$slots.header || __props.title || __props.icon || _ctx.$slots["header-left"] || _ctx.$slots["header-right"] ? (openBlock(), createElementBlock("view", _hoisted_2$6, [
111
111
  renderSlot(_ctx.$slots, "header", {}, () => [
112
- createElementVNode("view", _hoisted_3$3, [
113
- _ctx.$slots["header-left"] || __props.title || __props.icon ? (openBlock(), createElementBlock("view", _hoisted_4$2, [
112
+ createElementVNode("view", _hoisted_3$4, [
113
+ _ctx.$slots["header-left"] || __props.title || __props.icon ? (openBlock(), createElementBlock("view", _hoisted_4$3, [
114
114
  renderSlot(_ctx.$slots, "header-left", {}, () => [
115
- createElementVNode("view", _hoisted_5$1, [
115
+ createElementVNode("view", _hoisted_5$2, [
116
116
  __props.icon ? (openBlock(), createElementBlock("text", {
117
117
  key: 0,
118
118
  class: normalizeClass([__props.icon, __props.iconColor])
@@ -121,30 +121,30 @@ const _sfc_main$5 = /* @__PURE__ */ defineComponent({
121
121
  ])
122
122
  ], true)
123
123
  ])) : createCommentVNode("", true),
124
- _ctx.$slots["header-right"] || __props.extra ? (openBlock(), createElementBlock("view", _hoisted_6$1, [
124
+ _ctx.$slots["header-right"] || __props.extra ? (openBlock(), createElementBlock("view", _hoisted_6$2, [
125
125
  renderSlot(_ctx.$slots, "header-right", {}, () => [
126
- __props.extra ? (openBlock(), createElementBlock("text", _hoisted_7$1, toDisplayString(__props.extra), 1)) : createCommentVNode("", true)
126
+ __props.extra ? (openBlock(), createElementBlock("text", _hoisted_7$2, toDisplayString(__props.extra), 1)) : createCommentVNode("", true)
127
127
  ], true)
128
128
  ])) : createCommentVNode("", true)
129
129
  ])
130
130
  ], true)
131
131
  ])) : createCommentVNode("", true),
132
- createElementVNode("view", _hoisted_8, [
132
+ createElementVNode("view", _hoisted_8$1, [
133
133
  renderSlot(_ctx.$slots, "default", {}, void 0, true)
134
134
  ])
135
135
  ]);
136
136
  };
137
137
  }
138
138
  });
139
- const index$5 = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__scopeId", "data-v-787fc3a7"]]);
140
- const _hoisted_1$4 = { class: "hlw-empty" };
141
- const _hoisted_2$4 = ["src"];
142
- const _hoisted_3$2 = {
139
+ const index$6 = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["__scopeId", "data-v-787fc3a7"]]);
140
+ const _hoisted_1$5 = { class: "hlw-empty" };
141
+ const _hoisted_2$5 = ["src"];
142
+ const _hoisted_3$3 = {
143
143
  key: 1,
144
144
  class: "hlw-empty__icon"
145
145
  };
146
- const _hoisted_4$1 = { class: "hlw-empty__text" };
147
- const _sfc_main$4 = /* @__PURE__ */ defineComponent({
146
+ const _hoisted_4$2 = { class: "hlw-empty__text" };
147
+ const _sfc_main$5 = /* @__PURE__ */ defineComponent({
148
148
  __name: "index",
149
149
  props: {
150
150
  text: {},
@@ -152,29 +152,29 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
152
152
  },
153
153
  setup(__props) {
154
154
  return (_ctx, _cache) => {
155
- return openBlock(), createElementBlock("view", _hoisted_1$4, [
155
+ return openBlock(), createElementBlock("view", _hoisted_1$5, [
156
156
  __props.image ? (openBlock(), createElementBlock("image", {
157
157
  key: 0,
158
158
  class: "hlw-empty__image",
159
159
  src: __props.image,
160
160
  mode: "aspectFit"
161
- }, null, 8, _hoisted_2$4)) : (openBlock(), createElementBlock("text", _hoisted_3$2, "📦")),
162
- createElementVNode("text", _hoisted_4$1, toDisplayString(__props.text || "暂无数据"), 1),
161
+ }, null, 8, _hoisted_2$5)) : (openBlock(), createElementBlock("text", _hoisted_3$3, "📦")),
162
+ createElementVNode("text", _hoisted_4$2, toDisplayString(__props.text || "暂无数据"), 1),
163
163
  renderSlot(_ctx.$slots, "default", {}, void 0, true)
164
164
  ]);
165
165
  };
166
166
  }
167
167
  });
168
- const index$4 = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["__scopeId", "data-v-72364322"]]);
169
- const _hoisted_1$3 = {
168
+ const index$5 = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__scopeId", "data-v-72364322"]]);
169
+ const _hoisted_1$4 = {
170
170
  key: 0,
171
171
  class: "header-placeholder"
172
172
  };
173
- const _hoisted_2$3 = {
173
+ const _hoisted_2$4 = {
174
174
  key: 0,
175
175
  class: "header-title header-title--center"
176
176
  };
177
- const _sfc_main$3 = /* @__PURE__ */ defineComponent({
177
+ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
178
178
  __name: "index",
179
179
  props: {
180
180
  extraHeight: { default: 0 },
@@ -261,9 +261,9 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
261
261
  }, toDisplayString(props.title), 5)
262
262
  ], true)
263
263
  ], 2),
264
- props.titleAlign === "center" ? (openBlock(), createElementBlock("view", _hoisted_1$3)) : createCommentVNode("", true)
264
+ props.titleAlign === "center" ? (openBlock(), createElementBlock("view", _hoisted_1$4)) : createCommentVNode("", true)
265
265
  ], 64)) : renderSlot(_ctx.$slots, "default", { key: 1 }, () => [
266
- props.title ? (openBlock(), createElementBlock("view", _hoisted_2$3, [
266
+ props.title ? (openBlock(), createElementBlock("view", _hoisted_2$4, [
267
267
  createElementVNode("text", {
268
268
  class: "header-title-text",
269
269
  style: normalizeStyle(titleStyle.value)
@@ -275,27 +275,120 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
275
275
  };
276
276
  }
277
277
  });
278
- const index$3 = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__scopeId", "data-v-9a6c839c"]]);
279
- const _hoisted_1$2 = { class: "hlw-loading" };
280
- const _hoisted_2$2 = {
278
+ const index$4 = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["__scopeId", "data-v-9a6c839c"]]);
279
+ const _hoisted_1$3 = { class: "hlw-loading" };
280
+ const _hoisted_2$3 = {
281
281
  key: 0,
282
282
  class: "hlw-loading__text"
283
283
  };
284
- const _sfc_main$2 = /* @__PURE__ */ defineComponent({
284
+ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
285
285
  __name: "index",
286
286
  props: {
287
287
  text: {}
288
288
  },
289
289
  setup(__props) {
290
290
  return (_ctx, _cache) => {
291
- return openBlock(), createElementBlock("view", _hoisted_1$2, [
291
+ return openBlock(), createElementBlock("view", _hoisted_1$3, [
292
292
  _cache[0] || (_cache[0] = createElementVNode("view", { class: "hlw-loading__spinner" }, null, -1)),
293
- __props.text ? (openBlock(), createElementBlock("text", _hoisted_2$2, toDisplayString(__props.text), 1)) : createCommentVNode("", true)
293
+ __props.text ? (openBlock(), createElementBlock("text", _hoisted_2$3, toDisplayString(__props.text), 1)) : createCommentVNode("", true)
294
+ ]);
295
+ };
296
+ }
297
+ });
298
+ const index$3 = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__scopeId", "data-v-14242381"]]);
299
+ const _hoisted_1$2 = { class: "hlw-menu" };
300
+ const _hoisted_2$2 = { class: "hlw-menu-left" };
301
+ const _hoisted_3$2 = { class: "hlw-menu-label" };
302
+ const _hoisted_4$1 = { class: "hlw-menu-right" };
303
+ const _hoisted_5$1 = ["onClick"];
304
+ const _hoisted_6$1 = { class: "hlw-menu-left" };
305
+ const _hoisted_7$1 = { class: "hlw-menu-label" };
306
+ const _hoisted_8 = { class: "hlw-menu-right" };
307
+ const _hoisted_9 = {
308
+ key: 0,
309
+ class: "i-fa6-solid-circle-notch hlw-menu-spin hlw-menu-muted"
310
+ };
311
+ const _hoisted_10 = {
312
+ key: 2,
313
+ class: "hlw-menu-divider"
314
+ };
315
+ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
316
+ __name: "index",
317
+ props: {
318
+ items: {}
319
+ },
320
+ emits: ["click"],
321
+ setup(__props, { emit: __emit }) {
322
+ const props = __props;
323
+ const emit = __emit;
324
+ const visibleItems = computed(() => props.items.filter((item) => item.visible !== false));
325
+ const handleClick = (item) => {
326
+ emit("click", item);
327
+ };
328
+ return (_ctx, _cache) => {
329
+ const _component_navigator = resolveComponent("navigator");
330
+ return openBlock(), createElementBlock("view", _hoisted_1$2, [
331
+ (openBlock(true), createElementBlock(Fragment, null, renderList(visibleItems.value, (item, index2) => {
332
+ return openBlock(), createElementBlock(Fragment, { key: index2 }, [
333
+ item.url ? (openBlock(), createBlock(_component_navigator, {
334
+ key: 0,
335
+ url: item.url,
336
+ class: "hlw-menu-item",
337
+ "hover-class": "hlw-menu-item--active"
338
+ }, {
339
+ default: withCtx(() => [
340
+ createElementVNode("view", _hoisted_2$2, [
341
+ createElementVNode("view", {
342
+ class: normalizeClass(["hlw-menu-icon", `hlw-menu-icon--${item.iconTheme || "slate"}`])
343
+ }, [
344
+ createElementVNode("text", {
345
+ class: normalizeClass(item.icon)
346
+ }, null, 2)
347
+ ], 2),
348
+ createElementVNode("text", _hoisted_3$2, toDisplayString(item.label), 1)
349
+ ]),
350
+ createElementVNode("view", _hoisted_4$1, [
351
+ item.tag ? (openBlock(), createElementBlock("text", {
352
+ key: 0,
353
+ class: normalizeClass(["hlw-menu-tag", [`hlw-menu-tag--${item.tagTheme || "rose"}`, item.tagPulse ? "hlw-menu-tag-pulse" : ""]])
354
+ }, toDisplayString(item.tag), 3)) : createCommentVNode("", true),
355
+ _cache[0] || (_cache[0] = createElementVNode("text", { class: "i-fa6-solid-chevron-right hlw-menu-arrow" }, null, -1))
356
+ ])
357
+ ]),
358
+ _: 2
359
+ }, 1032, ["url"])) : (openBlock(), createElementBlock("view", {
360
+ key: 1,
361
+ class: "hlw-menu-item",
362
+ "hover-class": "hlw-menu-item--active",
363
+ onClick: ($event) => handleClick(item)
364
+ }, [
365
+ createElementVNode("view", _hoisted_6$1, [
366
+ createElementVNode("view", {
367
+ class: normalizeClass(["hlw-menu-icon", `hlw-menu-icon--${item.iconTheme || "slate"}`])
368
+ }, [
369
+ createElementVNode("text", {
370
+ class: normalizeClass(item.icon)
371
+ }, null, 2)
372
+ ], 2),
373
+ createElementVNode("text", _hoisted_7$1, toDisplayString(item.label), 1)
374
+ ]),
375
+ createElementVNode("view", _hoisted_8, [
376
+ item.loading ? (openBlock(), createElementBlock("text", _hoisted_9)) : createCommentVNode("", true),
377
+ item.tag ? (openBlock(), createElementBlock("text", {
378
+ key: 1,
379
+ class: normalizeClass(["hlw-menu-tag", [`hlw-menu-tag--${item.tagTheme || "rose"}`, item.tagPulse ? "hlw-menu-tag-pulse" : ""]])
380
+ }, toDisplayString(item.tag), 3)) : createCommentVNode("", true),
381
+ _cache[1] || (_cache[1] = createElementVNode("text", { class: "i-fa6-solid-chevron-right hlw-menu-arrow" }, null, -1))
382
+ ])
383
+ ], 8, _hoisted_5$1)),
384
+ index2 < visibleItems.value.length - 1 ? (openBlock(), createElementBlock("view", _hoisted_10)) : createCommentVNode("", true)
385
+ ], 64);
386
+ }), 128))
294
387
  ]);
295
388
  };
296
389
  }
297
390
  });
298
- const index$2 = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-14242381"]]);
391
+ const index$2 = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-ff3b3322"]]);
299
392
  const _hoisted_1$1 = { class: "hlw-menu-list" };
300
393
  const _hoisted_2$1 = ["onTap"];
301
394
  const _hoisted_3$1 = { class: "hlw-menu-list__left" };
@@ -394,12 +487,13 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
394
487
  });
395
488
  const index = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-155bc02a"]]);
396
489
  export {
397
- _sfc_main$7 as HlwAd,
398
- index$6 as HlwAvatar,
399
- index$5 as HlwCard,
400
- index$4 as HlwEmpty,
401
- index$3 as HlwHeader,
402
- index$2 as HlwLoading,
490
+ _sfc_main$8 as HlwAd,
491
+ index$7 as HlwAvatar,
492
+ index$6 as HlwCard,
493
+ index$5 as HlwEmpty,
494
+ index$4 as HlwHeader,
495
+ index$3 as HlwLoading,
496
+ index$2 as HlwMenu,
403
497
  index$1 as HlwMenuList,
404
498
  index as HlwPage
405
499
  };
package/dist/style.css CHANGED
@@ -144,7 +144,143 @@ to { transform: rotate(360deg);
144
144
  font-size: 26rpx;
145
145
  color: #999;
146
146
  }
147
-
147
+ .hlw-menu[data-v-ff3b3322] {
148
+ background: #fff;
149
+ border-radius: var(--radius-lg, 24rpx);
150
+ border: 1rpx solid var(--border-color, #e2e8f0);
151
+ overflow: hidden;
152
+ width: 100%;
153
+ padding: 8rpx 0;
154
+ }
155
+ .hlw-menu-item[data-v-ff3b3322] {
156
+ display: flex;
157
+ align-items: center;
158
+ justify-content: space-between;
159
+ padding: 16rpx 32rpx;
160
+ }
161
+ .hlw-menu-item--active[data-v-ff3b3322] {
162
+ background: #f8fafc;
163
+ }
164
+ .hlw-menu-divider[data-v-ff3b3322] {
165
+ margin: 8rpx 0;
166
+ height: 0;
167
+ border-bottom: 1rpx dashed var(--border-color, #e2e8f0);
168
+ }
169
+ .hlw-menu-left[data-v-ff3b3322] {
170
+ display: flex;
171
+ align-items: center;
172
+ gap: 24rpx;
173
+ }
174
+ .hlw-menu-right[data-v-ff3b3322] {
175
+ display: flex;
176
+ align-items: center;
177
+ gap: 16rpx;
178
+ }
179
+ .hlw-menu-icon[data-v-ff3b3322] {
180
+ width: 64rpx;
181
+ height: 64rpx;
182
+ border-radius: var(--radius-md, 16rpx);
183
+ display: flex;
184
+ align-items: center;
185
+ justify-content: center;
186
+ flex-shrink: 0;
187
+ }
188
+ .hlw-menu-icon text[data-v-ff3b3322] {
189
+ font-size: 20rpx;
190
+ }
191
+ .hlw-menu-icon--orange[data-v-ff3b3322] {
192
+ background: #fff7ed;
193
+ color: #f97316;
194
+ }
195
+ .hlw-menu-icon--purple[data-v-ff3b3322] {
196
+ background: #faf5ff;
197
+ color: #a855f7;
198
+ }
199
+ .hlw-menu-icon--wechat[data-v-ff3b3322] {
200
+ background: #f0fdf4;
201
+ color: #07C160;
202
+ }
203
+ .hlw-menu-icon--cyan[data-v-ff3b3322] {
204
+ background: #ecfeff;
205
+ color: #06b6d4;
206
+ }
207
+ .hlw-menu-icon--emerald[data-v-ff3b3322] {
208
+ background: #ecfdf5;
209
+ color: #10b981;
210
+ }
211
+ .hlw-menu-icon--slate[data-v-ff3b3322] {
212
+ background: #f1f5f9;
213
+ color: #64748b;
214
+ }
215
+ .hlw-menu-icon--rose[data-v-ff3b3322] {
216
+ background: #fff1f2;
217
+ color: #f43f5e;
218
+ }
219
+ .hlw-menu-icon--blue[data-v-ff3b3322] {
220
+ background: #eff6ff;
221
+ color: #3b82f6;
222
+ }
223
+ .hlw-menu-icon--red[data-v-ff3b3322] {
224
+ background: #fef2f2;
225
+ color: #ef4444;
226
+ }
227
+ .hlw-menu-label[data-v-ff3b3322] {
228
+ font-size: 28rpx;
229
+ font-weight: 500;
230
+ color: #334155;
231
+ }
232
+ .hlw-menu-tag[data-v-ff3b3322] {
233
+ font-size: 20rpx;
234
+ color: #fff;
235
+ padding: 2rpx 12rpx;
236
+ border-radius: 9999rpx;
237
+ box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
238
+ }
239
+ .hlw-menu-tag--orange[data-v-ff3b3322] {
240
+ background: #fb923c;
241
+ }
242
+ .hlw-menu-tag--red[data-v-ff3b3322] {
243
+ background: #ef4444;
244
+ }
245
+ .hlw-menu-tag--wechat[data-v-ff3b3322] {
246
+ background: #07C160;
247
+ }
248
+ .hlw-menu-tag--rose[data-v-ff3b3322] {
249
+ background: #f43f5e;
250
+ }
251
+ .hlw-menu-tag--blue[data-v-ff3b3322] {
252
+ background: #3b82f6;
253
+ }
254
+ .hlw-menu-tag-pulse[data-v-ff3b3322] {
255
+ animation: tag-pulse-ff3b3322 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
256
+ }
257
+ @keyframes tag-pulse-ff3b3322 {
258
+ 0%, 100% {
259
+ opacity: 1;
260
+ }
261
+ 50% {
262
+ opacity: 0.5;
263
+ }
264
+ }
265
+ .hlw-menu-arrow[data-v-ff3b3322] {
266
+ color: #d1d5db;
267
+ font-size: 20rpx;
268
+ }
269
+ .hlw-menu-spin[data-v-ff3b3322] {
270
+ animation: icon-spin-ff3b3322 1s linear infinite;
271
+ }
272
+ .hlw-menu-muted[data-v-ff3b3322] {
273
+ color: #94a3b8;
274
+ font-size: 20rpx;
275
+ }
276
+ @keyframes icon-spin-ff3b3322 {
277
+ from {
278
+ transform: rotate(0deg);
279
+ }
280
+ to {
281
+ transform: rotate(360deg);
282
+ }
283
+ }
148
284
  .hlw-menu-list[data-v-e465b0b4] {
149
285
  background: #fff;
150
286
  border-radius: 16rpx;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hlw-uni/mp-vue",
3
- "version": "1.0.12",
3
+ "version": "1.0.14",
4
4
  "description": "hlw-uni Vue 组件库 — 供小程序业务方使用的 UI 组件集合",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -0,0 +1,165 @@
1
+ <template>
2
+ <view class="hlw-menu">
3
+ <template v-for="(item, index) in visibleItems" :key="index">
4
+ <navigator v-if="item.url" :url="item.url" class="hlw-menu-item" hover-class="hlw-menu-item--active">
5
+ <view class="hlw-menu-left">
6
+ <view class="hlw-menu-icon" :class="`hlw-menu-icon--${item.iconTheme || 'slate'}`">
7
+ <text :class="item.icon"></text>
8
+ </view>
9
+ <text class="hlw-menu-label">{{ item.label }}</text>
10
+ </view>
11
+ <view class="hlw-menu-right">
12
+ <text v-if="item.tag" class="hlw-menu-tag" :class="[`hlw-menu-tag--${item.tagTheme || 'rose'}`, item.tagPulse ? 'hlw-menu-tag-pulse' : '']">{{ item.tag }}</text>
13
+ <text class="i-fa6-solid-chevron-right hlw-menu-arrow"></text>
14
+ </view>
15
+ </navigator>
16
+
17
+ <view v-else class="hlw-menu-item" hover-class="hlw-menu-item--active" @click="handleClick(item)">
18
+ <view class="hlw-menu-left">
19
+ <view class="hlw-menu-icon" :class="`hlw-menu-icon--${item.iconTheme || 'slate'}`">
20
+ <text :class="item.icon"></text>
21
+ </view>
22
+ <text class="hlw-menu-label">{{ item.label }}</text>
23
+ </view>
24
+ <view class="hlw-menu-right">
25
+ <text v-if="item.loading" class="i-fa6-solid-circle-notch hlw-menu-spin hlw-menu-muted"></text>
26
+ <text v-if="item.tag" class="hlw-menu-tag" :class="[`hlw-menu-tag--${item.tagTheme || 'rose'}`, item.tagPulse ? 'hlw-menu-tag-pulse' : '']">{{ item.tag }}</text>
27
+ <text class="i-fa6-solid-chevron-right hlw-menu-arrow"></text>
28
+ </view>
29
+ </view>
30
+
31
+ <view v-if="index < visibleItems.length - 1" class="hlw-menu-divider"></view>
32
+ </template>
33
+ </view>
34
+ </template>
35
+
36
+ <script setup lang="ts">
37
+ import { computed } from "vue";
38
+ import type { HlwMenuItem } from "./types";
39
+ export type { HlwMenuItem } from "./types";
40
+
41
+ interface Props {
42
+ items: HlwMenuItem[];
43
+ }
44
+
45
+ const props = defineProps<Props>();
46
+ const emit = defineEmits<{
47
+ click: [item: HlwMenuItem];
48
+ }>();
49
+
50
+ const visibleItems = computed(() => props.items.filter((item) => item.visible !== false));
51
+
52
+ const handleClick = (item: HlwMenuItem) => {
53
+ emit("click", item);
54
+ };
55
+ </script>
56
+
57
+ <style lang="scss" scoped>
58
+ .hlw-menu {
59
+ background: #fff;
60
+ border-radius: var(--radius-lg, 24rpx);
61
+ border: 1rpx solid var(--border-color, #e2e8f0);
62
+ overflow: hidden;
63
+ width: 100%;
64
+ padding: 8rpx 0;
65
+ }
66
+
67
+ .hlw-menu-item {
68
+ display: flex;
69
+ align-items: center;
70
+ justify-content: space-between;
71
+ padding: 16rpx 32rpx;
72
+
73
+ &--active {
74
+ background: #f8fafc;
75
+ }
76
+ }
77
+
78
+ .hlw-menu-divider {
79
+ margin: 8rpx 0;
80
+ height: 0;
81
+ border-bottom: 1rpx dashed var(--border-color, #e2e8f0);
82
+ }
83
+
84
+ .hlw-menu-left {
85
+ display: flex;
86
+ align-items: center;
87
+ gap: 24rpx;
88
+ }
89
+
90
+ .hlw-menu-right {
91
+ display: flex;
92
+ align-items: center;
93
+ gap: 16rpx;
94
+ }
95
+
96
+ .hlw-menu-icon {
97
+ width: 64rpx;
98
+ height: 64rpx;
99
+ border-radius: var(--radius-md, 16rpx);
100
+ display: flex;
101
+ align-items: center;
102
+ justify-content: center;
103
+ flex-shrink: 0;
104
+
105
+ text { font-size: 20rpx; }
106
+
107
+ &--orange { background: #fff7ed; color: #f97316; }
108
+ &--purple { background: #faf5ff; color: #a855f7; }
109
+ &--wechat { background: #f0fdf4; color: #07C160; }
110
+ &--cyan { background: #ecfeff; color: #06b6d4; }
111
+ &--emerald { background: #ecfdf5; color: #10b981; }
112
+ &--slate { background: #f1f5f9; color: #64748b; }
113
+ &--rose { background: #fff1f2; color: #f43f5e; }
114
+ &--blue { background: #eff6ff; color: #3b82f6; }
115
+ &--red { background: #fef2f2; color: #ef4444; }
116
+ }
117
+
118
+ .hlw-menu-label {
119
+ font-size: 28rpx;
120
+ font-weight: 500;
121
+ color: #334155;
122
+ }
123
+
124
+ .hlw-menu-tag {
125
+ font-size: 20rpx;
126
+ color: #fff;
127
+ padding: 2rpx 12rpx;
128
+ border-radius: 9999rpx;
129
+ box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
130
+
131
+ &--orange { background: #fb923c; }
132
+ &--red { background: #ef4444; }
133
+ &--wechat { background: #07C160; }
134
+ &--rose { background: #f43f5e; }
135
+ &--blue { background: #3b82f6; }
136
+ }
137
+
138
+ .hlw-menu-tag-pulse {
139
+ animation: tag-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
140
+ }
141
+
142
+ @keyframes tag-pulse {
143
+ 0%, 100% { opacity: 1; }
144
+ 50% { opacity: 0.5; }
145
+ }
146
+
147
+ .hlw-menu-arrow {
148
+ color: #d1d5db;
149
+ font-size: 20rpx;
150
+ }
151
+
152
+ .hlw-menu-spin {
153
+ animation: icon-spin 1s linear infinite;
154
+ }
155
+
156
+ .hlw-menu-muted {
157
+ color: #94a3b8;
158
+ font-size: 20rpx;
159
+ }
160
+
161
+ @keyframes icon-spin {
162
+ from { transform: rotate(0deg); }
163
+ to { transform: rotate(360deg); }
164
+ }
165
+ </style>
@@ -0,0 +1,20 @@
1
+ export interface HlwMenuItem {
2
+ /** 图标 class,如 'i-fa6-solid-gear' */
3
+ icon: string;
4
+ /** 图标主题色 */
5
+ iconTheme?: "orange" | "purple" | "cyan" | "emerald" | "slate" | "wechat" | "rose" | "blue" | "red";
6
+ /** 菜单文字 */
7
+ label: string;
8
+ /** 跳转路径,有值则用 navigator 包裹 */
9
+ url?: string;
10
+ /** 右侧标签文字 */
11
+ tag?: string;
12
+ /** 标签主题色 */
13
+ tagTheme?: "orange" | "red" | "wechat" | "rose" | "blue";
14
+ /** 标签是否闪烁 */
15
+ tagPulse?: boolean;
16
+ /** 加载中状态 */
17
+ loading?: boolean;
18
+ /** 是否显示,默认 true */
19
+ visible?: boolean;
20
+ }
package/src/index.ts CHANGED
@@ -8,6 +8,8 @@ export { default as HlwCard } from './components/hlw-card/index.vue';
8
8
  export { default as HlwEmpty } from './components/hlw-empty/index.vue';
9
9
  export { default as HlwHeader } from './components/hlw-header/index.vue';
10
10
  export { default as HlwLoading } from './components/hlw-loading/index.vue';
11
+ export { default as HlwMenu } from './components/hlw-menu/index.vue';
12
+ export type { HlwMenuItem } from './components/hlw-menu/types';
11
13
  export { default as HlwMenuList } from './components/hlw-menu-list/index.vue';
12
14
  export { default as HlwPage } from './components/hlw-page/index.vue';
13
15
  export type { MenuItem } from './components/hlw-menu-list/types';