feat: Implement new settings pages and refactor application layout and navigation with new components and hooks.

This commit is contained in:
syntaxbullet
2026-01-16 12:49:17 +01:00
parent 2f73f38877
commit 2a72beb0ef
33 changed files with 2584 additions and 1863 deletions

View File

@@ -135,6 +135,7 @@ const build = async () => {
minify: true,
target: "browser",
sourcemap: "linked",
publicPath: "/", // Use absolute paths for SPA routing compatibility
define: {
"process.env.NODE_ENV": JSON.stringify((cliConfig as any).watch ? "development" : "production"),
},
@@ -159,14 +160,86 @@ console.log(`\n✅ Build completed in ${buildTime}ms\n`);
if ((cliConfig as any).watch) {
console.log("👀 Watching for changes...\n");
// Keep the process alive for watch mode
// Bun.build with watch:true handles the watching,
// we just need to make sure the script doesn't exit.
process.stdin.resume();
// Also, handle manual exit
// Polling-based file watcher for Docker compatibility
// Docker volumes don't propagate filesystem events (inotify) reliably
const srcDir = path.join(process.cwd(), "src");
const POLL_INTERVAL_MS = 1000;
let lastMtimes = new Map<string, number>();
let isRebuilding = false;
// Collect all file mtimes in src directory
const collectMtimes = async (): Promise<Map<string, number>> => {
const mtimes = new Map<string, number>();
const glob = new Bun.Glob("**/*.{ts,tsx,js,jsx,css,html}");
for await (const file of glob.scan({ cwd: srcDir, absolute: true })) {
try {
const stat = await Bun.file(file).stat();
if (stat) {
mtimes.set(file, stat.mtime.getTime());
}
} catch {
// File may have been deleted, skip
}
}
return mtimes;
};
// Initial collection
lastMtimes = await collectMtimes();
// Polling loop
const poll = async () => {
if (isRebuilding) return;
const currentMtimes = await collectMtimes();
const changedFiles: string[] = [];
// Check for new or modified files
for (const [file, mtime] of currentMtimes) {
const lastMtime = lastMtimes.get(file);
if (lastMtime === undefined || lastMtime < mtime) {
changedFiles.push(path.relative(srcDir, file));
}
}
// Check for deleted files
for (const file of lastMtimes.keys()) {
if (!currentMtimes.has(file)) {
changedFiles.push(path.relative(srcDir, file) + " (deleted)");
}
}
if (changedFiles.length > 0) {
isRebuilding = true;
console.log(`\n🔄 Changes detected:`);
changedFiles.forEach(f => console.log(`${f}`));
console.log("");
try {
const rebuildStart = performance.now();
await build();
const rebuildEnd = performance.now();
console.log(`\n✅ Rebuild completed in ${(rebuildEnd - rebuildStart).toFixed(2)}ms\n`);
} catch (err) {
console.error("❌ Rebuild failed:", err);
}
lastMtimes = currentMtimes;
isRebuilding = false;
}
};
const interval = setInterval(poll, POLL_INTERVAL_MS);
// Handle manual exit
process.on("SIGINT", () => {
clearInterval(interval);
console.log("\n👋 Stopping build watcher...");
process.exit(0);
});
// Keep process alive
process.stdin.resume();
}