feat(web): migrate application shell to TanStack Start

- replace the legacy client-only Vite bootstrap with TanStack Router routes, Start SSR, and Nitro output

- compose the reusable layout, navigation, appearance, chats, and notifications blocks with application-owned data

- persist UI preferences through server functions and initialize theme, sidebar, and breakpoint state before hydration

- add React Query, hotkey, toaster, and responsive dashboard integration

- add application-owned Lingui configuration and catalogs, mount the runtime provider, and lazily enable I18nDevtool in development

- remove superseded HTML, main entry, theme provider, and application ESLint configuration
This commit is contained in:
Maofeng
2026-07-29 21:23:17 +08:00
parent 9e3f1d6b59
commit a9480ad9aa
32 changed files with 1555 additions and 309 deletions
+18
View File
@@ -0,0 +1,18 @@
import { createServerFn } from "@tanstack/react-start"
import { isUiStateUpdate } from "@workspace/blocks/appearance"
import { readUiState, writeUiState } from "./ui-state.server"
export const getUiState = createServerFn({ method: "GET" }).handler(() => {
return readUiState()
})
export const setUiState = createServerFn({ method: "POST" })
.validator((value: unknown) => {
if (!isUiStateUpdate(value)) {
throw new Error("Invalid UI state update")
}
return value
})
.handler(({ data }) => {
writeUiState(data.key, data.value)
})
+39
View File
@@ -0,0 +1,39 @@
import "@tanstack/react-start/server-only"
import { getCookie, setCookie } from "@tanstack/react-start/server"
import {
type UiState,
type UiStateKey,
uiStateDefinitions,
} from "@workspace/blocks/appearance"
const LEGACY_THEME_COOKIE = "simple-shop-admin-theme"
export function readUiState(): UiState {
return {
"main-compacted": uiStateDefinitions["main-compacted"].parse(
getCookie(uiStateDefinitions["main-compacted"].cookie)
),
"sidebar-collapsed": uiStateDefinitions["sidebar-collapsed"].parse(
getCookie(uiStateDefinitions["sidebar-collapsed"].cookie)
),
"theme-mode": uiStateDefinitions["theme-mode"].parse(
getCookie(uiStateDefinitions["theme-mode"].cookie) ??
getCookie(LEGACY_THEME_COOKIE)
),
"theme-light": uiStateDefinitions["theme-light"].parse(
getCookie(uiStateDefinitions["theme-light"].cookie)
),
"theme-dark": uiStateDefinitions["theme-dark"].parse(
getCookie(uiStateDefinitions["theme-dark"].cookie)
),
}
}
export function writeUiState<K extends UiStateKey>(key: K, value: UiState[K]) {
const definition = uiStateDefinitions[key]
setCookie(definition.cookie, definition.serialize(value), {
path: "/",
sameSite: "lax",
maxAge: 60 * 60 * 24 * 365,
})
}