Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -86,12 +86,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
55 changes: 53 additions & 2 deletions frontend/src/app.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@import "tailwindcss";
@import "highlight.js/styles/a11y-light.min.css";

@font-face {
font-family: "Helvetica";
Expand Down Expand Up @@ -41,7 +42,9 @@
}

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 +57,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 +77,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
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
4 changes: 4 additions & 0 deletions frontend/src/elements/MonacoEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useComputedColorScheme } from '@mantine/core';
import { Editor, loader } from '@monaco-editor/react';
import { ComponentProps } from 'react';

Expand All @@ -8,9 +9,12 @@ loader.config({
});

export default function MonacoEditor(props: ComponentProps<typeof Editor>) {
const computedColorScheme = useComputedColorScheme('dark');

return (
<Editor
{...props}
theme={computedColorScheme === 'dark' ? 'vs-dark' : 'light'}
onMount={(e, m) => {
for (const handler of window.extensionContext.extensionRegistry.elements.monacoEditor.onMountHandlers) {
handler(e, m);
Expand Down
14 changes: 7 additions & 7 deletions frontend/src/elements/PermissionSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,18 +111,18 @@ export default function PermissionSelector({

const selectedPanel = (
<Card>
<Title order={3} c='white'>
<Title order={3}>
{t('elements.permissionSelector.selectedPermissions', { count: selectedPermissions.length })}
</Title>
<div className='max-h-96 overflow-y-auto'>
{selectedPermissions.length === 0 ? (
<p className='text-gray-200 text-sm'>{t('elements.permissionSelector.noPermissions', {})}</p>
<p className='text-(--mantine-color-dimmed) text-sm'>{t('elements.permissionSelector.noPermissions', {})}</p>
) : (
<div className='space-y-1'>
{sortedSelectedPermissions.map((permission) => (
<Card key={permission} className='border border-neutral-600' padding='xs'>
<Card key={permission} className='border border-(--mantine-color-default-border)' padding='xs'>
<Group justify='space-between'>
<span className='text-sm font-mono text-white'>{permission}</span>
<span className='text-sm font-mono'>{permission}</span>
<ActionIcon color='red' onClick={() => togglePermission(permission)}>
<FontAwesomeIcon icon={faX} />
</ActionIcon>
Expand Down Expand Up @@ -170,7 +170,7 @@ export default function PermissionSelector({
/>
)}
<div>
<Title order={5} c='white' className='uppercase'>
<Title order={5} className='uppercase'>
{category.replace('-', ' ')}
</Title>
<p className='text-sm text-gray-200 mt-1'>{description}</p>
Expand All @@ -184,9 +184,9 @@ export default function PermissionSelector({
/>
<ActionIcon variant='subtle' onClick={() => toggleCategory(category)}>
{isExpanded ? (
<FontAwesomeIcon icon={faChevronUp} className='w-4 h-4 text-gray-200' />
<FontAwesomeIcon icon={faChevronUp} className='w-4 h-4' />
) : (
<FontAwesomeIcon icon={faChevronDown} className='w-4 h-4 text-gray-200' />
<FontAwesomeIcon icon={faChevronDown} className='w-4 h-4' />
)}
</ActionIcon>
</div>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/elements/ScreenBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ function ScreenBlock({ title, content }: { title: string; content: string }) {
<div className='flex items-center justify-center'>
<Card className='w-full max-w-md text-center'>
<Title order={2}>{title}</Title>
<p className='text-sm text-neutral-700 mt-2'>{content}</p>
<p className='text-sm text-(--mantine-color-dimmed) mt-2'>{content}</p>
</Card>
</div>
</>
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/elements/ServerStatusIndicator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,15 @@ export default function ServerStatusIndicator() {
{socketConnected ? (
<>
<span className={classNames('rounded-full size-4 animate-pulse', statusToColor(state))} />
<span className='font-medium text-white leading-none'>{t(`common.enum.serverState.${state}`, {})}</span>
<span className='font-medium leading-none'>{t(`common.enum.serverState.${state}`, {})}</span>
</>
) : (
<>
<FontAwesomeIcon
icon={faTowerBroadcast}
className={`${socketConnected ? 'animate-pulse text-green-500' : 'text-white'} w-4`}
className={`${socketConnected ? 'animate-pulse text-green-500' : ''} w-4`}
/>
<span className='font-medium text-white leading-none'>
<span className='font-medium leading-none'>
{socketConnected
? t('common.enum.connectionStatus.connected', {})
: t('common.enum.connectionStatus.offline', {})}
Expand Down
18 changes: 14 additions & 4 deletions frontend/src/elements/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ import {
faBars,
faEllipsisVertical,
faGraduationCap,
faMoon,
faSun,
faUserCog,
faWindowRestore,
IconDefinition,
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Menu } from '@mantine/core';
import { Menu, useComputedColorScheme, useMantineColorScheme } from '@mantine/core';
import classNames from 'classnames';
import { ReactNode, useEffect, useState } from 'react';
import { MemoryRouter, matchPath, NavLink, useLocation, useNavigate } from 'react-router';
Expand Down Expand Up @@ -150,7 +152,7 @@ function Link({ to, end, icon, name, title = name, className, activeMatches }: L
<Button
color={isActive ? 'blue' : 'gray'}
className={classNames(isActive && 'cursor-default! active', className)}
variant='subtle'
variant={isActive ? 'outline' : 'subtle'}
fullWidth
styles={{ label: { width: '100%' } }}
>
Expand All @@ -172,15 +174,19 @@ function Footer() {
const { t } = useTranslations();
const { impersonating, user, doLogout } = useAuth();
const navigate = useNavigate();
const { toggleColorScheme } = useMantineColorScheme();
const computedColorScheme = useComputedColorScheme('dark');

if (!user) {
return null;
}

const isDark = computedColorScheme === 'dark';

return (
<>
<div
className='border border-neutral-700 rounded-lg p-2 flex flex-row justify-between items-center min-h-fit'
className='border border-(--mantine-color-default-border) rounded-lg p-2 flex flex-row justify-between items-center min-h-fit'
id='sidebar-account-card'
>
<NavLink
Expand All @@ -196,7 +202,7 @@ function Footer() {
alt={user.username}
className='h-10 w-10 rounded-full select-none shrink-0'
/>
<span className='font-sans font-normal text-sm text-neutral-50 whitespace-nowrap leading-tight ml-3 overflow-hidden text-ellipsis'>
<span className='font-sans font-normal text-sm whitespace-nowrap leading-tight ml-3 overflow-hidden text-ellipsis'>
{user.username}
</span>
</NavLink>
Expand All @@ -221,6 +227,10 @@ function Footer() {
</>
)}
<Menu.Divider />
<Menu.Item leftSection={<FontAwesomeIcon icon={isDark ? faSun : faMoon} />} onClick={toggleColorScheme}>
{isDark ? t('elements.sidebar.button.switchToLight', {}) : t('elements.sidebar.button.switchToDark', {})}
</Menu.Item>
<Menu.Divider />
<Menu.Item leftSection={<FontAwesomeIcon icon={faArrowRightFromBracket} />} color='red' onClick={doLogout}>
{impersonating
? t('elements.sidebar.button.stopImpersonating', {})
Expand Down
Loading
Loading