fix: reverse Toolbox header orientation
This commit is contained in:
@@ -39,7 +39,7 @@ describe('portal UI', () => {
|
||||
).toHaveAttribute('rel', 'noopener noreferrer');
|
||||
expect(
|
||||
sourceLinks.find((link) =>
|
||||
link.getAttribute('href')?.endsWith('/toolbox-portal/src/tag/v0.4.1')
|
||||
link.getAttribute('href')?.endsWith('/toolbox-portal/src/tag/v0.4.2')
|
||||
)
|
||||
).toBeDefined();
|
||||
expect(
|
||||
@@ -229,16 +229,33 @@ describe('portal UI', () => {
|
||||
const brand = within(header).getByRole('link', {
|
||||
name: 'add·ideas Toolbox',
|
||||
});
|
||||
const controls = within(header).getByRole('group', {
|
||||
name: 'Toolbox controls',
|
||||
});
|
||||
expect(
|
||||
personalize.compareDocumentPosition(apps) &
|
||||
Node.DOCUMENT_POSITION_FOLLOWING
|
||||
).toBeTruthy();
|
||||
Array.from(controls.children, (element) =>
|
||||
element.getAttribute('aria-label')
|
||||
)
|
||||
).toEqual(['Help', 'Toolbox source on Gitea', 'Apps', 'Personalize']);
|
||||
expect(help.compareDocumentPosition(source)).toBe(
|
||||
Node.DOCUMENT_POSITION_FOLLOWING
|
||||
);
|
||||
expect(source.compareDocumentPosition(apps)).toBe(
|
||||
Node.DOCUMENT_POSITION_FOLLOWING
|
||||
);
|
||||
expect(apps.compareDocumentPosition(personalize)).toBe(
|
||||
Node.DOCUMENT_POSITION_FOLLOWING
|
||||
);
|
||||
expect(
|
||||
apps.compareDocumentPosition(source) & Node.DOCUMENT_POSITION_FOLLOWING
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
source.compareDocumentPosition(help) & Node.DOCUMENT_POSITION_FOLLOWING
|
||||
).toBeTruthy();
|
||||
Array.from(
|
||||
header.querySelector('.toolbox-shell__bar')?.children ?? [],
|
||||
(element) => element.className
|
||||
)
|
||||
).toEqual([
|
||||
'toolbox-shell__brand',
|
||||
'toolbox-shell__identity',
|
||||
'toolbox-shell__controls',
|
||||
]);
|
||||
expect(brand.querySelector('img')).toHaveAttribute('src', './favicon.svg');
|
||||
});
|
||||
|
||||
@@ -412,6 +429,13 @@ describe('portal UI', () => {
|
||||
});
|
||||
const popover = screen.getByRole('dialog', { name: 'Personalize Toolbox' });
|
||||
expect(popover).toContainElement(heading);
|
||||
expect(popover).toContainElement(screen.getByText('On this device'));
|
||||
expect(
|
||||
within(popover).getByRole('group', { name: 'Appearance' })
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
popover.querySelector('.toolbox-shell__preferences-content')
|
||||
).toBeInTheDocument();
|
||||
expect(popover).not.toHaveAttribute('aria-modal');
|
||||
expect(container.querySelector('.site-shell')).not.toHaveAttribute('inert');
|
||||
expect(screen.getByText(/does not transmit them/i)).toHaveTextContent(
|
||||
|
||||
@@ -473,9 +473,9 @@ export default function App() {
|
||||
</span>
|
||||
</p>
|
||||
<span>
|
||||
Portal v0.2.1 ·{' '}
|
||||
Portal v0.2.2 ·{' '}
|
||||
<a
|
||||
href="https://git.add-ideas.de/zemion/toolbox-portal/src/tag/v0.4.1"
|
||||
href="https://git.add-ideas.de/zemion/toolbox-portal/src/tag/v0.4.2"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useRef, useState, type ChangeEvent } from 'react';
|
||||
import { ToolboxPersonalizePanel } from '@add-ideas/toolbox-shell-react';
|
||||
import {
|
||||
defaultPreferences,
|
||||
parsePreferences,
|
||||
type Preferences,
|
||||
} from '../preferences';
|
||||
import type { ThemeMode } from '../types';
|
||||
|
||||
interface PreferencesPanelProps {
|
||||
preferences: Preferences;
|
||||
@@ -20,10 +20,6 @@ export function PreferencesPanel({
|
||||
const fileInput = useRef<HTMLInputElement>(null);
|
||||
const [message, setMessage] = useState('');
|
||||
|
||||
function setTheme(theme: ThemeMode) {
|
||||
onChange({ ...preferences, theme });
|
||||
}
|
||||
|
||||
function exportPreferences() {
|
||||
const blob = new Blob([`${JSON.stringify(preferences, null, 2)}\n`], {
|
||||
type: 'application/json',
|
||||
@@ -55,39 +51,11 @@ export function PreferencesPanel({
|
||||
}
|
||||
|
||||
return (
|
||||
<section
|
||||
className="preferences-content"
|
||||
aria-labelledby="preferences-title"
|
||||
<ToolboxPersonalizePanel
|
||||
theme={preferences.theme}
|
||||
onThemeChange={(theme) => onChange({ ...preferences, theme })}
|
||||
storageAvailable={storageAvailable}
|
||||
>
|
||||
<div className="preferences-heading">
|
||||
<p className="preferences-kicker">On this device</p>
|
||||
<h2 id="preferences-title">Personalize your toolbox</h2>
|
||||
</div>
|
||||
|
||||
{!storageAvailable && (
|
||||
<p className="inline-warning" role="status">
|
||||
Browser storage is unavailable. Changes will last only until this page
|
||||
closes.
|
||||
</p>
|
||||
)}
|
||||
|
||||
<fieldset className="theme-choice">
|
||||
<legend>Appearance</legend>
|
||||
<div>
|
||||
{(['system', 'light', 'dark'] as const).map((theme) => (
|
||||
<button
|
||||
key={theme}
|
||||
type="button"
|
||||
aria-pressed={preferences.theme === theme}
|
||||
className={preferences.theme === theme ? 'is-selected' : ''}
|
||||
onClick={() => setTheme(theme)}
|
||||
>
|
||||
{theme.slice(0, 1).toLocaleUpperCase() + theme.slice(1)}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div className="preference-summary">
|
||||
<div>
|
||||
<strong>{preferences.pinned.length}</strong>
|
||||
@@ -139,6 +107,6 @@ export function PreferencesPanel({
|
||||
<p className="action-message" role="status" aria-live="polite">
|
||||
{message}
|
||||
</p>
|
||||
</section>
|
||||
</ToolboxPersonalizePanel>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -690,38 +690,6 @@ main {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.portal-header .toolbox-shell__personalize-popover {
|
||||
width: min(26rem, calc(100vw - 1.5rem));
|
||||
max-height: calc(100vh - 5.5rem);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.preferences-content {
|
||||
padding: 0.35rem;
|
||||
color: var(--toolbox-text, var(--text));
|
||||
}
|
||||
|
||||
.preferences-heading {
|
||||
margin-bottom: 0.9rem;
|
||||
}
|
||||
|
||||
.preferences-content h2 {
|
||||
margin: 0;
|
||||
font-family: Inter, Avenir, 'Segoe UI', sans-serif;
|
||||
font-size: 1rem;
|
||||
letter-spacing: -0.025em;
|
||||
}
|
||||
|
||||
.portal-header .preferences-kicker {
|
||||
margin: 0 0 0.3rem;
|
||||
padding: 0;
|
||||
color: var(--toolbox-accent, var(--brand));
|
||||
font-size: 0.68rem;
|
||||
font-weight: 750;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.help-steps {
|
||||
display: grid;
|
||||
gap: 0.85rem;
|
||||
@@ -750,44 +718,6 @@ main {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.theme-choice {
|
||||
margin: 1rem 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.theme-choice legend {
|
||||
margin-bottom: 0.6rem;
|
||||
color: var(--muted);
|
||||
font-size: 0.78rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.theme-choice > div {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 0.45rem;
|
||||
padding: 0.35rem;
|
||||
border-radius: 0.75rem;
|
||||
background: var(--surface-soft);
|
||||
}
|
||||
|
||||
.theme-choice button {
|
||||
padding: 0.62rem;
|
||||
border: 0;
|
||||
border-radius: 0.5rem;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.theme-choice button.is-selected {
|
||||
background: var(--surface);
|
||||
color: var(--brand);
|
||||
box-shadow: 0 2px 8px rgba(20, 30, 60, 0.09);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.preference-summary {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
@@ -846,15 +776,6 @@ main {
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
|
||||
.portal-header .inline-warning {
|
||||
margin: 0 0 0.75rem;
|
||||
padding: 0.7rem 0.8rem;
|
||||
border-radius: 0.6rem;
|
||||
background: color-mix(in srgb, var(--danger) 8%, var(--surface));
|
||||
color: var(--danger);
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
|
||||
.visually-hidden {
|
||||
position: absolute !important;
|
||||
width: 1px !important;
|
||||
|
||||
@@ -7,7 +7,7 @@ export const pdfManifest: ToolboxAppManifest = {
|
||||
schemaVersion: 1,
|
||||
id: 'de.add-ideas.pdf-tools',
|
||||
name: 'PDF Workbench',
|
||||
version: '0.4.1',
|
||||
version: '0.4.2',
|
||||
description: 'Page-level PDF operations performed locally in the browser.',
|
||||
entry: './',
|
||||
icon: './favicon.svg',
|
||||
@@ -39,7 +39,7 @@ export const xsltManifest: ToolboxAppManifest = {
|
||||
...pdfManifest,
|
||||
id: 'de.add-ideas.xslt-tools',
|
||||
name: 'XSLT Workbench',
|
||||
version: '0.4.1',
|
||||
version: '0.4.2',
|
||||
description: 'Transform XML locally with XSLT in the browser.',
|
||||
icon: './xslt.svg',
|
||||
categories: ['documents', 'developer'],
|
||||
@@ -54,7 +54,7 @@ export const onenoteManifest: ToolboxAppManifest = {
|
||||
...pdfManifest,
|
||||
id: 'de.add-ideas.onenote-tools',
|
||||
name: 'OneNote Reader',
|
||||
version: '0.3.1',
|
||||
version: '0.3.2',
|
||||
description: 'Inspect OneNote packages locally in the browser.',
|
||||
icon: './onenote.svg',
|
||||
categories: ['documents', 'notes'],
|
||||
|
||||
Reference in New Issue
Block a user