style(code): 格式化代码缩进和布局样式

- 统一调整 admin.ts 文件中的接口定义缩进格式
- 优化 animated-theme-toggler.tsx 组件的代码结构和缩进
- 规范 app-config-modal.tsx 中 JSX 元素的嵌套格式
- 整理 app-providers.tsx 中的组件层级缩进
- 标准化 app-theme.ts 中的对象属性缩进格式
This commit is contained in:
HouYunFei
2026-05-22 23:19:25 +08:00
parent cee08cb5a8
commit e319481976
93 changed files with 11406 additions and 10424 deletions
+65 -65
View File
@@ -3,76 +3,76 @@ import type { ThemeConfig } from "antd";
import { theme as antdTheme } from "antd";
const neutral = {
light: {
primary: "#171717",
primaryHover: "#000000",
primaryText: "#ffffff",
menuBg: "#f5f5f5",
menuText: "#171717",
selectActiveBg: "#f5f5f5",
selectSelectedBg: "#f0f0f0",
selectText: "#171717",
tableSelectedBg: "rgba(17, 17, 17, 0.05)",
tableSelectedHoverBg: "rgba(17, 17, 17, 0.08)",
},
dark: {
primary: "#fafafa",
primaryHover: "#ffffff",
primaryText: "#171717",
menuBg: "#262626",
menuText: "#fafafa",
selectActiveBg: "#262626",
selectSelectedBg: "#333333",
selectText: "#fafafa",
tableSelectedBg: "rgba(255, 255, 255, 0.08)",
tableSelectedHoverBg: "rgba(255, 255, 255, 0.12)",
},
light: {
primary: "#171717",
primaryHover: "#000000",
primaryText: "#ffffff",
menuBg: "#f5f5f5",
menuText: "#171717",
selectActiveBg: "#f5f5f5",
selectSelectedBg: "#f0f0f0",
selectText: "#171717",
tableSelectedBg: "rgba(17, 17, 17, 0.05)",
tableSelectedHoverBg: "rgba(17, 17, 17, 0.08)",
},
dark: {
primary: "#fafafa",
primaryHover: "#ffffff",
primaryText: "#171717",
menuBg: "#262626",
menuText: "#fafafa",
selectActiveBg: "#262626",
selectSelectedBg: "#333333",
selectText: "#fafafa",
tableSelectedBg: "rgba(255, 255, 255, 0.08)",
tableSelectedHoverBg: "rgba(255, 255, 255, 0.12)",
},
};
export const adminLayoutStyle = {
siderWidth: 232,
headerHeight: 56,
brandHeight: 64,
menu: { borderInlineEnd: 0, padding: "18px 12px", fontSize: 15 } satisfies CSSProperties,
menuItem: { height: 44, lineHeight: "44px", marginBlock: 4, borderRadius: 8 } satisfies CSSProperties,
siderWidth: 232,
headerHeight: 56,
brandHeight: 64,
menu: { borderInlineEnd: 0, padding: "18px 12px", fontSize: 15 } satisfies CSSProperties,
menuItem: { height: 44, lineHeight: "44px", marginBlock: 4, borderRadius: 8 } satisfies CSSProperties,
};
export function getAntThemeConfig(dark: boolean): ThemeConfig {
const color = dark ? neutral.dark : neutral.light;
const color = dark ? neutral.dark : neutral.light;
return {
algorithm: dark ? antdTheme.darkAlgorithm : antdTheme.defaultAlgorithm,
cssVar: { key: dark ? "infinite-canvas-dark" : "infinite-canvas-light" },
token: {
colorPrimary: color.primary,
colorInfo: color.primary,
colorLink: color.primary,
colorLinkHover: color.primaryHover,
colorLinkActive: color.primary,
colorTextLightSolid: color.primaryText,
},
components: {
Button: {
primaryShadow: "none",
},
Menu: {
itemActiveBg: color.menuBg,
itemHoverBg: color.menuBg,
itemSelectedBg: color.menuBg,
itemSelectedColor: color.menuText,
darkItemHoverBg: neutral.dark.menuBg,
darkItemSelectedBg: neutral.dark.menuBg,
darkItemSelectedColor: neutral.dark.menuText,
},
Select: {
optionActiveBg: color.selectActiveBg,
optionSelectedBg: color.selectSelectedBg,
optionSelectedColor: color.selectText,
},
Table: {
rowSelectedBg: color.tableSelectedBg,
rowSelectedHoverBg: color.tableSelectedHoverBg,
},
},
};
return {
algorithm: dark ? antdTheme.darkAlgorithm : antdTheme.defaultAlgorithm,
cssVar: { key: dark ? "infinite-canvas-dark" : "infinite-canvas-light" },
token: {
colorPrimary: color.primary,
colorInfo: color.primary,
colorLink: color.primary,
colorLinkHover: color.primaryHover,
colorLinkActive: color.primary,
colorTextLightSolid: color.primaryText,
},
components: {
Button: {
primaryShadow: "none",
},
Menu: {
itemActiveBg: color.menuBg,
itemHoverBg: color.menuBg,
itemSelectedBg: color.menuBg,
itemSelectedColor: color.menuText,
darkItemHoverBg: neutral.dark.menuBg,
darkItemSelectedBg: neutral.dark.menuBg,
darkItemSelectedColor: neutral.dark.menuText,
},
Select: {
optionActiveBg: color.selectActiveBg,
optionSelectedBg: color.selectSelectedBg,
optionSelectedColor: color.selectText,
},
Table: {
rowSelectedBg: color.tableSelectedBg,
rowSelectedHoverBg: color.tableSelectedHoverBg,
},
},
};
}
+54 -54
View File
@@ -2,62 +2,62 @@ export type CanvasColorTheme = "light" | "dark";
export type CanvasBackgroundMode = "dots" | "lines" | "blank";
export const canvasThemes = {
light: {
canvas: {
background: "#f4f2ed",
dot: "rgba(68,64,60,.28)",
line: "rgba(68,64,60,.12)",
selectionStroke: "#1c1917",
selectionFill: "rgba(28,25,23,.06)",
light: {
canvas: {
background: "#f4f2ed",
dot: "rgba(68,64,60,.28)",
line: "rgba(68,64,60,.12)",
selectionStroke: "#1c1917",
selectionFill: "rgba(28,25,23,.06)",
},
node: {
label: "#57534e",
fill: "#e7e5df",
panel: "#fbfaf7",
stroke: "#d6d3ca",
activeStroke: "#1c1917",
placeholder: "#8a8479",
text: "#292524",
muted: "#78716c",
faint: "#a8a29e",
},
toolbar: {
panel: "rgba(251,250,247,.96)",
border: "#d6d3ca",
item: "#57534e",
itemHover: "#e7e5df",
activeBg: "#e7e5df",
activeText: "#292524",
},
},
node: {
label: "#57534e",
fill: "#e7e5df",
panel: "#fbfaf7",
stroke: "#d6d3ca",
activeStroke: "#1c1917",
placeholder: "#8a8479",
text: "#292524",
muted: "#78716c",
faint: "#a8a29e",
dark: {
canvas: {
background: "#181715",
dot: "rgba(245,245,244,.24)",
line: "rgba(245,245,244,.10)",
selectionStroke: "#fafaf9",
selectionFill: "rgba(250,250,249,.10)",
},
node: {
label: "#d6d3d1",
fill: "#292524",
panel: "#1f1d1a",
stroke: "#44403c",
activeStroke: "#fafaf9",
placeholder: "#a8a29e",
text: "#f5f5f4",
muted: "#d6d3d1",
faint: "#78716c",
},
toolbar: {
panel: "rgba(31,29,26,.96)",
border: "#44403c",
item: "#d6d3d1",
itemHover: "#292524",
activeBg: "#3a3631",
activeText: "#f5f5f4",
},
},
toolbar: {
panel: "rgba(251,250,247,.96)",
border: "#d6d3ca",
item: "#57534e",
itemHover: "#e7e5df",
activeBg: "#e7e5df",
activeText: "#292524",
},
},
dark: {
canvas: {
background: "#181715",
dot: "rgba(245,245,244,.24)",
line: "rgba(245,245,244,.10)",
selectionStroke: "#fafaf9",
selectionFill: "rgba(250,250,249,.10)",
},
node: {
label: "#d6d3d1",
fill: "#292524",
panel: "#1f1d1a",
stroke: "#44403c",
activeStroke: "#fafaf9",
placeholder: "#a8a29e",
text: "#f5f5f4",
muted: "#d6d3d1",
faint: "#78716c",
},
toolbar: {
panel: "rgba(31,29,26,.96)",
border: "#44403c",
item: "#d6d3d1",
itemHover: "#292524",
activeBg: "#3a3631",
activeText: "#f5f5f4",
},
},
} as const;
export type CanvasTheme = (typeof canvasThemes)[CanvasColorTheme];
+43 -43
View File
@@ -1,62 +1,62 @@
import type { ReferenceImage } from "@/types/image";
export function formatBytes(bytes: number) {
if (!Number.isFinite(bytes) || bytes <= 0) {
return "";
}
const units = ["B", "KB", "MB", "GB"];
let value = bytes;
let unitIndex = 0;
while (value >= 1024 && unitIndex < units.length - 1) {
value /= 1024;
unitIndex += 1;
}
return `${value >= 10 || unitIndex === 0 ? value.toFixed(0) : value.toFixed(1)} ${units[unitIndex]}`;
if (!Number.isFinite(bytes) || bytes <= 0) {
return "";
}
const units = ["B", "KB", "MB", "GB"];
let value = bytes;
let unitIndex = 0;
while (value >= 1024 && unitIndex < units.length - 1) {
value /= 1024;
unitIndex += 1;
}
return `${value >= 10 || unitIndex === 0 ? value.toFixed(0) : value.toFixed(1)} ${units[unitIndex]}`;
}
export function formatDuration(ms: number) {
const value = Math.max(0, Math.floor(ms / 1000));
const minutes = Math.floor(value / 60);
const seconds = value % 60;
return minutes ? `${minutes}${String(seconds).padStart(2, "0")}` : `${seconds}`;
const value = Math.max(0, Math.floor(ms / 1000));
const minutes = Math.floor(value / 60);
const seconds = value % 60;
return minutes ? `${minutes}${String(seconds).padStart(2, "0")}` : `${seconds}`;
}
export function getDataUrlByteSize(dataUrl: string) {
const base64 = dataUrl.split(",", 2)[1];
if (!base64) {
return 0;
}
const padding = base64.endsWith("==") ? 2 : base64.endsWith("=") ? 1 : 0;
return Math.max(0, Math.floor((base64.length * 3) / 4) - padding);
const base64 = dataUrl.split(",", 2)[1];
if (!base64) {
return 0;
}
const padding = base64.endsWith("==") ? 2 : base64.endsWith("=") ? 1 : 0;
return Math.max(0, Math.floor((base64.length * 3) / 4) - padding);
}
export function readFileAsDataUrl(file: File) {
return new Promise<string>((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(String(reader.result || ""));
reader.onerror = () => reject(new Error("读取图片失败"));
reader.readAsDataURL(file);
});
return new Promise<string>((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(String(reader.result || ""));
reader.onerror = () => reject(new Error("读取图片失败"));
reader.readAsDataURL(file);
});
}
export function readImageMeta(dataUrl: string) {
return new Promise<{ width: number; height: number; mimeType: string }>((resolve) => {
const image = new Image();
const done = () => resolve({ width: image.naturalWidth || 1024, height: image.naturalHeight || 1024, mimeType: dataUrl.match(/^data:([^;]+)/)?.[1] || "image/png" });
image.onload = done;
image.onerror = done;
setTimeout(done, 3000);
image.src = dataUrl;
});
return new Promise<{ width: number; height: number; mimeType: string }>((resolve) => {
const image = new Image();
const done = () => resolve({ width: image.naturalWidth || 1024, height: image.naturalHeight || 1024, mimeType: dataUrl.match(/^data:([^;]+)/)?.[1] || "image/png" });
image.onload = done;
image.onerror = done;
setTimeout(done, 3000);
image.src = dataUrl;
});
}
export function dataUrlToFile(image: ReferenceImage) {
const [header, content] = image.dataUrl.split(",", 2);
const mimeType = header.match(/data:(.*?);base64/)?.[1] || image.type || "image/png";
const binary = atob(content || "");
const bytes = new Uint8Array(binary.length);
for (let index = 0; index < binary.length; index += 1) {
bytes[index] = binary.charCodeAt(index);
}
return new File([bytes], image.name || "reference.png", { type: mimeType });
const [header, content] = image.dataUrl.split(",", 2);
const mimeType = header.match(/data:(.*?);base64/)?.[1] || image.type || "image/png";
const binary = atob(content || "");
const bytes = new Uint8Array(binary.length);
for (let index = 0; index < binary.length; index += 1) {
bytes[index] = binary.charCodeAt(index);
}
return new File([bytes], image.name || "reference.png", { type: mimeType });
}
+26 -26
View File
@@ -2,33 +2,33 @@ import localforage from "localforage";
import type { StateStorage } from "zustand/middleware";
localforage.config({
name: "infinite-canvas",
storeName: "app_state",
name: "infinite-canvas",
storeName: "app_state",
});
export const localForageStorage: StateStorage = {
getItem: async (name) => {
if (typeof window === "undefined") return null;
try {
return (await localforage.getItem<string>(name)) || null;
} catch {
return window.localStorage.getItem(name);
}
},
setItem: async (name, value) => {
if (typeof window === "undefined") return;
try {
await localforage.setItem(name, value);
} catch {
window.localStorage.setItem(name, value);
}
},
removeItem: async (name) => {
if (typeof window === "undefined") return;
try {
await localforage.removeItem(name);
} catch {
window.localStorage.removeItem(name);
}
},
getItem: async (name) => {
if (typeof window === "undefined") return null;
try {
return (await localforage.getItem<string>(name)) || null;
} catch {
return window.localStorage.getItem(name);
}
},
setItem: async (name, value) => {
if (typeof window === "undefined") return;
try {
await localforage.setItem(name, value);
} catch {
window.localStorage.setItem(name, value);
}
},
removeItem: async (name) => {
if (typeof window === "undefined") return;
try {
await localforage.removeItem(name);
} catch {
window.localStorage.removeItem(name);
}
},
};
+19 -19
View File
@@ -1,24 +1,24 @@
export type ReleaseInfo = {
version: string;
date: string;
items: { type: string; content: string }[];
version: string;
date: string;
items: { type: string; content: string }[];
};
export function parseChangelog(content: string): ReleaseInfo[] {
return content
.split(/^## /m)
.slice(1)
.map((block) => {
const [title = "", ...lines] = block.trim().split("\n");
const [, version = title.trim(), date = ""] = title.match(/^(.+?)(?:\s+-\s+(.+))?$/) || [];
return {
version: version.trim(),
date: date.trim(),
items: lines
.map((line) => line.trim().match(/^\+\s+\[(.+?)\]\s+(.+)$/))
.filter((match): match is RegExpMatchArray => Boolean(match))
.map((match) => ({ type: match[1], content: match[2] })),
};
})
.filter((release) => release.items.length);
return content
.split(/^## /m)
.slice(1)
.map((block) => {
const [title = "", ...lines] = block.trim().split("\n");
const [, version = title.trim(), date = ""] = title.match(/^(.+?)(?:\s+-\s+(.+))?$/) || [];
return {
version: version.trim(),
date: date.trim(),
items: lines
.map((line) => line.trim().match(/^\+\s+\[(.+?)\]\s+(.+)$/))
.filter((match): match is RegExpMatchArray => Boolean(match))
.map((match) => ({ type: match[1], content: match[2] })),
};
})
.filter((release) => release.items.length);
}
+3 -3
View File
@@ -1,6 +1,6 @@
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
return twMerge(clsx(inputs));
}