mirror of
https://github.com/lukaszraczylo/traefik-llmgateway.git
synced 2026-10-15 05:29:28 +00:00
feat(webui): vue admin panel source
Vue 3 + TypeScript + Pinia + Tailwind v4 + shadcn-vue + Chart.js admin panel source under webui/, built with Vite. Views: Overview (providers, redis/cache/retry status, model aliases), Usage (per-user/per-group/total tables with tokensIn/tokensOut/cost + limits), Charts (scope selector, req/tokens(stacked in-out)/cost metric tabs, 24h/30d/12mo window switcher, fed by GET /admin/api/usage/history). Pinia stores: auth (sessionStorage key gate, x-api-key header, 401/403 re-prompt), dashboard (5s poll), history (fetch-on-selection + 30s refresh). Design: deliberate neutral warm-neutral palette with a signature teal accent (no default Inter/purple-gradient/glassmorphism), real typographic hierarchy via the platform UI/mono font stacks (zero external assets - no Google Fonts), dark+light via prefers-color-scheme (no class toggle, no theme switcher). Charts: zero-based bars, honest axes, Okabe-Ito colorblind-safe series, tokens-in/out as a distinguishable stacked pair. vite.config.ts: base '/admin/' (matches admin.go's route layout) and build.modulePreload.polyfill:false (no inline bootstrap script, so the tightened admin CSP needs no 'unsafe-inline'). Code-split: Chart.js (ChartsView) loads lazily, not in the initial bundle. generate.mjs reads dist/ after `vite build` and writes ../admin_assets_gen.go (not committed by this change) - base64-encodes every asset, decoded once at package-var init; documented rationale in the script's own header comment. Hygiene: webui/go.mod walls webui/ off from the repo root's `go build`/ `vet`/`test ./...` (npm's node_modules bundles a stray .go file that would otherwise be swept in); tools/yaegi-check/main.go excludes webui/ from its GOPATH copy for the same reason. webui/ export-ignored (.gitattributes) from release source tarballs; webui/node_modules/ gitignored. tsconfig.app.json/tsconfig.node.json's JSONC comments dropped (TS itself is fine with either; the global pre-commit JSON validator is not) - no config values changed.
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
import { onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
|
||||
/**
|
||||
* useThemeColors exposes the current computed values of the design
|
||||
* tokens Chart.js needs to draw axis/grid/legend text (main.css) — Chart.js
|
||||
* paints to a <canvas>, so it cannot pick up CSS variables the way a DOM
|
||||
* element does; the caller must read them and hand them to Chart.js as
|
||||
* plain color strings. Every color literal in main.css is oklch()/hex,
|
||||
* both valid canvas fillStyle values in current evergreen browsers (the
|
||||
* only ones this admin panel targets — see vite.config.ts's
|
||||
* modulePreload note for the same reasoning), so no conversion is needed.
|
||||
*
|
||||
* Re-reads on a `prefers-color-scheme` change so an open Charts view
|
||||
* repaints if the OS theme flips while it's on screen — main.css's own
|
||||
* dark-mode block is a plain media query, not a class toggle, so this is
|
||||
* the only way a chart already on screen learns about it.
|
||||
*/
|
||||
export function useThemeColors() {
|
||||
const foreground = ref('')
|
||||
const mutedForeground = ref('')
|
||||
const border = ref('')
|
||||
|
||||
function sync(): void {
|
||||
const style = getComputedStyle(document.documentElement)
|
||||
foreground.value = style.getPropertyValue('--foreground').trim()
|
||||
mutedForeground.value = style.getPropertyValue('--muted-foreground').trim()
|
||||
border.value = style.getPropertyValue('--border').trim()
|
||||
}
|
||||
|
||||
let media: MediaQueryList | undefined
|
||||
onMounted(() => {
|
||||
sync()
|
||||
media = window.matchMedia('(prefers-color-scheme: dark)')
|
||||
media.addEventListener('change', sync)
|
||||
})
|
||||
onBeforeUnmount(() => {
|
||||
media?.removeEventListener('change', sync)
|
||||
})
|
||||
|
||||
return { foreground, mutedForeground, border }
|
||||
}
|
||||
Reference in New Issue
Block a user