beacon / frontend /src /components /DisplayMenu.jsx
kiyer's picture
feat: retrieved-works preference, text input, beacon rename
fd666e2
Raw
History Blame Contribute Delete
4.53 kB
import React from 'react';
// DisplayMenu — display preferences popover.
// Mirrors AnnotatorPanel chrome: ap-pop-backdrop + ap-settings panel.
// Controls four settings exposed to the user:
// 1. Palette (three swatch chips)
// 2. Body size (range slider)
// 3. Justify (checkbox)
// 4. Notes side (two chips: left / right)
//
// All other tweak fields (dropCaps, showScores) are preserved in the parent
// tweaks object but not exposed here.
export const PALETTES = [
{ label: 'Parchment', value: ['#f6f1e6', '#2b2418', '#9a3b20'] },
{ label: 'Ivory', value: ['#fbf8f1', '#231f17', '#8a5a18'] },
{ label: 'Chalk', value: ['#f3f2ee', '#22241f', '#3f5a96'] },
];
export default function DisplayMenu({ tweaks, onChange, onClose }) {
const set = (patch) => onChange({ ...tweaks, ...patch });
React.useEffect(() => {
const onKey = (e) => { if (e.key === 'Escape') onClose(); };
window.addEventListener('keydown', onKey);
return () => window.removeEventListener('keydown', onKey);
}, [onClose]);
// Determine which palette is active by matching all three colour values.
const activePalIdx = PALETTES.findIndex(
(p) =>
p.value[0] === tweaks.paperPalette[0] &&
p.value[1] === tweaks.paperPalette[1] &&
p.value[2] === tweaks.paperPalette[2],
);
return (
<div>
<div className="ap-pop-backdrop" onClick={onClose}></div>
<div className="ap-settings" data-screen-label="Display settings">
<div className="ap-settings-title">Display</div>
<div className="ap-settings-sub">paper, type, and margin layout</div>
{/* Palette */}
<div className="ap-field">
<label className="ap-field-label">Palette</label>
<div className="ap-provider-row">
{PALETTES.map((pal, i) => (
<button
key={pal.label}
className={'ap-provider' + (activePalIdx === i ? ' is-active' : '')}
onClick={() => set({ paperPalette: pal.value })}
title={pal.value.join(' · ')}
style={{
background: activePalIdx === i ? undefined : pal.value[0],
color: activePalIdx === i ? undefined : pal.value[1],
borderColor: activePalIdx === i ? undefined : pal.value[1] + '44',
}}
>
{pal.label}
</button>
))}
</div>
</div>
{/* Body size */}
<div className="ap-field">
<label className="ap-field-label">
Body size &mdash; {tweaks.bodySize}px
</label>
<input
type="range"
min={16}
max={23}
step={0.5}
value={tweaks.bodySize}
onChange={(e) => set({ bodySize: Number(e.target.value) })}
style={{ width: '100%', marginTop: '6px' }}
/>
</div>
{/* Retrieved works */}
<div className="ap-field">
<label className="ap-field-label">
Retrieved works &mdash; {tweaks.litCount ?? 3}
</label>
<input
type="range"
min={3}
max={10}
step={1}
value={tweaks.litCount ?? 3}
onChange={(e) => set({ litCount: Number(e.target.value) })}
style={{ width: '100%', marginTop: '6px' }}
/>
</div>
{/* Justify */}
<div className="ap-field">
<label className="ap-field-label" style={{ display: 'flex', alignItems: 'center', gap: '8px', cursor: 'pointer' }}>
<input
type="checkbox"
checked={tweaks.justify}
onChange={(e) => set({ justify: e.target.checked })}
/>
Justified text
</label>
</div>
{/* Notes side */}
<div className="ap-field">
<label className="ap-field-label">Notes side</label>
<div className="ap-provider-row">
{['right', 'left'].map((side) => (
<button
key={side}
className={'ap-provider' + (tweaks.notesSide === side ? ' is-active' : '')}
onClick={() => set({ notesSide: side })}
>
{side}
</button>
))}
</div>
</div>
<div className="ap-settings-foot">
<button className="ap-textbtn" onClick={onClose}>done</button>
</div>
</div>
</div>
);
}