mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-29 02:49:13 +00:00
refactor(ui): overlay the status icons and let the preview fill the panel
Three adjustments to the panel layout: - the timer status icons go back to overlaying the stage, which returns the row they were costing. They sit in the same chrome layer as the pop-out buttons, so the blackout no longer hides them - the screen state buttons group with the preview they act on, and the gap before the message inputs widens to separate the two - the stage drops its fixed aspect ratio and fills the panel width, which also removes the slack a tall panel used to leave around it Without a 16:9 frame the width derived font size can overflow a short, wide stage, so the timer is now capped by container height at the ratio the estimate assumes. In the pip window, which has no ancestor query container, both terms resolve against the viewport, so a 16:9 window is unchanged and a wider one stops clipping its digits. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011CHxSQ6nWHuyar8feieRra
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
/* the screen state buttons belong with the preview they act on, not with the message inputs */
|
||||
.screenGroup {
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $element-inner-spacing;
|
||||
}
|
||||
@@ -8,11 +8,15 @@ import InputRow from './InputRow';
|
||||
import ScreenControl from './ScreenControl';
|
||||
import TimerPreview from './TimerPreview';
|
||||
|
||||
import style from './MessageControl.module.scss';
|
||||
|
||||
export default function MessageControl() {
|
||||
return (
|
||||
<>
|
||||
<TimerPreview />
|
||||
<ScreenControl />
|
||||
<div className={style.screenGroup}>
|
||||
<TimerPreview />
|
||||
<ScreenControl />
|
||||
</div>
|
||||
<TimerMessageInput />
|
||||
<SecondaryInput />
|
||||
</>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $element-spacing;
|
||||
gap: $section-spacing;
|
||||
color: $ui-white;
|
||||
padding-top: $panel-top-padding;
|
||||
}
|
||||
|
||||
@@ -1,36 +1,17 @@
|
||||
.preview {
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/* the stage caps at the panel width, so centre whatever slack a tall panel leaves */
|
||||
justify-content: center;
|
||||
gap: $element-inner-spacing;
|
||||
}
|
||||
|
||||
/* the stage is the only elastic element in the panel, the controls below it keep their size */
|
||||
.stage {
|
||||
flex: 1 1 auto;
|
||||
min-height: 3rem;
|
||||
/* keep the height driven frame from growing wider than the panel */
|
||||
max-height: calc(100cqw * 9 / 16);
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
/* the frame is a query container so that the embedded timer scales to the preview, not to the viewport */
|
||||
.stageFrame {
|
||||
position: relative;
|
||||
container-type: inline-size;
|
||||
/* a query container so that the embedded timer scales to the preview, not to the viewport */
|
||||
container-type: size;
|
||||
contain: paint;
|
||||
overflow: hidden;
|
||||
aspect-ratio: 16 / 9;
|
||||
height: 100%;
|
||||
border-radius: $component-border-radius-md;
|
||||
}
|
||||
|
||||
/* keep the pop-out affordances reachable above the blackout and message overlays */
|
||||
.stageCorners {
|
||||
/* editor chrome sits above the blackout and message overlays, so it stays reachable and readable */
|
||||
.stageChrome {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: calc($zindex-floating + 2);
|
||||
|
||||
@@ -11,16 +11,12 @@ export default function TimerPreview() {
|
||||
const { data } = useViewSettings();
|
||||
|
||||
return (
|
||||
<div className={style.preview}>
|
||||
<div className={style.stage}>
|
||||
<div className={style.stageFrame}>
|
||||
<PipTimer viewSettings={data} />
|
||||
<div className={style.stageCorners}>
|
||||
<CornerWithPip onExtractClick={(event) => handleLinks('timer', event)} pipElement={<PipRoot />} />
|
||||
</div>
|
||||
</div>
|
||||
<div className={style.stage}>
|
||||
<PipTimer viewSettings={data} />
|
||||
<div className={style.stageChrome}>
|
||||
<TimerStatus />
|
||||
<CornerWithPip onExtractClick={(event) => handleLinks('timer', event)} pipElement={<PipRoot />} />
|
||||
</div>
|
||||
<TimerStatus />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
.timerStatus {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
margin: 0.5rem 0.25rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,9 @@ export function PipTimer({ viewSettings }: PipTimerProps) {
|
||||
|
||||
// gather presentation styles
|
||||
const resolvedTimerColour = getTimerColour(viewSettings, undefined, showWarning, showDanger);
|
||||
// the estimate is tuned for a 16:9 screen, so cap it by height for containers wider than that
|
||||
const timerFontSize = getEstimatedFontSize(display, secondaryContent);
|
||||
const timerFontRule = `min(${timerFontSize}cqw, ${((timerFontSize * 16) / 9).toFixed(2)}cqh)`;
|
||||
const userStyles = {
|
||||
...(resolvedTimerColour && { '--timer-colour': resolvedTimerColour }),
|
||||
};
|
||||
@@ -82,7 +84,7 @@ export function PipTimer({ viewSettings }: PipTimerProps) {
|
||||
<div className={cx(['timer-container', message.timer.blink && !showOverlay && 'blink'])}>
|
||||
<div
|
||||
className={cx(['timer', !isPlaying && 'timer--paused', showFinished && 'timer--finished'])}
|
||||
style={{ fontSize: `${timerFontSize}cqw` }}
|
||||
style={{ fontSize: timerFontRule }}
|
||||
data-phase={time.phase}
|
||||
>
|
||||
{display}
|
||||
|
||||
Reference in New Issue
Block a user