✨ 主页布局构建完成
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
const getInitialMode = () => {
|
||||
if (typeof window !== 'undefined') {
|
||||
// 优先用 html 的 class
|
||||
if (document.documentElement.classList.contains('dark')) return 'dark';
|
||||
if (document.documentElement.classList.contains('light')) return 'light';
|
||||
// 其次用 localStorage
|
||||
return localStorage.getItem('system-theme-mode') || 'light';
|
||||
}
|
||||
return 'light'; // SSR 默认
|
||||
};
|
||||
|
||||
const useColorModeStore = defineStore('colorMode', {
|
||||
state: () => ({
|
||||
colorMode: getInitialMode() as 'light' | 'dark',
|
||||
callBackFunctions: new Map<string, () => void>(),
|
||||
callBackId: 0,
|
||||
}),
|
||||
getters: {
|
||||
isDarkMode: (state) => state.colorMode === 'dark',
|
||||
},
|
||||
actions: {
|
||||
registerCallBack(func: () => void) {
|
||||
const id = `callback-${this.callBackId++}`;
|
||||
this.callBackFunctions.set(id, func);
|
||||
return id;
|
||||
},
|
||||
unregisterCallBack(id: string) {
|
||||
this.callBackFunctions.delete(id);
|
||||
},
|
||||
notifyCallBacks() {
|
||||
this.callBackFunctions.forEach((func) => {
|
||||
try {
|
||||
func();
|
||||
} catch (error) {
|
||||
console.error('Error in color mode callback:', error);
|
||||
}
|
||||
});
|
||||
},
|
||||
toggleColorMode() {
|
||||
this.setColorMode(this.colorMode === 'dark' ? 'light' : 'dark');
|
||||
},
|
||||
setColorMode(mode: 'light' | 'dark') {
|
||||
if (mode !== 'light' && mode !== 'dark') {
|
||||
throw new Error('Invalid color mode. Use "light" or "dark".');
|
||||
}
|
||||
this.colorMode = mode;
|
||||
if (mode === 'dark') {
|
||||
document.querySelector('html')!.classList.remove('light');
|
||||
document.querySelector('html')!.classList.add('dark');
|
||||
} else {
|
||||
document.querySelector('html')!.classList.remove('dark');
|
||||
document.querySelector('html')!.classList.add('light');
|
||||
}
|
||||
this.notifyCallBacks();
|
||||
},
|
||||
},
|
||||
});
|
||||
export default useColorModeStore;
|
||||
@@ -1,4 +0,0 @@
|
||||
export const store = defineStore('counter', {
|
||||
|
||||
});
|
||||
export default store;
|
||||
@@ -0,0 +1,69 @@
|
||||
const useIconStore = defineStore('icon', {
|
||||
state: () => ({
|
||||
iconCache: new Map<string, string>(),
|
||||
addingSet: new Set<string>(),
|
||||
waitingCallbackFunctions: new Map<string, (() => void)[]>(),
|
||||
}),
|
||||
actions: {
|
||||
getIcon(iconName: string): string {
|
||||
if (this.iconCache.has(iconName)) {
|
||||
return this.iconCache.get(iconName) as string;
|
||||
}
|
||||
return '';
|
||||
},
|
||||
getColoredIcon(iconName: string, color: string): string {
|
||||
const icon = this.getIcon(iconName);
|
||||
if (icon === '')
|
||||
return '';
|
||||
return icon.replace('<svg', `<svg style="color:${color};"`);
|
||||
},
|
||||
async setIconInfo(iconName: string, iconData?: string) {
|
||||
if (this.iconCache.has(iconName)) {
|
||||
return;
|
||||
}
|
||||
if (this.addingSet.has(iconName)) {
|
||||
return new Promise<void>((resolve) => {
|
||||
if (!this.waitingCallbackFunctions.has(iconName)) {
|
||||
this.waitingCallbackFunctions.set(iconName, [resolve]);
|
||||
} else
|
||||
this.waitingCallbackFunctions.get(iconName)!.push(resolve);
|
||||
});
|
||||
}
|
||||
this.addingSet.add(iconName);
|
||||
if (iconData === undefined || iconData === null || iconData === '') {
|
||||
this.iconCache.set(iconName, await fetchSvg(iconName));
|
||||
} else
|
||||
this.iconCache.set(iconName, iconData as string);
|
||||
this.addingSet.delete(iconName);
|
||||
this.waitingCallbackFunctions.get(iconName)?.forEach((callback) => callback());
|
||||
this.waitingCallbackFunctions.delete(iconName);
|
||||
},
|
||||
|
||||
},
|
||||
});
|
||||
export default useIconStore;
|
||||
|
||||
export async function fetchSvg(svgName: string, maxRetries = 3) {
|
||||
const iconifyUrl = 'https://api.iconify.design/';
|
||||
|
||||
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
||||
try {
|
||||
return await (await $fetch<Blob>(iconifyUrl + svgName + '.svg', {
|
||||
method: 'GET',
|
||||
params: {
|
||||
width: '100%',
|
||||
},
|
||||
})).text();
|
||||
} catch (error) {
|
||||
console.warn(`Attempt ${attempt} failed for ${svgName}:`, error);
|
||||
|
||||
if (attempt === maxRetries) {
|
||||
console.error(`All ${maxRetries} attempts failed for ${svgName}`);
|
||||
}
|
||||
|
||||
// 等待一段时间后重试(可选)
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000 * attempt));
|
||||
}
|
||||
}
|
||||
return '<svg></svg>';
|
||||
}
|
||||
Reference in New Issue
Block a user