Files
summercms/admin/src/main.ts
Jakub Zych 445404e394 feat(10-04): collapsible panel with flyout, user menu with logout, breadcrumbs and dark mode
- useSidebar: collapsed below 1100px (matchMedia) or by the admin's choice,
  persisted as a boolean under summer-admin.sidebar; the viewport never
  overwrites the stored choice
- SectionPanel collapse and rail expand buttons; SectionFlyout (role menu)
  opens on hover, focus, Enter or ArrowDown on a rail item, closes on Esc or
  about 200 ms after leaving and returns focus to the rail item
- Breadcrumbs with plugin, controller and record crumbs; UserMenu (Reka
  DropdownMenu) with initials, name, role and Wyloguj
- useAuth.logout POSTs /auth/logout, clears user, navigation and settings
  and routes to login even when the call fails
- applyColorScheme toggles .dark from prefers-color-scheme (no toggle, A6)
- newest toast first, 200 ms fade and scale for dialogs and toasts
- one relation-manager type constant in the registry
- shell smoke tests; tests default to a desktop, light matchMedia
2026-09-27 17:26:44 +02:00

39 lines
1.4 KiB
TypeScript

import { createApp } from 'vue'
import App from './App.vue'
import { createAdminRouter } from './app/router'
import { onUnauthorized } from './api/client'
import { loadStrings } from './app/i18n'
import { applyColorScheme } from './app/theme'
import { clearUser, me } from './state/useAuth'
import { loadNavigation } from './state/useNavigation'
import { loadSettings } from './state/useSettings'
import './styles/main.css'
async function boot(): Promise<void> {
// Dark mode follows the system preference before anything renders (A6).
applyColorScheme()
// Boot order (research Pattern 7): the public strings bundle first, so the
// login screen is translated, then the session, then navigation.
await loadStrings().catch(() => undefined)
// A 401 here only means "not signed in"; the router guard sends the
// visitor to the login route with the requested path as redirect.
const user = await me().catch(() => null)
if (user) {
await Promise.all([loadNavigation().catch(() => []), loadSettings().catch(() => [])])
}
const router = createAdminRouter()
onUnauthorized(() => {
clearUser()
const current = router.currentRoute.value
if (current.name !== 'login') {
void router.push({ name: 'login', query: { redirect: current.fullPath } })
}
})
const app = createApp(App)
app.use(router)
await router.isReady()
app.mount('#app')
}
void boot()