mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-18 21:54:09 +00:00
fix(teleprompter): larger text, a cue triangle and a corner close
Follow-up to the review pass: - 40px was too small once it was on a screen. 52px over the 1.3 line height keeps most of the density win, at 16 lines on a 1080p screen against the 11 the original defaults gave. - The speed follows the text size, since a larger font puts fewer words on a line. 14 lines per minute measures at 136 wpm on the new defaults, where 12 had dropped to 116. - The reading indicator is a triangle pointing in at the line rather than a bar. It is the shape prompter cue indicators have settled on: it names the line from the margin without putting a mark near the words. - The help dialog closes from an x in its corner, as the navigation menu and the params editor already do, rather than from a button under the list. - Teleprompter sits above Project Info in the navigation menu. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Cb8RVPNQ2ETPJxdy4b8CHf
This commit is contained in:
@@ -4,8 +4,8 @@ export const navigatorConstants = [
|
||||
{ url: 'timeline', label: 'Timeline' },
|
||||
{ url: 'studio', label: 'Studio Clock' },
|
||||
{ url: 'countdown', label: 'Countdown' },
|
||||
{ url: 'info', label: 'Project Info' },
|
||||
{ url: 'teleprompter', label: 'Teleprompter' },
|
||||
{ url: 'info', label: 'Project Info' },
|
||||
];
|
||||
|
||||
// default time format to use for users in 12 hour clocks
|
||||
|
||||
@@ -151,15 +151,22 @@
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* A triangle pointing in at the line, which is the shape prompter cue
|
||||
* indicators have settled on: it names one line without touching the words,
|
||||
* and it reads as a pointer from the edge rather than as punctuation in the
|
||||
* script. Clipped from a filled box rather than built from borders so its
|
||||
* height stays tied to the parent's single line.
|
||||
*/
|
||||
.teleprompter__reading-marker {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
/* sits in the gutter beside the column, never over the words */
|
||||
right: calc(100% + 0.4em);
|
||||
width: 0.16em;
|
||||
border-radius: 0.08em;
|
||||
right: calc(100% + 0.35em);
|
||||
width: 0.45em;
|
||||
background: $accent-color;
|
||||
clip-path: polygon(0 0, 100% 50%, 0 100%);
|
||||
font-size: var(--tp-font-size);
|
||||
}
|
||||
|
||||
@@ -238,10 +245,17 @@
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.teleprompter__help-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.teleprompter__help-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.teleprompter__help-groups {
|
||||
@@ -297,7 +311,3 @@
|
||||
color: $viewer-label-color;
|
||||
font-size: calc(1rem - 5px);
|
||||
}
|
||||
|
||||
.teleprompter__help-close {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ describe('getOptionsFromParams()', () => {
|
||||
showGroups: true,
|
||||
speed: DEFAULT_SPEED,
|
||||
followLoaded: true,
|
||||
fontSize: 40,
|
||||
fontSize: 52,
|
||||
lineHeight: 1.3,
|
||||
textWidth: 80,
|
||||
dimPast: true,
|
||||
@@ -60,7 +60,7 @@ describe('getOptionsFromParams()', () => {
|
||||
// Number(null) is 0, so a naive parse would silently produce a speed of zero
|
||||
expect(getOptionsFromParams(new URLSearchParams('speed=fast')).speed).toBe(DEFAULT_SPEED);
|
||||
expect(getOptionsFromParams(new URLSearchParams('speed=')).speed).toBe(DEFAULT_SPEED);
|
||||
expect(getOptionsFromParams(new URLSearchParams('fontSize=huge')).fontSize).toBe(40);
|
||||
expect(getOptionsFromParams(new URLSearchParams('fontSize=huge')).fontSize).toBe(52);
|
||||
});
|
||||
|
||||
test('rejects an unknown value for an enumerated option', () => {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { Dialog } from '@base-ui/react/dialog';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { IoClose } from 'react-icons/io5';
|
||||
|
||||
import Button from '../../../common/components/buttons/Button';
|
||||
import IconButton from '../../../common/components/buttons/IconButton';
|
||||
import Kbd from '../../../common/components/kbd/Kbd';
|
||||
|
||||
interface HelpOverlayProps {
|
||||
@@ -32,7 +33,12 @@ export default function HelpOverlay({ isOpen, onClose }: HelpOverlayProps) {
|
||||
<Dialog.Portal>
|
||||
<Dialog.Backdrop className='teleprompter__help' />
|
||||
<Dialog.Popup className='teleprompter__help-card'>
|
||||
<Dialog.Title className='teleprompter__help-title'>Prompter shortcuts</Dialog.Title>
|
||||
<div className='teleprompter__help-header'>
|
||||
<Dialog.Title className='teleprompter__help-title'>Prompter shortcuts</Dialog.Title>
|
||||
<IconButton variant='subtle-white' size='large' onClick={onClose} aria-label='Close'>
|
||||
<IoClose />
|
||||
</IconButton>
|
||||
</div>
|
||||
|
||||
<div className='teleprompter__help-groups'>
|
||||
<ShortcutGroup title='Transport'>
|
||||
@@ -94,10 +100,6 @@ export default function HelpOverlay({ isOpen, onClose }: HelpOverlayProps) {
|
||||
</Shortcut>
|
||||
</ShortcutGroup>
|
||||
</div>
|
||||
|
||||
<Button variant='subtle-white' onClick={onClose} className='teleprompter__help-close'>
|
||||
Close
|
||||
</Button>
|
||||
</Dialog.Popup>
|
||||
</Dialog.Portal>
|
||||
</Dialog.Root>
|
||||
|
||||
@@ -38,7 +38,7 @@ const defaults = {
|
||||
showGroups: true,
|
||||
speed: DEFAULT_SPEED,
|
||||
followLoaded: true,
|
||||
fontSize: 40,
|
||||
fontSize: 52,
|
||||
lineHeight: 1.3,
|
||||
textWidth: 80,
|
||||
readingLine: true,
|
||||
|
||||
@@ -10,14 +10,15 @@
|
||||
*
|
||||
* The default is calibrated against the reading rate rather than picked for
|
||||
* feel: broadcast presenters read at 140-160 words per minute and conference
|
||||
* talent slower still, and at the default column width a line carries a dozen
|
||||
* or so words. Twelve lines per minute lands in that band. The ceiling is set
|
||||
* where the text stops being readable at all, not at the fastest the loop can
|
||||
* physically scroll, so the arrow keys stay useful across their whole range.
|
||||
* talent slower still, and at the default size a line carries around ten words.
|
||||
* Fourteen lines per minute measures at 136 wpm, a presenter's pace rather than
|
||||
* a news reader's. The ceiling is set where the text stops being readable at
|
||||
* all, not at the fastest the loop can physically scroll, so the arrow keys
|
||||
* stay useful across their whole range.
|
||||
*/
|
||||
export const MIN_SPEED = 1;
|
||||
export const MAX_SPEED = 40;
|
||||
export const DEFAULT_SPEED = 12;
|
||||
export const DEFAULT_SPEED = 14;
|
||||
|
||||
/** how much one speed adjustment moves, shared by the keymap and the overlay */
|
||||
export const SPEED_STEP = 1;
|
||||
|
||||
Reference in New Issue
Block a user