Feat: add page titles and favicon support

This commit is contained in:
MangoPig
2026-07-06 18:01:26 +01:00
parent dc081ccc5b
commit 91b4c254ec
34 changed files with 145 additions and 4 deletions
@@ -1,11 +1,11 @@
// Path: Frontend/src/components/app-shell/AppShell/AppShell.tsx
import { useLocation } from "@solidjs/router";
import { createSignal, onCleanup, onMount, Show, type JSX } from "solid-js";
import { createEffect, createSignal, onCleanup, onMount, Show, type JSX } from "solid-js";
import { getDocumentTheme, setTheme, type Theme } from "../../../helper/themeRuntime";
import { BootstrapWizard } from "../../bootstrap/BootstrapWizard/BootstrapWizard";
import { AppShellDataProvider, useAppShellData } from "../data/app-shell.context";
import { getWorkspaceBreadcrumbSegments } from "../data/workspace-routes";
import { getWorkspaceBreadcrumbSegments, getWorkspaceDocumentTitle } from "../data/workspace-routes";
import { LeftRail } from "../../workspace-navigation/LeftRail/LeftRail";
import { MobileBottomNav } from "../MobileBottomNav/MobileBottomNav";
import { MobileWorkspaceBrowser } from "../../workspace-navigation/MobileWorkspaceBrowser/MobileWorkspaceBrowser";
@@ -94,6 +94,16 @@ const AppShellContent = (props: { children: JSX.Element }): JSX.Element => {
}),
].join(" / ");
createEffect((): void => {
if (typeof document === "undefined") {
return;
}
document.title = getWorkspaceDocumentTitle(location.pathname, {
activeProjectName: appShellData.activeProject().name,
});
});
return (
<div class={styles.shell} data-ui="app-shell" data-app-shell-status={appShellData.status()}>
<TopBar
@@ -1,6 +1,7 @@
// Path: Frontend/src/components/app-shell/data/workspace-routes.ts
import type { WorkspaceStaticKind } from "./shell.types";
import { buildPageTitle } from "../../../helper/pageTitle";
export type WorkspaceSurfaceKind = Exclude<WorkspaceStaticKind, "workspace">;
export type SettingsSectionKind = "account" | "workspace" | "server" | "theme" | "security" | "members";
@@ -11,6 +12,11 @@ export type WorkspaceBreadcrumbContext = {
activeTeamName?: string;
};
export type WorkspaceTitleContext = {
activeProjectName: string;
appName?: string;
};
const workspaceSurfaceRoutes: Record<WorkspaceSurfaceKind, string> = {
home: "/workspace/home",
settings: "/settings",
@@ -77,3 +83,38 @@ export const getWorkspaceBreadcrumbSegments = (
return [context.activeProjectName, getWorkspaceSurfaceBreadcrumbLabel(pathname)];
};
export const getWorkspaceDocumentTitle = (
pathname: string,
context: WorkspaceTitleContext,
): string => {
const appName = context.appName?.trim() || undefined;
const settingsSection = getSettingsSectionFromPathname(pathname);
if (pathname === workspaceSurfaceRoutes.settings || pathname === "/workspace/settings") {
return buildPageTitle(appName, "Settings");
}
if (settingsSection) {
switch (settingsSection) {
case "account":
return buildPageTitle(appName, "Account Settings");
case "workspace":
return buildPageTitle(appName, "Workspace Settings");
case "server":
return buildPageTitle(appName, "Server Settings");
case "theme":
return buildPageTitle(appName, "Theme Settings");
case "security":
return buildPageTitle(appName, "Security Settings");
case "members":
return buildPageTitle(appName, "Members & Roles");
}
}
if (pathname.startsWith(workspaceSurfaceRoutes.home)) {
return buildPageTitle(appName, context.activeProjectName);
}
return buildPageTitle(appName);
};