Vertical: páginas pegadas, sin separación entre ellas

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-31 12:54:52 -06:00
co-authored by Claude Opus 5.5
parent aabb87f6c1
commit d48378aa49
2 changed files with 7 additions and 13 deletions
+6 -11
View File
@@ -684,11 +684,10 @@ async function viewManga(id, langOverride) {
const READ_MODES = { paged: 'Una página', double: 'Doble página', vertical: 'Vertical' }
// Ajustes por defecto según el tipo de obra (se usan hasta que el usuario cambie algo en ese manga).
function defaultPrefs(manga) {
// gap: separación entre páginas en vertical (los webtoon son una tira continua; los mangas, páginas sueltas).
if (['Manhwa', 'Manhua', 'Webtoon'].includes(manga.type)) return { mode: 'vertical', fit: 'width', dir: 'ltr', gap: false }
if (manga.type === 'Manga') return { mode: 'paged', fit: 'height', dir: 'rtl', gap: true }
if (['Manhwa', 'Manhua', 'Webtoon'].includes(manga.type)) return { mode: 'vertical', fit: 'width', dir: 'ltr' }
if (manga.type === 'Manga') return { mode: 'paged', fit: 'height', dir: 'rtl' }
const legacy = store.get('readerSettings', {})
return { mode: READ_MODES[legacy.mode] ? legacy.mode : 'paged', fit: legacy.fit === 'width' ? 'width' : 'height', dir: legacy.dir === 'rtl' ? 'rtl' : 'ltr', gap: true }
return { mode: READ_MODES[legacy.mode] ? legacy.mode : 'paged', fit: legacy.fit === 'width' ? 'width' : 'height', dir: legacy.dir === 'rtl' ? 'rtl' : 'ltr' }
}
async function viewReader(mangaId, chapterId, startPage) {
@@ -744,13 +743,12 @@ async function viewReader(mangaId, chapterId, startPage) {
<select id="mode" title="Modo de lectura (se recuerda para este manga)">${Object.entries(READ_MODES).map(([k, v]) => `<option value="${k}">${v}</option>`).join('')}</select>
<select id="fit" title="Ajuste (se recuerda para este manga)"><option value="height">Ajustar alto</option><option value="width">Ajustar ancho</option></select>
<select id="dir" title="Dirección (se recuerda para este manga)"><option value="ltr">Izq → Der</option><option value="rtl">Der → Izq</option></select>
<label class="row muted" id="gapwrap" style="font-size:.85rem" title="Deja un espacio entre páginas en modo vertical (se recuerda para este manga)"><input type="checkbox" id="gap"> Separar páginas</label>
<select id="filter" title="Filtro">${Object.entries(FILTERS).map(([k, [label]]) => `<option value="${k}">${label}</option>`).join('')}</select>
<label class="row muted" style="font-size:.85rem" title="Brillo">☀ <input type="range" id="bright" min="40" max="120" step="5" style="width:90px"></label>
${manga.source === 'lc' || chap.local ? '' : '<label class="row muted" style="font-size:.85rem"><input type="checkbox" id="saver"> Ahorro datos</label>'}
${chap.hdAvailable ? '<label class="row muted" style="font-size:.85rem" title="Usar la versión reescalada de este capítulo"><input type="checkbox" id="hd"> Versión HD</label>'
: chap.local && info.upscale?.available ? `<button class="btn small" id="hdone" title="Reescala este capítulo con IA en segundo plano (unos minutos)">${icon('sparkles')} Reescalar a HD</button>` : ''}
<p class="muted">Modo, ajuste, dirección y separación se recuerdan para este manga. ${icon('scroll')} en la barra de arriba cambia entre páginas y vertical. Zoom: pellizca o toca dos veces en el centro (Ctrl+rueda o + / − en PC).</p>
<p class="muted">Modo, ajuste y dirección se recuerdan para este manga. ${icon('scroll')} en la barra de arriba cambia entre páginas y vertical. Zoom: pellizca o toca dos veces en el centro (Ctrl+rueda o + / − en PC).</p>
</div>
<div id="pages"></div>
<div class="rbar bottom">
@@ -767,7 +765,6 @@ async function viewReader(mangaId, chapterId, startPage) {
$('#mode').value = settings.mode
$('#fit').value = settings.fit
$('#dir').value = settings.dir
$('#gap').checked = !!settings.gap
// Botón rápido páginas ⇄ vertical (vuelve al último modo por páginas usado).
let lastPaged = settings.mode === 'double' ? 'double' : 'paged'
function renderModeQuick() {
@@ -877,13 +874,12 @@ async function viewReader(mangaId, chapterId, startPage) {
observer?.disconnect()
const keep = lastShown()
resetZoom()
box.className = isPaged() ? `paged ${settings.fit === 'width' ? 'fit-width' : ''} ${isDouble() ? 'double' : ''}` : `vertical fit-${settings.fit} ${settings.gap ? 'gap' : ''}`
box.className = isPaged() ? `paged ${settings.fit === 'width' ? 'fit-width' : ''} ${isDouble() ? 'double' : ''}` : `vertical fit-${settings.fit}`
renderModeQuick()
box.dataset.dir = settings.dir
// En der → izq la barra de progreso también avanza de derecha a izquierda (en vertical no aplica).
slider.dir = isPaged() && settings.dir === 'rtl' ? 'rtl' : 'ltr'
$('#dir').hidden = !isPaged()
$('#gapwrap').hidden = isPaged()
if (isPaged()) {
box.innerHTML = ''
atEnd = false
@@ -1028,7 +1024,7 @@ async function viewReader(mangaId, chapterId, startPage) {
const saveGlobal = () => store.set('readerSettings', { saver: settings.saver, filter: settings.filter, brightness: settings.brightness, hd: settings.hd !== false })
const savePrefs = () => {
api(`/api/prefs/${mangaId}`, { method: 'POST', body: { mode: settings.mode, fit: settings.fit, dir: settings.dir, gap: !!settings.gap } })
api(`/api/prefs/${mangaId}`, { method: 'POST', body: { mode: settings.mode, fit: settings.fit, dir: settings.dir } })
.then(() => toast('Guardado para este manga')).catch(err => toast(err.message))
}
$('#mode').addEventListener('change', e => { settings.mode = e.target.value; if (isPaged()) lastPaged = settings.mode; savePrefs(); render() })
@@ -1037,7 +1033,6 @@ async function viewReader(mangaId, chapterId, startPage) {
savePrefs()
render()
})
$('#gap').addEventListener('change', e => { settings.gap = e.target.checked; savePrefs(); render() })
$('#fit').addEventListener('change', e => { settings.fit = e.target.value; savePrefs(); render() })
$('#dir').addEventListener('change', e => { settings.dir = e.target.value; box.dataset.dir = settings.dir; slider.dir = settings.dir; savePrefs() })
$('#filter').addEventListener('change', e => { settings.filter = e.target.value; saveGlobal(); applyFilter() })
+1 -2
View File
@@ -108,10 +108,9 @@ input:focus, select:focus { border-color: var(--accent); }
.vertical { display: flex; flex-direction: column; align-items: center; }
.vertical img { width: 100%; max-width: 900px; min-height: 300px; background: #111; }
.vertical img[data-loaded] { min-height: 0; }
/* Vertical para mangas: cada página entera en pantalla y separadas */
/* Vertical para mangas: cada página entera en pantalla, pegadas */
.vertical.fit-height img { width: auto; max-width: 100%; max-height: 100vh; max-height: 100dvh; }
.vertical.fit-height img:not([data-loaded]) { width: min(100%, 640px); }
.vertical.gap { gap: 14px; }
.chapter-end { padding: 40px 16px 120px; text-align: center; display: grid; gap: 12px; justify-items: center; }
#toast { position: fixed; bottom: 80px; left: 50%; transform: translateX(-50%); z-index: 50; background: var(--surface-2);