feat: add tabbed Settings, 10 themes with custom accent/text color pickers, main project directory selector, and export filename/directory controls
This commit is contained in:
+109
-1
@@ -373,6 +373,7 @@ export const api = {
|
||||
port: number;
|
||||
activePort?: number;
|
||||
startOnBoot: boolean;
|
||||
projectDirectory?: string;
|
||||
}> => {
|
||||
const endpoints = [
|
||||
"/api/system/server-config",
|
||||
@@ -388,6 +389,7 @@ export const api = {
|
||||
port: number;
|
||||
activePort?: number;
|
||||
startOnBoot: boolean;
|
||||
projectDirectory?: string;
|
||||
};
|
||||
return {
|
||||
online: true,
|
||||
@@ -395,6 +397,7 @@ export const api = {
|
||||
port: data.port,
|
||||
...(data.activePort !== undefined ? { activePort: data.activePort } : {}),
|
||||
startOnBoot: data.startOnBoot,
|
||||
...(data.projectDirectory ? { projectDirectory: data.projectDirectory } : {}),
|
||||
};
|
||||
}
|
||||
} catch {
|
||||
@@ -410,7 +413,12 @@ export const api = {
|
||||
},
|
||||
|
||||
updateServerConfig: async (
|
||||
patch: { enabled?: boolean; port?: number; startOnBoot?: boolean },
|
||||
patch: {
|
||||
enabled?: boolean;
|
||||
port?: number;
|
||||
startOnBoot?: boolean;
|
||||
projectDirectory?: string;
|
||||
},
|
||||
portHint?: number,
|
||||
): Promise<{
|
||||
online: boolean;
|
||||
@@ -418,6 +426,7 @@ export const api = {
|
||||
port: number;
|
||||
activePort?: number;
|
||||
startOnBoot: boolean;
|
||||
projectDirectory?: string;
|
||||
}> => {
|
||||
const endpoints = [
|
||||
"/api/system/server-config",
|
||||
@@ -438,6 +447,7 @@ export const api = {
|
||||
port: number;
|
||||
activePort?: number;
|
||||
startOnBoot: boolean;
|
||||
projectDirectory?: string;
|
||||
};
|
||||
return {
|
||||
online: true,
|
||||
@@ -445,6 +455,7 @@ export const api = {
|
||||
port: data.port,
|
||||
...(data.activePort !== undefined ? { activePort: data.activePort } : {}),
|
||||
startOnBoot: data.startOnBoot,
|
||||
...(data.projectDirectory ? { projectDirectory: data.projectDirectory } : {}),
|
||||
};
|
||||
}
|
||||
} catch {
|
||||
@@ -456,6 +467,103 @@ export const api = {
|
||||
enabled: patch.enabled ?? true,
|
||||
port: patch.port ?? portHint ?? 8081,
|
||||
startOnBoot: patch.startOnBoot ?? false,
|
||||
...(patch.projectDirectory ? { projectDirectory: patch.projectDirectory } : {}),
|
||||
};
|
||||
},
|
||||
|
||||
listSystemDirectories: async (
|
||||
dirPath?: string,
|
||||
portHint?: number,
|
||||
): Promise<{
|
||||
online: boolean;
|
||||
currentPath: string;
|
||||
parentPath: string | null;
|
||||
homePath: string;
|
||||
directories: { name: string; path: string }[];
|
||||
}> => {
|
||||
const query = dirPath ? `?path=${encodeURIComponent(dirPath)}` : "";
|
||||
const endpoints = [
|
||||
`/api/system/list-dirs${query}`,
|
||||
...(portHint ? [`http://localhost:${portHint}/api/system/list-dirs${query}`] : []),
|
||||
];
|
||||
for (const url of endpoints) {
|
||||
try {
|
||||
const res = await fetch(url, { credentials: "include" });
|
||||
const ct = res.headers.get("content-type") ?? "";
|
||||
if (res.ok && ct.includes("application/json")) {
|
||||
const data = (await res.json()) as {
|
||||
currentPath: string;
|
||||
parentPath: string | null;
|
||||
homePath: string;
|
||||
directories: { name: string; path: string }[];
|
||||
};
|
||||
return {
|
||||
online: true,
|
||||
currentPath: data.currentPath,
|
||||
parentPath: data.parentPath,
|
||||
homePath: data.homePath,
|
||||
directories: data.directories,
|
||||
};
|
||||
}
|
||||
} catch {
|
||||
/* try next */
|
||||
}
|
||||
}
|
||||
return {
|
||||
online: false,
|
||||
currentPath: dirPath || "~/Documents/PubScript",
|
||||
parentPath: null,
|
||||
homePath: "~",
|
||||
directories: [],
|
||||
};
|
||||
},
|
||||
|
||||
saveExportToDirectory: async (
|
||||
params: {
|
||||
directory: string;
|
||||
fileName: string;
|
||||
data: Uint8Array | string;
|
||||
},
|
||||
portHint?: number,
|
||||
): Promise<{ savedOnServer: boolean; savedPath?: string }> => {
|
||||
const bytes =
|
||||
typeof params.data === "string"
|
||||
? new TextEncoder().encode(params.data)
|
||||
: params.data;
|
||||
let binary = "";
|
||||
const chunkSize = 0x8000;
|
||||
for (let i = 0; i < bytes.length; i += chunkSize) {
|
||||
binary += String.fromCharCode(...bytes.subarray(i, i + chunkSize));
|
||||
}
|
||||
const base64Data = btoa(binary);
|
||||
|
||||
const endpoints = [
|
||||
"/api/system/save-export",
|
||||
...(portHint ? [`http://localhost:${portHint}/api/system/save-export`] : []),
|
||||
];
|
||||
for (const url of endpoints) {
|
||||
try {
|
||||
const res = await fetch(url, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
directory: params.directory,
|
||||
fileName: params.fileName,
|
||||
base64Data,
|
||||
}),
|
||||
});
|
||||
const ct = res.headers.get("content-type") ?? "";
|
||||
if (res.ok && ct.includes("application/json")) {
|
||||
const out = (await res.json()) as { ok?: boolean; savedPath?: string };
|
||||
if (out.ok && out.savedPath) {
|
||||
return { savedOnServer: true, savedPath: out.savedPath };
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
/* try next */
|
||||
}
|
||||
}
|
||||
return { savedOnServer: false };
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user