ph-utils 0.17.2 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/lib/dom.d.ts +125 -25
- package/lib/dom.js +40 -6
- package/lib/src/array.d.ts +79 -0
- package/lib/src/array.js +212 -0
- package/lib/src/color.d.ts +55 -0
- package/lib/src/color.js +294 -0
- package/lib/src/config.d.ts +33 -0
- package/lib/src/config.js +99 -0
- package/lib/src/copy.d.ts +11 -0
- package/lib/src/copy.js +101 -0
- package/lib/src/crypto.d.ts +74 -0
- package/lib/src/crypto.js +261 -0
- package/lib/src/crypto_node.d.ts +61 -0
- package/lib/src/crypto_node.js +133 -0
- package/lib/src/date.d.ts +66 -0
- package/lib/src/date.js +202 -0
- package/lib/src/dom.d.ts +265 -0
- package/lib/src/dom.js +635 -0
- package/lib/src/file.d.ts +29 -0
- package/lib/src/file.js +54 -0
- package/lib/src/id.d.ts +68 -0
- package/lib/src/id.js +170 -0
- package/lib/src/index.d.ts +154 -0
- package/lib/src/index.js +239 -0
- package/lib/src/logger.d.ts +62 -0
- package/lib/src/logger.js +122 -0
- package/lib/src/server.d.ts +33 -0
- package/lib/src/server.js +65 -0
- package/lib/src/storage.d.ts +51 -0
- package/lib/src/storage.js +73 -0
- package/lib/src/theme.d.ts +44 -0
- package/lib/src/theme.js +156 -0
- package/lib/src/validator.d.ts +71 -0
- package/lib/src/validator.js +238 -0
- package/lib/src/web.d.ts +30 -0
- package/lib/src/web.js +100 -0
- package/package.json +2 -2
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
type LoggerLevel = "debug" | "info" | "warn" | "error" | "fatal";
|
|
2
|
+
/** 日志消息类型 */
|
|
3
|
+
type MessageIntf = number | string | boolean | object | any[] | Error;
|
|
4
|
+
/** 日志消息选项 */
|
|
5
|
+
type MessageOption = {
|
|
6
|
+
/** 日志名称 */
|
|
7
|
+
name?: string;
|
|
8
|
+
/** 日志级别 */
|
|
9
|
+
level?: LoggerLevel;
|
|
10
|
+
/** 日志消息 */
|
|
11
|
+
message: MessageIntf;
|
|
12
|
+
/** 当前消息是否美化输出 */
|
|
13
|
+
pretty?: boolean;
|
|
14
|
+
/** 如果消息是 JSON 格式, 转换为字符串时, 是否格式化 JSON */
|
|
15
|
+
jsonSpace?: number;
|
|
16
|
+
};
|
|
17
|
+
type LoggerOption = {
|
|
18
|
+
/** 记录的日志名称, 通常用于表明哪个页面 */
|
|
19
|
+
name?: string;
|
|
20
|
+
/** 记录日志级别, 通常上线时 error 或者禁用日志, 默认: debug */
|
|
21
|
+
level?: LoggerLevel;
|
|
22
|
+
/** 是否需要美化输出, 默认: true */
|
|
23
|
+
pretty?: boolean;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* 日志记录器
|
|
27
|
+
*/
|
|
28
|
+
export declare class Logger {
|
|
29
|
+
/** 日志级别 */
|
|
30
|
+
levels: string[];
|
|
31
|
+
colors: {
|
|
32
|
+
debug: string;
|
|
33
|
+
info: string;
|
|
34
|
+
warn: string;
|
|
35
|
+
error: string;
|
|
36
|
+
};
|
|
37
|
+
option: LoggerOption & {
|
|
38
|
+
levelNum: number;
|
|
39
|
+
};
|
|
40
|
+
/** 构造日志记录器 */
|
|
41
|
+
constructor(option?: LoggerOption);
|
|
42
|
+
setOption(option: LoggerOption): void;
|
|
43
|
+
log(message: MessageIntf | MessageOption): void;
|
|
44
|
+
info(message: MessageIntf | MessageOption): void;
|
|
45
|
+
debug(message: MessageIntf | MessageOption): void;
|
|
46
|
+
warn(message: MessageIntf | MessageOption): void;
|
|
47
|
+
error(message: MessageIntf | MessageOption): void;
|
|
48
|
+
fatal(message: MessageIntf | MessageOption): void;
|
|
49
|
+
getLevel(): string;
|
|
50
|
+
getName(): string | undefined;
|
|
51
|
+
getOption(): LoggerOption & {
|
|
52
|
+
levelNum: number;
|
|
53
|
+
};
|
|
54
|
+
private generateLog;
|
|
55
|
+
/** 格式化显示 */
|
|
56
|
+
private formatShow;
|
|
57
|
+
}
|
|
58
|
+
/** 默认日志记录器 */
|
|
59
|
+
export declare const logger: Logger;
|
|
60
|
+
/** 获取新的日志记录器, 属性采用之前的 */
|
|
61
|
+
export declare const getLogger: (option?: LoggerOption) => Logger;
|
|
62
|
+
export {};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { format } from "./date.js";
|
|
2
|
+
/**
|
|
3
|
+
* 日志记录器
|
|
4
|
+
*/
|
|
5
|
+
export class Logger {
|
|
6
|
+
/** 构造日志记录器 */
|
|
7
|
+
constructor(option) {
|
|
8
|
+
/** 日志级别 */
|
|
9
|
+
this.levels = ["debug", "info", "warn", "error", "fatal"];
|
|
10
|
+
this.colors = {
|
|
11
|
+
debug: "#909399",
|
|
12
|
+
info: "#1677ff",
|
|
13
|
+
warn: "#fadb14",
|
|
14
|
+
error: "#eb2f96",
|
|
15
|
+
};
|
|
16
|
+
this.setOption(option || {});
|
|
17
|
+
}
|
|
18
|
+
setOption(option) {
|
|
19
|
+
let opts = { level: "debug", levelNum: 0, pretty: true, ...option };
|
|
20
|
+
opts.levelNum = this.levels.indexOf(opts.level);
|
|
21
|
+
this.option = opts;
|
|
22
|
+
}
|
|
23
|
+
log(message) {
|
|
24
|
+
let msgInfo = {
|
|
25
|
+
name: this.option.name,
|
|
26
|
+
level: "info",
|
|
27
|
+
time: format(null, "yyyy-mm-dd HH:MM:ss.S"),
|
|
28
|
+
pretty: this.option.pretty,
|
|
29
|
+
jsonSpace: 0,
|
|
30
|
+
};
|
|
31
|
+
let msgContent = message;
|
|
32
|
+
if (typeof message === "object") {
|
|
33
|
+
if (message instanceof Error) {
|
|
34
|
+
msgInfo.level = "error";
|
|
35
|
+
msgContent = msgContent.stack;
|
|
36
|
+
}
|
|
37
|
+
else if (message.message != null) {
|
|
38
|
+
msgContent = message.message;
|
|
39
|
+
msgInfo = { ...msgInfo, ...message };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (typeof msgContent === "object") {
|
|
43
|
+
try {
|
|
44
|
+
msgInfo.message = JSON.stringify(msgContent, null, msgInfo.jsonSpace);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
msgInfo.message = msgContent.toString();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
msgInfo.message = msgContent;
|
|
52
|
+
}
|
|
53
|
+
if (msgInfo.pretty == null) {
|
|
54
|
+
msgInfo.pretty = this.option.pretty;
|
|
55
|
+
}
|
|
56
|
+
let levelIndex = this.levels.indexOf(msgInfo.level);
|
|
57
|
+
if (levelIndex >= this.option.levelNum) {
|
|
58
|
+
this.formatShow(msgInfo);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
info(message) {
|
|
62
|
+
this.log(this.generateLog(message, "info"));
|
|
63
|
+
}
|
|
64
|
+
debug(message) {
|
|
65
|
+
this.log(this.generateLog(message, "debug"));
|
|
66
|
+
}
|
|
67
|
+
warn(message) {
|
|
68
|
+
this.log(this.generateLog(message, "warn"));
|
|
69
|
+
}
|
|
70
|
+
error(message) {
|
|
71
|
+
this.log(this.generateLog(message, "error"));
|
|
72
|
+
}
|
|
73
|
+
fatal(message) {
|
|
74
|
+
this.log(this.generateLog(message, "fatal"));
|
|
75
|
+
}
|
|
76
|
+
getLevel() {
|
|
77
|
+
return this.levels[this.option.levelNum];
|
|
78
|
+
}
|
|
79
|
+
getName() {
|
|
80
|
+
return this.option.name;
|
|
81
|
+
}
|
|
82
|
+
getOption() {
|
|
83
|
+
return this.option;
|
|
84
|
+
}
|
|
85
|
+
generateLog(message, level = "info") {
|
|
86
|
+
let msgInfo = {
|
|
87
|
+
message: message,
|
|
88
|
+
};
|
|
89
|
+
if (typeof message === "object") {
|
|
90
|
+
if (message.message != null) {
|
|
91
|
+
msgInfo = message;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
msgInfo["level"] = level;
|
|
95
|
+
return msgInfo;
|
|
96
|
+
}
|
|
97
|
+
/** 格式化显示 */
|
|
98
|
+
formatShow(msg) {
|
|
99
|
+
if (msg.level === "fatal") {
|
|
100
|
+
msg.level = "error";
|
|
101
|
+
}
|
|
102
|
+
const res = [`[${msg.time}]`];
|
|
103
|
+
if (msg.name != null) {
|
|
104
|
+
res.push(`[${msg.name}]`);
|
|
105
|
+
}
|
|
106
|
+
res.push(`- ${msg.message}`);
|
|
107
|
+
if (!msg.pretty) {
|
|
108
|
+
res.splice(1, 0, `${msg.level.toUpperCase()}`);
|
|
109
|
+
console[msg.level](res.join(" "));
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
const color = this.colors[msg.level];
|
|
113
|
+
console.log(`%c ${`${msg.level.toUpperCase()}`} %c ${res.join(" ")} %c`, `background:${color};border:1px solid ${color}; padding: 1px; border-radius: 2px 0 0 2px; color: #fff;`, `border:1px solid ${color}; padding: 1px; border-radius: 0 2px 2px 0; color: ${color};`, "background:transparent");
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/** 默认日志记录器 */
|
|
118
|
+
export const logger = new Logger({ name: "APP" });
|
|
119
|
+
/** 获取新的日志记录器, 属性采用之前的 */
|
|
120
|
+
export const getLogger = (option) => {
|
|
121
|
+
return new Logger({ ...logger.getOption(), ...option });
|
|
122
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { SpawnOptionsWithoutStdio } from "node:child_process";
|
|
2
|
+
/**
|
|
3
|
+
* 执行命令
|
|
4
|
+
* @param command 待执行的命令
|
|
5
|
+
* @param args 命令参数
|
|
6
|
+
*/
|
|
7
|
+
export declare function exec(command: string, args?: string[]): Promise<{
|
|
8
|
+
stdout: string;
|
|
9
|
+
stderr: string;
|
|
10
|
+
}>;
|
|
11
|
+
export declare function exec(command: string, options?: SpawnOptions): Promise<{
|
|
12
|
+
stdout: string;
|
|
13
|
+
stderr: string;
|
|
14
|
+
}>;
|
|
15
|
+
export declare function exec(command: string, args?: string[], options?: SpawnOptions): Promise<{
|
|
16
|
+
stdout: string;
|
|
17
|
+
stderr: string;
|
|
18
|
+
}>;
|
|
19
|
+
type SpawnOptions = SpawnOptionsWithoutStdio & {
|
|
20
|
+
shell?: 'powershell';
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* 执行命令并返回执行结果的Promise
|
|
24
|
+
* @param command 要执行的命令
|
|
25
|
+
* @param args 命令参数数组
|
|
26
|
+
* @param options 执行选项,支持指定shell类型
|
|
27
|
+
* @returns Promise对象,成功时resolve包含stdout和stderr的对象,失败时reject包含错误信息
|
|
28
|
+
*/
|
|
29
|
+
export declare function spawn(command: string, args?: string[], options?: SpawnOptions): Promise<{
|
|
30
|
+
stdout: string;
|
|
31
|
+
stderr: string;
|
|
32
|
+
}>;
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { execFile, spawn as spawnOri } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
const execFilePromise = promisify(execFile);
|
|
4
|
+
/**
|
|
5
|
+
* 执行命令
|
|
6
|
+
* @param cmd 执行的命令
|
|
7
|
+
* @returns
|
|
8
|
+
*/
|
|
9
|
+
export function exec(command, ...params) {
|
|
10
|
+
let argvs = [];
|
|
11
|
+
const commandItems = command.split(" ");
|
|
12
|
+
const cmd = commandItems.shift();
|
|
13
|
+
if (commandItems.length > 0) {
|
|
14
|
+
argvs = commandItems;
|
|
15
|
+
}
|
|
16
|
+
let opts = { shell: true };
|
|
17
|
+
if (params[0] != null) {
|
|
18
|
+
if (params[0] instanceof Array) {
|
|
19
|
+
argvs.push(...params[0]);
|
|
20
|
+
if (params[1] != null) {
|
|
21
|
+
opts = params[1];
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
opts = params[0];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return execFilePromise(cmd, argvs, opts);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 执行命令并返回执行结果的Promise
|
|
32
|
+
* @param command 要执行的命令
|
|
33
|
+
* @param args 命令参数数组
|
|
34
|
+
* @param options 执行选项,支持指定shell类型
|
|
35
|
+
* @returns Promise对象,成功时resolve包含stdout和stderr的对象,失败时reject包含错误信息
|
|
36
|
+
*/
|
|
37
|
+
export function spawn(command, args, options = {}) {
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
let execArgs = [];
|
|
40
|
+
let cmd;
|
|
41
|
+
// 根据是否指定powershell shell来设置实际执行的命令和参数
|
|
42
|
+
if (options.shell === 'powershell') {
|
|
43
|
+
cmd = 'powershell.exe';
|
|
44
|
+
execArgs = ['-NoProfile', '-Command', command, ...(args || [])];
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
cmd = command;
|
|
48
|
+
execArgs = args || [];
|
|
49
|
+
}
|
|
50
|
+
delete options.shell;
|
|
51
|
+
const child = spawnOri(cmd, execArgs, options);
|
|
52
|
+
let stdout = '', stderr = '';
|
|
53
|
+
child.stdout.on('data', d => stdout += d);
|
|
54
|
+
child.stderr.on('data', d => stderr += d);
|
|
55
|
+
// 监听子进程关闭事件,根据退出码决定resolve或reject
|
|
56
|
+
child.on('close', code => {
|
|
57
|
+
if (code === 0)
|
|
58
|
+
resolve({ stdout, stderr });
|
|
59
|
+
else
|
|
60
|
+
reject(new Error(`spawn failed (${code}): ${stderr}`));
|
|
61
|
+
});
|
|
62
|
+
// 监听子进程错误事件,发生错误时直接reject
|
|
63
|
+
child.on('error', reject);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 缓存相关
|
|
3
|
+
*/
|
|
4
|
+
type StorageType = "session" | "local";
|
|
5
|
+
interface StorageSetOption {
|
|
6
|
+
storage?: StorageType;
|
|
7
|
+
/** 数据有效期, 单位秒, 默认: -1 - 永久存储 */
|
|
8
|
+
expire?: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* 存储值到 Storage 中
|
|
12
|
+
* @param key 设置的 key
|
|
13
|
+
* @param value 设置的值
|
|
14
|
+
* @param [option.storage] session 或 local, 默认: session
|
|
15
|
+
* @param [option.expire] 数据有效期, 单位秒, 默认: -1 - 永久存储
|
|
16
|
+
*
|
|
17
|
+
* @example <caption>1. 存储到 SessionStorage</caption>
|
|
18
|
+
* set("key", "value");
|
|
19
|
+
*
|
|
20
|
+
* @example <caption>2. 存储到 LocalStorage</caption>
|
|
21
|
+
* set("key", "value", { storage: "local" });
|
|
22
|
+
*/
|
|
23
|
+
export declare function set(key: string, value: any, option?: StorageSetOption): void;
|
|
24
|
+
/**
|
|
25
|
+
* 清空所有的缓存内容
|
|
26
|
+
* @param storage 待清空的缓存对象
|
|
27
|
+
*/
|
|
28
|
+
export declare function clear(storage?: StorageType): void;
|
|
29
|
+
/**
|
|
30
|
+
* 删除存储到 Storage 中的数据
|
|
31
|
+
* @param key
|
|
32
|
+
* @param storage
|
|
33
|
+
*/
|
|
34
|
+
export declare function remove(key: string, storage?: StorageType): void;
|
|
35
|
+
/** 从 Storage 中获取数据时的配置 */
|
|
36
|
+
interface StorageQueryOption {
|
|
37
|
+
/** 数据是否持久化, 默认为: false, 设置为 true 则会在每一次取出数据后删除 */
|
|
38
|
+
delete?: boolean;
|
|
39
|
+
/** 存储对象, session、local */
|
|
40
|
+
storage?: StorageType;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 从 Storage 中取出数据
|
|
44
|
+
* @param key 保存时的 key
|
|
45
|
+
* @param defaultValue 没有数据时的默认值
|
|
46
|
+
* @param [option.delete] 是否在取出后,删除数据,默认:false - 取出后删除数据
|
|
47
|
+
* @param [option.storage] 使用的 Storage ,可以是 localStorage、sessionStorage, 默认: localStorage、sessionStorage
|
|
48
|
+
* @returns Storage 中 key 对应的数据
|
|
49
|
+
*/
|
|
50
|
+
export declare function get<T>(key: string, defaultValue?: T, option?: StorageQueryOption): T;
|
|
51
|
+
export {};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
function getStorage(storage = "session") {
|
|
2
|
+
return storage === "session" ? sessionStorage : localStorage;
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* 存储值到 Storage 中
|
|
6
|
+
* @param key 设置的 key
|
|
7
|
+
* @param value 设置的值
|
|
8
|
+
* @param [option.storage] session 或 local, 默认: session
|
|
9
|
+
* @param [option.expire] 数据有效期, 单位秒, 默认: -1 - 永久存储
|
|
10
|
+
*
|
|
11
|
+
* @example <caption>1. 存储到 SessionStorage</caption>
|
|
12
|
+
* set("key", "value");
|
|
13
|
+
*
|
|
14
|
+
* @example <caption>2. 存储到 LocalStorage</caption>
|
|
15
|
+
* set("key", "value", { storage: "local" });
|
|
16
|
+
*/
|
|
17
|
+
export function set(key, value, option) {
|
|
18
|
+
const opts = {
|
|
19
|
+
expire: -1,
|
|
20
|
+
storage: "session",
|
|
21
|
+
...option,
|
|
22
|
+
};
|
|
23
|
+
const saveData = JSON.stringify({
|
|
24
|
+
value,
|
|
25
|
+
time: Date.now(),
|
|
26
|
+
expire: opts.expire === -1 ? -1 : Math.floor(Date.now() / 1000) + opts.expire,
|
|
27
|
+
});
|
|
28
|
+
getStorage(opts.storage).setItem(key, saveData);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 清空所有的缓存内容
|
|
32
|
+
* @param storage 待清空的缓存对象
|
|
33
|
+
*/
|
|
34
|
+
export function clear(storage) {
|
|
35
|
+
getStorage(storage).clear();
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 删除存储到 Storage 中的数据
|
|
39
|
+
* @param key
|
|
40
|
+
* @param storage
|
|
41
|
+
*/
|
|
42
|
+
export function remove(key, storage) {
|
|
43
|
+
getStorage(storage).removeItem(key);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 从 Storage 中取出数据
|
|
47
|
+
* @param key 保存时的 key
|
|
48
|
+
* @param defaultValue 没有数据时的默认值
|
|
49
|
+
* @param [option.delete] 是否在取出后,删除数据,默认:false - 取出后删除数据
|
|
50
|
+
* @param [option.storage] 使用的 Storage ,可以是 localStorage、sessionStorage, 默认: localStorage、sessionStorage
|
|
51
|
+
* @returns Storage 中 key 对应的数据
|
|
52
|
+
*/
|
|
53
|
+
export function get(key, defaultValue, option) {
|
|
54
|
+
const opts = (option || { delete: false });
|
|
55
|
+
const storage = getStorage(opts.storage);
|
|
56
|
+
let data = storage.getItem(key);
|
|
57
|
+
if (data == null) {
|
|
58
|
+
return defaultValue || null;
|
|
59
|
+
}
|
|
60
|
+
data = JSON.parse(data);
|
|
61
|
+
let d = data.value;
|
|
62
|
+
if (data.expire !== -1) {
|
|
63
|
+
// 数据过期
|
|
64
|
+
if (Math.floor(Date.now() / 1000) > data.expire) {
|
|
65
|
+
d = null;
|
|
66
|
+
storage.removeItem(key);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (opts.delete) {
|
|
70
|
+
storage.removeItem(key);
|
|
71
|
+
}
|
|
72
|
+
return d || defaultValue;
|
|
73
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/** 获取当前系统的主题 */
|
|
2
|
+
export declare function getSystemTheme(): "light" | "dark" | "auto";
|
|
3
|
+
/**
|
|
4
|
+
* 初始化主题, 让网页能够适应系统主题, 同时根据缓存的主题切换主题
|
|
5
|
+
* @returns 当前应用的主题
|
|
6
|
+
*/
|
|
7
|
+
export declare function initTheme(): Promise<"light" | "dark" | "auto">;
|
|
8
|
+
/**
|
|
9
|
+
* 切换主题, 通常用于预览
|
|
10
|
+
* @param theme 切换的主题
|
|
11
|
+
* @param transition 是否使用过渡动画, 注意浏览器必须支持 document.startViewTransition, 默认: true
|
|
12
|
+
* @returns 切换后的主题
|
|
13
|
+
*/
|
|
14
|
+
export declare function toggleTheme(theme?: "light" | "dark" | "auto", transition?: boolean): Promise<"light" | "dark" | "auto">;
|
|
15
|
+
/** 获取当前主题 */
|
|
16
|
+
export declare function getTheme(): string;
|
|
17
|
+
/**
|
|
18
|
+
* 应用主题
|
|
19
|
+
* @param theme 待应用的主题
|
|
20
|
+
* @param cache 是否缓存应用的主题, 让应用下一次启动的时候, 可以应用主题, 默认: true
|
|
21
|
+
* @param transition 是否使用过渡动画, 注意浏览器必须支持 document.startViewTransition, 默认: true
|
|
22
|
+
* @returns 应用的主题
|
|
23
|
+
*/
|
|
24
|
+
export declare function applyTheme(theme?: "light" | "dark" | "auto", cache?: boolean, transition?: boolean): Promise<"light" | "dark" | "auto">;
|
|
25
|
+
/** 获取当前主题色 */
|
|
26
|
+
export declare function getColorTheme(defaultValue?: string): string | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* 初始化主题色, 让网页能够适应系统主题色, 同时根据缓存的主题色切换主题色
|
|
29
|
+
* @returns 当前应用的主题色
|
|
30
|
+
*/
|
|
31
|
+
export declare function initColorTheme(): Promise<string> | null;
|
|
32
|
+
/**
|
|
33
|
+
* 切换主题色, 通常用于预览
|
|
34
|
+
* @param color 待切换的主题色
|
|
35
|
+
* @returns 切换后的主题色
|
|
36
|
+
*/
|
|
37
|
+
export declare function toggleColorTheme(color: string): Promise<string>;
|
|
38
|
+
/**
|
|
39
|
+
* 应用主题色
|
|
40
|
+
* @param color 主题色
|
|
41
|
+
* @param cache 是否缓存主题色, 让应用下一次启动的时候, 可以应用主题色, 默认: true
|
|
42
|
+
* @returns 切换后的主题色
|
|
43
|
+
*/
|
|
44
|
+
export declare function applyColorTheme(color: string, cache?: boolean): Promise<string>;
|
package/lib/src/theme.js
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { adjust } from "./color.js";
|
|
2
|
+
/** 获取当前系统的主题 */
|
|
3
|
+
export function getSystemTheme() {
|
|
4
|
+
if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
|
5
|
+
return "dark";
|
|
6
|
+
}
|
|
7
|
+
else if (window.matchMedia("(prefers-color-scheme: light)").matches) {
|
|
8
|
+
return "light";
|
|
9
|
+
}
|
|
10
|
+
return "auto";
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 初始化主题, 让网页能够适应系统主题, 同时根据缓存的主题切换主题
|
|
14
|
+
* @returns 当前应用的主题
|
|
15
|
+
*/
|
|
16
|
+
export async function initTheme() {
|
|
17
|
+
// 让网页能够适应系统主题
|
|
18
|
+
let $themeStyle = document.getElementById("theme-style");
|
|
19
|
+
if ($themeStyle == null) {
|
|
20
|
+
$themeStyle = document.createElement("style");
|
|
21
|
+
$themeStyle.id = "theme-style";
|
|
22
|
+
$themeStyle.innerHTML =
|
|
23
|
+
":root{color-scheme:light dark;}html.light{color-scheme: light;}html.dark {color-scheme: dark;}";
|
|
24
|
+
document.head.appendChild($themeStyle);
|
|
25
|
+
}
|
|
26
|
+
// 获取已经应用的主题设置
|
|
27
|
+
const cacheTheme = localStorage.getItem("web-theme-appearance");
|
|
28
|
+
return toggleTheme(cacheTheme);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 切换主题, 通常用于预览
|
|
32
|
+
* @param theme 切换的主题
|
|
33
|
+
* @param transition 是否使用过渡动画, 注意浏览器必须支持 document.startViewTransition, 默认: true
|
|
34
|
+
* @returns 切换后的主题
|
|
35
|
+
*/
|
|
36
|
+
export async function toggleTheme(theme, transition = true) {
|
|
37
|
+
return new Promise((resolve) => {
|
|
38
|
+
const classList = document.documentElement.classList;
|
|
39
|
+
if (theme == null) {
|
|
40
|
+
theme = getSystemTheme();
|
|
41
|
+
}
|
|
42
|
+
function updateThemeClass() {
|
|
43
|
+
if (theme === "light") {
|
|
44
|
+
classList.add("light");
|
|
45
|
+
classList.remove("dark");
|
|
46
|
+
}
|
|
47
|
+
else if (theme === "dark") {
|
|
48
|
+
classList.add("dark");
|
|
49
|
+
classList.remove("light");
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
classList.remove("light", "dark");
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// @ts-ignore
|
|
56
|
+
if (transition && document.startViewTransition) {
|
|
57
|
+
// @ts-ignore
|
|
58
|
+
document.startViewTransition(() => {
|
|
59
|
+
updateThemeClass();
|
|
60
|
+
resolve(theme);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
updateThemeClass();
|
|
65
|
+
resolve(theme);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/** 获取当前主题 */
|
|
70
|
+
export function getTheme() {
|
|
71
|
+
// 1. 从根节点获取
|
|
72
|
+
let theme = document.documentElement.className.match(/light|dark/);
|
|
73
|
+
if (theme != null) {
|
|
74
|
+
theme = theme[0];
|
|
75
|
+
}
|
|
76
|
+
if (theme == null) {
|
|
77
|
+
theme = localStorage.getItem("web-theme-appearance");
|
|
78
|
+
}
|
|
79
|
+
if (theme == null) {
|
|
80
|
+
theme = getSystemTheme();
|
|
81
|
+
}
|
|
82
|
+
return theme;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* 应用主题
|
|
86
|
+
* @param theme 待应用的主题
|
|
87
|
+
* @param cache 是否缓存应用的主题, 让应用下一次启动的时候, 可以应用主题, 默认: true
|
|
88
|
+
* @param transition 是否使用过渡动画, 注意浏览器必须支持 document.startViewTransition, 默认: true
|
|
89
|
+
* @returns 应用的主题
|
|
90
|
+
*/
|
|
91
|
+
export async function applyTheme(theme, cache = true, transition = true) {
|
|
92
|
+
if (cache === true) {
|
|
93
|
+
localStorage.setItem("web-theme-appearance", theme == null ? "auto" : theme);
|
|
94
|
+
}
|
|
95
|
+
return toggleTheme(theme, transition);
|
|
96
|
+
}
|
|
97
|
+
/** 获取当前主题色 */
|
|
98
|
+
export function getColorTheme(defaultValue) {
|
|
99
|
+
const root = document.documentElement;
|
|
100
|
+
const match = root.className.match(/color-([0-9a-fA-F]{6})/);
|
|
101
|
+
if (match == null) {
|
|
102
|
+
// 获取 --nt-primary-color 的值
|
|
103
|
+
let color = getComputedStyle(root).getPropertyValue("--l-primary-color");
|
|
104
|
+
if (color === "") {
|
|
105
|
+
color = localStorage.getItem("web-theme-color");
|
|
106
|
+
}
|
|
107
|
+
return color ? color : defaultValue;
|
|
108
|
+
}
|
|
109
|
+
return `#${match[1]}`;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* 初始化主题色, 让网页能够适应系统主题色, 同时根据缓存的主题色切换主题色
|
|
113
|
+
* @returns 当前应用的主题色
|
|
114
|
+
*/
|
|
115
|
+
export function initColorTheme() {
|
|
116
|
+
// 获取缓存主题色
|
|
117
|
+
const color = localStorage.getItem("web-theme-color");
|
|
118
|
+
if (color != null) {
|
|
119
|
+
return toggleColorTheme(color);
|
|
120
|
+
}
|
|
121
|
+
return color;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* 切换主题色, 通常用于预览
|
|
125
|
+
* @param color 待切换的主题色
|
|
126
|
+
* @returns 切换后的主题色
|
|
127
|
+
*/
|
|
128
|
+
export async function toggleColorTheme(color) {
|
|
129
|
+
const vars = [
|
|
130
|
+
`--l-primary-color: ${color};`,
|
|
131
|
+
`--l-primary-color-dark1: ${adjust(color, 1, false)};`,
|
|
132
|
+
];
|
|
133
|
+
for (let i = 1; i <= 5; i++) {
|
|
134
|
+
vars.push(`--l-primary-color-light${i}: ${adjust(color, i)};`);
|
|
135
|
+
}
|
|
136
|
+
let $style = document.getElementById("color-theme-style");
|
|
137
|
+
if ($style == null) {
|
|
138
|
+
$style = document.createElement("style");
|
|
139
|
+
$style.id = "color-theme-style";
|
|
140
|
+
document.head.appendChild($style);
|
|
141
|
+
}
|
|
142
|
+
$style.innerHTML = `:root{${vars.join("")}}`;
|
|
143
|
+
return color;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* 应用主题色
|
|
147
|
+
* @param color 主题色
|
|
148
|
+
* @param cache 是否缓存主题色, 让应用下一次启动的时候, 可以应用主题色, 默认: true
|
|
149
|
+
* @returns 切换后的主题色
|
|
150
|
+
*/
|
|
151
|
+
export function applyColorTheme(color, cache = true) {
|
|
152
|
+
if (cache === true) {
|
|
153
|
+
localStorage.setItem("web-theme-color", color);
|
|
154
|
+
}
|
|
155
|
+
return toggleColorTheme(color);
|
|
156
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 数据验证器
|
|
3
|
+
*/
|
|
4
|
+
interface RuleItem {
|
|
5
|
+
rule: RegExp | ((v: any) => boolean) | "required";
|
|
6
|
+
message: string;
|
|
7
|
+
sameKey?: string;
|
|
8
|
+
}
|
|
9
|
+
export type RuleType = string | RegExp | ((v: any) => boolean) | (RegExp | string | ((v: any) => boolean) | {
|
|
10
|
+
rule: string | RegExp | ((v: any) => boolean);
|
|
11
|
+
message?: string;
|
|
12
|
+
});
|
|
13
|
+
export interface SchemaType {
|
|
14
|
+
/** 数据字段 */
|
|
15
|
+
key: string;
|
|
16
|
+
/** 是否必须 */
|
|
17
|
+
required?: boolean;
|
|
18
|
+
/** 验证规则列表 */
|
|
19
|
+
rules?: RuleType[];
|
|
20
|
+
/** 错误信息 */
|
|
21
|
+
message?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 数据验证器
|
|
25
|
+
*/
|
|
26
|
+
declare class Validator {
|
|
27
|
+
rules: {
|
|
28
|
+
[index: string]: RuleItem[];
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* 构造数据验证转换器
|
|
32
|
+
*
|
|
33
|
+
* See {@link https://gitee.com/towardly/ph/wikis/utils/validator|Validator文档}.
|
|
34
|
+
*
|
|
35
|
+
* @param schemas 配置验证转换规则
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
*
|
|
39
|
+
* const validator = new Validator([
|
|
40
|
+
* { key: 'mobile', rules: ['required', 'mobile'] },
|
|
41
|
+
* { key: 'code': rules: /^\d{6}$/, message: '请输入正确的验证码' },
|
|
42
|
+
* { key: 'confirmPassword', rules: ['required', 'same:password'] }
|
|
43
|
+
* ])
|
|
44
|
+
* // 验证某一个字段
|
|
45
|
+
* validator.validateKey().then(res => {})
|
|
46
|
+
*/
|
|
47
|
+
constructor(schemas: SchemaType[]);
|
|
48
|
+
addSchemas(schemas: SchemaType[]): void;
|
|
49
|
+
addSchema(schema: SchemaType): void;
|
|
50
|
+
/**
|
|
51
|
+
* 进行数据验证
|
|
52
|
+
* @param data 待验证的数据
|
|
53
|
+
* @param all 是否全部验证, false - 只要验证错误一个则停止验证
|
|
54
|
+
* @returns
|
|
55
|
+
*/
|
|
56
|
+
validate(data: any, all?: boolean): Promise<boolean>;
|
|
57
|
+
/**
|
|
58
|
+
* 只验证指定 key 的数据格式
|
|
59
|
+
* @param key 指定待验证的 key
|
|
60
|
+
* @param value 待验证的数据
|
|
61
|
+
* @param data 原始数据,当验证确认密码时需要使用
|
|
62
|
+
*/
|
|
63
|
+
validateKey(key: string, value: any, data?: any): Promise<{
|
|
64
|
+
key: string;
|
|
65
|
+
value: any;
|
|
66
|
+
}>;
|
|
67
|
+
private _validateRule;
|
|
68
|
+
private _parseSchemaRules;
|
|
69
|
+
private _parseStringRule;
|
|
70
|
+
}
|
|
71
|
+
export default Validator;
|