adjustable card/font size
This commit is contained in:
@@ -559,6 +559,38 @@ body.theme-light .input-row input:focus {
|
||||
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 {
|
||||
width: 100%;
|
||||
padding: 9px 12px;
|
||||
@@ -872,11 +904,11 @@ body.theme-light .setting-item select option {
|
||||
}
|
||||
|
||||
.video-card h4 {
|
||||
font-size: 16px;
|
||||
font-size: calc(16px * var(--card-font-scale, 1));
|
||||
}
|
||||
|
||||
.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 {
|
||||
font-size: 15px;
|
||||
font-size: calc(15px * var(--card-font-scale, 1));
|
||||
font-weight: 500;
|
||||
padding: 12px 12px 10px;
|
||||
line-height: 1.3;
|
||||
@@ -1022,7 +1054,7 @@ body.theme-light .setting-item select option {
|
||||
}
|
||||
|
||||
.video-card p {
|
||||
font-size: 12px;
|
||||
font-size: calc(12px * var(--card-font-scale, 1));
|
||||
color: var(--text-secondary);
|
||||
padding: 0 12px 12px 12px;
|
||||
margin: 0;
|
||||
@@ -1040,7 +1072,7 @@ body.theme-light .setting-item select option {
|
||||
}
|
||||
|
||||
.video-tag {
|
||||
font-size: 11px;
|
||||
font-size: calc(11px * var(--card-font-scale, 1));
|
||||
color: var(--text-secondary);
|
||||
background: var(--bg-tertiary);
|
||||
border: 1px solid var(--border);
|
||||
|
||||
@@ -98,6 +98,14 @@
|
||||
<option value="compact">Compact</option>
|
||||
</select>
|
||||
</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">
|
||||
<label for="feed-end-select">Reels: On Video End</label>
|
||||
<select id="feed-end-select">
|
||||
|
||||
@@ -8,6 +8,9 @@ window.App = window.App || {};
|
||||
App.ui.applyPreferredQuality();
|
||||
App.ui.applyFeedEndBehavior();
|
||||
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.favorites.renderBar();
|
||||
App.ui.bindGlobalHandlers();
|
||||
|
||||
@@ -57,6 +57,30 @@ App.session = App.session || {};
|
||||
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() {
|
||||
const config = App.storage.getConfig();
|
||||
if (!config.servers || !Array.isArray(config.servers)) return [];
|
||||
|
||||
@@ -28,6 +28,29 @@ App.ui = App.ui || {};
|
||||
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.
|
||||
App.ui.showError = function(message) {
|
||||
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');
|
||||
if (feedEndSelect) {
|
||||
feedEndSelect.value = App.storage.getFeedEndBehavior();
|
||||
|
||||
@@ -565,6 +565,7 @@ App.videos = App.videos || {};
|
||||
const measureMetrics = function() {
|
||||
const el = grid();
|
||||
if (!el) return false;
|
||||
const phone = window.matchMedia('(max-width: 480px)').matches;
|
||||
const mobile = window.matchMedia('(max-width: 768px)').matches;
|
||||
const large = window.matchMedia('(min-width: 1600px)').matches;
|
||||
gap = mobile ? 12 : (large ? 24 : 16);
|
||||
@@ -580,8 +581,12 @@ App.videos = App.videos || {};
|
||||
if (inner <= 0) return false;
|
||||
// Density toggle (see enhance.js / settings) tunes the minimum card
|
||||
// width, so "compact" packs more columns at the same viewport width.
|
||||
const minCardW = document.body.dataset.density === 'compact' ? 210 : 260;
|
||||
cols = mobile ? 2 : Math.max(1, Math.floor((inner + gap) / (minCardW + gap)));
|
||||
// The user's Card Size setting scales that minimum on top of density.
|
||||
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;
|
||||
return true;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user