RSS Git Download  Clone
Raw Blame History 9kB 213 lines
import '@fontsource/roboto/latin-300.css'
import '@fontsource/roboto/latin-400.css'
import '@fontsource/roboto/latin-500.css'
import '@fontsource/roboto/latin-700.css'
import '@fontsource/roboto/latin-ext-300.css'
import '@fontsource/roboto/latin-ext-400.css'
import '@fontsource/roboto/latin-ext-500.css'
import '@fontsource/roboto/latin-ext-700.css'
import '@fontsource/roboto/cyrillic-300.css'
import '@fontsource/roboto/cyrillic-400.css'
import '@fontsource/roboto/cyrillic-500.css'
import '@fontsource/roboto/cyrillic-700.css'
import '@fontsource/roboto/cyrillic-ext-300.css'
import '@fontsource/roboto/cyrillic-ext-400.css'
import '@fontsource/roboto/cyrillic-ext-500.css'
import '@fontsource/roboto/cyrillic-ext-700.css'
import '@fontsource/roboto/greek-300.css'
import '@fontsource/roboto/greek-400.css'
import '@fontsource/roboto/greek-500.css'
import '@fontsource/roboto/greek-700.css'
import '@fontsource/roboto/vietnamese-300.css'
import '@fontsource/roboto/vietnamese-400.css'
import '@fontsource/roboto/vietnamese-500.css'
import '@fontsource/roboto/vietnamese-700.css'
import '@fontsource/roboto-mono/latin-400.css'
import '@fontsource/roboto-mono/latin-ext-400.css'
import '@fontsource/roboto-mono/cyrillic-400.css'
import '@fontsource/roboto-mono/cyrillic-ext-400.css'
import '@fontsource/roboto-mono/greek-400.css'
import '@fontsource/roboto-mono/vietnamese-400.css'
import '@fortawesome/fontawesome-free/css/all.css'
import 'vuetify/styles'

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import { createRouter, createWebHistory } from 'vue-router'
import { createVuetify } from 'vuetify'
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'
import { aliases } from 'vuetify/iconsets/mdi-svg'
import { mdiSvgIconSet } from './icons'

import App from './App.vue'
import { loadSavedConsoleDrawerHeight } from '../core/console-drawer-height'

// Apply the saved console drawer height BEFORE Vue renders so the CSS var
// is in place when components read it. Otherwise the drawer flashes at 30vh
// default before the component's own onMounted hook sets it.
loadSavedConsoleDrawerHeight()

const pinia = createPinia()

const router = createRouter({
    history: createWebHistory('/vue'),
    routes: [
        { path: '/', redirect: '/settings' },
        { path: '/settings', component: () => import('./pages/settings/SettingsPage.vue') },
        { path: '/info', component: () => import('./pages/info/InfoPage.vue') },
        {
            path: '/database',
            component: () => import('./pages/database/DatabasePage.vue'),
            children: [
                { path: 'statistics', component: () => import('./pages/database/StatisticsPage.vue') },
                { path: 'key/:key', component: () => import('./pages/database/DatabaseKeyPage.vue') },
            ],
        },
        { path: '/console', component: () => import('./pages/console/ConsoleComponent.vue') },
        { path: '/search', component: () => import('./pages/search/SearchPage.vue') },
        { path: '/login', component: () => import('./pages/login/LoginPage.vue') },
        {
            path: '/monitoring',
            component: () => import('./pages/monitoring/MonitoringShell.vue'),
            children: [
                { path: '', component: () => import('./pages/monitoring/PulsePage.vue') },
                { path: 'profiler', component: () => import('./pages/monitoring/ProfilerPage.vue') },
                { path: 'pubsub', component: () => import('./pages/monitoring/PubSubPage.vue') },
                { path: 'analysis', component: () => import('./pages/monitoring/MemoryAnalysisPage.vue') },
            ],
        },
    ],
})

// All 7 themes with exact toolbar colors from Angular/React
const vuetify = createVuetify({
    components,
    directives,
    icons: { defaultSet: 'mdi', aliases, sets: { mdi: mdiSvgIconSet } },
    defaults: {
        VTextField: { variant: 'outlined', density: 'compact' },
        VSelect: { variant: 'outlined', density: 'compact' },
        VSwitch: { density: 'compact', hideDetails: true },
    },
    theme: {
        defaultTheme: 'dark',
        themes: {
            // Light themes: WHITE text on colored buttons
            enterprise: {
                dark: false,
                colors: {
                    primary: '#3f51b5', 'on-primary': '#fff',
                    secondary: '#1976d2', 'on-secondary': '#fff',
                    error: '#d32f2f', 'on-error': '#fff',
                    success: '#4caf50', 'on-success': '#fff',
                    warning: '#d32f2f', 'on-warning': '#fff',
                    info: '#1976d2',
                    background: '#e0e0e0', surface: '#fafafa',
                },
            },
            light: {
                dark: false,
                colors: {
                    primary: '#673ab7', 'on-primary': '#fff',
                    secondary: '#9c27b0', 'on-secondary': '#fff',
                    error: '#d32f2f', 'on-error': '#fff',
                    success: '#4caf50', 'on-success': '#fff',
                    warning: '#d32f2f', 'on-warning': '#fff',
                    info: '#9c27b0',
                    background: '#cfd8dc', surface: '#eceff1',
                },
            },
            redis: {
                dark: false,
                colors: {
                    primary: '#212121', 'on-primary': 'rgba(255,255,255,0.87)',
                    secondary: '#757575', 'on-secondary': '#fff',
                    error: '#ffc107', 'on-error': '#fff',
                    success: '#4caf50', 'on-success': '#fff',
                    warning: '#ffc107', 'on-warning': '#fff',
                    info: '#757575',
                    background: '#ffcdd2', surface: '#fafafa',
                },
            },
            // Dark themes: BLACK text on colored buttons (bright backgrounds)
            dark: {
                dark: true,
                colors: {
                    primary: '#7986cb', 'on-primary': 'rgba(0,0,0,0.87)',
                    secondary: '#2196f3', 'on-secondary': 'rgba(0,0,0,0.87)',
                    error: '#ff9800', 'on-error': 'rgba(0,0,0,0.87)',
                    success: '#4caf50', 'on-success': 'rgba(0,0,0,0.87)',
                    warning: '#ff9800', 'on-warning': 'rgba(0,0,0,0.87)',
                    info: '#2196f3',
                    background: '#212121', surface: '#303030',
                },
            },
            darkNeu: {
                dark: true,
                colors: {
                    primary: '#00bcd4', 'on-primary': 'rgba(0,0,0,0.87)',
                    secondary: '#2196f3', 'on-secondary': 'rgba(0,0,0,0.87)',
                    error: '#ffeb3b', 'on-error': 'rgba(0,0,0,0.87)',
                    success: '#4caf50', 'on-success': 'rgba(0,0,0,0.87)',
                    warning: '#ffeb3b', 'on-warning': 'rgba(0,0,0,0.87)',
                    info: '#2196f3',
                    background: '#263238', surface: '#303030',
                },
            },
            darkoBluo: {
                dark: true,
                colors: {
                    primary: '#7986cb', 'on-primary': 'rgba(0,0,0,0.87)',
                    secondary: '#2196f3', 'on-secondary': 'rgba(0,0,0,0.87)',
                    error: '#ff9800', 'on-error': 'rgba(0,0,0,0.87)',
                    success: '#4caf50', 'on-success': 'rgba(0,0,0,0.87)',
                    warning: '#ff9800', 'on-warning': 'rgba(0,0,0,0.87)',
                    info: '#2196f3',
                    background: '#283593', surface: '#303030',
                },
            },
            matrix: {
                dark: true,
                colors: {
                    primary: '#76ff03', 'on-primary': 'rgba(0,0,0,0.87)',
                    secondary: '#c6ff00', 'on-secondary': 'rgba(0,0,0,0.87)',
                    error: '#00c853', 'on-error': 'rgba(0,0,0,0.87)',
                    success: '#76ff03', 'on-success': 'rgba(0,0,0,0.87)',
                    warning: '#00c853', 'on-warning': 'rgba(0,0,0,0.87)',
                    info: '#c6ff00',
                    background: '#1b5e20', surface: '#303030',
                },
            },
        },
    },
})

const app = createApp(App)
app.use(pinia)
app.use(router)
app.use(vuetify)

// Initialize i18n, socket, then mount
import { useI18nStore } from './stores/i18n'
import { ensureConnected } from './stores/socket.service'

const i18n = useI18nStore()
i18n.init().then(() => {
    ensureConnected()
    import('./stores/shortcuts')
    app.mount('#app')
}).catch((err) => {
    console.error('Vue init failed:', err)
    // Mount anyway so the user sees something
    app.mount('#app')
})

// E2E test interface
import { useRedisStateStore } from './stores/redis-state'
import { useSettingsStore } from './stores/settings'
;(globalThis as any).__p3xr_test = {
    state: new Proxy({}, { get(_, p: string) { return () => (useRedisStateStore() as any)[p] } }),
    settings: new Proxy({}, { get(_, p: string) { return () => (useSettingsStore() as any)[p] } }),
}