@hlw-uni/mp-vue 1.0.14 → 1.0.16

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-3081ac3b"]]);
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-3081ac3b"]]);
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,92 @@ 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-3081ac3b] {
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-3081ac3b] {
158
+ padding: 24rpx 32rpx 0;
159
+ }
160
+ .hlw-menu-title text[data-v-3081ac3b] {
161
+ font-size: 24rpx;
162
+ font-weight: 600;
163
+ color: #94a3b8;
164
+ letter-spacing: 1rpx;
165
+ }
166
+
167
+ /* ========== 列表模式 ========== */
168
+ .hlw-menu-item[data-v-3081ac3b] {
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-3081ac3b] {
162
175
  background: #f8fafc;
163
176
  }
164
- .hlw-menu-divider[data-v-ff3b3322] {
165
- margin: 8rpx 0;
177
+ .hlw-menu-divider[data-v-3081ac3b] {
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-3081ac3b] {
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-3081ac3b] {
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-3081ac3b] {
195
+ display: grid;
196
+ padding: 16rpx 0 24rpx;
197
+ }
198
+ .hlw-menu-grid-item[data-v-3081ac3b] {
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-3081ac3b] {
206
+ background: #f8fafc;
207
+ }
208
+ .hlw-menu-grid-icon-wrap[data-v-3081ac3b] {
209
+ position: relative;
210
+ padding-top: 20rpx; /* 预留徽标空间,保证所有格子图标水平对齐 */
211
+ }
212
+ .hlw-menu-badge[data-v-3081ac3b] {
213
+ position: absolute;
214
+ top: 0;
215
+ right: -8rpx;
216
+ font-size: 18rpx;
217
+ color: #fff;
218
+ padding: 0 8rpx;
219
+ border-radius: 9999rpx;
220
+ min-width: 28rpx;
221
+ text-align: center;
222
+ line-height: 28rpx;
223
+ height: 28rpx;
224
+ }
225
+ .hlw-menu-grid-label[data-v-3081ac3b] {
226
+ font-size: 24rpx;
227
+ color: #334155;
228
+ text-align: center;
229
+ }
230
+
231
+ /* ========== 图标 ========== */
232
+ .hlw-menu-icon[data-v-3081ac3b] {
180
233
  width: 64rpx;
181
234
  height: 64rpx;
182
235
  border-radius: var(--radius-md, 16rpx);
@@ -185,76 +238,86 @@ to { transform: rotate(360deg);
185
238
  justify-content: center;
186
239
  flex-shrink: 0;
187
240
  }
188
- .hlw-menu-icon text[data-v-ff3b3322] {
241
+ .hlw-menu-icon text[data-v-3081ac3b] {
189
242
  font-size: 20rpx;
190
243
  }
191
- .hlw-menu-icon--orange[data-v-ff3b3322] {
244
+ .hlw-menu-icon--grid[data-v-3081ac3b] {
245
+ width: 88rpx;
246
+ height: 88rpx;
247
+ border-radius: var(--radius-lg, 24rpx);
248
+ }
249
+ .hlw-menu-icon--grid text[data-v-3081ac3b] {
250
+ font-size: 32rpx;
251
+ }
252
+ .hlw-menu-icon--orange[data-v-3081ac3b] {
192
253
  background: #fff7ed;
193
254
  color: #f97316;
194
255
  }
195
- .hlw-menu-icon--purple[data-v-ff3b3322] {
256
+ .hlw-menu-icon--purple[data-v-3081ac3b] {
196
257
  background: #faf5ff;
197
258
  color: #a855f7;
198
259
  }
199
- .hlw-menu-icon--wechat[data-v-ff3b3322] {
260
+ .hlw-menu-icon--wechat[data-v-3081ac3b] {
200
261
  background: #f0fdf4;
201
- color: #07C160;
262
+ color: #07c160;
202
263
  }
203
- .hlw-menu-icon--cyan[data-v-ff3b3322] {
264
+ .hlw-menu-icon--cyan[data-v-3081ac3b] {
204
265
  background: #ecfeff;
205
266
  color: #06b6d4;
206
267
  }
207
- .hlw-menu-icon--emerald[data-v-ff3b3322] {
268
+ .hlw-menu-icon--emerald[data-v-3081ac3b] {
208
269
  background: #ecfdf5;
209
270
  color: #10b981;
210
271
  }
211
- .hlw-menu-icon--slate[data-v-ff3b3322] {
272
+ .hlw-menu-icon--slate[data-v-3081ac3b] {
212
273
  background: #f1f5f9;
213
274
  color: #64748b;
214
275
  }
215
- .hlw-menu-icon--rose[data-v-ff3b3322] {
276
+ .hlw-menu-icon--rose[data-v-3081ac3b] {
216
277
  background: #fff1f2;
217
278
  color: #f43f5e;
218
279
  }
219
- .hlw-menu-icon--blue[data-v-ff3b3322] {
280
+ .hlw-menu-icon--blue[data-v-3081ac3b] {
220
281
  background: #eff6ff;
221
282
  color: #3b82f6;
222
283
  }
223
- .hlw-menu-icon--red[data-v-ff3b3322] {
284
+ .hlw-menu-icon--red[data-v-3081ac3b] {
224
285
  background: #fef2f2;
225
286
  color: #ef4444;
226
287
  }
227
- .hlw-menu-label[data-v-ff3b3322] {
288
+
289
+ /* ========== 标签 / 角标 ========== */
290
+ .hlw-menu-label[data-v-3081ac3b] {
228
291
  font-size: 28rpx;
229
292
  font-weight: 500;
230
293
  color: #334155;
231
294
  }
232
- .hlw-menu-tag[data-v-ff3b3322] {
295
+ .hlw-menu-tag[data-v-3081ac3b] {
233
296
  font-size: 20rpx;
234
297
  color: #fff;
235
298
  padding: 2rpx 12rpx;
236
299
  border-radius: 9999rpx;
237
300
  box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
238
301
  }
239
- .hlw-menu-tag--orange[data-v-ff3b3322] {
302
+ .hlw-menu-tag--orange[data-v-3081ac3b] {
240
303
  background: #fb923c;
241
304
  }
242
- .hlw-menu-tag--red[data-v-ff3b3322] {
305
+ .hlw-menu-tag--red[data-v-3081ac3b] {
243
306
  background: #ef4444;
244
307
  }
245
- .hlw-menu-tag--wechat[data-v-ff3b3322] {
246
- background: #07C160;
308
+ .hlw-menu-tag--wechat[data-v-3081ac3b] {
309
+ background: #07c160;
247
310
  }
248
- .hlw-menu-tag--rose[data-v-ff3b3322] {
311
+ .hlw-menu-tag--rose[data-v-3081ac3b] {
249
312
  background: #f43f5e;
250
313
  }
251
- .hlw-menu-tag--blue[data-v-ff3b3322] {
314
+ .hlw-menu-tag--blue[data-v-3081ac3b] {
252
315
  background: #3b82f6;
253
316
  }
254
- .hlw-menu-tag-pulse[data-v-ff3b3322] {
255
- animation: tag-pulse-ff3b3322 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
317
+ .hlw-menu-tag-pulse[data-v-3081ac3b] {
318
+ animation: tag-pulse-3081ac3b 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
256
319
  }
257
- @keyframes tag-pulse-ff3b3322 {
320
+ @keyframes tag-pulse-3081ac3b {
258
321
  0%, 100% {
259
322
  opacity: 1;
260
323
  }
@@ -262,18 +325,18 @@ to { transform: rotate(360deg);
262
325
  opacity: 0.5;
263
326
  }
264
327
  }
265
- .hlw-menu-arrow[data-v-ff3b3322] {
328
+ .hlw-menu-arrow[data-v-3081ac3b] {
266
329
  color: #d1d5db;
267
330
  font-size: 20rpx;
268
331
  }
269
- .hlw-menu-spin[data-v-ff3b3322] {
270
- animation: icon-spin-ff3b3322 1s linear infinite;
332
+ .hlw-menu-spin[data-v-3081ac3b] {
333
+ animation: icon-spin-3081ac3b 1s linear infinite;
271
334
  }
272
- .hlw-menu-muted[data-v-ff3b3322] {
335
+ .hlw-menu-muted[data-v-3081ac3b] {
273
336
  color: #94a3b8;
274
337
  font-size: 20rpx;
275
338
  }
276
- @keyframes icon-spin-ff3b3322 {
339
+ @keyframes icon-spin-3081ac3b {
277
340
  from {
278
341
  transform: rotate(0deg);
279
342
  }
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.16",
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,50 @@ 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
+ padding-top: 20rpx; /* 预留徽标空间,保证所有格子图标水平对齐 */
172
+ }
173
+
174
+ .hlw-menu-badge {
175
+ position: absolute;
176
+ top: 0;
177
+ right: -8rpx;
178
+ font-size: 18rpx;
179
+ color: #fff;
180
+ padding: 0 8rpx;
181
+ border-radius: 9999rpx;
182
+ min-width: 28rpx;
183
+ text-align: center;
184
+ line-height: 28rpx;
185
+ height: 28rpx;
186
+ }
187
+
188
+ .hlw-menu-grid-label {
189
+ font-size: 24rpx;
190
+ color: #334155;
191
+ text-align: center;
192
+ }
193
+
194
+ /* ========== 图标 ========== */
96
195
  .hlw-menu-icon {
97
196
  width: 64rpx;
98
197
  height: 64rpx;
@@ -104,9 +203,16 @@ const handleClick = (item: HlwMenuItem) => {
104
203
 
105
204
  text { font-size: 20rpx; }
106
205
 
206
+ &--grid {
207
+ width: 88rpx;
208
+ height: 88rpx;
209
+ border-radius: var(--radius-lg, 24rpx);
210
+ text { font-size: 32rpx; }
211
+ }
212
+
107
213
  &--orange { background: #fff7ed; color: #f97316; }
108
214
  &--purple { background: #faf5ff; color: #a855f7; }
109
- &--wechat { background: #f0fdf4; color: #07C160; }
215
+ &--wechat { background: #f0fdf4; color: #07c160; }
110
216
  &--cyan { background: #ecfeff; color: #06b6d4; }
111
217
  &--emerald { background: #ecfdf5; color: #10b981; }
112
218
  &--slate { background: #f1f5f9; color: #64748b; }
@@ -115,6 +221,7 @@ const handleClick = (item: HlwMenuItem) => {
115
221
  &--red { background: #fef2f2; color: #ef4444; }
116
222
  }
117
223
 
224
+ /* ========== 标签 / 角标 ========== */
118
225
  .hlw-menu-label {
119
226
  font-size: 28rpx;
120
227
  font-weight: 500;
@@ -127,14 +234,14 @@ const handleClick = (item: HlwMenuItem) => {
127
234
  padding: 2rpx 12rpx;
128
235
  border-radius: 9999rpx;
129
236
  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
237
  }
137
238
 
239
+ .hlw-menu-tag--orange { background: #fb923c; }
240
+ .hlw-menu-tag--red { background: #ef4444; }
241
+ .hlw-menu-tag--wechat { background: #07c160; }
242
+ .hlw-menu-tag--rose { background: #f43f5e; }
243
+ .hlw-menu-tag--blue { background: #3b82f6; }
244
+
138
245
  .hlw-menu-tag-pulse {
139
246
  animation: tag-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
140
247
  }
@@ -144,19 +251,9 @@ const handleClick = (item: HlwMenuItem) => {
144
251
  50% { opacity: 0.5; }
145
252
  }
146
253
 
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
- }
254
+ .hlw-menu-arrow { color: #d1d5db; font-size: 20rpx; }
255
+ .hlw-menu-spin { animation: icon-spin 1s linear infinite; }
256
+ .hlw-menu-muted { color: #94a3b8; font-size: 20rpx; }
160
257
 
161
258
  @keyframes icon-spin {
162
259
  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;