ProPresenter 1.1.0: a Now tile, and switches for everything on it
The + picker now offers the module two ways. "Now / Next" is the card as it was. "Now" is the live item on its own: the gradient comes off the card and fills the tile edge to edge, the border, radius and box go, and the playlist name and live dot float over the colour instead of sitting above it. A wall of them reads as panels of colour rather than cards on a background. Every part of the tile is now a switch in a "Show" group in the gear — playlist, live status, the NOW and NEXT labels, slide count, progress bar, the next list and its item tags. One or two words each, no descriptions. The Now entry carries its own six, since the three Next ones have nothing to act on there. Two things the tile still insists on. Trouble overrides the switches: the top row and the live chip come back the moment the feed drops, whatever is switched off, because a tile that has stopped updating must never look like one with nothing live. And at the Now tile's shortest sizes the floating top row would sit on the title, so below the height it needs it goes — the header dot and the title itself still say what is wrong. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
6cca6d4d1a
commit
52d700df3d
@@ -6,6 +6,12 @@
|
||||
in /admin; the tile only renders. */
|
||||
|
||||
export default function create({ root, moduleApi }) {
|
||||
/* "now" is the live item on its own, filling the tile; "full" is that plus
|
||||
the rest of the playlist. The picker presets `view`; a tile placed before
|
||||
this module had a picker has neither, and gets the full card. */
|
||||
const view = String(moduleApi.instanceSettings.view || moduleApi.variant || 'full');
|
||||
const nowOnly = view === 'now';
|
||||
|
||||
let state = null;
|
||||
let feedOffline = false;
|
||||
let stream = null;
|
||||
@@ -33,11 +39,13 @@ export default function create({ root, moduleApi }) {
|
||||
</div>`;
|
||||
|
||||
const screenEl = root.querySelector('.nn-screen');
|
||||
if (nowOnly) screenEl.classList.add('nn-only-now');
|
||||
const topRow = root.querySelector('.nn-top');
|
||||
const playlistNameEl = root.querySelector('.nn-playlist');
|
||||
const liveEl = root.querySelector('.nn-live');
|
||||
const liveTextEl = root.querySelector('.nn-live-text');
|
||||
const nowEl = root.querySelector('.nn-now');
|
||||
const nowLabelEl = root.querySelector('.nn-label');
|
||||
const nowTitleBox = root.querySelector('.nn-title-box');
|
||||
let nowTitleEl = root.querySelector('.nn-title');
|
||||
const nowMetaEl = root.querySelector('.nn-meta');
|
||||
@@ -47,9 +55,11 @@ export default function create({ root, moduleApi }) {
|
||||
const nextListEl = root.querySelector('.nn-next-list');
|
||||
const nextMoreEl = root.querySelector('.nn-next-more');
|
||||
|
||||
/** A setting, defaulting to on — a Now tile's schema omits the Next ones. */
|
||||
function prefs() {
|
||||
return moduleApi.instanceSettings; // showPlaylist / showProgress / cleanTitles
|
||||
return moduleApi.instanceSettings;
|
||||
}
|
||||
const on = (key) => prefs()[key] !== false;
|
||||
|
||||
/* ── title tidying (same rule as propresenter-core.cleanItemName) ─ */
|
||||
|
||||
@@ -65,7 +75,7 @@ export default function create({ root, moduleApi }) {
|
||||
}
|
||||
|
||||
function displayName(raw) {
|
||||
return prefs().cleanTitles ? cleanItemName(raw) : String(raw || '').trim();
|
||||
return on('cleanTitles') ? cleanItemName(raw) : String(raw || '').trim();
|
||||
}
|
||||
|
||||
function itemTypeTag(type) {
|
||||
@@ -307,7 +317,9 @@ export default function create({ root, moduleApi }) {
|
||||
|
||||
const total = state.currentSlideTotal || activeItem?.slideCount || 0;
|
||||
const current = state.currentSlide || 0;
|
||||
if (total > 0 && current > 0) {
|
||||
if (!on('showSlideCount')) {
|
||||
nowMetaEl.textContent = '';
|
||||
} else if (total > 0 && current > 0) {
|
||||
const remaining = Math.max(0, total - current);
|
||||
nowMetaEl.textContent = `Slide ${current} / ${total} · ${remaining} left`;
|
||||
} else if (total > 0) {
|
||||
@@ -318,7 +330,7 @@ export default function create({ root, moduleApi }) {
|
||||
nowMetaEl.textContent = '';
|
||||
}
|
||||
|
||||
if (prefs().showProgress && total > 0) {
|
||||
if (on('showProgress') && total > 0) {
|
||||
progressEl.hidden = false;
|
||||
const pct = current > 0 ? Math.max(0, Math.min(100, (current / total) * 100)) : 0;
|
||||
progressFillEl.style.width = `${pct}%`;
|
||||
@@ -349,6 +361,10 @@ export default function create({ root, moduleApi }) {
|
||||
nameEl.textContent = displayName(item.name) || '(untitled)';
|
||||
row.appendChild(nameEl);
|
||||
|
||||
if (!on('showTags')) {
|
||||
nextListEl.appendChild(row);
|
||||
continue;
|
||||
}
|
||||
if (item.type === 'presentation' && Number.isInteger(item.slideCount)) {
|
||||
const chip = document.createElement('div');
|
||||
chip.className = 'nn-count-chip';
|
||||
@@ -366,7 +382,7 @@ export default function create({ root, moduleApi }) {
|
||||
nextListEl.appendChild(row);
|
||||
}
|
||||
|
||||
nextLabelEl.hidden = upcoming.length === 0;
|
||||
nextLabelEl.hidden = upcoming.length === 0 || !on('showNextLabel');
|
||||
nextMoreEl.hidden = true;
|
||||
markNextOverflow();
|
||||
requestAnimationFrame(markNextOverflow);
|
||||
@@ -374,12 +390,22 @@ export default function create({ root, moduleApi }) {
|
||||
|
||||
function render() {
|
||||
screenEl.classList.toggle('is-offline', feedOffline);
|
||||
const showTop = prefs().showPlaylist || feedOffline || !state?.reachable || !state?.enabled;
|
||||
topRow.classList.toggle('hidden-row', !showTop);
|
||||
playlistNameEl.textContent = prefs().showPlaylist ? state?.playlistName || '' : '';
|
||||
// Trouble always shows, whatever is switched off: a tile that has stopped
|
||||
// updating must never look like one with nothing live.
|
||||
const trouble = feedOffline || !state?.reachable || !state?.enabled;
|
||||
const wantPlaylist = on('showPlaylist');
|
||||
const wantLive = on('showLive') || trouble;
|
||||
topRow.classList.toggle('hidden-row', !wantPlaylist && !wantLive);
|
||||
liveEl.hidden = !wantLive;
|
||||
// Hidden, not just emptied: it is flex:1, so an emptied one still holds
|
||||
// the row open and pushes the live dot off the right edge.
|
||||
playlistNameEl.hidden = !wantPlaylist;
|
||||
playlistNameEl.textContent = state?.playlistName || '';
|
||||
nowLabelEl.hidden = !on('showNowLabel');
|
||||
screenEl.classList.toggle('nn-no-next', nowOnly || !on('showNext'));
|
||||
renderLive();
|
||||
renderNow();
|
||||
renderNext();
|
||||
if (!nowOnly && on('showNext')) renderNext();
|
||||
}
|
||||
|
||||
/* ── sizing: --unit scales the whole card to the tile ───────────── */
|
||||
@@ -387,6 +413,10 @@ export default function create({ root, moduleApi }) {
|
||||
function applyUnit() {
|
||||
const unit = Math.max(6.5, Math.min(20, root.clientHeight * 0.032));
|
||||
screenEl.style.setProperty('--unit', unit.toFixed(2) + 'px');
|
||||
// On a Now tile the top row floats over the gradient, so at the shortest
|
||||
// sizes it would sit on the title. Below the height it needs, it goes —
|
||||
// the header dot and the title itself still report trouble.
|
||||
screenEl.classList.toggle('nn-tight', nowOnly && root.clientHeight < unit * 9);
|
||||
}
|
||||
|
||||
/* ── live feed ──────────────────────────────────────────────────── */
|
||||
|
||||
Reference in New Issue
Block a user