Scale TV dashboard blocks and rules overlay to fit without scrolling

When there are more than 6 schedule blocks or 5 rules, font sizes,
padding, and gaps scale down proportionally via CSS custom properties
so all content fits on screen without requiring scroll.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-20 07:51:43 -07:00
parent fdd85d3df5
commit a67b325b01

View File

@@ -126,7 +126,7 @@
<!-- Right: schedule list -->
<div class="tv-sidebar">
<div class="tv-schedule-list">
<div class="tv-schedule-list" :style="blocksScaleStyle">
<ScheduleBlock
v-for="block in scheduleStore.blocks"
:key="block.id"
@@ -175,7 +175,7 @@
<!-- Rules/Expectations full-screen overlay -->
<transition name="tv-alert">
<div v-if="scheduleStore.showRulesOverlay" class="tv-rules-overlay" @click="scheduleStore.showRulesOverlay = false">
<div class="tv-rules-box">
<div class="tv-rules-box" :style="rulesScaleStyle">
<div class="tv-rules-header">
<span class="tv-rules-icon">📋</span>
<span class="tv-rules-title">Rules &amp; Expectations</span>
@@ -288,6 +288,22 @@ const currentSubjectOptions = computed(() =>
scheduleStore.currentBlock?.subject?.options || []
)
const rulesScaleStyle = computed(() => {
const count = scheduleStore.rulesOverlayItems?.length || 0
if (count <= 5) return {}
// Scale down: at 5 rules = 1.0, at 10 rules ≈ 0.65, capped at 0.5
const scale = Math.max(0.5, 5 / count)
return { '--rules-scale': scale }
})
const blocksScaleStyle = computed(() => {
const count = scheduleStore.blocks?.length || 0
if (count <= 6) return {}
// Scale down: at 6 blocks = 1.0, at 12 blocks ≈ 0.55, capped at 0.5
const scale = Math.max(0.5, 6 / count)
return { '--blocks-scale': scale }
})
function blockElapsed(block) {
const currentId = scheduleStore.session?.current_block_id
if (block.id === currentId && scheduleStore.blockStartedAt && !scheduleStore.isPaused) {
@@ -531,11 +547,10 @@ onMounted(async () => {
}
.tv-schedule-list {
overflow-y: auto;
overflow: hidden;
display: flex;
flex-direction: column;
gap: 0.75rem;
max-height: 60vh;
gap: calc(0.75rem * var(--blocks-scale, 1));
}
/* Expand timer to fill the column */
@@ -546,10 +561,10 @@ onMounted(async () => {
.tv-timer-col :deep(.timer-time) { font-size: 5.5rem; }
.tv-timer-col :deep(.timer-label) { font-size: 1.4rem; }
/* Make schedule block text larger for TV viewing */
.tv-schedule-list :deep(.block-title) { font-size: 1.2rem; }
.tv-schedule-list :deep(.block-time) { font-size: 1rem; }
.tv-schedule-list :deep(.block-card) { padding: 0.85rem 1rem; }
/* Make schedule block text larger for TV viewing, scaling with block count */
.tv-schedule-list :deep(.block-title) { font-size: calc(1.2rem * var(--blocks-scale, 1)); }
.tv-schedule-list :deep(.block-time) { font-size: calc(1rem * var(--blocks-scale, 1)); }
.tv-schedule-list :deep(.block-card) { padding: calc(0.85rem * var(--blocks-scale, 1)) calc(1rem * var(--blocks-scale, 1)); }
.tv-ws-status {
position: fixed;
@@ -663,12 +678,12 @@ onMounted(async () => {
padding: 3.5rem 4.5rem;
max-width: 800px;
width: 90%;
max-height: 85vh;
overflow-y: auto;
max-height: 90vh;
overflow: hidden;
box-shadow: 0 0 80px rgba(16, 185, 129, 0.3);
display: flex;
flex-direction: column;
gap: 2rem;
gap: calc(2rem * var(--rules-scale, 1));
}
.tv-rules-header {
display: flex;
@@ -676,9 +691,9 @@ onMounted(async () => {
gap: 1rem;
justify-content: center;
}
.tv-rules-icon { font-size: 3rem; }
.tv-rules-icon { font-size: calc(3rem * var(--rules-scale, 1)); }
.tv-rules-title {
font-size: 2.5rem;
font-size: calc(2.5rem * var(--rules-scale, 1));
font-weight: 800;
color: #34d399;
text-transform: uppercase;
@@ -690,19 +705,19 @@ onMounted(async () => {
margin: 0;
display: flex;
flex-direction: column;
gap: 1.25rem;
gap: calc(1.25rem * var(--rules-scale, 1));
counter-reset: rules-counter;
}
.tv-rules-item {
counter-increment: rules-counter;
display: flex;
align-items: flex-start;
gap: 1.25rem;
font-size: 2rem;
gap: calc(1.25rem * var(--rules-scale, 1));
font-size: calc(2rem * var(--rules-scale, 1));
font-weight: 500;
color: #f1f5f9;
line-height: 1.3;
padding-bottom: 1.25rem;
padding-bottom: calc(1.25rem * var(--rules-scale, 1));
border-bottom: 1px solid #1e293b;
}
.tv-rules-item:last-child { border-bottom: none; padding-bottom: 0; }
@@ -711,12 +726,12 @@ onMounted(async () => {
display: flex;
align-items: center;
justify-content: center;
min-width: 2.5rem;
height: 2.5rem;
min-width: calc(2.5rem * var(--rules-scale, 1));
height: calc(2.5rem * var(--rules-scale, 1));
background: #064e3b;
border: 2px solid #10b981;
border-radius: 50%;
font-size: 1.2rem;
font-size: calc(1.2rem * var(--rules-scale, 1));
font-weight: 800;
color: #34d399;
flex-shrink: 0;