adjustable card/font size
This commit is contained in:
@@ -559,6 +559,38 @@ body.theme-light .input-row input:focus {
|
|||||||
background: var(--bg-tertiary);
|
background: var(--bg-tertiary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.setting-item input[type="range"] {
|
||||||
|
width: 100%;
|
||||||
|
appearance: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
height: 6px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: var(--bg-tertiary);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
cursor: pointer;
|
||||||
|
margin: 6px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-item input[type="range"]::-webkit-slider-thumb {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--text-primary);
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-item input[type="range"]::-moz-range-thumb {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--text-primary);
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.setting-item select {
|
.setting-item select {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 9px 12px;
|
padding: 9px 12px;
|
||||||
@@ -872,11 +904,11 @@ body.theme-light .setting-item select option {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.video-card h4 {
|
.video-card h4 {
|
||||||
font-size: 16px;
|
font-size: calc(16px * var(--card-font-scale, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
.video-card p {
|
.video-card p {
|
||||||
font-size: 13px;
|
font-size: calc(13px * var(--card-font-scale, 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -989,7 +1021,7 @@ body.theme-light .setting-item select option {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.video-card h4 {
|
.video-card h4 {
|
||||||
font-size: 15px;
|
font-size: calc(15px * var(--card-font-scale, 1));
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
padding: 12px 12px 10px;
|
padding: 12px 12px 10px;
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
@@ -1022,7 +1054,7 @@ body.theme-light .setting-item select option {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.video-card p {
|
.video-card p {
|
||||||
font-size: 12px;
|
font-size: calc(12px * var(--card-font-scale, 1));
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
padding: 0 12px 12px 12px;
|
padding: 0 12px 12px 12px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -1040,7 +1072,7 @@ body.theme-light .setting-item select option {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.video-tag {
|
.video-tag {
|
||||||
font-size: 11px;
|
font-size: calc(11px * var(--card-font-scale, 1));
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
background: var(--bg-tertiary);
|
background: var(--bg-tertiary);
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
|
|||||||
@@ -98,6 +98,14 @@
|
|||||||
<option value="compact">Compact</option>
|
<option value="compact">Compact</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="setting-item">
|
||||||
|
<label for="card-size-range">Card Size</label>
|
||||||
|
<input type="range" id="card-size-range" min="0.7" max="1.5" step="0.1" value="1">
|
||||||
|
</div>
|
||||||
|
<div class="setting-item">
|
||||||
|
<label for="text-size-range">Text Size</label>
|
||||||
|
<input type="range" id="text-size-range" min="0.8" max="1.4" step="0.1" value="1">
|
||||||
|
</div>
|
||||||
<div class="setting-item">
|
<div class="setting-item">
|
||||||
<label for="feed-end-select">Reels: On Video End</label>
|
<label for="feed-end-select">Reels: On Video End</label>
|
||||||
<select id="feed-end-select">
|
<select id="feed-end-select">
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ window.App = window.App || {};
|
|||||||
App.ui.applyPreferredQuality();
|
App.ui.applyPreferredQuality();
|
||||||
App.ui.applyFeedEndBehavior();
|
App.ui.applyFeedEndBehavior();
|
||||||
App.ui.applyDensity();
|
App.ui.applyDensity();
|
||||||
|
// Set the text-size CSS variable before the first pack so initial card
|
||||||
|
// heights are measured at the user's chosen size.
|
||||||
|
document.documentElement.style.setProperty('--card-font-scale', App.storage.getFontScale());
|
||||||
App.ui.renderMenu();
|
App.ui.renderMenu();
|
||||||
App.favorites.renderBar();
|
App.favorites.renderBar();
|
||||||
App.ui.bindGlobalHandlers();
|
App.ui.bindGlobalHandlers();
|
||||||
|
|||||||
@@ -57,6 +57,30 @@ App.session = App.session || {};
|
|||||||
localStorage.setItem('density', nextDensity === 'compact' ? 'compact' : 'comfortable');
|
localStorage.setItem('density', nextDensity === 'compact' ? 'compact' : 'comfortable');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// User-tunable card width / text size multipliers (default 1.0). Clamped so a
|
||||||
|
// stale or hand-edited value can never break the layout.
|
||||||
|
const clampScale = function(value, min, max, fallback) {
|
||||||
|
const n = parseFloat(value);
|
||||||
|
if (!isFinite(n)) return fallback;
|
||||||
|
return Math.min(max, Math.max(min, n));
|
||||||
|
};
|
||||||
|
|
||||||
|
App.storage.getCardScale = function() {
|
||||||
|
return clampScale(localStorage.getItem('cardScale'), 0.7, 1.5, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
App.storage.setCardScale = function(next) {
|
||||||
|
localStorage.setItem('cardScale', clampScale(next, 0.7, 1.5, 1));
|
||||||
|
};
|
||||||
|
|
||||||
|
App.storage.getFontScale = function() {
|
||||||
|
return clampScale(localStorage.getItem('fontScale'), 0.8, 1.4, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
App.storage.setFontScale = function(next) {
|
||||||
|
localStorage.setItem('fontScale', clampScale(next, 0.8, 1.4, 1));
|
||||||
|
};
|
||||||
|
|
||||||
App.storage.getServerEntries = function() {
|
App.storage.getServerEntries = function() {
|
||||||
const config = App.storage.getConfig();
|
const config = App.storage.getConfig();
|
||||||
if (!config.servers || !Array.isArray(config.servers)) return [];
|
if (!config.servers || !Array.isArray(config.servers)) return [];
|
||||||
|
|||||||
@@ -28,6 +28,29 @@ App.ui = App.ui || {};
|
|||||||
if (select) select.value = density;
|
if (select) select.value = density;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Card Size: re-packs the virtual grid (column count derives from the scaled
|
||||||
|
// minimum card width in videos.js).
|
||||||
|
App.ui.applyCardScale = function() {
|
||||||
|
const scale = App.storage.getCardScale();
|
||||||
|
const range = document.getElementById('card-size-range');
|
||||||
|
if (range) range.value = scale;
|
||||||
|
if (App.virtualGrid && typeof App.virtualGrid.relayout === 'function') {
|
||||||
|
App.virtualGrid.relayout();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Text Size: drives the --card-font-scale CSS variable; a re-pack follows so
|
||||||
|
// card heights account for the new text size.
|
||||||
|
App.ui.applyFontScale = function() {
|
||||||
|
const scale = App.storage.getFontScale();
|
||||||
|
document.documentElement.style.setProperty('--card-font-scale', scale);
|
||||||
|
const range = document.getElementById('text-size-range');
|
||||||
|
if (range) range.value = scale;
|
||||||
|
if (App.virtualGrid && typeof App.virtualGrid.relayout === 'function') {
|
||||||
|
App.virtualGrid.relayout();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Toast helper for playback + network errors.
|
// Toast helper for playback + network errors.
|
||||||
App.ui.showError = function(message) {
|
App.ui.showError = function(message) {
|
||||||
const toast = document.getElementById('error-toast');
|
const toast = document.getElementById('error-toast');
|
||||||
@@ -305,6 +328,24 @@ App.ui = App.ui || {};
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cardSizeRange = document.getElementById('card-size-range');
|
||||||
|
if (cardSizeRange) {
|
||||||
|
cardSizeRange.value = App.storage.getCardScale();
|
||||||
|
cardSizeRange.oninput = () => {
|
||||||
|
App.storage.setCardScale(cardSizeRange.value);
|
||||||
|
App.ui.applyCardScale();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const textSizeRange = document.getElementById('text-size-range');
|
||||||
|
if (textSizeRange) {
|
||||||
|
textSizeRange.value = App.storage.getFontScale();
|
||||||
|
textSizeRange.oninput = () => {
|
||||||
|
App.storage.setFontScale(textSizeRange.value);
|
||||||
|
App.ui.applyFontScale();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const feedEndSelect = document.getElementById('feed-end-select');
|
const feedEndSelect = document.getElementById('feed-end-select');
|
||||||
if (feedEndSelect) {
|
if (feedEndSelect) {
|
||||||
feedEndSelect.value = App.storage.getFeedEndBehavior();
|
feedEndSelect.value = App.storage.getFeedEndBehavior();
|
||||||
|
|||||||
@@ -565,6 +565,7 @@ App.videos = App.videos || {};
|
|||||||
const measureMetrics = function() {
|
const measureMetrics = function() {
|
||||||
const el = grid();
|
const el = grid();
|
||||||
if (!el) return false;
|
if (!el) return false;
|
||||||
|
const phone = window.matchMedia('(max-width: 480px)').matches;
|
||||||
const mobile = window.matchMedia('(max-width: 768px)').matches;
|
const mobile = window.matchMedia('(max-width: 768px)').matches;
|
||||||
const large = window.matchMedia('(min-width: 1600px)').matches;
|
const large = window.matchMedia('(min-width: 1600px)').matches;
|
||||||
gap = mobile ? 12 : (large ? 24 : 16);
|
gap = mobile ? 12 : (large ? 24 : 16);
|
||||||
@@ -580,8 +581,12 @@ App.videos = App.videos || {};
|
|||||||
if (inner <= 0) return false;
|
if (inner <= 0) return false;
|
||||||
// Density toggle (see enhance.js / settings) tunes the minimum card
|
// Density toggle (see enhance.js / settings) tunes the minimum card
|
||||||
// width, so "compact" packs more columns at the same viewport width.
|
// width, so "compact" packs more columns at the same viewport width.
|
||||||
const minCardW = document.body.dataset.density === 'compact' ? 210 : 260;
|
// The user's Card Size setting scales that minimum on top of density.
|
||||||
cols = mobile ? 2 : Math.max(1, Math.floor((inner + gap) / (minCardW + gap)));
|
const cardScale = (App.storage && App.storage.getCardScale) ? App.storage.getCardScale() : 1;
|
||||||
|
const minCardW = (document.body.dataset.density === 'compact' ? 210 : 260) * cardScale;
|
||||||
|
// One card per row on phones, two on larger handsets/tablets, and a
|
||||||
|
// size-driven count on desktop.
|
||||||
|
cols = phone ? 1 : (mobile ? 2 : Math.max(1, Math.floor((inner + gap) / (minCardW + gap))));
|
||||||
colWidth = (inner - gap * (cols - 1)) / cols;
|
colWidth = (inner - gap * (cols - 1)) / cols;
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user