Skip to content
4 changes: 3 additions & 1 deletion frontend/public/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,9 @@
"stopImpersonating": "Stop Impersonating",
"openInVirtualWindow": "Open in Virtual Window",
"openInPopup": "Open in Popup",
"openInNewTab": "Open in New Tab"
"openInNewTab": "Open in New Tab",
"switchToDark": "Switch to Dark Mode",
"switchToLight": "Switch to Light Mode"
}
},
"permissionSelector": {
Expand Down
9 changes: 2 additions & 7 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MantineProvider, type MantineThemeOverride, v8CssVariablesResolver } from '@mantine/core';
import { MantineProvider, type MantineThemeOverride } from '@mantine/core';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { createBrowserHistory } from 'history';
Expand Down Expand Up @@ -96,12 +96,7 @@ export default function App({ theme }: { theme: MantineThemeOverride }) {

return Object.keys(settings).length > 0 ? (
<ErrorBoundary>
<MantineProvider
theme={theme}
forceColorScheme='dark'
cssVariablesResolver={v8CssVariablesResolver}
deduplicateInlineStyles
>
<MantineProvider theme={theme} defaultColorScheme='dark' deduplicateInlineStyles>
<QueryClientProvider client={queryClient}>
<TranslationProvider>
<ToastProvider>
Expand Down
193 changes: 191 additions & 2 deletions frontend/src/app.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
@import "tailwindcss";
@import "highlight.js/styles/a11y-light.min.css";

@custom-variant dark (&:where([data-mantine-color-scheme="dark"], [data-mantine-color-scheme="dark"] *));
@custom-variant light (&:where([data-mantine-color-scheme="light"], [data-mantine-color-scheme="light"] *));

@font-face {
font-family: "Helvetica";
Expand Down Expand Up @@ -40,8 +44,145 @@
}
}

:root[data-mantine-color-scheme="light"] {
--mantine-color-body: #f0eff0;
}

:root[data-mantine-color-scheme="dark"] {
--mantine-color-anchor: var(--mantine-color-blue-4);
--mantine-color-blue-filled: var(--mantine-color-blue-8);
--mantine-color-blue-filled-hover: var(--mantine-color-blue-9);
--mantine-color-blue-light: rgba(34, 139, 230, 0.15);
--mantine-color-blue-light-color: var(--mantine-color-blue-3);
--mantine-color-blue-light-hover: rgba(34, 139, 230, 0.2);
--mantine-color-blue-outline: var(--mantine-color-blue-4);
--mantine-color-blue-outline-hover: rgba(77, 171, 247, 0.05);
--mantine-color-blue-text: var(--mantine-color-blue-4);
--mantine-color-body: var(--mantine-color-dark-7);
--mantine-color-bright: var(--mantine-color-white);
--mantine-color-cyan-filled: var(--mantine-color-cyan-8);
--mantine-color-cyan-filled-hover: var(--mantine-color-cyan-9);
--mantine-color-cyan-light: rgba(21, 170, 191, 0.15);
--mantine-color-cyan-light-color: var(--mantine-color-cyan-3);
--mantine-color-cyan-light-hover: rgba(21, 170, 191, 0.2);
--mantine-color-cyan-outline: var(--mantine-color-cyan-4);
--mantine-color-cyan-outline-hover: rgba(59, 201, 219, 0.05);
--mantine-color-cyan-text: var(--mantine-color-cyan-4);
--mantine-color-dark-filled: var(--mantine-color-dark-8);
--mantine-color-dark-filled-hover: var(--mantine-color-dark-9);
--mantine-color-dark-light: rgba(46, 46, 46, 0.15);
--mantine-color-dark-light-color: var(--mantine-color-dark-3);
--mantine-color-dark-light-hover: rgba(46, 46, 46, 0.2);
--mantine-color-dark-outline: var(--mantine-color-dark-4);
--mantine-color-dark-outline-hover: rgba(66, 66, 66, 0.05);
--mantine-color-dark-text: var(--mantine-color-dark-4);
--mantine-color-default: var(--mantine-color-dark-6);
--mantine-color-default-border: var(--mantine-color-dark-4);
--mantine-color-default-color: var(--mantine-color-white);
--mantine-color-default-hover: var(--mantine-color-dark-5);
--mantine-color-dimmed: var(--mantine-color-dark-2);
--mantine-color-disabled: var(--mantine-color-dark-6);
--mantine-color-disabled-border: var(--mantine-color-dark-4);
--mantine-color-disabled-color: var(--mantine-color-dark-3);
--mantine-color-error: var(--mantine-color-red-8);
--mantine-color-grape-filled: var(--mantine-color-grape-8);
--mantine-color-grape-filled-hover: var(--mantine-color-grape-9);
--mantine-color-grape-light: rgba(190, 75, 219, 0.15);
--mantine-color-grape-light-color: var(--mantine-color-grape-3);
--mantine-color-grape-light-hover: rgba(190, 75, 219, 0.2);
--mantine-color-grape-outline: var(--mantine-color-grape-4);
--mantine-color-grape-outline-hover: rgba(218, 119, 242, 0.05);
--mantine-color-grape-text: var(--mantine-color-grape-4);
--mantine-color-gray-filled: var(--mantine-color-gray-8);
--mantine-color-gray-filled-hover: var(--mantine-color-gray-9);
--mantine-color-gray-light: rgba(134, 142, 150, 0.15);
--mantine-color-gray-light-color: var(--mantine-color-gray-3);
--mantine-color-gray-light-hover: rgba(134, 142, 150, 0.2);
--mantine-color-gray-outline: var(--mantine-color-gray-4);
--mantine-color-gray-outline-hover: rgba(206, 212, 218, 0.05);
--mantine-color-gray-text: var(--mantine-color-gray-4);
--mantine-color-green-filled: var(--mantine-color-green-8);
--mantine-color-green-filled-hover: var(--mantine-color-green-9);
--mantine-color-green-light: rgba(64, 192, 87, 0.15);
--mantine-color-green-light-color: var(--mantine-color-green-3);
--mantine-color-green-light-hover: rgba(64, 192, 87, 0.2);
--mantine-color-green-outline: var(--mantine-color-green-4);
--mantine-color-green-outline-hover: rgba(105, 219, 124, 0.05);
--mantine-color-green-text: var(--mantine-color-green-4);
--mantine-color-indigo-filled: var(--mantine-color-indigo-8);
--mantine-color-indigo-filled-hover: var(--mantine-color-indigo-9);
--mantine-color-indigo-light: rgba(76, 110, 245, 0.15);
--mantine-color-indigo-light-color: var(--mantine-color-indigo-3);
--mantine-color-indigo-light-hover: rgba(76, 110, 245, 0.2);
--mantine-color-indigo-outline: var(--mantine-color-indigo-4);
--mantine-color-indigo-outline-hover: rgba(116, 143, 252, 0.05);
--mantine-color-indigo-text: var(--mantine-color-indigo-4);
--mantine-color-lime-filled: var(--mantine-color-lime-8);
--mantine-color-lime-filled-hover: var(--mantine-color-lime-9);
--mantine-color-lime-light: rgba(130, 201, 30, 0.15);
--mantine-color-lime-light-color: var(--mantine-color-lime-3);
--mantine-color-lime-light-hover: rgba(130, 201, 30, 0.2);
--mantine-color-lime-outline: var(--mantine-color-lime-4);
--mantine-color-lime-outline-hover: rgba(169, 227, 75, 0.05);
--mantine-color-lime-text: var(--mantine-color-lime-4);
--mantine-color-orange-filled: var(--mantine-color-orange-8);
--mantine-color-orange-filled-hover: var(--mantine-color-orange-9);
--mantine-color-orange-light: rgba(253, 126, 20, 0.15);
--mantine-color-orange-light-color: var(--mantine-color-orange-3);
--mantine-color-orange-light-hover: rgba(253, 126, 20, 0.2);
--mantine-color-orange-outline: var(--mantine-color-orange-4);
--mantine-color-orange-outline-hover: rgba(255, 169, 77, 0.05);
--mantine-color-orange-text: var(--mantine-color-orange-4);
--mantine-color-pink-filled: var(--mantine-color-pink-8);
--mantine-color-pink-filled-hover: var(--mantine-color-pink-9);
--mantine-color-pink-light: rgba(230, 73, 128, 0.15);
--mantine-color-pink-light-color: var(--mantine-color-pink-3);
--mantine-color-pink-light-hover: rgba(230, 73, 128, 0.2);
--mantine-color-pink-outline: var(--mantine-color-pink-4);
--mantine-color-pink-outline-hover: rgba(247, 131, 172, 0.05);
--mantine-color-pink-text: var(--mantine-color-pink-4);
--mantine-color-placeholder: var(--mantine-color-dark-3);
--mantine-color-red-filled: var(--mantine-color-red-8);
--mantine-color-red-filled-hover: var(--mantine-color-red-9);
--mantine-color-red-light: rgba(250, 82, 82, 0.15);
--mantine-color-red-light-color: var(--mantine-color-red-3);
--mantine-color-red-light-hover: rgba(250, 82, 82, 0.2);
--mantine-color-red-outline: var(--mantine-color-red-4);
--mantine-color-red-outline-hover: rgba(255, 135, 135, 0.05);
--mantine-color-red-text: var(--mantine-color-red-4);
--mantine-color-scheme: dark;
--mantine-color-teal-filled: var(--mantine-color-teal-8);
--mantine-color-teal-filled-hover: var(--mantine-color-teal-9);
--mantine-color-teal-light: rgba(18, 184, 134, 0.15);
--mantine-color-teal-light-color: var(--mantine-color-teal-3);
--mantine-color-teal-light-hover: rgba(18, 184, 134, 0.2);
--mantine-color-teal-outline: var(--mantine-color-teal-4);
--mantine-color-teal-outline-hover: rgba(56, 217, 169, 0.05);
--mantine-color-teal-text: var(--mantine-color-teal-4);
--mantine-color-text: var(--mantine-color-dark-0);
--mantine-color-violet-filled: var(--mantine-color-violet-8);
--mantine-color-violet-filled-hover: var(--mantine-color-violet-9);
--mantine-color-violet-light: rgba(121, 80, 242, 0.15);
--mantine-color-violet-light-color: var(--mantine-color-violet-3);
--mantine-color-violet-light-hover: rgba(121, 80, 242, 0.2);
--mantine-color-violet-outline: var(--mantine-color-violet-4);
--mantine-color-violet-outline-hover: rgba(151, 117, 250, 0.05);
--mantine-color-violet-text: var(--mantine-color-violet-4);
--mantine-color-yellow-filled: var(--mantine-color-yellow-8);
--mantine-color-yellow-filled-hover: var(--mantine-color-yellow-9);
--mantine-color-yellow-light: rgba(250, 176, 5, 0.15);
--mantine-color-yellow-light-color: var(--mantine-color-yellow-3);
--mantine-color-yellow-light-hover: rgba(250, 176, 5, 0.2);
--mantine-color-yellow-outline: var(--mantine-color-yellow-4);
--mantine-color-yellow-outline-hover: rgba(255, 212, 59, 0.05);
--mantine-color-yellow-text: var(--mantine-color-yellow-4);
--mantine-primary-color-contrast: var(--mantine-color-white);
}

body {
@apply font-sans bg-neutral-850 text-neutral-200;
@apply font-sans;
background-color: var(--mantine-color-body);
color: var(--mantine-color-text);
}

h1,
Expand All @@ -54,7 +195,8 @@ h6 {
}

p {
@apply text-neutral-200 leading-snug font-sans;
@apply leading-snug font-sans;
color: var(--mantine-color-text);
}

form {
Expand All @@ -73,3 +215,50 @@ button:focus-visible {
strong {
@apply font-semibold;
}

[data-mantine-color-scheme="dark"] {
.hljs {
background: #2b2b2b;
color: #f8f8f2;
}
.hljs-comment,
.hljs-quote {
color: #d4d0ab;
}
.hljs-deletion,
.hljs-name,
.hljs-regexp,
.hljs-selector-class,
.hljs-selector-id,
.hljs-tag,
.hljs-template-variable,
.hljs-variable {
color: #ffa07a;
}
.hljs-built_in,
.hljs-link,
.hljs-literal,
.hljs-meta,
.hljs-number,
.hljs-params,
.hljs-type {
color: #f5ab35;
}
.hljs-attribute {
color: gold;
}
.hljs-addition,
.hljs-bullet,
.hljs-string,
.hljs-symbol {
color: #abe338;
}
.hljs-section,
.hljs-title {
color: #00e0e0;
}
.hljs-keyword,
.hljs-selector-tag {
color: #dcc6e0;
}
}
2 changes: 1 addition & 1 deletion frontend/src/elements/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>(
style={{
cursor: loading ? 'wait' : undefined,
fontWeight: 'normal',
border: disabled ? '1px solid var(--mantine-color-dark-4)' : undefined,
border: disabled ? '1px solid var(--mantine-color-default-border)' : undefined,
color: disabled ? 'var(--mantine-color-dimmed)' : undefined,
...rest.style,
}}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/elements/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const Card = forwardRef<HTMLDivElement, CardProps & ComponentProps<'div'>>(
className={classNames(
'relative',
className,
hoverable && 'transition-all! duration-190 hover:border-white/25! cursor-pointer',
hoverable && 'transition-all! duration-190 hover:border-(--mantine-color-default-border)/20! cursor-pointer',
)}
pl={typeof pl === 'number' && leftStripeClassName ? pl + 4 : leftStripeClassName ? 20 : pl}
radius='md'
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/elements/CollapsibleSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ function CollapsibleSection({ icon, title, className, enabled, onToggle, childre
<Box
className={className}
style={{
background: enabled ? 'var(--mantine-color-dark-6)' : 'transparent',
border: `1px solid ${enabled ? 'var(--mantine-color-dark-4)' : 'var(--mantine-color-dark-5)'}`,
background: enabled ? 'var(--mantine-color-default)' : 'transparent',
border: `1px solid var(--mantine-color-default-border)`,
borderRadius: 8,
overflow: 'hidden',
transition: 'all 0.15s ease',
Expand All @@ -42,14 +42,14 @@ function CollapsibleSection({ icon, title, className, enabled, onToggle, childre
alignItems: 'center',
justifyContent: 'center',
borderRadius: 6,
background: enabled ? 'var(--mantine-color-blue-9)' : 'var(--mantine-color-dark-5)',
background: enabled ? 'var(--mantine-color-blue-9)' : 'var(--mantine-color-default-hover)',
color: enabled ? 'var(--mantine-color-blue-2)' : 'var(--mantine-color-gray-5)',
transition: 'background 0.15s ease',
}}
>
{icon}
</Box>
<Text size='sm' fw={500} c={enabled ? 'gray.2' : 'gray.5'} style={{ flex: 1, textAlign: 'left' }}>
<Text size='sm' fw={500} c={enabled ? undefined : 'dimmed'} style={{ flex: 1, textAlign: 'left' }}>
{title}
</Text>
<FontAwesomeIcon
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/elements/Copyright.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Anchor from '@/elements/Anchor.tsx';

export default function Copyright({ className }: { className?: string }) {
return (
<div className={classNames('flex flex-col text-xs transition-all text-gray-400', className)}>
<div className={classNames('flex flex-col text-xs transition-all text-(--mantine-color-dimmed)', className)}>
{window.extensionContext.extensionRegistry.elements.copyright.prependedComponents.map((Component, index) => (
<Component key={`global-copyright-prepended-${index}`} />
))}
Expand Down
12 changes: 6 additions & 6 deletions frontend/src/elements/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,17 @@ class ErrorBoundary extends Component<Props, State> {
<div className='flex justify-center mb-4'>
<button
onClick={() => window.location.reload()}
className='px-4 py-2 text-sm font-medium rounded-md bg-neutral-700 hover:bg-neutral-600 text-neutral-100 transition-colors'
className='px-4 py-2 text-sm font-medium rounded-md bg-(--mantine-color-default) hover:bg-(--mantine-color-default-hover) border border-(--mantine-color-default-border) transition-colors'
>
Refresh page
</button>
</div>

{error && appDebug && (
<div className='mt-2 border bg-neutral-800 border-neutral-700/60 rounded-lg overflow-hidden'>
<div className='mt-2 border bg-(--mantine-color-default) border-(--mantine-color-default-border) rounded-lg overflow-hidden'>
<button
onClick={this.toggleDetails}
className='w-full flex items-center justify-between px-4 py-3 text-xs text-neutral-400 hover:text-neutral-200 hover:bg-neutral-800/50 transition-colors'
className='w-full flex items-center justify-between px-4 py-3 text-xs text-(--mantine-color-dimmed) hover:bg-(--mantine-color-default-hover) transition-colors'
>
<span className='font-medium tracking-wide uppercase'>
{showDetails
Expand All @@ -88,7 +88,7 @@ class ErrorBoundary extends Component<Props, State> {
<p className='text-xs font-semibold text-red-400 mb-1'>
{this.context?.t('elements.errorBoundary.errorMessage', {}) || 'Error Message:'}
</p>
<pre className='text-xs text-neutral-300 whitespace-pre-wrap wrap-break-word bg-neutral-950 p-2 rounded'>
<pre className='text-xs whitespace-pre-wrap wrap-break-word bg-(--mantine-color-default-hover) p-2 rounded'>
{error.message || this.context?.t('common.na', {}) || 'N/A'}
</pre>
</div>
Expand All @@ -98,7 +98,7 @@ class ErrorBoundary extends Component<Props, State> {
<p className='text-xs font-semibold text-red-400 mb-1'>
{this.context?.t('elements.errorBoundary.stackTrace', {}) || 'Stack Trace:'}
</p>
<pre className='text-xs text-neutral-300 whitespace-pre-wrap wrap-break-word bg-neutral-950 p-2 rounded overflow-x-auto'>
<pre className='text-xs whitespace-pre-wrap wrap-break-word bg-(--mantine-color-default-hover) p-2 rounded overflow-x-auto'>
{error.stack}
</pre>
</div>
Expand All @@ -109,7 +109,7 @@ class ErrorBoundary extends Component<Props, State> {
<p className='text-xs font-semibold text-red-400 mb-1'>
{this.context?.t('elements.errorBoundary.componentStack', {}) || 'Component Stack:'}
</p>
<pre className='text-xs text-neutral-300 whitespace-pre-wrap wrap-break-word bg-neutral-950 p-2 rounded overflow-x-auto'>
<pre className='text-xs whitespace-pre-wrap wrap-break-word bg-(--mantine-color-default-hover) p-2 rounded overflow-x-auto'>
{errorInfo.componentStack}
</pre>
</div>
Expand Down
3 changes: 1 addition & 2 deletions frontend/src/elements/HljsCode.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { LanguageFn } from 'highlight.js';
import hljs from 'highlight.js/lib/core';
import { forwardRef, useCallback, useEffect, useState } from 'react';
import 'highlight.js/styles/a11y-dark.min.css';
import { LanguageFn } from 'highlight.js';
import Spinner from '@/elements/Spinner.tsx';
import Code from './Code.tsx';

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/elements/KbdKey.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function KbdKey({ children, className, icon }: KbdKeyProps) {
return (
<div
className={classNames(
'inline-flex items-center justify-center w-11 h-8 bg-linear-to-b from-(--mantine-color-dark-5) to-(--mantine-color-dark-6) border border-(--mantine-color-dark-4) rounded-md shadow-[0_2px_0_var(--mantine-color-dark-7),inset_0_1px_0_rgba(255,255,255,0.05)] text-xs font-semibold font-sans text-(--mantine-color-gray-3) uppercase tracking-[0.02em]',
'inline-flex items-center justify-center w-11 h-8 bg-linear-to-b from-(--mantine-color-default-hover) to-(--mantine-color-default) border border-(--mantine-color-default-border) rounded-md shadow-[0_2px_0_var(--mantine-color-default-border),inset_0_1px_0_rgba(255,255,255,0.05)] text-xs font-semibold font-sans text-(--mantine-color-text) uppercase tracking-[0.02em]',
className,
)}
>
Expand Down
Loading