@hlw-uni/mp-vue 1.0.33 → 1.0.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/composables/theme.d.ts +22 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +217 -54
- package/dist/index.mjs +217 -53
- package/dist/stores/theme.d.ts +1 -0
- package/dist/style.css +87 -2
- package/package.json +1 -1
- package/src/composables/theme.ts +142 -0
- package/src/index.ts +2 -2
- package/src/stores/theme.ts +2 -2
- package/dist/components/hlw-page/font-presets.d.ts +0 -54
- package/src/composables/theme-presets.ts +0 -109
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type FontScale = "small" | "normal" | "large" | "xlarge";
|
|
2
|
+
export interface FontPreset {
|
|
3
|
+
label: string;
|
|
4
|
+
vars: Record<string, string>;
|
|
5
|
+
}
|
|
6
|
+
export interface ThemeColor {
|
|
7
|
+
label: string;
|
|
8
|
+
value: string;
|
|
9
|
+
}
|
|
10
|
+
export declare const FONT_SCALE_KEY = "hlw_font_scale";
|
|
11
|
+
export declare const THEME_COLOR_KEY = "hlw_theme_color";
|
|
12
|
+
export declare const THEME_CHANGE_EVENT = "hlw:theme-change";
|
|
13
|
+
export declare const FONT_PRESETS: Record<FontScale, FontPreset>;
|
|
14
|
+
export declare function getCurrentFontScale(): FontScale;
|
|
15
|
+
export declare function getCurrentFontVars(): Record<string, string>;
|
|
16
|
+
export declare const DEFAULT_THEMES: ThemeColor[];
|
|
17
|
+
export declare function getCurrentThemeColor(): string;
|
|
18
|
+
export declare function getCurrentThemeVars(): Record<string, string>;
|
|
19
|
+
export declare function buildThemeStyle(): string;
|
|
20
|
+
export declare function useThemePageStyle(): {
|
|
21
|
+
themePageStyle: any;
|
|
22
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -10,5 +10,6 @@ export { default as HlwLoading } from './components/hlw-loading/index.vue';
|
|
|
10
10
|
export { default as HlwMenu } from './components/hlw-menu/index.vue';
|
|
11
11
|
export type { HlwMenuItem } from './components/hlw-menu/types';
|
|
12
12
|
export { default as HlwPage } from './components/hlw-page/index.vue';
|
|
13
|
-
export type { FontScale, FontPreset } from './
|
|
14
|
-
export { FONT_PRESETS, FONT_SCALE_KEY,
|
|
13
|
+
export type { FontScale, FontPreset, ThemeColor } from './composables/theme';
|
|
14
|
+
export { FONT_PRESETS, FONT_SCALE_KEY, DEFAULT_THEMES, THEME_COLOR_KEY, THEME_CHANGE_EVENT, getCurrentFontScale, getCurrentFontVars, getCurrentThemeColor, getCurrentThemeVars, buildThemeStyle, useThemePageStyle } from './composables/theme';
|
|
15
|
+
export { useThemeStore } from './stores/theme';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(function(global, factory) {
|
|
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
|
-
})(this, function(exports2, vue) {
|
|
2
|
+
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("vue"), require("pinia")) : typeof define === "function" && define.amd ? define(["exports", "vue", "pinia"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.HlwUniVue = {}, global.vue, global.pinia));
|
|
3
|
+
})(this, function(exports2, vue, pinia) {
|
|
4
4
|
"use strict";
|
|
5
5
|
const _sfc_main$7 = /* @__PURE__ */ vue.defineComponent({
|
|
6
6
|
...{ name: "HlwAd" },
|
|
@@ -79,67 +79,108 @@
|
|
|
79
79
|
return target;
|
|
80
80
|
};
|
|
81
81
|
const index$6 = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["__scopeId", "data-v-89dcbc96"]]);
|
|
82
|
-
const _hoisted_1$5 = {
|
|
83
|
-
const _hoisted_2$5 = {
|
|
82
|
+
const _hoisted_1$5 = {
|
|
84
83
|
key: 0,
|
|
85
84
|
class: "hlw-card-header"
|
|
86
85
|
};
|
|
87
|
-
const
|
|
88
|
-
const
|
|
89
|
-
const
|
|
90
|
-
|
|
86
|
+
const _hoisted_2$5 = { class: "hlw-card-header-inner" };
|
|
87
|
+
const _hoisted_3$3 = { class: "hlw-card-header-left" };
|
|
88
|
+
const _hoisted_4$2 = {
|
|
89
|
+
key: 0,
|
|
90
|
+
class: "hlw-card-title"
|
|
91
|
+
};
|
|
92
|
+
const _hoisted_5$1 = {
|
|
93
|
+
key: 0,
|
|
94
|
+
class: "hlw-card-header-right"
|
|
95
|
+
};
|
|
96
|
+
const _hoisted_6$1 = {
|
|
97
|
+
key: 0,
|
|
98
|
+
class: "hlw-card-extra"
|
|
99
|
+
};
|
|
91
100
|
const _hoisted_7$1 = {
|
|
101
|
+
key: 1,
|
|
102
|
+
class: "hlw-card-divider"
|
|
103
|
+
};
|
|
104
|
+
const _hoisted_8$1 = {
|
|
105
|
+
key: 2,
|
|
106
|
+
class: "hlw-card-footer"
|
|
107
|
+
};
|
|
108
|
+
const _hoisted_9$1 = { class: "hlw-card-footer-inner" };
|
|
109
|
+
const _hoisted_10$1 = { class: "hlw-card-footer-left" };
|
|
110
|
+
const _hoisted_11$1 = {
|
|
92
111
|
key: 0,
|
|
93
|
-
class: "
|
|
112
|
+
class: "hlw-card-footer-right"
|
|
94
113
|
};
|
|
95
|
-
const _hoisted_8$1 = { class: "hlw-card-body" };
|
|
96
114
|
const _sfc_main$5 = /* @__PURE__ */ vue.defineComponent({
|
|
97
|
-
...{
|
|
98
|
-
options: {
|
|
99
|
-
styleIsolation: "shared",
|
|
100
|
-
virtualHost: true
|
|
101
|
-
}
|
|
102
|
-
},
|
|
103
115
|
__name: "index",
|
|
104
116
|
props: {
|
|
105
117
|
title: { default: "" },
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
118
|
+
extra: { default: "" },
|
|
119
|
+
border: { type: Boolean, default: true },
|
|
120
|
+
radius: { default: "xl" },
|
|
121
|
+
divider: { type: Boolean, default: void 0 },
|
|
122
|
+
padding: { type: Boolean, default: true }
|
|
109
123
|
},
|
|
110
124
|
setup(__props) {
|
|
125
|
+
const props = __props;
|
|
126
|
+
const slots = vue.useSlots();
|
|
127
|
+
const hasHeader = vue.computed(
|
|
128
|
+
() => !!(props.title || props.extra || slots.header || slots["header-left"] || slots["header-right"])
|
|
129
|
+
);
|
|
130
|
+
const hasFooter = vue.computed(
|
|
131
|
+
() => !!(slots.footer || slots["footer-left"] || slots["footer-right"])
|
|
132
|
+
);
|
|
133
|
+
const showDivider = vue.computed(() => {
|
|
134
|
+
if (props.divider !== void 0)
|
|
135
|
+
return props.divider;
|
|
136
|
+
return hasHeader.value;
|
|
137
|
+
});
|
|
111
138
|
return (_ctx, _cache) => {
|
|
112
|
-
return vue.openBlock(), vue.createElementBlock("view",
|
|
113
|
-
|
|
139
|
+
return vue.openBlock(), vue.createElementBlock("view", {
|
|
140
|
+
class: vue.normalizeClass(["hlw-card", [
|
|
141
|
+
`hlw-card--radius-${__props.radius}`,
|
|
142
|
+
__props.border ? "hlw-card--bordered" : ""
|
|
143
|
+
]])
|
|
144
|
+
}, [
|
|
145
|
+
hasHeader.value ? (vue.openBlock(), vue.createElementBlock("view", _hoisted_1$5, [
|
|
114
146
|
vue.renderSlot(_ctx.$slots, "header", {}, () => [
|
|
115
|
-
vue.createElementVNode("view",
|
|
116
|
-
|
|
147
|
+
vue.createElementVNode("view", _hoisted_2$5, [
|
|
148
|
+
vue.createElementVNode("view", _hoisted_3$3, [
|
|
117
149
|
vue.renderSlot(_ctx.$slots, "header-left", {}, () => [
|
|
118
|
-
vue.
|
|
119
|
-
__props.icon ? (vue.openBlock(), vue.createElementBlock("text", {
|
|
120
|
-
key: 0,
|
|
121
|
-
class: vue.normalizeClass([__props.icon, __props.iconColor])
|
|
122
|
-
}, null, 2)) : vue.createCommentVNode("", true),
|
|
123
|
-
vue.createElementVNode("text", null, vue.toDisplayString(__props.title), 1)
|
|
124
|
-
])
|
|
150
|
+
__props.title ? (vue.openBlock(), vue.createElementBlock("text", _hoisted_4$2, vue.toDisplayString(__props.title), 1)) : vue.createCommentVNode("", true)
|
|
125
151
|
], true)
|
|
126
|
-
])
|
|
127
|
-
_ctx.$slots["header-right"] || __props.extra ? (vue.openBlock(), vue.createElementBlock("view",
|
|
152
|
+
]),
|
|
153
|
+
_ctx.$slots["header-right"] || __props.extra ? (vue.openBlock(), vue.createElementBlock("view", _hoisted_5$1, [
|
|
128
154
|
vue.renderSlot(_ctx.$slots, "header-right", {}, () => [
|
|
129
|
-
__props.extra ? (vue.openBlock(), vue.createElementBlock("text",
|
|
155
|
+
__props.extra ? (vue.openBlock(), vue.createElementBlock("text", _hoisted_6$1, vue.toDisplayString(__props.extra), 1)) : vue.createCommentVNode("", true)
|
|
130
156
|
], true)
|
|
131
157
|
])) : vue.createCommentVNode("", true)
|
|
132
158
|
])
|
|
133
159
|
], true)
|
|
134
160
|
])) : vue.createCommentVNode("", true),
|
|
135
|
-
vue.
|
|
161
|
+
showDivider.value ? (vue.openBlock(), vue.createElementBlock("view", _hoisted_7$1)) : vue.createCommentVNode("", true),
|
|
162
|
+
vue.createElementVNode("view", {
|
|
163
|
+
class: vue.normalizeClass(["hlw-card-body", { "hlw-card-body--padded": __props.padding }])
|
|
164
|
+
}, [
|
|
136
165
|
vue.renderSlot(_ctx.$slots, "default", {}, void 0, true)
|
|
137
|
-
])
|
|
138
|
-
|
|
166
|
+
], 2),
|
|
167
|
+
hasFooter.value ? (vue.openBlock(), vue.createElementBlock("view", _hoisted_8$1, [
|
|
168
|
+
vue.renderSlot(_ctx.$slots, "footer", {}, () => [
|
|
169
|
+
vue.createElementVNode("view", _hoisted_9$1, [
|
|
170
|
+
vue.createElementVNode("view", _hoisted_10$1, [
|
|
171
|
+
vue.renderSlot(_ctx.$slots, "footer-left", {}, void 0, true)
|
|
172
|
+
]),
|
|
173
|
+
_ctx.$slots["footer-right"] ? (vue.openBlock(), vue.createElementBlock("view", _hoisted_11$1, [
|
|
174
|
+
vue.renderSlot(_ctx.$slots, "footer-right", {}, void 0, true)
|
|
175
|
+
])) : vue.createCommentVNode("", true)
|
|
176
|
+
])
|
|
177
|
+
], true)
|
|
178
|
+
])) : vue.createCommentVNode("", true)
|
|
179
|
+
], 2);
|
|
139
180
|
};
|
|
140
181
|
}
|
|
141
182
|
});
|
|
142
|
-
const index$5 = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__scopeId", "data-v-
|
|
183
|
+
const index$5 = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__scopeId", "data-v-cf55252e"]]);
|
|
143
184
|
const _hoisted_1$4 = { class: "hlw-empty" };
|
|
144
185
|
const _hoisted_2$4 = ["src"];
|
|
145
186
|
const _hoisted_3$2 = {
|
|
@@ -523,45 +564,161 @@
|
|
|
523
564
|
}
|
|
524
565
|
});
|
|
525
566
|
const index = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-d8833363"]]);
|
|
567
|
+
function varsToStyle(vars) {
|
|
568
|
+
return Object.entries(vars).map(([k, v]) => `${k}:${v}`).join(";") + ";";
|
|
569
|
+
}
|
|
570
|
+
function hexToRgba(hex, alpha) {
|
|
571
|
+
const r = parseInt(hex.slice(1, 3), 16);
|
|
572
|
+
const g = parseInt(hex.slice(3, 5), 16);
|
|
573
|
+
const b = parseInt(hex.slice(5, 7), 16);
|
|
574
|
+
return `rgba(${r},${g},${b},${alpha})`;
|
|
575
|
+
}
|
|
576
|
+
function darkenHex(hex, amount = 0.15) {
|
|
577
|
+
const r = Math.max(0, Math.round(parseInt(hex.slice(1, 3), 16) * (1 - amount)));
|
|
578
|
+
const g = Math.max(0, Math.round(parseInt(hex.slice(3, 5), 16) * (1 - amount)));
|
|
579
|
+
const b = Math.max(0, Math.round(parseInt(hex.slice(5, 7), 16) * (1 - amount)));
|
|
580
|
+
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
|
|
581
|
+
}
|
|
526
582
|
const FONT_SCALE_KEY = "hlw_font_scale";
|
|
527
|
-
const
|
|
583
|
+
const THEME_COLOR_KEY = "hlw_theme_color";
|
|
584
|
+
const THEME_CHANGE_EVENT = "hlw:theme-change";
|
|
528
585
|
const FONT_PRESETS = {
|
|
586
|
+
small: {
|
|
587
|
+
label: "小字体",
|
|
588
|
+
vars: {
|
|
589
|
+
"--font-xs": "16rpx",
|
|
590
|
+
"--font-sm": "20rpx",
|
|
591
|
+
"--font-base": "24rpx",
|
|
592
|
+
"--font-md": "28rpx",
|
|
593
|
+
"--font-lg": "32rpx",
|
|
594
|
+
"--font-xl": "36rpx"
|
|
595
|
+
}
|
|
596
|
+
},
|
|
529
597
|
normal: {
|
|
530
598
|
label: "标准",
|
|
531
|
-
|
|
599
|
+
vars: {
|
|
600
|
+
"--font-xs": "20rpx",
|
|
601
|
+
"--font-sm": "24rpx",
|
|
602
|
+
"--font-base": "28rpx",
|
|
603
|
+
"--font-md": "32rpx",
|
|
604
|
+
"--font-lg": "36rpx",
|
|
605
|
+
"--font-xl": "40rpx"
|
|
606
|
+
}
|
|
532
607
|
},
|
|
533
608
|
large: {
|
|
534
609
|
label: "大字体",
|
|
535
|
-
|
|
610
|
+
vars: {
|
|
611
|
+
"--font-xs": "24rpx",
|
|
612
|
+
"--font-sm": "30rpx",
|
|
613
|
+
"--font-base": "34rpx",
|
|
614
|
+
"--font-md": "40rpx",
|
|
615
|
+
"--font-lg": "46rpx",
|
|
616
|
+
"--font-xl": "52rpx"
|
|
617
|
+
}
|
|
536
618
|
},
|
|
537
619
|
xlarge: {
|
|
538
620
|
label: "超大字体",
|
|
539
|
-
|
|
621
|
+
vars: {
|
|
622
|
+
"--font-xs": "28rpx",
|
|
623
|
+
"--font-sm": "36rpx",
|
|
624
|
+
"--font-base": "42rpx",
|
|
625
|
+
"--font-md": "48rpx",
|
|
626
|
+
"--font-lg": "56rpx",
|
|
627
|
+
"--font-xl": "64rpx"
|
|
628
|
+
}
|
|
540
629
|
}
|
|
541
630
|
};
|
|
542
631
|
function getCurrentFontScale() {
|
|
543
632
|
try {
|
|
544
633
|
const v = uni.getStorageSync(FONT_SCALE_KEY);
|
|
545
|
-
if (v === "large" || v === "xlarge")
|
|
634
|
+
if (v === "small" || v === "large" || v === "xlarge")
|
|
546
635
|
return v;
|
|
547
636
|
} catch {
|
|
548
637
|
}
|
|
549
638
|
return "normal";
|
|
550
639
|
}
|
|
551
|
-
function
|
|
552
|
-
return FONT_PRESETS[getCurrentFontScale()].
|
|
640
|
+
function getCurrentFontVars() {
|
|
641
|
+
return FONT_PRESETS[getCurrentFontScale()].vars;
|
|
553
642
|
}
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
643
|
+
const DEFAULT_THEMES = [
|
|
644
|
+
{ label: "默认蓝", value: "#3b82f6" },
|
|
645
|
+
{ label: "活力橙", value: "#f97316" },
|
|
646
|
+
{ label: "翡翠绿", value: "#10b981" },
|
|
647
|
+
{ label: "玫瑰红", value: "#f43f5e" },
|
|
648
|
+
{ label: "紫罗兰", value: "#8b5cf6" },
|
|
649
|
+
{ label: "青石灰", value: "#64748b" }
|
|
650
|
+
];
|
|
651
|
+
function getCurrentThemeColor() {
|
|
652
|
+
try {
|
|
653
|
+
const v = uni.getStorageSync(THEME_COLOR_KEY);
|
|
654
|
+
if (v && typeof v === "string")
|
|
655
|
+
return v;
|
|
656
|
+
} catch {
|
|
657
|
+
}
|
|
658
|
+
return DEFAULT_THEMES[0].value;
|
|
659
|
+
}
|
|
660
|
+
function getCurrentThemeVars() {
|
|
661
|
+
const color = getCurrentThemeColor();
|
|
662
|
+
return {
|
|
663
|
+
"--primary-color": color,
|
|
664
|
+
"--primary-light": hexToRgba(color, 0.12),
|
|
665
|
+
"--primary-dark": darkenHex(color)
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
function buildThemeStyle() {
|
|
669
|
+
return varsToStyle({
|
|
670
|
+
...getCurrentFontVars(),
|
|
671
|
+
...getCurrentThemeVars()
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
function useThemePageStyle() {
|
|
675
|
+
const themePageStyle = vue.ref(buildThemeStyle());
|
|
676
|
+
const onThemeChange = () => {
|
|
677
|
+
themePageStyle.value = buildThemeStyle();
|
|
558
678
|
};
|
|
559
|
-
vue.onMounted(() => uni.$on(
|
|
560
|
-
vue.onUnmounted(() => uni.$off(
|
|
561
|
-
return {
|
|
679
|
+
vue.onMounted(() => uni.$on(THEME_CHANGE_EVENT, onThemeChange));
|
|
680
|
+
vue.onUnmounted(() => uni.$off(THEME_CHANGE_EVENT, onThemeChange));
|
|
681
|
+
return { themePageStyle };
|
|
562
682
|
}
|
|
683
|
+
const useThemeStore = pinia.defineStore(
|
|
684
|
+
"theme",
|
|
685
|
+
() => {
|
|
686
|
+
const scale = vue.ref("normal");
|
|
687
|
+
function setScale(s) {
|
|
688
|
+
scale.value = s;
|
|
689
|
+
uni.setStorageSync(FONT_SCALE_KEY, s);
|
|
690
|
+
uni.$emit(THEME_CHANGE_EVENT);
|
|
691
|
+
}
|
|
692
|
+
const fontOptions = Object.keys(FONT_PRESETS).map((key) => ({
|
|
693
|
+
value: key,
|
|
694
|
+
label: FONT_PRESETS[key].label
|
|
695
|
+
}));
|
|
696
|
+
const primaryColor = vue.ref(DEFAULT_THEMES[0].value);
|
|
697
|
+
const themes = DEFAULT_THEMES;
|
|
698
|
+
const activeTheme = vue.computed(
|
|
699
|
+
() => themes.find((t) => t.value === primaryColor.value) ?? { label: "自定义", value: primaryColor.value }
|
|
700
|
+
);
|
|
701
|
+
function setTheme(color) {
|
|
702
|
+
primaryColor.value = color;
|
|
703
|
+
uni.setStorageSync(THEME_COLOR_KEY, color);
|
|
704
|
+
uni.$emit(THEME_CHANGE_EVENT);
|
|
705
|
+
}
|
|
706
|
+
return {
|
|
707
|
+
// 字体
|
|
708
|
+
scale,
|
|
709
|
+
fontOptions,
|
|
710
|
+
setScale,
|
|
711
|
+
// 主题色
|
|
712
|
+
primaryColor,
|
|
713
|
+
themes,
|
|
714
|
+
activeTheme,
|
|
715
|
+
setTheme
|
|
716
|
+
};
|
|
717
|
+
},
|
|
718
|
+
{ unistorage: true }
|
|
719
|
+
);
|
|
720
|
+
exports2.DEFAULT_THEMES = DEFAULT_THEMES;
|
|
563
721
|
exports2.FONT_PRESETS = FONT_PRESETS;
|
|
564
|
-
exports2.FONT_SCALE_EVENT = FONT_SCALE_EVENT;
|
|
565
722
|
exports2.FONT_SCALE_KEY = FONT_SCALE_KEY;
|
|
566
723
|
exports2.HlwAd = _sfc_main$7;
|
|
567
724
|
exports2.HlwAvatar = index$6;
|
|
@@ -571,8 +728,14 @@
|
|
|
571
728
|
exports2.HlwLoading = index$2;
|
|
572
729
|
exports2.HlwMenu = index$1;
|
|
573
730
|
exports2.HlwPage = index;
|
|
731
|
+
exports2.THEME_CHANGE_EVENT = THEME_CHANGE_EVENT;
|
|
732
|
+
exports2.THEME_COLOR_KEY = THEME_COLOR_KEY;
|
|
733
|
+
exports2.buildThemeStyle = buildThemeStyle;
|
|
574
734
|
exports2.getCurrentFontScale = getCurrentFontScale;
|
|
575
|
-
exports2.
|
|
576
|
-
exports2.
|
|
735
|
+
exports2.getCurrentFontVars = getCurrentFontVars;
|
|
736
|
+
exports2.getCurrentThemeColor = getCurrentThemeColor;
|
|
737
|
+
exports2.getCurrentThemeVars = getCurrentThemeVars;
|
|
738
|
+
exports2.useThemePageStyle = useThemePageStyle;
|
|
739
|
+
exports2.useThemeStore = useThemeStore;
|
|
577
740
|
Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
|
|
578
741
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { defineComponent, resolveComponent, openBlock, createBlock, ref, computed, createElementBlock, normalizeClass, createElementVNode, toDisplayString, renderSlot, createCommentVNode,
|
|
1
|
+
import { defineComponent, resolveComponent, openBlock, createBlock, ref, computed, createElementBlock, normalizeClass, createElementVNode, toDisplayString, useSlots, renderSlot, createCommentVNode, normalizeStyle, unref, Fragment, renderList, withCtx, createVNode, onMounted, onUnmounted } from "vue";
|
|
2
|
+
import { defineStore } from "pinia";
|
|
2
3
|
const _sfc_main$7 = /* @__PURE__ */ defineComponent({
|
|
3
4
|
...{ name: "HlwAd" },
|
|
4
5
|
__name: "index",
|
|
@@ -76,67 +77,108 @@ const _export_sfc = (sfc, props) => {
|
|
|
76
77
|
return target;
|
|
77
78
|
};
|
|
78
79
|
const index$6 = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["__scopeId", "data-v-89dcbc96"]]);
|
|
79
|
-
const _hoisted_1$5 = {
|
|
80
|
-
const _hoisted_2$5 = {
|
|
80
|
+
const _hoisted_1$5 = {
|
|
81
81
|
key: 0,
|
|
82
82
|
class: "hlw-card-header"
|
|
83
83
|
};
|
|
84
|
-
const
|
|
85
|
-
const
|
|
86
|
-
const
|
|
87
|
-
|
|
84
|
+
const _hoisted_2$5 = { class: "hlw-card-header-inner" };
|
|
85
|
+
const _hoisted_3$3 = { class: "hlw-card-header-left" };
|
|
86
|
+
const _hoisted_4$2 = {
|
|
87
|
+
key: 0,
|
|
88
|
+
class: "hlw-card-title"
|
|
89
|
+
};
|
|
90
|
+
const _hoisted_5$1 = {
|
|
91
|
+
key: 0,
|
|
92
|
+
class: "hlw-card-header-right"
|
|
93
|
+
};
|
|
94
|
+
const _hoisted_6$1 = {
|
|
95
|
+
key: 0,
|
|
96
|
+
class: "hlw-card-extra"
|
|
97
|
+
};
|
|
88
98
|
const _hoisted_7$1 = {
|
|
99
|
+
key: 1,
|
|
100
|
+
class: "hlw-card-divider"
|
|
101
|
+
};
|
|
102
|
+
const _hoisted_8$1 = {
|
|
103
|
+
key: 2,
|
|
104
|
+
class: "hlw-card-footer"
|
|
105
|
+
};
|
|
106
|
+
const _hoisted_9$1 = { class: "hlw-card-footer-inner" };
|
|
107
|
+
const _hoisted_10$1 = { class: "hlw-card-footer-left" };
|
|
108
|
+
const _hoisted_11$1 = {
|
|
89
109
|
key: 0,
|
|
90
|
-
class: "
|
|
110
|
+
class: "hlw-card-footer-right"
|
|
91
111
|
};
|
|
92
|
-
const _hoisted_8$1 = { class: "hlw-card-body" };
|
|
93
112
|
const _sfc_main$5 = /* @__PURE__ */ defineComponent({
|
|
94
|
-
...{
|
|
95
|
-
options: {
|
|
96
|
-
styleIsolation: "shared",
|
|
97
|
-
virtualHost: true
|
|
98
|
-
}
|
|
99
|
-
},
|
|
100
113
|
__name: "index",
|
|
101
114
|
props: {
|
|
102
115
|
title: { default: "" },
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
116
|
+
extra: { default: "" },
|
|
117
|
+
border: { type: Boolean, default: true },
|
|
118
|
+
radius: { default: "xl" },
|
|
119
|
+
divider: { type: Boolean, default: void 0 },
|
|
120
|
+
padding: { type: Boolean, default: true }
|
|
106
121
|
},
|
|
107
122
|
setup(__props) {
|
|
123
|
+
const props = __props;
|
|
124
|
+
const slots = useSlots();
|
|
125
|
+
const hasHeader = computed(
|
|
126
|
+
() => !!(props.title || props.extra || slots.header || slots["header-left"] || slots["header-right"])
|
|
127
|
+
);
|
|
128
|
+
const hasFooter = computed(
|
|
129
|
+
() => !!(slots.footer || slots["footer-left"] || slots["footer-right"])
|
|
130
|
+
);
|
|
131
|
+
const showDivider = computed(() => {
|
|
132
|
+
if (props.divider !== void 0)
|
|
133
|
+
return props.divider;
|
|
134
|
+
return hasHeader.value;
|
|
135
|
+
});
|
|
108
136
|
return (_ctx, _cache) => {
|
|
109
|
-
return openBlock(), createElementBlock("view",
|
|
110
|
-
|
|
137
|
+
return openBlock(), createElementBlock("view", {
|
|
138
|
+
class: normalizeClass(["hlw-card", [
|
|
139
|
+
`hlw-card--radius-${__props.radius}`,
|
|
140
|
+
__props.border ? "hlw-card--bordered" : ""
|
|
141
|
+
]])
|
|
142
|
+
}, [
|
|
143
|
+
hasHeader.value ? (openBlock(), createElementBlock("view", _hoisted_1$5, [
|
|
111
144
|
renderSlot(_ctx.$slots, "header", {}, () => [
|
|
112
|
-
createElementVNode("view",
|
|
113
|
-
|
|
145
|
+
createElementVNode("view", _hoisted_2$5, [
|
|
146
|
+
createElementVNode("view", _hoisted_3$3, [
|
|
114
147
|
renderSlot(_ctx.$slots, "header-left", {}, () => [
|
|
115
|
-
|
|
116
|
-
__props.icon ? (openBlock(), createElementBlock("text", {
|
|
117
|
-
key: 0,
|
|
118
|
-
class: normalizeClass([__props.icon, __props.iconColor])
|
|
119
|
-
}, null, 2)) : createCommentVNode("", true),
|
|
120
|
-
createElementVNode("text", null, toDisplayString(__props.title), 1)
|
|
121
|
-
])
|
|
148
|
+
__props.title ? (openBlock(), createElementBlock("text", _hoisted_4$2, toDisplayString(__props.title), 1)) : createCommentVNode("", true)
|
|
122
149
|
], true)
|
|
123
|
-
])
|
|
124
|
-
_ctx.$slots["header-right"] || __props.extra ? (openBlock(), createElementBlock("view",
|
|
150
|
+
]),
|
|
151
|
+
_ctx.$slots["header-right"] || __props.extra ? (openBlock(), createElementBlock("view", _hoisted_5$1, [
|
|
125
152
|
renderSlot(_ctx.$slots, "header-right", {}, () => [
|
|
126
|
-
__props.extra ? (openBlock(), createElementBlock("text",
|
|
153
|
+
__props.extra ? (openBlock(), createElementBlock("text", _hoisted_6$1, toDisplayString(__props.extra), 1)) : createCommentVNode("", true)
|
|
127
154
|
], true)
|
|
128
155
|
])) : createCommentVNode("", true)
|
|
129
156
|
])
|
|
130
157
|
], true)
|
|
131
158
|
])) : createCommentVNode("", true),
|
|
132
|
-
|
|
159
|
+
showDivider.value ? (openBlock(), createElementBlock("view", _hoisted_7$1)) : createCommentVNode("", true),
|
|
160
|
+
createElementVNode("view", {
|
|
161
|
+
class: normalizeClass(["hlw-card-body", { "hlw-card-body--padded": __props.padding }])
|
|
162
|
+
}, [
|
|
133
163
|
renderSlot(_ctx.$slots, "default", {}, void 0, true)
|
|
134
|
-
])
|
|
135
|
-
|
|
164
|
+
], 2),
|
|
165
|
+
hasFooter.value ? (openBlock(), createElementBlock("view", _hoisted_8$1, [
|
|
166
|
+
renderSlot(_ctx.$slots, "footer", {}, () => [
|
|
167
|
+
createElementVNode("view", _hoisted_9$1, [
|
|
168
|
+
createElementVNode("view", _hoisted_10$1, [
|
|
169
|
+
renderSlot(_ctx.$slots, "footer-left", {}, void 0, true)
|
|
170
|
+
]),
|
|
171
|
+
_ctx.$slots["footer-right"] ? (openBlock(), createElementBlock("view", _hoisted_11$1, [
|
|
172
|
+
renderSlot(_ctx.$slots, "footer-right", {}, void 0, true)
|
|
173
|
+
])) : createCommentVNode("", true)
|
|
174
|
+
])
|
|
175
|
+
], true)
|
|
176
|
+
])) : createCommentVNode("", true)
|
|
177
|
+
], 2);
|
|
136
178
|
};
|
|
137
179
|
}
|
|
138
180
|
});
|
|
139
|
-
const index$5 = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__scopeId", "data-v-
|
|
181
|
+
const index$5 = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__scopeId", "data-v-cf55252e"]]);
|
|
140
182
|
const _hoisted_1$4 = { class: "hlw-empty" };
|
|
141
183
|
const _hoisted_2$4 = ["src"];
|
|
142
184
|
const _hoisted_3$2 = {
|
|
@@ -520,46 +562,162 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
520
562
|
}
|
|
521
563
|
});
|
|
522
564
|
const index = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-d8833363"]]);
|
|
565
|
+
function varsToStyle(vars) {
|
|
566
|
+
return Object.entries(vars).map(([k, v]) => `${k}:${v}`).join(";") + ";";
|
|
567
|
+
}
|
|
568
|
+
function hexToRgba(hex, alpha) {
|
|
569
|
+
const r = parseInt(hex.slice(1, 3), 16);
|
|
570
|
+
const g = parseInt(hex.slice(3, 5), 16);
|
|
571
|
+
const b = parseInt(hex.slice(5, 7), 16);
|
|
572
|
+
return `rgba(${r},${g},${b},${alpha})`;
|
|
573
|
+
}
|
|
574
|
+
function darkenHex(hex, amount = 0.15) {
|
|
575
|
+
const r = Math.max(0, Math.round(parseInt(hex.slice(1, 3), 16) * (1 - amount)));
|
|
576
|
+
const g = Math.max(0, Math.round(parseInt(hex.slice(3, 5), 16) * (1 - amount)));
|
|
577
|
+
const b = Math.max(0, Math.round(parseInt(hex.slice(5, 7), 16) * (1 - amount)));
|
|
578
|
+
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
|
|
579
|
+
}
|
|
523
580
|
const FONT_SCALE_KEY = "hlw_font_scale";
|
|
524
|
-
const
|
|
581
|
+
const THEME_COLOR_KEY = "hlw_theme_color";
|
|
582
|
+
const THEME_CHANGE_EVENT = "hlw:theme-change";
|
|
525
583
|
const FONT_PRESETS = {
|
|
584
|
+
small: {
|
|
585
|
+
label: "小字体",
|
|
586
|
+
vars: {
|
|
587
|
+
"--font-xs": "16rpx",
|
|
588
|
+
"--font-sm": "20rpx",
|
|
589
|
+
"--font-base": "24rpx",
|
|
590
|
+
"--font-md": "28rpx",
|
|
591
|
+
"--font-lg": "32rpx",
|
|
592
|
+
"--font-xl": "36rpx"
|
|
593
|
+
}
|
|
594
|
+
},
|
|
526
595
|
normal: {
|
|
527
596
|
label: "标准",
|
|
528
|
-
|
|
597
|
+
vars: {
|
|
598
|
+
"--font-xs": "20rpx",
|
|
599
|
+
"--font-sm": "24rpx",
|
|
600
|
+
"--font-base": "28rpx",
|
|
601
|
+
"--font-md": "32rpx",
|
|
602
|
+
"--font-lg": "36rpx",
|
|
603
|
+
"--font-xl": "40rpx"
|
|
604
|
+
}
|
|
529
605
|
},
|
|
530
606
|
large: {
|
|
531
607
|
label: "大字体",
|
|
532
|
-
|
|
608
|
+
vars: {
|
|
609
|
+
"--font-xs": "24rpx",
|
|
610
|
+
"--font-sm": "30rpx",
|
|
611
|
+
"--font-base": "34rpx",
|
|
612
|
+
"--font-md": "40rpx",
|
|
613
|
+
"--font-lg": "46rpx",
|
|
614
|
+
"--font-xl": "52rpx"
|
|
615
|
+
}
|
|
533
616
|
},
|
|
534
617
|
xlarge: {
|
|
535
618
|
label: "超大字体",
|
|
536
|
-
|
|
619
|
+
vars: {
|
|
620
|
+
"--font-xs": "28rpx",
|
|
621
|
+
"--font-sm": "36rpx",
|
|
622
|
+
"--font-base": "42rpx",
|
|
623
|
+
"--font-md": "48rpx",
|
|
624
|
+
"--font-lg": "56rpx",
|
|
625
|
+
"--font-xl": "64rpx"
|
|
626
|
+
}
|
|
537
627
|
}
|
|
538
628
|
};
|
|
539
629
|
function getCurrentFontScale() {
|
|
540
630
|
try {
|
|
541
631
|
const v = uni.getStorageSync(FONT_SCALE_KEY);
|
|
542
|
-
if (v === "large" || v === "xlarge")
|
|
632
|
+
if (v === "small" || v === "large" || v === "xlarge")
|
|
543
633
|
return v;
|
|
544
634
|
} catch {
|
|
545
635
|
}
|
|
546
636
|
return "normal";
|
|
547
637
|
}
|
|
548
|
-
function
|
|
549
|
-
return FONT_PRESETS[getCurrentFontScale()].
|
|
638
|
+
function getCurrentFontVars() {
|
|
639
|
+
return FONT_PRESETS[getCurrentFontScale()].vars;
|
|
550
640
|
}
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
641
|
+
const DEFAULT_THEMES = [
|
|
642
|
+
{ label: "默认蓝", value: "#3b82f6" },
|
|
643
|
+
{ label: "活力橙", value: "#f97316" },
|
|
644
|
+
{ label: "翡翠绿", value: "#10b981" },
|
|
645
|
+
{ label: "玫瑰红", value: "#f43f5e" },
|
|
646
|
+
{ label: "紫罗兰", value: "#8b5cf6" },
|
|
647
|
+
{ label: "青石灰", value: "#64748b" }
|
|
648
|
+
];
|
|
649
|
+
function getCurrentThemeColor() {
|
|
650
|
+
try {
|
|
651
|
+
const v = uni.getStorageSync(THEME_COLOR_KEY);
|
|
652
|
+
if (v && typeof v === "string")
|
|
653
|
+
return v;
|
|
654
|
+
} catch {
|
|
655
|
+
}
|
|
656
|
+
return DEFAULT_THEMES[0].value;
|
|
657
|
+
}
|
|
658
|
+
function getCurrentThemeVars() {
|
|
659
|
+
const color = getCurrentThemeColor();
|
|
660
|
+
return {
|
|
661
|
+
"--primary-color": color,
|
|
662
|
+
"--primary-light": hexToRgba(color, 0.12),
|
|
663
|
+
"--primary-dark": darkenHex(color)
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
function buildThemeStyle() {
|
|
667
|
+
return varsToStyle({
|
|
668
|
+
...getCurrentFontVars(),
|
|
669
|
+
...getCurrentThemeVars()
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
function useThemePageStyle() {
|
|
673
|
+
const themePageStyle = ref(buildThemeStyle());
|
|
674
|
+
const onThemeChange = () => {
|
|
675
|
+
themePageStyle.value = buildThemeStyle();
|
|
555
676
|
};
|
|
556
|
-
onMounted(() => uni.$on(
|
|
557
|
-
onUnmounted(() => uni.$off(
|
|
558
|
-
return {
|
|
677
|
+
onMounted(() => uni.$on(THEME_CHANGE_EVENT, onThemeChange));
|
|
678
|
+
onUnmounted(() => uni.$off(THEME_CHANGE_EVENT, onThemeChange));
|
|
679
|
+
return { themePageStyle };
|
|
559
680
|
}
|
|
681
|
+
const useThemeStore = defineStore(
|
|
682
|
+
"theme",
|
|
683
|
+
() => {
|
|
684
|
+
const scale = ref("normal");
|
|
685
|
+
function setScale(s) {
|
|
686
|
+
scale.value = s;
|
|
687
|
+
uni.setStorageSync(FONT_SCALE_KEY, s);
|
|
688
|
+
uni.$emit(THEME_CHANGE_EVENT);
|
|
689
|
+
}
|
|
690
|
+
const fontOptions = Object.keys(FONT_PRESETS).map((key) => ({
|
|
691
|
+
value: key,
|
|
692
|
+
label: FONT_PRESETS[key].label
|
|
693
|
+
}));
|
|
694
|
+
const primaryColor = ref(DEFAULT_THEMES[0].value);
|
|
695
|
+
const themes = DEFAULT_THEMES;
|
|
696
|
+
const activeTheme = computed(
|
|
697
|
+
() => themes.find((t) => t.value === primaryColor.value) ?? { label: "自定义", value: primaryColor.value }
|
|
698
|
+
);
|
|
699
|
+
function setTheme(color) {
|
|
700
|
+
primaryColor.value = color;
|
|
701
|
+
uni.setStorageSync(THEME_COLOR_KEY, color);
|
|
702
|
+
uni.$emit(THEME_CHANGE_EVENT);
|
|
703
|
+
}
|
|
704
|
+
return {
|
|
705
|
+
// 字体
|
|
706
|
+
scale,
|
|
707
|
+
fontOptions,
|
|
708
|
+
setScale,
|
|
709
|
+
// 主题色
|
|
710
|
+
primaryColor,
|
|
711
|
+
themes,
|
|
712
|
+
activeTheme,
|
|
713
|
+
setTheme
|
|
714
|
+
};
|
|
715
|
+
},
|
|
716
|
+
{ unistorage: true }
|
|
717
|
+
);
|
|
560
718
|
export {
|
|
719
|
+
DEFAULT_THEMES,
|
|
561
720
|
FONT_PRESETS,
|
|
562
|
-
FONT_SCALE_EVENT,
|
|
563
721
|
FONT_SCALE_KEY,
|
|
564
722
|
_sfc_main$7 as HlwAd,
|
|
565
723
|
index$6 as HlwAvatar,
|
|
@@ -569,7 +727,13 @@ export {
|
|
|
569
727
|
index$2 as HlwLoading,
|
|
570
728
|
index$1 as HlwMenu,
|
|
571
729
|
index as HlwPage,
|
|
730
|
+
THEME_CHANGE_EVENT,
|
|
731
|
+
THEME_COLOR_KEY,
|
|
732
|
+
buildThemeStyle,
|
|
572
733
|
getCurrentFontScale,
|
|
573
|
-
|
|
574
|
-
|
|
734
|
+
getCurrentFontVars,
|
|
735
|
+
getCurrentThemeColor,
|
|
736
|
+
getCurrentThemeVars,
|
|
737
|
+
useThemePageStyle,
|
|
738
|
+
useThemeStore
|
|
575
739
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const useThemeStore: any;
|
package/dist/style.css
CHANGED
|
@@ -33,10 +33,95 @@
|
|
|
33
33
|
.hlw-avatar--large .hlw-avatar__initial[data-v-89dcbc96] { font-size: var(--font-xl, 40rpx);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
.hlw-card[data-v-
|
|
37
|
-
|
|
36
|
+
.hlw-card[data-v-cf55252e] {
|
|
37
|
+
width: 100%;
|
|
38
|
+
background: #fff;
|
|
39
|
+
overflow: hidden;
|
|
40
|
+
/* 圆角档位 */
|
|
41
|
+
}
|
|
42
|
+
.hlw-card--radius-none[data-v-cf55252e] {
|
|
43
|
+
border-radius: 0;
|
|
44
|
+
}
|
|
45
|
+
.hlw-card--radius-sm[data-v-cf55252e] {
|
|
46
|
+
border-radius: var(--radius-sm, 8rpx);
|
|
47
|
+
}
|
|
48
|
+
.hlw-card--radius-md[data-v-cf55252e] {
|
|
49
|
+
border-radius: var(--radius-md, 16rpx);
|
|
50
|
+
}
|
|
51
|
+
.hlw-card--radius-lg[data-v-cf55252e] {
|
|
52
|
+
border-radius: var(--radius-lg, 24rpx);
|
|
53
|
+
}
|
|
54
|
+
.hlw-card--radius-xl[data-v-cf55252e] {
|
|
55
|
+
border-radius: var(--radius-xl, 32rpx);
|
|
56
|
+
}
|
|
57
|
+
.hlw-card[data-v-cf55252e] {
|
|
58
|
+
/* 边框 */
|
|
59
|
+
}
|
|
60
|
+
.hlw-card--bordered[data-v-cf55252e] {
|
|
61
|
+
border: 1rpx solid var(--border-color, #e2e8f0);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* 头部 */
|
|
65
|
+
.hlw-card-header[data-v-cf55252e] {
|
|
66
|
+
width: 100%;
|
|
67
|
+
}
|
|
68
|
+
.hlw-card-header-inner[data-v-cf55252e] {
|
|
69
|
+
display: flex;
|
|
70
|
+
align-items: center;
|
|
71
|
+
justify-content: space-between;
|
|
72
|
+
padding: 24rpx 28rpx;
|
|
73
|
+
}
|
|
74
|
+
.hlw-card-header-left[data-v-cf55252e] {
|
|
75
|
+
flex: 1;
|
|
76
|
+
min-width: 0;
|
|
77
|
+
}
|
|
78
|
+
.hlw-card-header-right[data-v-cf55252e] {
|
|
79
|
+
flex-shrink: 0;
|
|
80
|
+
margin-left: 16rpx;
|
|
81
|
+
}
|
|
82
|
+
.hlw-card-title[data-v-cf55252e] {
|
|
83
|
+
font-size: var(--font-sm, 24rpx);
|
|
84
|
+
font-weight: 700;
|
|
85
|
+
color: #1e293b;
|
|
86
|
+
letter-spacing: 0.02em;
|
|
87
|
+
}
|
|
88
|
+
.hlw-card-extra[data-v-cf55252e] {
|
|
89
|
+
font-size: var(--font-xs, 20rpx);
|
|
90
|
+
color: #94a3b8;
|
|
38
91
|
}
|
|
39
92
|
|
|
93
|
+
/* 虚线分隔 */
|
|
94
|
+
.hlw-card-divider[data-v-cf55252e] {
|
|
95
|
+
width: 100%;
|
|
96
|
+
border-bottom: 1rpx dashed var(--border-color, #e2e8f0);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* 内容区 */
|
|
100
|
+
.hlw-card-body[data-v-cf55252e] {
|
|
101
|
+
width: 100%;
|
|
102
|
+
}
|
|
103
|
+
.hlw-card-body--padded[data-v-cf55252e] {
|
|
104
|
+
padding: 24rpx 28rpx;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/* 底部 */
|
|
108
|
+
.hlw-card-footer[data-v-cf55252e] {
|
|
109
|
+
width: 100%;
|
|
110
|
+
border-top: 1rpx solid var(--border-color-light, #f1f5f9);
|
|
111
|
+
}
|
|
112
|
+
.hlw-card-footer-inner[data-v-cf55252e] {
|
|
113
|
+
display: flex;
|
|
114
|
+
align-items: center;
|
|
115
|
+
padding: 20rpx 28rpx;
|
|
116
|
+
}
|
|
117
|
+
.hlw-card-footer-left[data-v-cf55252e] {
|
|
118
|
+
flex: 1;
|
|
119
|
+
min-width: 0;
|
|
120
|
+
}
|
|
121
|
+
.hlw-card-footer-right[data-v-cf55252e] {
|
|
122
|
+
flex-shrink: 0;
|
|
123
|
+
margin-left: 16rpx;
|
|
124
|
+
}
|
|
40
125
|
.hlw-empty[data-v-08b8d8fe] {
|
|
41
126
|
display: flex;
|
|
42
127
|
flex-direction: column;
|
package/package.json
CHANGED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { ref, onMounted, onUnmounted } from "vue";
|
|
2
|
+
|
|
3
|
+
// ─── 工具函数 ───────────────────────────────────
|
|
4
|
+
|
|
5
|
+
function varsToStyle(vars: Record<string, string>): string {
|
|
6
|
+
return Object.entries(vars).map(([k, v]) => `${k}:${v}`).join(";") + ";";
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function hexToRgba(hex: string, alpha: number): string {
|
|
10
|
+
const r = parseInt(hex.slice(1, 3), 16);
|
|
11
|
+
const g = parseInt(hex.slice(3, 5), 16);
|
|
12
|
+
const b = parseInt(hex.slice(5, 7), 16);
|
|
13
|
+
return `rgba(${r},${g},${b},${alpha})`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function darkenHex(hex: string, amount = 0.15): string {
|
|
17
|
+
const r = Math.max(0, Math.round(parseInt(hex.slice(1, 3), 16) * (1 - amount)));
|
|
18
|
+
const g = Math.max(0, Math.round(parseInt(hex.slice(3, 5), 16) * (1 - amount)));
|
|
19
|
+
const b = Math.max(0, Math.round(parseInt(hex.slice(5, 7), 16) * (1 - amount)));
|
|
20
|
+
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// ─── 类型 ──────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
export type FontScale = "small" | "normal" | "large" | "xlarge";
|
|
26
|
+
|
|
27
|
+
export interface FontPreset {
|
|
28
|
+
label: string;
|
|
29
|
+
vars: Record<string, string>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface ThemeColor {
|
|
33
|
+
label: string;
|
|
34
|
+
value: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// ─── 存储 Key ──────────────────────────────────
|
|
38
|
+
|
|
39
|
+
export const FONT_SCALE_KEY = "hlw_font_scale";
|
|
40
|
+
export const THEME_COLOR_KEY = "hlw_theme_color";
|
|
41
|
+
|
|
42
|
+
// ─── 事件 ──────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
export const THEME_CHANGE_EVENT = "hlw:theme-change";
|
|
45
|
+
|
|
46
|
+
// ─── 字体档位 ──────────────────────────────────
|
|
47
|
+
|
|
48
|
+
export const FONT_PRESETS: Record<FontScale, FontPreset> = {
|
|
49
|
+
small: {
|
|
50
|
+
label: "小字体",
|
|
51
|
+
vars: {
|
|
52
|
+
"--font-xs": "16rpx", "--font-sm": "20rpx", "--font-base": "24rpx",
|
|
53
|
+
"--font-md": "28rpx", "--font-lg": "32rpx", "--font-xl": "36rpx",
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
normal: {
|
|
57
|
+
label: "标准",
|
|
58
|
+
vars: {
|
|
59
|
+
"--font-xs": "20rpx", "--font-sm": "24rpx", "--font-base": "28rpx",
|
|
60
|
+
"--font-md": "32rpx", "--font-lg": "36rpx", "--font-xl": "40rpx",
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
large: {
|
|
64
|
+
label: "大字体",
|
|
65
|
+
vars: {
|
|
66
|
+
"--font-xs": "24rpx", "--font-sm": "30rpx", "--font-base": "34rpx",
|
|
67
|
+
"--font-md": "40rpx", "--font-lg": "46rpx", "--font-xl": "52rpx",
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
xlarge: {
|
|
71
|
+
label: "超大字体",
|
|
72
|
+
vars: {
|
|
73
|
+
"--font-xs": "28rpx", "--font-sm": "36rpx", "--font-base": "42rpx",
|
|
74
|
+
"--font-md": "48rpx", "--font-lg": "56rpx", "--font-xl": "64rpx",
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export function getCurrentFontScale(): FontScale {
|
|
80
|
+
try {
|
|
81
|
+
const v = uni.getStorageSync(FONT_SCALE_KEY);
|
|
82
|
+
if (v === "small" || v === "large" || v === "xlarge") return v;
|
|
83
|
+
} catch {}
|
|
84
|
+
return "normal";
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function getCurrentFontVars(): Record<string, string> {
|
|
88
|
+
return FONT_PRESETS[getCurrentFontScale()].vars;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ─── 主题色 ────────────────────────────────────
|
|
92
|
+
|
|
93
|
+
export const DEFAULT_THEMES: ThemeColor[] = [
|
|
94
|
+
{ label: "默认蓝", value: "#3b82f6" },
|
|
95
|
+
{ label: "活力橙", value: "#f97316" },
|
|
96
|
+
{ label: "翡翠绿", value: "#10b981" },
|
|
97
|
+
{ label: "玫瑰红", value: "#f43f5e" },
|
|
98
|
+
{ label: "紫罗兰", value: "#8b5cf6" },
|
|
99
|
+
{ label: "青石灰", value: "#64748b" },
|
|
100
|
+
];
|
|
101
|
+
|
|
102
|
+
export function getCurrentThemeColor(): string {
|
|
103
|
+
try {
|
|
104
|
+
const v = uni.getStorageSync(THEME_COLOR_KEY);
|
|
105
|
+
if (v && typeof v === "string") return v;
|
|
106
|
+
} catch {}
|
|
107
|
+
return DEFAULT_THEMES[0].value;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function getCurrentThemeVars(): Record<string, string> {
|
|
111
|
+
const color = getCurrentThemeColor();
|
|
112
|
+
return {
|
|
113
|
+
"--primary-color": color,
|
|
114
|
+
"--primary-light": hexToRgba(color, 0.12),
|
|
115
|
+
"--primary-dark": darkenHex(color),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ─── 统一样式构建 ──────────────────────────────
|
|
120
|
+
// 后续新增主题维度时,只需添加 getCurrentXxxVars() 并在此展开
|
|
121
|
+
|
|
122
|
+
export function buildThemeStyle(): string {
|
|
123
|
+
return varsToStyle({
|
|
124
|
+
...getCurrentFontVars(),
|
|
125
|
+
...getCurrentThemeVars(),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ─── 组合式函数 ────────────────────────────────
|
|
130
|
+
|
|
131
|
+
export function useThemePageStyle() {
|
|
132
|
+
const themePageStyle = ref(buildThemeStyle());
|
|
133
|
+
|
|
134
|
+
const onThemeChange = () => {
|
|
135
|
+
themePageStyle.value = buildThemeStyle();
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
onMounted(() => uni.$on(THEME_CHANGE_EVENT, onThemeChange));
|
|
139
|
+
onUnmounted(() => uni.$off(THEME_CHANGE_EVENT, onThemeChange));
|
|
140
|
+
|
|
141
|
+
return { themePageStyle };
|
|
142
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -11,6 +11,6 @@ export { default as HlwLoading } from "./components/hlw-loading/index.vue";
|
|
|
11
11
|
export { default as HlwMenu } from "./components/hlw-menu/index.vue";
|
|
12
12
|
export type { HlwMenuItem } from "./components/hlw-menu/types";
|
|
13
13
|
export { default as HlwPage } from "./components/hlw-page/index.vue";
|
|
14
|
-
export type { FontScale, FontPreset, ThemeColor } from "./composables/theme
|
|
15
|
-
export { FONT_PRESETS, FONT_SCALE_KEY, DEFAULT_THEMES, THEME_COLOR_KEY, THEME_CHANGE_EVENT, getCurrentFontScale,
|
|
14
|
+
export type { FontScale, FontPreset, ThemeColor } from "./composables/theme";
|
|
15
|
+
export { FONT_PRESETS, FONT_SCALE_KEY, DEFAULT_THEMES, THEME_COLOR_KEY, THEME_CHANGE_EVENT, getCurrentFontScale, getCurrentFontVars, getCurrentThemeColor, getCurrentThemeVars, buildThemeStyle, useThemePageStyle } from "./composables/theme";
|
|
16
16
|
export { useThemeStore } from "./stores/theme";
|
package/src/stores/theme.ts
CHANGED
|
@@ -10,8 +10,8 @@ import {
|
|
|
10
10
|
DEFAULT_THEMES,
|
|
11
11
|
THEME_COLOR_KEY,
|
|
12
12
|
THEME_CHANGE_EVENT,
|
|
13
|
-
} from "../composables/theme
|
|
14
|
-
import type { FontScale, ThemeColor } from "../composables/theme
|
|
13
|
+
} from "../composables/theme";
|
|
14
|
+
import type { FontScale, ThemeColor } from "../composables/theme";
|
|
15
15
|
|
|
16
16
|
export const useThemeStore = defineStore(
|
|
17
17
|
"theme",
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* hlw-page 字体档位预设
|
|
3
|
-
*
|
|
4
|
-
* 三档:标准 / 大字体 / 超大字体
|
|
5
|
-
* 通过 <page-meta page-style="..."> 注入到页面根节点,
|
|
6
|
-
* 覆盖 CSS 变量,所有使用 var(--font-*) 的组件自动跟随。
|
|
7
|
-
*/
|
|
8
|
-
export type FontScale = "normal" | "large" | "xlarge";
|
|
9
|
-
/** storage key,与 qz2 font store 保持一致 */
|
|
10
|
-
export declare const FONT_SCALE_KEY = "hlw_font_scale";
|
|
11
|
-
/** 全局事件名,store.setScale 触发后 hlw-page 实时响应 */
|
|
12
|
-
export declare const FONT_SCALE_EVENT = "hlw:font-scale-change";
|
|
13
|
-
export interface FontPreset {
|
|
14
|
-
/** 展示名称 */
|
|
15
|
-
label: string;
|
|
16
|
-
/** 注入到 page-meta 的 CSS 变量字符串 */
|
|
17
|
-
style: string;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* 三档字体预设
|
|
21
|
-
*
|
|
22
|
-
* 变量说明:
|
|
23
|
-
* --font-xs 极小文字(角标、辅助标注)
|
|
24
|
-
* --font-sm 小文字(次要说明、标签、grid-label)
|
|
25
|
-
* --font-base 正文(菜单项、内容主体)
|
|
26
|
-
* --font-md 中等(次级标题)
|
|
27
|
-
* --font-lg 大号(页面标题、导航标题)
|
|
28
|
-
* --font-xl 特大(数字展示)
|
|
29
|
-
*/
|
|
30
|
-
export declare const FONT_PRESETS: Record<FontScale, FontPreset>;
|
|
31
|
-
/** 读取当前档位(同步,从 storage 取) */
|
|
32
|
-
export declare function getCurrentFontScale(): FontScale;
|
|
33
|
-
/** 读取当前档位对应的 page-style 字符串 */
|
|
34
|
-
export declare function getCurrentFontStyle(): string;
|
|
35
|
-
/**
|
|
36
|
-
* 在页面根节点使用,配合 <page-meta :page-style="fontPageStyle"> 实现全局字体缩放。
|
|
37
|
-
*
|
|
38
|
-
* 注意:<page-meta> 必须作为页面 .vue 文件 template 的第一个根节点,不可放在子组件内。
|
|
39
|
-
*
|
|
40
|
-
* @example
|
|
41
|
-
* ```vue
|
|
42
|
-
* <template>
|
|
43
|
-
* <page-meta :page-style="fontPageStyle" />
|
|
44
|
-
* <hlw-page title="xxx">...</hlw-page>
|
|
45
|
-
* </template>
|
|
46
|
-
* <script setup>
|
|
47
|
-
* import { useFontPageStyle } from '@hlw-uni/mp-vue';
|
|
48
|
-
* const { fontPageStyle } = useFontPageStyle();
|
|
49
|
-
* </script>
|
|
50
|
-
* ```
|
|
51
|
-
*/
|
|
52
|
-
export declare function useFontPageStyle(): {
|
|
53
|
-
fontPageStyle: any;
|
|
54
|
-
};
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { ref, computed, onMounted, onUnmounted } from "vue";
|
|
2
|
-
|
|
3
|
-
// ─── 字体档位 ────────────────────────────────────────
|
|
4
|
-
|
|
5
|
-
export type FontScale = "small" | "normal" | "large" | "xlarge";
|
|
6
|
-
|
|
7
|
-
export const FONT_SCALE_KEY = "hlw_font_scale";
|
|
8
|
-
|
|
9
|
-
export interface FontPreset {
|
|
10
|
-
label: string;
|
|
11
|
-
style: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const FONT_PRESETS: Record<FontScale, FontPreset> = {
|
|
15
|
-
small: {
|
|
16
|
-
label: "小字体",
|
|
17
|
-
style: "--font-xs:16rpx;--font-sm:20rpx;--font-base:24rpx;--font-md:28rpx;--font-lg:32rpx;--font-xl:36rpx;",
|
|
18
|
-
},
|
|
19
|
-
normal: {
|
|
20
|
-
label: "标准",
|
|
21
|
-
style: "--font-xs:20rpx;--font-sm:24rpx;--font-base:28rpx;--font-md:32rpx;--font-lg:36rpx;--font-xl:40rpx;",
|
|
22
|
-
},
|
|
23
|
-
large: {
|
|
24
|
-
label: "大字体",
|
|
25
|
-
style: "--font-xs:24rpx;--font-sm:30rpx;--font-base:34rpx;--font-md:40rpx;--font-lg:46rpx;--font-xl:52rpx;",
|
|
26
|
-
},
|
|
27
|
-
xlarge: {
|
|
28
|
-
label: "超大字体",
|
|
29
|
-
style: "--font-xs:28rpx;--font-sm:36rpx;--font-base:42rpx;--font-md:48rpx;--font-lg:56rpx;--font-xl:64rpx;",
|
|
30
|
-
},
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export function getCurrentFontScale(): FontScale {
|
|
34
|
-
try {
|
|
35
|
-
const v = uni.getStorageSync(FONT_SCALE_KEY);
|
|
36
|
-
if (v === "small" || v === "large" || v === "xlarge") return v;
|
|
37
|
-
} catch {}
|
|
38
|
-
return "normal";
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function getCurrentFontStyle(): string {
|
|
42
|
-
return FONT_PRESETS[getCurrentFontScale()].style;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// ─── 主题色 ──────────────────────────────────────────
|
|
46
|
-
|
|
47
|
-
export interface ThemeColor {
|
|
48
|
-
label: string;
|
|
49
|
-
value: string;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export const THEME_COLOR_KEY = "hlw_theme_color";
|
|
53
|
-
|
|
54
|
-
/** 内置预设主题色 */
|
|
55
|
-
export const DEFAULT_THEMES: ThemeColor[] = [
|
|
56
|
-
{ label: "默认蓝", value: "#3b82f6" },
|
|
57
|
-
{ label: "活力橙", value: "#f97316" },
|
|
58
|
-
{ label: "翡翠绿", value: "#10b981" },
|
|
59
|
-
{ label: "玫瑰红", value: "#f43f5e" },
|
|
60
|
-
{ label: "紫罗兰", value: "#8b5cf6" },
|
|
61
|
-
{ label: "青石灰", value: "#64748b" },
|
|
62
|
-
];
|
|
63
|
-
|
|
64
|
-
export function getCurrentThemeColor(): string {
|
|
65
|
-
try {
|
|
66
|
-
const v = uni.getStorageSync(THEME_COLOR_KEY);
|
|
67
|
-
if (v && typeof v === "string") return v;
|
|
68
|
-
} catch {}
|
|
69
|
-
return DEFAULT_THEMES[0].value;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export function getCurrentThemeStyle(): string {
|
|
73
|
-
return `--primary-color:${getCurrentThemeColor()};`;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// ─── 统一事件 ────────────────────────────────────────
|
|
77
|
-
|
|
78
|
-
/** 字体 / 主题色变更时统一广播此事件 */
|
|
79
|
-
export const THEME_CHANGE_EVENT = "hlw:theme-change";
|
|
80
|
-
|
|
81
|
-
// ─── 组合式函数 ──────────────────────────────────────
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* 在页面中使用,配合 <page-meta :page-style="themePageStyle"> 注入字体 + 主题色。
|
|
85
|
-
*
|
|
86
|
-
* @example
|
|
87
|
-
* ```vue
|
|
88
|
-
* <template>
|
|
89
|
-
* <page-meta :page-style="themePageStyle" />
|
|
90
|
-
* <hlw-page title="xxx">...</hlw-page>
|
|
91
|
-
* </template>
|
|
92
|
-
* <script setup>
|
|
93
|
-
* import { useThemePageStyle } from '@hlw-uni/mp-vue';
|
|
94
|
-
* const { themePageStyle } = useThemePageStyle();
|
|
95
|
-
* </script>
|
|
96
|
-
* ```
|
|
97
|
-
*/
|
|
98
|
-
export function useThemePageStyle() {
|
|
99
|
-
const themePageStyle = ref(getCurrentFontStyle() + getCurrentThemeStyle());
|
|
100
|
-
|
|
101
|
-
const onThemeChange = () => {
|
|
102
|
-
themePageStyle.value = getCurrentFontStyle() + getCurrentThemeStyle();
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
onMounted(() => uni.$on(THEME_CHANGE_EVENT, onThemeChange));
|
|
106
|
-
onUnmounted(() => uni.$off(THEME_CHANGE_EVENT, onThemeChange));
|
|
107
|
-
|
|
108
|
-
return { themePageStyle };
|
|
109
|
-
}
|