import { createTheme, ThemeOptions } from '@mui/material' // Extend MUI theme with custom p3xr properties declare module '@mui/material/styles' { interface Theme { p3xr: { accordionBg: string accordionColor: string strongBg: string strongColor: string inputBorderColor: string inputBg: string inputColor: string treeBranchColor: string commonWarnColor: string treecontrolIconColor: string matSysPrimary: string } } interface ThemeOptions { p3xr?: { accordionBg?: string accordionColor?: string strongBg?: string strongColor?: string inputBorderColor?: string inputBg?: string inputColor?: string treeBranchColor?: string commonWarnColor?: string treecontrolIconColor?: string matSysPrimary?: string } } } const TOOLBAR_HEIGHT = 48 // FontAwesome icon sizing const faIconBase = { display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: 24, height: 24, fontSize: 20, lineHeight: '24px', verticalAlign: 'middle', } const faIconSmaller = { ...faIconBase, fontSize: 18 } // Toolbar button styles const toolbarButtonStyles = { color: 'inherit !important', letterSpacing: '0.1px !important', textTransform: 'uppercase' as const, height: 36, minHeight: 36, minWidth: 'auto', padding: '0 4px', margin: '0 4px', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', whiteSpace: 'nowrap' as const, gap: 0, borderRadius: '4px', '&:hover': { backgroundColor: 'rgba(255, 255, 255, 0.15) !important' }, '& .MuiSvgIcon-root, & i.fa, & i.fas, & i.far, & i.fab': { marginRight: 4, marginLeft: 0 }, '& .MuiSvgIcon-root:only-child, & i:only-child': { marginRight: 0 }, } const toolbarIconButtonStyles = { borderRadius: '4px !important', color: 'inherit !important', margin: '0 2px', '&:hover': { backgroundColor: 'rgba(255, 255, 255, 0.15) !important', borderRadius: '4px !important' }, '& .MuiTouchRipple-root': { borderRadius: '4px !important' }, '& .MuiTouchRipple-child': { borderRadius: '4px !important' }, '&.Mui-focusVisible': { borderRadius: '4px !important' }, } function makeShared(toolbarBg: string, toolbarColor: string): ThemeOptions['components'] { return { MuiCssBaseline: { styleOverrides: ` body.p3xr-no-main-scroll { overflow: hidden; } body.p3xr-no-main-scroll #p3xr-layout-content { overflow: hidden; } body.p3xr-no-main-scroll #p3xr-monitoring-content { overflow: hidden; } body.p3xr-theme-dark { color-scheme: dark; } body.p3xr-theme-light { color-scheme: light; } [data-color-scheme="dark"] { color-scheme: dark; } [data-color-scheme="light"] { color-scheme: light; } body.p3xr-theme-dark ::selection { color: white; background: black; } body.p3xr-theme-light fieldset { border-color: rgba(0, 0, 0, 0.5); } body.p3xr-theme-dark fieldset { border-color: rgba(255, 255, 255, 0.25); } body.p3xr-no-animation *, body.p3xr-no-animation *::before, body.p3xr-no-animation *::after { animation-duration: 0ms !important; transition-duration: 0ms !important; transition-delay: 0ms !important; } body.p3xr-no-animation .fa-spin { animation-duration: 2s !important; } .p3xr-console-content-output-item:before { content: "> "; opacity: 0.5; } .p3xr-console-ai-result { display: block; } #p3xr-console-content { font-family: 'Roboto Mono', monospace; text-align: center; } #p3xr-console-content-output { min-width: calc(100% - 20px); text-align: left; overflow: auto; } #p3xr-console-content-output pre { font-family: 'Roboto Mono', monospace; white-space: pre-wrap; word-break: break-word; overflow-wrap: anywhere; margin: 0; } #p3xr-console-input { display: block; width: 100%; box-sizing: border-box; font-family: 'Roboto Mono', monospace; resize: none; overflow-y: hidden; outline: none; max-height: 90px; } .p3xr-key-type-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: center; gap: 8px; padding: 4px 8px; } .p3xr-key-type-content { padding: 8px 16px 24px; } .p3xr-key-type-display { padding: 8px; } .p3xr-key-type-editor { width: 100%; } .p3xr-key-type-editor textarea { font-family: 'Roboto Mono', monospace; font-size: 13px; } .p3xr-key-type-buffer-info { padding: 8px; opacity: 0.7; font-style: italic; } .p3xr-json-tree-key { color: var(--p3xr-json-key-color, inherit); } .p3xr-json-tree-value-string { color: var(--p3xr-json-value-string, #0b7500); } .p3xr-json-tree-value-number { color: var(--p3xr-json-value-number, #1a01cc); } .p3xr-json-tree-value-boolean { color: var(--p3xr-json-value-boolean, #c41a16); } .p3xr-json-tree-value-null { color: var(--p3xr-json-value-null, #808080); font-style: italic; } .p3xr-console-hint { font-family: 'Roboto Mono', monospace; font-size: 12px; padding: 2px 6px; opacity: 0.6; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .p3xr-pager-input::-webkit-outer-spin-button, .p3xr-pager-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; } `}, MuiToolbar: { styleOverrides: { root: { minHeight: `${TOOLBAR_HEIGHT}px !important`, height: TOOLBAR_HEIGHT, '& i.fa, & i.fas, & i.far, & i.fab': faIconBase, '& i.fa-power-off': faIconSmaller, '& i.fa-donate': faIconSmaller, }}}, MuiAppBar: { styleOverrides: { root: { backgroundColor: toolbarBg, color: toolbarColor, '& .MuiButton-root': toolbarButtonStyles, '& .MuiIconButton-root': toolbarIconButtonStyles, }}}, } } // Helper to build a theme from exact SCSS hex values interface ThemeColors { mode: 'light' | 'dark' toolbarBg: string toolbarColor: string strongBg: string accordionBg: string accordionColor: string primary: string primaryText: string accent: string // → secondary accentText: string warn: string // → error warnText: string success: string successText: string bodyBg: string contentBg: string dialogBg: string borderColor: string hoverBg: string selectedBg: string linkColor: string inputBorderColor: string inputBg: string inputColor: string treeBranchColor: string commonWarnColor: string treecontrolIconColor: string matSysPrimary: string // M3 system primary from main sub-theme (used for tab indicators) } function buildTheme(c: ThemeColors) { return createTheme({ typography: { fontFamily: "Roboto, 'Helvetica Neue', sans-serif", // Reset letter-spacing to normal (matches Angular's --mat-*-tracking: normal) h1: { letterSpacing: 'normal' }, h2: { letterSpacing: 'normal' }, h3: { letterSpacing: 'normal' }, h4: { letterSpacing: 'normal' }, h5: { letterSpacing: 'normal' }, h6: { letterSpacing: 'normal' }, subtitle1: { letterSpacing: 'normal' }, subtitle2: { letterSpacing: 'normal' }, body1: { letterSpacing: 'normal' }, body2: { letterSpacing: 'normal' }, button: { letterSpacing: 'normal' }, caption: { letterSpacing: 'normal' }, overline: { letterSpacing: 'normal' }, }, p3xr: { accordionBg: c.accordionBg, accordionColor: c.accordionColor, strongBg: c.strongBg, strongColor: 'rgba(255,255,255,0.87)', inputBorderColor: c.inputBorderColor, inputBg: c.inputBg, inputColor: c.inputColor, treeBranchColor: c.treeBranchColor, commonWarnColor: c.commonWarnColor, treecontrolIconColor: c.treecontrolIconColor, matSysPrimary: c.matSysPrimary, }, palette: { mode: c.mode, primary: { main: c.primary, contrastText: c.primaryText }, secondary: { main: c.accent, contrastText: c.accentText }, error: { main: c.warn, contrastText: c.warnText }, success: { main: c.success, contrastText: c.successText }, warning: { main: c.warn, contrastText: c.warnText }, background: { default: c.bodyBg, paper: c.contentBg }, divider: c.mode === 'dark' ? 'rgba(255,255,255,0.12)' : 'rgba(0,0,0,0.12)', action: { hover: c.hoverBg, selected: c.selectedBg }, }, components: { ...makeShared(c.toolbarBg, c.toolbarColor), MuiDialog: { styleOverrides: { paper: { backgroundColor: c.dialogBg, backgroundImage: 'none' } } }, }, }) } // ============================================================ // All 7 themes with exact colors from _theme-custom.scss // ============================================================ export const themes: Record> = { // Enterprise (light) — Layout=grey, Main=indigo/blue/red enterprise: buildTheme({ mode: 'light', toolbarBg: '#424242', toolbarColor: 'rgba(255,255,255,0.87)', strongBg: '#212121', accordionBg: '#9e9e9e', accordionColor: 'rgba(0,0,0,0.87)', primary: '#3f51b5', primaryText: '#fff', accent: '#1976d2', accentText: '#fff', warn: '#d32f2f', warnText: '#fff', success: '#4caf50', successText: '#fff', bodyBg: '#e0e0e0', contentBg: '#fafafa', dialogBg: '#ffffff', borderColor: '#424242', hoverBg: 'rgba(0,0,0,0.1)', selectedBg: 'rgba(0,0,0,0.1)', linkColor: '#1a73e8', inputBorderColor: '#9e9e9e', inputBg: 'white', inputColor: 'black', treeBranchColor: '#343dff', commonWarnColor: '#03a9f4', treecontrolIconColor: 'rgba(0,0,0,0.87)', matSysPrimary: '#005faf', // azure tone 40 }), // Light — Layout=blue-grey, Main=deep-purple/purple/red light: buildTheme({ mode: 'light', toolbarBg: '#37474f', toolbarColor: 'rgba(255,255,255,0.87)', strongBg: '#263238', accordionBg: '#b0bec5', accordionColor: 'rgba(0,0,0,0.87)', primary: '#673ab7', primaryText: '#fff', accent: '#9c27b0', accentText: '#fff', warn: '#d32f2f', warnText: '#fff', success: '#4caf50', successText: '#fff', bodyBg: '#cfd8dc', contentBg: '#eceff1', dialogBg: '#cfd8dc', borderColor: '#37474f', hoverBg: 'rgba(0,0,0,0.1)', selectedBg: 'rgba(0,0,0,0.1)', linkColor: '#1a73e8', inputBorderColor: '#b0bec5', inputBg: 'white', inputColor: 'black', treeBranchColor: '#a900a9', commonWarnColor: '#607d8b', treecontrolIconColor: 'rgba(0,0,0,0.87)', matSysPrimary: '#6750a4', // violet tone 40 }), // Redis (light) — Layout=red, Main=grey/amber redis: buildTheme({ mode: 'light', toolbarBg: '#c62828', toolbarColor: 'rgba(255,255,255,0.87)', strongBg: '#b71c1c', accordionBg: '#ef9a9a', accordionColor: 'rgba(0,0,0,0.87)', primary: '#212121', primaryText: 'rgba(255,255,255,0.87)', accent: '#757575', accentText: '#fff', warn: '#ffc107', warnText: '#fff', success: '#4caf50', successText: '#fff', bodyBg: '#ffcdd2', contentBg: '#fafafa', dialogBg: '#ffffff', borderColor: '#c62828', hoverBg: 'rgba(0,0,0,0.1)', selectedBg: 'rgba(0,0,0,0.1)', linkColor: '#1a73e8', inputBorderColor: '#ef9a9a', inputBg: 'white', inputColor: 'black', treeBranchColor: '#964900', commonWarnColor: '#f44336', treecontrolIconColor: 'rgba(0,0,0,0.87)', matSysPrimary: '#b0294b', // rose tone 40 }), // Dark — Layout=grey, Main=indigo-300/blue/orange dark: buildTheme({ mode: 'dark', toolbarBg: '#424242', toolbarColor: 'rgba(255,255,255,0.87)', strongBg: '#212121', accordionBg: '#9e9e9e', accordionColor: 'rgba(0,0,0,0.87)', primary: '#7986cb', primaryText: 'rgba(0,0,0,0.87)', accent: '#2196f3', accentText: 'rgba(0,0,0,0.87)', warn: '#ff9800', warnText: 'rgba(0,0,0,0.87)', success: '#4caf50', successText: 'rgba(0,0,0,0.87)', bodyBg: '#212121', contentBg: '#303030', dialogBg: '#424242', borderColor: '#424242', hoverBg: 'rgba(255,255,255,0.1)', selectedBg: 'rgba(255,255,255,0.1)', linkColor: '#82b1ff', inputBorderColor: '#9e9e9e', inputBg: 'rgba(64,64,64,1)', inputColor: 'white', treeBranchColor: '#bec2ff', commonWarnColor: '#9fa8da', treecontrolIconColor: 'rgba(255,255,255,0.7)', matSysPrimary: '#9ecaff', // azure tone 80 }), // DarkNeu — Layout=blue-grey, Main=cyan/blue/yellow darkNeu: buildTheme({ mode: 'dark', toolbarBg: '#37474f', toolbarColor: 'rgba(255,255,255,0.87)', strongBg: '#263238', accordionBg: '#90a4ae', accordionColor: 'rgba(0,0,0,0.87)', primary: '#00bcd4', primaryText: 'rgba(0,0,0,0.87)', accent: '#2196f3', accentText: 'rgba(0,0,0,0.87)', warn: '#ffeb3b', warnText: 'rgba(0,0,0,0.87)', success: '#4caf50', successText: 'rgba(0,0,0,0.87)', bodyBg: '#263238', contentBg: '#303030', dialogBg: '#424242', borderColor: '#37474f', hoverBg: 'rgba(255,255,255,0.1)', selectedBg: 'rgba(255,255,255,0.1)', linkColor: '#82b1ff', inputBorderColor: '#90a4ae', inputBg: 'rgba(64,64,64,1)', inputColor: 'white', treeBranchColor: '#bec2ff', commonWarnColor: '#2196f3', treecontrolIconColor: 'rgba(255,255,255,0.7)', matSysPrimary: '#54d7eb', // cyan tone 80 }), // DarkoBluo — Layout=indigo, Main=indigo-300/blue/orange darkoBluo: buildTheme({ mode: 'dark', toolbarBg: '#1a237e', toolbarColor: 'rgba(255,255,255,0.87)', strongBg: '#1a237e', accordionBg: '#3f51b5', accordionColor: '#fff', primary: '#7986cb', primaryText: 'rgba(0,0,0,0.87)', accent: '#2196f3', accentText: 'rgba(0,0,0,0.87)', warn: '#ff9800', warnText: 'rgba(0,0,0,0.87)', success: '#4caf50', successText: 'rgba(0,0,0,0.87)', bodyBg: '#283593', contentBg: '#303030', dialogBg: '#424242', borderColor: '#1a237e', hoverBg: 'rgba(255,255,255,0.1)', selectedBg: 'rgba(255,255,255,0.1)', linkColor: '#82b1ff', inputBorderColor: '#3f51b5', inputBg: 'rgba(64,64,64,1)', inputColor: 'white', treeBranchColor: '#bec2ff', commonWarnColor: '#03a9f4', treecontrolIconColor: 'rgba(255,255,255,0.7)', matSysPrimary: '#cfbcff', // violet tone 80 }), // Matrix — Layout=light-green, Main=light-green/lime/green matrix: buildTheme({ mode: 'dark', toolbarBg: '#76ff03', toolbarColor: 'rgba(0,0,0,0.87)', strongBg: '#33691e', accordionBg: '#76ff03', accordionColor: 'rgba(0,0,0,0.87)', primary: '#76ff03', primaryText: 'rgba(0,0,0,0.87)', accent: '#c6ff00', accentText: 'rgba(0,0,0,0.87)', warn: '#00c853', warnText: 'rgba(0,0,0,0.87)', success: '#76ff03', successText: 'rgba(0,0,0,0.87)', bodyBg: '#1b5e20', contentBg: '#303030', dialogBg: '#424242', borderColor: '#76ff03', hoverBg: 'rgba(255,255,255,0.1)', selectedBg: 'rgba(255,255,255,0.1)', linkColor: '#82b1ff', inputBorderColor: '#76ff03', inputBg: 'rgba(64,64,64,1)', inputColor: 'white', treeBranchColor: '#76ff03', commonWarnColor: '#4caf50', // override: #76ff03 treecontrolIconColor: 'rgba(255,255,255,0.7)', matSysPrimary: '#a1d45b', // chartreuse tone 80 }), } // Dark theme keys for classification export const DARK_THEMES = ['dark', 'darkNeu', 'darkoBluo', 'matrix'] export const LIGHT_THEMES = ['light', 'enterprise', 'redis'] export const ALL_THEME_KEYS = ['light', 'enterprise', 'dark', 'darkNeu', 'darkoBluo', 'matrix', 'redis'] export function isDarkTheme(key: string): boolean { return DARK_THEMES.includes(key) } // For backward compat export const enterpriseTheme = themes.enterprise export const darkTheme = themes.dark