- 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
39 lines
1.4 KiB
TypeScript
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()
|