@hlw-uni/mp-vue 1.0.14 → 1.0.15

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.
@@ -1,19 +1,21 @@
1
+ export type HlwMenuIconTheme = "orange" | "purple" | "cyan" | "emerald" | "slate" | "wechat" | "rose" | "blue" | "red";
2
+ export type HlwMenuTagTheme = "orange" | "red" | "wechat" | "rose" | "blue";
1
3
  export interface HlwMenuItem {
2
4
  /** 图标 class,如 'i-fa6-solid-gear' */
3
5
  icon: string;
4
6
  /** 图标主题色 */
5
- iconTheme?: "orange" | "purple" | "cyan" | "emerald" | "slate" | "wechat" | "rose" | "blue" | "red";
7
+ iconTheme?: HlwMenuIconTheme;
6
8
  /** 菜单文字 */
7
9
  label: string;
8
10
  /** 跳转路径,有值则用 navigator 包裹 */
9
11
  url?: string;
10
- /** 右侧标签文字 */
12
+ /** 右侧标签文字(列表模式)/ 角标文字(宫格模式) */
11
13
  tag?: string;
12
14
  /** 标签主题色 */
13
- tagTheme?: "orange" | "red" | "wechat" | "rose" | "blue";
15
+ tagTheme?: HlwMenuTagTheme;
14
16
  /** 标签是否闪烁 */
15
17
  tagPulse?: boolean;
16
- /** 加载中状态 */
18
+ /** 加载中状态(列表模式) */
17
19
  loading?: boolean;
18
20
  /** 是否显示,默认 true */
19
21
  visible?: boolean;
package/dist/index.js CHANGED
@@ -300,25 +300,37 @@
300
300
  });
301
301
  const index$3 = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__scopeId", "data-v-14242381"]]);
302
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 = {
303
+ const _hoisted_2$2 = {
311
304
  key: 0,
312
- class: "i-fa6-solid-circle-notch hlw-menu-spin hlw-menu-muted"
305
+ class: "hlw-menu-title"
313
306
  };
307
+ const _hoisted_3$2 = { class: "hlw-menu-left" };
308
+ const _hoisted_4$1 = { class: "hlw-menu-label" };
309
+ const _hoisted_5$1 = { class: "hlw-menu-right" };
310
+ const _hoisted_6$1 = ["onClick"];
311
+ const _hoisted_7$1 = { class: "hlw-menu-left" };
312
+ const _hoisted_8 = { class: "hlw-menu-label" };
313
+ const _hoisted_9 = { class: "hlw-menu-right" };
314
314
  const _hoisted_10 = {
315
+ key: 0,
316
+ class: "i-fa6-solid-circle-notch hlw-menu-spin hlw-menu-muted"
317
+ };
318
+ const _hoisted_11 = {
315
319
  key: 2,
316
320
  class: "hlw-menu-divider"
317
321
  };
322
+ const _hoisted_12 = { class: "hlw-menu-grid-icon-wrap" };
323
+ const _hoisted_13 = { class: "hlw-menu-grid-label" };
324
+ const _hoisted_14 = ["onClick"];
325
+ const _hoisted_15 = { class: "hlw-menu-grid-icon-wrap" };
326
+ const _hoisted_16 = { class: "hlw-menu-grid-label" };
318
327
  const _sfc_main$2 = /* @__PURE__ */ vue.defineComponent({
319
328
  __name: "index",
320
329
  props: {
321
- items: {}
330
+ items: {},
331
+ title: { default: "" },
332
+ mode: { default: "list" },
333
+ columns: { default: 4 }
322
334
  },
323
335
  emits: ["click"],
324
336
  setup(__props, { emit: __emit }) {
@@ -331,7 +343,10 @@
331
343
  return (_ctx, _cache) => {
332
344
  const _component_navigator = vue.resolveComponent("navigator");
333
345
  return vue.openBlock(), vue.createElementBlock("view", _hoisted_1$2, [
334
- (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(visibleItems.value, (item, index2) => {
346
+ props.title ? (vue.openBlock(), vue.createElementBlock("view", _hoisted_2$2, [
347
+ vue.createElementVNode("text", null, vue.toDisplayString(props.title), 1)
348
+ ])) : vue.createCommentVNode("", true),
349
+ props.mode === "list" ? (vue.openBlock(true), vue.createElementBlock(vue.Fragment, { key: 1 }, vue.renderList(visibleItems.value, (item, index2) => {
335
350
  return vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: index2 }, [
336
351
  item.url ? (vue.openBlock(), vue.createBlock(_component_navigator, {
337
352
  key: 0,
@@ -340,7 +355,7 @@
340
355
  "hover-class": "hlw-menu-item--active"
341
356
  }, {
342
357
  default: vue.withCtx(() => [
343
- vue.createElementVNode("view", _hoisted_2$2, [
358
+ vue.createElementVNode("view", _hoisted_3$2, [
344
359
  vue.createElementVNode("view", {
345
360
  class: vue.normalizeClass(["hlw-menu-icon", `hlw-menu-icon--${item.iconTheme || "slate"}`])
346
361
  }, [
@@ -348,9 +363,9 @@
348
363
  class: vue.normalizeClass(item.icon)
349
364
  }, null, 2)
350
365
  ], 2),
351
- vue.createElementVNode("text", _hoisted_3$2, vue.toDisplayString(item.label), 1)
366
+ vue.createElementVNode("text", _hoisted_4$1, vue.toDisplayString(item.label), 1)
352
367
  ]),
353
- vue.createElementVNode("view", _hoisted_4$1, [
368
+ vue.createElementVNode("view", _hoisted_5$1, [
354
369
  item.tag ? (vue.openBlock(), vue.createElementBlock("text", {
355
370
  key: 0,
356
371
  class: vue.normalizeClass(["hlw-menu-tag", [`hlw-menu-tag--${item.tagTheme || "rose"}`, item.tagPulse ? "hlw-menu-tag-pulse" : ""]])
@@ -365,7 +380,7 @@
365
380
  "hover-class": "hlw-menu-item--active",
366
381
  onClick: ($event) => handleClick(item)
367
382
  }, [
368
- vue.createElementVNode("view", _hoisted_6$1, [
383
+ vue.createElementVNode("view", _hoisted_7$1, [
369
384
  vue.createElementVNode("view", {
370
385
  class: vue.normalizeClass(["hlw-menu-icon", `hlw-menu-icon--${item.iconTheme || "slate"}`])
371
386
  }, [
@@ -373,25 +388,78 @@
373
388
  class: vue.normalizeClass(item.icon)
374
389
  }, null, 2)
375
390
  ], 2),
376
- vue.createElementVNode("text", _hoisted_7$1, vue.toDisplayString(item.label), 1)
391
+ vue.createElementVNode("text", _hoisted_8, vue.toDisplayString(item.label), 1)
377
392
  ]),
378
- vue.createElementVNode("view", _hoisted_8, [
379
- item.loading ? (vue.openBlock(), vue.createElementBlock("text", _hoisted_9)) : vue.createCommentVNode("", true),
393
+ vue.createElementVNode("view", _hoisted_9, [
394
+ item.loading ? (vue.openBlock(), vue.createElementBlock("text", _hoisted_10)) : vue.createCommentVNode("", true),
380
395
  item.tag ? (vue.openBlock(), vue.createElementBlock("text", {
381
396
  key: 1,
382
397
  class: vue.normalizeClass(["hlw-menu-tag", [`hlw-menu-tag--${item.tagTheme || "rose"}`, item.tagPulse ? "hlw-menu-tag-pulse" : ""]])
383
398
  }, vue.toDisplayString(item.tag), 3)) : vue.createCommentVNode("", true),
384
399
  _cache[1] || (_cache[1] = vue.createElementVNode("text", { class: "i-fa6-solid-chevron-right hlw-menu-arrow" }, null, -1))
385
400
  ])
386
- ], 8, _hoisted_5$1)),
387
- index2 < visibleItems.value.length - 1 ? (vue.openBlock(), vue.createElementBlock("view", _hoisted_10)) : vue.createCommentVNode("", true)
401
+ ], 8, _hoisted_6$1)),
402
+ index2 < visibleItems.value.length - 1 ? (vue.openBlock(), vue.createElementBlock("view", _hoisted_11)) : vue.createCommentVNode("", true)
388
403
  ], 64);
389
- }), 128))
404
+ }), 128)) : (vue.openBlock(), vue.createElementBlock("view", {
405
+ key: 2,
406
+ class: "hlw-menu-grid",
407
+ style: vue.normalizeStyle({ gridTemplateColumns: `repeat(${props.columns}, 1fr)` })
408
+ }, [
409
+ (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(visibleItems.value, (item, index2) => {
410
+ return vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: index2 }, [
411
+ item.url ? (vue.openBlock(), vue.createBlock(_component_navigator, {
412
+ key: 0,
413
+ url: item.url,
414
+ class: "hlw-menu-grid-item",
415
+ "hover-class": "hlw-menu-grid-item--active"
416
+ }, {
417
+ default: vue.withCtx(() => [
418
+ vue.createElementVNode("view", _hoisted_12, [
419
+ vue.createElementVNode("view", {
420
+ class: vue.normalizeClass(["hlw-menu-icon hlw-menu-icon--grid", `hlw-menu-icon--${item.iconTheme || "slate"}`])
421
+ }, [
422
+ vue.createElementVNode("text", {
423
+ class: vue.normalizeClass(item.icon)
424
+ }, null, 2)
425
+ ], 2),
426
+ item.tag ? (vue.openBlock(), vue.createElementBlock("text", {
427
+ key: 0,
428
+ class: vue.normalizeClass(["hlw-menu-badge", [`hlw-menu-tag--${item.tagTheme || "rose"}`, item.tagPulse ? "hlw-menu-tag-pulse" : ""]])
429
+ }, vue.toDisplayString(item.tag), 3)) : vue.createCommentVNode("", true)
430
+ ]),
431
+ vue.createElementVNode("text", _hoisted_13, vue.toDisplayString(item.label), 1)
432
+ ]),
433
+ _: 2
434
+ }, 1032, ["url"])) : (vue.openBlock(), vue.createElementBlock("view", {
435
+ key: 1,
436
+ class: "hlw-menu-grid-item",
437
+ "hover-class": "hlw-menu-grid-item--active",
438
+ onClick: ($event) => handleClick(item)
439
+ }, [
440
+ vue.createElementVNode("view", _hoisted_15, [
441
+ vue.createElementVNode("view", {
442
+ class: vue.normalizeClass(["hlw-menu-icon hlw-menu-icon--grid", `hlw-menu-icon--${item.iconTheme || "slate"}`])
443
+ }, [
444
+ vue.createElementVNode("text", {
445
+ class: vue.normalizeClass(item.icon)
446
+ }, null, 2)
447
+ ], 2),
448
+ item.tag ? (vue.openBlock(), vue.createElementBlock("text", {
449
+ key: 0,
450
+ class: vue.normalizeClass(["hlw-menu-badge", [`hlw-menu-tag--${item.tagTheme || "rose"}`, item.tagPulse ? "hlw-menu-tag-pulse" : ""]])
451
+ }, vue.toDisplayString(item.tag), 3)) : vue.createCommentVNode("", true)
452
+ ]),
453
+ vue.createElementVNode("text", _hoisted_16, vue.toDisplayString(item.label), 1)
454
+ ], 8, _hoisted_14))
455
+ ], 64);
456
+ }), 128))
457
+ ], 4))
390
458
  ]);
391
459
  };
392
460
  }
393
461
  });
394
- const index$2 = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-ff3b3322"]]);
462
+ const index$2 = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-f4bdcedc"]]);
395
463
  const _hoisted_1$1 = { class: "hlw-menu-list" };
396
464
  const _hoisted_2$1 = ["onTap"];
397
465
  const _hoisted_3$1 = { class: "hlw-menu-list__left" };
package/dist/index.mjs CHANGED
@@ -297,25 +297,37 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
297
297
  });
298
298
  const index$3 = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__scopeId", "data-v-14242381"]]);
299
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 = {
300
+ const _hoisted_2$2 = {
308
301
  key: 0,
309
- class: "i-fa6-solid-circle-notch hlw-menu-spin hlw-menu-muted"
302
+ class: "hlw-menu-title"
310
303
  };
304
+ const _hoisted_3$2 = { class: "hlw-menu-left" };
305
+ const _hoisted_4$1 = { class: "hlw-menu-label" };
306
+ const _hoisted_5$1 = { class: "hlw-menu-right" };
307
+ const _hoisted_6$1 = ["onClick"];
308
+ const _hoisted_7$1 = { class: "hlw-menu-left" };
309
+ const _hoisted_8 = { class: "hlw-menu-label" };
310
+ const _hoisted_9 = { class: "hlw-menu-right" };
311
311
  const _hoisted_10 = {
312
+ key: 0,
313
+ class: "i-fa6-solid-circle-notch hlw-menu-spin hlw-menu-muted"
314
+ };
315
+ const _hoisted_11 = {
312
316
  key: 2,
313
317
  class: "hlw-menu-divider"
314
318
  };
319
+ const _hoisted_12 = { class: "hlw-menu-grid-icon-wrap" };
320
+ const _hoisted_13 = { class: "hlw-menu-grid-label" };
321
+ const _hoisted_14 = ["onClick"];
322
+ const _hoisted_15 = { class: "hlw-menu-grid-icon-wrap" };
323
+ const _hoisted_16 = { class: "hlw-menu-grid-label" };
315
324
  const _sfc_main$2 = /* @__PURE__ */ defineComponent({
316
325
  __name: "index",
317
326
  props: {
318
- items: {}
327
+ items: {},
328
+ title: { default: "" },
329
+ mode: { default: "list" },
330
+ columns: { default: 4 }
319
331
  },
320
332
  emits: ["click"],
321
333
  setup(__props, { emit: __emit }) {
@@ -328,7 +340,10 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
328
340
  return (_ctx, _cache) => {
329
341
  const _component_navigator = resolveComponent("navigator");
330
342
  return openBlock(), createElementBlock("view", _hoisted_1$2, [
331
- (openBlock(true), createElementBlock(Fragment, null, renderList(visibleItems.value, (item, index2) => {
343
+ props.title ? (openBlock(), createElementBlock("view", _hoisted_2$2, [
344
+ createElementVNode("text", null, toDisplayString(props.title), 1)
345
+ ])) : createCommentVNode("", true),
346
+ props.mode === "list" ? (openBlock(true), createElementBlock(Fragment, { key: 1 }, renderList(visibleItems.value, (item, index2) => {
332
347
  return openBlock(), createElementBlock(Fragment, { key: index2 }, [
333
348
  item.url ? (openBlock(), createBlock(_component_navigator, {
334
349
  key: 0,
@@ -337,7 +352,7 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
337
352
  "hover-class": "hlw-menu-item--active"
338
353
  }, {
339
354
  default: withCtx(() => [
340
- createElementVNode("view", _hoisted_2$2, [
355
+ createElementVNode("view", _hoisted_3$2, [
341
356
  createElementVNode("view", {
342
357
  class: normalizeClass(["hlw-menu-icon", `hlw-menu-icon--${item.iconTheme || "slate"}`])
343
358
  }, [
@@ -345,9 +360,9 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
345
360
  class: normalizeClass(item.icon)
346
361
  }, null, 2)
347
362
  ], 2),
348
- createElementVNode("text", _hoisted_3$2, toDisplayString(item.label), 1)
363
+ createElementVNode("text", _hoisted_4$1, toDisplayString(item.label), 1)
349
364
  ]),
350
- createElementVNode("view", _hoisted_4$1, [
365
+ createElementVNode("view", _hoisted_5$1, [
351
366
  item.tag ? (openBlock(), createElementBlock("text", {
352
367
  key: 0,
353
368
  class: normalizeClass(["hlw-menu-tag", [`hlw-menu-tag--${item.tagTheme || "rose"}`, item.tagPulse ? "hlw-menu-tag-pulse" : ""]])
@@ -362,7 +377,7 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
362
377
  "hover-class": "hlw-menu-item--active",
363
378
  onClick: ($event) => handleClick(item)
364
379
  }, [
365
- createElementVNode("view", _hoisted_6$1, [
380
+ createElementVNode("view", _hoisted_7$1, [
366
381
  createElementVNode("view", {
367
382
  class: normalizeClass(["hlw-menu-icon", `hlw-menu-icon--${item.iconTheme || "slate"}`])
368
383
  }, [
@@ -370,25 +385,78 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
370
385
  class: normalizeClass(item.icon)
371
386
  }, null, 2)
372
387
  ], 2),
373
- createElementVNode("text", _hoisted_7$1, toDisplayString(item.label), 1)
388
+ createElementVNode("text", _hoisted_8, toDisplayString(item.label), 1)
374
389
  ]),
375
- createElementVNode("view", _hoisted_8, [
376
- item.loading ? (openBlock(), createElementBlock("text", _hoisted_9)) : createCommentVNode("", true),
390
+ createElementVNode("view", _hoisted_9, [
391
+ item.loading ? (openBlock(), createElementBlock("text", _hoisted_10)) : createCommentVNode("", true),
377
392
  item.tag ? (openBlock(), createElementBlock("text", {
378
393
  key: 1,
379
394
  class: normalizeClass(["hlw-menu-tag", [`hlw-menu-tag--${item.tagTheme || "rose"}`, item.tagPulse ? "hlw-menu-tag-pulse" : ""]])
380
395
  }, toDisplayString(item.tag), 3)) : createCommentVNode("", true),
381
396
  _cache[1] || (_cache[1] = createElementVNode("text", { class: "i-fa6-solid-chevron-right hlw-menu-arrow" }, null, -1))
382
397
  ])
383
- ], 8, _hoisted_5$1)),
384
- index2 < visibleItems.value.length - 1 ? (openBlock(), createElementBlock("view", _hoisted_10)) : createCommentVNode("", true)
398
+ ], 8, _hoisted_6$1)),
399
+ index2 < visibleItems.value.length - 1 ? (openBlock(), createElementBlock("view", _hoisted_11)) : createCommentVNode("", true)
385
400
  ], 64);
386
- }), 128))
401
+ }), 128)) : (openBlock(), createElementBlock("view", {
402
+ key: 2,
403
+ class: "hlw-menu-grid",
404
+ style: normalizeStyle({ gridTemplateColumns: `repeat(${props.columns}, 1fr)` })
405
+ }, [
406
+ (openBlock(true), createElementBlock(Fragment, null, renderList(visibleItems.value, (item, index2) => {
407
+ return openBlock(), createElementBlock(Fragment, { key: index2 }, [
408
+ item.url ? (openBlock(), createBlock(_component_navigator, {
409
+ key: 0,
410
+ url: item.url,
411
+ class: "hlw-menu-grid-item",
412
+ "hover-class": "hlw-menu-grid-item--active"
413
+ }, {
414
+ default: withCtx(() => [
415
+ createElementVNode("view", _hoisted_12, [
416
+ createElementVNode("view", {
417
+ class: normalizeClass(["hlw-menu-icon hlw-menu-icon--grid", `hlw-menu-icon--${item.iconTheme || "slate"}`])
418
+ }, [
419
+ createElementVNode("text", {
420
+ class: normalizeClass(item.icon)
421
+ }, null, 2)
422
+ ], 2),
423
+ item.tag ? (openBlock(), createElementBlock("text", {
424
+ key: 0,
425
+ class: normalizeClass(["hlw-menu-badge", [`hlw-menu-tag--${item.tagTheme || "rose"}`, item.tagPulse ? "hlw-menu-tag-pulse" : ""]])
426
+ }, toDisplayString(item.tag), 3)) : createCommentVNode("", true)
427
+ ]),
428
+ createElementVNode("text", _hoisted_13, toDisplayString(item.label), 1)
429
+ ]),
430
+ _: 2
431
+ }, 1032, ["url"])) : (openBlock(), createElementBlock("view", {
432
+ key: 1,
433
+ class: "hlw-menu-grid-item",
434
+ "hover-class": "hlw-menu-grid-item--active",
435
+ onClick: ($event) => handleClick(item)
436
+ }, [
437
+ createElementVNode("view", _hoisted_15, [
438
+ createElementVNode("view", {
439
+ class: normalizeClass(["hlw-menu-icon hlw-menu-icon--grid", `hlw-menu-icon--${item.iconTheme || "slate"}`])
440
+ }, [
441
+ createElementVNode("text", {
442
+ class: normalizeClass(item.icon)
443
+ }, null, 2)
444
+ ], 2),
445
+ item.tag ? (openBlock(), createElementBlock("text", {
446
+ key: 0,
447
+ class: normalizeClass(["hlw-menu-badge", [`hlw-menu-tag--${item.tagTheme || "rose"}`, item.tagPulse ? "hlw-menu-tag-pulse" : ""]])
448
+ }, toDisplayString(item.tag), 3)) : createCommentVNode("", true)
449
+ ]),
450
+ createElementVNode("text", _hoisted_16, toDisplayString(item.label), 1)
451
+ ], 8, _hoisted_14))
452
+ ], 64);
453
+ }), 128))
454
+ ], 4))
387
455
  ]);
388
456
  };
389
457
  }
390
458
  });
391
- const index$2 = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-ff3b3322"]]);
459
+ const index$2 = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-f4bdcedc"]]);
392
460
  const _hoisted_1$1 = { class: "hlw-menu-list" };
393
461
  const _hoisted_2$1 = ["onTap"];
394
462
  const _hoisted_3$1 = { class: "hlw-menu-list__left" };
package/dist/style.css CHANGED
@@ -1,4 +1,4 @@
1
-
1
+ @charset "UTF-8";
2
2
  .hlw-avatar[data-v-7e8f98a5] {
3
3
  border-radius: 50%;
4
4
  overflow: hidden;
@@ -144,39 +144,91 @@ to { transform: rotate(360deg);
144
144
  font-size: 26rpx;
145
145
  color: #999;
146
146
  }
147
- .hlw-menu[data-v-ff3b3322] {
147
+
148
+ .hlw-menu[data-v-f4bdcedc] {
148
149
  background: #fff;
149
150
  border-radius: var(--radius-lg, 24rpx);
150
151
  border: 1rpx solid var(--border-color, #e2e8f0);
151
152
  overflow: hidden;
152
153
  width: 100%;
153
- padding: 8rpx 0;
154
154
  }
155
- .hlw-menu-item[data-v-ff3b3322] {
155
+
156
+ /* 标题 */
157
+ .hlw-menu-title[data-v-f4bdcedc] {
158
+ padding: 24rpx 32rpx 0;
159
+ }
160
+ .hlw-menu-title text[data-v-f4bdcedc] {
161
+ font-size: 24rpx;
162
+ font-weight: 600;
163
+ color: #94a3b8;
164
+ letter-spacing: 1rpx;
165
+ }
166
+
167
+ /* ========== 列表模式 ========== */
168
+ .hlw-menu-item[data-v-f4bdcedc] {
156
169
  display: flex;
157
170
  align-items: center;
158
171
  justify-content: space-between;
159
- padding: 16rpx 32rpx;
172
+ padding: 24rpx 32rpx;
160
173
  }
161
- .hlw-menu-item--active[data-v-ff3b3322] {
174
+ .hlw-menu-item--active[data-v-f4bdcedc] {
162
175
  background: #f8fafc;
163
176
  }
164
- .hlw-menu-divider[data-v-ff3b3322] {
165
- margin: 8rpx 0;
177
+ .hlw-menu-divider[data-v-f4bdcedc] {
178
+ margin: 0 32rpx;
166
179
  height: 0;
167
180
  border-bottom: 1rpx dashed var(--border-color, #e2e8f0);
168
181
  }
169
- .hlw-menu-left[data-v-ff3b3322] {
182
+ .hlw-menu-left[data-v-f4bdcedc] {
170
183
  display: flex;
171
184
  align-items: center;
172
185
  gap: 24rpx;
173
186
  }
174
- .hlw-menu-right[data-v-ff3b3322] {
187
+ .hlw-menu-right[data-v-f4bdcedc] {
175
188
  display: flex;
176
189
  align-items: center;
177
190
  gap: 16rpx;
178
191
  }
179
- .hlw-menu-icon[data-v-ff3b3322] {
192
+
193
+ /* ========== 宫格模式 ========== */
194
+ .hlw-menu-grid[data-v-f4bdcedc] {
195
+ display: grid;
196
+ padding: 16rpx 0 24rpx;
197
+ }
198
+ .hlw-menu-grid-item[data-v-f4bdcedc] {
199
+ display: flex;
200
+ flex-direction: column;
201
+ align-items: center;
202
+ gap: 12rpx;
203
+ padding: 16rpx 8rpx;
204
+ }
205
+ .hlw-menu-grid-item--active[data-v-f4bdcedc] {
206
+ background: #f8fafc;
207
+ }
208
+ .hlw-menu-grid-icon-wrap[data-v-f4bdcedc] {
209
+ position: relative;
210
+ }
211
+ .hlw-menu-badge[data-v-f4bdcedc] {
212
+ position: absolute;
213
+ top: -8rpx;
214
+ right: -8rpx;
215
+ font-size: 18rpx;
216
+ color: #fff;
217
+ padding: 0 8rpx;
218
+ border-radius: 9999rpx;
219
+ min-width: 28rpx;
220
+ text-align: center;
221
+ line-height: 28rpx;
222
+ height: 28rpx;
223
+ }
224
+ .hlw-menu-grid-label[data-v-f4bdcedc] {
225
+ font-size: 24rpx;
226
+ color: #334155;
227
+ text-align: center;
228
+ }
229
+
230
+ /* ========== 图标 ========== */
231
+ .hlw-menu-icon[data-v-f4bdcedc] {
180
232
  width: 64rpx;
181
233
  height: 64rpx;
182
234
  border-radius: var(--radius-md, 16rpx);
@@ -185,76 +237,86 @@ to { transform: rotate(360deg);
185
237
  justify-content: center;
186
238
  flex-shrink: 0;
187
239
  }
188
- .hlw-menu-icon text[data-v-ff3b3322] {
240
+ .hlw-menu-icon text[data-v-f4bdcedc] {
189
241
  font-size: 20rpx;
190
242
  }
191
- .hlw-menu-icon--orange[data-v-ff3b3322] {
243
+ .hlw-menu-icon--grid[data-v-f4bdcedc] {
244
+ width: 88rpx;
245
+ height: 88rpx;
246
+ border-radius: var(--radius-lg, 24rpx);
247
+ }
248
+ .hlw-menu-icon--grid text[data-v-f4bdcedc] {
249
+ font-size: 32rpx;
250
+ }
251
+ .hlw-menu-icon--orange[data-v-f4bdcedc] {
192
252
  background: #fff7ed;
193
253
  color: #f97316;
194
254
  }
195
- .hlw-menu-icon--purple[data-v-ff3b3322] {
255
+ .hlw-menu-icon--purple[data-v-f4bdcedc] {
196
256
  background: #faf5ff;
197
257
  color: #a855f7;
198
258
  }
199
- .hlw-menu-icon--wechat[data-v-ff3b3322] {
259
+ .hlw-menu-icon--wechat[data-v-f4bdcedc] {
200
260
  background: #f0fdf4;
201
- color: #07C160;
261
+ color: #07c160;
202
262
  }
203
- .hlw-menu-icon--cyan[data-v-ff3b3322] {
263
+ .hlw-menu-icon--cyan[data-v-f4bdcedc] {
204
264
  background: #ecfeff;
205
265
  color: #06b6d4;
206
266
  }
207
- .hlw-menu-icon--emerald[data-v-ff3b3322] {
267
+ .hlw-menu-icon--emerald[data-v-f4bdcedc] {
208
268
  background: #ecfdf5;
209
269
  color: #10b981;
210
270
  }
211
- .hlw-menu-icon--slate[data-v-ff3b3322] {
271
+ .hlw-menu-icon--slate[data-v-f4bdcedc] {
212
272
  background: #f1f5f9;
213
273
  color: #64748b;
214
274
  }
215
- .hlw-menu-icon--rose[data-v-ff3b3322] {
275
+ .hlw-menu-icon--rose[data-v-f4bdcedc] {
216
276
  background: #fff1f2;
217
277
  color: #f43f5e;
218
278
  }
219
- .hlw-menu-icon--blue[data-v-ff3b3322] {
279
+ .hlw-menu-icon--blue[data-v-f4bdcedc] {
220
280
  background: #eff6ff;
221
281
  color: #3b82f6;
222
282
  }
223
- .hlw-menu-icon--red[data-v-ff3b3322] {
283
+ .hlw-menu-icon--red[data-v-f4bdcedc] {
224
284
  background: #fef2f2;
225
285
  color: #ef4444;
226
286
  }
227
- .hlw-menu-label[data-v-ff3b3322] {
287
+
288
+ /* ========== 标签 / 角标 ========== */
289
+ .hlw-menu-label[data-v-f4bdcedc] {
228
290
  font-size: 28rpx;
229
291
  font-weight: 500;
230
292
  color: #334155;
231
293
  }
232
- .hlw-menu-tag[data-v-ff3b3322] {
294
+ .hlw-menu-tag[data-v-f4bdcedc] {
233
295
  font-size: 20rpx;
234
296
  color: #fff;
235
297
  padding: 2rpx 12rpx;
236
298
  border-radius: 9999rpx;
237
299
  box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
238
300
  }
239
- .hlw-menu-tag--orange[data-v-ff3b3322] {
301
+ .hlw-menu-tag--orange[data-v-f4bdcedc] {
240
302
  background: #fb923c;
241
303
  }
242
- .hlw-menu-tag--red[data-v-ff3b3322] {
304
+ .hlw-menu-tag--red[data-v-f4bdcedc] {
243
305
  background: #ef4444;
244
306
  }
245
- .hlw-menu-tag--wechat[data-v-ff3b3322] {
246
- background: #07C160;
307
+ .hlw-menu-tag--wechat[data-v-f4bdcedc] {
308
+ background: #07c160;
247
309
  }
248
- .hlw-menu-tag--rose[data-v-ff3b3322] {
310
+ .hlw-menu-tag--rose[data-v-f4bdcedc] {
249
311
  background: #f43f5e;
250
312
  }
251
- .hlw-menu-tag--blue[data-v-ff3b3322] {
313
+ .hlw-menu-tag--blue[data-v-f4bdcedc] {
252
314
  background: #3b82f6;
253
315
  }
254
- .hlw-menu-tag-pulse[data-v-ff3b3322] {
255
- animation: tag-pulse-ff3b3322 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
316
+ .hlw-menu-tag-pulse[data-v-f4bdcedc] {
317
+ animation: tag-pulse-f4bdcedc 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
256
318
  }
257
- @keyframes tag-pulse-ff3b3322 {
319
+ @keyframes tag-pulse-f4bdcedc {
258
320
  0%, 100% {
259
321
  opacity: 1;
260
322
  }
@@ -262,18 +324,18 @@ to { transform: rotate(360deg);
262
324
  opacity: 0.5;
263
325
  }
264
326
  }
265
- .hlw-menu-arrow[data-v-ff3b3322] {
327
+ .hlw-menu-arrow[data-v-f4bdcedc] {
266
328
  color: #d1d5db;
267
329
  font-size: 20rpx;
268
330
  }
269
- .hlw-menu-spin[data-v-ff3b3322] {
270
- animation: icon-spin-ff3b3322 1s linear infinite;
331
+ .hlw-menu-spin[data-v-f4bdcedc] {
332
+ animation: icon-spin-f4bdcedc 1s linear infinite;
271
333
  }
272
- .hlw-menu-muted[data-v-ff3b3322] {
334
+ .hlw-menu-muted[data-v-f4bdcedc] {
273
335
  color: #94a3b8;
274
336
  font-size: 20rpx;
275
337
  }
276
- @keyframes icon-spin-ff3b3322 {
338
+ @keyframes icon-spin-f4bdcedc {
277
339
  from {
278
340
  transform: rotate(0deg);
279
341
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hlw-uni/mp-vue",
3
- "version": "1.0.14",
3
+ "version": "1.0.15",
4
4
  "description": "hlw-uni Vue 组件库 — 供小程序业务方使用的 UI 组件集合",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -1,35 +1,68 @@
1
1
  <template>
2
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>
3
+ <!-- 标题 -->
4
+ <view v-if="props.title" class="hlw-menu-title">
5
+ <text>{{ props.title }}</text>
6
+ </view>
7
+
8
+ <!-- 列表模式 -->
9
+ <template v-if="props.mode === 'list'">
10
+ <template v-for="(item, index) in visibleItems" :key="index">
11
+ <navigator v-if="item.url" :url="item.url" class="hlw-menu-item" hover-class="hlw-menu-item--active">
12
+ <view class="hlw-menu-left">
13
+ <view class="hlw-menu-icon" :class="`hlw-menu-icon--${item.iconTheme || 'slate'}`">
14
+ <text :class="item.icon"></text>
15
+ </view>
16
+ <text class="hlw-menu-label">{{ item.label }}</text>
8
17
  </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>
18
+ <view class="hlw-menu-right">
19
+ <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>
20
+ <text class="i-fa6-solid-chevron-right hlw-menu-arrow"></text>
21
+ </view>
22
+ </navigator>
16
23
 
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>
24
+ <view v-else class="hlw-menu-item" hover-class="hlw-menu-item--active" @click="handleClick(item)">
25
+ <view class="hlw-menu-left">
26
+ <view class="hlw-menu-icon" :class="`hlw-menu-icon--${item.iconTheme || 'slate'}`">
27
+ <text :class="item.icon"></text>
28
+ </view>
29
+ <text class="hlw-menu-label">{{ item.label }}</text>
30
+ </view>
31
+ <view class="hlw-menu-right">
32
+ <text v-if="item.loading" class="i-fa6-solid-circle-notch hlw-menu-spin hlw-menu-muted"></text>
33
+ <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>
34
+ <text class="i-fa6-solid-chevron-right hlw-menu-arrow"></text>
21
35
  </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
36
  </view>
29
- </view>
30
37
 
31
- <view v-if="index < visibleItems.length - 1" class="hlw-menu-divider"></view>
38
+ <view v-if="index < visibleItems.length - 1" class="hlw-menu-divider"></view>
39
+ </template>
32
40
  </template>
41
+
42
+ <!-- 宫格模式 -->
43
+ <view v-else class="hlw-menu-grid" :style="{ gridTemplateColumns: `repeat(${props.columns}, 1fr)` }">
44
+ <template v-for="(item, index) in visibleItems" :key="index">
45
+ <navigator v-if="item.url" :url="item.url" class="hlw-menu-grid-item" hover-class="hlw-menu-grid-item--active">
46
+ <view class="hlw-menu-grid-icon-wrap">
47
+ <view class="hlw-menu-icon hlw-menu-icon--grid" :class="`hlw-menu-icon--${item.iconTheme || 'slate'}`">
48
+ <text :class="item.icon"></text>
49
+ </view>
50
+ <text v-if="item.tag" class="hlw-menu-badge" :class="[`hlw-menu-tag--${item.tagTheme || 'rose'}`, item.tagPulse ? 'hlw-menu-tag-pulse' : '']">{{ item.tag }}</text>
51
+ </view>
52
+ <text class="hlw-menu-grid-label">{{ item.label }}</text>
53
+ </navigator>
54
+
55
+ <view v-else class="hlw-menu-grid-item" hover-class="hlw-menu-grid-item--active" @click="handleClick(item)">
56
+ <view class="hlw-menu-grid-icon-wrap">
57
+ <view class="hlw-menu-icon hlw-menu-icon--grid" :class="`hlw-menu-icon--${item.iconTheme || 'slate'}`">
58
+ <text :class="item.icon"></text>
59
+ </view>
60
+ <text v-if="item.tag" class="hlw-menu-badge" :class="[`hlw-menu-tag--${item.tagTheme || 'rose'}`, item.tagPulse ? 'hlw-menu-tag-pulse' : '']">{{ item.tag }}</text>
61
+ </view>
62
+ <text class="hlw-menu-grid-label">{{ item.label }}</text>
63
+ </view>
64
+ </template>
65
+ </view>
33
66
  </view>
34
67
  </template>
35
68
 
@@ -40,9 +73,20 @@ export type { HlwMenuItem } from "./types";
40
73
 
41
74
  interface Props {
42
75
  items: HlwMenuItem[];
76
+ /** 标题 */
77
+ title?: string;
78
+ /** 布局模式,默认 list */
79
+ mode?: "list" | "grid";
80
+ /** 宫格列数,默认 4 */
81
+ columns?: number;
43
82
  }
44
83
 
45
- const props = defineProps<Props>();
84
+ const props = withDefaults(defineProps<Props>(), {
85
+ title: "",
86
+ mode: "list",
87
+ columns: 4,
88
+ });
89
+
46
90
  const emit = defineEmits<{
47
91
  click: [item: HlwMenuItem];
48
92
  }>();
@@ -61,14 +105,25 @@ const handleClick = (item: HlwMenuItem) => {
61
105
  border: 1rpx solid var(--border-color, #e2e8f0);
62
106
  overflow: hidden;
63
107
  width: 100%;
64
- padding: 8rpx 0;
65
108
  }
66
109
 
110
+ /* 标题 */
111
+ .hlw-menu-title {
112
+ padding: 24rpx 32rpx 0;
113
+ text {
114
+ font-size: 24rpx;
115
+ font-weight: 600;
116
+ color: #94a3b8;
117
+ letter-spacing: 1rpx;
118
+ }
119
+ }
120
+
121
+ /* ========== 列表模式 ========== */
67
122
  .hlw-menu-item {
68
123
  display: flex;
69
124
  align-items: center;
70
125
  justify-content: space-between;
71
- padding: 16rpx 32rpx;
126
+ padding: 24rpx 32rpx;
72
127
 
73
128
  &--active {
74
129
  background: #f8fafc;
@@ -76,7 +131,7 @@ const handleClick = (item: HlwMenuItem) => {
76
131
  }
77
132
 
78
133
  .hlw-menu-divider {
79
- margin: 8rpx 0;
134
+ margin: 0 32rpx;
80
135
  height: 0;
81
136
  border-bottom: 1rpx dashed var(--border-color, #e2e8f0);
82
137
  }
@@ -93,6 +148,49 @@ const handleClick = (item: HlwMenuItem) => {
93
148
  gap: 16rpx;
94
149
  }
95
150
 
151
+ /* ========== 宫格模式 ========== */
152
+ .hlw-menu-grid {
153
+ display: grid;
154
+ padding: 16rpx 0 24rpx;
155
+ }
156
+
157
+ .hlw-menu-grid-item {
158
+ display: flex;
159
+ flex-direction: column;
160
+ align-items: center;
161
+ gap: 12rpx;
162
+ padding: 16rpx 8rpx;
163
+
164
+ &--active {
165
+ background: #f8fafc;
166
+ }
167
+ }
168
+
169
+ .hlw-menu-grid-icon-wrap {
170
+ position: relative;
171
+ }
172
+
173
+ .hlw-menu-badge {
174
+ position: absolute;
175
+ top: -8rpx;
176
+ right: -8rpx;
177
+ font-size: 18rpx;
178
+ color: #fff;
179
+ padding: 0 8rpx;
180
+ border-radius: 9999rpx;
181
+ min-width: 28rpx;
182
+ text-align: center;
183
+ line-height: 28rpx;
184
+ height: 28rpx;
185
+ }
186
+
187
+ .hlw-menu-grid-label {
188
+ font-size: 24rpx;
189
+ color: #334155;
190
+ text-align: center;
191
+ }
192
+
193
+ /* ========== 图标 ========== */
96
194
  .hlw-menu-icon {
97
195
  width: 64rpx;
98
196
  height: 64rpx;
@@ -104,9 +202,16 @@ const handleClick = (item: HlwMenuItem) => {
104
202
 
105
203
  text { font-size: 20rpx; }
106
204
 
205
+ &--grid {
206
+ width: 88rpx;
207
+ height: 88rpx;
208
+ border-radius: var(--radius-lg, 24rpx);
209
+ text { font-size: 32rpx; }
210
+ }
211
+
107
212
  &--orange { background: #fff7ed; color: #f97316; }
108
213
  &--purple { background: #faf5ff; color: #a855f7; }
109
- &--wechat { background: #f0fdf4; color: #07C160; }
214
+ &--wechat { background: #f0fdf4; color: #07c160; }
110
215
  &--cyan { background: #ecfeff; color: #06b6d4; }
111
216
  &--emerald { background: #ecfdf5; color: #10b981; }
112
217
  &--slate { background: #f1f5f9; color: #64748b; }
@@ -115,6 +220,7 @@ const handleClick = (item: HlwMenuItem) => {
115
220
  &--red { background: #fef2f2; color: #ef4444; }
116
221
  }
117
222
 
223
+ /* ========== 标签 / 角标 ========== */
118
224
  .hlw-menu-label {
119
225
  font-size: 28rpx;
120
226
  font-weight: 500;
@@ -127,14 +233,14 @@ const handleClick = (item: HlwMenuItem) => {
127
233
  padding: 2rpx 12rpx;
128
234
  border-radius: 9999rpx;
129
235
  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
236
  }
137
237
 
238
+ .hlw-menu-tag--orange { background: #fb923c; }
239
+ .hlw-menu-tag--red { background: #ef4444; }
240
+ .hlw-menu-tag--wechat { background: #07c160; }
241
+ .hlw-menu-tag--rose { background: #f43f5e; }
242
+ .hlw-menu-tag--blue { background: #3b82f6; }
243
+
138
244
  .hlw-menu-tag-pulse {
139
245
  animation: tag-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
140
246
  }
@@ -144,19 +250,9 @@ const handleClick = (item: HlwMenuItem) => {
144
250
  50% { opacity: 0.5; }
145
251
  }
146
252
 
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
- }
253
+ .hlw-menu-arrow { color: #d1d5db; font-size: 20rpx; }
254
+ .hlw-menu-spin { animation: icon-spin 1s linear infinite; }
255
+ .hlw-menu-muted { color: #94a3b8; font-size: 20rpx; }
160
256
 
161
257
  @keyframes icon-spin {
162
258
  from { transform: rotate(0deg); }
@@ -1,19 +1,22 @@
1
+ export type HlwMenuIconTheme = "orange" | "purple" | "cyan" | "emerald" | "slate" | "wechat" | "rose" | "blue" | "red";
2
+ export type HlwMenuTagTheme = "orange" | "red" | "wechat" | "rose" | "blue";
3
+
1
4
  export interface HlwMenuItem {
2
5
  /** 图标 class,如 'i-fa6-solid-gear' */
3
6
  icon: string;
4
7
  /** 图标主题色 */
5
- iconTheme?: "orange" | "purple" | "cyan" | "emerald" | "slate" | "wechat" | "rose" | "blue" | "red";
8
+ iconTheme?: HlwMenuIconTheme;
6
9
  /** 菜单文字 */
7
10
  label: string;
8
11
  /** 跳转路径,有值则用 navigator 包裹 */
9
12
  url?: string;
10
- /** 右侧标签文字 */
13
+ /** 右侧标签文字(列表模式)/ 角标文字(宫格模式) */
11
14
  tag?: string;
12
15
  /** 标签主题色 */
13
- tagTheme?: "orange" | "red" | "wechat" | "rose" | "blue";
16
+ tagTheme?: HlwMenuTagTheme;
14
17
  /** 标签是否闪烁 */
15
18
  tagPulse?: boolean;
16
- /** 加载中状态 */
19
+ /** 加载中状态(列表模式) */
17
20
  loading?: boolean;
18
21
  /** 是否显示,默认 true */
19
22
  visible?: boolean;