A full-featured, touch-optimized E-H/ExH viewer. Adapted for desktop, Android, iOS. Features: a built-in reader, zoomable gallery previews, mobile UI adaptation, gesture navigation, reading history, and more.
// ==UserScript==
// @name EhPeek
// @version 260912.1746
// @description A full-featured, touch-optimized E-H/ExH viewer. Adapted for desktop, Android, iOS. Features: a built-in reader, zoomable gallery previews, mobile UI adaptation, gesture navigation, reading history, and more.
// @description:ja タッチ操作向けの多機能 E-H/ExH ビューア。 デスクトップ、Android、iOS に対応。 内蔵リーダー、ズーム対応のギャラリープレビュー、モバイル向け UI、ジェスチャー操作、閲覧履歴など。
// @description:zh-CN 针对触屏优化的 E-H/ExH 阅读器。 适配桌面端、安卓、iOS。 功能: 内置阅读器、可缩放画廊预览、移动端 UI 适配、手势导航、阅读历史等。
// @icon https://raw.githubusercontent.com/yamipot/ehpeek/master/icon.svg
// @icon64 https://raw.githubusercontent.com/yamipot/ehpeek/master/icon.svg
// @license MIT
// @namespace https://github.com/yamipot/ehpeek
// @homepage https://github.com/yamipot/ehpeek
// @supportURL https://github.com/yamipot/ehpeek/issues
// @match *://exhentai.org/*
// @match *://exhentai55ld2wyap5juskbm67czulomrouspdacjamjeloj7ugjbsad.onion/*
// @match *://e-hentai.org/*
// @match *://*.exhentai.org/*
// @match *://*.exhentai55ld2wyap5juskbm67czulomrouspdacjamjeloj7ugjbsad.onion/*
// @match *://*.e-hentai.org/*
// @match *://*.hath.network/*
// @exclude *://forums.e-hentai.org/*
// @grant GM.getValue
// @grant GM.setValue
// @grant GM.deleteValue
// @grant GM.listValues
// @grant GM.registerMenuCommand
// @grant GM.download
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_deleteValue
// @grant GM_listValues
// @grant GM_registerMenuCommand
// @grant GM_download
// @inject-into content
// @run-at document-start
// @noframes
// ==/UserScript==
/*
This helper script bridges compatibility between the Greasemonkey 4 APIs and
existing/legacy APIs. Say for example your user script includes
// @grant GM_getValue
And you'd like to be compatible with both Greasemonkey 3 and Greasemonkey 4
(and for that matter all versions of Violentmonkey, Tampermonkey, and any other
user script engine). Add:
// @grant GM.getValue
// @require https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js
And switch to the new (GM-dot) APIs, which return promises. If your script
is running in an engine that does not provide the new asynchronous APIs, this
helper will add them, based on the old APIs.
If you use `await` at the top level, you'll need to wrap your script in an
`async` function to be compatible with any user script engine besides
Greasemonkey 4.
(async () => {
let x = await GM.getValue('x');
})();
*/
if (typeof GM == 'undefined') {
this.GM = {};
}
if (typeof GM_addStyle == 'undefined') {
this.GM_addStyle = (aCss) => {
'use strict';
let head = document.getElementsByTagName('head')[0];
if (head) {
let style = document.createElement('style');
style.setAttribute('type', 'text/css');
style.textContent = aCss;
head.appendChild(style);
return style;
}
return null;
};
}
if (typeof GM_registerMenuCommand == 'undefined') {
this.GM_registerMenuCommand = (caption, commandFunc, accessKey) => {
if (!document.body) {
if (document.readyState === 'loading'
&& document.documentElement && document.documentElement.localName === 'html') {
new MutationObserver((mutations, observer) => {
if (document.body) {
observer.disconnect();
GM_registerMenuCommand(caption, commandFunc, accessKey);
}
}).observe(document.documentElement, {childList: true});
} else {
console.error('GM_registerMenuCommand got no body.');
}
return;
}
let contextMenu = document.body.getAttribute('contextmenu');
let menu = (contextMenu ? document.querySelector('menu#' + contextMenu) : null);
if (!menu) {
menu = document.createElement('menu');
menu.setAttribute('id', 'gm-registered-menu');
menu.setAttribute('type', 'context');
document.body.appendChild(menu);
document.body.setAttribute('contextmenu', 'gm-registered-menu');
}
let menuItem = document.createElement('menuitem');
menuItem.textContent = caption;
menuItem.addEventListener('click', commandFunc, true);
menu.appendChild(menuItem);
};
}
if (typeof GM_getResourceText == 'undefined') {
this.GM_getResourceText = (aRes) => {
'use strict';
return GM.getResourceUrl(aRes)
.then(url => fetch(url))
.then(resp => resp.text())
.catch(function(error) {
GM.log('Request failed', error);
return null;
});
};
}
Object.entries({
'log': console.log.bind(console), // Pale Moon compatibility. See #13.
'info': GM_info,
}).forEach(([newKey, old]) => {
if (old && (typeof GM[newKey] == 'undefined')) {
GM[newKey] = old;
}
});
Object.entries({
'GM_addStyle': 'addStyle',
'GM_deleteValue': 'deleteValue',
'GM_getResourceURL': 'getResourceUrl',
'GM_getValue': 'getValue',
'GM_listValues': 'listValues',
'GM_notification': 'notification',
'GM_openInTab': 'openInTab',
'GM_registerMenuCommand': 'registerMenuCommand',
'GM_setClipboard': 'setClipboard',
'GM_setValue': 'setValue',
'GM_xmlhttpRequest': 'xmlHttpRequest',
'GM_getResourceText': 'getResourceText',
}).forEach(([oldKey, newKey]) => {
let old = this[oldKey];
if (old && (typeof GM[newKey] == 'undefined')) {
GM[newKey] = function(...args) {
return new Promise((resolve, reject) => {
try {
resolve(old.apply(this, args));
} catch (e) {
reject(e);
}
});
};
}
});
"use strict";
(() => {
var __getOwnPropNames = Object.getOwnPropertyNames;
var __typeError = (msg) => {
throw TypeError(msg);
};
var __esm = (fn, res, err) => function() {
if (err) throw err[0];
try {
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
} catch (e) {
throw err = [e], e;
}
};
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj)), __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value), __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
// src/locales/en.json
var en_default, init_en = __esm({
"src/locales/en.json"() {
en_default = {
metadata: {
description: "A full-featured, touch-optimized E-H/ExH viewer. Adapted for desktop, Android, iOS. Features: a built-in reader, zoomable gallery previews, mobile UI adaptation, gesture navigation, reading history, and more."
},
help: {
sections: [
{
title: "Browse",
items: [
"Choose EhPeek or EhPeekLite from the **layout menu** to replace the original result layout.",
"When **Enhance > Search Swipe** is enabled, **swipe** horizontally to change search result pages."
]
},
{
title: "Gallery",
items: [
"When **Enhance > Preview Swipe** is enabled, **swipe** horizontally to change preview pages.",
"The Page Bar in Gallery can be **dragged** to adjust the range."
]
}
]
},
reader: {
downloadHelp: 'You may enable the browser download API in your userscript manager. For example, enable "Use browser download API" in Violentmonkey.',
originalImageSource: "Original source provided by E-Hentai"
},
history: {
actions: {
clear: "Clear All",
export: "Export",
import: "Import",
remove: "Delete"
},
clearConfirm: "Clear all reading history?",
empty: "No reading history",
exported: "History exported",
importFailed: "History import failed",
imported: "Imported {count} history entries",
limit: "(max {limit})",
visitedLabel: "VISITED",
range: "{start}–{end} of {total} history entries",
removeConfirm: "Remove this gallery from Read History?"
},
gallery: {
pages: "Pages",
notFavorited: "Not Favorited",
rate: "Rate gallery",
rateWithStars: "Rate gallery: {rating} stars",
tagging: "Tagging",
resizeColumns: "Resize gallery columns",
resetColumns: "Reset gallery columns",
favoriteTag: "Add My Tag",
copyOriginalTag: "Copy Original Tag",
editFavoriteNote: "Edit Note",
discardFavoriteNote: "Discard note edits?",
favoriteRequiresLogin: "Not logged in",
removeFavoriteTag: "Remove My Tag",
tagCollection: "Collection",
tagBehavior: "Behavior",
markTag: "Mark",
watchTag: "Watch",
hideTag: "Hide"
},
settings: {
openSettings: "Settings",
on: "On",
off: "Off",
discardChanges: "Discard unsaved settings changes?",
general: "General",
options: "Options",
about: "About",
licenses: "Licenses",
readerLabel: "Reader",
readerHelp: "Opens gallery images in EhPeek's reader",
readerFullscreenLabel: "Open Reader in Fullscreen",
readerFullscreenHelp: "Enters fullscreen when the Reader opens",
twoColumnsReaderModeLabel: "Two Columns Reader Mode",
readerModeFullView: "Full View",
readerModeOnPreview: "On Preview",
readerModeReaderPreview: "Reader + Preview",
exitReaderOnFullscreenExitLabel: "Close Reader on Fullscreen Exit",
exitReaderOnFullscreenExitHelp: "Closes the Reader when fullscreen is exited",
includeReaderPageInUrlLabel: "Include Reader Page in URL",
includeReaderPageInUrlHelp: "Updates the URL with the current Reader page. This may pollute browser history",
more: "More",
replacePreviewWithScrollLabel: "Embed Scroll Preview",
replacePreviewWithScrollHelp: "Replaces the original gallery preview area with Scroll Preview",
openGalleryInNewTabLabel: "Open Gallery in New Tab",
openGalleryInNewTabHelp: "Opens gallery links in a new browser tab",
uiControlsLabel: "UI Layout",
uiScaleLabel: "UI Scale",
portraitUiScaleLabel: "Portrait UI Scale",
landscapeUiScaleLabel: "Landscape UI Scale",
leftHandedControlsLabel: "Left-handed controls",
columnsLabel: "Two Columns",
showColumnsResizeHandle: "Show column resize handle",
hideColumnsResizeHandle: "Hide column resize handle",
enhance: "Enhance",
enhanceSearchLabel: "Search Swipe",
enhanceSearchHelp: "Swipe between search result pages",
enhanceThumbsLabel: "Preview Swipe",
enhanceThumbsHelp: "Swipe between preview pages; makes the page bar draggable",
myTagsLabel: "My Tags Color",
myTagsHelp: "Colors my tags in galleries",
historyLabel: "History",
readHistoryLabel: "Read History",
readHistoryHelp: "Adds galleries to Read History and remembers reading progress",
includeUnreadHistoryLabel: "Include Unread History",
includeUnreadHistoryHelp: "Records opened but unread galleries in Read History",
searchHistoryLabel: "Search History",
searchHistoryHelp: "Keeps a history of search keywords",
touchUiLabel: "Touch UI",
touchUiHelp: "Uses touch-friendly navigation UI",
fitToViewportLabel: "Fit Pages to Screen",
fitToViewportHelp: "Fits pages to the browser width"
},
search: {
advancedOptions: "Advanced Options",
categories: "Categories",
fileSearch: "File Search"
},
errors: {
searchPageContentNotFound: "Cannot find search page content"
}
};
}
});
// ../../node_modules/.pnpm/[email protected]/node_modules/solid-js/dist/solid.js
function getContextId(count) {
let num = String(count), len = num.length - 1;
return sharedConfig.context.id + (len ? String.fromCharCode(96 + len) : "") + num;
}
function setHydrateContext(context) {
sharedConfig.context = context;
}
function nextHydrateContext() {
return {
...sharedConfig.context,
id: sharedConfig.getNextContextId(),
count: 0
};
}
function createRoot(fn, detachedOwner) {
let listener = Listener, owner = Owner, unowned = fn.length === 0, current = detachedOwner === void 0 ? owner : detachedOwner, root = unowned ? UNOWNED : {
owned: null,
cleanups: null,
context: current ? current.context : null,
owner: current
}, updateFn = unowned ? fn : () => fn(() => untrack(() => cleanNode(root)));
Owner = root, Listener = null;
try {
return runUpdates(updateFn, !0);
} finally {
Listener = listener, Owner = owner;
}
}
function createSignal(value, options) {
options = options ? Object.assign({}, signalOptions, options) : signalOptions;
let s = {
value,
observers: null,
observerSlots: null,
comparator: options.equals || void 0
}, setter = (value2) => (typeof value2 == "function" && (Transition && Transition.running && Transition.sources.has(s) ? value2 = value2(s.tValue) : value2 = value2(s.value)), writeSignal(s, value2));
return [readSignal.bind(s), setter];
}
function createRenderEffect(fn, value, options) {
let c = createComputation(fn, value, !1, STALE);
Scheduler && Transition && Transition.running ? Updates.push(c) : updateComputation(c);
}
function createEffect(fn, value, options) {
runEffects = runUserEffects;
let c = createComputation(fn, value, !1, STALE), s = SuspenseContext && useContext(SuspenseContext);
s && (c.suspense = s), (!options || !options.render) && (c.user = !0), Effects ? Effects.push(c) : updateComputation(c);
}
function createMemo(fn, value, options) {
options = options ? Object.assign({}, signalOptions, options) : signalOptions;
let c = createComputation(fn, value, !0, 0);
return c.observers = null, c.observerSlots = null, c.comparator = options.equals || void 0, Scheduler && Transition && Transition.running ? (c.tState = STALE, Updates.push(c)) : updateComputation(c), readSignal.bind(c);
}
function batch(fn) {
return runUpdates(fn, !1);
}
function untrack(fn) {
if (!ExternalSourceConfig && Listener === null) return fn();
let listener = Listener;
Listener = null;
try {
return ExternalSourceConfig ? ExternalSourceConfig.untrack(fn) : fn();
} finally {
Listener = listener;
}
}
function on(deps, fn, options) {
let isArray = Array.isArray(deps), prevInput, defer = options && options.defer;
return (prevValue) => {
let input2;
if (isArray) {
input2 = Array(deps.length);
for (let i = 0; i < deps.length; i++) input2[i] = deps[i]();
} else input2 = deps();
if (defer)
return defer = !1, prevValue;
let result = untrack(() => fn(input2, prevInput, prevValue));
return prevInput = input2, result;
};
}
function onMount(fn) {
createEffect(() => untrack(fn));
}
function onCleanup(fn) {
return Owner === null || (Owner.cleanups === null ? Owner.cleanups = [fn] : Owner.cleanups.push(fn)), fn;
}
function catchError(fn, handler) {
ERROR || (ERROR = /* @__PURE__ */ Symbol("error")), Owner = createComputation(void 0, void 0, !0), Owner.context = {
...Owner.context,
[ERROR]: [handler]
}, Transition && Transition.running && Transition.sources.add(Owner);
try {
return fn();
} catch (err) {
handleError(err);
} finally {
Owner = Owner.owner;
}
}
function getListener() {
return Listener;
}
function getOwner() {
return Owner;
}
function runWithOwner(o, fn) {
let prev = Owner, prevListener = Listener;
Owner = o, Listener = null;
try {
return runUpdates(fn, !0);
} catch (err) {
handleError(err);
} finally {
Owner = prev, Listener = prevListener;
}
}
function startTransition(fn) {
if (Transition && Transition.running)
return fn(), Transition.done;
let l = Listener, o = Owner;
return Promise.resolve().then(() => {
Listener = l, Owner = o;
let t;
return (Scheduler || SuspenseContext) && (t = Transition || (Transition = {
sources: /* @__PURE__ */ new Set(),
effects: [],
promises: /* @__PURE__ */ new Set(),
disposed: /* @__PURE__ */ new Set(),
queue: /* @__PURE__ */ new Set(),
running: !0
}), t.done || (t.done = new Promise((res) => t.resolve = res)), t.running = !0), runUpdates(fn, !1), Listener = Owner = null, t ? t.done : void 0;
});
}
function createContext(defaultValue, options) {
let id2 = /* @__PURE__ */ Symbol("context");
return {
id: id2,
Provider: createProvider(id2),
defaultValue
};
}
function useContext(context) {
let value;
return Owner && Owner.context && (value = Owner.context[context.id]) !== void 0 ? value : context.defaultValue;
}
function children(fn) {
let children2 = createMemo(fn), memo2 = createMemo(() => resolveChildren(children2()));
return memo2.toArray = () => {
let c = memo2();
return Array.isArray(c) ? c : c != null ? [c] : [];
}, memo2;
}
function readSignal() {
let runningTransition = Transition && Transition.running;
if (this.sources && (runningTransition ? this.tState : this.state))
if ((runningTransition ? this.tState : this.state) === STALE) updateComputation(this);
else {
let updates = Updates;
Updates = null, runUpdates(() => lookUpstream(this), !1), Updates = updates;
}
if (Listener) {
let observers = this.observers;
if (!observers || observers[observers.length - 1] !== Listener) {
let sSlot = observers ? observers.length : 0;
Listener.sources ? (Listener.sources.push(this), Listener.sourceSlots.push(sSlot)) : (Listener.sources = [this], Listener.sourceSlots = [sSlot]), observers ? (observers.push(Listener), this.observerSlots.push(Listener.sources.length - 1)) : (this.observers = [Listener], this.observerSlots = [Listener.sources.length - 1]);
}
}
return runningTransition && Transition.sources.has(this) ? this.tValue : this.value;
}
function writeSignal(node, value, isComp) {
let current = Transition && Transition.running && Transition.sources.has(node) ? node.tValue : node.value;
if (!node.comparator || !node.comparator(current, value)) {
if (Transition) {
let TransitionRunning = Transition.running;
(TransitionRunning || !isComp && Transition.sources.has(node)) && (Transition.sources.add(node), node.tValue = value), TransitionRunning || (node.value = value);
} else node.value = value;
node.observers && node.observers.length && runUpdates(() => {
for (let i = 0; i < node.observers.length; i += 1) {
let o = node.observers[i], TransitionRunning = Transition && Transition.running;
TransitionRunning && Transition.disposed.has(o) || ((TransitionRunning ? !o.tState : !o.state) && (o.pure ? Updates.push(o) : Effects.push(o), o.observers && markDownstream(o)), TransitionRunning ? o.tState = STALE : o.state = STALE);
}
if (Updates.length > 1e6)
throw Updates = [], new Error();
}, !1);
}
return value;
}
function updateComputation(node) {
if (!node.fn) return;
cleanNode(node);
let time = ExecCount;
runComputation(node, Transition && Transition.running && Transition.sources.has(node) ? node.tValue : node.value, time), Transition && !Transition.running && Transition.sources.has(node) && queueMicrotask(() => {
runUpdates(() => {
Transition && (Transition.running = !0), Listener = Owner = node, runComputation(node, node.tValue, time), Listener = Owner = null;
}, !1);
});
}
function runComputation(node, value, time) {
let nextValue, owner = Owner, listener = Listener;
Listener = Owner = node;
try {
nextValue = node.fn(value);
} catch (err) {
return node.pure && (Transition && Transition.running ? (node.tState = STALE, node.tOwned && node.tOwned.forEach(cleanNode), node.tOwned = void 0) : (node.state = STALE, node.owned && node.owned.forEach(cleanNode), node.owned = null)), node.updatedAt = time + 1, handleError(err);
} finally {
Listener = listener, Owner = owner;
}
(!node.updatedAt || node.updatedAt <= time) && (node.updatedAt != null && "observers" in node ? writeSignal(node, nextValue, !0) : Transition && Transition.running && node.pure ? (Transition.sources.has(node) || (node.value = nextValue), Transition.sources.add(node), node.tValue = nextValue) : node.value = nextValue, node.updatedAt = time);
}
function createComputation(fn, init, pure, state2 = STALE, options) {
let c = {
fn,
state: state2,
updatedAt: null,
owned: null,
sources: null,
sourceSlots: null,
cleanups: null,
value: init,
owner: Owner,
context: Owner ? Owner.context : null,
pure
};
if (Transition && Transition.running && (c.state = 0, c.tState = state2), Owner === null || Owner !== UNOWNED && (Transition && Transition.running && Owner.pure ? Owner.tOwned ? Owner.tOwned.push(c) : Owner.tOwned = [c] : Owner.owned ? Owner.owned.push(c) : Owner.owned = [c]), ExternalSourceConfig && c.fn) {
let sourceFn = c.fn, [track, trigger] = createSignal(void 0, {
equals: !1
}), ordinary = ExternalSourceConfig.factory(sourceFn, trigger);
onCleanup(() => ordinary.dispose());
let inTransition, triggerInTransition = () => startTransition(trigger).then(() => {
inTransition && (inTransition.dispose(), inTransition = void 0);
});
c.fn = (x) => (track(), Transition && Transition.running ? (inTransition || (inTransition = ExternalSourceConfig.factory(sourceFn, triggerInTransition)), inTransition.track(x)) : ordinary.track(x));
}
return c;
}
function runTop(node) {
let runningTransition = Transition && Transition.running;
if ((runningTransition ? node.tState : node.state) === 0) return;
if ((runningTransition ? node.tState : node.state) === PENDING) return lookUpstream(node);
if (node.suspense && untrack(node.suspense.inFallback)) return node.suspense.effects.push(node);
let ancestors = [node];
for (; (node = node.owner) && (!node.updatedAt || node.updatedAt < ExecCount); ) {
if (runningTransition && Transition.disposed.has(node)) return;
(runningTransition ? node.tState : node.state) && ancestors.push(node);
}
for (let i = ancestors.length - 1; i >= 0; i--) {
if (node = ancestors[i], runningTransition) {
let top = node, prev = ancestors[i + 1];
for (; (top = top.owner) && top !== prev; )
if (Transition.disposed.has(top)) return;
}
if ((runningTransition ? node.tState : node.state) === STALE)
updateComputation(node);
else if ((runningTransition ? node.tState : node.state) === PENDING) {
let updates = Updates;
Updates = null, runUpdates(() => lookUpstream(node, ancestors[0]), !1), Updates = updates;
}
}
}
function runUpdates(fn, init) {
if (Updates) return fn();
let wait = !1;
init || (Updates = []), Effects ? wait = !0 : Effects = [], ExecCount++;
try {
let res = fn();
return completeUpdates(wait), res;
} catch (err) {
wait || (Effects = null), Updates = null, handleError(err);
}
}
function completeUpdates(wait) {
if (Updates && (Scheduler && Transition && Transition.running ? scheduleQueue(Updates) : runQueue(Updates), Updates = null), wait) return;
let res;
if (Transition) {
if (!Transition.promises.size && !Transition.queue.size) {
let sources = Transition.sources, disposed = Transition.disposed;
Effects.push.apply(Effects, Transition.effects), res = Transition.resolve;
for (let e2 of Effects)
"tState" in e2 && (e2.state = e2.tState), delete e2.tState;
Transition = null, runUpdates(() => {
for (let d of disposed) cleanNode(d);
for (let v of sources) {
if (v.value = v.tValue, v.owned)
for (let i = 0, len = v.owned.length; i < len; i++) cleanNode(v.owned[i]);
v.tOwned && (v.owned = v.tOwned), delete v.tValue, delete v.tOwned, v.tState = 0;
}
setTransPending(!1);
}, !1);
} else if (Transition.running) {
Transition.running = !1, Transition.effects.push.apply(Transition.effects, Effects), Effects = null, setTransPending(!0);
return;
}
}
let e = Effects;
Effects = null, e.length && runUpdates(() => runEffects(e), !1), res && res();
}
function runQueue(queue) {
for (let i = 0; i < queue.length; i++) runTop(queue[i]);
}
function scheduleQueue(queue) {
for (let i = 0; i < queue.length; i++) {
let item = queue[i], tasks = Transition.queue;
tasks.has(item) || (tasks.add(item), Scheduler(() => {
tasks.delete(item), runUpdates(() => {
Transition.running = !0, runTop(item);
}, !1), Transition && (Transition.running = !1);
}));
}
}
function runUserEffects(queue) {
let i, userLength = 0;
for (i = 0; i < queue.length; i++) {
let e = queue[i];
e.user ? queue[userLength++] = e : runTop(e);
}
if (sharedConfig.context) {
if (sharedConfig.count) {
sharedConfig.effects || (sharedConfig.effects = []), sharedConfig.effects.push(...queue.slice(0, userLength));
return;
}
setHydrateContext();
}
for (sharedConfig.effects && (sharedConfig.done || !sharedConfig.count) && (queue = [...sharedConfig.effects, ...queue], userLength += sharedConfig.effects.length, delete sharedConfig.effects), i = 0; i < userLength; i++) runTop(queue[i]);
}
function lookUpstream(node, ignore) {
let runningTransition = Transition && Transition.running;
runningTransition ? node.tState = 0 : node.state = 0;
for (let i = 0; i < node.sources.length; i += 1) {
let source = node.sources[i];
if (source.sources) {
let state2 = runningTransition ? source.tState : source.state;
state2 === STALE ? source !== ignore && (!source.updatedAt || source.updatedAt < ExecCount) && runTop(source) : state2 === PENDING && lookUpstream(source, ignore);
}
}
}
function markDownstream(node) {
let runningTransition = Transition && Transition.running;
for (let i = 0; i < node.observers.length; i += 1) {
let o = node.observers[i];
(runningTransition ? !o.tState : !o.state) && (runningTransition ? o.tState = PENDING : o.state = PENDING, o.pure ? Updates.push(o) : Effects.push(o), o.observers && markDownstream(o));
}
}
function cleanNode(node) {
let i;
if (node.sources)
for (; node.sources.length; ) {
let source = node.sources.pop(), index = node.sourceSlots.pop(), obs = source.observers;
if (obs && obs.length) {
let n = obs.pop(), s = source.observerSlots.pop();
index < obs.length && (n.sourceSlots[s] = index, obs[index] = n, source.observerSlots[index] = s);
}
}
if (node.tOwned) {
for (i = node.tOwned.length - 1; i >= 0; i--) cleanNode(node.tOwned[i]);
delete node.tOwned;
}
if (Transition && Transition.running && node.pure)
reset(node, !0);
else if (node.owned) {
for (i = node.owned.length - 1; i >= 0; i--) cleanNode(node.owned[i]);
node.owned = null;
}
if (node.cleanups) {
for (i = node.cleanups.length - 1; i >= 0; i--) node.cleanups[i]();
node.cleanups = null;
}
Transition && Transition.running ? node.tState = 0 : node.state = 0;
}
function reset(node, top) {
if (top || (node.tState = 0, Transition.disposed.add(node)), node.owned)
for (let i = 0; i < node.owned.length; i++) reset(node.owned[i]);
}
function castError(err) {
return err instanceof Error ? err : new Error(typeof err == "string" ? err : "Unknown error", {
cause: err
});
}
function runErrors(err, fns, owner) {
try {
for (let f of fns) f(err);
} catch (e) {
handleError(e, owner && owner.owner || null);
}
}
function handleError(err, owner = Owner) {
let fns = ERROR && owner && owner.context && owner.context[ERROR], error = castError(err);
if (!fns) throw error;
Effects ? Effects.push({
fn() {
runErrors(error, fns, owner);
},
state: STALE
}) : runErrors(error, fns, owner);
}
function resolveChildren(children2) {
if (typeof children2 == "function" && !children2.length) return resolveChildren(children2());
if (Array.isArray(children2)) {
let results = [];
for (let i = 0; i < children2.length; i++) {
let result = resolveChildren(children2[i]);
if (Array.isArray(result))
if (result.length < 32768) results.push.apply(results, result);
else for (let j = 0; j < result.length; j++) results.push(result[j]);
else
results.push(result);
}
return results;
}
return children2;
}
function createProvider(id2, options) {
return function(props) {
let res;
return createRenderEffect(() => res = untrack(() => (Owner.context = {
...Owner.context,
[id2]: props.value
}, children(() => props.children))), void 0), res;
};
}
function dispose(d) {
for (let i = 0; i < d.length; i++) d[i]();
}
function mapArray(list, mapFn, options = {}) {
let items = [], mapped = [], disposers = [], len = 0, indexes = mapFn.length > 1 ? [] : null;
return onCleanup(() => dispose(disposers)), () => {
let newItems = list() || [], newLen = newItems.length, i, j;
return newItems[$TRACK], untrack(() => {
let newIndices, newIndicesNext, temp, tempdisposers, tempIndexes, start2, end, newEnd, item;
if (newLen === 0)
len !== 0 && (dispose(disposers), disposers = [], items = [], mapped = [], len = 0, indexes && (indexes = [])), options.fallback && (items = [FALLBACK], mapped[0] = createRoot((disposer) => (disposers[0] = disposer, options.fallback())), len = 1);
else if (len === 0) {
for (mapped = new Array(newLen), j = 0; j < newLen; j++)
items[j] = newItems[j], mapped[j] = createRoot(mapper);
len = newLen;
} else {
for (temp = new Array(newLen), tempdisposers = new Array(newLen), indexes && (tempIndexes = new Array(newLen)), start2 = 0, end = Math.min(len, newLen); start2 < end && items[start2] === newItems[start2]; start2++) ;
for (end = len - 1, newEnd = newLen - 1; end >= start2 && newEnd >= start2 && items[end] === newItems[newEnd]; end--, newEnd--)
temp[newEnd] = mapped[end], tempdisposers[newEnd] = disposers[end], indexes && (tempIndexes[newEnd] = indexes[end]);
for (newIndices = /* @__PURE__ */ new Map(), newIndicesNext = new Array(newEnd + 1), j = newEnd; j >= start2; j--)
item = newItems[j], i = newIndices.get(item), newIndicesNext[j] = i === void 0 ? -1 : i, newIndices.set(item, j);
for (i = start2; i <= end; i++)
item = items[i], j = newIndices.get(item), j !== void 0 && j !== -1 ? (temp[j] = mapped[i], tempdisposers[j] = disposers[i], indexes && (tempIndexes[j] = indexes[i]), j = newIndicesNext[j], newIndices.set(item, j)) : disposers[i]();
for (j = start2; j < newLen; j++)
j in temp ? (mapped[j] = temp[j], disposers[j] = tempdisposers[j], indexes && (indexes[j] = tempIndexes[j], indexes[j](j))) : mapped[j] = createRoot(mapper);
mapped = mapped.slice(0, len = newLen), items = newItems.slice(0);
}
return mapped;
});
function mapper(disposer) {
if (disposers[j] = disposer, indexes) {
let [s, set] = createSignal(j);
return indexes[j] = set, mapFn(newItems[j], s);
}
return mapFn(newItems[j]);
}
};
}
function createComponent(Comp, props) {
if (hydrationEnabled && sharedConfig.context) {
let c = sharedConfig.context;
setHydrateContext(nextHydrateContext());
let r = untrack(() => Comp(props || {}));
return setHydrateContext(c), r;
}
return untrack(() => Comp(props || {}));
}
function trueFn() {
return !0;
}
function resolveSource(s) {
return (s = typeof s == "function" ? s() : s) ? s : {};
}
function resolveSources() {
for (let i = 0, length = this.length; i < length; ++i) {
let v = this[i]();
if (v !== void 0) return v;
}
}
function mergeProps(...sources) {
let proxy = !1;
for (let i = 0; i < sources.length; i++) {
let s = sources[i];
proxy = proxy || !!s && $PROXY in s, sources[i] = typeof s == "function" ? (proxy = !0, createMemo(s)) : s;
}
if (SUPPORTS_PROXY && proxy)
return new Proxy({
get(property) {
for (let i = sources.length - 1; i >= 0; i--) {
let v = resolveSource(sources[i])[property];
if (v !== void 0) return v;
}
},
has(property) {
for (let i = sources.length - 1; i >= 0; i--)
if (property in resolveSource(sources[i])) return !0;
return !1;
},
keys() {
let keys = [];
for (let i = 0; i < sources.length; i++) keys.push(...Object.keys(resolveSource(sources[i])));
return [...new Set(keys)];
}
}, propTraps);
let sourcesMap = {}, defined = /* @__PURE__ */ Object.create(null);
for (let i = sources.length - 1; i >= 0; i--) {
let source = sources[i];
if (!source) continue;
let sourceKeys = Object.getOwnPropertyNames(source);
for (let i2 = sourceKeys.length - 1; i2 >= 0; i2--) {
let key = sourceKeys[i2];
if (key === "__proto__" || key === "constructor") continue;
let desc = Object.getOwnPropertyDescriptor(source, key);
if (!defined[key])
defined[key] = desc.get ? {
enumerable: !0,
configurable: !0,
get: resolveSources.bind(sourcesMap[key] = [desc.get.bind(source)])
} : desc.value !== void 0 ? desc : void 0;
else {
let sources2 = sourcesMap[key];
sources2 && (desc.get ? sources2.push(desc.get.bind(source)) : desc.value !== void 0 && sources2.push(() => desc.value));
}
}
}
let target = {}, definedKeys = Object.keys(defined);
for (let i = definedKeys.length - 1; i >= 0; i--) {
let key = definedKeys[i], desc = defined[key];
desc && desc.get ? Object.defineProperty(target, key, desc) : target[key] = desc ? desc.value : void 0;
}
return target;
}
function splitProps(props, ...keys) {
let len = keys.length;
if (SUPPORTS_PROXY && $PROXY in props) {
let blocked = len > 1 ? keys.flat() : keys[0], res = keys.map((k) => new Proxy({
get(property) {
return k.includes(property) ? props[property] : void 0;
},
has(property) {
return k.includes(property) && property in props;
},
keys() {
return k.filter((property) => property in props);
}
}, propTraps));
return res.push(new Proxy({
get(property) {
return blocked.includes(property) ? void 0 : props[property];
},
has(property) {
return blocked.includes(property) ? !1 : property in props;
},
keys() {
return Object.keys(props).filter((k) => !blocked.includes(k));
}
}, propTraps)), res;
}
let objects = [];
for (let i = 0; i <= len; i++)
objects[i] = {};
for (let propName of Object.getOwnPropertyNames(props)) {
let keyIndex = len;
for (let i = 0; i < keys.length; i++)
if (keys[i].includes(propName)) {
keyIndex = i;
break;
}
let desc = Object.getOwnPropertyDescriptor(props, propName);
!desc.get && !desc.set && desc.enumerable && desc.writable && desc.configurable ? objects[keyIndex][propName] = desc.value : Object.defineProperty(objects[keyIndex], propName, desc);
}
return objects;
}
function For(props) {
let fallback = "fallback" in props && {
fallback: () => props.fallback
};
return createMemo(mapArray(() => props.each, props.children, fallback || void 0));
}
function Show(props) {
let keyed = props.keyed, conditionValue = createMemo(() => props.when, void 0, void 0), condition = keyed ? conditionValue : createMemo(conditionValue, void 0, {
equals: (a, b) => !a == !b
});
return createMemo(() => {
let c = condition();
if (c) {
let child = props.children;
return typeof child == "function" && child.length > 0 ? untrack(() => child(keyed ? c : () => {
if (!untrack(condition)) throw narrowedError("Show");
return conditionValue();
})) : child;
}
return props.fallback;
}, void 0, void 0);
}
function ErrorBoundary(props) {
let err;
sharedConfig.context && sharedConfig.load && (err = sharedConfig.load(sharedConfig.getContextId()));
let [errored, setErrored] = createSignal(err, void 0);
return Errors || (Errors = /* @__PURE__ */ new Set()), Errors.add(setErrored), onCleanup(() => Errors.delete(setErrored)), createMemo(() => {
let e;
if (e = errored()) {
let f = props.fallback;
return typeof f == "function" && f.length ? untrack(() => f(e, () => setErrored())) : f;
}
return catchError(() => props.children, setErrored);
}, void 0, void 0);
}
var sharedConfig, IS_DEV, equalFn, $PROXY, SUPPORTS_PROXY, $TRACK, signalOptions, ERROR, runEffects, STALE, PENDING, UNOWNED, Owner, Transition, Scheduler, ExternalSourceConfig, Listener, Updates, Effects, ExecCount, transPending, setTransPending, SuspenseContext, FALLBACK, hydrationEnabled, propTraps, narrowedError, Errors, init_solid = __esm({
"../../node_modules/.pnpm/[email protected]/node_modules/solid-js/dist/solid.js"() {
sharedConfig = {
context: void 0,
registry: void 0,
effects: void 0,
done: !1,
getContextId() {
return getContextId(this.context.count);
},
getNextContextId() {
return getContextId(this.context.count++);
}
};
IS_DEV = !1, equalFn = (a, b) => a === b, $PROXY = /* @__PURE__ */ Symbol("solid-proxy"), SUPPORTS_PROXY = typeof Proxy == "function", $TRACK = /* @__PURE__ */ Symbol("solid-track"), signalOptions = {
equals: equalFn
}, ERROR = null, runEffects = runQueue, STALE = 1, PENDING = 2, UNOWNED = {
owned: null,
cleanups: null,
context: null,
owner: null
}, Owner = null, Transition = null, Scheduler = null, ExternalSourceConfig = null, Listener = null, Updates = null, Effects = null, ExecCount = 0;
[transPending, setTransPending] = /* @__PURE__ */ createSignal(!1);
FALLBACK = /* @__PURE__ */ Symbol("fallback");
hydrationEnabled = !1;
propTraps = {
get(_, property, receiver) {
return property === $PROXY ? receiver : _.get(property);
},
has(_, property) {
return property === $PROXY ? !0 : _.has(property);
},
set: trueFn,
deleteProperty: trueFn,
getOwnPropertyDescriptor(_, property) {
return {
configurable: !0,
enumerable: !0,
get() {
return _.get(property);
},
set: trueFn,
deleteProperty: trueFn
};
},
ownKeys(_) {
return _.keys();
}
};
narrowedError = (name) => `Stale read from <${name}>.`;
}
});
// ../../node_modules/.pnpm/[email protected]/node_modules/solid-js/web/dist/web.js
function getPropAlias(prop, tagName) {
let a = PropAliases[prop];
return typeof a == "object" ? a[tagName] ? a.$ : void 0 : a;
}
function reconcileArrays(parentNode, a, b) {
let bLength = b.length, aEnd = a.length, bEnd = bLength, aStart = 0, bStart = 0, after = a[aEnd - 1].nextSibling, map = null;
for (; aStart < aEnd || bStart < bEnd; ) {
if (a[aStart] === b[bStart]) {
aStart++, bStart++;
continue;
}
for (; a[aEnd - 1] === b[bEnd - 1]; )
aEnd--, bEnd--;
if (aEnd === aStart) {
let node = bEnd < bLength ? bStart ? b[bStart - 1].nextSibling : b[bEnd - bStart] : after;
for (; bStart < bEnd; ) parentNode.insertBefore(b[bStart++], node);
} else if (bEnd === bStart)
for (; aStart < aEnd; )
(!map || !map.has(a[aStart])) && a[aStart].remove(), aStart++;
else if (a[aStart] === b[bEnd - 1] && b[bStart] === a[aEnd - 1]) {
let node = a[--aEnd].nextSibling;
parentNode.insertBefore(b[bStart++], a[aStart++].nextSibling), parentNode.insertBefore(b[--bEnd], node), a[aEnd] = b[bEnd];
} else {
if (!map) {
map = /* @__PURE__ */ new Map();
let i = bStart;
for (; i < bEnd; ) map.set(b[i], i++);
}
let index = map.get(a[aStart]);
if (index != null)
if (bStart < index && index < bEnd) {
let i = aStart, sequence = 1, t;
for (; ++i < aEnd && i < bEnd && !((t = map.get(a[i])) == null || t !== index + sequence); )
sequence++;
if (sequence > index - bStart) {
let node = a[aStart];
for (; bStart < index; ) parentNode.insertBefore(b[bStart++], node);
} else parentNode.replaceChild(b[bStart++], a[aStart++]);
} else aStart++;
else a[aStart++].remove();
}
}
}
function render(code, element, init, options = {}) {
let disposer;
return createRoot((dispose2) => {
disposer = dispose2, element === document ? code() : insert(element, code(), element.firstChild ? null : void 0, init);
}, options.owner), () => {
disposer(), element.textContent = "";
};
}
function template(html, isImportNode, isSVG, isMathML) {
let node, create = () => {
let t = isMathML ? document.createElementNS("http://www.w3.org/1998/Math/MathML", "template") : document.createElement("template");
return t.innerHTML = html, isSVG ? t.content.firstChild.firstChild : isMathML ? t.firstChild : t.content.firstChild;
}, fn = isImportNode ? () => untrack(() => document.importNode(node || (node = create()), !0)) : () => (node || (node = create())).cloneNode(!0);
return fn.cloneNode = fn, fn;
}
function delegateEvents(eventNames, document2 = window.document) {
let e = document2[$$EVENTS] || (document2[$$EVENTS] = /* @__PURE__ */ new Set());
for (let i = 0, l = eventNames.length; i < l; i++) {
let name = eventNames[i];
e.has(name) || (e.add(name), document2.addEventListener(name, eventHandler));
}
}
function setAttribute(node, name, value) {
isHydrating(node) || (value == null ? node.removeAttribute(name) : node.setAttribute(name, value));
}
function setAttributeNS(node, namespace, name, value) {
isHydrating(node) || (value == null ? node.removeAttributeNS(namespace, name) : node.setAttributeNS(namespace, name, value));
}
function setBoolAttribute(node, name, value) {
isHydrating(node) || (value ? node.setAttribute(name, "") : node.removeAttribute(name));
}
function className(node, value) {
isHydrating(node) || (value == null ? node.removeAttribute("class") : node.className = value);
}
function addEventListener(node, name, handler, delegate) {
if (delegate)
Array.isArray(handler) ? (node[`$$${name}`] = handler[0], node[`$$${name}Data`] = handler[1]) : node[`$$${name}`] = handler;
else if (Array.isArray(handler)) {
let handlerFn = handler[0];
node.addEventListener(name, handler[0] = (e) => handlerFn.call(node, handler[1], e));
} else node.addEventListener(name, handler, typeof handler != "function" && handler);
}
function classList(node, value, prev = {}) {
let classKeys = Object.keys(value || {}), prevKeys = Object.keys(prev), i, len;
for (i = 0, len = prevKeys.length; i < len; i++) {
let key = prevKeys[i];
!key || key === "undefined" || value[key] || (toggleClassKey(node, key, !1), delete prev[key]);
}
for (i = 0, len = classKeys.length; i < len; i++) {
let key = classKeys[i], classValue = !!value[key];
!key || key === "undefined" || prev[key] === classValue || !classValue || (toggleClassKey(node, key, !0), prev[key] = classValue);
}
return prev;
}
function style(node, value, prev) {
if (!value) return prev ? setAttribute(node, "style") : value;
let nodeStyle = node.style;
if (typeof value == "string") return nodeStyle.cssText = value;
typeof prev == "string" && (nodeStyle.cssText = prev = void 0), prev || (prev = {}), value || (value = {});
let v, s;
for (s in prev)
value[s] == null && nodeStyle.removeProperty(s), delete prev[s];
for (s in value)
v = value[s], v !== prev[s] && (nodeStyle.setProperty(s, v), prev[s] = v);
return prev;
}
function setStyleProperty(node, name, value) {
value != null ? node.style.setProperty(name, value) : node.style.removeProperty(name);
}
function spread(node, props = {}, isSVG, skipChildren) {
let prevProps = {};
return skipChildren || createRenderEffect(() => prevProps.children = insertExpression(node, props.children, prevProps.children)), createRenderEffect(() => typeof props.ref == "function" && use(props.ref, node)), createRenderEffect(() => assign(node, props, isSVG, !0, prevProps, !0)), prevProps;
}
function use(fn, element, arg) {
return untrack(() => fn(element, arg));
}
function insert(parent, accessor, marker, initial) {
if (marker !== void 0 && !initial && (initial = []), typeof accessor != "function") return insertExpression(parent, accessor, initial, marker);
createRenderEffect((current) => insertExpression(parent, accessor(), current, marker), initial);
}
function assign(node, props, isSVG, skipChildren, prevProps = {}, skipRef = !1) {
props || (props = {});
for (let prop in prevProps)
if (!(prop in props)) {
if (prop === "children") continue;
prevProps[prop] = assignProp(node, prop, null, prevProps[prop], isSVG, skipRef, props);
}
for (let prop in props) {
if (prop === "children") {
skipChildren || insertExpression(node, props.children);
continue;
}
let value = props[prop];
prevProps[prop] = assignProp(node, prop, value, prevProps[prop], isSVG, skipRef, props);
}
}
function getNextElement(template2) {
let node, key;
return !isHydrating() || !(node = sharedConfig.registry.get(key = getHydrationKey())) ? template2() : (sharedConfig.completed && sharedConfig.completed.add(node), sharedConfig.registry.delete(key), node);
}
function isHydrating(node) {
return !!sharedConfig.context && !sharedConfig.done && (!node || node.isConnected);
}
function toPropertyName(name) {
return name.toLowerCase().replace(/-([a-z])/g, (_, w) => w.toUpperCase());
}
function toggleClassKey(node, key, value) {
let classNames = key.trim().split(/\s+/);
for (let i = 0, nameLen = classNames.length; i < nameLen; i++) node.classList.toggle(classNames[i], value);
}
function assignProp(node, prop, value, prev, isSVG, skipRef, props) {
let isCE, isProp, isChildProp, propAlias, forceProp;
if (prop === "style") return style(node, value, prev);
if (prop === "classList") return classList(node, value, prev);
if (value === prev) return prev;
if (prop === "ref")
skipRef || value(node);
else if (prop.slice(0, 3) === "on:") {
let e = prop.slice(3);
prev && node.removeEventListener(e, prev, typeof prev != "function" && prev), value && node.addEventListener(e, value, typeof value != "function" && value);
} else if (prop.slice(0, 10) === "oncapture:") {
let e = prop.slice(10);
prev && node.removeEventListener(e, prev, !0), value && node.addEventListener(e, value, !0);
} else if (prop.slice(0, 2) === "on") {
let name = prop.slice(2).toLowerCase(), delegate = DelegatedEvents.has(name);
if (!delegate && prev) {
let h = Array.isArray(prev) ? prev[0] : prev;
node.removeEventListener(name, h);
}
(delegate || value) && (addEventListener(node, name, value, delegate), delegate && delegateEvents([name]));
} else if (prop.slice(0, 5) === "attr:")
setAttribute(node, prop.slice(5), value);
else if (prop.slice(0, 5) === "bool:")
setBoolAttribute(node, prop.slice(5), value);
else if ((forceProp = prop.slice(0, 5) === "prop:") || (isChildProp = ChildProperties.has(prop)) || !isSVG && ((propAlias = getPropAlias(prop, node.tagName)) || (isProp = Properties.has(prop))) || (isCE = node.nodeName.includes("-") || "is" in props)) {
if (forceProp)
prop = prop.slice(5), isProp = !0;
else if (isHydrating(node)) return value;
prop === "class" || prop === "className" ? className(node, value) : isCE && !isProp && !isChildProp ? node[toPropertyName(prop)] = value : node[propAlias || prop] = value;
} else {
let ns = isSVG && prop.indexOf(":") > -1 && SVGNamespace[prop.split(":")[0]];
ns ? setAttributeNS(node, ns, prop, value) : setAttribute(node, Aliases[prop] || prop, value);
}
return value;
}
function eventHandler(e) {
if (sharedConfig.registry && sharedConfig.events && sharedConfig.events.find(([el, ev]) => ev === e))
return;
let node = e.target, key = `$$${e.type}`, oriTarget = e.target, oriCurrentTarget = e.currentTarget, retarget = (value) => Object.defineProperty(e, "target", {
configurable: !0,
value
}), handleNode = () => {
let handler = node[key];
if (handler && !node.disabled) {
let data = node[`${key}Data`];
if (data !== void 0 ? handler.call(node, data, e) : handler.call(node, e), e.cancelBubble) return;
}
return node.host && typeof node.host != "string" && !node.host._$host && node.contains(e.target) && retarget(node.host), !0;
}, walkUpTree = () => {
for (; handleNode() && (node = node._$host || node.parentNode || node.host); ) ;
};
if (Object.defineProperty(e, "currentTarget", {
configurable: !0,
get() {
return node || document;
}
}), sharedConfig.registry && !sharedConfig.done && (sharedConfig.done = _$HY.done = !0), e.composedPath) {
let path = e.composedPath();
retarget(path[0]);
for (let i = 0; i < path.length - 2 && (node = path[i], !!handleNode()); i++) {
if (node._$host) {
node = node._$host, walkUpTree();
break;
}
if (node.parentNode === oriCurrentTarget)
break;
}
} else walkUpTree();
retarget(oriTarget);
}
function insertExpression(parent, value, current, marker, unwrapArray) {
let hydrating = isHydrating(parent);
if (hydrating) {
!current && (current = [...parent.childNodes]);
let cleaned = [];
for (let i = 0; i < current.length; i++) {
let node = current[i];
node.nodeType === 8 && node.data.slice(0, 2) === "!$" ? node.remove() : cleaned.push(node);
}
current = cleaned;
}
for (; typeof current == "function"; ) current = current();
if (value === current) return current;
let t = typeof value, multi = marker !== void 0;
if (parent = multi && current[0] && current[0].parentNode || parent, t === "string" || t === "number") {
if (hydrating || t === "number" && (value = value.toString(), value === current))
return current;
if (multi) {
let node = current[0];
node && node.nodeType === 3 ? node.data !== value && (node.data = value) : node = document.createTextNode(value), current = cleanChildren(parent, current, marker, node);
} else
current !== "" && typeof current == "string" ? current = parent.firstChild.data = value : current = parent.textContent = value;
} else if (value == null || t === "boolean") {
if (hydrating) return current;
current = cleanChildren(parent, current, marker);
} else {
if (t === "function")
return createRenderEffect(() => {
let v = value();
for (; typeof v == "function"; ) v = v();
current = insertExpression(parent, v, current, marker);
}), () => current;
if (Array.isArray(value)) {
let array = [], currentArray = current && Array.isArray(current);
if (normalizeIncomingArray(array, value, current, unwrapArray))
return createRenderEffect(() => current = insertExpression(parent, array, current, marker, !0)), () => current;
if (hydrating) {
if (!array.length) return current;
if (marker === void 0) return current = [...parent.childNodes];
let node = array[0];
if (node.parentNode !== parent) return current;
let nodes = [node];
for (; (node = node.nextSibling) !== marker; ) nodes.push(node);
return current = nodes;
}
if (array.length === 0) {
if (current = cleanChildren(parent, current, marker), multi) return current;
} else currentArray ? current.length === 0 ? appendNodes(parent, array, marker) : reconcileArrays(parent, current, array) : (current && cleanChildren(parent), appendNodes(parent, array));
current = array;
} else if (value.nodeType) {
if (hydrating && value.parentNode) return current = multi ? [value] : value;
if (Array.isArray(current)) {
if (multi) return current = cleanChildren(parent, current, marker, value);
cleanChildren(parent, current, null, value);
} else current == null || current === "" || !parent.firstChild ? parent.appendChild(value) : parent.replaceChild(value, parent.firstChild);
current = value;
}
}
return current;
}
function normalizeIncomingArray(normalized, array, current, unwrap2) {
let dynamic = !1;
for (let i = 0, len = array.length; i < len; i++) {
let item = array[i], prev = current && current[normalized.length], t;
if (!(item == null || item === !0 || item === !1)) if ((t = typeof item) == "object" && item.nodeType)
normalized.push(item);
else if (Array.isArray(item))
dynamic = normalizeIncomingArray(normalized, item, prev) || dynamic;
else if (t === "function")
if (unwrap2) {
for (; typeof item == "function"; ) item = item();
dynamic = normalizeIncomingArray(normalized, Array.isArray(item) ? item : [item], Array.isArray(prev) ? prev : [prev]) || dynamic;
} else
normalized.push(item), dynamic = !0;
else {
let value = String(item);
prev && prev.nodeType === 3 && prev.data === value ? normalized.push(prev) : normalized.push(document.createTextNode(value));
}
}
return dynamic;
}
function appendNodes(parent, array, marker = null) {
for (let i = 0, len = array.length; i < len; i++) parent.insertBefore(array[i], marker);
}
function cleanChildren(parent, current, marker, replacement) {
if (marker === void 0) return parent.textContent = "";
let node = replacement || document.createTextNode("");
if (current.length) {
let inserted = !1;
for (let i = current.length - 1; i >= 0; i--) {
let el = current[i];
if (node !== el) {
let isParent = el.parentNode === parent;
!inserted && !i ? isParent ? parent.replaceChild(node, el) : parent.insertBefore(node, marker) : isParent && el.remove();
} else inserted = !0;
}
} else parent.insertBefore(node, marker);
return [node];
}
function getHydrationKey() {
return sharedConfig.getNextContextId();
}
function createElement(tagName, isSVG = !1, is = void 0) {
return isSVG ? document.createElementNS(SVG_NAMESPACE, tagName) : document.createElement(tagName, {
is
});
}
function Portal(props) {
let {
useShadow
} = props, marker = document.createTextNode(""), mount = () => props.mount || document.body, owner = getOwner(), content, hydrating = !!sharedConfig.context;
return createEffect(() => {
hydrating && (getOwner().user = hydrating = !1), content || (content = runWithOwner(owner, () => createMemo(() => props.children)));
let el = mount();
if (el instanceof HTMLHeadElement) {
let [clean, setClean] = createSignal(!1), cleanup = () => setClean(!0);
createRoot((dispose2) => insert(el, () => clean() ? dispose2() : content(), null)), onCleanup(cleanup);
} else {
let container = createElement(props.isSVG ? "g" : "div", props.isSVG), renderRoot = useShadow && container.attachShadow ? container.attachShadow({
mode: "open"
}) : container;
Object.defineProperty(container, "_$host", {
get() {
return marker.parentNode;
},
configurable: !0
}), insert(renderRoot, content), el.appendChild(container), props.ref && props.ref(container), onCleanup(() => el.contains(container) && el.removeChild(container));
}
}, void 0, {
render: !hydrating
}), marker;
}
function createDynamic(component, props) {
let cached = createMemo(component);
return createMemo(() => {
let component2 = cached();
switch (typeof component2) {
case "function":
return untrack(() => component2(props));
case "string":
let isSvg = SVGElements.has(component2), el = sharedConfig.context ? getNextElement() : createElement(component2, isSvg, untrack(() => props.is));
return spread(el, props, isSvg), el;
}
});
}
function Dynamic(props) {
let [, others] = splitProps(props, ["component"]);
return createDynamic(() => props.component, others);
}
var booleans, Properties, ChildProperties, Aliases, PropAliases, DelegatedEvents, SVGElements, SVGNamespace, memo, $$EVENTS, SVG_NAMESPACE, init_web = __esm({
"../../node_modules/.pnpm/[email protected]/node_modules/solid-js/web/dist/web.js"() {
init_solid();
init_solid();
booleans = [
"allowfullscreen",
"async",
"alpha",
"autofocus",
"autoplay",
"checked",
"controls",
"default",
"disabled",
"formnovalidate",
"hidden",
"indeterminate",
"inert",
"ismap",
"loop",
"multiple",
"muted",
"nomodule",
"novalidate",
"open",
"playsinline",
"readonly",
"required",
"reversed",
"seamless",
"selected",
"adauctionheaders",
"browsingtopics",
"credentialless",
"defaultchecked",
"defaultmuted",
"defaultselected",
"defer",
"disablepictureinpicture",
"disableremoteplayback",
"preservespitch",
"shadowrootclonable",
"shadowrootcustomelementregistry",
"shadowrootdelegatesfocus",
"shadowrootserializable",
"sharedstoragewritable"
], Properties = /* @__PURE__ */ new Set([
"className",
"value",
"readOnly",
"noValidate",
"formNoValidate",
"isMap",
"noModule",
"playsInline",
"adAuctionHeaders",
"allowFullscreen",
"browsingTopics",
"defaultChecked",
"defaultMuted",
"defaultSelected",
"disablePictureInPicture",
"disableRemotePlayback",
"preservesPitch",
"shadowRootClonable",
"shadowRootCustomElementRegistry",
"shadowRootDelegatesFocus",
"shadowRootSerializable",
"sharedStorageWritable",
...booleans
]), ChildProperties = /* @__PURE__ */ new Set(["innerHTML", "textContent", "innerText", "children"]), Aliases = /* @__PURE__ */ Object.assign(/* @__PURE__ */ Object.create(null), {
className: "class",
htmlFor: "for"
}), PropAliases = /* @__PURE__ */ Object.assign(/* @__PURE__ */ Object.create(null), {
class: "className",
novalidate: {
$: "noValidate",
FORM: 1
},
formnovalidate: {
$: "formNoValidate",
BUTTON: 1,
INPUT: 1
},
ismap: {
$: "isMap",
IMG: 1
},
nomodule: {
$: "noModule",
SCRIPT: 1
},
playsinline: {
$: "playsInline",
VIDEO: 1
},
readonly: {
$: "readOnly",
INPUT: 1,
TEXTAREA: 1
},
adauctionheaders: {
$: "adAuctionHeaders",
IFRAME: 1
},
allowfullscreen: {
$: "allowFullscreen",
IFRAME: 1
},
browsingtopics: {
$: "browsingTopics",
IMG: 1
},
defaultchecked: {
$: "defaultChecked",
INPUT: 1
},
defaultmuted: {
$: "defaultMuted",
AUDIO: 1,
VIDEO: 1
},
defaultselected: {
$: "defaultSelected",
OPTION: 1
},
disablepictureinpicture: {
$: "disablePictureInPicture",
VIDEO: 1
},
disableremoteplayback: {
$: "disableRemotePlayback",
AUDIO: 1,
VIDEO: 1
},
preservespitch: {
$: "preservesPitch",
AUDIO: 1,
VIDEO: 1
},
shadowrootclonable: {
$: "shadowRootClonable",
TEMPLATE: 1
},
shadowrootdelegatesfocus: {
$: "shadowRootDelegatesFocus",
TEMPLATE: 1
},
shadowrootserializable: {
$: "shadowRootSerializable",
TEMPLATE: 1
},
sharedstoragewritable: {
$: "sharedStorageWritable",
IFRAME: 1,
IMG: 1
}
});
DelegatedEvents = /* @__PURE__ */ new Set(["beforeinput", "click", "dblclick", "contextmenu", "focusin", "focusout", "input", "keydown", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup", "pointerdown", "pointermove", "pointerout", "pointerover", "pointerup", "touchend", "touchmove", "touchstart"]), SVGElements = /* @__PURE__ */ new Set([
"altGlyph",
"altGlyphDef",
"altGlyphItem",
"animate",
"animateColor",
"animateMotion",
"animateTransform",
"circle",
"clipPath",
"color-profile",
"cursor",
"defs",
"desc",
"ellipse",
"feBlend",
"feColorMatrix",
"feComponentTransfer",
"feComposite",
"feConvolveMatrix",
"feDiffuseLighting",
"feDisplacementMap",
"feDistantLight",
"feDropShadow",
"feFlood",
"feFuncA",
"feFuncB",
"feFuncG",
"feFuncR",
"feGaussianBlur",
"feImage",
"feMerge",
"feMergeNode",
"feMorphology",
"feOffset",
"fePointLight",
"feSpecularLighting",
"feSpotLight",
"feTile",
"feTurbulence",
"filter",
"font",
"font-face",
"font-face-format",
"font-face-name",
"font-face-src",
"font-face-uri",
"foreignObject",
"g",
"glyph",
"glyphRef",
"hkern",
"image",
"line",
"linearGradient",
"marker",
"mask",
"metadata",
"missing-glyph",
"mpath",
"path",
"pattern",
"polygon",
"polyline",
"radialGradient",
"rect",
"set",
"stop",
"svg",
"switch",
"symbol",
"text",
"textPath",
"tref",
"tspan",
"use",
"view",
"vkern"
]), SVGNamespace = {
xlink: "http://www.w3.org/1999/xlink",
xml: "http://www.w3.org/XML/1998/namespace"
}, memo = (fn) => createMemo(() => fn());
$$EVENTS = "_$DX_DELEGATE";
SVG_NAMESPACE = "http://www.w3.org/2000/svg";
}
});
// ../reader/dist/chunk-JXES5MWD.js
function ReaderTextsProvider(props) {
let texts = untrack(() => props.texts);
return createComponent(ReaderTextsContext.Provider, {
value: texts,
get children() {
return props.children;
}
});
}
function useReaderTexts() {
return useContext(ReaderTextsContext);
}
var en_default2, ja_default, zh_CN_default, readerLocales, ReaderTextsContext, init_chunk_JXES5MWD = __esm({
"../reader/dist/chunk-JXES5MWD.js"() {
"use strict";
init_web();
init_solid();
en_default2 = {
common: {
actions: {
apply: "Apply",
close: "Close",
confirm: "Confirm",
current: "Current",
default: "Default",
submit: "Submit",
zoomIn: "Zoom in",
zoomOut: "Zoom out"
},
status: {
failed: "Failed",
loading: "Loading..."
}
},
reader: {
readingOptions: "Reading options",
fullscreen: "Fullscreen",
exitFullscreen: "Exit fullscreen",
adjustScrollViewport: "Adjust Scroll viewport size",
resizeScrollViewport: "Resize Scroll viewport",
fit: "Fit",
fill: "Fill",
applyGlobally: "Set Default",
pagedMode: "Paged mode",
singlePageMode: "Single-page layout",
doublePageMode: "Double-page layout",
pairFirstAndSecondPages: "Pair 1+2",
pairSecondAndThirdPages: "Pair 2+3",
scrollMode: "Scroll mode",
rightTapPrevious: `Right side action:
Previous page`,
rightTapNext: `Right side action:
Next page`,
directionRtl: `Reading direction:
Right to left`,
directionLtr: `Reading direction:
Left to right`,
directionTtb: `Reading direction:
Top to bottom`,
download: "Download",
downloadHelpLabel: "Can't download?",
openImage: "Open image",
displayedImageShort: "Displayed",
originalImageShort: "Original",
downloadDisplayedImage: "Displayed image",
downloadOriginalImage: "Original image",
originalImageSource: "Original image source",
originalImageUnavailable: "Original image unavailable",
startReading: "Read",
continueReading: "Continue",
endPage: "End",
end: "End of gallery. Tap to exit.",
reloadPage: "Reload page"
},
help: {
title: "Help",
sections: [
{
title: "Reader",
items: [
"**Tap** the center to show or hide the toolbar.",
"**Swipe or scroll** in the reading direction; tap either side or use the **Arrow keys** to turn pages.",
"In **Paged mode**, pull down or swipe sideways across the reading direction to open Scroll Preview.",
"**Pinch** to zoom. With a mouse, **press and hold** an image or use **Ctrl/⌘ + wheel** to zoom; while zoomed, press and hold, double-click, or double-tap to exit."
]
}
]
},
gallery: {
scrollPreview: "Scroll Preview",
confirmScrollPreviewDirection: "Change Scroll Preview direction?",
openScrollPreview: "Open full-screen Scroll Preview",
scrollPreviewDirectionTtb: "Scroll Preview: top to bottom",
scrollPreviewDirectionLtr: "Scroll Preview: left to right",
scrollPreviewDirectionRtl: "Scroll Preview: right to left"
},
errors: {
imageNotFound: "Image not found",
loadFailed: "Load failed",
imageLoadFailed: "Image load failed",
downloadFailed: "Download failed"
}
}, ja_default = {
common: {
actions: {
apply: "適用",
close: "閉じる",
confirm: "確定",
current: "現在位置",
default: "デフォルト",
submit: "送信",
zoomIn: "拡大",
zoomOut: "縮小"
},
status: {
failed: "失敗",
loading: "読み込み中..."
}
},
reader: {
readingOptions: "閲覧オプション",
fullscreen: "フルスクリーン",
exitFullscreen: "フルスクリーンを終了",
adjustScrollViewport: "スクロール表示領域のサイズを調整",
resizeScrollViewport: "スクロール表示領域をリサイズ",
fit: "フィット",
fill: "画面いっぱい",
applyGlobally: "デフォルトに設定",
pagedMode: "ページモード",
singlePageMode: "単ページレイアウト",
doublePageMode: "見開きレイアウト",
pairFirstAndSecondPages: "1+2ページを組み合わせる",
pairSecondAndThirdPages: "2+3ページを組み合わせる",
scrollMode: "スクロールモード",
rightTapPrevious: `右側の操作:
前のページ`,
rightTapNext: `右側の操作:
次のページ`,
directionRtl: `閲覧方向:
右から左`,
directionLtr: `閲覧方向:
左から右`,
directionTtb: `閲覧方向:
上から下`,
download: "ダウンロード",
downloadHelpLabel: "ダウンロードできませんか?",
openImage: "画像を開く",
displayedImageShort: "表示中",
originalImageShort: "オリジナル",
downloadDisplayedImage: "表示中の画像",
downloadOriginalImage: "オリジナル画像",
originalImageSource: "オリジナル画像",
originalImageUnavailable: "オリジナル画像は利用できません",
startReading: "読む",
continueReading: "続きから読む",
endPage: "終了",
end: "ギャラリーの最後です。タップして終了します。",
reloadPage: "ページを再読み込み"
},
help: {
title: "ヘルプ",
sections: [
{
title: "リーダー",
items: [
"中央を**タップ**すると、ツールバーの表示と非表示を切り替えられます。",
"閲覧方向に**スワイプまたはスクロール**します。左右をタップするか、**矢印キー**でもページをめくれます。",
"**ページモード**では、下へ引くか閲覧方向と交差する向きにスワイプすると、スクロールプレビューを開けます。",
"**ピンチ**で拡大縮小できます。マウスでは画像を**長押し**するか、**Ctrl/⌘ + ホイール**を使用します。拡大中に長押し、ダブルクリック、またはダブルタップすると終了します。"
]
}
]
},
gallery: {
scrollPreview: "スクロールプレビュー",
confirmScrollPreviewDirection: "スクロールプレビューの方向を変更しますか?",
openScrollPreview: "全画面スクロールプレビューを開く",
scrollPreviewDirectionTtb: "スクロールプレビュー:上から下",
scrollPreviewDirectionLtr: "スクロールプレビュー:左から右",
scrollPreviewDirectionRtl: "スクロールプレビュー:右から左"
},
errors: {
imageNotFound: "画像が見つかりません",
loadFailed: "読み込みに失敗しました",
imageLoadFailed: "画像の読み込みに失敗しました",
downloadFailed: "ダウンロードに失敗しました"
}
}, zh_CN_default = {
common: {
actions: {
apply: "应用",
close: "关闭",
confirm: "确认",
current: "当前位置",
default: "默认",
submit: "提交",
zoomIn: "放大",
zoomOut: "缩小"
},
status: {
failed: "失败",
loading: "加载中..."
}
},
reader: {
readingOptions: "阅读选项",
fullscreen: "全屏",
exitFullscreen: "退出全屏",
adjustScrollViewport: "调整滚动视口大小",
resizeScrollViewport: "调整滚动视口",
fit: "适应",
fill: "铺满",
applyGlobally: "设为默认",
pagedMode: "分页模式",
singlePageMode: "单页布局",
doublePageMode: "双页布局",
pairFirstAndSecondPages: "组合第 1+2 页",
pairSecondAndThirdPages: "组合第 2+3 页",
scrollMode: "滚动模式",
rightTapPrevious: `右侧操作:
上一页`,
rightTapNext: `右侧操作:
下一页`,
directionRtl: `阅读方向:
从右向左`,
directionLtr: `阅读方向:
从左向右`,
directionTtb: `阅读方向:
从上向下`,
download: "下载",
downloadHelpLabel: "无法下载?",
openImage: "打开图像",
displayedImageShort: "当前显示",
originalImageShort: "原图",
downloadDisplayedImage: "当前显示的图像",
downloadOriginalImage: "原始图像",
originalImageSource: "原始图片来源",
originalImageUnavailable: "原始图像不可用",
startReading: "阅读",
continueReading: "继续",
endPage: "结束",
end: "已到画廊末尾。点击退出。",
reloadPage: "重新加载页面"
},
help: {
title: "帮助",
sections: [
{
title: "阅读器",
items: [
"**点击**中央区域可显示或隐藏工具栏。",
"沿阅读方向**滑动或滚动**;点击两侧或使用**方向键**翻页。",
"在**分页模式**下,下拉或沿阅读方向的垂直方向滑动可打开滚动预览。",
"通过**双指捏合**缩放。使用鼠标时,可**长按**图像或使用 **Ctrl/⌘ + 滚轮**缩放;缩放后,长按、双击鼠标或双击屏幕可退出缩放。"
]
}
]
},
gallery: {
scrollPreview: "滚动预览",
confirmScrollPreviewDirection: "更改滚动预览方向?",
openScrollPreview: "打开全屏滚动预览",
scrollPreviewDirectionTtb: "滚动预览:从上向下",
scrollPreviewDirectionLtr: "滚动预览:从左向右",
scrollPreviewDirectionRtl: "滚动预览:从右向左"
},
errors: {
imageNotFound: "未找到图像",
loadFailed: "加载失败",
imageLoadFailed: "图像加载失败",
downloadFailed: "下载失败"
}
}, readerLocales = {
en: en_default2,
ja: ja_default,
"zh-CN": zh_CN_default
}, ReaderTextsContext = createContext(en_default2);
}
});
// ../reader/dist/chunk-PKBMQBKP.js
var __defProp, __defNormalProp, __publicField, init_chunk_PKBMQBKP = __esm({
"../reader/dist/chunk-PKBMQBKP.js"() {
"use strict";
__defProp = Object.defineProperty, __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value, __publicField = (obj, key, value) => __defNormalProp(obj, typeof key != "symbol" ? key + "" : key, value);
}
});
// ../reader/dist/kit/i18n.js
var init_i18n = __esm({
"../reader/dist/kit/i18n.js"() {
"use strict";
init_chunk_JXES5MWD();
init_chunk_PKBMQBKP();
}
});
// src/locales/ja.json
var ja_default2, init_ja = __esm({
"src/locales/ja.json"() {
ja_default2 = {
metadata: {
description: "タッチ操作向けの多機能 E-H/ExH ビューア。 デスクトップ、Android、iOS に対応。 内蔵リーダー、ズーム対応のギャラリープレビュー、モバイル向け UI、ジェスチャー操作、閲覧履歴など。"
},
help: {
sections: [
{
title: "ブラウズ",
items: [
"**レイアウトメニュー**から EhPeek または EhPeekLite を選択すると、元の検索結果レイアウトを置き換えます。",
"**拡張 > 検索スワイプ**を有効にすると、**横方向にスワイプ**して検索結果ページを切り替えられます。"
]
},
{
title: "ギャラリー",
items: [
"**拡張 > プレビュースワイプ**を有効にすると、**横方向にスワイプ**してプレビューページを切り替えられます。",
"ギャラリーのページバーを**ドラッグ**して範囲を調整できます。"
]
}
]
},
reader: {
downloadHelp: "ユーザースクリプトマネージャーでブラウザーのダウンロード API を有効にできます。たとえば Violentmonkey では「ブラウザーのダウンロード API を使用」を有効にしてください。",
originalImageSource: "E-Hentai が提供するオリジナル画像"
},
history: {
actions: {
clear: "すべて消去",
export: "エクスポート",
import: "インポート",
remove: "削除"
},
clearConfirm: "閲覧履歴をすべて消去しますか?",
empty: "閲覧履歴はありません",
exported: "履歴をエクスポートしました",
importFailed: "履歴のインポートに失敗しました",
imported: "{count} 件の履歴をインポートしました",
limit: "(最大 {limit} 件)",
visitedLabel: "閲覧済み",
range: "全 {total} 件中 {start}–{end} 件",
removeConfirm: "このギャラリーを閲覧履歴から削除しますか?"
},
gallery: {
pages: "ページ",
notFavorited: "お気に入り未登録",
rate: "ギャラリーを評価",
rateWithStars: "ギャラリーを評価:{rating} 星",
tagging: "タグ操作",
resizeColumns: "ギャラリーの列幅を調整します",
resetColumns: "ギャラリーの列幅をデフォルトに戻します",
favoriteTag: "マイタグを追加",
copyOriginalTag: "元のタグをコピー",
editFavoriteNote: "メモを編集",
discardFavoriteNote: "メモの変更を破棄しますか?",
favoriteRequiresLogin: "未ログイン",
removeFavoriteTag: "マイタグを削除",
tagCollection: "コレクション",
tagBehavior: "動作",
markTag: "マーク",
watchTag: "ウォッチ",
hideTag: "非表示"
},
settings: {
openSettings: "設定",
on: "オン",
off: "オフ",
discardChanges: "未適用の設定変更を破棄しますか?",
general: "一般",
options: "オプション",
about: "情報",
licenses: "ライセンス",
readerLabel: "リーダー",
readerHelp: "ギャラリー画像を EhPeek のリーダーで開きます",
readerFullscreenLabel: "リーダーをフルスクリーンで開く",
readerFullscreenHelp: "リーダーを開いたときにフルスクリーンにします",
twoColumnsReaderModeLabel: "2 列リーダーモード",
readerModeFullView: "全体表示",
readerModeOnPreview: "プレビュー上",
readerModeReaderPreview: "リーダー + プレビュー",
exitReaderOnFullscreenExitLabel: "フルスクリーン終了時にリーダーを閉じる",
exitReaderOnFullscreenExitHelp: "フルスクリーンを終了するとリーダーを閉じます",
includeReaderPageInUrlLabel: "リーダーページを URL に含める",
includeReaderPageInUrlHelp: "現在のリーダーページで URL を更新します。ブラウザーの履歴を汚す可能性があります",
more: "その他",
replacePreviewWithScrollLabel: "スクロールプレビューを埋め込む",
replacePreviewWithScrollHelp: "元のギャラリープレビュー領域をスクロールプレビューに置き換えます",
openGalleryInNewTabLabel: "ギャラリーを新しいタブで開く",
openGalleryInNewTabHelp: "ギャラリーリンクをブラウザーの新しいタブで開きます",
uiControlsLabel: "UI レイアウト",
uiScaleLabel: "UI スケール",
portraitUiScaleLabel: "縦向き UI スケール",
landscapeUiScaleLabel: "横向き UI スケール",
leftHandedControlsLabel: "左手用コントロール",
columnsLabel: "2 列",
showColumnsResizeHandle: "列幅調整ハンドルを表示",
hideColumnsResizeHandle: "列幅調整ハンドルを非表示",
enhance: "拡張",
enhanceSearchLabel: "検索スワイプ",
enhanceSearchHelp: "スワイプして検索結果ページを切り替えます",
enhanceThumbsLabel: "プレビュースワイプ",
enhanceThumbsHelp: "スワイプしてプレビューページを切り替え、ページバーをドラッグ可能にします",
myTagsLabel: "マイタグの色",
myTagsHelp: "ギャラリー内のマイタグに色を付けます",
historyLabel: "履歴",
readHistoryLabel: "閲覧履歴",
readHistoryHelp: "ギャラリーを閲覧履歴に追加し、閲覧進捗を保存します",
includeUnreadHistoryLabel: "未読の履歴を含める",
includeUnreadHistoryHelp: "開いたものの未読のギャラリーを閲覧履歴に記録します",
searchHistoryLabel: "検索履歴",
searchHistoryHelp: "検索キーワードの履歴を保存します",
touchUiLabel: "タッチ UI",
touchUiHelp: "タッチ操作に適したナビゲーション UI を使用します",
fitToViewportLabel: "ページを画面幅に合わせる",
fitToViewportHelp: "ページをブラウザーの幅に合わせます"
},
search: {
advancedOptions: "詳細オプション",
categories: "カテゴリ",
fileSearch: "ファイル検索"
},
errors: {
searchPageContentNotFound: "検索ページの内容が見つかりません"
}
};
}
});
// src/locales/zh-CN.json
var zh_CN_default2, init_zh_CN = __esm({
"src/locales/zh-CN.json"() {
zh_CN_default2 = {
metadata: {
description: "针对触屏优化的 E-H/ExH 阅读器。 适配桌面端、安卓、iOS。 功能: 内置阅读器、可缩放画廊预览、移动端 UI 适配、手势导航、阅读历史等。"
},
help: {
sections: [
{
title: "浏览",
items: [
"在**布局菜单**中选择 EhPeek 或 EhPeekLite,以替换原始结果布局。",
"启用**增强 > 搜索滑动**后,可**水平滑动**切换搜索结果页。"
]
},
{
title: "画廊",
items: [
"启用**增强 > 预览滑动**后,可**水平滑动**切换预览页。",
"可以**拖动画廊中的页码条**来调整范围。"
]
}
]
},
reader: {
downloadHelp: "你可以在用户脚本管理器中启用浏览器下载 API。例如,在 Violentmonkey 中启用“使用浏览器下载 API”。",
originalImageSource: "由 E-Hentai 提供的原图来源"
},
history: {
actions: {
clear: "全部清除",
export: "导出",
import: "导入",
remove: "删除"
},
clearConfirm: "清除全部阅读历史?",
empty: "没有阅读历史",
exported: "历史记录已导出",
importFailed: "历史记录导入失败",
imported: "已导入 {count} 条历史记录",
limit: "(最多 {limit} 条)",
visitedLabel: "已访问",
range: "第 {start}–{end} 条,共 {total} 条历史记录",
removeConfirm: "从阅读历史中删除此画廊?"
},
gallery: {
pages: "页",
notFavorited: "未收藏",
rate: "为画廊评分",
rateWithStars: "为画廊评分:{rating} 星",
tagging: "标签操作",
resizeColumns: "调整画廊双栏比例",
resetColumns: "恢复画廊双栏默认比例",
favoriteTag: "添加我的标签",
copyOriginalTag: "复制原始标签",
editFavoriteNote: "编辑备注",
discardFavoriteNote: "放弃备注修改?",
favoriteRequiresLogin: "未登录",
removeFavoriteTag: "移除我的标签",
tagCollection: "标签集",
tagBehavior: "行为",
markTag: "标记",
watchTag: "关注",
hideTag: "隐藏"
},
settings: {
openSettings: "设置",
on: "开",
off: "关",
discardChanges: "放弃尚未应用的设置修改?",
general: "常规",
options: "选项",
about: "关于",
licenses: "许可证",
readerLabel: "阅读器",
readerHelp: "使用 EhPeek 阅读器打开画廊图像",
readerFullscreenLabel: "以全屏方式打开阅读器",
readerFullscreenHelp: "打开阅读器时进入全屏",
twoColumnsReaderModeLabel: "双栏阅读器模式",
readerModeFullView: "完整视图",
readerModeOnPreview: "覆盖预览",
readerModeReaderPreview: "阅读器 + 预览",
exitReaderOnFullscreenExitLabel: "退出全屏时关闭阅读器",
exitReaderOnFullscreenExitHelp: "退出全屏后关闭阅读器",
includeReaderPageInUrlLabel: "在 URL 中包含阅读器页码",
includeReaderPageInUrlHelp: "在 URL 中更新当前阅读器页码,可能会污染浏览器历史记录",
more: "更多",
replacePreviewWithScrollLabel: "嵌入滚动预览",
replacePreviewWithScrollHelp: "使用滚动预览替换原始画廊预览区域",
openGalleryInNewTabLabel: "在新标签页中打开画廊",
openGalleryInNewTabHelp: "在新的浏览器标签页中打开画廊链接",
uiControlsLabel: "界面布局",
uiScaleLabel: "界面缩放",
portraitUiScaleLabel: "竖屏界面缩放",
landscapeUiScaleLabel: "横屏界面缩放",
leftHandedControlsLabel: "左手控制",
columnsLabel: "双栏",
showColumnsResizeHandle: "显示双栏调整柄",
hideColumnsResizeHandle: "隐藏双栏调整柄",
enhance: "增强",
enhanceSearchLabel: "搜索滑动",
enhanceSearchHelp: "通过滑动切换搜索结果页",
enhanceThumbsLabel: "预览滑动",
enhanceThumbsHelp: "通过滑动切换预览页,并使页码条可拖动",
myTagsLabel: "我的标签颜色",
myTagsHelp: "在画廊中为我的标签着色",
historyLabel: "历史记录",
readHistoryLabel: "阅读历史",
readHistoryHelp: "将画廊加入阅读历史并记住阅读进度",
includeUnreadHistoryLabel: "包括未读记录",
includeUnreadHistoryHelp: "将打开但尚未阅读的画廊记录到阅读历史",
searchHistoryLabel: "搜索历史",
searchHistoryHelp: "保存搜索关键词历史",
touchUiLabel: "触控界面",
touchUiHelp: "使用适合触控操作的导航界面",
fitToViewportLabel: "页面贴合屏幕",
fitToViewportHelp: "使页面贴合浏览器宽度"
},
search: {
advancedOptions: "高级选项",
categories: "分类",
fileSearch: "文件搜索"
},
errors: {
searchPageContentNotFound: "无法找到搜索页面内容"
}
};
}
});
// src/i18n.ts
function combineTexts(reader, client) {
return {
...reader,
...client,
reader: { ...reader.reader, ...client.reader },
gallery: { ...reader.gallery, ...client.gallery },
errors: { ...reader.errors, ...client.errors },
help: { ...reader.help, sections: [...reader.help.sections, ...client.help.sections] }
};
}
function setAppLocale(locale) {
appLocale = locale, activeTexts = localeTexts[locale];
}
var APP_LOCALES, APP_LOCALE_OPTIONS, APP_LOCALE_SETTING_KEY, DEFAULT_APP_LOCALE, localeTexts, appLocale, activeTexts, init_i18n2 = __esm({
"src/i18n.ts"() {
"use strict";
init_en();
init_i18n();
init_ja();
init_zh_CN();
APP_LOCALES = ["en", "zh-CN", "ja"], APP_LOCALE_OPTIONS = [
{ label: "English", value: "en" },
{ label: "简体中文", value: "zh-CN" },
{ label: "日本語", value: "ja" }
], APP_LOCALE_SETTING_KEY = "ehpeek:language", DEFAULT_APP_LOCALE = "en";
localeTexts = {
en: combineTexts(readerLocales.en, en_default),
"zh-CN": combineTexts(readerLocales["zh-CN"], zh_CN_default2),
ja: combineTexts(readerLocales.ja, ja_default2)
}, appLocale = DEFAULT_APP_LOCALE, activeTexts = localeTexts[appLocale];
}
});
// src/state/storage.ts
async function loadPersistedState() {
await Promise.all(Array.from(persistedStateValues, (item) => item.reload()));
}
function persisted(key, defaultValue, codec = { parse: (value) => value }) {
let item = {
defaultValue,
value: defaultValue,
async clear() {
item.value = defaultValue, await GM.deleteValue(key);
},
preload() {
return persistedStateValues.add(item), item;
},
set(value) {
item.setAsync(value).catch((error) => {
console.error(`[ehpeek] Failed to persist ${key}`, error);
});
},
async setAsync(value) {
item.value = value, await GM.setValue(key, value);
},
async reload() {
let stored = await GM.getValue(key, defaultValue), parsed = codec.parse(stored);
return item.value = parsed ?? defaultValue, parsed === void 0 && await GM.setValue(key, defaultValue), item.value;
}
};
return item;
}
function local(key, defaultValue, codec) {
let read = () => {
let stored = window.localStorage.getItem(key);
return stored === null ? defaultValue : codec.parse(stored) ?? defaultValue;
}, item = {
defaultValue,
value: read(),
set(value) {
item.value = value;
let stored = codec.serialize(value);
stored === null ? window.localStorage.removeItem(key) : window.localStorage.setItem(key, stored);
},
reload() {
return item.value = read(), item.value;
},
clear() {
item.value = defaultValue, window.localStorage.removeItem(key);
},
stored() {
return window.localStorage.getItem(key) !== null;
}
};
return item;
}
function enumCodec(values) {
return {
parse: (value) => values.includes(value) ? value : void 0,
serialize: (value) => value
};
}
function numberRangeCodec(min, max) {
return {
parse: (value) => typeof value == "number" && Number.isFinite(value) && value >= min && value <= max ? value : void 0
};
}
function nullableStateCodec(codec) {
return {
parse: (value) => value === null ? null : codec.parse(value)
};
}
function nullableCodec(codec) {
return {
parse: codec.parse,
serialize: (value) => value === null ? null : codec.serialize(value)
};
}
function arrayCodec(valid) {
return {
parse: (value) => Array.isArray(value) ? value.filter(valid) : void 0
};
}
function jsonCodec(codec) {
return {
parse(value) {
if (typeof value == "string")
try {
return codec.parse(JSON.parse(value));
} catch {
return;
}
},
serialize: (value) => JSON.stringify(value) ?? null
};
}
var persistedStateValues, init_storage = __esm({
"src/state/storage.ts"() {
"use strict";
persistedStateValues = /* @__PURE__ */ new Set();
}
});
// ../reader/dist/chunk-A6WI3YS4.js
function markUiRoot(root) {
root.classList.add("ehpeek-ui-root");
}
function applyUiScale(scale, root, pixelFactor = 1) {
for (let [property, value] of uiScaleDeclarations(
UI_SCALE_FACTORS[scale] * pixelFactor
))
root.style.setProperty(property, value);
}
function uiScaleFactor(scale) {
return UI_SCALE_FACTORS[scale];
}
function uiScaleDeclarations(factor) {
return [
...sizeScaleDeclarations(
"--ui-control-size",
reader_ui_sizes_default.control,
factor
),
...hitSizeScaleDeclarations(reader_ui_sizes_default.control, factor),
...sizeScaleDeclarations("--ui-font-size", reader_ui_sizes_default.font, factor),
...sizeScaleDeclarations("--ui-icon-size", reader_ui_sizes_default.icon, factor),
...sizeScaleDeclarations("--ui-space", reader_ui_sizes_default.space, factor),
...sizeScaleDeclarations("--ui-radius", reader_ui_sizes_default.radius, factor)
];
}
function sizeScaleDeclarations(prefix, values, factor) {
return Object.entries(values).map(
([name, value]) => [`${prefix}-${name}`, `${scaledPixelValue(value, factor)}px`]
);
}
function hitSizeScaleDeclarations(values, factor) {
return Object.entries(values).map(
([name, value]) => [
`--ui-hit-size-${name}`,
`${Math.max(32, scaledPixelValue(value, factor))}px`
]
);
}
function scaledPixelValue(value, factor) {
return Math.round(pixelValue(value) * factor * 1e3) / 1e3;
}
function pixelValue(value) {
let pixels = /^([\d.]+)px$/.exec(value)?.[1];
if (pixels === void 0)
throw new Error(`Expected a pixel UI size, received: ${value}`);
return Number(pixels);
}
var reader_ui_sizes_default, UI_SCALE_FACTORS, UI_SCALE_NAMES, init_chunk_A6WI3YS4 = __esm({
"../reader/dist/chunk-A6WI3YS4.js"() {
"use strict";
reader_ui_sizes_default = { control: { xs: "24px", sm: "32px", md: "40px", lg: "48px", xl: "56px" }, font: { xs: "10px", sm: "14px", md: "16px", lg: "20px", xl: "28px" }, icon: { xs: "14px", sm: "16px", md: "20px", lg: "22px", xl: "26px" }, space: { xs: "4px", sm: "8px", md: "12px", lg: "16px", xl: "24px" }, radius: { xs: "3px", sm: "4px", md: "6px", lg: "8px", xl: "10px" } }, UI_SCALE_FACTORS = {
xsmall: 0.8,
small: 1,
medium: 1.25,
large: 1.5,
xlarge: 1.8
}, UI_SCALE_NAMES = Object.freeze(
Object.keys(UI_SCALE_FACTORS)
);
}
});
// ../reader/dist/kit/ui.js
var init_ui = __esm({
"../reader/dist/kit/ui.js"() {
"use strict";
init_chunk_A6WI3YS4();
init_chunk_PKBMQBKP();
}
});
// src/ui.ts
function configureUi(options) {
uiState = { ...options }, applyUiStateClasses();
}
function markUiRoot2(root) {
root.parentElement?.closest(`.${UI_ROOT_CLASS}`) || root.classList.add(UI_ROOT_CLASS);
}
function setUiPointer(pointer) {
let state2 = requireUiState();
state2.pointer = pointer, applyUiStateClasses();
}
function nextUiScale(scale) {
let index = UI_SCALE_NAMES.indexOf(scale);
return UI_SCALE_NAMES[(index + 1) % UI_SCALE_NAMES.length];
}
function uiScaleLevel(scale) {
return UI_SCALE_NAMES.indexOf(scale) + 1;
}
function applyUiScale2(scale, root, pixelFactor = 1) {
let factor = uiScaleFactor(scale) * pixelFactor;
if (!root) {
applyGlobalUiScale(factor);
return;
}
applyUiScale(scale, root, pixelFactor);
}
function applyGlobalUiScale(factor) {
let style2 = uiStateStyle(), declarations = uiScaleDeclarations(factor).map(([property, value]) => `${property}:${value}`).join(";");
style2.textContent = `${UI_SCALE_SELECTOR}{${declarations}}`;
}
function applyUiStateClasses() {
let state2 = requireUiState(), style2 = uiStateStyle();
style2.classList.toggle("ehpeek-pointer-mouse", state2.pointer === "mouse"), style2.classList.toggle("ehpeek-site-e-hentai", state2.site === "e-hentai"), style2.classList.toggle("ehpeek-site-exhentai", state2.site === "exhentai");
}
function uiStateStyle() {
let style2 = document.getElementById(UI_STATE_STYLE_ID);
return style2 || (style2 = document.createElement("style"), style2.id = UI_STATE_STYLE_ID, (document.head ?? document.documentElement).append(style2)), style2;
}
function requireUiState() {
if (!uiState)
throw new Error("UI must be configured before it is initialized.");
return uiState;
}
function reportUiError(error) {
let message = error instanceof Error ? error.message : activeTexts.errors.loadFailed;
console.error("[ehpeek]", error), window.alert(message);
}
var UI_ROOT_CLASS, UI_STATE_STYLE_ID, UI_SCALE_SELECTOR, uiState, init_ui2 = __esm({
"src/ui.ts"() {
"use strict";
init_i18n2();
init_ui();
init_ui();
UI_ROOT_CLASS = "ehpeek-ui-root", UI_STATE_STYLE_ID = "ehpeek-ui-state", UI_SCALE_SELECTOR = ".ehpeek-ui-root, body.ehpeek-touch-gallery-page, .ehpeek-external-autocomplete";
}
});
// src/state/index.ts
async function clearBackToTopPositions() {
await Promise.all([
state.widgets.backToTopPosition.clear(),
state.widgets.galleryColumnsBackToTopPosition.clear()
]);
}
async function loadSearchHistory() {
return state.search.searchHistory.reload();
}
async function addSearchHistory(value) {
let normalized = value.trim();
if (!normalized)
return loadSearchHistory();
let history = [
normalized,
...(await loadSearchHistory()).filter((item) => item !== normalized)
];
return await state.search.searchHistory.setAsync(history), history;
}
async function removeSearchHistory(value) {
let history = (await loadSearchHistory()).filter((item) => item !== value);
return await state.search.searchHistory.setAsync(history), history;
}
function readerControls(orientation) {
return {
navigationMode: persisted(
`ehpeek:reader:navigation-mode:${orientation}`,
"paged"
).preload(),
scrollDirection: persisted(
`ehpeek:reader:scroll-direction:${orientation}`,
"ttb"
).preload(),
pagedDirection: persisted(
`ehpeek:reader:paged-direction:${orientation}`,
"rtl"
).preload(),
pageLayout: persisted(
`ehpeek:reader:page-layout:${orientation}`,
"single"
).preload(),
rightTapAction: persisted(
`ehpeek:reader:right-tap-action:${orientation}`,
"previous"
).preload()
};
}
function isMyTagAppearance(value) {
if (!value || typeof value != "object" || Array.isArray(value))
return !1;
let item = value;
return typeof item.name == "string" && typeof item.backgroundColor == "string" && typeof item.color == "string" && typeof item.id == "string" && typeof item.tagSet == "string";
}
function isMyTagSetOption(value) {
if (!value || typeof value != "object" || Array.isArray(value))
return !1;
let item = value;
return typeof item.label == "string" && typeof item.selected == "boolean" && typeof item.value == "string";
}
var GALLERY_COLUMNS_RATIO_DEFAULT, GALLERY_COLUMNS_RATIO_MAX, GALLERY_COLUMNS_RATIO_MIN, touchUiDefault, portraitUiScaleDefault, landscapeUiScaleDefault, state, init_state = __esm({
"src/state/index.ts"() {
"use strict";
init_storage();
init_ui2();
init_i18n2();
init_storage();
GALLERY_COLUMNS_RATIO_DEFAULT = 0.5, GALLERY_COLUMNS_RATIO_MAX = 0.95, GALLERY_COLUMNS_RATIO_MIN = 0.05, touchUiDefault = window.matchMedia("(pointer: coarse)").matches, portraitUiScaleDefault = touchUiDefault ? "large" : "small", landscapeUiScaleDefault = touchUiDefault && Math.min(window.screen.width, window.screen.height) >= 600 ? "medium" : portraitUiScaleDefault, state = {
app: {
locale: persisted(
APP_LOCALE_SETTING_KEY,
DEFAULT_APP_LOCALE,
enumCodec(APP_LOCALES)
).preload(),
leftHandedControls: persisted("ehpeek:left-handed-controls", !1).preload(),
openGalleryInNewTab: persisted("ehpeek:open-gallery-in-new-tab", !1).preload(),
portraitUiScale: persisted(
"ehpeek:ui-scale:portrait",
portraitUiScaleDefault,
enumCodec(UI_SCALE_NAMES)
).preload(),
landscapeUiScale: persisted(
"ehpeek:ui-scale:landscape",
landscapeUiScaleDefault,
enumCodec(UI_SCALE_NAMES)
).preload()
},
reader: {
twoColumnsMode: persisted(
"ehpeek:reader:two-columns-mode",
"full-view",
enumCodec([
"full-view",
"on-preview",
"reader-preview"
])
).preload(),
enabled: persisted("ehpeek:reader:enabled", !0).preload(),
exitOnFullscreenExit: persisted(
"ehpeek:reader:exit-on-fullscreen-exit",
!1
).preload(),
fullscreen: persisted("ehpeek:reader:fullscreen", !1).preload(),
includePageInUrl: persisted(
"ehpeek:reader:include-page-in-url",
!1
).preload(),
portraitControls: readerControls("portrait"),
landscapeControls: readerControls("landscape"),
scrollTtbScale: persisted(
"ehpeek:reader:scroll-ttb-scale",
"fill"
).preload(),
scrollHorizontalScale: persisted(
"ehpeek:reader:scroll-horizontal-scale",
"fill"
).preload()
},
gallery: {
enhanceThumbs: persisted("ehpeek:enhance-thumbs:enabled", !0).preload(),
replacePreviewWithScroll: persisted(
"ehpeek:scroll-preview:replace-original",
!1
).preload(),
embeddedScrollPreviewSingleDirection: persisted(
"ehpeek:gallery-scroll-preview:single-direction",
"rtl"
).preload(),
embeddedScrollPreviewColumnsDirection: persisted(
"ehpeek:gallery-scroll-preview:columns-direction",
"ttb"
).preload(),
scrollPreviewDirection: persisted(
"ehpeek:scroll-preview:direction",
"ttb"
).preload(),
myTags: persisted("ehpeek:my-tags:enabled", !0).preload(),
myTagAppearances: local(
"ehpeek:my-tags",
[],
jsonCodec(arrayCodec(isMyTagAppearance))
),
myTagSets: local(
"ehpeek:my-tag-sets",
[],
jsonCodec(arrayCodec(isMyTagSetOption))
),
readHistory: persisted("ehpeek:read-history:enabled", !0).preload(),
includeUnreadHistory: persisted(
"ehpeek:read-history:include-unread",
!0
).preload(),
readHistoryCompactEstimate: persisted("ehpeek:history-count", 0).preload(),
titlePreference: local(
"ehpeek:gallery-title-preference",
"main",
enumCodec(["main", "sub"])
)
},
search: {
enhance: persisted("ehpeek:enhance-search:enabled", !0).preload(),
grid: local(
"ehpeek:search-grid",
null,
nullableCodec(enumCodec(["ehpeek", "ehpeek-lite"]))
),
history: persisted("ehpeek:search-history:enabled", !0).preload(),
searchHistory: persisted(
"ehpeek:search:history",
[],
arrayCodec((value) => typeof value == "string")
).preload()
},
touch: {
enabled: persisted("ehpeek:touch-ui:enabled", touchUiDefault).preload(),
fitToViewport: persisted("ehpeek:touch-ui:fit-to-viewport", !0).preload(),
portraitColumns: persisted("ehpeek:touch-ui:portrait-columns", !1).preload(),
landscapeColumns: persisted("ehpeek:touch-ui:landscape-columns", !0).preload(),
portraitGalleryColumnsRatio: persisted(
"ehpeek:touch-ui:portrait-gallery-columns-ratio",
GALLERY_COLUMNS_RATIO_DEFAULT,
numberRangeCodec(GALLERY_COLUMNS_RATIO_MIN, GALLERY_COLUMNS_RATIO_MAX)
).preload(),
landscapeGalleryColumnsRatio: persisted(
"ehpeek:touch-ui:landscape-gallery-columns-ratio",
GALLERY_COLUMNS_RATIO_DEFAULT,
numberRangeCodec(GALLERY_COLUMNS_RATIO_MIN, GALLERY_COLUMNS_RATIO_MAX)
).preload(),
portraitReaderPreviewColumnsRatio: persisted(
"ehpeek:touch-ui:portrait-reader-preview-columns-ratio",
null,
nullableStateCodec(
numberRangeCodec(GALLERY_COLUMNS_RATIO_MIN, GALLERY_COLUMNS_RATIO_MAX)
)
).preload(),
landscapeReaderPreviewColumnsRatio: persisted(
"ehpeek:touch-ui:landscape-reader-preview-columns-ratio",
null,
nullableStateCodec(
numberRangeCodec(GALLERY_COLUMNS_RATIO_MIN, GALLERY_COLUMNS_RATIO_MAX)
)
).preload()
},
widgets: {
backToTopPosition: persisted(
"ehpeek:back-to-top:position",
null
).preload(),
galleryColumnsBackToTopPosition: persisted(
"ehpeek:gallery-columns-back-to-top:position",
null
).preload()
}
};
}
});
// src/eh/url.ts
function ehSiteTheme(url = window.location.href) {
let hostname = new URL(url, window.location.href).hostname;
return hostname === EXHENTAI_HOST || hostname.endsWith(`.${EXHENTAI_HOST}`) || hostname === EXHENTAI_ONION_HOST || hostname.endsWith(`.${EXHENTAI_ONION_HOST}`) ? "exhentai" : "e-hentai";
}
function galleryIdentityFromUrl(url = window.location.href) {
try {
let match = new URL(url, window.location.href).pathname.match(/^\/g\/(\d+)\/([^/]+)/i), galleryId = Number(match?.[1]), token = match?.[2];
return token && Number.isSafeInteger(galleryId) && galleryId > 0 ? { galleryId, token } : null;
} catch {
return null;
}
}
function urlPath(url) {
try {
return new URL(url, window.location.href).pathname.toLowerCase();
} catch {
return "";
}
}
function galleryTagNameFromUrl(url) {
let encodedName = urlPath(url).match(/^\/tag\/(.+?)\/?$/i)?.[1];
try {
return encodedName ? decodeURIComponent(encodedName.replace(/\+/g, " ")) : null;
} catch {
return null;
}
}
function isFullImageUrl(url) {
return urlPath(url).includes("/fullimg");
}
function extractPageType(url = window.location.href) {
try {
let parsed = new URL(url, window.location.href), hash = new URLSearchParams(parsed.hash.replace(/^#/, ""));
if (parsed.pathname === "/popular" && hash.has("ehpeek_history")) {
let requestedPage = Number(hash.get("page") ?? "0");
return {
type: "readHistory",
url: parsed.href,
pageIndex: Number.isSafeInteger(requestedPage) && requestedPage >= 0 ? requestedPage : 0
};
}
let galleryMatch = parsed.pathname.match(/^\/g\/(\d+)\/([^/]+)\/?$/i);
if (galleryMatch) {
let galleryId = Number(galleryMatch[1]), token = galleryMatch[2];
if (token && Number.isFinite(galleryId) && galleryId > 0)
return {
type: "gallery",
url: parsed.href,
galleryId,
token,
previewIndex: previewPageIndex(parsed.href),
peekPage: peekPageFromHash(parsed.hash)
};
}
let imageMatch = parsed.pathname.match(/^\/s\/[^/]+\/(\d+)-(\d+)\/?$/i);
if (imageMatch) {
let galleryId = Number(imageMatch[1]), pageNum = Number(imageMatch[2]);
if (Number.isFinite(galleryId) && galleryId > 0 && Number.isFinite(pageNum) && pageNum > 0)
return {
type: "image",
url: parsed.href,
galleryId,
pageNum
};
}
return parsed.pathname === "/favorites.php" ? {
type: "favorites",
url: parsed.href
} : /^\/mytags\/?$/.test(parsed.pathname) ? {
type: "myTags",
url: parsed.href
} : parsed.pathname === "/uconfig.php" ? {
type: "settings",
url: parsed.href
} : parsed.pathname === "/" || SEARCH_CATEGORY_PATH.test(parsed.pathname) || parsed.pathname.startsWith("/tag/") || parsed.pathname.startsWith("/uploader/") || /^\/(?:popular|watched)\/?$/.test(parsed.pathname) ? {
type: "search",
url: parsed.href
} : {
type: "other",
url: parsed.href
};
} catch {
return {
type: "other",
url
};
}
}
function readHistoryUrl(pageIndex = 0) {
let url = new URL("/popular", window.location.href);
return url.hash = pageIndex > 0 ? `ehpeek_history&page=${pageIndex}` : "ehpeek_history", url.href;
}
function peekPageUrl(pageNum, galleryUrl) {
let url = new URL(galleryUrl, window.location.href), params = new URLSearchParams(url.hash.replace(/^#/, ""));
return params.set("peek_page", String(pageNum)), url.hash = params.toString(), url.href;
}
function peekPageFromHash(hash = window.location.hash) {
let params = new URLSearchParams(hash.replace(/^#/, "")), pageNum = Number(params.get("peek_page") || "");
return Number.isSafeInteger(pageNum) && pageNum > 0 ? pageNum : null;
}
function galleryPageNumber(url) {
let page2 = extractPageType(url);
return page2.type === "image" ? page2.pageNum : void 0;
}
function previewPageIndex(url = window.location.href) {
try {
let value = Number(new URL(url).searchParams.get("p") || "0");
return Number.isFinite(value) && value >= 0 ? value : 0;
} catch {
return 0;
}
}
function previewUrlForIndex(previewIndex, pageUrl = window.location.href) {
let url = new URL(pageUrl);
return setPreviewIndex(url, previewIndex), url.hash = "", url.href;
}
function previewPageIndexForGalleryPage(galleryPage, pageSize, maxPreviewIndex) {
let previewIndex = Math.max(0, Math.floor((galleryPage - 1) / pageSize));
return Math.min(previewIndex, maxPreviewIndex);
}
function setPreviewIndex(url, previewIndex) {
previewIndex <= 0 ? url.searchParams.delete("p") : url.searchParams.set("p", String(previewIndex));
}
var EXHENTAI_HOST, EXHENTAI_ONION_HOST, SEARCH_CATEGORY_PATH, init_url = __esm({
"src/eh/url.ts"() {
"use strict";
EXHENTAI_HOST = "exhentai.org", EXHENTAI_ONION_HOST = "exhentai55ld2wyap5juskbm67czulomrouspdacjamjeloj7ugjbsad.onion", SEARCH_CATEGORY_PATH = /^\/(?:doujinshi|manga|artistcg|gamecg|western|non-h|imageset|cosplay|asianporn|misc)\/?$/i;
}
});
// src/eh/request.ts
async function requestPage(url, options = {}) {
let controller = new AbortController(), abort = () => controller.abort(), timeoutMs = options.timeoutMs === void 0 ? 3e4 : options.timeoutMs, timeout = timeoutMs === null ? null : window.setTimeout(abort, timeoutMs);
options.signal?.aborted ? controller.abort() : options.signal?.addEventListener("abort", abort, { once: !0 });
try {
let response = await fetch(url, {
method: options.method ?? "GET",
body: options.body,
credentials: "include",
headers: options.headers,
signal: controller.signal
});
if (!response.ok)
throw new Error(`HTTP ${response.status}`);
let html = await response.text();
return {
document: new DOMParser().parseFromString(html, "text/html"),
url: response.url || url
};
} finally {
timeout !== null && window.clearTimeout(timeout), options.signal?.removeEventListener("abort", abort);
}
}
async function updateGalleryFavorite(actionUrl, value, note) {
let body = new URLSearchParams();
body.set("favcat", value), body.set("favnote", note), body.set("apply", "Apply Changes"), body.set("update", "1"), await requestPage(actionUrl, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body
});
}
async function addMyTag(tagName, tagSet, mode) {
let body = new URLSearchParams();
body.set("usertag_action", "add"), body.set("tagname_new", tagName), body.set("tagcolor_new", ""), body.set("tagweight_new", "10"), mode === "watched" ? body.set("tagwatch_new", "on") : mode === "hidden" && body.set("taghide_new", "on");
let url = new URL("/mytags", window.location.origin);
return url.searchParams.set("tagset", tagSet), requestPage(url.href, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body
});
}
async function deleteMyTag(tagId, tagSet) {
let body = new URLSearchParams();
body.set("usertag_action", "mass"), body.set("usertag_target", "0"), body.append("modify_usertags[]", tagId);
let url = new URL("/mytags", window.location.origin);
return url.searchParams.set("tagset", tagSet), requestPage(url.href, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body
});
}
var init_request = __esm({
"src/eh/request.ts"() {
"use strict";
}
});
// src/eh/dom/external.ts
function initializeExternalAutocompleteUi() {
let observer = null, mark = () => {
for (let source of EXTERNAL_AUTOCOMPLETE_SOURCES)
document.querySelectorAll(source.root).forEach((root) => {
root.classList.add(AUTOCOMPLETE_ROOT_CLASS), root.querySelectorAll(source.items).forEach((item) => {
item.classList.add(AUTOCOMPLETE_ITEM_CLASS);
}), source.text && root.querySelectorAll(source.text).forEach((text) => {
text.classList.add(AUTOCOMPLETE_TEXT_CLASS);
});
});
}, stopObserving = () => {
observer?.disconnect(), observer = null;
}, startObserving = (event) => {
!(event.target instanceof Element) || !event.target.matches(AUTOCOMPLETE_INPUT_SELECTOR) || (stopObserving(), mark(), observer = new MutationObserver(mark), observer.observe(document.body, { childList: !0, subtree: !0 }));
}, stopWhenInputBlurs = (event) => {
event.target instanceof Element && event.target.matches(AUTOCOMPLETE_INPUT_SELECTOR) && stopObserving();
};
document.addEventListener("focusin", startObserving), document.addEventListener("focusout", stopWhenInputBlurs);
}
var AUTOCOMPLETE_INPUT_SELECTOR, AUTOCOMPLETE_ROOT_CLASS, AUTOCOMPLETE_ITEM_CLASS, AUTOCOMPLETE_TEXT_CLASS, externalDom, EXTERNAL_AUTOCOMPLETE_SOURCES, init_external = __esm({
"src/eh/dom/external.ts"() {
"use strict";
AUTOCOMPLETE_INPUT_SELECTOR = "#f_search, #newtagfield", AUTOCOMPLETE_ROOT_CLASS = "ehpeek-external-autocomplete", AUTOCOMPLETE_ITEM_CLASS = "ehpeek-external-autocomplete-item", AUTOCOMPLETE_TEXT_CLASS = "ehpeek-external-autocomplete-text", externalDom = {
retainedOriginalPageSelector: ".eh-syringe-ignore",
tagLabelAttribute: "ehs-tag"
}, EXTERNAL_AUTOCOMPLETE_SOURCES = [
{
items: ".auto-complete-item",
root: ".eh-syringe-lite-auto-complete-list",
text: ".auto-complete-text"
},
{
items: ".lolicon-autocomplete-item",
root: ".lolicon-autocomplete-dropdown",
text: null
}
];
}
});
// src/eh/dom/core.ts
function defineDomNode() {
return (selector, options = {}) => {
let childs = options.childs ?? emptyDomChilds;
return Object.assign({
apply: options.apply ?? emptyDomApply,
childs,
kind: "node",
selector
}, childs);
};
}
function cls(name, options = {}) {
return query(`.${name}`, options);
}
function id(name, options = {}) {
return query(`#${name}`, options);
}
function tag(name, options = {}) {
return defineDomNode()(name, options);
}
function domSelector(source) {
return typeof source == "string" ? source : source.selector;
}
function originalPageNode(node) {
return node.closest(externalDom.retainedOriginalPageSelector) === null;
}
function retainedOriginalPageNode(node) {
return node.closest(externalDom.retainedOriginalPageSelector) !== null;
}
function anyDomNode() {
return !0;
}
function createAnchor(name) {
let selector = `[${EHPEEK_ANCHOR_ATTRIBUTE}="${CSS.escape(name)}"]`;
if (document.querySelector(selector))
return null;
let anchor2 = document.createElement("div");
return anchor2.setAttribute(EHPEEK_ANCHOR_ATTRIBUTE, name), DomNode.from(anchor2).inplace();
}
function createManagedElement(tagName, apply = emptyDomApply) {
return ManagedDomNode.from(document.createElement(tagName), apply);
}
function documentBody() {
return managedBody ?? (managedBody = DomNode.from(document.body).inplace()), managedBody;
}
function bindDom(description, scopes) {
let children2 = [], invalidateChildren = () => {
for (let child of children2)
child.invalidate();
}, definition = isDomDefinition(description) ? description : null, nodeController = definition ? bindDomNode(definition, scopes, invalidateChildren) : null, bound = nodeController?.bound ?? {}, childScopes = definition ? () => nodeController?.bound.all() ?? [] : scopes, childs = definition?.childs ?? description;
for (let [name, child] of Object.entries(childs)) {
if (name in bound)
throw new Error(`Original DOM child name is reserved: ${name}`);
let childController = bindDom(child, childScopes);
children2.push(childController), Object.assign(bound, { [name]: childController.bound });
}
return {
bound,
invalidate: nodeController?.invalidate ?? invalidateChildren
};
}
function isDomDefinition(description) {
return "kind" in description && description.kind === "node";
}
function bindDomNode(description, scopes, invalidateChildren) {
let cached, queryNodes = () => scopes().flatMap((scope) => scope.all(description.selector)), resolve = () => (cached ?? (cached = queryNodes()), cached);
return {
bound: {
all: () => [...resolve()],
clone: () => resolve()[0]?.clone(description.apply) ?? null,
cloneAll: () => resolve().map((node) => node.clone(description.apply)),
inplace: () => resolve()[0]?.inplace(description.apply) ?? null,
inplaceAll: () => resolve().map((node) => node.inplace(description.apply)),
move: () => resolve()[0]?.move(description.apply) ?? null,
moveAll: () => resolve().map((node) => node.move(description.apply)),
one: () => resolve()[0] ?? null,
requery: () => (cached = queryNodes(), invalidateChildren(), [...cached])
},
invalidate: () => {
cached = void 0, invalidateChildren();
}
};
}
var HIDDEN_ORIGINAL_DOM_NODE_CLASS, EHPEEK_ANCHOR_ATTRIBUTE, mountedNodes, managedBody, emptyDomApply, emptyDomChilds, query, anchor, area, button, cell, control, form, image, input, option, row, script, select, table, textarea, _node, _DomNode, DomNode, _apply, _node2, _ManagedDomNode, ManagedDomNode, init_core = __esm({
"src/eh/dom/core.ts"() {
"use strict";
init_web();
init_ui2();
init_external();
HIDDEN_ORIGINAL_DOM_NODE_CLASS = "ehpeek-hide-original-node", EHPEEK_ANCHOR_ATTRIBUTE = "data-ehpeek-anchor", mountedNodes = /* @__PURE__ */ new WeakMap(), managedBody = null, emptyDomApply = {}, emptyDomChilds = {};
query = defineDomNode(), anchor = defineDomNode(), area = defineDomNode(), button = defineDomNode(), cell = defineDomNode(), control = defineDomNode(), form = defineDomNode(), image = defineDomNode(), input = defineDomNode(), option = defineDomNode(), row = defineDomNode(), script = defineDomNode(), select = defineDomNode(), table = defineDomNode(), textarea = defineDomNode();
_DomNode = class _DomNode {
constructor(node) {
__privateAdd(this, _node);
__privateSet(this, _node, node);
}
static from(node) {
return new _DomNode(node);
}
use(description) {
return bindDom(description, () => [this]).bound;
}
one(source, filter = originalPageNode) {
return Array.from(
__privateGet(this, _node).querySelectorAll(domSelector(source)),
_DomNode.from
).find(filter) ?? null;
}
all(source, filter = originalPageNode) {
return Array.from(__privateGet(this, _node).querySelectorAll(domSelector(source))).map(_DomNode.from).filter(filter);
}
parent() {
let parent = __privateGet(this, _node).parentElement;
return parent ? _DomNode.from(parent) : null;
}
children() {
return Array.from(__privateGet(this, _node).children, (child) => _DomNode.from(child));
}
closest(source) {
let element = __privateGet(this, _node).closest(domSelector(source));
return element ? _DomNode.from(element) : null;
}
matches(source) {
return __privateGet(this, _node).matches(domSelector(source));
}
previous() {
let previous = __privateGet(this, _node).previousElementSibling;
return previous instanceof HTMLElement ? _DomNode.from(previous) : null;
}
form() {
return __privateGet(this, _node).form ? _DomNode.from(__privateGet(this, _node).form) : null;
}
childElementCount() {
return __privateGet(this, _node).childElementCount;
}
text() {
return __privateGet(this, _node).textContent?.trim() ?? "";
}
attribute(name) {
return __privateGet(this, _node).getAttribute(name);
}
hasAttribute(name) {
return __privateGet(this, _node).hasAttribute(name);
}
attributeNames() {
return __privateGet(this, _node).getAttributeNames();
}
hasClass(className2) {
return __privateGet(this, _node).classList.contains(className2);
}
computedStyle() {
return window.getComputedStyle(__privateGet(this, _node));
}
imageSize() {
return {
height: __privateGet(this, _node).naturalHeight || __privateGet(this, _node).height || Number(__privateGet(this, _node).getAttribute("height") || ""),
width: __privateGet(this, _node).naturalWidth || __privateGet(this, _node).width || Number(__privateGet(this, _node).getAttribute("width") || "")
};
}
inputValue() {
return __privateGet(this, _node).value;
}
checked() {
return __privateGet(this, _node).checked;
}
selected() {
return __privateGet(this, _node).selected;
}
sameNode(other) {
return __privateGet(this, _node) === __privateGet(other, _node);
}
observe(source, onObserved, options = { childList: !0, subtree: !0 }) {
let seen = [], cleanups = [], scan = () => {
for (let node of this.all(domSelector(source))) {
if (seen.some((candidate) => candidate.sameNode(node)))
continue;
seen.push(node);
let cleanup = onObserved(node);
cleanup && cleanups.push(cleanup);
}
}, observer = new MutationObserver(scan);
return scan(), observer.observe(__privateGet(this, _node), options), () => {
observer.disconnect(), cleanups.forEach((cleanup) => cleanup());
};
}
inplace(apply = emptyDomApply) {
return ManagedDomNode.from(__privateGet(this, _node), apply);
}
move(apply = emptyDomApply) {
let managed = this.inplace(apply);
return managed.remove(), managed;
}
clone(applyOrDeep = emptyDomApply, deep = !0) {
let apply = typeof applyOrDeep == "boolean" ? emptyDomApply : applyOrDeep, cloneDeep = typeof applyOrDeep == "boolean" ? applyOrDeep : deep;
return ManagedDomNode.from(
__privateGet(this, _node).cloneNode(cloneDeep),
apply
);
}
};
_node = new WeakMap();
DomNode = _DomNode;
_ManagedDomNode = class _ManagedDomNode {
constructor(element, apply) {
__privateAdd(this, _apply);
__privateAdd(this, _node2);
__privateSet(this, _apply, apply), __privateSet(this, _node2, element), this.Component = () => __privateGet(this, _node2);
}
static from(element, apply = emptyDomApply) {
return new _ManagedDomNode(element, apply);
}
apply(...names) {
let classes = names.map((name) => {
let className2 = __privateGet(this, _apply)[name];
if (!className2)
throw new Error(`Unknown original DOM application: ${name}`);
return className2;
});
return __privateGet(this, _node2).classList.add(...classes), this;
}
all(source) {
let apply = typeof source == "string" ? emptyDomApply : source.apply;
return Array.from(
__privateGet(this, _node2).querySelectorAll(domSelector(source)),
(node) => _ManagedDomNode.from(node, apply)
);
}
rect() {
return __privateGet(this, _node2).getBoundingClientRect();
}
readAttribute(name) {
return __privateGet(this, _node2).getAttribute(name);
}
imageSize() {
return {
height: __privateGet(this, _node2).naturalHeight || __privateGet(this, _node2).height || Number(__privateGet(this, _node2).getAttribute("height") || ""),
width: __privateGet(this, _node2).naturalWidth || __privateGet(this, _node2).width || Number(__privateGet(this, _node2).getAttribute("width") || "")
};
}
setAttributes(values) {
for (let [name, value] of Object.entries(values))
__privateGet(this, _node2).setAttribute(name, value);
return this;
}
removeAttributes(...names) {
for (let name of names)
__privateGet(this, _node2).removeAttribute(name);
return this;
}
addClasses(...names) {
return __privateGet(this, _node2).classList.add(...names), this;
}
removeClasses(...names) {
return __privateGet(this, _node2).classList.remove(...names), this;
}
replaceClasses(value) {
return __privateGet(this, _node2).className = value, this;
}
styles(values, priority = "") {
for (let [property, value] of Object.entries(values))
__privateGet(this, _node2).style.setProperty(property, value, priority);
return this;
}
removeStyles(...properties) {
for (let property of properties)
__privateGet(this, _node2).style.removeProperty(property);
return this;
}
removeAllStyles() {
return __privateGet(this, _node2).removeAttribute("style"), this;
}
attribute(name, value) {
return __privateGet(this, _node2).setAttribute(name, value), this;
}
click() {
__privateGet(this, _node2).click();
}
// This is an independent Solid root, not a child of the caller's component.
// The node owner must call remove() or replace this mount to dispose its contents.
mount(view) {
mountedNodes.get(__privateGet(this, _node2))?.(), __privateGet(this, _node2).replaceChildren(), markUiRoot2(__privateGet(this, _node2)), mountedNodes.set(__privateGet(this, _node2), render(view, __privateGet(this, _node2)));
}
remove() {
mountedNodes.get(__privateGet(this, _node2))?.(), mountedNodes.delete(__privateGet(this, _node2)), __privateGet(this, _node2).remove();
}
replaceWith(replacement) {
__privateGet(this, _node2).replaceWith(
replacement instanceof _ManagedDomNode ? __privateGet(replacement, _node2) : replacement
);
}
before(sibling) {
__privateGet(this, _node2).before(sibling instanceof _ManagedDomNode ? __privateGet(sibling, _node2) : sibling);
}
after(sibling) {
__privateGet(this, _node2).after(sibling instanceof _ManagedDomNode ? __privateGet(sibling, _node2) : sibling);
}
append(...children2) {
return __privateGet(this, _node2).append(...children2.map((child) => __privateGet(child, _node2))), this;
}
prepend(child) {
__privateGet(this, _node2).prepend(child instanceof _ManagedDomNode ? __privateGet(child, _node2) : child);
}
setTextUnlessInput(text) {
__privateGet(this, _node2) instanceof HTMLInputElement || (__privateGet(this, _node2).textContent = text);
}
setHidden(hidden) {
return __privateGet(this, _node2).hidden = hidden, this;
}
hideOriginal() {
return __privateGet(this, _node2).classList.add(HIDDEN_ORIGINAL_DOM_NODE_CLASS), this;
}
replaceChildren(...children2) {
__privateGet(this, _node2).replaceChildren(...children2.map((child) => child instanceof _ManagedDomNode ? __privateGet(child, _node2) : child));
}
listen(type, listener, options) {
return __privateGet(this, _node2).addEventListener(type, listener, options), () => __privateGet(this, _node2).removeEventListener(type, listener, options);
}
observe(onChange, options = { childList: !0, subtree: !0 }) {
let observer = new MutationObserver(onChange);
return observer.observe(__privateGet(this, _node2), options), () => observer.disconnect();
}
focus() {
__privateGet(this, _node2).focus();
}
scrollIntoView(options) {
__privateGet(this, _node2).scrollIntoView(options);
}
isNode(node) {
return __privateGet(this, _node2) === node;
}
contains(node) {
return __privateGet(this, _node2).contains(node);
}
matches(source) {
return __privateGet(this, _node2).matches(domSelector(source));
}
copyAttributesTo(target) {
for (let attribute of Array.from(__privateGet(this, _node2).attributes))
__privateGet(target, _node2).setAttribute(attribute.name, attribute.value);
}
setInputValue(value) {
__privateGet(this, _node2).value = value;
}
inputValue() {
return __privateGet(this, _node2).value;
}
setSelected(selected) {
__privateGet(this, _node2).selected = selected;
}
dispatchInput() {
__privateGet(this, _node2).dispatchEvent(new Event("input", { bubbles: !0 }));
}
mirrorContentTo(target) {
let update = () => {
target.replaceChildren(
...Array.from(__privateGet(this, _node2).childNodes, (node) => node.cloneNode(!0))
);
let language = __privateGet(this, _node2).getAttribute("lang");
language ? target.setAttribute("lang", language) : target.removeAttribute("lang");
};
return update(), this.observe(update, {
attributes: !0,
attributeFilter: ["lang"],
characterData: !0,
childList: !0,
subtree: !0
});
}
};
_apply = new WeakMap(), _node2 = new WeakMap();
ManagedDomNode = _ManagedDomNode;
}
});
// src/eh/dom/domClass.ts
var sharedApply, page, common, myTags, gallery, search, settings, topBar, domClass, init_domClass = __esm({
"src/eh/dom/domClass.ts"() {
"use strict";
init_core();
sharedApply = {
coverlessSearchGrid: "ehpeek-expand-coverless-search-grid",
fitToViewport: "ehpeek-fit-to-viewport",
galleryTagMenuItem: "ehpeek-layout-gallery-tag-menu-item",
hideOriginalSearchAction: "ehpeek-hide-original-search-action",
historyLabel: "ehpeek-prefix-read-history-label",
liteSearchGrid: "ehpeek-layout-search-grid-lite",
searchGrid: "ehpeek-layout-search-grid",
searchResultColumns: "ehpeek-search-result-columns",
stackSearchGridTags: "ehpeek-stack-search-grid-tags",
tallSearchGridCover: "ehpeek-contain-tall-search-grid-cover"
}, page = {
footer: query("body > .dp"),
html: tag("html", {
apply: {
fitToViewport: sharedApply.fitToViewport,
galleryTouchLayout: "ehpeek-touch-gallery-page",
galleryWideLayout: "ehpeek-gallery-wide-layout-root"
}
}),
body: tag("body", {
apply: {
uiTheme: "ehpeek-ui-theme",
galleryTouchLayout: "ehpeek-touch-gallery-page",
galleryWideLayout: "ehpeek-gallery-wide-layout-root",
hidePreviewPageBars: "ehpeek-hide-original-preview-page-bars"
}
})
}, common = {
descendants: query("*"),
galleryLink: anchor('a[href*="/g/"]'),
image: image("img"),
interactive: query(
"a[href], button, input, select, textarea, label, [onclick]"
),
links: anchor("a[href]"),
scripts: script("script")
}, myTags = {
tags: id("usertags_outer", {
childs: {
items: query(":scope > [id^='usertag_']", {
childs: {
color: input("input[id^='tagcolor_']"),
preview: query("[id^='tagpreview_'][title]")
}
})
}
}),
options: option("#tagset_outer select option"),
defaultColor: input("#tagcolor"),
enabled: input("#tagset_enable")
}, gallery = {
actions: id("gd5", {
apply: {
expand: "ehpeek-expand-gallery-actions"
},
childs: {
items: query("a, button, input[type='button'], input[type='submit']", {
apply: {
layout: "ehpeek-layout-gallery-action"
}
})
}
}),
comments: id("cdiv", {
apply: {
touchScore: "ehpeek-enable-touch-comment-score"
},
childs: {
showAll: anchor("#chd > :first-child a[href*='hc=1']"),
score: cls("c5"),
scoreComment: cls("c1", {
childs: {
details: query(".c7[id^='cvotes_']")
}
})
}
}),
commentActions: id("postnewcomment"),
favoriteDialog: {
note: textarea("textarea[name='favnote']"),
optionRow: query("div[style*='height']"),
options: input("input[name='favcat']")
},
commentsAnchor: anchor('a[name="comments"]'),
imagePage: {
image: image("img#img"),
links: anchor("a[href]"),
navigationTop: id("i2")
},
info: {
category: id("gdc", {
childs: {
appearance: query("[class*='ct']")
}
}),
cover: id("gd1", {
childs: {
image: image("img", {
apply: {
fit: "ehpeek-fit-gallery-cover"
}
}),
descendants: query("*")
}
}),
details: id("gdd", {
childs: {
rows: row("tr", {
childs: {
cells: cell("td, th")
}
})
}
}),
favorite: id("fav", {
childs: {
link: id("favoritelink"),
titled: query("[title]")
}
}),
hostFallback: id("gleft"),
original: id("gmid"),
rating: {
actions: area('map[name="rating"] area'),
count: id("rating_count"),
image: id("rating_image"),
label: id("rating_label"),
rated: query(".irb, .irg, .irr")
},
tagMenu: id("tagmenu_act", {
apply: {
layout: "ehpeek-layout-gallery-tag-menu"
},
childs: {
actions: anchor("a")
}
}),
newTag: id("tagmenu_new", {
apply: {
layout: "ehpeek-layout-new-tag-form"
},
childs: {
button: control("#newtagbutton"),
field: input("#newtagfield"),
form: form("form")
}
}),
titleMain: id("gn"),
titleSub: id("gj"),
uploader: id("gdn", {
childs: {
link: anchor("a[href]")
}
})
},
preview: {
description: cls("gpc"),
imageLinks: anchor(
"#gdt a[href], .gdtm a[href], .gdtl a[href], a[href*='/s/']"
),
imageLinkHost: query("#gdt, .gdtm, .gdtl"),
pageBarBottom: cls("ptb"),
pageBarHost: cls("gtb"),
pageBarTop: cls("ptt"),
thumbs: id("gdt", {
apply: {
swipe: "ehpeek-enable-preview-swipe-input"
},
childs: {
images: image("img"),
links: anchor("a[href]")
}
})
},
tagContainer: query("div.gt, div.gtl, div.gtw", {
apply: {
myTag: "ehpeek-color-my-tag"
}
}),
tags: id("taglist", {
childs: {
links: anchor("a"),
rows: row("tr", {
childs: {
namespace: query(".tc, td:first-child"),
links: anchor("a")
}
})
}
})
}, search = {
controls: query("#toppane, .searchtext, .searchwarn, .searchnav, .ptt, .ptb"),
displayMode: select("select[onchange*='inline_set=dm_']", {
childs: {
options: option("option")
}
}),
favorites: {
categories: query(".ido > .nosel", {
apply: {
hide: "ehpeek-hide-original-favorites-categories"
},
childs: {
items: query(":scope > .fp, :scope > .fps", {
childs: {
indicator: cls("i")
}
})
}
}),
input: input("input[name='f_search']"),
selectedCategory: cls("fps")
},
input: input("#f_search, input[name='f_search']", {
apply: {
expand: "ehpeek-expand-search-input"
}
}),
navigation: cls("searchnav", {
childs: {
first: anchor("a[id$='first'][href]"),
previous: anchor("a[id$='prev'][href]"),
next: anchor("a[id$='next'][href]"),
last: anchor("a[id$='last'][href]"),
links: anchor("a[href]")
}
}),
navigationLink: anchor(
".searchnav a[id$='first'][href], .searchnav a[id$='prev'][href], .searchnav a[id$='next'][href], .searchnav a[id$='last'][href]"
),
panel: {
box: id("searchbox", {
apply: {
reset: "ehpeek-reset-search-box-layout"
},
childs: {
advanced: id("advdiv", {
apply: {
expand: "ehpeek-expand-search-advanced-options"
}
}),
categories: table("form > table", {
apply: {
layout: "ehpeek-layout-search-categories"
}
}),
form: form("form", {
apply: {
stack: "ehpeek-stack-search-form"
}
})
}
}),
clear: control("input[name='f_clear'], button[name='f_clear']", {
apply: {
hide: sharedApply.hideOriginalSearchAction
}
}),
clearFallback: control("input[type='button'], button[type='button']", {
apply: {
hide: sharedApply.hideOriginalSearchAction
}
}),
fileSearch: id("fsdiv", {
apply: {
expand: "ehpeek-expand-file-search"
}
}),
optionLinks: anchor("a"),
submit: control("input[name='f_apply'], button[name='f_apply']", {
apply: {
hide: sharedApply.hideOriginalSearchAction
}
}),
submitFallback: control("input[type='submit'], button[type='submit']", {
apply: {
hide: sharedApply.hideOriginalSearchAction
}
})
},
rangeBar: id("rangebar"),
removeHistory: control("[data-ehpeek-remove-history]"),
results: cls("itg", {
apply: {
compactFavorites: "ehpeek-compact-all-favorites-results",
containFavorites: "ehpeek-contain-favorites-results",
containSearch: "ehpeek-contain-search-results",
columns: sharedApply.searchResultColumns,
grid: sharedApply.searchGrid,
swipe: "ehpeek-enable-search-swipe-input"
},
childs: {
body: query(":scope > tbody"),
rows: row("tbody > tr", {
apply: {
coverless: sharedApply.coverlessSearchGrid
},
childs: {
cover: query(":scope > .gl1e"),
content: query(":scope > .gl2e", {
childs: {
detail: cls("gl4e", {
childs: {
tags: query(":scope > *", {
apply: {
stack: sharedApply.stackSearchGridTags
}
}),
title: query(":scope > .glink", {
apply: {
history: sharedApply.historyLabel
}
})
}
}),
metadata: cls("gl3e")
}
})
}
}),
galleryLinks: anchor('a[href*="/g/"]'),
links: anchor("a[href]"),
titles: cls("glink", {
apply: {
history: "ehpeek-prefix-read-history-label"
}
})
}
}),
resultText: cls("searchtext"),
submit: control("input[name='f_apply'], button[name='f_apply']"),
submitFallback: control("input[type='submit'], button[type='submit']")
}, settings = {
titleDefault: input("#tl_r"),
titleJapanese: input("#tl_j")
}, topBar = {
galleryTitle: query("#gd2, h1"),
navigation: id("nb", {
apply: {
hide: "ehpeek-hide-original-top-bar"
},
childs: {
links: anchor("a[href]", {
apply: {
layout: "ehpeek-layout-top-bar-menu-item"
}
})
}
})
}, domClass = {
common,
gallery,
myTags,
page,
search,
settings,
topBar
};
}
});
// ../reader/dist/chunk-E6UKP7HT.js
function clamp(value, min, max) {
return max < min ? min : Math.min(max, Math.max(min, value));
}
function normalizeUrl(url, baseUrl = window.location.href) {
try {
return new URL(url, baseUrl).href;
} catch {
return "";
}
}
function normalizedAspectRatio(value, fallback) {
return value && Number.isFinite(value) && value > 0 ? value : fallback;
}
function positiveNumber(value) {
return value && Number.isFinite(value) && value > 0 ? value : null;
}
function stopEvent(event) {
event.stopPropagation();
}
function registerGlobalStyle(id2, css) {
if (!css || document.getElementById(id2))
return;
let style2 = document.createElement("style");
style2.id = id2, style2.textContent = css, (document.head ?? document.documentElement).append(style2);
}
function widgetClass(base, props) {
let toggles = Object.entries(props.classList ?? {}).filter(([, enabled]) => enabled).map(([name]) => name);
return [base, props.class ?? "", ...toggles].join(" ");
}
function listenForOutsidePress(options) {
let listener = (event) => {
event.target instanceof Node && options.contains(event.target) || options.onOutsidePress(event);
};
return options.document.addEventListener(options.event, listener), () => options.document.removeEventListener(options.event, listener);
}
var init_chunk_E6UKP7HT = __esm({
"../reader/dist/chunk-E6UKP7HT.js"() {
"use strict";
}
});
// ../reader/dist/kit/helpers.js
var init_helpers = __esm({
"../reader/dist/kit/helpers.js"() {
"use strict";
init_chunk_E6UKP7HT();
init_chunk_PKBMQBKP();
}
});
// src/eh/dom/gallery.ts
function extractMyTagsPageData(root = document, tagSet) {
let source = DomNode.from(root).use(domClass.myTags), tags = source.tags.one();
if (!tags)
throw new Error("The My Tags page could not be read.");
let options = source.options.all().map((option2) => ({
label: option2.text() || option2.inputValue(),
selected: option2.selected(),
value: option2.inputValue()
})), activeTagSet = tagSet ?? options.find((option2) => option2.selected)?.value ?? "1", defaultColor = source.defaultColor.one()?.inputValue().trim() ?? "", output = [];
for (let item of tags.all(domClass.myTags.tags.items)) {
let preview = item.one(domClass.myTags.tags.items.preview), name = normalizeTagName(preview?.attribute("title") ?? "");
if (!preview || !name)
continue;
let itemColor = item.one(domClass.myTags.tags.items.color)?.inputValue() ?? "", backgroundColor = normalizeTagColor(itemColor) || normalizeTagColor(defaultColor), id2 = item.attribute("id")?.match(/^usertag_(\d+)$/)?.[1] ?? "";
id2 && output.push({
name,
backgroundColor,
color: readableTagColor(backgroundColor),
id: id2,
tagSet: activeTagSet
});
}
return {
appearances: output,
enabled: source.enabled.one()?.checked() ?? !0,
options
};
}
function normalizeTagName(value) {
return value.trim().replace(/\s+/g, " ").toLowerCase();
}
function normalizeTagColor(value) {
let color = value.trim();
return /^#[\da-f]{6}$/i.test(color) ? color : "";
}
function readableTagColor(backgroundColor) {
let red = Number.parseInt(backgroundColor.slice(1, 3), 16) / 255, green = Number.parseInt(backgroundColor.slice(3, 5), 16) / 255, blue = Number.parseInt(backgroundColor.slice(5, 7), 16) / 255, linear = (channel) => channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4;
return 0.2126 * linear(red) + 0.7152 * linear(green) + 0.0722 * linear(blue) > 0.179 ? "#000000" : "#ffffff";
}
function mutateGalleryMyTags(appearances) {
let byName = new Map(appearances.map((appearance) => [appearance.name, appearance])), source = DomNode.from(document).use(domClass.gallery), apply = () => {
for (let tag2 of source.tags.links.requery()) {
let name = galleryTagNameFromUrl(tag2.attribute("href") ?? ""), appearance = name ? byName.get(normalizeTagName(name)) : void 0;
if (!appearance?.backgroundColor)
continue;
let container = tag2.closest(domClass.gallery.tagContainer);
container && (container.inplace(domClass.gallery.tagContainer.apply).styles({
"--ehpeek-my-tag-background": appearance.backgroundColor,
"--ehpeek-my-tag-color": appearance.color
}).apply("myTag"), tag2.inplace().setAttributes({
"data-ehpeek-my-tag-id": appearance.id,
"data-ehpeek-my-tag-set": appearance.tagSet
}));
}
};
return apply(), source.tags.inplace()?.observe(apply) ?? (() => {
});
}
function manageGalleryContinueReadingButtonMount() {
let managedHost = createManagedElement("div").replaceClasses("box-border w-full px-sm pt-sm pb-sm"), viewerOptions = DomNode.from(document).use(domClass.gallery).actions.inplace();
return viewerOptions ? (viewerOptions.apply("expand").append(managedHost), managedHost) : (documentBody().append(managedHost), managedHost);
}
function manageImageReaderButtonMount() {
let navigation = DomNode.from(document).use(domClass.gallery).imagePage.navigationTop.one();
if (!navigation)
return null;
let mount = createManagedElement("div");
return navigation.inplace().after(mount), mount;
}
function manageGalleryPreview(root = document, baseUrl = window.location.href) {
let source = DomNode.from(root).use(domClass.gallery.preview), currentUrl = new URL(baseUrl, window.location.href).href, currentIndex = previewPageIndex(currentUrl), pageDescriptionSource = source.description.one(), rangeText = pageDescriptionSource?.text() ?? "", rangeValues = rangeText.match(/([\d,]+)\s*-\s*([\d,]+)\D+([\d,]+)/)?.slice(1).map((value) => Number(value.replace(/,/g, ""))) ?? [], startImage = rangeValues[0], endImage = rangeValues[1], totalImages = rangeValues[2];
if (startImage === void 0 || endImage === void 0 || totalImages === void 0 || !Number.isSafeInteger(startImage) || !Number.isSafeInteger(endImage) || !Number.isSafeInteger(totalImages) || startImage <= 0 || endImage <= 0 || totalImages <= 0 || endImage < startImage || totalImages < endImage)
throw new Error("Cannot read the gallery preview image range.");
let currentPageSize = endImage - startImage + 1, inferredFullPageSize = endImage === totalImages && currentIndex > 0 ? (totalImages - currentPageSize) / currentIndex : currentPageSize;
if (!Number.isInteger(inferredFullPageSize) || inferredFullPageSize <= 0)
throw new Error("Cannot determine the gallery preview page size.");
let pageSize = inferredFullPageSize, maxIndex = Math.max(currentIndex, Math.ceil(totalImages / pageSize) - 1), seen = /* @__PURE__ */ new Set(), previewItems = source.imageLinks.all().flatMap((link) => {
let url = normalizeUrl(link.attribute("href") || "", currentUrl), imagePage = extractPageType(url);
if (imagePage.type !== "image" || seen.has(url))
return [];
seen.add(url);
let image2 = link.one(domClass.common.image), size = image2?.imageSize(), backgroundStyle = (link.one("[style*='url(']") ?? link.closest("[style*='url(']"))?.attribute("style") ?? "", backgroundUrl = cssBackgroundUrl(backgroundStyle), imageSrc = image2?.attribute("src") || "", lazyImageSrc = image2?.attribute("data-src") || "", imageSource = imageSrc && !/blank\.gif(?:$|\?)/i.test(imageSrc) ? imageSrc : lazyImageSrc || imageSrc, thumbnail = backgroundUrl ? backgroundThumbnail(backgroundStyle, backgroundUrl, currentUrl, size) : imageThumbnail(imageSource, currentUrl, size);
return [{
aspectRatio: thumbnail.height / thumbnail.width,
pageNum: imagePage.pageNum,
pageUrl: url,
thumbnail
}];
}).sort((left, right) => left.pageNum - right.pageNum), pages = previewItems.map((item) => ({
aspectRatio: item.aspectRatio,
pageNum: item.pageNum,
url: item.pageUrl
})), data = {
currentIndex,
currentUrl,
descriptionText: rangeText,
dominantAspectRatio: dominantPreviewAspectRatio(previewItems),
endImage,
maxIndex,
pageSize,
pages,
previewItems,
startImage,
totalImages
}, thumbsSource = source.thumbs.one(), pageBarTopSource = source.pageBarTop.one(), pageBarBottomSource = source.pageBarBottom.one(), pageBarTopHostSource = pageBarTopSource?.closest(
domClass.gallery.preview.pageBarHost
), pageBarBottomHostSource = pageBarBottomSource?.closest(
domClass.gallery.preview.pageBarHost
), createPageBarMount = (position) => createManagedElement("div").replaceClasses(
`w-max max-w-full mx-auto overflow-x-auto touch-pan-y [-webkit-overflow-scrolling:touch] [&[data-dragging=true]]:select-none ${position === "top" ? "mt-2px mb-0" : "mt-0 mb-10px"}`
), elems = {
mount: root === document && thumbsSource ? createManagedElement("div").replaceClasses("contents") : null,
originalPageBarBottom: pageBarBottomSource?.inplace() ?? null,
originalPageBarBottomHost: pageBarBottomHostSource?.inplace() ?? null,
originalPageBarTop: pageBarTopSource?.inplace() ?? null,
originalPageBarTopHost: pageBarTopHostSource?.inplace() ?? null,
originalPageDescription: pageDescriptionSource?.inplace() ?? null,
pageBarBottom: pageBarBottomSource ? createPageBarMount("bottom") : null,
pageBarDescription: pageDescriptionSource && pageBarTopSource ? createManagedElement("div") : null,
pageBarTop: pageBarTopSource ? createPageBarMount("top") : null,
thumbImages: source.thumbs.images.inplaceAll(),
thumbItems: thumbsSource?.children().map(
(item) => root === document ? item.inplace() : item.move()
) ?? [],
thumbs: root === document ? source.thumbs.inplace() : null
};
return elems.mount && elems.thumbs && elems.thumbs.before(elems.mount), { data, elems, handle: {
/** Opens thumbnail image links in EhPeek Reader instead of original navigation. */
interceptPreviewImageOpen(onOpen) {
let handleClick = (event) => {
let link = event.target instanceof Element ? DomNode.from(event.target).closest(domClass.common.links) : null, href = link?.attribute("href") ?? "";
!link || extractPageType(href).type !== "image" || !link.one(domClass.common.image) && !link.closest(domClass.gallery.preview.imageLinkHost) || (event.preventDefault(), event.stopPropagation(), onOpen(normalizeUrl(href, currentUrl)));
};
return elems.thumbs?.listen("click", handleClick) ?? (() => {
});
},
/** Makes thumbnail dragging available to the horizontal preview-page gesture. */
ensurePreviewSwipeInput() {
elems.thumbs?.apply("swipe");
for (let image2 of elems.thumbImages)
image2.setAttributes({ draggable: "false" });
},
/** Installs a fetched preview page into the currently visible thumbnail host. */
replacePreviewThumbs(items) {
elems.thumbs?.replaceChildren(...items);
},
/** Marks preview loading while retaining the currently visible thumbnails. */
updatePreviewLoading(loading) {
elems.thumbs?.attribute("aria-busy", String(loading));
},
/** Gives Scroll Preview its own layout box while retaining the original Preview DOM. */
installScrollPreviewMount() {
elems.mount?.replaceClasses("ehpeek-scroll-preview-mount"), elems.originalPageBarTopHost?.hideOriginal(), elems.originalPageBarBottomHost?.hideOriginal(), elems.originalPageDescription?.hideOriginal(), elems.thumbs?.hideOriginal();
},
/** Replaces both original page bars with mounts owned by EhPeek pagination. */
installPreviewPageBars() {
DomNode.from(document).use(domClass.page).body.inplace()?.apply("hidePreviewPageBars"), elems.originalPageBarTop && elems.pageBarTop && elems.originalPageBarTop.after(elems.pageBarTop), elems.originalPageBarBottom && elems.pageBarBottom && elems.originalPageBarBottom.after(elems.pageBarBottom), elems.originalPageDescription && elems.pageBarDescription && elems.pageBarTop && elems.pageBarTop.before(elems.pageBarDescription);
},
/** Brings the requested EhPeek page bar into view after preview navigation. */
scrollPreviewPageBarIntoView(position) {
(position === "top" ? elems.pageBarTop : elems.pageBarBottom)?.scrollIntoView({
behavior: "smooth",
block: position === "top" ? "start" : "end"
});
}
} };
}
function dominantPreviewAspectRatio(items) {
let buckets = /* @__PURE__ */ new Map(), dominant = null;
for (let item of items) {
let key = Math.round(item.aspectRatio * 10), bucket = buckets.get(key) ?? { count: 0, total: 0 };
bucket.count += 1, bucket.total += item.aspectRatio, buckets.set(key, bucket), (!dominant || bucket.count > dominant.count) && (dominant = bucket);
}
if (!dominant)
throw new Error("Cannot determine the gallery preview aspect ratio.");
return dominant.total / dominant.count;
}
function cssBackgroundUrl(style2) {
return style2.match(/url\(\s*(['"]?)(.*?)\1\s*\)/i)?.[2] ?? "";
}
function backgroundThumbnail(style2, url, baseUrl, fallbackSize) {
let declaration = document.createElement("div").style;
return declaration.cssText = style2, {
backgroundPosition: declaration.backgroundPosition || "0 0",
backgroundRepeat: declaration.backgroundRepeat || "no-repeat",
backgroundSize: declaration.backgroundSize || "auto",
height: cssPixelSize(declaration.height) ?? validThumbnailSize(fallbackSize?.height),
kind: "background",
url: normalizeUrl(url, baseUrl),
width: cssPixelSize(declaration.width) ?? validThumbnailSize(fallbackSize?.width)
};
}
function imageThumbnail(url, baseUrl, size) {
return {
backgroundPosition: "0 0",
backgroundRepeat: "no-repeat",
backgroundSize: "auto",
height: validThumbnailSize(size?.height),
kind: "image",
url: url ? normalizeUrl(url, baseUrl) : "",
width: validThumbnailSize(size?.width)
};
}
function cssPixelSize(value) {
if (!value.endsWith("px"))
return null;
let parsed = Number.parseFloat(value);
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
}
function validThumbnailSize(value) {
return value && Number.isFinite(value) && value > 0 ? value : 100;
}
async function loadGalleryPreviewPage(previewIndex, pageUrl) {
let url = previewUrlForIndex(previewIndex, pageUrl), response = await requestPage(url);
return manageGalleryPreview(response.document, response.url);
}
function extractImageGalleryPage(root = document) {
for (let link of DomNode.from(root).use(domClass.common).links.all()) {
let page2 = extractPageType(normalizeUrl(link.attribute("href") || ""));
if (page2.type === "gallery")
return page2;
}
return null;
}
async function loadEhImagePage(page2, signal) {
let response = await requestPage(page2.url, { signal }), imagePage = DomNode.from(response.document).use(domClass.gallery.imagePage), image2 = imagePage.image.one(), imageUrl = normalizeUrl(
image2?.attribute("src") || image2?.attribute("data-src") || "",
page2.url
);
if (!imageUrl)
throw new Error(activeTexts.errors.imageNotFound);
let numberAttribute = (name) => {
let value = Number(image2?.attribute(name));
return Number.isFinite(value) && value > 0 ? value : null;
};
return {
height: numberAttribute("height"),
imageUrl,
originalImageUrl: imagePage.links.all().map((link) => normalizeUrl(link.attribute("href") || "", page2.url)).find(isFullImageUrl) ?? null,
width: numberAttribute("width")
};
}
var init_gallery = __esm({
"src/eh/dom/gallery.ts"() {
"use strict";
init_request();
init_i18n2();
init_helpers();
init_url();
init_core();
init_domClass();
}
});
// src/eh/dom/galleryInfo.ts
function extractGalleryHistoryInfo() {
let page2 = DomNode.from(document), source = page2.use(domClass.gallery.info), category = source.category.one(), historyCategory = page2.one(
domClass.gallery.info.category,
retainedOriginalPageNode
) ?? category, categoryClass = (historyCategory?.one(
domClass.gallery.info.category.appearance,
anyDomNode
)?.attribute("class") ?? historyCategory?.attribute("class") ?? "").split(/\s+/).find((className2) => /^ct[1-9a]$/.test(className2)), readDetailRows = (details) => details?.all(domClass.gallery.info.details.rows, anyDomNode).map((detailRow) => detailRow.all(
domClass.gallery.info.details.rows.cells,
anyDomNode
).slice(1).map((detailCell) => detailCell.text()).filter(Boolean).join(" ")) ?? [], retainedDetails = page2.one(
domClass.gallery.info.details,
retainedOriginalPageNode
), retainedRows = readDetailRows(retainedDetails), rows = retainedRows.length > 0 ? retainedRows : source.details.rows.all().map((detailRow) => detailRow.all(domClass.gallery.info.details.rows.cells).slice(1).map((detailCell) => detailCell.text()).filter(Boolean).join(" ")), postedAt = page2.one(domClass.gallery.info.details, anyDomNode)?.all(domClass.gallery.info.details.rows.cells, anyDomNode).map((cell2) => parseGalleryPostedAt(cell2.text())).find((value) => value !== void 0), ratingMatch = (page2.all(domClass.common.scripts).map((pageScript) => pageScript.text()).find((script2) => script2.includes("display_rating")) ?? "").match(/\bdisplay_rating\s*=\s*(-?\d+(?:\.\d+)?)/), rating = Number(ratingMatch?.[1]), cover = source.cover.one(), coverUrl = source.cover.image.one()?.attribute("src") ?? "";
if (!coverUrl && cover)
for (let node of [cover, ...cover.all(domClass.common.descendants)]) {
let match = node.computedStyle().backgroundImage.match(/url\(["']?(.+?)["']?\)/);
if (match?.[1]) {
coverUrl = match[1];
break;
}
}
return {
category: historyCategory?.text() || void 0,
categoryClass,
coverUrl: coverUrl || void 0,
language: rows[3] || void 0,
postedAt,
rating: ratingMatch && Number.isFinite(rating) ? rating : void 0,
title: page2.one(domClass.gallery.info.titleMain, retainedOriginalPageNode)?.text() || source.titleMain.one()?.text() || void 0,
titleSub: page2.one(domClass.gallery.info.titleSub, retainedOriginalPageNode)?.text() || source.titleSub.one()?.text() || void 0,
uploader: page2.one(domClass.gallery.info.uploader, retainedOriginalPageNode)?.text() || source.uploader.one()?.text() || void 0
};
}
function parseGalleryPostedAt(value) {
let match = value?.match(
/^(\d{4})-(\d{2})-(\d{2})[ T](\d{2}):(\d{2})(?::(\d{2}))?$/
);
if (!match)
return;
let [, year, month, day, hour, minute, second = "0"] = match;
return Date.UTC(
Number(year),
Number(month) - 1,
Number(day),
Number(hour),
Number(minute),
Number(second)
);
}
function manageGalleryInfo(preview) {
let mount = createAnchor("gallery-info");
if (!mount)
return null;
let page2 = DomNode.from(document), gallery2 = page2.use(domClass.gallery), source = gallery2.info, original = source.original.one(), host = original?.parent() ?? source.hostFallback.one()?.parent() ?? null;
if (!original || !host)
return null;
let readMeta = () => {
let rows = source.details.rows.all().map((detailRow) => {
let cells = detailRow.all(domClass.gallery.info.details.rows.cells);
return {
label: cells[0]?.text() ?? "",
value: cells.slice(1).map((cell2) => cell2.text()).filter(Boolean).join(" ")
};
});
return {
favorited: rows[6]?.value ? [rows[6].label, rows[6].value].filter(Boolean).join(" ") : void 0,
fileSize: rows[4]?.value,
language: rows[3]?.value,
parent: rows[1]?.value,
posted: rows[0]?.value
};
}, readActions = () => gallery2.actions.items.all().filter((node) => {
let href = node.attribute("href")?.trim() ?? "";
return node.hasAttribute("onclick") || !!(href && href !== "#" && !/^javascript:/i.test(href));
}).slice(0, 6), readTagGroups = () => {
let rows = gallery2.tags.rows.all();
return rows.length > 0 ? rows.map((row2) => ({
namespace: row2.one(domClass.gallery.tags.rows.namespace)?.text().replace(/:$/, "") || "tag",
tags: row2.all(domClass.gallery.tags.rows.links).map(readTag).filter((tag2) => tag2 !== null).slice(0, 30)
})).filter((group) => group.tags.length > 0) : [{
namespace: "tag",
tags: gallery2.tags.links.all().map(readTag).filter((tag2) => tag2 !== null).slice(0, 60)
}].filter((group) => group.tags.length > 0);
}, manageTagGroups = () => readTagGroups().map((group) => ({
namespace: group.namespace,
tags: group.tags.map(({ data: tag2, source: source2 }) => ({
...tag2,
contentSource: source2.inplace()
}))
})), meta = readMeta(), category = source.category.one(), categoryStyle = source.category.appearance.one() ?? category, cover = source.cover.one(), coverSource = source.cover.image.one(), favorite = source.favorite.one(), ratingCount = source.rating.count.one(), ratingImage = source.rating.image.one(), ratingLabel = source.rating.label.one(), ratingActions = source.rating.actions.all(), uploader = source.uploader.link.one(), newTagButton = source.newTag.button.one(), newTagField = source.newTag.field.one(), newTagForm = source.newTag.form.one(), scripts = page2.all(domClass.common.scripts).map((pageScript) => pageScript.text()), actionSources = readActions(), tagContentSources = [], tagGroups = readTagGroups().map((group) => ({
namespace: group.namespace,
tags: group.tags.map(({ data: tag2, source: source2 }) => {
let contentSourceIndex = tagContentSources.push(source2) - 1;
return { ...tag2, contentSourceIndex };
})
})), data = {
category: category?.text() ?? "",
categoryAppearance: readCategory(categoryStyle),
categoryUrl: readCategoryUrl(categoryStyle),
favorite: readFavorite(favorite, scripts),
rating: readRating(ratingCount, ratingImage, ratingLabel, scripts),
summary: [
meta.language,
preview?.totalImages ? `${preview.totalImages} ${activeTexts.gallery.pages.toLowerCase()}` : void 0,
meta.fileSize,
meta.favorited,
meta.posted ?? meta.parent
].filter((value) => !!value).slice(0, 6).map((value) => ({ value })),
tagGroups,
titleMain: source.titleMain.one()?.text() ?? "",
titleSub: source.titleSub.one()?.text() ?? "",
uploader: uploader?.text() ?? "",
uploaderUrl: uploader?.attribute("href") ?? ""
}, coverUrl = readCoverUrl(cover, coverSource), managedCover = coverUrl ? source.cover.image.clone()?.replaceClasses("").apply("fit") ?? createManagedElement("img", { fit: "ehpeek-fit-gallery-cover" }).apply("fit") : null;
managedCover?.removeAttributes("id", "style", "width", "height").setAttributes({ alt: "", decoding: "async", loading: "eager", src: coverUrl });
let managedNewTag = newTagButton && newTagField && newTagForm ? source.newTag.inplace()?.apply("layout") ?? null : null, hostApply = { hide: "ehpeek-hide-original-gallery-info" };
managedNewTag?.setHidden(!1).removeStyles("display");
let elems = {
actionItems: actionSources.map((item) => item.move(domClass.gallery.actions.items.apply).apply("layout")),
cover: managedCover,
host: host.inplace(hostApply).apply("hide"),
mount,
newTag: managedNewTag,
ratingActions: ratingActions.map((action) => action.inplace()),
tagContents: tagContentSources.map((source2) => source2.inplace()),
tagList: gallery2.tags.inplace(),
tagMenuAction: source.tagMenu.inplace()
}, selectedTagSource = null, activateTagMenu = (source2) => {
let stopNavigation = source2.listen("click", (event) => {
event.preventDefault();
}, { once: !0 });
source2.click(), stopNavigation();
};
return { data, elems, handle: {
/** Normalizes the original cover for GalleryInfoPanel's responsive layout. */
/** Hides original GalleryInfo children and installs the component mount. */
installGalleryInfoPanel() {
elems.host.prepend(elems.mount);
},
/** Loads the original favorite categories and note for EhPeek's favorite modal. */
async loadGalleryFavoriteDialog(actionUrl, favorited) {
let response = await requestPage(actionUrl);
return isLoginDocument(response.document) ? { authenticated: !1 } : { authenticated: !0, ...readFavoriteDialog(response.document, favorited) };
},
/** Submits a tag to the chosen My Tags collection and validates the response. */
async submitFavoriteTag(tag2, tagSet, mode) {
let response = await addMyTag(tag2.name, tagSet, mode);
return extractMyTagsPageData(response.document, tagSet);
},
/** Keeps component tag groups synchronized with original-page tag updates. */
observeGalleryTagGroups(onChange) {
return elems.tagList?.observe(() => {
gallery2.tags.rows.requery(), gallery2.tags.links.requery(), onChange(manageTagGroups());
}) ?? (() => {
});
},
/** Activates E-H's original rating area and lets its page script submit the vote. */
submitGalleryRating(value) {
let rating = Math.round(value * 2);
if (rating < 1 || rating > 10)
throw new RangeError("Gallery rating must be between 0.5 and 5 stars.");
let action = elems.ratingActions[rating - 1];
if (!action)
throw new Error("Gallery rating action is unavailable.");
action.click();
},
/** Removes the selected tag from its stored My Tags collection. */
async removeFavoriteTag(tag2) {
if (!tag2.myTag)
throw new Error("The tag is not in My Tags.");
let response = await deleteMyTag(tag2.myTag.id, tag2.myTag.tagSet);
return extractMyTagsPageData(response.document, tag2.myTag.tagSet);
},
/** Opens E-H's original tag actions and only adapts their presentation. */
openGalleryTagMenu(tag2) {
if (!elems.tagMenuAction)
throw new Error("Gallery tag actions are unavailable.");
activateTagMenu(tag2.contentSource), elems.newTag?.setHidden(!1).removeStyles("display");
let actions = elems.tagMenuAction.all(domClass.gallery.info.tagMenu.actions);
if (actions.length === 0)
throw activateTagMenu(tag2.contentSource), elems.newTag?.setHidden(!1).removeStyles("display"), new Error("Gallery tag actions could not be opened.");
selectedTagSource = tag2.contentSource, elems.tagMenuAction.apply("layout"), actions.find((action) => action.readAttribute("onclick")?.includes("toggle_tagmenu"))?.hideOriginal();
},
/** Closes E-H's selected tag without replacing its action DOM. */
closeGalleryTagMenu() {
selectedTagSource && activateTagMenu(selectedTagSource), elems.newTag?.setHidden(!1).removeStyles("display"), selectedTagSource = null;
},
/** Updates the Gallery favorite state through the original site endpoint. */
updateGalleryFavorite
} };
}
function mutateGalleryTouchLayout(fitToViewport) {
let page2 = DomNode.from(document).use(domClass.page), html = page2.html.inplace(), body = page2.body.inplace();
if (!html || !body)
throw new Error("Gallery page layout is unavailable.");
html.apply("galleryTouchLayout"), body.apply("galleryTouchLayout"), body.apply("uiTheme"), fitToViewport && html.apply("fitToViewport");
}
function mutateGalleryWideLayout(info, preview, initiallyEnabled, initialInfoRatio, replacesOriginalPreview) {
let page2 = DomNode.from(document).use(domClass.page), source = DomNode.from(document).use(domClass.gallery), html = page2.html.inplace(), body = page2.body.inplace(), footer = page2.footer.inplace(), comments = source.comments.inplace(), commentsAnchor = source.commentsAnchor.inplace(), pageBarTopHost = source.preview.pageBarTop.one()?.parent()?.inplace() ?? null, pageBarBottomHost = source.preview.pageBarBottom.one()?.parent()?.inplace() ?? null, previewMount = preview.elems.mount, thumbs = preview.elems.thumbs;
if (!html || !body || !comments || !previewMount || !thumbs)
return null;
let leftNodes = [info.elems.host, commentsAnchor, comments].filter((node) => node !== null), rightNodes = (replacesOriginalPreview ? [previewMount] : [pageBarTopHost, previewMount, thumbs, pageBarBottomHost]).filter((node) => node !== null), resizeHandleMount = createManagedElement("div").replaceClasses("ehpeek-touch-gallery-layout-resizer"), layout = null, left = null, right = null, positions = [], enabled = initiallyEnabled, infoRatio = initialInfoRatio, columnSubscriptions = /* @__PURE__ */ new Set(), columnScopes = {
info: createColumnScope("info", () => left?.Component() ?? null, columnSubscriptions),
preview: createColumnScope("preview", () => right?.Component() ?? null, columnSubscriptions)
}, update = () => {
if (enabled && !layout) {
if (layout = createAnchor("gallery-wide-layout")?.replaceClasses("ehpeek-touch-gallery-layout") ?? null, !layout)
return;
layout.styles({
"grid-template-columns": `${infoRatio}fr ${1 - infoRatio}fr`
}), window.scrollTo(0, 0), html.apply("galleryWideLayout"), body.apply("galleryWideLayout"), left = createManagedElement("div").replaceClasses("ehpeek-touch-gallery-layout-left"), right = createManagedElement("div").replaceClasses("ehpeek-touch-gallery-layout-right"), positions = [...leftNodes, ...rightNodes, footer].filter((node) => node !== null).map((node) => {
let marker = createManagedElement("span").setHidden(!0);
return node.before(marker), { marker, node };
}), info.elems.host.before(layout), layout.append(
left,
right,
resizeHandleMount,
...footer ? [footer] : []
), left.append(...leftNodes), right.append(...rightNodes);
for (let syncColumn of columnSubscriptions)
syncColumn();
window.dispatchEvent(new Event("resize"));
return;
}
if (!enabled && layout) {
for (let { marker, node } of positions)
marker.after(node), marker.remove();
positions = [], layout.remove(), layout = null, left = null, right = null;
for (let syncColumn of columnSubscriptions)
syncColumn();
html.removeClasses("ehpeek-gallery-wide-layout-root"), body.removeClasses("ehpeek-gallery-wide-layout-root"), window.dispatchEvent(new Event("resize"));
}
};
return update(), {
columnScope: (column) => columnScopes[column],
resizeHandleMount,
updateEnabled(value) {
enabled = value, update();
},
updateInfoRatio(value) {
infoRatio = value, layout?.styles({
"grid-template-columns": `${infoRatio}fr ${1 - infoRatio}fr`
});
}
};
}
function manageGalleryCommentsTouch(onLoadError) {
let gallery2 = DomNode.from(document).use(domClass.gallery), comments = gallery2.comments.inplace();
comments?.apply("touchScore");
let showAllSource = gallery2.comments.showAll.one(), showAll = showAllSource?.inplace() ?? null, showAllButton = showAllSource?.clone() ?? null, showAllUrl = showAll?.readAttribute("href"), loadingAll = !1;
if (comments && showAll && showAllUrl) {
showAllButton && gallery2.commentActions.inplace()?.append(showAllButton);
let loadAll = (event) => {
event.preventDefault(), !loadingAll && (loadingAll = !0, showAll.setAttributes({ "aria-busy": "true" }), showAllButton?.setAttributes({ "aria-busy": "true" }), requestPage(showAllUrl).then((response) => {
let loaded = DomNode.from(response.document).use(domClass.gallery.comments).one();
if (!loaded)
throw new Error("Cannot read all gallery comments");
comments.replaceChildren(...loaded.children().map((child) => child.move())), manageGalleryCommentsTouch(onLoadError);
}).catch(onLoadError).finally(() => {
loadingAll = !1, showAll.removeAttributes("aria-busy"), showAllButton?.removeAttributes("aria-busy");
}));
};
showAll.listen("click", loadAll), showAllButton?.listen("click", loadAll);
}
let items = gallery2.comments.score.all().filter((trigger) => trigger.attribute("data-ehpeek-touch-comment-score") !== "true").map((trigger) => ({
trigger,
details: trigger.closest(domClass.gallery.comments.scoreComment)?.one(domClass.gallery.comments.scoreComment.details) ?? null
})).filter((item) => item.details !== null).map(({ trigger, details }) => ({
details: details.inplace(),
detailsId: details.attribute("id") ?? "",
expanded: !1,
trigger: trigger.inplace()
})), setExpanded = (item, expanded) => {
item.expanded = expanded, item.trigger.attribute("aria-expanded", String(expanded)), item.details.attribute("aria-hidden", String(!expanded));
};
for (let item of items) {
item.trigger.removeAttributes("onmouseover", "onmouseout", "onclick").setAttributes({
"data-ehpeek-touch-comment-score": "true",
role: "button",
tabindex: "0",
"aria-controls": item.detailsId
}), setExpanded(item, !1);
let toggle = (event) => {
event.preventDefault(), event.stopImmediatePropagation();
let shouldExpand = !item.expanded;
for (let candidate of items)
setExpanded(candidate, candidate === item && shouldExpand);
};
item.trigger.listen("click", toggle), item.trigger.listen("keydown", (event) => {
(event.key === "Enter" || event.key === " ") && toggle(event);
});
}
}
function createColumnScope(column, element, columnSubscriptions) {
return {
column,
available: () => element()?.isConnected ?? !1,
bounds: () => {
let target = element();
if (!target?.isConnected)
return null;
let { bottom, height, left, right, top, width } = target.getBoundingClientRect();
return { bottom, height, left, right, top, width };
},
listen: ({ onBoundsChange, onScroll }) => {
let target = null, frame = null, scheduleBoundsChange = () => {
frame === null && (frame = window.requestAnimationFrame(() => {
frame = null, onBoundsChange();
}));
}, resizeObserver = new ResizeObserver(scheduleBoundsChange), syncColumn = () => {
let next = element();
next !== target && (target && onScroll && target.removeEventListener("scroll", onScroll), resizeObserver.disconnect(), target = next, target && (resizeObserver.observe(target), onScroll && target.addEventListener("scroll", onScroll, { passive: !0 })), scheduleBoundsChange());
}, onAncestorScroll = (event) => {
if (!target)
return;
let scroller = event.target;
(scroller === document || scroller === window || scroller instanceof Element && scroller !== target && scroller.contains(target)) && scheduleBoundsChange();
};
return syncColumn(), columnSubscriptions.add(syncColumn), window.addEventListener("resize", scheduleBoundsChange), window.addEventListener("scroll", onAncestorScroll, { capture: !0, passive: !0 }), () => {
columnSubscriptions.delete(syncColumn), resizeObserver.disconnect(), target && onScroll && target.removeEventListener("scroll", onScroll), window.removeEventListener("resize", scheduleBoundsChange), window.removeEventListener("scroll", onAncestorScroll, !0), frame !== null && window.cancelAnimationFrame(frame);
};
},
scrollToTop: () => element()?.scrollTo({ top: 0, behavior: "smooth" }),
scrollTop: () => element()?.scrollTop ?? 0
};
}
var GALLERY_CATEGORY_FLAGS, readCategory, readCategoryUrl, readCoverUrl, readFavorite, readRating, readTag, favoriteColor, readFavoriteDialog, isLoginDocument, init_galleryInfo = __esm({
"src/eh/dom/galleryInfo.ts"() {
"use strict";
init_i18n2();
init_request();
init_url();
init_core();
init_gallery();
init_domClass();
init_external();
GALLERY_CATEGORY_FLAGS = {
ct1: 1,
ct2: 2,
ct3: 4,
ct4: 8,
ct5: 16,
ct6: 32,
ct7: 64,
ct8: 128,
ct9: 256,
cta: 512
};
readCategory = (node) => {
let style2 = node?.computedStyle();
return {
"background-color": style2?.backgroundColor ?? "",
"background-image": style2?.backgroundImage ?? "",
"border-color": style2?.borderColor ?? "",
color: style2?.color ?? ""
};
}, readCategoryUrl = (node) => {
let categoryClass = node?.attribute("class")?.split(/\s+/).find((className2) => className2 in GALLERY_CATEGORY_FLAGS);
if (!categoryClass)
return null;
let url = new URL("/", window.location.href);
return url.searchParams.set(
"f_cats",
String(1023 - GALLERY_CATEGORY_FLAGS[categoryClass])
), url.href;
}, readCoverUrl = (cover, source) => {
let direct = source?.attribute("src") ?? "";
if (direct)
return direct;
for (let node of cover ? [cover, ...cover.all(domClass.common.descendants)] : []) {
let match = node.computedStyle().backgroundImage.match(/url\(["']?(.+?)["']?\)/);
if (match?.[1])
return match[1];
}
return "";
}, readFavorite = (element, scripts) => {
let displayed = element?.one(domClass.gallery.info.favorite.link)?.text() || element?.one(domClass.gallery.info.favorite.titled)?.attribute("title")?.trim() || "", slot = displayed.match(/(?:^|\D)([0-9])(?:\D|$)/)?.[1], favorited = slot !== void 0 || /^favorited$/i.test(displayed), match = (scripts.find(
(item) => item.includes("popbase") && item.includes("addfav")
) ?? "").match(
/popbase\s*=\s*base_url\s*\+\s*"gallerypopups\.php\?gid=(\d+)&t=([^"]+)&act="/
);
return {
actionUrl: match ? `/gallerypopups.php?gid=${match[1]}&t=${match[2]}&act=addfav` : "",
color: slot === void 0 ? null : `var(--color-site-favorite-${slot})`,
favorited,
label: favorited ? displayed : activeTexts.gallery.notFavorited
};
}, readRating = (count, image2, labelNode, scripts) => {
let label = labelNode?.text() ?? "", match = (scripts.find((item) => item.includes("display_rating")) ?? "").match(/\bdisplay_rating\s*=\s*(-?\d+(?:\.\d+)?)/), scriptValue = Number(match?.[1]), value = match && Number.isFinite(scriptValue) ? scriptValue : null;
return label && value !== null ? {
count: count?.text() ?? "",
label,
rated: image2?.matches(domClass.gallery.info.rating.rated) ?? !1,
value
} : null;
}, readTag = (tag2) => {
let label = tag2.text() || tag2.attribute(externalDom.tagLabelAttribute)?.trim() || tag2.attribute("title")?.trim() || "", href = tag2.attribute("href") ?? "", name = galleryTagNameFromUrl(href);
if (!label || !name || !href)
return null;
let container = tag2.closest(domClass.gallery.tagContainer) ?? tag2, tagStyle = tag2.computedStyle(), containerStyle = container.computedStyle(), myTagId = tag2.attribute("data-ehpeek-my-tag-id"), myTagSet = tag2.attribute("data-ehpeek-my-tag-set");
return {
data: {
appearance: {
backgroundColor: containerStyle.backgroundColor,
borderColor: containerStyle.borderColor,
color: tagStyle.color
},
label,
myTag: myTagId && myTagSet ? { id: myTagId, tagSet: myTagSet } : null,
name,
url: href
},
source: tag2
};
}, favoriteColor = (value) => {
let slot = value.match(/^(?:fav)?([0-9])$/i)?.[1] ?? value.match(/^favorites?\s+([0-9])$/i)?.[1];
return slot === void 0 ? null : `var(--color-site-favorite-${slot})`;
}, readFavoriteDialog = (doc, favorited) => {
let dialog = DomNode.from(doc).use(domClass.gallery.favoriteDialog), options = dialog.options.all().map((favoriteInput) => {
let row2 = favoriteInput.closest(domClass.gallery.favoriteDialog.optionRow), value = favoriteInput.inputValue();
return {
color: favoriteColor(value),
label: row2?.text().replace(/\s+/g, " ") || value,
selected: favorited && favoriteInput.checked(),
value
};
});
return {
note: dialog.note.one()?.inputValue() ?? "",
options
};
}, isLoginDocument = (doc) => doc.querySelector('input[type="password"]') !== null;
}
});
// src/eh/dom/search.ts
function listenGalleryLinksOpenInNewTab(host) {
let handleClick = (event) => {
let link = event.target instanceof Element ? DomNode.from(event.target).closest(domClass.search.results.galleryLinks) : null;
link?.closest(domClass.search.results) && link.inplace().setAttributes({ target: "_blank", rel: "noopener noreferrer" });
};
return host.listen("click", handleClick, !0);
}
function createReadHistoryGridRow(item, titlePreference) {
let info = item.info, metadataItems = [], appendMetadata = (value, className2) => {
if (!value)
return;
let element = createManagedElement("div").replaceClasses(className2);
element.setTextUnlessInput(value), metadataItems.push(element);
};
if (info?.category && info.categoryClass) {
let category = createManagedElement("div").replaceClasses(`cn ${info.categoryClass} ehpeek-search-meta-category`);
category.setTextUnlessInput(info.category), metadataItems.push(category);
}
if (appendMetadata(
info?.postedAt === void 0 ? void 0 : new Date(info.postedAt).toISOString().slice(0, 16).replace("T", " "),
"ehpeek-search-meta-posted"
), info?.rating !== void 0) {
let rounded = Math.round(info.rating * 2) / 2, rating = createManagedElement("div").replaceClasses("ir ehpeek-search-meta-rating").styles({
"background-position": `${-16 * (5 - Math.ceil(rounded))}px ${Number.isInteger(rounded) ? -1 : -21}px`,
opacity: "1"
});
metadataItems.push(rating);
}
appendMetadata(info?.uploader, "ehpeek-search-meta-uploader"), appendMetadata(
item.totalPages ? `${item.totalPages} ${activeTexts.gallery.pages.toLowerCase()}` : void 0,
"ehpeek-search-meta-pages"
);
let historyLabel = item.currentPage > 0 ? `${item.currentPage} / ${item.totalPages ?? "?"}` : activeTexts.history.visitedLabel, removeButton = createManagedElement("button").setAttributes({ type: "button", "data-ehpeek-remove-history": "true" }).replaceClasses(
"relative z-2 ui-hit-min-h-lg ui-py-xs ui-px-lg ui-rounded-md border border-[var(--color-site-border-subtle)] bg-[var(--color-site-surface)] ehp-color-site-text font-inherit textsize-md font-700 text-center cursor-pointer [touch-action:manipulation] hover:bg-[var(--color-site-item-hover)]"
);
removeButton.setTextUnlessInput(activeTexts.history.actions.remove);
let historyActions = createManagedElement("div").replaceClasses("ehpeek-read-history-actions box-border flex items-center justify-end ui-gap-md ui-pr-sm ui-pb-xs").append(removeButton), titleText = titlePreference === "sub" ? info?.titleSub || info?.title : info?.title || info?.titleSub, galleryHref = new URL(
`/g/${item.galleryId}/${item.token}/`,
window.location.href
).href, row2 = createManagedElement("tr").setAttributes({
"data-ehpeek-read-history": item.currentPage > 0 ? "reading" : "visited"
}), thumbnailCell = createManagedElement("td").replaceClasses("gl1e"), thumbnail = createManagedElement("div"), image2 = info?.coverUrl ? createManagedElement("img").setAttributes({
alt: titleText ?? "",
loading: "lazy",
src: info.coverUrl
}) : null;
image2 ? thumbnail.append(
createManagedElement("a").attribute("href", galleryHref).append(image2)
) : thumbnailCell.setHidden(!0), thumbnailCell.append(thumbnail);
let contentCell = createManagedElement("td").replaceClasses("gl2e"), galleryLink = createManagedElement("a").attribute("href", galleryHref), detail = createManagedElement("div").replaceClasses("gl4e h-full"), title = createManagedElement("div").replaceClasses(`glink ${sharedApply.historyLabel}`).setAttributes({ "data-ehpeek-history-label": historyLabel });
title.setTextUnlessInput(titleText ?? ""), title.setHidden(!titleText);
let metadata = createManagedElement("div").replaceClasses("gl3e");
return metadata.append(...metadataItems), galleryLink.append(detail.append(title)), contentCell.append(
createManagedElement("div").replaceClasses("h-full").append(metadata, galleryLink)
), row2.append(thumbnailCell, contentCell), {
coverImage: image2,
detail,
galleryHref,
galleryLink,
metadata,
originalGalleryLink: !1,
row: row2,
stackTags: !1,
tags: [historyActions],
title,
titleText: titleText ?? "",
withoutCover: !image2
};
}
function manageReadHistoryPage(items, titlePreference, mode = "ehpeek-lite") {
let page2 = DomNode.from(document), resultList = page2.use(domClass.search).results.one(), navigationTopMount = createAnchor("read-history-navigation-top"), navigationBottomMount = createAnchor("read-history-navigation-bottom");
if (!resultList || !navigationTopMount || !navigationBottomMount)
return null;
let grids = manageReadHistoryGrids({
items,
mode,
source: resultList,
titlePreference
});
grids.elems.resultList.before(navigationTopMount), grids.elems.resultList.after(navigationBottomMount);
for (let control2 of page2.all(domClass.search.controls, anyDomNode))
control2.inplace().hideOriginal();
let handle = {
/** Applies new-tab semantics to History gallery links at activation time. */
listenGalleryLinksOpenInNewTab: () => listenGalleryLinksOpenInNewTab(grids.elems.resultList),
/** Replaces the visible History rows without navigating away from the current document. */
updateReadHistoryItems: grids.handle.updateItems,
/** Reports explicit removal requests without exposing History rows. */
listenForReadHistoryRemoval: grids.handle.listenForItemRemoval,
/** Keeps navigation anchored to the corresponding edge after an in-page page change. */
scrollReadHistoryPage(position) {
(position === "bottom" ? navigationBottomMount : navigationTopMount).scrollIntoView({
behavior: "smooth",
block: position === "bottom" ? "end" : "start"
});
},
/** Switches the History result list between one and two result columns. */
updateResultColumns(enabled) {
enabled ? grids.elems.resultList.addClasses(sharedApply.searchResultColumns) : grids.elems.resultList.removeClasses(sharedApply.searchResultColumns);
}
};
return {
elems: {
navigationBottomMount,
navigationTopMount,
resultList: grids.elems.resultList
},
handle
};
}
function manageSearchResults() {
let source = DomNode.from(document).use(domClass.search), resultSource = source.results.one();
if (!resultSource)
return null;
let resultHost = resultSource.parent()?.inplace() ?? null, elems = {
resultList: resultSource.inplace(domClass.search.results.apply),
searchInput: source.input.inplace()
};
return { elems, handle: {
/** Reads the live original link so swipe navigation matches the current page controls. */
readNavigationUrl(direction) {
return (direction === "next" ? source.navigation.next.one() : source.navigation.previous.one())?.attribute("href") ?? null;
},
/** Routes the original pagination controls through the active page owner. */
interceptSearchNavigation(onNavigate) {
let handleClick = (event) => {
let url = (event.target instanceof Element ? DomNode.from(event.target).closest(domClass.search.navigationLink) : null)?.attribute("href") ?? null;
url && (event.preventDefault(), event.stopPropagation(), onNavigate(url));
};
return document.addEventListener("click", handleClick, !0), () => document.removeEventListener("click", handleClick, !0);
},
/** Replaces the current result page without deciding browser-history behavior. */
async loadSearchPage(url, signal) {
let response = await requestPage(url, { signal });
if (!replaceSearchPageContent(response.document))
throw new Error(activeTexts.errors.searchPageContentNotFound);
},
/** Returns enhanced Search navigation to its input, or the page top when absent. */
scrollSearchPageToInput() {
elems.searchInput ? elems.searchInput.scrollIntoView({ block: "start", behavior: "auto" }) : window.scrollTo({ top: 0, behavior: "auto" });
},
/** Exposes result loading state without removing the current result list. */
updateSearchLoading(busy) {
busy ? elems.resultList.setAttributes({ "aria-busy": "true" }) : elems.resultList.removeAttributes("aria-busy");
},
/** Switches the EhPeek result list between one and two result columns. */
updateResultColumns(enabled) {
enabled ? elems.resultList.apply("columns") : elems.resultList.removeClasses(sharedApply.searchResultColumns);
},
/** Prevents result content from stealing a horizontal swipe gesture. */
ensureSearchSwipeInput() {
elems.resultList.apply("swipe");
},
/** Applies new-tab semantics at activation time so replaced result pages need no rebinding. */
listenGalleryLinksOpenInNewTab: () => resultHost ? listenGalleryLinksOpenInNewTab(resultHost) : () => {
},
/** Reports rows appended by third-party infinite-scroll integrations. */
listenResultRowsAdded(callback) {
let observer = new MutationObserver((records) => {
records.some((record) => Array.from(record.addedNodes).some((node) => node instanceof HTMLTableRowElement || node instanceof Element && node.querySelector("tr"))) && callback();
});
return observer.observe(elems.resultList.Component(), {
childList: !0,
subtree: !0
}), () => observer.disconnect();
}
} };
}
function manageSearchTextInput(inputSource) {
let formSource = inputSource?.form() ?? null, submitSource = formSource?.one(domClass.search.submit) ?? inputSource?.parent()?.one(domClass.search.submitFallback) ?? null;
if (!submitSource)
return null;
let elems = {
form: formSource?.inplace() ?? null,
input: inputSource.inplace(),
submit: submitSource.inplace()
};
return { data: { value: elems.input.inputValue() }, elems, handle: {
/** Connects the original input to EhPeek's history and suggestion overlay. */
listenSearchHistoryOverlay(callbacks, overlay) {
let update = () => callbacks.onInput(
elems.input.inputValue(),
document.activeElement === elems.input.Component()
), submitValue = () => callbacks.onSubmit(elems.input.inputValue()), outsidePointer = (event) => {
let target = event.target;
target instanceof Node && (elems.input.isNode(target) || overlay()?.contains(target)) || callbacks.onOutsidePointer();
}, disconnect = [
elems.input.listen("input", update),
elems.input.listen("focus", callbacks.onFocus),
elems.input.listen("pointerdown", callbacks.onFocus),
elems.input.listen("keydown", callbacks.onKeyDown),
elems.submit.listen("click", submitValue),
...elems.form ? [elems.form.listen("submit", submitValue)] : []
];
return document.addEventListener("pointerdown", outsidePointer, !0), window.addEventListener("resize", callbacks.onPositionChange), () => {
disconnect.forEach((cleanup) => cleanup()), document.removeEventListener("pointerdown", outsidePointer, !0), window.removeEventListener("resize", callbacks.onPositionChange);
};
},
/** Locates the overlay directly below the original search input. */
readSearchOverlayPosition() {
let rect = elems.input.rect();
return {
left: rect.left + window.scrollX,
top: rect.bottom + window.scrollY,
width: rect.width
};
},
/** Commits a history or suggestion choice through the original input events. */
applySearchSelection(value) {
elems.input.setInputValue(value), elems.input.dispatchInput(), elems.input.focus(), elems.input.Component().setSelectionRange(value.length, value.length);
}
} };
}
function observeSearchBar(onManaged) {
return DomNode.from(document).observe(
domClass.search.panel.box,
(searchBar) => {
let input2 = searchBar.one(domClass.search.input);
if (!input2)
return;
let source = manageSearchTextInput(input2);
if (source)
return onManaged(source);
}
);
}
function manageReadHistoryGrids(options) {
let resultList = createManagedElement("table").replaceClasses("itg"), body = createManagedElement("tbody"), visibleRows = [];
resultList.append(body).addClasses(
"overscroll-x-contain",
"touch-pan-y",
"[&[data-dragging=true]]:select-none"
), options.source.inplace().replaceWith(resultList);
let updateItems = (items) => {
visibleRows = items.map((item) => ({
item,
row: createReadHistoryGridRow(item, options.titlePreference)
})), body.replaceChildren(...visibleRows.map(({ row: row2 }) => row2.row)), manageEhPeekGrid(
resultList,
visibleRows.map(({ row: row2 }) => row2),
options.mode
);
};
return updateItems(options.items), {
elems: { resultList },
handle: {
updateItems,
listenForItemRemoval(callback) {
let itemForTarget = (target) => target instanceof Node ? visibleRows.find(({ row: row2 }) => row2.row.contains(target))?.item ?? null : null;
return resultList.listen("click", (event) => {
let item = (event.target instanceof Element ? DomNode.from(event.target).closest(domClass.search.removeHistory) : null) ? itemForTarget(event.target) : null;
item && (event.preventDefault(), event.stopPropagation(), callback(item));
});
}
}
};
}
function manageSearchGrids(mode) {
let managedAttribute = "data-ehpeek-search-grid-managed", source = DomNode.from(document).use(domClass.search), resultList = source.results.one();
if (!resultList)
return;
let rows = source.results.rows.all().map(manageSearchGridRow).filter((row2) => row2 !== null);
manageEhPeekGrid(
resultList.inplace(),
rows,
mode
);
function manageSearchGridRow(row2) {
if (row2.hasAttribute(managedAttribute))
return null;
let thumbnailCell = row2.one(domClass.search.results.rows.cover), contentCell = row2.one(domClass.search.results.rows.content), detail = contentCell?.one(domClass.search.results.rows.content.detail), metadata = contentCell?.one(domClass.search.results.rows.content.metadata);
if (!thumbnailCell || !contentCell || !detail || !metadata)
return null;
let title = detail.one(domClass.search.results.rows.content.detail.title), parent = detail.parent(), galleryLink = parent?.matches(domClass.common.links) ? parent : null, tags = detail.children().filter((element) => !title?.sameNode(element)), coverImage = thumbnailCell.one(domClass.common.image), metadataItems = metadata.children(), category = metadataItems.find((item) => item.matches(':is(.cn, .cs, [class*="ct"])')), posted = metadataItems.find((item) => item.matches('[id^="posted_"]')), rating = metadataItems.find((item) => item.matches(".ir")), uploader = metadataItems.find((item) => item.one('a[href*="/uploader/"]') !== null), download = metadataItems.find((item) => item.matches(".gldown")), pages = download?.previous(), knownMetadata = [category, posted, rating, uploader, pages, download], extraMetadata = metadataItems.filter((item) => !knownMetadata.some((known) => known?.sameNode(item))), metadataFields = [
[category, "ehpeek-search-meta-category"],
[pages, "ehpeek-search-meta-pages"],
[posted, "ehpeek-search-meta-posted"],
[rating, "ehpeek-search-meta-rating"],
[uploader, "ehpeek-search-meta-uploader"],
[download, "ehpeek-search-meta-download"]
];
for (let [field, className2] of metadataFields)
field?.inplace().addClasses(className2);
for (let field of extraMetadata)
field.inplace().addClasses("ehpeek-search-meta-extra");
let managedRow = row2.inplace();
return managedRow.attribute(managedAttribute, "true"), {
coverImage: coverImage?.inplace() ?? null,
detail: detail.inplace(),
galleryHref: galleryLink?.attribute("href") ?? null,
galleryLink: galleryLink?.inplace() ?? null,
metadata: metadata.inplace(),
originalGalleryLink: !0,
row: managedRow,
stackTags: !0,
tags: tags.map((item) => item.inplace()),
title: title?.inplace() ?? null,
titleText: title?.text() ?? "",
withoutCover: !1
};
}
}
function manageEhPeekGrid(resultList, rows, mode = "ehpeek") {
let liteTagPrefixes = {
female: "f",
male: "m",
mixed: "x"
};
resultList.addClasses(sharedApply.searchGrid), DomNode.from(resultList.Component()).parent()?.inplace().addClasses("[container-type:inline-size]"), mode === "ehpeek-lite" && resultList.addClasses(sharedApply.liteSearchGrid);
for (let row2 of rows)
row2.row.addClasses(
...row2.withoutCover ? [sharedApply.coverlessSearchGrid] : []
), manageSearchGridCover(row2), manageEhPeekGridContent(row2);
function manageSearchGridCover(source) {
if (!source.coverImage)
return;
let update = () => {
let size = source.coverImage?.imageSize();
!!(size && size.width > 0 && size.height / size.width > 4) ? source.row.addClasses(sharedApply.tallSearchGridCover) : source.row.removeClasses(sharedApply.tallSearchGridCover);
};
update(), source.coverImage.listen("load", update, { once: !0 });
}
function manageEhPeekGridContent(source) {
let { detail, galleryLink, metadata, row: row2, tags, title } = source;
if (galleryLink && title && source.galleryHref) {
let titleLink = createManagedElement("a").attribute("href", source.galleryHref).replaceClasses("block min-w-0 ehp-color-site-text no-underline");
titleLink.append(title), galleryLink.before(detail), source.originalGalleryLink ? galleryLink.hideOriginal() : galleryLink.remove(), detail.replaceChildren(titleLink, metadata, ...tags), ensureEhPeekGridRowNavigation(
row2,
titleLink,
source.galleryHref,
source.titleText
);
} else title && title.after(metadata);
if (source.stackTags)
for (let tag2 of tags)
tag2.addClasses(sharedApply.stackSearchGridTags), mode === "ehpeek-lite" && markLiteSearchTags(tag2);
}
function markLiteSearchTags(container) {
for (let tag2 of container.all(
':is(.gt, .gtl, .gtw)[title*=":"]'
)) {
let namespace = tag2.readAttribute("title")?.split(":", 1)[0]?.trim(), prefix = namespace ? liteTagPrefixes[namespace.toLowerCase()] : null;
prefix && tag2.attribute("data-ehpeek-lite-prefix", prefix);
}
}
function ensureEhPeekGridRowNavigation(row2, galleryLink, galleryHref, title) {
row2.attribute("data-ehpeek-pressable", "true");
let overlay = createManagedElement("a", {
cover: "ehpeek-cover-search-grid-row"
}).attribute("href", galleryHref).attribute("aria-label", title || "Open gallery").replaceClasses("hidden search-panel-compact:block absolute inset-0 z-1").apply("cover");
row2.append(overlay).listen("click", (event) => {
(event.target instanceof Element ? DomNode.from(event.target) : null)?.closest(domClass.common.interactive) || galleryLink.click();
});
}
}
function mutateSearchReadHistoryAppearance(readProgressForGallery) {
let resultList = DomNode.from(document).use(domClass.search).results.one();
if (!resultList)
return;
let items = (resultList.one(domClass.search.results.body) ?? resultList).children();
for (let item of items) {
let galleryLinks = item.all(domClass.search.results.galleryLinks), galleryLink = galleryLinks.find((link) => !!link.text()) ?? galleryLinks[0];
if (!galleryLink)
continue;
let identity = galleryIdentityFromUrl(galleryLink.attribute("href") ?? "");
if (!identity)
continue;
let progress = readProgressForGallery(identity.galleryId, identity.token);
if (!progress)
continue;
(item.one(domClass.search.results.titles) ?? galleryLink).inplace(domClass.search.results.titles.apply).setAttributes({
"data-ehpeek-history-label": progress.pageNum > 0 ? `${progress.pageNum} / ${progress.totalPages ?? "?"}` : activeTexts.history.visitedLabel
}).apply("history"), item.inplace().setAttributes({
"data-ehpeek-read-history": progress.pageNum > 0 ? "reading" : "visited"
});
}
}
function mutateSearchGridModeSelect(selected, onEhPeekSelect, onOriginalSelect) {
let selects = DomNode.from(document).use(domClass.search).displayMode.all();
for (let source of selects) {
let select2 = source.inplace();
for (let { label, value } of [
{ label: "EhPeek", value: "ehpeek" },
{ label: "EhPeekLite", value: "ehpeek-lite" }
]) {
let option2 = source.all(domClass.search.displayMode.options).find((item) => item.inputValue() === value)?.inplace() ?? null;
option2 || (option2 = createManagedElement("option").attribute("value", value), option2.setTextUnlessInput(label), select2.append(option2)), option2.setSelected(selected === value);
}
source.attribute("data-ehpeek-grid-mode") !== "true" && (select2.attribute("data-ehpeek-grid-mode", "true"), select2.listen("change", (event) => {
let value = select2.inputValue();
if (value !== "ehpeek" && value !== "ehpeek-lite") {
onOriginalSelect();
return;
}
event.preventDefault(), event.stopImmediatePropagation(), onEhPeekSelect(value);
}, !0));
}
}
function replaceSearchPageContent(doc) {
let currentList = DomNode.from(document).use(domClass.search).results.one(), incomingList = DomNode.from(doc).use(domClass.search).results.one();
if (!currentList || !incomingList || !refreshSearchRangeBar(doc))
return !1;
replaceSearchResultText(doc), replaceSearchNavigationBars(doc);
let current = currentList.inplace(), importedList = incomingList.clone();
return current.replaceWith(importedList), !0;
}
function refreshSearchRangeBar(doc) {
let current = DomNode.from(document).use(domClass.search).rangeBar.one(), incomingPage = DomNode.from(doc), incoming = incomingPage.use(domClass.search).rangeBar.one();
if (!current && !incoming)
return !0;
if (!current || !incoming)
return !1;
let script2 = incomingPage.all(domClass.common.scripts).map((item) => item.text()).find((item) => item.includes("build_rangebar()")), rangeUrl = script2?.match(/\brangeurl\s*=\s*["']([^"']*)["']/)?.[1], rangeMin = Number(script2?.match(/\brangemin\s*=\s*(-?\d+)/)?.[1]), rangeMax = Number(script2?.match(/\brangemax\s*=\s*(-?\d+)/)?.[1]), rangeSpan = Number(script2?.match(/\brangespan\s*=\s*(-?\d+)/)?.[1]);
if (rangeUrl === void 0 || !Number.isFinite(rangeMin) || !Number.isFinite(rangeMax) || !Number.isFinite(rangeSpan))
return !1;
let items = [];
if (rangeSpan > 0)
for (let index = 0; index < 99; index += rangeSpan) {
let marker = createManagedElement("div");
if ((index === 98 && rangeMin === 99 || index >= rangeMin && index <= rangeMax) && marker.attribute("data-inrange", "1"), !rangeUrl) {
items.push(marker);
continue;
}
let href = index === 0 ? rangeUrl : `${rangeUrl}${rangeUrl.includes("?") ? "&" : "?"}range=${index}`;
items.push(createManagedElement("a").attribute("href", href).append(marker));
}
return current.inplace().replaceChildren(...items), !0;
}
function replaceSearchNavigationBars(doc) {
let currentBars = DomNode.from(document).use(domClass.search).navigation.all(), incomingBars = DomNode.from(doc).use(domClass.search).navigation.all(), count = Math.min(currentBars.length, incomingBars.length);
for (let index = 0; index < count; index += 1) {
let currentSource = currentBars[index], incomingSource = incomingBars[index];
if (!currentSource || !incomingSource)
continue;
let current = currentSource.inplace(), incoming = incomingSource.clone();
current.replaceWith(incoming);
}
}
function replaceSearchResultText(doc) {
let current = DomNode.from(document).use(domClass.search).resultText.one(), incoming = DomNode.from(doc).use(domClass.search).resultText.one();
if (!current || !incoming)
return;
let currentElement = current.inplace(), incomingElement = incoming.clone();
currentElement.replaceWith(incomingElement);
}
function favoritesPageTouch(fitToViewport) {
let page2 = DomNode.from(document), pageSource = page2.use(domClass.page), source = page2.use(domClass.search);
fitToViewport && pageSource.html.inplace()?.apply("fitToViewport");
let categories = source.favorites.categories.one(), categorySelect = categories ? manageFavoritesCategories(categories) : null, searchHostApply = { expand: "ehpeek-expand-favorites-search" };
source.favorites.input.one()?.form()?.parent()?.inplace(searchHostApply).apply("expand");
let resultSource = source.results.one();
if (!resultSource)
return categorySelect;
let allSelected = categorySelect?.info.categories[0]?.selected === !0, resultList = resultSource.inplace(domClass.search.results.apply).apply("containFavorites");
return allSelected && resultList.apply("compactFavorites"), categorySelect;
}
function manageFavoritesCategories(container) {
let nodes = container.all(domClass.search.favorites.categories.items);
if (nodes.length === 0)
return null;
let parsed = nodes.map((node) => {
let children2 = node.children(), countText = children2[0]?.text() ?? "0", label = children2[children2.length - 1]?.text() || node.text(), count = Number(countText.replace(/,/g, "")), indicatorStyle = node.one(domClass.search.favorites.categories.items.indicator)?.computedStyle() ?? null;
return {
appearance: indicatorStyle ? {
backgroundImage: indicatorStyle.backgroundImage,
backgroundPosition: indicatorStyle.backgroundPosition,
backgroundSize: indicatorStyle.backgroundSize
} : null,
count: Number.isFinite(count) ? count : 0,
label,
selected: node.matches(domClass.search.favorites.selectedCategory),
source: node
};
}), all = parsed.find((category) => category.source.childElementCount() === 0), favorites = parsed.filter((category) => category !== all), total = favorites.reduce((sum, category) => sum + category.count, 0);
container.inplace(domClass.search.favorites.categories.apply).apply("hide");
let categories = [
...all ? [{ ...all, count: total }] : [],
...favorites
];
return {
info: {
categories: categories.map(({ appearance, count, label, selected }) => ({
appearance,
count,
label,
selected
}))
},
items: categories.map(({ source }) => source.inplace())
};
}
function searchResultsPageTouch(fitToViewport) {
let page2 = DomNode.from(document), pageSource = page2.use(domClass.page), source = page2.use(domClass.search);
fitToViewport && pageSource.html.inplace()?.apply("fitToViewport");
let resultSource = source.results.one();
resultSource && resultSource.inplace(domClass.search.results.apply).apply("containSearch");
}
function manageTouchResultsPage(page2, fitToViewport) {
let apply = () => page2.type === "favorites" ? favoritesPageTouch(fitToViewport) : ((page2.type === "search" || page2.type === "readHistory") && searchResultsPageTouch(fitToViewport), null), favoritesCategory = apply(), data = { favoritesCategory: favoritesCategory?.info ?? null }, elems = {
favoriteCategoryItems: favoritesCategory?.items ?? []
};
return { data, elems, handle: {
/** Activates E-H's original Favorites collection control. */
activateFavoriteCategory(index) {
elems.favoriteCategoryItems[index]?.click();
},
/** Reapplies TouchUI layout after the result list is replaced in place. */
updateTouchResultsLayout() {
let updated = apply();
updated && elems.favoriteCategoryItems.splice(
0,
elems.favoriteCategoryItems.length,
...updated.items
);
}
} };
}
var init_search = __esm({
"src/eh/dom/search.ts"() {
"use strict";
init_i18n2();
init_url();
init_request();
init_core();
init_domClass();
}
});
// src/eh/dom/searchPanel.ts
function manageSearchPanel() {
let search2 = DomNode.from(document).use(domClass.search), source = search2.panel, searchInput = search2.input.one(), form2 = searchInput?.form() ?? null, standardSearchBox = source.box.one(), categories = source.box.categories.one(), advancedPanel = source.box.advanced.one(), optionLinks = advancedPanel?.previous() ?? null, fileSearch = source.fileSearch.one(), searchSubmit = form2?.one(domClass.search.submit) ?? searchInput?.parent()?.one(domClass.search.submitFallback) ?? null, clearButton = form2?.one(domClass.search.panel.clear) ?? searchInput?.parent()?.one(domClass.search.panel.clearFallback) ?? null;
if (!searchInput || !form2 || !searchSubmit)
return null;
let mount = createAnchor("search-panel"), categoryToggleMount = categories && optionLinks ? createAnchor("search-category-toggle") : null, searchActionMount = createAnchor("search-action"), clearActionMount = clearButton ? createAnchor("search-clear-action") : null;
if (!mount || !searchActionMount || clearButton && !clearActionMount)
return null;
let optionLinkItems = optionLinks?.all(domClass.search.panel.optionLinks) ?? [], advancedToggle = advancedPanel ? optionLinkItems[0] ?? null : null, fileSearchToggle = fileSearch ? optionLinkItems[advancedToggle ? 1 : 0] ?? null : null, advancedToggleMount = advancedToggle ? createAnchor("search-advanced-toggle") : null, fileSearchToggleMount = fileSearchToggle ? createAnchor("search-file-toggle") : null, searchControls = createManagedElement("div", {
overlay: "ehpeek-overlay-search-actions"
}).apply("overlay");
searchSubmit.inplace(domClass.search.panel.submit.apply).apply("hide");
let optionLinksApply = { wrap: "ehpeek-wrap-search-options" }, elems = {
advancedPanel: source.box.advanced.inplace()?.apply("expand") ?? null,
advancedToggle: advancedToggle?.inplace() ?? null,
advancedToggleMount,
categories: source.box.categories.inplace()?.apply("layout") ?? null,
categoryToggleMount,
clearActionMount,
clearButton: clearButton?.inplace(domClass.search.panel.clear.apply).apply("hide") ?? null,
fileSearch: source.fileSearch.inplace()?.apply("expand") ?? null,
fileSearchToggle: fileSearchToggle?.inplace() ?? null,
fileSearchToggleMount,
form: form2.inplace(domClass.search.panel.box.form.apply),
mount,
optionLinks: optionLinks?.inplace(optionLinksApply).apply("wrap") ?? null,
searchActionMount,
searchBox: source.box.inplace()?.apply("reset") ?? searchControls,
searchControls,
searchInput: searchInput.inplace(domClass.search.input.apply).apply("expand")
};
(standardSearchBox ? elems.searchBox : elems.form).before(elems.mount), elems.searchInput.replaceWith(elems.searchControls), elems.searchControls.append(elems.searchInput), elems.clearButton && elems.clearActionMount && (elems.clearButton.hideOriginal(), elems.searchControls.append(elems.clearActionMount)), elems.searchControls.append(elems.searchActionMount), elems.categories && elems.optionLinks && elems.categoryToggleMount && (elems.optionLinks.after(elems.categories), elems.optionLinks.prepend(elems.categoryToggleMount)), elems.optionLinks && elems.advancedToggle && elems.advancedToggleMount && (elems.advancedToggle.after(elems.advancedToggleMount), elems.advancedToggle.hideOriginal()), elems.optionLinks && elems.fileSearchToggle && elems.fileSearchToggleMount && (elems.fileSearchToggle.after(elems.fileSearchToggleMount), elems.fileSearchToggle.hideOriginal());
let formInsideSearchBox = source.box.form.one()?.sameNode(form2) ?? !1, formId = form2.attribute("id") || "ehpeek-search-form", data = {
clearLabel: clearButton ? actionLabel(clearButton) : null,
hasClear: elems.clearButton !== null && elems.clearActionMount !== null,
searchLabel: actionLabel(searchSubmit)
};
elems.searchActionMount.addClasses("contents"), elems.clearActionMount?.addClasses("contents"), elems.form.apply("stack"), elems.searchControls.setAttributes({ "data-ehpeek-has-clear": String(data.hasClear) }), elems.categories?.setAttributes({ "aria-hidden": "true" });
let handle = {
/** Controls the original category table from EhPeek's category toggle. */
updateCategoryVisibility(open) {
elems.categories?.setAttributes({ "aria-hidden": String(!open) });
},
/** Activates the live Search submit control in case another script replaced it. */
activateSearch() {
elems.form.all(
`.${domClass.search.panel.submit.apply.hide}[type="submit"]`
)[0]?.click();
},
/** Clears only the Search text without invoking E-H's page-navigation reset. */
clearSearchText() {
elems.searchInput.setInputValue(""), elems.searchInput.dispatchInput(), elems.searchInput.focus();
},
toggleAdvancedOptions() {
elems.advancedToggle?.click();
},
toggleFileSearch() {
elems.fileSearchToggle?.click();
}
};
return formInsideSearchBox || (elems.form.setAttributes({ id: formId }), elems.searchInput.setAttributes({ form: formId }), elems.clearButton?.setAttributes({ form: formId })), { data, elems, handle };
}
function actionLabel(element) {
return element.attribute("value") ?? element.text();
}
var init_searchPanel = __esm({
"src/eh/dom/searchPanel.ts"() {
"use strict";
init_core();
init_domClass();
}
});
// src/eh/dom/settings.ts
function extractGalleryTitlePreference() {
let source = DomNode.from(document).use(domClass.settings), japaneseTitle = source.titleJapanese.one(), defaultTitle = source.titleDefault.one();
return japaneseTitle?.checked() ? "sub" : defaultTitle?.checked() ? "main" : null;
}
var init_settings = __esm({
"src/eh/dom/settings.ts"() {
"use strict";
init_core();
init_domClass();
}
});
// src/eh/dom/topBar.ts
function manageSettingsMenuMount() {
let page2 = DomNode.from(document), source = page2.use(domClass.topBar), thumbnailContainer = page2.use(domClass.gallery).preview.thumbs.one(), titleContainer = source.galleryTitle.one(), topNav = source.navigation.one(), anchor2 = thumbnailContainer ?? titleContainer;
if (topNav) {
let item2 = createManagedElement("div");
return topNav.inplace().append(item2), item2;
}
if (!anchor2?.parent())
return null;
let item = createManagedElement("div").replaceClasses("text-right"), managedAnchor = anchor2.inplace();
return thumbnailContainer ? managedAnchor.before(item) : managedAnchor.after(item), item;
}
function manageTopBar() {
let mount = createAnchor("top-bar");
if (!mount)
return null;
let source = DomNode.from(document).use(domClass.topBar), original = source.navigation.one(), links = source.navigation.links.all();
if (!original || links.length === 0)
return null;
let data = {
favoritesHref: new URL("/favorites.php", window.location.href).href,
homeHref: links[0]?.attribute("href") ?? "/"
}, elems = {
mount
}, originalNavigation = original.inplace(domClass.topBar.navigation.apply).apply("hide").setAttributes({ "aria-hidden": "true" }), navigationTargets = [];
return originalNavigation.before(elems.mount), {
data,
elems,
handle: {
/** Reads the live original navigation only when TouchUI opens its menu. */
readNavigationItems() {
let current = source.navigation.links.requery();
return navigationTargets = current.map((link) => link.inplace()), current.map((link, index) => ({
href: link.attribute("href") ?? "#",
index,
label: link.text(),
target: link.attribute("target")
}));
},
/** Delegates activation to the retained original node, including third-party handlers. */
activateNavigationItem(index) {
navigationTargets[index]?.click();
}
}
};
}
var init_topBar = __esm({
"src/eh/dom/topBar.ts"() {
"use strict";
init_core();
init_domClass();
}
});
// src/eh/dom/index.ts
var init_dom = __esm({
"src/eh/dom/index.ts"() {
"use strict";
init_core();
init_domClass();
init_external();
init_galleryInfo();
init_gallery();
init_search();
init_searchPanel();
init_settings();
init_topBar();
}
});
// src/eh/types.ts
var init_types = __esm({
"src/eh/types.ts"() {
"use strict";
}
});
// src/eh/index.ts
var init_eh = __esm({
"src/eh/index.ts"() {
"use strict";
init_url();
init_request();
init_dom();
init_types();
}
});
// ../reader/dist/chunk-4EQKK5DW.js
function Popover(props) {
let [local2, rest] = splitProps(props, ["class", "classList", "onOutsidePress", "outsideEvent", "contains"]), panel;
return onMount(() => {
let stop = listenForOutsidePress({
document: panel.ownerDocument,
contains: (target) => local2.contains ? local2.contains(target) : panel.contains(target),
event: local2.outsideEvent ?? "click",
onOutsidePress: (event) => local2.onOutsidePress(event)
});
onCleanup(stop);
}), (() => {
var _el$ = _tmpl$(), _ref$ = panel;
return typeof _ref$ == "function" ? use(_ref$, _el$) : panel = _el$, spread(_el$, mergeProps(rest, {
get class() {
return widgetClass("ehpeek-popover", local2);
}
}), !1, !1), _el$;
})();
}
var _tmpl$, init_chunk_4EQKK5DW = __esm({
"../reader/dist/chunk-4EQKK5DW.js"() {
"use strict";
init_chunk_E6UKP7HT();
init_web();
init_web();
init_web();
init_web();
init_solid();
_tmpl$ = /* @__PURE__ */ template("<div>");
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/defaultAttributes.mjs
var defaultAttributes, init_defaultAttributes = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/defaultAttributes.mjs"() {
defaultAttributes = {
xmlns: "http://www.w3.org/2000/svg",
width: 24,
height: 24,
viewBox: "0 0 24 24",
fill: "none",
stroke: "currentColor",
"stroke-width": 2,
"stroke-linecap": "round",
"stroke-linejoin": "round"
};
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/context.mjs
var LucideContext, init_context = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/context.mjs"() {
init_solid();
LucideContext = createContext({
size: 24,
color: "currentColor",
strokeWidth: 2,
absoluteStrokeWidth: !1,
class: ""
});
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/shared/src/utils/hasA11yProp.mjs
var hasA11yProp, init_hasA11yProp = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/shared/src/utils/hasA11yProp.mjs"() {
hasA11yProp = (props) => {
for (let prop in props)
if (prop.startsWith("aria-") || prop === "role" || prop === "title")
return !0;
return !1;
};
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/shared/src/utils/mergeClasses.mjs
var mergeClasses, init_mergeClasses = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/shared/src/utils/mergeClasses.mjs"() {
mergeClasses = (...classes) => classes.filter((className2, index, array) => !!className2 && className2.trim() !== "" && array.indexOf(className2) === index).join(" ").trim();
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/shared/src/utils/toKebabCase.mjs
var toKebabCase, init_toKebabCase = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/shared/src/utils/toKebabCase.mjs"() {
toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/shared/src/utils/toCamelCase.mjs
var toCamelCase, init_toCamelCase = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/shared/src/utils/toCamelCase.mjs"() {
toCamelCase = (string) => string.replace(/^([A-Z])|[\s-_]+(\w)/g, (match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase());
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/shared/src/utils/toPascalCase.mjs
var toPascalCase, init_toPascalCase = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/shared/src/utils/toPascalCase.mjs"() {
init_toCamelCase();
toPascalCase = (string) => {
let camelCase = toCamelCase(string);
return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
};
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/Icon.mjs
var _tmpl$2, Icon, init_Icon = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/Icon.mjs"() {
init_web();
init_solid();
init_defaultAttributes();
init_context();
init_hasA11yProp();
init_mergeClasses();
init_toKebabCase();
init_toPascalCase();
_tmpl$2 = /* @__PURE__ */ template("<svg>"), Icon = (props) => {
let [localProps, rest] = splitProps(props, ["color", "size", "strokeWidth", "children", "class", "name", "iconNode", "absoluteStrokeWidth"]), globalProps = useContext(LucideContext);
return (() => {
var _el$ = _tmpl$2();
return spread(_el$, mergeProps(defaultAttributes, {
get width() {
return localProps.size ?? globalProps.size ?? defaultAttributes.width;
},
get height() {
return localProps.size ?? globalProps.size ?? defaultAttributes.height;
},
get stroke() {
return localProps.color ?? globalProps.color ?? defaultAttributes.stroke;
},
get "stroke-width"() {
return memo(() => (localProps.absoluteStrokeWidth ?? globalProps.absoluteStrokeWidth) === !0)() ? Number(localProps.strokeWidth ?? globalProps.strokeWidth ?? defaultAttributes["stroke-width"]) * 24 / Number(localProps.size ?? globalProps.size) : Number(localProps.strokeWidth ?? globalProps.strokeWidth ?? defaultAttributes["stroke-width"]);
},
get class() {
return mergeClasses("lucide", "lucide-icon", globalProps.class, ...localProps.name != null ? [`lucide-${toKebabCase(toPascalCase(localProps.name))}`, `lucide-${toKebabCase(localProps.name)}`] : [], localProps.class);
},
get "aria-hidden"() {
return !localProps.children && !hasA11yProp(rest) ? "true" : void 0;
}
}, rest), !0, !0), insert(_el$, createComponent(For, {
get each() {
return localProps.iconNode;
},
children: ([elementName, attrs]) => createComponent(Dynamic, mergeProps({
component: elementName
}, attrs))
})), _el$;
})();
};
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/arrow-down.mjs
var iconNode, ArrowDown, init_arrow_down = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/arrow-down.mjs"() {
init_web();
init_Icon();
iconNode = [["path", {
d: "M12 5v14",
key: "s699le"
}], ["path", {
d: "m19 12-7 7-7-7",
key: "1idqje"
}]], ArrowDown = (props) => createComponent(Icon, mergeProps(props, {
iconNode,
name: "arrow-down"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/arrow-left.mjs
var iconNode2, ArrowLeft, init_arrow_left = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/arrow-left.mjs"() {
init_web();
init_Icon();
iconNode2 = [["path", {
d: "m12 19-7-7 7-7",
key: "1l729n"
}], ["path", {
d: "M19 12H5",
key: "x3x0zl"
}]], ArrowLeft = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode2,
name: "arrow-left"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/arrow-right.mjs
var iconNode3, ArrowRight, init_arrow_right = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/arrow-right.mjs"() {
init_web();
init_Icon();
iconNode3 = [["path", {
d: "M5 12h14",
key: "1ays0h"
}], ["path", {
d: "m12 5 7 7-7 7",
key: "xquz4c"
}]], ArrowRight = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode3,
name: "arrow-right"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/arrow-up.mjs
var iconNode4, ArrowUp, init_arrow_up = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/arrow-up.mjs"() {
init_web();
init_Icon();
iconNode4 = [["path", {
d: "m5 12 7-7 7 7",
key: "hav0vg"
}], ["path", {
d: "M12 19V5",
key: "x0mq9r"
}]], ArrowUp = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode4,
name: "arrow-up"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/book-open.mjs
var iconNode5, BookOpen, init_book_open = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/book-open.mjs"() {
init_web();
init_Icon();
iconNode5 = [["path", {
d: "M12 5v16",
key: "1f6ucr"
}], ["path", {
d: "M20.001 19A2 2 0 0022 17V5a2 2 0 00-1.999-2L16 3.002A5 5 0 0012 5a5 5 0 00-4-2H4a2 2 0 00-2 2v12a2 2 0 001.999 2H8a5 5 0 014 2 5 5 0 014-2z",
key: "1fyvmf"
}]], BookOpen = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode5,
name: "book-open"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/check.mjs
var iconNode6, Check, init_check = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/check.mjs"() {
init_web();
init_Icon();
iconNode6 = [["path", {
d: "M20 6 9 17l-5-5",
key: "1gmf2c"
}]], Check = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode6,
name: "check"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/chevron-left.mjs
var iconNode7, ChevronLeft, init_chevron_left = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/chevron-left.mjs"() {
init_web();
init_Icon();
iconNode7 = [["path", {
d: "m15 18-6-6 6-6",
key: "1wnfg3"
}]], ChevronLeft = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode7,
name: "chevron-left"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/chevron-right.mjs
var iconNode8, ChevronRight, init_chevron_right = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/chevron-right.mjs"() {
init_web();
init_Icon();
iconNode8 = [["path", {
d: "m9 18 6-6-6-6",
key: "mthhwq"
}]], ChevronRight = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode8,
name: "chevron-right"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/columns-2.mjs
var iconNode9, Columns2, init_columns_2 = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/columns-2.mjs"() {
init_web();
init_Icon();
iconNode9 = [["rect", {
width: "18",
height: "18",
x: "3",
y: "3",
rx: "2",
key: "afitv7"
}], ["path", {
d: "M12 3v18",
key: "108xh3"
}]], Columns2 = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode9,
name: "columns-2"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/copy.mjs
var iconNode10, Copy, init_copy = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/copy.mjs"() {
init_web();
init_Icon();
iconNode10 = [["rect", {
width: "14",
height: "14",
x: "8",
y: "8",
rx: "2",
ry: "2",
key: "17jyea"
}], ["path", {
d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",
key: "zix9uf"
}]], Copy = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode10,
name: "copy"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/download.mjs
var iconNode11, Download, init_download = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/download.mjs"() {
init_web();
init_Icon();
iconNode11 = [["path", {
d: "M12 15V3",
key: "m9g1x1"
}], ["path", {
d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",
key: "ih7n3h"
}], ["path", {
d: "m7 10 5 5 5-5",
key: "brsn70"
}]], Download = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode11,
name: "download"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/ellipsis-vertical.mjs
var iconNode12, EllipsisVertical, init_ellipsis_vertical = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/ellipsis-vertical.mjs"() {
init_web();
init_Icon();
iconNode12 = [["circle", {
cx: "12",
cy: "12",
r: "1",
key: "41hilf"
}], ["circle", {
cx: "12",
cy: "5",
r: "1",
key: "gxeob9"
}], ["circle", {
cx: "12",
cy: "19",
r: "1",
key: "lyex9k"
}]], EllipsisVertical = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode12,
name: "ellipsis-vertical"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/external-link.mjs
var iconNode13, ExternalLink, init_external_link = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/external-link.mjs"() {
init_web();
init_Icon();
iconNode13 = [["path", {
d: "M15 3h6v6",
key: "1q9fwt"
}], ["path", {
d: "M10 14 21 3",
key: "gplh6r"
}], ["path", {
d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",
key: "a6xqqp"
}]], ExternalLink = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode13,
name: "external-link"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/file.mjs
var iconNode14, File, init_file = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/file.mjs"() {
init_web();
init_Icon();
iconNode14 = [["path", {
d: "M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",
key: "1oefj6"
}], ["path", {
d: "M14 2v5a1 1 0 0 0 1 1h5",
key: "wfsgrz"
}]], File = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode14,
name: "file"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/grid-2x2.mjs
var iconNode15, Grid2x2, init_grid_2x2 = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/grid-2x2.mjs"() {
init_web();
init_Icon();
iconNode15 = [["path", {
d: "M12 3v18",
key: "108xh3"
}], ["path", {
d: "M3 12h18",
key: "1i2n21"
}], ["rect", {
x: "3",
y: "3",
width: "18",
height: "18",
rx: "2",
key: "h1oib"
}]], Grid2x2 = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode15,
name: "grid-2x2"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/heart.mjs
var iconNode16, Heart, init_heart = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/heart.mjs"() {
init_web();
init_Icon();
iconNode16 = [["path", {
d: "M2 9.5a5.5 5.5 0 0 1 9.591-3.676.56.56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29-1.5 4-3 5.5l-5.492 5.313a2 2 0 0 1-3 .019L5 15c-1.5-1.5-3-3.2-3-5.5",
key: "mvr1a0"
}]], Heart = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode16,
name: "heart"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/history.mjs
var iconNode17, History, init_history = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/history.mjs"() {
init_web();
init_Icon();
iconNode17 = [["path", {
d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",
key: "1357e3"
}], ["path", {
d: "M3 3v5h5",
key: "1xhq8a"
}], ["path", {
d: "M12 7v5l4 2",
key: "1fdv2h"
}]], History = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode17,
name: "history"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/house.mjs
var iconNode18, House, init_house = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/house.mjs"() {
init_web();
init_Icon();
iconNode18 = [["path", {
d: "M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8",
key: "5wwlr5"
}], ["path", {
d: "M3 10a2 2 0 0 1 .709-1.528l7-6a2 2 0 0 1 2.582 0l7 6A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z",
key: "r6nss1"
}]], House = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode18,
name: "house"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/hand.mjs
var iconNode19, Hand, init_hand = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/hand.mjs"() {
init_web();
init_Icon();
iconNode19 = [["path", {
d: "M18 11V6a2 2 0 0 0-2-2a2 2 0 0 0-2 2",
key: "1fvzgz"
}], ["path", {
d: "M14 10V4a2 2 0 0 0-2-2a2 2 0 0 0-2 2v2",
key: "1kc0my"
}], ["path", {
d: "M10 10.5V6a2 2 0 0 0-2-2a2 2 0 0 0-2 2v8",
key: "10h0bg"
}], ["path", {
d: "M18 8a2 2 0 1 1 4 0v6a8 8 0 0 1-8 8h-2c-2.8 0-4.5-.86-5.99-2.34l-3.6-3.6a2 2 0 0 1 2.83-2.82L7 15",
key: "1s1gnw"
}]], Hand = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode19,
name: "hand"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/info.mjs
var iconNode20, Info, init_info = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/info.mjs"() {
init_web();
init_Icon();
iconNode20 = [["circle", {
cx: "12",
cy: "12",
r: "10",
key: "1mglay"
}], ["path", {
d: "M12 16v-4",
key: "1dtifu"
}], ["path", {
d: "M12 8h.01",
key: "e9boi3"
}]], Info = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode20,
name: "info"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/locate-fixed.mjs
var iconNode21, LocateFixed, init_locate_fixed = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/locate-fixed.mjs"() {
init_web();
init_Icon();
iconNode21 = [["line", {
x1: "2",
x2: "5",
y1: "12",
y2: "12",
key: "bvdh0s"
}], ["line", {
x1: "19",
x2: "22",
y1: "12",
y2: "12",
key: "1tbv5k"
}], ["line", {
x1: "12",
x2: "12",
y1: "2",
y2: "5",
key: "11lu5j"
}], ["line", {
x1: "12",
x2: "12",
y1: "19",
y2: "22",
key: "x3vr5v"
}], ["circle", {
cx: "12",
cy: "12",
r: "7",
key: "fim9np"
}], ["circle", {
cx: "12",
cy: "12",
r: "3",
key: "1v7zrd"
}]], LocateFixed = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode21,
name: "locate-fixed"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/maximize.mjs
var iconNode22, Maximize, init_maximize = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/maximize.mjs"() {
init_web();
init_Icon();
iconNode22 = [["path", {
d: "M8 3H5a2 2 0 0 0-2 2v3",
key: "1dcmit"
}], ["path", {
d: "M21 8V5a2 2 0 0 0-2-2h-3",
key: "1e4gt3"
}], ["path", {
d: "M3 16v3a2 2 0 0 0 2 2h3",
key: "wsl5sc"
}], ["path", {
d: "M16 21h3a2 2 0 0 0 2-2v-3",
key: "18trek"
}]], Maximize = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode22,
name: "maximize"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/minimize.mjs
var iconNode23, Minimize, init_minimize = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/minimize.mjs"() {
init_web();
init_Icon();
iconNode23 = [["path", {
d: "M8 3v3a2 2 0 0 1-2 2H3",
key: "hohbtr"
}], ["path", {
d: "M21 8h-3a2 2 0 0 1-2-2V3",
key: "5jw1f3"
}], ["path", {
d: "M3 16h3a2 2 0 0 1 2 2v3",
key: "198tvr"
}], ["path", {
d: "M16 21v-3a2 2 0 0 1 2-2h3",
key: "ph8mxp"
}]], Minimize = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode23,
name: "minimize"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/move-horizontal.mjs
var iconNode24, MoveHorizontal, init_move_horizontal = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/move-horizontal.mjs"() {
init_web();
init_Icon();
iconNode24 = [["path", {
d: "m18 8 4 4-4 4",
key: "1ak13k"
}], ["path", {
d: "M2 12h20",
key: "9i4pu4"
}], ["path", {
d: "m6 8-4 4 4 4",
key: "15zrgr"
}]], MoveHorizontal = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode24,
name: "move-horizontal"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/move-vertical.mjs
var iconNode25, MoveVertical, init_move_vertical = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/move-vertical.mjs"() {
init_web();
init_Icon();
iconNode25 = [["path", {
d: "M12 2v20",
key: "t6zp3m"
}], ["path", {
d: "m8 18 4 4 4-4",
key: "bh5tu3"
}], ["path", {
d: "m8 6 4-4 4 4",
key: "ybng9g"
}]], MoveVertical = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode25,
name: "move-vertical"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/palette.mjs
var iconNode26, Palette, init_palette = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/palette.mjs"() {
init_web();
init_Icon();
iconNode26 = [["path", {
d: "M12 22a1 1 0 0 1 0-20 10 9 0 0 1 10 9 5 5 0 0 1-5 5h-2.25a1.75 1.75 0 0 0-1.4 2.8l.3.4a1.75 1.75 0 0 1-1.4 2.8z",
key: "e79jfc"
}], ["circle", {
cx: "13.5",
cy: "6.5",
r: ".5",
fill: "currentColor",
key: "1okk4w"
}], ["circle", {
cx: "17.5",
cy: "10.5",
r: ".5",
fill: "currentColor",
key: "f64h9f"
}], ["circle", {
cx: "6.5",
cy: "12.5",
r: ".5",
fill: "currentColor",
key: "qy21gx"
}], ["circle", {
cx: "8.5",
cy: "7.5",
r: ".5",
fill: "currentColor",
key: "fotxhn"
}]], Palette = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode26,
name: "palette"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/pencil.mjs
var iconNode27, Pencil, init_pencil = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/pencil.mjs"() {
init_web();
init_Icon();
iconNode27 = [["path", {
d: "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",
key: "1a8usu"
}], ["path", {
d: "m15 5 4 4",
key: "1mk7zo"
}]], Pencil = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode27,
name: "pencil"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/play.mjs
var iconNode28, Play, init_play = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/play.mjs"() {
init_web();
init_Icon();
iconNode28 = [["path", {
d: "M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z",
key: "10ikf1"
}]], Play = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode28,
name: "play"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/refresh-cw.mjs
var iconNode29, RefreshCw, init_refresh_cw = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/refresh-cw.mjs"() {
init_web();
init_Icon();
iconNode29 = [["path", {
d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",
key: "v9h5vc"
}], ["path", {
d: "M21 3v5h-5",
key: "1q7to0"
}], ["path", {
d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",
key: "3uifl3"
}], ["path", {
d: "M8 16H3v5",
key: "1cv678"
}]], RefreshCw = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode29,
name: "refresh-cw"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/rows-3.mjs
var iconNode30, Rows3, init_rows_3 = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/rows-3.mjs"() {
init_web();
init_Icon();
iconNode30 = [["rect", {
width: "18",
height: "18",
x: "3",
y: "3",
rx: "2",
key: "afitv7"
}], ["path", {
d: "M21 9H3",
key: "1338ky"
}], ["path", {
d: "M21 15H3",
key: "9uk58r"
}]], Rows3 = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode30,
name: "rows-3"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/scan-line.mjs
var iconNode31, ScanLine, init_scan_line = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/scan-line.mjs"() {
init_web();
init_Icon();
iconNode31 = [["path", {
d: "M3 7V5a2 2 0 0 1 2-2h2",
key: "aa7l1z"
}], ["path", {
d: "M17 3h2a2 2 0 0 1 2 2v2",
key: "4qcy5o"
}], ["path", {
d: "M21 17v2a2 2 0 0 1-2 2h-2",
key: "6vwrx8"
}], ["path", {
d: "M7 21H5a2 2 0 0 1-2-2v-2",
key: "ioqczr"
}], ["path", {
d: "M7 12h10",
key: "b7w52i"
}]], ScanLine = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode31,
name: "scan-line"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/search.mjs
var iconNode32, Search, init_search2 = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/search.mjs"() {
init_web();
init_Icon();
iconNode32 = [["path", {
d: "m21 21-4.34-4.34",
key: "14j7rj"
}], ["circle", {
cx: "11",
cy: "11",
r: "8",
key: "4ej97u"
}]], Search = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode32,
name: "search"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/settings.mjs
var iconNode33, Settings, init_settings2 = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/settings.mjs"() {
init_web();
init_Icon();
iconNode33 = [["path", {
d: "M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915",
key: "1i5ecw"
}], ["circle", {
cx: "12",
cy: "12",
r: "3",
key: "1v7zrd"
}]], Settings = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode33,
name: "settings"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/sparkles.mjs
var iconNode34, Sparkles, init_sparkles = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/sparkles.mjs"() {
init_web();
init_Icon();
iconNode34 = [["path", {
d: "M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z",
key: "1s2grr"
}], ["path", {
d: "M20 2v4",
key: "1rf3ol"
}], ["path", {
d: "M22 4h-4",
key: "gwowj6"
}], ["circle", {
cx: "4",
cy: "20",
r: "2",
key: "6kqj1y"
}]], Sparkles = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode34,
name: "sparkles"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/star.mjs
var iconNode35, Star, init_star = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/star.mjs"() {
init_web();
init_Icon();
iconNode35 = [["path", {
d: "M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z",
key: "r04s7s"
}]], Star = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode35,
name: "star"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/x.mjs
var iconNode36, X, init_x = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/x.mjs"() {
init_web();
init_Icon();
iconNode36 = [["path", {
d: "M18 6 6 18",
key: "1bl5f8"
}], ["path", {
d: "m6 6 12 12",
key: "d8bk6v"
}]], X = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode36,
name: "x"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/zoom-in.mjs
var iconNode37, ZoomIn, init_zoom_in = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/zoom-in.mjs"() {
init_web();
init_Icon();
iconNode37 = [["circle", {
cx: "11",
cy: "11",
r: "8",
key: "4ej97u"
}], ["line", {
x1: "21",
x2: "16.65",
y1: "21",
y2: "16.65",
key: "13gj7c"
}], ["line", {
x1: "11",
x2: "11",
y1: "8",
y2: "14",
key: "1vmskp"
}], ["line", {
x1: "8",
x2: "14",
y1: "11",
y2: "11",
key: "durymu"
}]], ZoomIn = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode37,
name: "zoom-in"
}));
}
});
// ../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/zoom-out.mjs
var iconNode38, ZoomOut, init_zoom_out = __esm({
"../../node_modules/.pnpm/[email protected][email protected]/node_modules/lucide-solid/dist/esm/icons/zoom-out.mjs"() {
init_web();
init_Icon();
iconNode38 = [["circle", {
cx: "11",
cy: "11",
r: "8",
key: "4ej97u"
}], ["line", {
x1: "21",
x2: "16.65",
y1: "21",
y2: "16.65",
key: "13gj7c"
}], ["line", {
x1: "8",
x2: "14",
y1: "11",
y2: "11",
key: "durymu"
}]], ZoomOut = (props) => createComponent(Icon, mergeProps(props, {
iconNode: iconNode38,
name: "zoom-out"
}));
}
});
// ../reader/dist/chunk-UPVG5Y6S.js
function Icon2(props) {
let component = createMemo(() => props.name === "panda-peek" ? void 0 : LUCIDE_ICONS[props.name]), filled = createMemo(() => props.filled && FILLABLE_ICONS.has(props.name)), size = createMemo(() => typeof props.size == "number" ? `${props.size}px` : props.size ?? "var(--ui-icon-size-md)");
return [createComponent(Dynamic, {
get component() {
return component();
},
class: "ehpeek-icon",
get size() {
return size();
},
get style() {
return {
width: size(),
height: size()
};
},
color: "currentColor",
get fill() {
return filled() ? "currentColor" : "none";
},
get stroke() {
return filled() ? "none" : "currentColor";
},
get strokeWidth() {
return props.strokeWidth ?? 2;
},
get "data-icon-name"() {
return props.name;
}
}), createComponent(Show, {
get when() {
return props.name === "panda-peek";
},
get children() {
return createComponent(PandaPeekIcon, {
get size() {
return size();
},
get strokeWidth() {
return props.strokeWidth ?? 2;
}
});
}
})];
}
function PandaPeekIcon(props) {
return (() => {
var _el$ = _tmpl$3();
return insert(_el$, createComponent(For, {
each: PANDA_FILLED_PATHS,
children: (path) => (() => {
var _el$2 = _tmpl$22();
return setAttribute(_el$2, "d", path), _el$2;
})()
}), null), insert(_el$, createComponent(For, {
each: PANDA_PATHS,
children: (path) => (() => {
var _el$3 = _tmpl$32();
return setAttribute(_el$3, "d", path), _el$3;
})()
}), null), createRenderEffect((_p$) => {
var _v$ = props.size, _v$2 = props.size, _v$3 = props.strokeWidth;
return _v$ !== _p$.e && setStyleProperty(_el$, "width", _p$.e = _v$), _v$2 !== _p$.t && setStyleProperty(_el$, "height", _p$.t = _v$2), _v$3 !== _p$.a && setAttribute(_el$, "stroke-width", _p$.a = _v$3), _p$;
}, {
e: void 0,
t: void 0,
a: void 0
}), _el$;
})();
}
var _tmpl$3, _tmpl$22, _tmpl$32, LUCIDE_ICONS, FILLABLE_ICONS, PANDA_FILLED_PATHS, PANDA_PATHS, init_chunk_UPVG5Y6S = __esm({
"../reader/dist/chunk-UPVG5Y6S.js"() {
"use strict";
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_arrow_down();
init_arrow_left();
init_arrow_right();
init_arrow_up();
init_book_open();
init_check();
init_chevron_left();
init_chevron_right();
init_columns_2();
init_copy();
init_download();
init_ellipsis_vertical();
init_external_link();
init_file();
init_grid_2x2();
init_heart();
init_history();
init_house();
init_hand();
init_info();
init_locate_fixed();
init_maximize();
init_minimize();
init_move_horizontal();
init_move_vertical();
init_palette();
init_pencil();
init_play();
init_refresh_cw();
init_rows_3();
init_scan_line();
init_search2();
init_settings2();
init_sparkles();
init_star();
init_x();
init_zoom_in();
init_zoom_out();
init_solid();
init_web();
_tmpl$3 = /* @__PURE__ */ template('<svg class=ehpeek-icon viewBox="0 0 24 24"fill=none stroke=currentColor stroke-linecap=round stroke-linejoin=round data-icon-name=panda-peek aria-hidden=true>'), _tmpl$22 = /* @__PURE__ */ template("<svg><path fill=currentColor stroke=none></svg>", !1, !0, !1), _tmpl$32 = /* @__PURE__ */ template("<svg><path></svg>", !1, !0, !1);
LUCIDE_ICONS = {
"arrow-left": ArrowLeft,
"arrow-right": ArrowRight,
"arrow-down": ArrowDown,
"arrow-up": ArrowUp,
"arrows-horizontal": MoveHorizontal,
"arrows-vertical": MoveVertical,
"book-open": BookOpen,
check: Check,
"chevron-left": ChevronLeft,
"chevron-right": ChevronRight,
close: X,
copy: Copy,
download: Download,
edit: Pencil,
"external-link": ExternalLink,
fullscreen: Maximize,
"fullscreen-exit": Minimize,
grid: Grid2x2,
hand: Hand,
heart: Heart,
history: History,
home: House,
info: Info,
locate: LocateFixed,
menu: EllipsisVertical,
page: File,
palette: Palette,
pages: Columns2,
play: Play,
refresh: RefreshCw,
search: Search,
settings: Settings,
sparkles: Sparkles,
"scroll-continuous": Rows3,
star: Star,
viewport: ScanLine,
"zoom-in": ZoomIn,
"zoom-out": ZoomOut
}, FILLABLE_ICONS = /* @__PURE__ */ new Set(["heart", "star"]), PANDA_FILLED_PATHS = ["M7.2 3.2a2.4 2.4 0 1 0 0 4.8 2.4 2.4 0 0 0 0-4.8Z", "M16.8 3.2a2.4 2.4 0 1 0 0 4.8 2.4 2.4 0 0 0 0-4.8Z", "M7.6 9.8c.5-1.2 1.6-1.8 2.6-1.3s1.3 1.8.8 3-1.6 1.8-2.6 1.3-1.3-1.8-.8-3Z", "M13.8 8.5c1-.5 2.1.1 2.6 1.3s.2 2.5-.8 3-2.1-.1-2.6-1.3-.2-2.5.8-3Z", "M10.9 13.6c0-.6.5-.9 1.1-.9s1.1.3 1.1.9-.5 1-1.1 1-1.1-.4-1.1-1Z", "M5.2 13.7a2.8 1.9 0 1 0 0 3.8 2.8 1.9 0 0 0 0-3.8Z", "M18.8 14.1a2.8 1.9 0 1 0 0 3.8 2.8 1.9 0 0 0 0-3.8Z"], PANDA_PATHS = ["M5 17c-.8-6.4 2.1-10.8 7-10.8s7.8 4.4 7 10.8", "M12 14.6v.7c0 .7-.6 1.2-1.3 1.2m1.3-1.2c0 .7.6 1.2 1.3 1.2", "M2 17h20"];
}
});
// ../reader/dist/chunk-FLAQB24C.js
function SwipeIndicator(props) {
let progress = createMemo(() => Math.min(1, Math.max(0, props.state.progress))), hidden = createMemo(() => progress() <= HIDE_PROGRESS), pull = createMemo(() => Math.round(48 * progress())), offset = createMemo(() => props.state.direction === "left" ? 42 - pull() : pull() - 42), iconName = createMemo(() => props.state.blocked ? "close" : props.state.direction === "left" ? "chevron-left" : "chevron-right");
return (() => {
var _el$ = _tmpl$4();
return insert(_el$, createComponent(Icon2, {
get name() {
return iconName();
},
size: 36
})), createRenderEffect((_p$) => {
var _v$ = hidden() ? "true" : "false", _v$2 = hidden() ? "none" : "flex", _v$3 = props.state.direction === "right" ? "6px" : "", _v$4 = hidden() ? "0" : String(0.35 + progress() * 0.65), _v$5 = props.state.direction === "left" ? "6px" : "", _v$6 = `translate(${offset()}px, -50%)`;
return _v$ !== _p$.e && setAttribute(_el$, "aria-hidden", _p$.e = _v$), _v$2 !== _p$.t && setStyleProperty(_el$, "display", _p$.t = _v$2), _v$3 !== _p$.a && setStyleProperty(_el$, "left", _p$.a = _v$3), _v$4 !== _p$.o && setStyleProperty(_el$, "opacity", _p$.o = _v$4), _v$5 !== _p$.i && setStyleProperty(_el$, "right", _p$.i = _v$5), _v$6 !== _p$.n && setStyleProperty(_el$, "transform", _p$.n = _v$6), _p$;
}, {
e: void 0,
t: void 0,
a: void 0,
o: void 0,
i: void 0,
n: void 0
}), _el$;
})();
}
var _tmpl$4, HIDE_PROGRESS, init_chunk_FLAQB24C = __esm({
"../reader/dist/chunk-FLAQB24C.js"() {
"use strict";
init_chunk_UPVG5Y6S();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_solid();
_tmpl$4 = /* @__PURE__ */ template("<div class=ehpeek-swipe-indicator>"), HIDE_PROGRESS = 1e-3;
}
});
// ../reader/dist/chunk-M4W444CR.js
var init_chunk_M4W444CR = __esm({
"../reader/dist/chunk-M4W444CR.js"() {
"use strict";
}
});
// ../reader/dist/chunk-M65F42KE.js
function LauncherButton(props) {
return (() => {
var _el$ = _tmpl$5();
return _el$.$$click = () => props.onClick(), insert(_el$, createComponent(Icon2, {
get name() {
return props.icon;
},
size: "var(--ui-icon-size-sm)"
}), null), insert(_el$, () => props.label, null), createRenderEffect(() => setAttribute(_el$, "title", props.title)), _el$;
})();
}
var _tmpl$5, init_chunk_M65F42KE = __esm({
"../reader/dist/chunk-M65F42KE.js"() {
"use strict";
init_chunk_UPVG5Y6S();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
_tmpl$5 = /* @__PURE__ */ template("<button type=button class=ehpeek-launcher-button>");
delegateEvents(["click"]);
}
});
// ../reader/dist/chunk-QXLQXDIQ.js
function ProgressBar(props) {
let input2;
createEffect(() => {
let direction = props.direction ?? "ltr";
input2.min = String(props.min), input2.max = String(Math.max(1, props.max ?? props.min)), input2.step = String(props.step), input2.dir = direction, input2.style.setProperty("--progress-bar-track-direction", direction === "rtl" ? "to left" : "to right"), input2.style.setProperty("--progress-bar-fill", `${Math.min(100, Math.max(0, props.fillPercent ?? 0))}%`), !props.keepInputValue && props.value !== void 0 && (input2.value = String(props.value));
});
let currentValue = (event) => Number(event.currentTarget.value || "");
return (() => {
var _el$ = _tmpl$6();
return _el$.addEventListener("pointercancel", (event) => {
props.onCommit?.(currentValue(event));
}), _el$.$$pointerup = (event) => {
props.onCommit?.(currentValue(event));
}, _el$.addEventListener("change", (event) => {
props.onCommit?.(currentValue(event));
}), _el$.$$input = (event) => {
props.onInput?.(currentValue(event));
}, _el$.$$pointerdown = (event) => {
props.onPointerDown?.(event);
}, use((element) => {
input2 = element, element.min = String(props.min), element.max = String(Math.max(1, props.max ?? props.min)), element.step = String(props.step), element.value = String(props.value ?? props.min);
}, _el$), createRenderEffect((_p$) => {
var _v$ = `ehpeek-progress-bar${props.class ? ` ${props.class}` : ""}`, _v$2 = String(props.min), _v$3 = String(Math.max(1, props.max ?? props.min)), _v$4 = String(props.step), _v$5 = props.direction ?? "ltr";
return _v$ !== _p$.e && className(_el$, _p$.e = _v$), _v$2 !== _p$.t && setAttribute(_el$, "min", _p$.t = _v$2), _v$3 !== _p$.a && setAttribute(_el$, "max", _p$.a = _v$3), _v$4 !== _p$.o && setAttribute(_el$, "step", _p$.o = _v$4), _v$5 !== _p$.i && setAttribute(_el$, "dir", _p$.i = _v$5), _p$;
}, {
e: void 0,
t: void 0,
a: void 0,
o: void 0,
i: void 0
}), _el$;
})();
}
var _tmpl$6, init_chunk_QXLQXDIQ = __esm({
"../reader/dist/chunk-QXLQXDIQ.js"() {
"use strict";
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_solid();
_tmpl$6 = /* @__PURE__ */ template("<input type=range>");
delegateEvents(["pointerdown", "input", "pointerup"]);
}
});
// ../reader/dist/chunk-6JKLIWFA.js
function lockPageThemeColor(color) {
if (themeLocks.length === 0) {
let existing = document.querySelector('meta[name="theme-color"]'), meta = existing ?? document.createElement("meta"), previous = existing?.getAttribute("content") ?? null;
existing || (meta.name = "theme-color", document.head.append(meta)), themeMeta = meta, restoreTheme = () => {
existing ? previous === null ? meta.removeAttribute("content") : meta.content = previous : meta.remove();
};
}
let entry = { color };
return themeLocks.push(entry), themeMeta.content = color, () => {
let index = themeLocks.indexOf(entry);
if (index < 0) return;
themeLocks.splice(index, 1);
let active = themeLocks[themeLocks.length - 1];
active ? themeMeta.content = active.color : (restoreTheme?.(), themeMeta = null, restoreTheme = null);
};
}
function lockPageScroll() {
if (scrollLockCount++ === 0) {
let roots = [document.documentElement, document.body], previous = roots.map((root) => ({
value: root.style.getPropertyValue("overflow"),
priority: root.style.getPropertyPriority("overflow")
}));
for (let root of roots) root.style.setProperty("overflow", "hidden", "important");
restoreScroll = () => roots.forEach((root, index) => {
let style2 = previous[index];
style2.value ? root.style.setProperty("overflow", style2.value, style2.priority) : root.style.removeProperty("overflow");
});
}
let released = !1;
return () => {
released || (released = !0, --scrollLockCount === 0 && (restoreScroll?.(), restoreScroll = null));
};
}
function prepareFullscreenSnapshot() {
let existing = document.querySelector(
'meta[name="viewport"]'
), meta = existing ?? document.createElement("meta"), scale = Math.max(0.1, window.visualViewport?.scale ?? 1), snapshot = {
content: existing?.getAttribute("content") ?? null,
created: !existing,
meta,
scale,
scrollX: window.scrollX,
scrollY: window.scrollY
};
return existing || (meta.name = "viewport", document.head.append(meta)), meta.content = lockedViewportContent(snapshot.content, scale), snapshot;
}
async function restorePageViewport(snapshot) {
await nextAnimationFrame(), restoreViewportMeta(snapshot), await nextAnimationFrame(), snapshot.meta.isConnected || (snapshot.meta.name = "viewport", document.head.append(snapshot.meta)), snapshot.meta.content = lockedViewportContent(snapshot.content, snapshot.scale), await waitForViewportSettled(), restoreViewportMeta(snapshot), await nextAnimationFrame(), await nextAnimationFrame(), window.scrollTo(snapshot.scrollX, snapshot.scrollY);
}
function restoreViewportMeta(snapshot) {
snapshot.created ? snapshot.meta.remove() : snapshot.content === null ? snapshot.meta.removeAttribute("content") : snapshot.meta.content = snapshot.content;
}
function createFullscreenController(target, onScaleChange = () => {
}) {
let snapshot = null, restorePromise = null, active = () => {
let fullscreenElement = document.fullscreenElement;
return fullscreenElement === target || fullscreenElement instanceof HTMLElement && fullscreenElement.contains(target);
}, restore2 = () => {
if (restorePromise)
return restorePromise;
onScaleChange(1);
let captured = snapshot;
return snapshot = null, captured ? (restorePromise = waitForViewportSettled().then(() => restorePageViewport(captured)).finally(() => {
restorePromise = null;
}), restorePromise) : Promise.resolve();
};
return {
active,
enter: async () => {
if (document.fullscreenElement || !document.fullscreenEnabled)
return;
await restorePromise, snapshot = prepareFullscreenSnapshot();
let scaleBefore = snapshot.scale;
try {
await target.requestFullscreen(), await nextAnimationFrame();
let scaleAfter = Math.max(0.01, window.visualViewport?.scale ?? 1), scale = Math.min(1, Math.max(0.1, scaleBefore / scaleAfter));
onScaleChange(scale);
} catch (error) {
throw await restore2(), error;
}
},
exit: async () => {
active() && await document.exitFullscreen(), await restore2(), onScaleChange(1);
},
restore: restore2,
subscribe: (callback) => {
let onChange = () => {
let fullscreenActive = active();
fullscreenActive || (onScaleChange(1), restore2()), callback(fullscreenActive);
};
return document.addEventListener("fullscreenchange", onChange), () => document.removeEventListener("fullscreenchange", onChange);
}
};
}
function nextAnimationFrame() {
return new Promise((resolve) => {
window.requestAnimationFrame(() => resolve());
});
}
function lockedViewportContent(content, scale) {
let preserved = (content ?? "").split(",").map((item) => item.trim()).filter(
(item) => item && !/^(?:initial-scale|minimum-scale|maximum-scale|user-scalable|viewport-fit)\s*=/i.test(item)
), value = String(Math.round(scale * 1e3) / 1e3);
return [
...preserved,
`initial-scale=${value}`,
`minimum-scale=${value}`,
`maximum-scale=${value}`,
"user-scalable=no",
"viewport-fit=cover"
].join(", ");
}
async function waitForViewportSettled() {
await nextAnimationFrame(), await new Promise((resolve) => {
let viewport = window.visualViewport, quietTimer = window.setTimeout(finish, 80), timeoutTimer = window.setTimeout(finish, 500), onResize = () => {
window.clearTimeout(quietTimer), quietTimer = window.setTimeout(finish, 80);
};
function finish() {
viewport?.removeEventListener("resize", onResize), window.clearTimeout(quietTimer), window.clearTimeout(timeoutTimer), resolve();
}
viewport?.addEventListener("resize", onResize);
}), await nextAnimationFrame();
}
var themeLocks, themeMeta, restoreTheme, scrollLockCount, restoreScroll, init_chunk_6JKLIWFA = __esm({
"../reader/dist/chunk-6JKLIWFA.js"() {
"use strict";
themeLocks = [], themeMeta = null, restoreTheme = null;
scrollLockCount = 0, restoreScroll = null;
}
});
// ../reader/dist/chunk-W6BYXZGJ.js
function UiPixelScaleProvider(props) {
let value = untrack(() => props.value);
return createComponent(UiPixelScaleContext.Provider, {
value,
get children() {
return props.children;
}
});
}
function useUiPixelScale() {
return useContext(UiPixelScaleContext);
}
var UiPixelScaleContext, init_chunk_W6BYXZGJ = __esm({
"../reader/dist/chunk-W6BYXZGJ.js"() {
"use strict";
init_web();
init_solid();
UiPixelScaleContext = createContext(() => 1);
}
});
// ../reader/dist/chunk-ENSDPUNG.js
function createOverlayHost(parent, initialUiScale = "small", texts = readerLocales.en) {
let element = document.createElement("div");
element.dataset.ehpeekOverlayHost = "true", parent.append(element), markUiRoot(element);
let [uiScale, setScale] = createSignal(initialUiScale), fullscreenScale = 1, [fullscreenPixelScale, setFullscreenPixelScale] = createSignal(1), applyScale = () => applyUiScale(uiScale(), element, fullscreenScale), fullscreen = createFullscreenController(element, (factor) => {
fullscreenScale = factor, setFullscreenPixelScale(factor), applyScale();
});
return untrack(applyScale), {
element,
texts,
fullscreen,
fullscreenPixelScale,
uiScale,
setUiScale: (scale) => {
setScale(scale), applyScale();
}
};
}
function OverlayHostProvider(props) {
let host = untrack(() => props.host);
return createComponent(OverlayHostContext.Provider, {
value: host,
get children() {
return createComponent(ReaderTextsProvider, {
get texts() {
return host.texts;
},
get children() {
return props.children;
}
});
}
});
}
function OverlayPortal(props) {
let host = useOverlayHost();
return createComponent(Portal, {
get mount() {
return host.element;
},
get children() {
return createComponent(UiPixelScaleProvider, {
get value() {
return host.fullscreenPixelScale;
},
get children() {
return props.children;
}
});
}
});
}
function useOverlayHost() {
let host = useContext(OverlayHostContext);
if (!host)
throw new Error("OverlayHostProvider is required for overlay content.");
return host;
}
var OverlayHostContext, init_chunk_ENSDPUNG = __esm({
"../reader/dist/chunk-ENSDPUNG.js"() {
"use strict";
init_chunk_A6WI3YS4();
init_chunk_6JKLIWFA();
init_chunk_W6BYXZGJ();
init_chunk_JXES5MWD();
init_web();
init_solid();
init_web();
OverlayHostContext = createContext();
}
});
// ../reader/dist/chunk-4Y6MOAXB.js
function Button(props) {
let [local2, rest] = splitProps(props, ["variant", "class", "classList", "type"]);
return (() => {
var _el$ = _tmpl$7();
return spread(_el$, mergeProps(rest, {
get type() {
return local2.type ?? "button";
},
get class() {
return widgetClass(BUTTON_VARIANTS[local2.variant ?? "control"], local2);
}
}), !1, !1), _el$;
})();
}
function IconButton(props) {
let [local2, rest] = splitProps(props, ["variant", "size", "class", "classList", "type"]);
return (() => {
var _el$2 = _tmpl$7();
return spread(_el$2, mergeProps(rest, {
get type() {
return local2.type ?? "button";
},
get class() {
return widgetClass(`ehpeek-icon-action ${ICON_BUTTON_SIZES[local2.size]} ${ICON_BUTTON_VARIANTS[local2.variant]}`, local2);
}
}), !1, !1), _el$2;
})();
}
function IconLink(props) {
let [local2, rest] = splitProps(props, ["variant", "size", "class", "classList"]);
return (() => {
var _el$3 = _tmpl$23();
return spread(_el$3, mergeProps(rest, {
get class() {
return widgetClass(`ehpeek-icon-action ${ICON_BUTTON_SIZES[local2.size]} ${ICON_BUTTON_VARIANTS[local2.variant]}`, local2);
}
}), !1, !1), _el$3;
})();
}
var _tmpl$7, _tmpl$23, BUTTON_VARIANTS, ICON_BUTTON_VARIANTS, ICON_BUTTON_SIZES, init_chunk_4Y6MOAXB = __esm({
"../reader/dist/chunk-4Y6MOAXB.js"() {
"use strict";
init_chunk_E6UKP7HT();
init_web();
init_web();
init_web();
init_solid();
_tmpl$7 = /* @__PURE__ */ template("<button>"), _tmpl$23 = /* @__PURE__ */ template("<a>"), BUTTON_VARIANTS = {
control: "ehpeek-button ehpeek-button--control",
option: "ehpeek-button ehpeek-button--option"
};
ICON_BUTTON_VARIANTS = {
ghost: "ehpeek-icon-action--ghost",
subtle: "ehpeek-icon-action--subtle",
surface: "ehpeek-icon-action--surface"
}, ICON_BUTTON_SIZES = {
sm: "ehpeek-icon-action--sm",
md: "ehpeek-icon-action--md",
xl: "ehpeek-icon-action--xl"
};
}
});
// ../reader/dist/chunk-QUSU3A2M.js
function Dialog(props) {
let texts = useReaderTexts();
return onMount(() => {
let unlockScroll = props.lockPageScroll ? lockPageScroll() : () => {
}, closeOnEscape = (event) => {
event.key === "Escape" && (event.preventDefault(), event.stopImmediatePropagation(), props.onClose());
};
window.addEventListener("keydown", closeOnEscape, !0), onCleanup(() => {
window.removeEventListener("keydown", closeOnEscape, !0), unlockScroll();
});
}), createComponent(OverlayPortal, {
get children() {
var _el$ = _tmpl$8(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.firstChild, _el$5 = _el$3.nextSibling;
return _el$.addEventListener("wheel", (event) => event.stopPropagation()), _el$.$$pointerdown = (event) => event.stopPropagation(), _el$.$$click = (event) => {
event.stopPropagation(), event.target === event.currentTarget && props.onClose();
}, insert(_el$4, () => props.title), insert(_el$3, createComponent(IconButton, {
variant: "ghost",
size: "md",
class: "ehpeek-dialog__close",
get "aria-label"() {
return texts.common.actions.close;
},
get title() {
return texts.common.actions.close;
},
onClick: () => props.onClose(),
get children() {
return createComponent(Icon2, {
name: "close",
size: "var(--ui-icon-size-md)"
});
}
}), null), insert(_el$5, () => props.children), createRenderEffect((_p$) => {
var _v$ = props.variant, _v$2 = props.label, _v$3 = `ehpeek-dialog__panel ${DIALOG_WIDTHS[props.width]}`, _v$4 = `ehpeek-dialog__body ${props.bodyClass ?? ""}`;
return _v$ !== _p$.e && setAttribute(_el$, "data-ui-dialog", _p$.e = _v$), _v$2 !== _p$.t && setAttribute(_el$, "aria-label", _p$.t = _v$2), _v$3 !== _p$.a && className(_el$2, _p$.a = _v$3), _v$4 !== _p$.o && className(_el$5, _p$.o = _v$4), _p$;
}, {
e: void 0,
t: void 0,
a: void 0,
o: void 0
}), _el$;
}
});
}
var _tmpl$8, DIALOG_WIDTHS, init_chunk_QUSU3A2M = __esm({
"../reader/dist/chunk-QUSU3A2M.js"() {
"use strict";
init_chunk_ENSDPUNG();
init_chunk_6JKLIWFA();
init_chunk_4Y6MOAXB();
init_chunk_UPVG5Y6S();
init_chunk_JXES5MWD();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_solid();
_tmpl$8 = /* @__PURE__ */ template("<div class=ehpeek-dialog role=dialog aria-modal=true><div><div class=ehpeek-dialog__header><h2 class=ehpeek-dialog__title></h2></div><div>"), DIALOG_WIDTHS = {
md: "ehpeek-dialog__panel--md",
lg: "ehpeek-dialog__panel--lg"
};
delegateEvents(["click", "pointerdown"]);
}
});
// ../reader/dist/chunk-PV2I4MKV.js
function InteractionHelp(props) {
let texts = useReaderTexts();
return createComponent(Dialog, {
bodyClass: "ehpeek-help-body",
get label() {
return texts.help.title;
},
get onClose() {
return props.onClose;
},
get title() {
return texts.help.title;
},
get variant() {
return props.variant;
},
width: "lg",
get children() {
var _el$ = _tmpl$9();
return insert(_el$, createComponent(For, {
get each() {
return texts.help.sections;
},
children: (section) => (() => {
var _el$2 = _tmpl$24(), _el$3 = _el$2.firstChild, _el$4 = _el$3.nextSibling;
return insert(_el$3, () => section.title), insert(_el$4, createComponent(For, {
get each() {
return section.items;
},
children: (item) => (() => {
var _el$5 = _tmpl$33();
return insert(_el$5, createComponent(HelpText, {
text: item
})), _el$5;
})()
})), _el$2;
})()
})), _el$;
}
});
}
function HelpText(props) {
return createComponent(For, {
get each() {
return props.text.split(/(\*\*[^*]+\*\*)/g);
},
children: (part) => part.startsWith("**") && part.endsWith("**") ? (() => {
var _el$6 = _tmpl$42();
return insert(_el$6, () => part.slice(2, -2)), _el$6;
})() : part
});
}
var _tmpl$9, _tmpl$24, _tmpl$33, _tmpl$42, init_chunk_PV2I4MKV = __esm({
"../reader/dist/chunk-PV2I4MKV.js"() {
"use strict";
init_chunk_QUSU3A2M();
init_chunk_JXES5MWD();
init_web();
init_web();
init_web();
init_solid();
_tmpl$9 = /* @__PURE__ */ template("<div class=ehpeek-help>"), _tmpl$24 = /* @__PURE__ */ template("<section><h3 class=ehpeek-help-title></h3><ul class=ehpeek-help-list>"), _tmpl$33 = /* @__PURE__ */ template("<li class=ehpeek-help-item>"), _tmpl$42 = /* @__PURE__ */ template("<strong>");
}
});
// ../reader/dist/chunk-NU4SG75H.js
function PositionBar(props) {
let pixelScale = useUiPixelScale(), [dragging, setDragging] = createSignal(!1), track, thumb, dragOffset = 0, capturedPointer = null;
createEffect(() => {
props.disabled && (setDragging(!1), capturedPointer !== null && track.hasPointerCapture(capturedPointer) && track.releasePointerCapture(capturedPointer), capturedPointer = null);
});
let axis = untrack(() => props.axis), thickness = () => props.thickness ?? "normal", horizontal = axis === "horizontal", minValue = () => props.minValue ?? 1, valueRange = () => Math.max(0, props.maxValue - minValue()), expanded = () => !!props.expanded || dragging(), visible = () => props.visible !== !1 || dragging(), logicalPosition = () => valueRange() === 0 ? 0 : (props.currentValue - minValue()) / valueRange() * 100, visualPosition = () => horizontal && props.reversed ? 100 - logicalPosition() : logicalPosition(), thumbRatio = () => clamp(props.visibleRatio ?? (props.visibleValueCount ?? 1) / Math.max(1, valueRange() + 1), 0, 1), draggable = () => !props.disabled && valueRange() > 0 && thumbRatio() < 1, coordinate = (event) => horizontal ? event.clientX : event.clientY, valueAt = (pointerCoordinate) => {
let trackRect = track.getBoundingClientRect(), trackStart = horizontal ? trackRect.left : trackRect.top, trackLength = horizontal ? trackRect.width : trackRect.height, thumbLength = horizontal ? thumb.offsetWidth : thumb.offsetHeight, visualRatio = clamp((pointerCoordinate - trackStart - dragOffset) / Math.max(1, trackLength - thumbLength), 0, 1), ratio = horizontal && props.reversed ? 1 - visualRatio : visualRatio;
return minValue() + ratio * valueRange();
}, inputAt = (event) => {
let value = valueAt(coordinate(event));
return props.onInput(value), value;
}, onPointerDown = (event) => {
if (event.preventDefault(), event.stopPropagation(), !draggable())
return;
let thumbPressed = event.target instanceof Node && thumb.contains(event.target);
if (!thumbPressed && props.trackClickEnabled === !1)
return;
setDragging(!0), track.setPointerCapture(event.pointerId), capturedPointer = event.pointerId;
let thumbRect = thumb.getBoundingClientRect();
dragOffset = thumbPressed ? coordinate(event) - (horizontal ? thumbRect.left : thumbRect.top) : (horizontal ? thumbRect.width : thumbRect.height) / 2, props.onPointerDown?.(event), inputAt(event);
}, onPointerMove = (event) => {
dragging() && inputAt(event);
}, onPointerUp = (event) => {
if (!dragging())
return;
setDragging(!1);
let value = inputAt(event);
track.releasePointerCapture(event.pointerId), capturedPointer = null, props.onCommit?.(value);
}, onPointerCancel = (event) => {
dragging() && (setDragging(!1), track.releasePointerCapture(event.pointerId), capturedPointer = null, props.onCommit?.(props.currentValue));
}, stopClick = (event) => event.stopPropagation(), stopContextMenu = (event) => {
event.preventDefault(), event.stopPropagation();
}, stopWheel = (event) => event.stopPropagation(), renderHorizontal = () => (() => {
var _el$ = _tmpl$10(), _el$2 = _el$.firstChild, _el$3 = _el$2.nextSibling, _el$4 = _el$3.firstChild;
_el$.addEventListener("wheel", stopWheel), _el$.$$pointerup = onPointerUp, _el$.$$pointermove = onPointerMove, _el$.$$pointerdown = onPointerDown, _el$.addEventListener("pointercancel", onPointerCancel), _el$.$$contextmenu = stopContextMenu, _el$.$$click = stopClick;
var _ref$ = track;
typeof _ref$ == "function" ? use(_ref$, _el$) : track = _el$;
var _ref$2 = thumb;
return typeof _ref$2 == "function" ? use(_ref$2, _el$3) : thumb = _el$3, createRenderEffect((_p$) => {
var _v$ = props.position ?? "absolute", _v$2 = thickness(), _v$3 = draggable(), _v$4 = props.trackVisible !== !1, _v$5 = props.ariaLabel, _v$6 = !draggable(), _v$7 = props.maxValue, _v$8 = minValue(), _v$9 = props.currentValue, _v$0 = `${visualPosition()}%`, _v$1 = `translateX(-${visualPosition()}%)`, _v$10 = `clamp(var(--ui-control-size-md), ${thumbRatio() * 100}%, 100%)`, _v$11 = `scaleY(${pixelScale()})`;
return _v$ !== _p$.e && setAttribute(_el$, "data-position", _p$.e = _v$), _v$2 !== _p$.t && setAttribute(_el$, "data-thickness", _p$.t = _v$2), _v$3 !== _p$.a && setAttribute(_el$, "data-draggable", _p$.a = _v$3), _v$4 !== _p$.o && setAttribute(_el$, "data-track-visible", _p$.o = _v$4), _v$5 !== _p$.i && setAttribute(_el$, "aria-label", _p$.i = _v$5), _v$6 !== _p$.n && setAttribute(_el$, "aria-disabled", _p$.n = _v$6), _v$7 !== _p$.s && setAttribute(_el$, "aria-valuemax", _p$.s = _v$7), _v$8 !== _p$.h && setAttribute(_el$, "aria-valuemin", _p$.h = _v$8), _v$9 !== _p$.r && setAttribute(_el$, "aria-valuenow", _p$.r = _v$9), _v$0 !== _p$.d && setStyleProperty(_el$3, "left", _p$.d = _v$0), _v$1 !== _p$.l && setStyleProperty(_el$3, "transform", _p$.l = _v$1), _v$10 !== _p$.u && setStyleProperty(_el$3, "width", _p$.u = _v$10), _v$11 !== _p$.c && setStyleProperty(_el$4, "transform", _p$.c = _v$11), _p$;
}, {
e: void 0,
t: void 0,
a: void 0,
o: void 0,
i: void 0,
n: void 0,
s: void 0,
h: void 0,
r: void 0,
d: void 0,
l: void 0,
u: void 0,
c: void 0
}), _el$;
})(), renderVertical = () => (() => {
var _el$5 = _tmpl$25(), _el$6 = _el$5.firstChild, _el$7 = _el$6.nextSibling, _el$8 = _el$7.firstChild;
_el$5.addEventListener("wheel", stopWheel), _el$5.$$pointerup = onPointerUp, _el$5.$$pointermove = onPointerMove, _el$5.$$pointerdown = onPointerDown, _el$5.addEventListener("pointercancel", onPointerCancel), _el$5.$$contextmenu = stopContextMenu, _el$5.$$click = stopClick;
var _ref$3 = track;
typeof _ref$3 == "function" ? use(_ref$3, _el$5) : track = _el$5;
var _ref$4 = thumb;
return typeof _ref$4 == "function" ? use(_ref$4, _el$7) : thumb = _el$7, createRenderEffect((_p$) => {
var _v$12 = props.position ?? "absolute", _v$13 = thickness(), _v$14 = expanded(), _v$15 = visible(), _v$16 = draggable(), _v$17 = props.trackVisible !== !1, _v$18 = props.ariaLabel, _v$19 = !draggable(), _v$20 = props.maxValue, _v$21 = minValue(), _v$22 = props.currentValue, _v$23 = `clamp(var(--ehpeek-position-bar-thumb-min), ${thumbRatio() * 100}%, 100%)`, _v$24 = `${visualPosition()}%`, _v$25 = `translateY(-${visualPosition()}%)`, _v$26 = `scaleX(${pixelScale()})`;
return _v$12 !== _p$.e && setAttribute(_el$5, "data-position", _p$.e = _v$12), _v$13 !== _p$.t && setAttribute(_el$5, "data-thickness", _p$.t = _v$13), _v$14 !== _p$.a && setAttribute(_el$5, "data-expanded", _p$.a = _v$14), _v$15 !== _p$.o && setAttribute(_el$5, "data-visible", _p$.o = _v$15), _v$16 !== _p$.i && setAttribute(_el$5, "data-draggable", _p$.i = _v$16), _v$17 !== _p$.n && setAttribute(_el$5, "data-track-visible", _p$.n = _v$17), _v$18 !== _p$.s && setAttribute(_el$5, "aria-label", _p$.s = _v$18), _v$19 !== _p$.h && setAttribute(_el$5, "aria-disabled", _p$.h = _v$19), _v$20 !== _p$.r && setAttribute(_el$5, "aria-valuemax", _p$.r = _v$20), _v$21 !== _p$.d && setAttribute(_el$5, "aria-valuemin", _p$.d = _v$21), _v$22 !== _p$.l && setAttribute(_el$5, "aria-valuenow", _p$.l = _v$22), _v$23 !== _p$.u && setStyleProperty(_el$7, "height", _p$.u = _v$23), _v$24 !== _p$.c && setStyleProperty(_el$7, "top", _p$.c = _v$24), _v$25 !== _p$.w && setStyleProperty(_el$7, "transform", _p$.w = _v$25), _v$26 !== _p$.m && setStyleProperty(_el$8, "transform", _p$.m = _v$26), _p$;
}, {
e: void 0,
t: void 0,
a: void 0,
o: void 0,
i: void 0,
n: void 0,
s: void 0,
h: void 0,
r: void 0,
d: void 0,
l: void 0,
u: void 0,
c: void 0,
w: void 0,
m: void 0
}), _el$5;
})();
return memo(() => horizontal ? renderHorizontal() : renderVertical());
}
var _tmpl$10, _tmpl$25, init_chunk_NU4SG75H = __esm({
"../reader/dist/chunk-NU4SG75H.js"() {
"use strict";
init_chunk_W6BYXZGJ();
init_chunk_E6UKP7HT();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_solid();
_tmpl$10 = /* @__PURE__ */ template("<div class=ehpeek-position-bar data-axis=horizontal aria-orientation=horizontal role=scrollbar><div class=ehpeek-position-bar__track></div><div class=ehpeek-position-bar__thumb><span class=ehpeek-position-bar__fill style=transform-origin:bottom>"), _tmpl$25 = /* @__PURE__ */ template("<div class=ehpeek-position-bar data-axis=vertical aria-orientation=vertical role=scrollbar><div class=ehpeek-position-bar__track></div><div class=ehpeek-position-bar__thumb><span class=ehpeek-position-bar__fill style=transform-origin:right>");
delegateEvents(["click", "contextmenu", "pointerdown", "pointermove", "pointerup"]);
}
});
// ../reader/dist/chunk-VWKAYSAY.js
var theme_default, reader_default, init_chunk_VWKAYSAY = __esm({
"../reader/dist/chunk-VWKAYSAY.js"() {
"use strict";
init_chunk_E6UKP7HT();
theme_default = `.ehpeek-ui-root,
.ehpeek-ui-theme {
--ehpeek-ui-font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--color-site-page: #34353b;
--color-site-surface: #4f535b;
--color-site-elevated: #3f4249;
--color-site-text: #f1f1f1;
--color-site-accent: #f0b35a;
--color-site-border: #8d7454;
--color-background: var(--color-site-page);
--color-surface: var(--color-site-surface);
--color-elevated: var(--color-site-elevated);
--color-text: var(--color-site-text);
--color-accent: var(--color-site-accent);
--color-danger: #ffb2a7;
--color-state-on: #4ec46a;
--color-state-off: #8c8f96;
--color-shadow: #000000;
--color-icon-button-text: var(--color-site-text);
--color-icon-button-hover: var(--color-site-item-hover);
--color-muted: color-mix(in srgb, var(--color-text) 72%, transparent);
--color-border: var(--color-site-border);
--color-track: color-mix(in srgb, var(--color-text) 34%, var(--color-background));
--color-danger-soft: color-mix(in srgb, var(--color-danger) 12%, transparent);
--color-danger-border: color-mix(in srgb, var(--color-danger) 64%, transparent);
--color-control: color-mix(in srgb, var(--color-elevated) 88%, transparent);
--color-badge: color-mix(in srgb, var(--color-background) 34%, transparent);
--color-shadow-panel: color-mix(in srgb, var(--color-shadow) 32%, transparent);
--color-shadow-elevated: color-mix(in srgb, var(--color-shadow) 38%, transparent);
--color-shadow-control: color-mix(in srgb, var(--color-shadow) 40%, transparent);
--color-shadow-floating: color-mix(in srgb, var(--color-shadow) 42%, transparent);
--color-site-accent-hover: color-mix(in srgb, var(--color-site-accent) 12%, transparent);
--color-site-border-subtle: color-mix(in srgb, var(--color-site-border) 16%, transparent);
--color-site-item-hover: color-mix(in srgb, var(--color-site-text) 8%, transparent);
--color-loading: color-mix(
in srgb,
color-mix(in srgb, var(--color-site-elevated) 80%, var(--color-site-surface)) 92%,
transparent
);
--color-site-swipe-background: color-mix(in srgb, var(--color-site-elevated) 94%, transparent);
--color-site-swipe-border: color-mix(in srgb, var(--color-site-border) 38%, transparent);
}
.ehpeek-ui-root [data-ui-dialog="reader"] {
--color-dialog-background: var(--color-background);
--color-dialog-border: var(--color-border);
--color-dialog-divider: var(--color-border);
--color-dialog-text: var(--color-text);
--color-icon-button-text: var(--color-text);
--color-icon-button-hover: var(--color-badge);
}
.ehpeek-ui-root [data-ui-dialog="site"] {
--color-dialog-background: var(--color-site-elevated);
--color-dialog-border: var(--color-site-border);
--color-dialog-divider: var(--color-site-border-subtle);
--color-dialog-text: var(--color-site-text);
--color-icon-button-text: var(--color-site-text);
--color-icon-button-hover: var(--color-site-item-hover);
}
#ehpeek-reader {
--color-reader-background: #070707;
--color-reader-surface: #151515;
--color-reader-elevated: #232323;
--color-reader-text: #f3f3f3;
--color-reader-accent: #4da3ff;
--color-reader-border: color-mix(in srgb, var(--color-reader-text) 18%, transparent);
--color-reader-muted: color-mix(in srgb, var(--color-reader-text) 72%, transparent);
--color-reader-scrollbar: color-mix(in srgb, var(--color-reader-text) 56%, transparent);
--color-background: var(--color-reader-background);
--color-surface: var(--color-reader-surface);
--color-elevated: var(--color-reader-elevated);
--color-text: var(--color-reader-text);
--color-accent: var(--color-reader-accent);
--color-border: color-mix(in srgb, var(--color-text) 18%, transparent);
--color-muted: color-mix(in srgb, var(--color-text) 72%, transparent);
--color-track: color-mix(in srgb, var(--color-text) 34%, var(--color-background));
--color-control: color-mix(in srgb, var(--color-elevated) 88%, transparent);
--color-badge: color-mix(in srgb, var(--color-background) 34%, transparent);
}
`, reader_default = `#ehpeek-reader,
#ehpeek-reader * {
box-sizing: border-box;
}
#ehpeek-reader[data-navigation-mode="paged"][data-page-layout="double"]:not([data-read-direction="ttb"])
.ehpeek-page {
width: calc(50% - 1.5px);
flex: 0 0 calc(50% - 1.5px);
}
.ehpeek-button {
justify-content: center;
border-width: 1px;
border-color: var(--color-border);
border-radius: var(--ui-radius-md);
background-color: var(--color-control);
color: var(--color-text);
cursor: pointer;
}
.ehpeek-button--control {
display: inline-flex;
min-width: var(--ui-hit-size-md);
height: var(--ui-hit-size-md);
align-items: center;
padding: 0 var(--ui-space-md);
font-family: var(--ehpeek-ui-font-sans);
font-size: var(--ui-font-size-md);
font-weight: 700;
line-height: 0.25rem;
}
.ehpeek-button--option {
display: flex;
width: 100%;
min-height: var(--ui-hit-size-lg);
flex-direction: column;
align-items: flex-start;
gap: var(--ui-space-xs);
padding: var(--ui-space-md) var(--ui-space-lg);
text-align: left;
}
.ehpeek-button:disabled {
opacity: 0.4;
cursor: default;
}
.ehpeek-icon-action {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0;
border-width: 0;
cursor: pointer;
}
.ehpeek-icon-action--sm {
width: var(--ui-control-size-sm);
height: var(--ui-control-size-sm);
}
.ehpeek-icon-action--md {
width: var(--ui-control-size-md);
height: var(--ui-control-size-md);
}
.ehpeek-icon-action--xl {
width: var(--ui-control-size-xl);
height: var(--ui-control-size-xl);
}
.ehpeek-icon-action--ghost {
border-radius: var(--ui-radius-md);
background-color: transparent;
color: var(--color-icon-button-text);
}
.ehpeek-icon-action--subtle {
border-radius: var(--ui-radius-md);
background-color: transparent;
color: var(--color-site-text);
font-family: var(--ehpeek-ui-font-sans);
font-size: var(--ui-font-size-sm);
font-weight: 700;
line-height: 0.25rem;
opacity: 0.9;
transition: opacity 160ms, background-color 160ms;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
.ehpeek-icon-action--subtle:focus-visible {
opacity: 1;
}
.ehpeek-icon-action--surface {
border-radius: var(--ui-radius-sm);
background-color: var(--color-site-surface);
color: var(--color-site-text);
}
.ehpeek-icon-action--surface:enabled:active {
transform: scale(0.96);
}
html[data-reader-pointer="mouse"] .ehpeek-button--option:hover {
background-color: var(--color-badge);
}
html[data-reader-pointer="mouse"] .ehpeek-icon-action--ghost:hover {
background-color: var(--color-icon-button-hover);
}
html[data-reader-pointer="mouse"] .ehpeek-icon-action--subtle:hover {
opacity: 1;
background-color: var(--color-site-page);
}
.ehpeek-icon-action:disabled {
opacity: 0.4;
cursor: default;
}
.ehpeek-icon-action--ghost:disabled {
opacity: 0.35;
}
html[data-reader-pointer="mouse"] .ehpeek-icon-action--ghost:disabled:hover {
background-color: transparent;
}
.ehpeek-icon {
display: block;
flex: none;
}
.ehpeek-debug-overlay {
all: initial;
position: fixed;
right: 8px;
bottom: calc(8px + env(safe-area-inset-bottom, 0px));
left: 8px;
z-index: 2147483647;
box-sizing: border-box;
max-height: 60dvh;
overflow: auto;
padding: 8px;
border: 2px solid #ffcc00;
border-radius: 4px;
background: rgb(0 0 0 / 0.9);
color: #fff;
pointer-events: none;
white-space: pre-wrap;
overflow-wrap: anywhere;
font: 11px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace;
text-align: left;
-webkit-text-size-adjust: none;
}
.ehpeek-launcher-button {
display: inline-flex;
min-height: var(--ui-control-size-xs);
align-items: center;
justify-content: center;
gap: var(--ui-space-sm);
padding-left: var(--ui-space-md);
padding-right: var(--ui-space-md);
border-width: 0;
border-radius: var(--ui-radius-xl);
background-color: var(--color-site-surface);
color: var(--color-site-text);
font-family: var(--ehpeek-ui-font-sans);
font-size: var(--ui-font-size-sm);
font-weight: 700;
cursor: pointer;
transition: background-color 120ms, transform 120ms;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
html[data-reader-pointer="mouse"] .ehpeek-launcher-button:hover {
background-color: var(--color-site-item-hover);
}
.ehpeek-launcher-button:active {
transform: scale(0.98);
}
.ehpeek-popover {
z-index: 2100;
overflow: hidden;
border-width: 1px;
border-color: var(--color-site-border);
border-radius: var(--ui-radius-sm);
background-color: var(--color-site-elevated);
box-shadow: 0 8px 24px var(--color-shadow-elevated);
}
.ehpeek-dialog {
position: fixed;
inset: 0;
z-index: 2400;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
padding: var(--ui-space-lg);
background-color: rgb(0 0 0 / 0.65);
pointer-events: auto;
font-family: var(--ehpeek-ui-font-sans);
}
.ehpeek-dialog__panel {
box-sizing: border-box;
display: flex;
width: 100%;
max-height: min(calc(var(--ui-control-size-xl) * 12.75), calc(100dvh - var(--ui-space-lg) - var(--ui-space-lg)));
flex-direction: column;
overflow: hidden;
border-width: 1px;
border-color: var(--color-dialog-border);
border-radius: var(--ui-radius-lg);
background-color: var(--color-dialog-background);
color: var(--color-dialog-text);
box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
}
.ehpeek-dialog__panel--md {
max-width: calc(var(--ui-control-size-xl) * 7.5);
}
.ehpeek-dialog__panel--lg {
max-width: calc(var(--ui-control-size-xl) * 9.25);
}
.ehpeek-dialog__header {
box-sizing: border-box;
display: flex;
min-height: var(--ui-control-size-lg);
flex: none;
align-items: center;
justify-content: space-between;
gap: var(--ui-space-md);
padding: var(--ui-space-sm) var(--ui-space-sm) var(--ui-space-sm) var(--ui-space-lg);
border-width: 0;
border-bottom-width: 1px;
border-bottom-color: var(--color-dialog-divider);
}
.ehpeek-dialog__title {
margin: 0;
font-size: var(--ui-font-size-lg);
font-weight: 700;
}
.ehpeek-dialog__close {
flex: none;
}
.ehpeek-dialog__body {
min-height: 0;
overflow-y: auto;
overscroll-behavior: contain;
padding-bottom: var(--ui-space-lg);
}
.ehpeek-dialog__body > :last-child {
border-bottom-width: 0 !important;
}
.ehpeek-position-bar {
position: absolute;
z-index: 2;
touch-action: none;
-webkit-user-select: none;
user-select: none;
}
.ehpeek-position-bar[data-position="fixed"] {
position: fixed;
}
.ehpeek-position-bar__track {
position: absolute;
background-color: var(--color-reader-border, var(--color-border));
}
.ehpeek-position-bar[data-track-visible="false"] .ehpeek-position-bar__track {
background-color: transparent;
}
.ehpeek-position-bar__thumb {
position: absolute;
display: flex;
cursor: default;
}
.ehpeek-position-bar[data-draggable="true"] .ehpeek-position-bar__thumb {
cursor: grab;
}
.ehpeek-position-bar[data-draggable="true"] .ehpeek-position-bar__thumb:active {
cursor: grabbing;
}
.ehpeek-position-bar__fill {
display: block;
background-color: var(--color-reader-scrollbar, var(--color-muted));
box-shadow: 0 2px 10px var(--color-shadow-control);
}
/* UI scale changes the interaction surface, not the visual weight of the bar. */
.ehpeek-position-bar[data-axis="horizontal"] {
inset: auto 0 0;
height: var(--ui-space-xl);
}
.ehpeek-position-bar[data-axis="horizontal"] .ehpeek-position-bar__track {
inset: auto 0 4px;
height: 6px;
}
.ehpeek-position-bar[data-axis="horizontal"] .ehpeek-position-bar__thumb {
bottom: 0;
height: var(--ui-space-xl);
align-items: flex-end;
}
.ehpeek-position-bar[data-axis="horizontal"] .ehpeek-position-bar__fill {
width: 100%;
height: 24px;
border-radius: 0.375rem 0.375rem 0 0;
}
.ehpeek-position-bar[data-axis="horizontal"][data-thickness="narrow"] .ehpeek-position-bar__fill {
height: 8px;
}
.ehpeek-position-bar[data-axis="vertical"] {
--ehpeek-position-bar-thumb-min: calc(var(--ui-control-size-md) * 1.5);
--ehpeek-position-bar-hit-width: var(--ui-space-xl);
--ehpeek-position-bar-fill-width: 24px;
inset: 0 0 0 auto;
width: var(--ehpeek-position-bar-hit-width);
opacity: 1;
transition: width 160ms, opacity 160ms;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
.ehpeek-position-bar[data-axis="vertical"][data-expanded="true"] {
--ehpeek-position-bar-hit-width: var(--ui-hit-size-sm);
--ehpeek-position-bar-fill-width: 32px;
}
.ehpeek-position-bar[data-axis="vertical"][data-thickness="narrow"] {
--ehpeek-position-bar-fill-width: 8px;
}
.ehpeek-position-bar[data-axis="vertical"][data-thickness="narrow"][data-expanded="true"] {
--ehpeek-position-bar-fill-width: 16px;
}
.ehpeek-position-bar[data-visible="false"] {
opacity: 0;
pointer-events: none;
}
.ehpeek-position-bar[data-axis="vertical"] .ehpeek-position-bar__track {
inset: 0 4px 0 auto;
width: 6px;
}
.ehpeek-position-bar[data-axis="vertical"] .ehpeek-position-bar__thumb {
right: 0;
width: var(--ehpeek-position-bar-hit-width);
align-items: center;
justify-content: flex-end;
transition: width 160ms, height 160ms;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
.ehpeek-position-bar[data-axis="vertical"] .ehpeek-position-bar__fill {
width: var(--ehpeek-position-bar-fill-width);
height: 100%;
border-radius: 0.375rem 0 0 0.375rem;
transition: width 160ms, opacity 160ms;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
.ehpeek-progress-bar {
--progress-bar-fill: 0%;
--progress-bar-track-direction: to right;
width: 100%;
height: 2.4em;
margin: 0;
padding: 0 0.6em;
background-color: transparent;
cursor: grab;
touch-action: none;
-webkit-user-select: none;
user-select: none;
-webkit-appearance: none;
appearance: none;
accent-color: var(--color-text);
}
.ehpeek-progress-bar:active {
cursor: grabbing;
}
.ehpeek-progress-bar::-webkit-slider-runnable-track {
height: 0.4em;
border-radius: 9999px;
background: linear-gradient(
var(--progress-bar-track-direction),
var(--color-accent) 0 var(--progress-bar-fill),
var(--color-track) var(--progress-bar-fill) 100%
);
}
.ehpeek-progress-bar::-webkit-slider-thumb {
width: 1.4em;
height: 1.4em;
margin-top: -0.5em;
border: 2px solid var(--color-border);
border-radius: 9999px;
background: var(--color-text);
box-shadow: 0 2px 10px var(--color-shadow-control);
appearance: none;
-webkit-appearance: none;
}
.ehpeek-progress-bar::-moz-range-track,
.ehpeek-progress-bar::-moz-range-progress {
height: 0.4em;
border-radius: 9999px;
}
.ehpeek-progress-bar::-moz-range-track {
background: var(--color-track);
}
.ehpeek-progress-bar::-moz-range-progress {
background: var(--color-accent);
}
.ehpeek-progress-bar::-moz-range-thumb {
width: 1.4em;
height: 1.4em;
border: 2px solid var(--color-border);
border-radius: 9999px;
background: var(--color-text);
box-shadow: 0 2px 10px var(--color-shadow-control);
}
.ehpeek-swipe-indicator {
position: fixed;
top: 50%;
z-index: 2100;
display: flex;
width: 42px;
height: 108px;
align-items: center;
justify-content: center;
border-width: 1px;
border-color: var(--color-site-swipe-border);
border-radius: 9999px;
background-color: var(--color-site-swipe-background);
color: var(--color-site-text);
box-shadow: 0 6px 20px var(--color-shadow-floating);
pointer-events: none;
-webkit-user-select: none;
user-select: none;
backdrop-filter: blur(8px);
transition: opacity 120ms cubic-bezier(0.4, 0, 0.2, 1);
}
/* Reader layout and controls. State selectors belong to the component that owns them. */
.ehpeek-reading-view,
.ehpeek-reader-header,
.ehpeek-reader-tools {
display: contents;
}
.ehpeek-reader-panel { z-index: 900; }
.ehpeek-reader {
position: fixed;
inset: 0;
z-index: 2200;
overflow: hidden;
background: var(--color-reader-background);
color: var(--color-reader-text);
font-family: var(--ehpeek-ui-font-sans);
font-size: var(--ui-font-size-sm);
line-height: 1.4;
}
.ehpeek-reader-canvas { position: fixed; inset: 0; z-index: 1; }
.ehpeek-reader-toolbar {
position: fixed;
top: calc(10px + env(safe-area-inset-top, 0px));
right: max(8px, env(safe-area-inset-right, 0px));
z-index: 3;
display: flex;
justify-content: flex-end;
pointer-events: none;
}
.ehpeek-reader-toolbar-controls {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: var(--ui-space-md);
pointer-events: auto;
}
.ehpeek-reader-toolbar-controls[hidden] { display: none; }
.ehpeek-reader-toolbar-row,
.ehpeek-reader-toolbar-more {
display: flex;
gap: var(--ui-space-md);
}
.ehpeek-reader-toolbar-more {
width: calc(var(--ui-control-size-lg) * 4 + var(--ui-space-md) * 4);
flex-wrap: wrap;
}
.ehpeek-reader-toolbar-button {
width: var(--ui-control-size-lg) !important;
min-width: 0 !important;
padding-inline: var(--ui-space-sm) !important;
flex: none;
}
.ehpeek-reader-floating-toolbar {
position: fixed;
right: max(12px, env(safe-area-inset-right, 0px));
bottom: calc(var(--ui-control-size-lg) * 2 + var(--ui-font-size-lg) * 2.4 + env(safe-area-inset-bottom, 0px));
z-index: 2;
display: flex;
justify-content: flex-end;
transition: opacity 160ms ease-in-out, transform 160ms ease-in-out, visibility 160ms;
}
.ehpeek-reader-floating-actions { display: flex; flex-direction: column; gap: var(--ui-space-sm); }
.ehpeek-reader-floating-button {
width: calc(var(--ui-control-size-lg) * 2) !important;
min-width: var(--ui-control-size-lg) !important;
height: var(--ui-control-size-lg) !important;
padding-inline: 0;
opacity: 0.85;
transition: opacity 160ms;
}
.ehpeek-reader-floating-button:focus-visible,
html[data-reader-pointer="mouse"] .ehpeek-reader-floating-button:enabled:hover { opacity: 1; }
.ehpeek-reader-floating-button:disabled { opacity: 0.4; }
.ehpeek-reader-progress {
position: fixed;
right: max(12px, env(safe-area-inset-right, 0px));
bottom: calc(12px + env(safe-area-inset-bottom, 0px));
left: max(12px, env(safe-area-inset-left, 0px));
z-index: 2;
display: flex;
align-items: center;
padding: 0;
transition: opacity 160ms ease-in-out, transform 160ms ease-in-out, visibility 160ms;
}
.ehpeek-reader-progress-input { font-size: var(--ui-font-size-lg); }
.ehpeek-reader-floating-toolbar[data-open="false"],
.ehpeek-reader-progress[data-open="false"] {
opacity: 0;
transform: translateY(calc(100% + 16px));
pointer-events: none;
/* Stop iOS Safari repainting the still-composited (blue) progress track while
it is hidden — a page turn updates the value and would otherwise flash a
thin accent line at the bottom safe-area edge. */
visibility: hidden;
}
.ehpeek-reader-page-number,
.ehpeek-reader-fullscreen-status {
position: fixed;
top: calc(10px + env(safe-area-inset-top, 0px));
left: max(8px, env(safe-area-inset-left, 0px));
z-index: 3;
padding: var(--ui-space-xs) var(--ui-space-md);
border-radius: var(--ui-radius-md);
background: var(--color-badge);
color: var(--color-text);
font: 600 var(--ui-font-size-md)/1.4 var(--ehpeek-ui-font-sans);
white-space: nowrap;
pointer-events: none;
}
.ehpeek-reader-page-number { right: auto; min-width: 0; max-width: calc(100vw - 20px); text-align: left; }
.ehpeek-reader-fullscreen-status { display: flex; align-items: center; gap: var(--ui-space-sm); }
.ehpeek-reader-tools[data-left-handed="true"] .ehpeek-reader-toolbar {
left: max(8px, env(safe-area-inset-left, 0px));
right: auto;
}
.ehpeek-reader-tools[data-left-handed="true"] .ehpeek-reader-floating-toolbar {
left: max(12px, env(safe-area-inset-left, 0px));
right: auto;
}
.ehpeek-reader-tools[data-left-handed="true"] .ehpeek-reader-toolbar-controls { align-items: flex-start; }
.ehpeek-reader-tools[data-left-handed="true"] .ehpeek-reader-toolbar-row,
.ehpeek-reader-tools[data-left-handed="true"] .ehpeek-reader-toolbar-more { flex-direction: row-reverse; }
.ehpeek-reader-tools[data-left-handed="true"] .ehpeek-reader-page-number,
.ehpeek-reader-tools[data-left-handed="true"] .ehpeek-reader-fullscreen-status {
right: max(8px, env(safe-area-inset-right, 0px));
left: auto;
text-align: right;
}
.ehpeek-reader-control-notice {
position: fixed;
top: 50%;
left: 50%;
z-index: 2100;
width: max-content;
max-width: calc(100vw - 32px);
transform: translate(-50%, -50%);
pointer-events: none;
padding: var(--ui-space-lg) var(--ui-space-xl);
border-radius: var(--ui-radius-lg);
background: var(--color-badge);
color: var(--color-text);
font: 700 var(--ui-font-size-lg)/1.3 var(--ehpeek-ui-font-sans);
white-space: pre-line;
text-align: center;
box-shadow: 0 20px 25px -5px #0000001a, 0 8px 10px -6px #0000001a;
}
.ehpeek-reader-download-body { padding-top: var(--ui-space-lg); padding-inline: var(--ui-space-lg); }
.ehpeek-reader-download-options { font-size: var(--ui-font-size-md); font-family: var(--ehpeek-ui-font-sans); }
.ehpeek-reader-download-options,
.ehpeek-reader-download-page { display: grid; gap: var(--ui-space-md); }
.ehpeek-reader-download-title { font-size: var(--ui-font-size-md); font-weight: 700; }
.ehpeek-reader-download-filename,
.ehpeek-reader-download-detail { font-size: var(--ui-font-size-sm); opacity: 0.75; }
.ehpeek-reader-download-filename { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ehpeek-reader-download-summary { cursor: pointer; font-weight: 700; }
.ehpeek-reader-download-help { margin: var(--ui-space-sm) 0 0; line-height: 1.4; }
.ehpeek-reader-download-links {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--ui-space-sm) var(--ui-space-md);
margin-top: var(--ui-space-md);
}
.ehpeek-reader-download-link { color: var(--color-accent); }
html[data-reader-pointer="mouse"] .ehpeek-reader-download-link:hover { text-decoration: underline; }
/* Image scaling stays inside the reader's containing block. */
.ehpeek-reader-scale-gesture { position: absolute; inset: 0; z-index: 2; touch-action: none; user-select: none; }
.ehpeek-reader-scale-toolbar {
position: fixed;
bottom: calc(12px + env(safe-area-inset-bottom, 0px));
left: 50%;
z-index: 3;
display: flex;
width: min(680px, calc(100% - 24px));
transform: translateX(-50%);
flex-direction: column;
align-items: center;
gap: var(--ui-space-sm);
padding: var(--ui-space-sm);
border: 1px solid var(--color-reader-border);
border-radius: var(--ui-radius-lg);
background: var(--color-control);
box-shadow: 0 20px 25px -5px #0000001a, 0 8px 10px -6px #0000001a;
container-type: inline-size;
}
.ehpeek-reader-scale-slider-row,
.ehpeek-reader-scale-presets,
.ehpeek-reader-scale-actions {
display: grid;
width: 100%;
justify-content: center;
gap: var(--ui-space-sm);
}
.ehpeek-reader-scale-slider-row {
grid-template-columns: max-content minmax(var(--ui-control-size-md), 1fr);
align-items: center;
}
.ehpeek-reader-scale-label {
display: flex;
width: 100%;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
font: 600 var(--ui-font-size-sm)/1.05 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}
.ehpeek-reader-scale-input { width: 100%; min-width: 0; accent-color: var(--color-reader-accent); }
.ehpeek-reader-scale-presets { grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: stretch; }
.ehpeek-reader-scale-actions { max-width: 100%; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr) minmax(0, 1fr); align-items: stretch; }
.ehpeek-reader-scale-presets > button,
.ehpeek-reader-scale-actions > button { width: 100%; }
.ehpeek-reader-scale-apply-all { white-space: normal; line-height: 1.1; }
.ehpeek-reader-zoom {
position: fixed;
inset: 0;
z-index: 4;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
background: var(--color-reader-background);
color: var(--color-reader-text);
pointer-events: none;
}
.ehpeek-reader-zoom-image {
display: block;
max-width: 100vw;
max-height: 100vh;
object-fit: contain;
transform-origin: center;
user-select: none;
will-change: transform;
-webkit-user-drag: none;
}
/* Page layouts use the viewport's mode and direction, not generated class fragments. */
.ehpeek-reader-scroller {
width: 100%;
height: 100%;
overflow: auto;
overscroll-behavior: contain;
scroll-behavior: auto;
cursor: grab;
scrollbar-width: none;
-ms-overflow-style: none;
touch-action: none;
}
.ehpeek-reader-scroller::-webkit-scrollbar { display: none; }
.ehpeek-reader-scroller[data-navigation-mode="scroll"] { overflow-anchor: none; }
.ehpeek-reader-scroller[data-navigation-mode="scroll"][data-read-direction="ttb"][data-zoom-active="false"] { touch-action: pan-x pan-y; }
.ehpeek-reader-scroller[data-navigation-mode="scroll"]:not([data-read-direction="ttb"])[data-zoom-active="false"] { touch-action: pan-x; }
.ehpeek-reader-scroller[data-dragging="true"] { cursor: grabbing; user-select: none; }
.ehpeek-reader-scroller[data-navigation-mode="paged"] { overflow: hidden; touch-action: none; user-select: none; }
.ehpeek-reader-page-strip { display: flex; }
.ehpeek-reader-scroller[data-navigation-mode="paged"] .ehpeek-reader-page-strip { width: auto; height: 100%; }
.ehpeek-reader-scroller[data-navigation-mode="paged"][data-read-direction="ttb"] .ehpeek-reader-page-strip {
width: 100%;
flex-direction: column;
}
.ehpeek-reader-scroller[data-navigation-mode="paged"][data-page-layout="double"] .ehpeek-reader-page-strip { gap: 3px; }
.ehpeek-reader-scroller[data-navigation-mode="paged"][data-read-direction="ttb"][data-page-layout="double"] .ehpeek-reader-page-strip {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
grid-auto-rows: 100%;
column-gap: 3px;
row-gap: 0;
}
.ehpeek-reader-scroller[data-navigation-mode="scroll"][data-read-direction="ttb"] .ehpeek-reader-page-strip {
flex-direction: column;
min-height: 100%;
margin-inline: auto;
padding: 56px 0 0;
}
.ehpeek-reader-horizontal-spacer { display: none; }
.ehpeek-reader-scroller[data-navigation-mode="scroll"]:not([data-read-direction="ttb"]) .ehpeek-reader-horizontal-spacer {
display: block;
width: var(--reader-horizontal-spacer-width);
height: 1px;
flex: 0 0 var(--reader-horizontal-spacer-width);
order: -1;
}
.ehpeek-reader-vertical-spacer { display: none; }
.ehpeek-reader-scroller[data-navigation-mode="scroll"][data-read-direction="ttb"] .ehpeek-reader-vertical-spacer {
display: block;
flex: 0 0 var(--reader-vertical-spacer-height);
width: 1px;
}
.ehpeek-reader-scroller[data-navigation-mode="scroll"]:not([data-read-direction="ttb"]) .ehpeek-reader-page-strip {
min-width: 100%;
margin-block: auto;
padding: 0 72px 0 56px;
}
.ehpeek-reader-scroller[data-navigation-mode="scroll"][data-read-direction="rtl"] .ehpeek-reader-page-strip { padding: 0 56px 0 72px; }
.ehpeek-page { display: flex; align-items: center; justify-content: center; height: 100%; }
.ehpeek-page[data-pair-side="left"] { justify-content: flex-end; }
.ehpeek-page[data-pair-side="right"] { justify-content: flex-start; }
.ehpeek-reader-scroller[data-navigation-mode="scroll"][data-read-direction="ttb"] .ehpeek-page {
width: 100%;
height: var(--reader-page-height);
align-items: flex-start;
padding-bottom: 8px;
}
.ehpeek-reader-scroller[data-navigation-mode="scroll"]:not([data-read-direction="ttb"]) .ehpeek-page {
flex: 0 0 var(--reader-page-width);
width: var(--reader-page-width);
padding-right: 8px;
}
.ehpeek-reader-scroller[data-navigation-mode="paged"][data-page-layout="single"] .ehpeek-page { width: 100%; flex: 0 0 100%; }
.ehpeek-reader-scroller[data-navigation-mode="paged"][data-read-direction="ttb"][data-page-layout="double"] .ehpeek-page { width: 100%; }
.ehpeek-reader-page-frame {
position: relative;
display: flex;
width: var(--reader-frame-width);
height: var(--reader-frame-height);
align-items: center;
justify-content: center;
overflow: hidden;
container-type: size;
}
.ehpeek-reader-page-image { display: block; width: 100%; height: 100%; object-fit: contain; user-select: none; -webkit-user-drag: none; }
.ehpeek-reader-page-loading,
.ehpeek-reader-placeholder-spinner {
display: block;
box-sizing: border-box;
width: var(--ui-icon-size-xl);
height: var(--ui-icon-size-xl);
border: 2px solid var(--color-reader-border);
border-top-color: var(--color-reader-accent);
border-radius: 50%;
animation: ehpeek-reader-spin 1s linear infinite;
}
.ehpeek-reader-page-loading {
position: absolute;
right: var(--ui-space-sm);
bottom: var(--ui-space-sm);
z-index: 1;
pointer-events: none;
}
.ehpeek-reader-placeholder-spinner { flex: none; border-width: 4px; }
.ehpeek-reader-placeholder {
position: relative;
display: flex;
width: 100%;
height: 100%;
align-items: center;
justify-content: center;
background: var(--color-reader-surface);
color: var(--color-reader-muted);
text-align: center;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: min(25vw, 35cqi, 35cqb, 180px);
font-weight: 850;
line-height: 1;
font-variant-numeric: tabular-nums;
}
.ehpeek-reader-placeholder[data-kind="end"] {
padding: var(--reader-end-padding);
direction: ltr;
font-family: inherit;
font-size: min(var(--ui-font-size-xl), var(--reader-end-font-size));
font-weight: 700;
line-height: 1.3;
unicode-bidi: plaintext;
}
.ehpeek-reader-placeholder[data-state="error"] {
flex-direction: column;
gap: var(--ui-space-lg);
padding: var(--ui-space-xl);
color: var(--color-danger);
font-family: inherit;
font-size: var(--ui-font-size-md);
font-weight: 700;
line-height: 1;
}
.ehpeek-reader-placeholder-loading {
display: flex;
width: 100%;
height: 100%;
flex-direction: column;
align-items: center;
justify-content: center;
gap: var(--ui-space-xl);
overflow: hidden;
}
.ehpeek-reader-placeholder-number {
display: block;
max-width: 100%;
flex: none;
margin: 0;
padding: 0;
text-align: center;
line-height: 1;
white-space: nowrap;
direction: ltr;
unicode-bidi: plaintext;
}
.ehpeek-reader-page-reload {
appearance: none;
display: inline-flex;
width: var(--ui-hit-size-xl);
height: var(--ui-hit-size-xl);
align-items: center;
justify-content: center;
border: 1px solid var(--color-border);
border-radius: var(--ui-radius-md);
background: var(--color-control);
color: var(--color-text);
cursor: pointer;
font: 700 var(--ui-font-size-lg)/1 var(--ehpeek-ui-font-sans);
touch-action: manipulation;
}
html[data-reader-pointer="mouse"] .ehpeek-reader-page-reload:hover { background: var(--color-badge); }
.ehpeek-reader-page-reload:active { transform: scale(0.96); }
.ehpeek-reader-page-error,
.ehpeek-reader-page-error-detail { max-width: min(86vw, 760px); overflow-wrap: anywhere; direction: ltr; unicode-bidi: plaintext; }
.ehpeek-reader-page-error-detail { opacity: 0.8; font-size: var(--ui-font-size-sm); font-weight: 500; line-height: 1.4; }
/* Embedded and overlay previews share the same tile and toolbar styles. */
.ehpeek-preview-host[data-embedded="false"] { position: fixed; inset: 0; z-index: 2300; touch-action: pan-x pan-y; }
.ehpeek-preview-host[data-embedded="true"] { display: contents; }
.ehpeek-preview-panel {
box-sizing: border-box;
display: flex;
width: 100%;
flex-direction: column;
overflow: hidden;
color: var(--color-text);
font: var(--ui-font-size-md)/1.4 var(--ehpeek-ui-font-sans);
}
.ehpeek-preview-panel[data-scroll-preview-instance] {
position: relative;
height: 100%;
min-height: 0;
background: var(--color-site-elevated);
}
.ehpeek-preview-host[data-embedded="true"] > .ehpeek-preview-panel {
position: relative;
height: var(--scroll-preview-height);
max-height: 100svh;
border: 1px solid var(--color-site-border-subtle);
border-radius: var(--ui-radius-sm);
background: var(--color-site-elevated);
}
.ehpeek-preview-panel[data-scroll-preview-instance][hidden] { display: none; }
/* Overlay and embedded previews share one compact, softly-bordered chrome; the
former overlay-only full-width toolbar (strong border, large padding) has been
dropped. The fullscreen overlay still clears device safe areas via the max()
padding floor. */
.ehpeek-preview-toolbar {
display: flex;
min-height: var(--ui-control-size-sm);
flex: none;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: var(--ui-space-sm);
padding:
max(var(--ui-space-xs), env(safe-area-inset-top, 0px))
max(var(--ui-space-sm), env(safe-area-inset-right, 0px))
var(--ui-space-xs)
max(var(--ui-space-sm), env(safe-area-inset-left, 0px));
border: 0;
border-bottom: 1px solid var(--color-site-border-subtle);
background: var(--color-site-elevated);
color: var(--color-site-text);
font-size: var(--ui-font-size-sm);
}
.ehpeek-preview-range {
display: inline-flex;
min-height: var(--ui-control-size-sm);
flex: none;
align-items: center;
gap: var(--ui-space-xs);
padding-inline: var(--ui-space-sm);
border-radius: var(--ui-radius-sm);
background: var(--color-site-surface);
opacity: 0.75;
}
.ehpeek-preview-toolbar-actions {
display: flex;
min-width: 0;
max-width: 100%;
flex: 0 1 auto;
flex-wrap: wrap;
align-items: center;
gap: var(--ui-space-xs);
margin-inline-start: auto;
}
.ehpeek-preview-toolbar[data-left-handed="true"],
.ehpeek-preview-toolbar[data-left-handed="true"] .ehpeek-preview-toolbar-actions { flex-direction: row-reverse; }
.ehpeek-preview-loading {
display: block;
box-sizing: border-box;
width: var(--ui-icon-size-sm);
height: var(--ui-icon-size-sm);
border: 2px solid var(--color-border);
border-top-color: var(--color-accent);
border-radius: 50%;
animation: ehpeek-reader-spin 1s linear infinite;
}
.ehpeek-preview-viewport { position: relative; min-height: 0; width: 100%; flex: 1; }
.ehpeek-preview-scroller {
position: absolute;
inset: 0 4px 4px;
box-sizing: border-box;
background: var(--color-surface);
cursor: grab;
scrollbar-width: none;
-webkit-overflow-scrolling: touch;
overflow-x: hidden;
overflow-y: auto;
overscroll-behavior: contain;
touch-action: none;
}
.ehpeek-preview-scroller::-webkit-scrollbar { display: none; }
.ehpeek-preview-scroller[data-dragging="true"] { cursor: grabbing; user-select: none; }
.ehpeek-preview-scroller--horizontal { overflow-x: auto; overflow-y: hidden; bottom: calc(var(--ui-control-size-xs) / 2); }
.ehpeek-preview-canvas { position: relative; }
.ehpeek-preview-slot { position: absolute; }
.ehpeek-preview-launcher { display: flex; width: 100%; justify-content: center; margin-block: var(--ui-space-sm); }
.ehpeek-preview-tile {
position: relative;
display: flex;
width: 100%;
min-width: 0;
align-items: center;
justify-content: center;
overflow: hidden;
border-radius: 4px;
background: var(--color-background);
}
.ehpeek-preview-placeholder {
display: flex;
width: 100%;
height: 100%;
flex-direction: column;
align-items: center;
justify-content: center;
gap: var(--ui-space-sm);
border: 0;
background: transparent !important;
color: var(--color-text);
font-family: inherit;
font-size: var(--ui-font-size-sm);
cursor: default;
}
.ehpeek-preview-placeholder:enabled { cursor: pointer; }
.ehpeek-preview-image { pointer-events: none; display: block; flex: none; user-select: none; -webkit-user-drag: none; }
.ehpeek-preview-page-link { position: absolute; inset: 0; color: var(--color-text); text-decoration: none; }
.ehpeek-preview-page-link:hover,
.ehpeek-preview-page-link:active { text-decoration: none; }
.ehpeek-preview-highlight {
pointer-events: none;
position: absolute;
inset: 0;
z-index: 1;
box-sizing: border-box;
border-radius: 4px;
border: 6px solid var(--color-danger);
}
.ehpeek-help-body { padding: var(--ui-space-xl); }
.ehpeek-help { display: grid; gap: var(--ui-space-lg); text-align: left; font-size: var(--ui-font-size-md); line-height: 1.45; }
.ehpeek-help-title { margin: 0 0 var(--ui-space-sm); font-size: var(--ui-font-size-md); font-weight: 700; }
.ehpeek-help-list { margin: 0; padding-left: var(--ui-space-xl); }
.ehpeek-help-item { margin-bottom: var(--ui-space-xs); }
.ehpeek-help-item:last-child { margin-bottom: 0; }
#ehpeek-reader[inert] .ehpeek-reader-scroller,
.ehpeek-preview-panel[inert] .ehpeek-preview-scroller {
overflow: hidden;
touch-action: none;
}
@keyframes ehpeek-reader-spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
[data-ehpeek-overlay-host="true"]:fullscreen {
width: 100%;
height: 100%;
overflow: hidden;
background: var(--color-background);
}
[data-ehpeek-overlay-host="true"]:fullscreen .ehpeek-reader-fullscreen-status {
top: 0;
right: max(10px, env(safe-area-inset-right, 0px));
left: auto;
transform: translateY(50%);
}
[data-ehpeek-overlay-host="true"]:fullscreen .ehpeek-reader-page-number {
top: 0;
right: auto;
left: max(10px, env(safe-area-inset-left, 0px));
min-width: 0;
transform: translateY(50%);
text-align: left;
}
[data-ehpeek-overlay-host="true"]:fullscreen .ehpeek-reader-toolbar {
top: calc(max(var(--ui-control-size-xs), env(safe-area-inset-top, 0px)) + 8px);
}
[data-ehpeek-overlay-host="true"]:fullscreen
#ehpeek-reader[data-navigation-mode="scroll"][data-read-direction="ttb"]
.ehpeek-reader-page-strip {
padding-top: 0;
}
`;
registerGlobalStyle("ehpeek-reader-theme", theme_default);
registerGlobalStyle("ehpeek-reader-style", reader_default);
document.addEventListener("pointerover", (event) => {
document.documentElement.dataset.readerPointer = event.pointerType === "mouse" ? "mouse" : "touch";
}, !0);
}
});
// ../reader/dist/kit/Widgets/index.js
var init_Widgets = __esm({
"../reader/dist/kit/Widgets/index.js"() {
"use strict";
init_chunk_4EQKK5DW();
init_chunk_FLAQB24C();
init_chunk_M4W444CR();
init_chunk_M65F42KE();
init_chunk_QXLQXDIQ();
init_chunk_PV2I4MKV();
init_chunk_QUSU3A2M();
init_chunk_ENSDPUNG();
init_chunk_A6WI3YS4();
init_chunk_6JKLIWFA();
init_chunk_4Y6MOAXB();
init_chunk_NU4SG75H();
init_chunk_UPVG5Y6S();
init_chunk_W6BYXZGJ();
init_chunk_JXES5MWD();
init_chunk_VWKAYSAY();
init_chunk_E6UKP7HT();
init_chunk_PKBMQBKP();
}
});
// src/components/WelcomeIcon.tsx
function WelcomeIcon(props) {
let label = () => props.label ?? activeTexts.common.status.loading, showIcon = () => props.showIcon !== !1, placementClass = () => props.embedded ? "relative box-border w-full border-0 bg-transparent ui-px-lg ui-py-md" : "fixed left-1/2 top-1/2 z-[2200] -translate-x-1/2 -translate-y-1/2 ui-rounded-lg border ehp-color-site-border bg-[var(--color-loading)] ui-px-xl ui-py-lg shadow-[0_6px_20px_var(--color-shadow-floating)]";
return (() => {
var _el$ = _tmpl$11(), _el$2 = _el$.firstChild;
return insert(_el$, (() => {
var _c$ = memo(() => !!showIcon());
return () => _c$() ? createComponent(Icon2, {
name: "panda-peek",
size: "var(--ui-control-size-xl)",
strokeWidth: 1.6
}) : null;
})(), _el$2), createRenderEffect((_p$) => {
var _v$ = `${placementClass()} flex select-none flex-col items-center ui-gap-lg ehp-color-site-accent pointer-events-none`, _v$2 = label();
return _v$ !== _p$.e && className(_el$, _p$.e = _v$), _v$2 !== _p$.t && setAttribute(_el$, "aria-label", _p$.t = _v$2), _p$;
}, {
e: void 0,
t: void 0
}), _el$;
})();
}
var _tmpl$11, init_WelcomeIcon = __esm({
"src/components/WelcomeIcon.tsx"() {
"use strict";
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_i18n2();
init_Widgets();
_tmpl$11 = /* @__PURE__ */ template('<div role=status aria-live=polite><span class="inline-flex items-center justify-center ehp-color-site-text"><span class="inline-block box-border w-[var(--ui-icon-size-xl)] h-[var(--ui-icon-size-xl)] animate-spin rounded-full border-4 border-solid ehp-color-spinner"aria-hidden=true>');
}
});
// src/components/Widgets/Loading.tsx
function LoadingOverlay(props) {
return createComponent(Show, {
get when() {
return props.visible;
},
get children() {
return createComponent(WelcomeIcon, {
get label() {
return props.label;
}
});
}
});
}
var init_Loading = __esm({
"src/components/Widgets/Loading.tsx"() {
"use strict";
init_web();
init_solid();
init_WelcomeIcon();
}
});
// ../reader/dist/chunk-V7QAVQKV.js
function createPointerGestureElement(target, callbacks) {
let gesture = null;
return createEffect(() => {
let element = target();
element && (gesture = new PointerGesture(element, callbacks), onCleanup(() => {
gesture?.dispose(), gesture = null;
}));
}), () => gesture?.isDragging() ?? !1;
}
var DEFAULT_TAP_MOVE_THRESHOLD_PX, DEFAULT_DRAG_START_THRESHOLD_PX, DEFAULT_DRAG_INTENT_RATIO, VELOCITY_SAMPLE_WINDOW_MS, MOUSE_POINTER_ID, PointerGesture, init_chunk_V7QAVQKV = __esm({
"../reader/dist/chunk-V7QAVQKV.js"() {
"use strict";
init_chunk_PKBMQBKP();
init_solid();
DEFAULT_TAP_MOVE_THRESHOLD_PX = 8, DEFAULT_DRAG_START_THRESHOLD_PX = 8, DEFAULT_DRAG_INTENT_RATIO = 1, VELOCITY_SAMPLE_WINDOW_MS = 60, MOUSE_POINTER_ID = -1, PointerGesture = class {
constructor(target, callbacks) {
__publicField(this, "pinchPointers", /* @__PURE__ */ new Map()), __publicField(this, "drag", null), __publicField(this, "holdTimer", null), __publicField(this, "suppressClick", !1), __publicField(this, "suppressClickTimer", null), __publicField(this, "pinch", null), __publicField(this, "onDragStart", (event) => {
this.drag?.canDrag && event.preventDefault();
}), __publicField(this, "onClick", (event) => {
this.suppressClick && (this.clearClickSuppression(), event.preventDefault(), event.stopImmediatePropagation());
}), __publicField(this, "onClickSuppressionPointerDown", () => {
this.clearClickSuppression();
}), __publicField(this, "onContextMenu", () => {
this.drag?.active || (this.cancel(), this.clearPinch());
}), __publicField(this, "onPointerDown", (event) => {
if (event.pointerType === "mouse" && event.button !== 0 || this.trackPinchPointerDown(event) || this.pinch || this.drag)
return;
let callbacks2 = this.callbacks(), canDrag = callbacks2.shouldCaptureDrag?.(event) ?? !0;
(canDrag || (callbacks2.shouldObserveTap?.(event) ?? !1)) && (this.start(event.pointerId, event.pointerType, event.clientX, event.clientY, event, canDrag), event.pointerType === "mouse" ? (callbacks2.onMouseDown?.(event) && this.consumePress(), this.addMouseListeners()) : callbacks2.onNonMouseDown?.(event) && this.consumePress());
}), __publicField(this, "onMouseDown", (event) => {
event.button !== 0 || typeof PointerEvent < "u" || this.drag || !(this.callbacks().shouldCaptureDrag?.(event) ?? !0) || (this.start(MOUSE_POINTER_ID, "mouse", event.clientX, event.clientY, event, !0), this.callbacks().onMouseDown?.(event) && this.consumePress(), this.addMouseListeners());
}), __publicField(this, "onPointerMove", (event) => {
if (!(!this.drag || event.pointerId !== this.drag.pointerId || this.drag.pointerType === "mouse")) {
if (this.drag.canDrag && typeof event.getCoalescedEvents == "function") {
let coalesced = event.getCoalescedEvents();
for (let i = 0; i < coalesced.length - 1; i += 1) {
let sample = coalesced[i];
if (!this.drag || !sample) break;
this.updateLastMove(this.drag, sample.clientX, sample.clientY, sample);
}
}
this.move(event.clientX, event.clientY, event);
}
}), __publicField(this, "onPointerUp", (event) => {
!this.drag || event.pointerId !== this.drag.pointerId || (this.finish(event.clientX, event.clientY, event), this.releasePinchPointer(event));
}), __publicField(this, "onPointerCancel", (event) => {
!this.drag || event.pointerId !== this.drag.pointerId || (this.finish(event.clientX, event.clientY, event, !0), this.releasePinchPointer(event));
}), __publicField(this, "onMouseMove", (event) => {
!this.drag || this.drag.pointerType !== "mouse" || this.move(event.clientX, event.clientY, event);
}), __publicField(this, "onMouseUp", (event) => {
!this.drag || this.drag.pointerType !== "mouse" || this.finish(event.clientX, event.clientY, event);
}), __publicField(this, "onPinchPointerMove", (event) => {
if (!this.pinch || !this.pinchPointers.has(event.pointerId))
return;
this.pinchPointers.set(event.pointerId, {
clientX: event.clientX,
clientY: event.clientY
});
let snapshot = this.pinchSnapshot();
snapshot && (this.callbacks().onPinchMove?.({
...snapshot,
scale: snapshot.distance / this.pinch.startDistance
}, event), event.preventDefault());
}), __publicField(this, "onPinchPointerEnd", (event) => {
this.pinchPointers.has(event.pointerId) && (this.pinchPointers.delete(event.pointerId), !(!this.pinch || this.pinchPointers.size >= 2) && (this.callbacks().onPinchEnd?.(), this.clearPinch(), event.preventDefault()));
}), this.target = target, this.callbacks = callbacks, this.setDragging(!1), target.addEventListener("pointerdown", this.onPointerDown), target.addEventListener("mousedown", this.onMouseDown), target.addEventListener("dragstart", this.onDragStart), target.addEventListener("contextmenu", this.onContextMenu);
}
dispose() {
this.drag && this.releaseCapture(this.drag), this.drag = null, this.clearHold(), this.setDragging(!1), this.clearPinch(), this.removePointerListeners(), this.removeMouseListeners(), this.target.removeEventListener("pointerdown", this.onPointerDown), this.target.removeEventListener("mousedown", this.onMouseDown), this.target.removeEventListener("dragstart", this.onDragStart), this.target.removeEventListener("contextmenu", this.onContextMenu), this.clearClickSuppression();
}
isDragging() {
return this.drag?.active === !0;
}
cancel(preservePinchPointers = !1) {
let drag = this.drag;
drag && (this.releaseCapture(drag), preservePinchPointers || this.pinchPointers.delete(drag.pointerId), this.drag = null, this.clearHold(), this.setDragging(!1), this.removePointerListeners(), this.removeMouseListeners());
}
consumePress() {
this.clearHold(), this.drag && (this.drag.pressConsumed = !0, this.drag.tapCancelled = !0);
}
start(pointerId, pointerType, clientX, clientY, event, canDrag) {
this.drag = {
active: !1,
canDrag,
captureTarget: null,
pointerId,
pointerType,
pressConsumed: !1,
startClientX: clientX,
startClientY: clientY,
holdConsumed: !1,
startTarget: event.target,
tapCancelled: !1,
velocityX: 0,
velocityY: 0,
velocitySamples: [{
clientX,
clientY,
timeStamp: event.timeStamp
}]
};
let captureTarget = event.target;
canDrag && "pointerId" in event && typeof captureTarget?.setPointerCapture == "function" && (captureTarget.setPointerCapture(pointerId), this.drag.captureTarget = captureTarget), this.addPointerListeners(), this.startHold(this.drag, event);
}
move(clientX, clientY, event) {
let drag = this.drag;
if (!drag)
return;
if (drag.holdConsumed) {
event.preventDefault();
return;
}
let dx = clientX - drag.startClientX, dy = clientY - drag.startClientY, tapMoveThreshold = this.tapMoveThreshold();
if ((Math.abs(dx) >= tapMoveThreshold || Math.abs(dy) >= tapMoveThreshold) && (drag.tapCancelled = !0, this.clearHold()), !drag.canDrag) {
this.updateLastMove(drag, clientX, clientY, event);
return;
}
let intent = this.dragIntent(dx, dy);
if (!drag.active && intent === "cancel") {
this.cancel();
return;
}
if (!drag.active && intent !== "start") {
this.updateLastMove(drag, clientX, clientY, event);
return;
}
drag.active || this.activateDrag(drag, event), this.updateLastMove(drag, clientX, clientY, event), this.callbacks().onMove?.({
pointerId: drag.pointerId,
clientX,
clientY,
dx: clientX - drag.startClientX,
dy: clientY - drag.startClientY,
velocityX: drag.velocityX,
velocityY: drag.velocityY
}, event), event.preventDefault();
}
finish(clientX, clientY, event, cancelled = !1) {
let drag = this.drag;
if (!drag)
return;
this.drag = null, this.clearHold(), this.setDragging(!1), this.releaseCapture(drag), this.removePointerListeners(), this.removeMouseListeners(), !cancelled && drag.active && this.updateLastMove(drag, clientX, clientY, event);
let info = {
pointerId: drag.pointerId,
clientX,
clientY,
dx: clientX - drag.startClientX,
dy: clientY - drag.startClientY,
velocityX: drag.velocityX,
velocityY: drag.velocityY
};
if (drag.holdConsumed || drag.pressConsumed && !drag.active) {
this.suppressNextClick();
return;
}
let tapMoveThreshold = this.tapMoveThreshold(), isTap = !drag.tapCancelled && Math.abs(info.dx) < tapMoveThreshold && Math.abs(info.dy) < tapMoveThreshold;
if (!cancelled && !drag.active && isTap && this.callbacks().onTap?.({
...info,
startTarget: drag.startTarget
}, event), drag.active) {
if (cancelled) {
this.callbacks().onEnd?.({
...info,
dx: 0,
dy: 0,
velocityX: 0,
velocityY: 0
}, event);
return;
}
this.suppressNextClick(), this.callbacks().onEnd?.(info, event);
}
}
addPointerListeners() {
document.addEventListener("pointermove", this.onPointerMove, !0), document.addEventListener("pointerup", this.onPointerUp, !0), document.addEventListener("pointercancel", this.onPointerCancel, !0);
}
removePointerListeners() {
document.removeEventListener("pointermove", this.onPointerMove, !0), document.removeEventListener("pointerup", this.onPointerUp, !0), document.removeEventListener("pointercancel", this.onPointerCancel, !0);
}
addMouseListeners() {
window.addEventListener("mousemove", this.onMouseMove, !0), window.addEventListener("mouseup", this.onMouseUp, !0);
}
removeMouseListeners() {
window.removeEventListener("mousemove", this.onMouseMove, !0), window.removeEventListener("mouseup", this.onMouseUp, !0);
}
trackPinchPointerDown(event) {
let callbacks = this.callbacks();
if (!callbacks.onPinchStart || event.pointerType === "mouse" || (this.pinchPointers.set(event.pointerId, {
clientX: event.clientX,
clientY: event.clientY
}), this.pinch || this.pinchPointers.size !== 2))
return !1;
let snapshot = this.pinchSnapshot();
return snapshot ? callbacks.onPinchStart(snapshot, event) ? (this.cancel(!0), this.pinch = {
startDistance: snapshot.distance
}, this.addPinchListeners(), event.preventDefault(), event.stopPropagation(), !0) : (this.pinchPointers.delete(event.pointerId), !1) : !1;
}
addPinchListeners() {
document.addEventListener("pointermove", this.onPinchPointerMove, !0), document.addEventListener("pointerup", this.onPinchPointerEnd, !0), document.addEventListener("pointercancel", this.onPinchPointerEnd, !0);
}
removePinchListeners() {
document.removeEventListener("pointermove", this.onPinchPointerMove, !0), document.removeEventListener("pointerup", this.onPinchPointerEnd, !0), document.removeEventListener("pointercancel", this.onPinchPointerEnd, !0);
}
clearPinch() {
this.pinch = null, this.pinchPointers.clear(), this.removePinchListeners();
}
releasePinchPointer(event) {
this.pinch || this.pinchPointers.delete(event.pointerId);
}
pinchSnapshot() {
let points = Array.from(this.pinchPointers.values()), first = points[0], second = points[1];
if (!first || !second)
return null;
let dx = second.clientX - first.clientX, dy = second.clientY - first.clientY;
return {
clientX: (first.clientX + second.clientX) / 2,
clientY: (first.clientY + second.clientY) / 2,
distance: Math.hypot(dx, dy)
};
}
tapMoveThreshold() {
return this.callbacks().tapMoveThreshold ?? DEFAULT_TAP_MOVE_THRESHOLD_PX;
}
startHold(drag, event) {
let callbacks = this.callbacks();
callbacks.holdDelay === void 0 || !callbacks.onHold || (this.holdTimer = window.setTimeout(() => {
if (this.holdTimer = null, this.drag !== drag || drag.active || drag.tapCancelled)
return;
let result = this.callbacks().onHold?.({
clientX: drag.startClientX,
clientY: drag.startClientY,
pointerId: drag.pointerId
}, event);
result && (drag.tapCancelled = !0, result === "consume" ? drag.holdConsumed = !0 : this.activateDrag(drag, event));
}, callbacks.holdDelay));
}
clearHold() {
this.holdTimer !== null && (window.clearTimeout(this.holdTimer), this.holdTimer = null);
}
dragStartThreshold() {
return this.callbacks().dragStartThreshold ?? DEFAULT_DRAG_START_THRESHOLD_PX;
}
dragIntentRatio() {
return this.callbacks().dragIntentRatio ?? DEFAULT_DRAG_INTENT_RATIO;
}
dragAxis() {
return this.callbacks().dragAxis ?? "any";
}
dragIntent(dx, dy) {
let absX = Math.abs(dx), absY = Math.abs(dy), threshold = this.dragStartThreshold(), ratio = this.dragIntentRatio();
return this.dragAxis() === "x" ? absY >= threshold && absY > absX ? "cancel" : absX >= threshold && absX >= absY * ratio ? "start" : "pending" : this.dragAxis() === "y" ? absX >= threshold && absX > absY ? "cancel" : absY >= threshold && absY >= absX * ratio ? "start" : "pending" : Math.hypot(dx, dy) >= threshold ? "start" : "pending";
}
activateDrag(drag, event) {
drag.active = !0, this.setDragging(!0), drag.pointerType === "mouse" && window.getSelection()?.removeAllRanges(), this.callbacks().onStart?.({
pointerId: drag.pointerId,
clientX: drag.startClientX,
clientY: drag.startClientY
}, event), event.preventDefault();
}
updateLastMove(drag, clientX, clientY, event) {
drag.velocitySamples.push({
clientX,
clientY,
timeStamp: event.timeStamp
});
let cutoff = event.timeStamp - VELOCITY_SAMPLE_WINDOW_MS;
for (; drag.velocitySamples.length > 2 && (drag.velocitySamples[0]?.timeStamp ?? event.timeStamp) < cutoff; )
drag.velocitySamples.shift();
let first = drag.velocitySamples[0];
if (first) {
let elapsed = Math.max(1, event.timeStamp - first.timeStamp);
drag.velocityX = (clientX - first.clientX) / elapsed, drag.velocityY = (clientY - first.clientY) / elapsed;
}
}
suppressNextClick() {
this.suppressClick = !0, this.target.addEventListener("click", this.onClick, !0), this.target.addEventListener("mousedown", this.onClickSuppressionPointerDown, !0), this.target.addEventListener("pointerdown", this.onClickSuppressionPointerDown, !0), this.suppressClickTimer !== null && window.clearTimeout(this.suppressClickTimer), this.suppressClickTimer = window.setTimeout(() => {
this.clearClickSuppression();
}, 400);
}
clearClickSuppression() {
this.suppressClick = !1, this.target.removeEventListener("click", this.onClick, !0), this.target.removeEventListener("mousedown", this.onClickSuppressionPointerDown, !0), this.target.removeEventListener("pointerdown", this.onClickSuppressionPointerDown, !0), this.suppressClickTimer !== null && (window.clearTimeout(this.suppressClickTimer), this.suppressClickTimer = null);
}
setDragging(dragging) {
this.target.dataset.dragging = String(dragging);
}
releaseCapture(drag) {
drag.captureTarget?.hasPointerCapture(drag.pointerId) && drag.captureTarget.releasePointerCapture(drag.pointerId);
}
};
}
});
// ../reader/dist/kit/PointerGesture.js
var init_PointerGesture = __esm({
"../reader/dist/kit/PointerGesture.js"() {
"use strict";
init_chunk_V7QAVQKV();
init_chunk_PKBMQBKP();
}
});
// src/components/Enhance/PageSwipe.tsx
function PageSwipe(props) {
let [indicator, setIndicator] = createSignal({
blocked: !1,
direction: "left",
progress: 0
}), directionFor = (dx) => dx < 0 ? "next" : "previous", reset2 = () => setIndicator((current) => ({
...current,
blocked: !1,
progress: 0
}));
return createPointerGestureElement(() => props.target(), () => ({
onStart: reset2,
onMove: (info) => {
let direction = directionFor(info.dx);
setIndicator({
blocked: !props.canNavigate(direction),
direction: direction === "next" ? "left" : "right",
progress: Math.min(1, Math.max(0, (Math.abs(info.dx) - SWIPE_INTENT_DISTANCE) / (SWIPE_MIN_DISTANCE - SWIPE_INTENT_DISTANCE)))
});
},
onEnd: (info, event) => {
navigate(info, event), reset2();
},
dragAxis: "x",
dragIntentRatio: HORIZONTAL_INTENT_RATIO,
dragStartThreshold: SWIPE_INTENT_DISTANCE
})), createComponent(SwipeIndicator, {
get state() {
return indicator();
}
});
function navigate(info, event) {
let absX = Math.abs(info.dx), absY = Math.abs(info.dy), direction = directionFor(info.dx);
absX < SWIPE_MIN_DISTANCE || absY > absX * SWIPE_MAX_VERTICAL_RATIO || !props.canNavigate(direction) || (event.preventDefault(), props.onNavigate(direction));
}
}
var SWIPE_MIN_DISTANCE, SWIPE_INTENT_DISTANCE, HORIZONTAL_INTENT_RATIO, SWIPE_MAX_VERTICAL_RATIO, init_PageSwipe = __esm({
"src/components/Enhance/PageSwipe.tsx"() {
"use strict";
init_web();
init_solid();
init_PointerGesture();
init_Widgets();
SWIPE_MIN_DISTANCE = 96, SWIPE_INTENT_DISTANCE = 28, HORIZONTAL_INTENT_RATIO = 2.2, SWIPE_MAX_VERTICAL_RATIO = 0.38;
}
});
// src/components/Enhance/EnhanceSearchGrids.tsx
function EnhanceSearchGrids(props) {
let [gestureTarget, setGestureTarget] = createSignal(null), [loading, setLoading] = createSignal(!1), source = untrack(() => props.source), navigationController = null, swipeUrl = (direction) => source.handle.readNavigationUrl(direction === "next" ? "next" : "previous"), navigate = async (url, options) => {
if (navigationController && !options.replacePending)
return;
navigationController?.abort();
let controller = new AbortController();
navigationController = controller;
let loadingSource = source;
setLoading(!0), loadingSource.handle.updateSearchLoading(!0);
try {
if (await loadingSource.handle.loadSearchPage(url, controller.signal), controller.signal.aborted)
return;
let nextSource = manageSearchResults();
if (!nextSource)
throw new Error(activeTexts.errors.searchPageContentNotFound);
options.pushHistory && window.history.pushState(window.history.state, "", url), source = nextSource, props.onPageChange(source), source.handle.ensureSearchSwipeInput(), setGestureTarget(source.elems.resultList.Component()), source.handle.scrollSearchPageToInput();
} catch (error) {
controller.signal.aborted || console.error("[ehpeek]", error);
} finally {
loadingSource.handle.updateSearchLoading(!1), navigationController === controller && (navigationController = null, setLoading(!1));
}
}, onNavigation = (url) => {
navigate(url, {
pushHistory: !0
});
};
return onMount(() => {
let previousScrollRestoration = window.history.scrollRestoration, onHistoryNavigation = () => {
navigate(window.location.href, {
pushHistory: !1,
replacePending: !0
});
};
window.history.scrollRestoration = "manual", source.handle.ensureSearchSwipeInput(), setGestureTarget(source.elems.resultList.Component()), window.addEventListener("popstate", onHistoryNavigation), onCleanup(source.handle.interceptSearchNavigation(onNavigation)), onCleanup(() => {
navigationController?.abort(), window.removeEventListener("popstate", onHistoryNavigation), window.history.scrollRestoration = previousScrollRestoration;
});
}), [createComponent(PageSwipe, {
canNavigate: (direction) => !!swipeUrl(direction),
onNavigate: (direction) => {
let url = swipeUrl(direction);
url && navigate(url, {
pushHistory: !0
});
},
target: gestureTarget
}), createComponent(LoadingOverlay, {
get label() {
return activeTexts.common.status.loading;
},
get visible() {
return loading();
}
})];
}
var init_EnhanceSearchGrids = __esm({
"src/components/Enhance/EnhanceSearchGrids.tsx"() {
"use strict";
init_web();
init_solid();
init_eh();
init_i18n2();
init_Loading();
init_PageSwipe();
}
});
// src/App/searchScroll.ts
function currentScrollY() {
return window.scrollY || document.documentElement.scrollTop || document.body.scrollTop || 0;
}
function readSaved() {
try {
let raw = sessionStorage.getItem(STORAGE_KEY);
if (!raw)
return null;
let parsed = JSON.parse(raw);
if (typeof parsed.url == "string" && typeof parsed.y == "number")
return { url: parsed.url, y: parsed.y };
} catch {
}
return null;
}
function writeSaved() {
try {
let value = { url: window.location.href, y: currentScrollY() };
sessionStorage.setItem(STORAGE_KEY, JSON.stringify(value));
} catch {
}
}
function clearSaved() {
try {
sessionStorage.removeItem(STORAGE_KEY);
} catch {
}
}
function restore() {
let saved = readSaved();
if (!saved || saved.url !== window.location.href || saved.y <= 0)
return;
let frames = 0, aborted = !1, abort = () => {
aborted = !0;
}, abortEvents = ["wheel", "touchmove", "keydown", "pointerdown"];
for (let type of abortEvents)
window.addEventListener(type, abort, { once: !0, passive: !0 });
let cleanupAbort = () => {
for (let type of abortEvents)
window.removeEventListener(type, abort);
}, tick = () => {
if (aborted) {
cleanupAbort();
return;
}
if (window.scrollTo(0, saved.y), frames += 1, currentScrollY() < saved.y - 2 && frames < 60) {
requestAnimationFrame(tick);
return;
}
clearSaved(), cleanupAbort();
};
requestAnimationFrame(tick);
}
function installSearchScrollMemory() {
restore();
let onHide = () => writeSaved(), onVisibility = () => {
document.visibilityState === "hidden" && writeSaved();
}, onPageShow = () => restore();
return window.addEventListener("pagehide", onHide), document.addEventListener("visibilitychange", onVisibility), window.addEventListener("pageshow", onPageShow), () => {
window.removeEventListener("pagehide", onHide), document.removeEventListener("visibilitychange", onVisibility), window.removeEventListener("pageshow", onPageShow);
};
}
var STORAGE_KEY, init_searchScroll = __esm({
"src/App/searchScroll.ts"() {
"use strict";
STORAGE_KEY = "ehpeek:search-scroll";
}
});
// ../reader/dist/chunk-JM34DFW3.js
function ReaderPreviewNavi(views) {
return {
async openReader(pageNum, configuredFullscreen = !1) {
let top = views.top();
(top === "overlay-preview" || top === "embedded-preview") && await views.closePreview(!1), await views.openReader(pageNum, configuredFullscreen);
},
openPreview(pageNum, fromReader = !1) {
fromReader && views.focusPreview(pageNum), views.openPreview(pageNum, fromReader ? views.previewMode() : "overlay");
},
back() {
let top = views.top();
return top ? ((top === "reader" ? views.closeReader() : views.closePreview(!0)).catch(views.onError), !0) : !1;
},
closeAll() {
views.closeReader().catch(views.onError);
}
};
}
var init_chunk_JM34DFW3 = __esm({
"../reader/dist/chunk-JM34DFW3.js"() {
"use strict";
}
});
// ../reader/dist/chunk-UVKXFJHK.js
var DEFAULT_CONCURRENT_LOADS, PriorityLoadQueue, init_chunk_UVKXFJHK = __esm({
"../reader/dist/chunk-UVKXFJHK.js"() {
"use strict";
DEFAULT_CONCURRENT_LOADS = 6, PriorityLoadQueue = class {
constructor(concurrentLoads = DEFAULT_CONCURRENT_LOADS) {
this.concurrentLoads = concurrentLoads, this.pending = /* @__PURE__ */ new Map(), this.active = /* @__PURE__ */ new Set(), this.timer = null, this.disposed = !1, this.callbacks = {};
}
updateCallbacks(callbacks) {
this.callbacks = callbacks, this.schedule();
}
dispose() {
this.disposed = !0, this.pending.clear(), this.timer !== null && (window.clearTimeout(this.timer), this.timer = null);
}
sync(targets) {
this.pending = new Map(targets.filter(({ key }) => !this.active.has(key)).map((target) => [target.key, target])), this.schedule();
}
schedule() {
this.timer !== null || this.disposed || !this.callbacks.loadTarget || (this.timer = window.setTimeout(() => {
this.timer = null, this.process();
}, 0));
}
process() {
if (!this.disposed)
for (; this.active.size < this.concurrentLoads; ) {
let next = Array.from(this.pending.values()).sort((left, right) => left.priority - right.priority)[0];
if (!next)
return;
this.pending.delete(next.key), this.start(next);
}
}
start({ key, target }) {
let { loadTarget, markLoading, onLoaded, onError } = this.callbacks;
if (!loadTarget || !markLoading || !onLoaded || !onError)
return;
let token = markLoading(target);
token !== null && (this.active.add(key), loadTarget(target).then(async (loaded) => {
this.disposed || await onLoaded(target, loaded, token);
}).catch((error) => {
this.disposed || onError(target, error, token);
}).finally(() => {
this.active.delete(key), this.process();
}));
}
};
}
});
// ../reader/dist/chunk-I2UURCWR.js
function imageFileExtension(imageUrl) {
try {
let extension = decodeURIComponent(new URL(imageUrl).pathname.split("/").pop() ?? "").match(/\.([a-z0-9]{2,5})$/i)?.[1]?.toLowerCase();
if (extension && ["avif", "bmp", "gif", "jpeg", "jpg", "png", "webp"].includes(extension))
return extension;
} catch {
return "";
}
return "";
}
function createImageLoadBudget(maxBytes, minConcurrentLoads) {
let waiters = [], activeBytes = 0, activeLoads = 0, drain = () => {
let next = waiters[0];
if (!next || activeLoads >= minConcurrentLoads && activeBytes + next.bytes > maxBytes)
return;
waiters.shift(), activeBytes += next.bytes, activeLoads += 1;
let released = !1;
next.resolve(() => {
released || (released = !0, activeBytes = Math.max(0, activeBytes - next.bytes), activeLoads = Math.max(0, activeLoads - 1), drain());
}), drain();
};
return (bytes) => new Promise((resolve) => {
waiters.push({ bytes, resolve }), drain();
});
}
var LOADED_IMAGE_INFO_CACHE_LIMIT, CONCURRENT_IMAGE_BYTE_LIMIT, MIN_CONCURRENT_IMAGE_LOADS, ReaderImages, init_chunk_I2UURCWR = __esm({
"../reader/dist/chunk-I2UURCWR.js"() {
"use strict";
init_chunk_UVKXFJHK();
init_chunk_E6UKP7HT();
LOADED_IMAGE_INFO_CACHE_LIMIT = 160, CONCURRENT_IMAGE_BYTE_LIMIT = 6 * 1024 * 1024, MIN_CONCURRENT_IMAGE_LOADS = 3, ReaderImages = class {
constructor(source, concurrentLoads) {
this.source = source, this.controller = new AbortController(), this.loaded = /* @__PURE__ */ new Map(), this.acquireBudget = createImageLoadBudget(
CONCURRENT_IMAGE_BYTE_LIMIT,
MIN_CONCURRENT_IMAGE_LOADS
), this.queue = new PriorityLoadQueue(concurrentLoads);
}
get(pageNum) {
return this.loaded.get(pageNum);
}
touch(pageNum) {
let image2 = this.loaded.get(pageNum);
image2 && (this.loaded.delete(pageNum), this.loaded.set(pageNum, image2));
}
load(target) {
return Promise.resolve(
this.loaded.get(target.pageNum) ?? this.source.loadImage(target.page, this.controller.signal)
);
}
remember(pageNum, loaded) {
let image2 = {
...loaded,
pageNum,
imageUrl: loaded.imageUrl,
originalImageUrl: loaded.originalImageUrl ?? null,
width: positiveNumber(loaded.width),
height: positiveNumber(loaded.height)
};
for (this.loaded.delete(pageNum), this.loaded.set(pageNum, image2); this.loaded.size > LOADED_IMAGE_INFO_CACHE_LIMIT; ) {
let oldest = this.loaded.keys().next().value;
if (oldest === void 0) break;
this.loaded.delete(oldest);
}
return image2;
}
reserveDecode(byteSize) {
return this.acquireBudget(byteSize ?? CONCURRENT_IMAGE_BYTE_LIMIT);
}
dispose() {
this.controller.abort(), this.queue.dispose();
}
};
}
});
// ../reader/dist/chunk-GUZXW3OF.js
function doublePagePairStart(pageNum, firstPageSeparate) {
return firstPageSeparate ? pageNum <= 1 ? 1 : pageNum - pageNum % 2 : pageNum % 2 === 0 ? pageNum - 1 : pageNum;
}
function normalizeReadingPage(page2, total, mode, layout, separate) {
let target = clamp(Math.round(page2), 1, total ? total + 1 : Number.MAX_SAFE_INTEGER);
return mode === "paged" && layout === "double" && (!total || target !== total + 1) ? doublePagePairStart(target, separate) : target;
}
function nextReadingPage(page2, step, total, layout, separate) {
let delta = step;
return layout === "double" && (total && page2 === total + 1 && step < 0 ? delta = doublePagePairStart(total, separate) - page2 : separate && page2 === 1 && step > 0 ? delta = 1 : separate && page2 === 2 && step < 0 ? delta = -1 : delta = step * 2), clamp(page2 + delta, 1, total ? total + 1 : Number.MAX_SAFE_INTEGER);
}
function pageWindowNumbers(currentPageNum, windowSize) {
let numbers = [];
for (let offset = -windowSize; offset <= windowSize; offset += 1)
numbers.push(currentPageNum + offset);
return numbers;
}
function containFitScale(imageWidth, imageHeight, viewportWidth, viewportHeight) {
return Math.min(
Math.max(1, viewportWidth) / Math.max(1, imageWidth),
Math.max(1, viewportHeight) / Math.max(1, imageHeight)
);
}
function containFitFrame(aspectRatio, viewportWidth, viewportHeight, scale = 1) {
let width = Math.max(1, Math.min(
Math.max(1, viewportWidth),
Math.max(1, viewportHeight) / aspectRatio
) * scale);
return { height: width * aspectRatio, width };
}
function pageFrameSize(options) {
let { aspectRatio, viewportWidth, viewportHeight, navigationMode, pageLayout, sizeScale, reference, referenceAspectRatio, horizontal } = options;
if (navigationMode === "paged") {
let availableWidth = pageLayout === "double" ? Math.max(1, (viewportWidth - 3) / 2) : viewportWidth;
return options.contentPage ? containFitFrame(aspectRatio, availableWidth, viewportHeight) : { width: availableWidth, height: viewportHeight };
}
let scaleMultiplier = sizeScale === "one-to-one" && reference ? 1 / containFitScale(
reference.width,
reference.height,
viewportWidth,
viewportHeight
) : typeof sizeScale == "number" ? sizeScale : 1, referenceFrame = sizeScale === "fill" ? horizontal ? {
height: viewportHeight,
width: viewportHeight / referenceAspectRatio
} : {
height: viewportWidth * referenceAspectRatio,
width: viewportWidth
} : containFitFrame(
referenceAspectRatio,
viewportWidth,
viewportHeight,
scaleMultiplier
);
return horizontal ? { height: referenceFrame.height, width: referenceFrame.height / aspectRatio } : { width: referenceFrame.width, height: referenceFrame.width * aspectRatio };
}
var init_chunk_GUZXW3OF = __esm({
"../reader/dist/chunk-GUZXW3OF.js"() {
"use strict";
init_chunk_E6UKP7HT();
}
});
// ../reader/dist/chunk-I4HV7TJW.js
function createReaderLoading(options) {
let texts = useReaderTexts(), controller = new AbortController(), images = new ReaderImages(options.source, options.concurrentLoads), resources = /* @__PURE__ */ new Map(), retained = /* @__PURE__ */ new Map(), renderSize = options.renderWindowSize ?? 10, preloadSize = options.preloadWindowSize ?? 10, cacheLimit = Math.max(0, Math.floor(options.decodedImageCacheLimit ?? 24)), disposed = !1, direction = 1, directionEdge = options.requestedPage(), stopped = () => disposed || options.closing(), isContent = (page2) => page2 >= 1 && (!options.source.totalPages || page2 <= options.source.totalPages), windowPages = createMemo(() => pageWindowNumbers(options.requestedPage(), renderSize)), entry = (page2) => {
let resource = resources.get(page2);
return resource || (resource = createResource(), resources.set(page2, resource)), resource;
};
function update(page2, patch) {
entry(page2).set((value) => ({
...value,
...patch
}));
}
async function requestPage2(pageNum) {
let resource = entry(pageNum);
if (!(resource.value().page || resource.value().status !== "idle" || stopped())) {
update(pageNum, {
status: "loading",
error: null
});
try {
let incoming = await options.source.getPages([pageNum], controller.signal);
if (stopped()) return;
let page2 = incoming.find((page22) => page22.pageNum === pageNum);
if (!page2) throw new Error(texts.errors.imageNotFound);
update(pageNum, {
page: {
...page2,
aspectRatio: normalizedAspectRatio(page2.aspectRatio, 1.42)
},
status: "idle"
}), options.seeking() || maintainQueue();
} catch (error) {
stopped() || update(pageNum, {
status: "error",
error: error instanceof Error ? error.message : texts.errors.loadFailed
});
}
}
}
function maintainQueue() {
if (stopped() || options.seeking()) return;
let first = options.firstVisiblePage() ?? options.requestedPage(), movement = (first - directionEdge) * direction;
movement >= 0 ? directionEdge = first : -movement > 2 && (direction = direction === 1 ? -1 : 1, directionEdge = first);
let targets = [...options.priorityPages(), first];
for (let offset = 1; offset <= preloadSize; offset++) targets.push(first + offset * direction);
targets.push(first - direction), images.queue.sync([...new Set(targets)].flatMap((pageNum, priority) => {
let resource = resources.get(pageNum)?.value();
return resource?.page && resource.status === "idle" ? [{
key: pageNum,
priority,
target: {
pageNum,
page: resource.page
}
}] : [];
}));
}
function retainOffWindow() {
let visible = new Set(windowPages());
for (let [page2, resource] of resources) {
let element = resource.value().element;
visible.has(page2) ? retained.delete(page2) : element && resource.value().status === "ready" && !retained.has(page2) && retained.set(page2, (element.naturalWidth || element.width) * (element.naturalHeight || element.height) * 4);
}
let bytes = [...retained.values()].reduce((sum, value) => sum + value, 0);
for (; retained.size > cacheLimit || bytes > 96 * 1024 * 1024; ) {
let oldest = retained.entries().next().value;
if (!oldest) break;
retained.delete(oldest[0]), bytes -= oldest[1], entry(oldest[0]).value().element?.removeAttribute("src"), update(oldest[0], {
element: null,
image: null,
status: "idle"
});
}
}
return images.queue.updateCallbacks({
loadTarget: (target) => images.load(target),
markLoading: (target) => stopped() || entry(target.pageNum).value().status !== "idle" ? null : (update(target.pageNum, {
status: "loading",
error: null
}), 0),
onLoaded: async (target, loaded) => {
if (stopped()) return;
let image2 = images.remember(target.pageNum, loaded);
if (!windowPages().includes(target.pageNum)) {
update(target.pageNum, {
status: "idle"
});
return;
}
update(target.pageNum, {
image: image2
});
let release = await images.reserveDecode(image2.byteSize);
try {
if (stopped()) return;
if (!windowPages().includes(target.pageNum)) {
update(target.pageNum, {
image: null,
status: "idle"
});
return;
}
let alt = `Page ${target.pageNum}`, fetchPriority = options.priorityPages().includes(target.pageNum) ? "high" : "low", width = image2.width && image2.height ? image2.width : void 0, height = image2.width && image2.height ? image2.height : void 0, element;
untrack(() => (() => {
var _el$ = _tmpl$12(), _ref$ = element;
return typeof _ref$ == "function" ? use(_ref$, _el$) : element = _el$, setAttribute(_el$, "alt", alt), setAttribute(_el$, "draggable", !1), setAttribute(_el$, "fetchpriority", fetchPriority), setAttribute(_el$, "width", width), setAttribute(_el$, "height", height), _el$;
})());
let progressive = image2.displayWhileLoading ?? (imageFileExtension(image2.imageUrl) === "gif" || imageFileExtension(image2.originalImageUrl ?? "") === "gif" || (image2.byteSize ?? 0) > 2 * 1024 * 1024), ready = loadImage(element, image2.imageUrl, controller.signal, texts.errors.imageLoadFailed);
if (progressive && update(target.pageNum, {
element
}), await ready, stopped()) return;
update(target.pageNum, {
element,
status: "ready",
error: null
}), retainOffWindow();
} finally {
release();
}
},
onError: (target, error) => {
if (stopped()) return;
entry(target.pageNum).value().element?.removeAttribute("src"), update(target.pageNum, {
element: null,
image: null,
status: "error",
error: error instanceof Error ? error.message : texts.errors.imageLoadFailed
});
}
}), createEffect(on([windowPages, options.seeking, options.closing], () => {
if (!stopped()) {
if (retainOffWindow(), options.seeking()) {
images.queue.sync([]);
return;
}
for (let page2 of windowPages().filter(isContent)) requestPage2(page2);
maintainQueue();
}
})), createEffect(on([options.firstVisiblePage, options.priorityPages], () => maintainQueue())), onCleanup(() => {
disposed = !0, controller.abort(), images.dispose();
for (let resource of resources.values()) resource.value().element?.removeAttribute("src");
resources.clear(), retained.clear();
}), {
windowPages,
page: (pageNum) => isContent(pageNum) ? entry(pageNum).value() : void 0,
retry(pageNum) {
stopped() || entry(pageNum).value().status !== "error" || untrack(() => {
update(pageNum, {
status: "idle",
error: null
}), entry(pageNum).value().page ? maintainQueue() : requestPage2(pageNum);
});
}
};
}
function createResource() {
let [value, set] = createSignal({
page: null,
image: null,
element: null,
status: "idle",
error: null
});
return {
value,
set
};
}
async function loadImage(image2, url, signal, message) {
await new Promise((resolve, reject) => {
let cleanup = () => {
image2.removeEventListener("load", loaded), image2.removeEventListener("error", failed), signal.removeEventListener("abort", aborted);
}, loaded = () => {
cleanup(), resolve();
}, failed = () => {
cleanup(), reject(new Error(message));
}, aborted = () => {
image2.removeAttribute("src"), cleanup(), reject(signal.reason);
};
image2.addEventListener("load", loaded), image2.addEventListener("error", failed), signal.addEventListener("abort", aborted, {
once: !0
}), image2.src = url, image2.complete && image2.naturalWidth > 0 && loaded();
});
try {
await image2.decode();
} catch {
}
}
var _tmpl$12, init_chunk_I4HV7TJW = __esm({
"../reader/dist/chunk-I4HV7TJW.js"() {
"use strict";
init_chunk_I2UURCWR();
init_chunk_GUZXW3OF();
init_chunk_JXES5MWD();
init_chunk_E6UKP7HT();
init_web();
init_web();
init_web();
init_solid();
_tmpl$12 = /* @__PURE__ */ template("<img class=ehpeek-reader-page-image decoding=async loading=eager>", !0, !1, !1);
}
});
// ../reader/dist/chunk-PBZTMYEM.js
function bindInteractionGate(element, disabled) {
createEffect(() => {
let root = element();
if (!disabled()) return;
root.inert = !0;
let focused = document.activeElement;
focused instanceof HTMLElement && root.contains(focused) && focused.blur();
let block = (event) => {
event.preventDefault(), event.stopImmediatePropagation();
}, events = [
"click",
"dblclick",
"pointerdown",
"pointermove",
"pointerup",
"pointercancel",
"mousedown",
"mouseup",
"touchstart",
"touchmove",
"wheel",
"keydown",
"input",
"change",
"contextmenu"
];
for (let event of events) root.addEventListener(event, block, { capture: !0, passive: !1 });
onCleanup(() => {
root.inert = !1;
for (let event of events) root.removeEventListener(event, block, !0);
});
});
}
var init_chunk_PBZTMYEM = __esm({
"../reader/dist/chunk-PBZTMYEM.js"() {
"use strict";
init_solid();
}
});
// ../reader/dist/chunk-FRCEUGG2.js
function createReadProgressPublisher() {
let listeners = /* @__PURE__ */ new Set();
return {
subscribe(listener) {
return listeners.add(listener), () => {
listeners.delete(listener);
};
},
publish(pageNum) {
for (let listener of listeners) listener(pageNum);
}
};
}
var ReadProgressSyncer, init_chunk_FRCEUGG2 = __esm({
"../reader/dist/chunk-FRCEUGG2.js"() {
"use strict";
ReadProgressSyncer = class {
constructor(source, target) {
this.disconnect = source.subscribe(
(pageNum) => target.setProgress(pageNum)
);
}
dispose() {
this.disconnect();
}
};
}
});
// ../reader/dist/chunk-WWFOV7YA.js
function createReaderSettings(initial = {}, callbacks = {}) {
return {
portraitControls: createOrientationSettings(initial.portraitControls, callbacks.portraitControls),
landscapeControls: createOrientationSettings(initial.landscapeControls, callbacks.landscapeControls),
scrollTtbScale: createSettingItem(
initial.scrollTtbScale === void 0 ? "fill" : initial.scrollTtbScale,
callbacks.scrollTtbScale
),
scrollHorizontalScale: createSettingItem(
initial.scrollHorizontalScale === void 0 ? "fill" : initial.scrollHorizontalScale,
callbacks.scrollHorizontalScale
),
leftHandedControls: createSettingItem(initial.leftHandedControls ?? !1, callbacks.leftHandedControls),
previewDirection: createSettingItem(initial.previewDirection ?? "ttb", callbacks.previewDirection),
embeddedPreviewDirection: createSettingItem(initial.embeddedPreviewDirection ?? "rtl", callbacks.embeddedPreviewDirection)
};
}
function createOrientationSettings(initial = defaultControls, onChange) {
let notify = () => onChange?.(untrack(() => ({
navigationMode: settings2.navigationMode.value(),
scrollDirection: settings2.scrollDirection.value(),
pagedDirection: settings2.pagedDirection.value(),
pageLayout: settings2.pageLayout.value(),
rightTapAction: settings2.rightTapAction.value()
}))), settings2 = {
navigationMode: createSettingItem(initial.navigationMode, notify),
scrollDirection: createSettingItem(initial.scrollDirection, notify),
pagedDirection: createSettingItem(initial.pagedDirection, notify),
pageLayout: createSettingItem(initial.pageLayout, notify),
rightTapAction: createSettingItem(initial.rightTapAction, notify)
};
return settings2;
}
function createSettingItem(initial, onChange) {
let [value, setValue] = createSignal(initial);
return {
value,
set(next) {
Object.is(untrack(value), next) || (setValue(() => next), onChange?.(next));
}
};
}
function currentReaderOrientation() {
return window.matchMedia("(orientation: landscape)").matches ? "landscape" : "portrait";
}
function normalizeReaderScrollSizeScale(scale) {
return Number.isFinite(scale) ? Math.min(100, Math.max(1e-3, scale)) : 1;
}
var defaultControls, init_chunk_WWFOV7YA = __esm({
"../reader/dist/chunk-WWFOV7YA.js"() {
"use strict";
init_solid();
defaultControls = {
navigationMode: "scroll",
scrollDirection: "ttb",
pagedDirection: "rtl",
pageLayout: "single",
rightTapAction: "previous"
};
}
});
// ../reader/dist/chunk-TRAUK5J2.js
function useReaderContext() {
let ctx = useContext(ReaderContextKey);
if (!ctx) throw new Error("Reader components require Reader context");
return ctx;
}
function getReaderControls(ctx) {
let settings2 = ctx.settings[`${ctx.orientation()}Controls`], navigationMode = settings2.navigationMode.value();
return {
navigationMode,
direction: navigationMode === "scroll" ? settings2.scrollDirection.value() : settings2.pagedDirection.value(),
pageLayout: settings2.pageLayout.value(),
rightTapAction: settings2.rightTapAction.value(),
firstPageSeparate: ctx.firstPageSeparate[0]()
};
}
var ReaderContextKey, init_chunk_TRAUK5J2 = __esm({
"../reader/dist/chunk-TRAUK5J2.js"() {
"use strict";
init_solid();
ReaderContextKey = createContext();
}
});
// ../reader/dist/chunk-CK6USHZG.js
function createReaderScrollScale(options) {
let [ttb, setTtb] = createSignal(untrack(options.settings.scrollTtbScale.value)), [horizontal, setHorizontal] = createSignal(untrack(options.settings.scrollHorizontalScale.value)), [adjusting, setAdjusting] = createSignal(!1), value = () => options.direction() === "ttb" ? ttb() : horizontal(), setValue = (next) => options.direction() === "ttb" ? setTtb(next) : setHorizontal(next), adjustmentStart = untrack(value);
createEffect(on(options.settings.scrollTtbScale.value, setTtb)), createEffect(on(options.settings.scrollHorizontalScale.value, setHorizontal));
let fitScale = () => {
let image2 = options.referenceImageSize(), viewport = options.viewportSize();
return image2 && viewport ? containFitScale(image2.width, image2.height, viewport.width, viewport.height) : null;
};
return {
referenceImageSize: options.referenceImageSize,
value,
adjusting,
percent() {
if (value() === "one-to-one") return 100;
let image2 = options.referenceImageSize(), viewport = options.viewportSize();
if (value() === "fill") return image2 && viewport ? (options.direction() === "ttb" ? viewport.width / image2.width : viewport.height / image2.height) * 100 : null;
let fit = fitScale(), current = value();
return fit ? (typeof current == "number" ? current : 1) * fit * 100 : null;
},
open() {
adjustmentStart = value(), setAdjusting(!0);
},
resize(imageScale) {
let fit = fitScale();
fit && setValue(normalizeReaderScrollSizeScale(imageScale / fit));
},
selectPreset(preset) {
setValue(preset === "fit" ? null : preset);
},
apply() {
setAdjusting(!1);
},
applyGlobally() {
(options.direction() === "ttb" ? options.settings.scrollTtbScale : options.settings.scrollHorizontalScale).set(value()), setAdjusting(!1);
},
cancel() {
setValue(adjustmentStart), setAdjusting(!1);
}
};
}
function ReaderScrollScaleControls() {
let ctx = useReaderContext(), scale = ctx.scrollScale, scaleMode = () => scale.value() === null ? "fit" : typeof scale.value() == "number" ? "custom" : scale.value(), percentLabel = () => {
let percent = scale.percent();
return percent === null ? "—" : `${Math.round(percent)}%`;
}, texts = useReaderTexts(), pointers = /* @__PURE__ */ new Map(), pinchStart = null, interactionLayer, sliderPercent = () => Math.min(MAX_SCALE_PERCENT, Math.max(MIN_SCALE_PERCENT, scale.percent() ?? 100)), clampScale = (scale2) => Math.min(MAX_SCALE_PERCENT / 100, Math.max(MIN_SCALE_PERCENT / 100, scale2)), stopInteraction = (event) => {
event.preventDefault(), event.stopPropagation();
}, endPointer = (event) => {
pointers.delete(event.pointerId), pointers.size < 2 && (pinchStart = null);
};
return createEffect(() => {
if (!scale.adjusting() || ctx.disabled()) {
for (let id2 of pointers.keys())
interactionLayer.hasPointerCapture(id2) && interactionLayer.releasePointerCapture(id2);
pointers.clear(), pinchStart = null;
}
}), createComponent(Show, {
get when() {
return scale.adjusting();
},
get children() {
return [(() => {
var _el$ = _tmpl$13();
_el$.addEventListener("pointercancel", endPointer), _el$.$$pointerup = endPointer, _el$.$$pointermove = (event) => {
if (!pointers.has(event.pointerId) || (pointers.set(event.pointerId, {
x: event.clientX,
y: event.clientY
}), !pinchStart || pointers.size < 2))
return;
let [first, second] = Array.from(pointers.values());
if (!first || !second)
return;
let distance = Math.hypot(second.x - first.x, second.y - first.y);
scale.resize(clampScale(pinchStart.scale * distance / pinchStart.distance));
}, _el$.$$pointerdown = (event) => {
if (stopInteraction(event), pointers.set(event.pointerId, {
x: event.clientX,
y: event.clientY
}), interactionLayer.setPointerCapture(event.pointerId), pointers.size !== 2)
return;
let [first, second] = Array.from(pointers.values());
!first || !second || (pinchStart = {
distance: Math.max(1, Math.hypot(second.x - first.x, second.y - first.y)),
scale: (scale.percent() ?? 100) / 100
});
}, _el$.addEventListener("wheel", (event) => {
stopInteraction(event);
let deltaPixels = event.deltaY * (event.deltaMode === WheelEvent.DOM_DELTA_LINE ? 16 : event.deltaMode === WheelEvent.DOM_DELTA_PAGE ? interactionLayer.clientHeight : 1);
scale.resize(clampScale((scale.percent() ?? 100) / 100 * Math.exp(-deltaPixels * 15e-4)));
}), _el$.$$click = stopInteraction;
var _ref$ = interactionLayer;
return typeof _ref$ == "function" ? use(_ref$, _el$) : interactionLayer = _el$, _el$;
})(), (() => {
var _el$2 = _tmpl$34(), _el$3 = _el$2.firstChild, _el$4 = _el$3.firstChild, _el$6 = _el$4.firstChild, _el$7 = _el$4.nextSibling, _el$8 = _el$3.nextSibling, _el$9 = _el$8.nextSibling;
return insert(_el$4, createComponent(Show, {
get when() {
return scaleMode() !== "custom";
},
get children() {
var _el$5 = _tmpl$26();
return insert(_el$5, (() => {
var _c$ = memo(() => scaleMode() === "fit");
return () => _c$() ? texts.reader.fit : memo(() => scaleMode() === "fill")() ? texts.reader.fill : "1:1";
})()), _el$5;
}
}), _el$6), insert(_el$6, percentLabel), _el$7.$$input = (event) => scale.resize(event.currentTarget.valueAsNumber / 100), insert(_el$8, createComponent(Button, {
onClick: () => scale.selectPreset("fit"),
get children() {
return texts.reader.fit;
}
}), null), insert(_el$8, createComponent(Button, {
onClick: () => scale.selectPreset("fill"),
get children() {
return texts.reader.fill;
}
}), null), insert(_el$8, createComponent(Button, {
onClick: () => scale.selectPreset("one-to-one"),
children: "1:1"
}), null), insert(_el$9, createComponent(Button, {
class: "ehpeek-reader-scale-apply-all",
onClick: () => scale.applyGlobally(),
get children() {
return texts.reader.applyGlobally;
}
}), null), insert(_el$9, createComponent(Button, {
onClick: () => scale.apply(),
get children() {
return texts.common.actions.apply;
}
}), null), insert(_el$9, createComponent(Button, {
onClick: () => scale.cancel(),
get children() {
return texts.common.actions.close;
}
}), null), createRenderEffect((_p$) => {
var _v$ = texts.reader.adjustScrollViewport, _v$2 = texts.reader.resizeScrollViewport;
return _v$ !== _p$.e && setAttribute(_el$2, "aria-label", _p$.e = _v$), _v$2 !== _p$.t && setAttribute(_el$7, "aria-label", _p$.t = _v$2), _p$;
}, {
e: void 0,
t: void 0
}), createRenderEffect(() => _el$7.value = sliderPercent()), _el$2;
})()];
}
});
}
var _tmpl$13, _tmpl$26, _tmpl$34, MIN_SCALE_PERCENT, MAX_SCALE_PERCENT, init_chunk_CK6USHZG = __esm({
"../reader/dist/chunk-CK6USHZG.js"() {
"use strict";
init_chunk_WWFOV7YA();
init_chunk_4Y6MOAXB();
init_chunk_GUZXW3OF();
init_chunk_JXES5MWD();
init_chunk_TRAUK5J2();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_solid();
_tmpl$13 = /* @__PURE__ */ template("<div class=ehpeek-reader-scale-gesture>"), _tmpl$26 = /* @__PURE__ */ template("<span>"), _tmpl$34 = /* @__PURE__ */ template("<div class=ehpeek-reader-scale-toolbar role=toolbar><div class=ehpeek-reader-scale-slider-row><span class=ehpeek-reader-scale-label><span></span></span><input type=range class=ehpeek-reader-scale-input min=10 max=500 step=1></div><div class=ehpeek-reader-scale-presets></div><div class=ehpeek-reader-scale-actions>");
MIN_SCALE_PERCENT = 10, MAX_SCALE_PERCENT = 500;
delegateEvents(["click", "pointerdown", "pointermove", "pointerup", "input"]);
}
});
// ../reader/dist/chunk-7DN2G2IN.js
function ReaderToolbar(props) {
let ctx = useReaderContext(), controls = () => getReaderControls(ctx), settings2 = () => ctx.settings[`${ctx.orientation()}Controls`], progress = () => ({
pageNum: ctx.position.page(),
totalPages: ctx.source.totalPages,
maxProgressPageNum: ctx.source.totalPages || Number.MAX_SAFE_INTEGER,
keepInputValue: ctx.position.seeking()
}), downloadInfos = () => ctx.position.contentPages().flatMap((pageNum) => {
let resource = ctx.loading.page(pageNum), image2 = resource?.image;
if (!image2) return [];
let fileName = image2.fileName ?? `page-${pageNum}.${imageFileExtension(image2.imageUrl) || "webp"}`;
return [{
currentFileName: fileName,
currentImageUrl: image2.imageUrl,
imageWidth: resource.element?.naturalWidth || image2.width || null,
imageHeight: resource.element?.naturalHeight || image2.height || null,
originalFileName: image2.originalFileName ?? fileName,
originalImageUrl: image2.originalImageUrl ?? null,
pageNum
}];
}), openOriginal = () => {
let page2 = ctx.loading.page(ctx.position.page())?.page;
page2 && ctx.customization.onOpenOriginalPage?.(page2.url, ctx.position.page());
}, texts = useReaderTexts(), leftHandedControls = () => ctx.settings.leftHandedControls.value(), [helpOpen, setHelpOpen] = createSignal(!1), [moreOpen, setMoreOpen] = createSignal(!1), [controlChange, setControlChange] = createSignal(null), [fullscreenToolbarTop, setFullscreenToolbarTop] = createSignal(), pageNumber, fullscreenStatus, controlChangeTimer = null, fullscreenTime = createFullscreenTime(() => props.fullscreenActive), showControlChange = (message) => {
controlChangeTimer !== null && window.clearTimeout(controlChangeTimer), setControlChange(message), controlChangeTimer = window.setTimeout(() => {
setControlChange(null), controlChangeTimer = null;
}, 1200);
};
return onCleanup(() => {
controlChangeTimer !== null && window.clearTimeout(controlChangeTimer);
}), onMount(() => {
let updateFullscreenToolbarTop = () => {
if (!props.fullscreenActive) {
setFullscreenToolbarTop(void 0);
return;
}
let statusBottom = fullscreenStatus?.getBoundingClientRect().bottom ?? 0, pageNumberBottom = pageNumber.getBoundingClientRect().bottom;
setFullscreenToolbarTop(`${Math.ceil(Math.max(statusBottom, pageNumberBottom) + 8)}px`);
}, observer = new ResizeObserver(updateFullscreenToolbarTop);
observer.observe(pageNumber), window.addEventListener("resize", updateFullscreenToolbarTop), createEffect(() => {
props.fullscreenActive ? queueMicrotask(updateFullscreenToolbarTop) : updateFullscreenToolbarTop();
}), onCleanup(() => {
observer.disconnect(), window.removeEventListener("resize", updateFullscreenToolbarTop);
});
}), createEffect(() => {
props.open || setMoreOpen(!1);
}), (() => {
var _el$ = _tmpl$35(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$2.nextSibling, _el$5 = _el$4.firstChild, _el$6 = _el$5.firstChild, _el$8 = _el$4.nextSibling, _el$1 = _el$8.nextSibling;
addEventListener(_el$2, "wheel", stopEvent), addEventListener(_el$2, "pointerdown", stopEvent, !0), addEventListener(_el$2, "click", stopEvent, !0), insert(_el$3, createComponent(Button, {
class: READER_FLOATING_ICON_ACTION_CLASS,
get "aria-label"() {
return texts.gallery.scrollPreview;
},
get title() {
return texts.gallery.scrollPreview;
},
onClick: () => ctx.openPreview(),
get children() {
return createComponent(Icon2, {
name: "grid",
size: READER_ICON_SIZE
});
}
}), null), insert(_el$3, createComponent(Button, {
class: READER_FLOATING_ICON_ACTION_CLASS,
disabled: !FULLSCREEN_SUPPORTED,
get "aria-label"() {
return memo(() => !!props.fullscreenActive)() ? texts.reader.exitFullscreen : texts.reader.fullscreen;
},
get title() {
return memo(() => !!props.fullscreenActive)() ? texts.reader.exitFullscreen : texts.reader.fullscreen;
},
onClick: () => props.onToggleFullscreen(),
get children() {
return createComponent(Icon2, {
get name() {
return props.fullscreenActive ? "fullscreen-exit" : "fullscreen";
},
size: READER_ICON_SIZE
});
}
}), null), insert(_el$3, createComponent(ReaderDownload, {
get disabled() {
return ctx.disabled();
},
get downloadInfos() {
return downloadInfos();
},
get pageNum() {
return progress().pageNum;
},
get customization() {
return ctx.customization;
}
}), null), addEventListener(_el$4, "wheel", stopEvent), addEventListener(_el$4, "pointerdown", stopEvent, !0), addEventListener(_el$4, "click", stopEvent, !0), insert(_el$6, createComponent(Button, {
class: READER_TOOLBAR_BUTTON_CLASS,
get disabled() {
return !ctx.customization?.onOpenOriginalPage;
},
onClick: () => openOriginal(),
get children() {
return createComponent(Icon2, {
name: "external-link",
size: READER_ICON_SIZE
});
}
}), null), insert(_el$6, createComponent(Button, {
class: READER_TOOLBAR_BUTTON_CLASS,
get "aria-label"() {
return texts.reader.readingOptions;
},
get title() {
return texts.reader.readingOptions;
},
get "aria-expanded"() {
return moreOpen();
},
onClick: () => setMoreOpen((open) => !open),
get children() {
return createComponent(Icon2, {
name: "book-open",
size: READER_ICON_SIZE
});
}
}), null), insert(_el$6, createComponent(Button, {
class: READER_TOOLBAR_BUTTON_CLASS,
get "aria-label"() {
return texts.help.title;
},
get title() {
return texts.help.title;
},
onClick: () => setHelpOpen(!0),
children: "?"
}), null), insert(_el$6, createComponent(Button, {
class: READER_TOOLBAR_BUTTON_CLASS,
get "aria-label"() {
return texts.common.actions.close;
},
get title() {
return texts.common.actions.close;
},
onClick: () => ctx.close(),
get children() {
return createComponent(Icon2, {
name: "close",
size: READER_ICON_SIZE
});
}
}), null), insert(_el$5, createComponent(Show, {
get when() {
return moreOpen();
},
get children() {
var _el$7 = _tmpl$14();
return insert(_el$7, createComponent(Button, {
class: READER_TOOLBAR_BUTTON_CLASS,
get "aria-label"() {
return memo(() => controls().navigationMode === "scroll")() ? texts.reader.scrollMode : texts.reader.pagedMode;
},
get title() {
return memo(() => controls().navigationMode === "scroll")() ? texts.reader.scrollMode : texts.reader.pagedMode;
},
onClick: () => {
let navigationMode = controls().navigationMode === "scroll" ? "paged" : "scroll";
settings2().navigationMode.set(navigationMode), showControlChange(navigationMode === "paged" ? texts.reader.pagedMode : texts.reader.scrollMode);
},
get children() {
return createComponent(Icon2, {
get name() {
return controls().navigationMode === "paged" ? "page" : "scroll-continuous";
},
size: READER_ICON_SIZE
});
}
}), null), insert(_el$7, createComponent(Button, {
class: READER_TOOLBAR_BUTTON_CLASS,
get "aria-label"() {
return memo(() => controls().direction === "rtl")() ? texts.reader.directionRtl : memo(() => controls().direction === "ltr")() ? texts.reader.directionLtr : texts.reader.directionTtb;
},
onClick: () => {
let direction = controls().direction === "rtl" ? "ltr" : controls().direction === "ltr" ? "ttb" : "rtl";
(controls().navigationMode === "scroll" ? settings2().scrollDirection : settings2().pagedDirection).set(direction), showControlChange(direction === "rtl" ? texts.reader.directionRtl : direction === "ltr" ? texts.reader.directionLtr : texts.reader.directionTtb);
},
get children() {
return createComponent(Icon2, {
get name() {
return memo(() => controls().direction === "rtl")() ? "arrow-left" : controls().direction === "ltr" ? "arrow-right" : "arrow-down";
},
size: READER_ICON_SIZE
});
}
}), null), insert(_el$7, createComponent(Button, {
class: READER_TOOLBAR_BUTTON_CLASS,
get "aria-label"() {
return memo(() => controls().pageLayout === "double")() ? texts.reader.doublePageMode : texts.reader.singlePageMode;
},
get disabled() {
return controls().navigationMode !== "paged";
},
onClick: () => {
let pageLayout = controls().pageLayout === "single" ? "double" : "single";
settings2().pageLayout.set(pageLayout), showControlChange(pageLayout === "double" ? texts.reader.doublePageMode : texts.reader.singlePageMode);
},
get children() {
return controls().pageLayout === "double" ? "2P" : "1P";
}
}), null), insert(_el$7, createComponent(Button, {
class: READER_TOOLBAR_BUTTON_CLASS,
get "aria-pressed"() {
return controls().firstPageSeparate;
},
get "aria-label"() {
return memo(() => !!controls().firstPageSeparate)() ? texts.reader.pairSecondAndThirdPages : texts.reader.pairFirstAndSecondPages;
},
get title() {
return memo(() => !!controls().firstPageSeparate)() ? texts.reader.pairSecondAndThirdPages : texts.reader.pairFirstAndSecondPages;
},
get disabled() {
return controls().navigationMode !== "paged" || controls().pageLayout !== "double";
},
onClick: () => {
let firstPageSeparate = !controls().firstPageSeparate;
ctx.firstPageSeparate[1](firstPageSeparate), showControlChange(firstPageSeparate ? texts.reader.pairSecondAndThirdPages : texts.reader.pairFirstAndSecondPages);
},
get children() {
return controls().firstPageSeparate ? "2+3" : "1+2";
}
}), null), insert(_el$7, createComponent(Button, {
class: READER_TOOLBAR_BUTTON_CLASS,
get "aria-label"() {
return memo(() => controls().rightTapAction === "previous")() ? texts.reader.rightTapPrevious : texts.reader.rightTapNext;
},
onClick: () => {
let rightTapAction = controls().rightTapAction === "previous" ? "next" : "previous";
settings2().rightTapAction.set(rightTapAction), showControlChange(rightTapAction === "previous" ? texts.reader.rightTapPrevious : texts.reader.rightTapNext);
},
get children() {
return controls().rightTapAction === "previous" ? "R-" : "R+";
}
}), null), insert(_el$7, createComponent(Button, {
class: READER_TOOLBAR_BUTTON_CLASS,
get "aria-label"() {
return texts.reader.adjustScrollViewport;
},
get title() {
return texts.reader.adjustScrollViewport;
},
get disabled() {
return controls().navigationMode !== "scroll";
},
onClick: () => ctx.scrollScale.open(),
get children() {
return createComponent(Icon2, {
name: "viewport",
size: READER_ICON_SIZE
});
}
}), null), _el$7;
}
}), null);
var _ref$ = pageNumber;
return typeof _ref$ == "function" ? use(_ref$, _el$8) : pageNumber = _el$8, insert(_el$8, () => pageNumberText(texts, progress().pageNum, progress().totalPages, controls().navigationMode, controls().pageLayout, controls().firstPageSeparate)), insert(_el$, createComponent(Show, {
get when() {
return props.fullscreenActive;
},
get children() {
var _el$9 = _tmpl$27(), _el$0 = _el$9.firstChild, _ref$2 = fullscreenStatus;
return typeof _ref$2 == "function" ? use(_ref$2, _el$9) : fullscreenStatus = _el$9, insert(_el$0, fullscreenTime), _el$9;
}
}), _el$1), insert(_el$, createComponent(Show, {
get when() {
return controlChange();
},
keyed: !0,
children: (message) => (() => {
var _el$10 = _tmpl$43();
return insert(_el$10, message), _el$10;
})()
}), _el$1), addEventListener(_el$1, "wheel", stopEvent), addEventListener(_el$1, "pointerdown", stopEvent, !0), addEventListener(_el$1, "click", stopEvent, !0), insert(_el$1, createComponent(ProgressBar, {
class: "ehpeek-reader-progress-input",
get direction() {
return controls().direction === "rtl" ? "rtl" : "ltr";
},
get fillPercent() {
return progressFillPercent(progress());
},
get keepInputValue() {
return progress().keepInputValue;
},
get max() {
return Math.max(1, progress().maxProgressPageNum);
},
min: 1,
step: 1,
get value() {
return progress().pageNum;
},
onPointerDown: (event) => {
event.stopPropagation(), ctx.position.beginSeek();
},
get onInput() {
return ctx.position.seek;
},
get onCommit() {
return ctx.position.commitSeek;
}
})), insert(_el$, createComponent(Show, {
get when() {
return memo(() => !ctx.disabled())() && helpOpen();
},
get children() {
return createComponent(InteractionHelp, {
variant: "reader",
onClose: () => setHelpOpen(!1)
});
}
}), null), createRenderEffect((_p$) => {
var _v$ = leftHandedControls(), _v$2 = String(props.open), _v$3 = fullscreenToolbarTop(), _v$4 = !props.open, _v$5 = controls().navigationMode === "scroll" && !props.open && !props.fullscreenActive, _v$6 = String(props.open);
return _v$ !== _p$.e && setAttribute(_el$, "data-left-handed", _p$.e = _v$), _v$2 !== _p$.t && setAttribute(_el$2, "data-open", _p$.t = _v$2), _v$3 !== _p$.a && setStyleProperty(_el$4, "top", _p$.a = _v$3), _v$4 !== _p$.o && (_el$5.hidden = _p$.o = _v$4), _v$5 !== _p$.i && (_el$8.hidden = _p$.i = _v$5), _v$6 !== _p$.n && setAttribute(_el$1, "data-open", _p$.n = _v$6), _p$;
}, {
e: void 0,
t: void 0,
a: void 0,
o: void 0,
i: void 0,
n: void 0
}), _el$;
})();
}
function ReaderDownload(props) {
let texts = useReaderTexts(), startImageDownload = (url, name) => props.customization?.download?.(url, name) ?? !1, [downloadDialogPageNum, setDownloadDialogPageNum] = createSignal(null);
return createEffect(() => {
let pageNum = downloadDialogPageNum();
pageNum !== null && pageNum !== props.pageNum && setDownloadDialogPageNum(null);
}), [createComponent(Button, {
class: READER_FLOATING_ICON_ACTION_CLASS,
get disabled() {
return props.downloadInfos.length === 0;
},
get "aria-label"() {
return texts.reader.download;
},
get title() {
return texts.reader.download;
},
onClick: () => setDownloadDialogPageNum(props.pageNum),
get children() {
return createComponent(Icon2, {
name: "download",
size: READER_ICON_SIZE
});
}
}), createComponent(Show, {
get when() {
return memo(() => !props.disabled && downloadDialogPageNum() !== null)() && props.downloadInfos.length > 0;
},
get children() {
return createComponent(Dialog, {
bodyClass: "ehpeek-reader-download-body",
get label() {
return texts.reader.download;
},
onClose: () => setDownloadDialogPageNum(null),
get title() {
return `${texts.reader.download} · ${props.downloadInfos.map((info) => info.pageNum).join(", ")}`;
},
variant: "reader",
width: "lg",
get children() {
var _el$11 = _tmpl$52(), _el$12 = _el$11.firstChild, _el$13 = _el$12.firstChild, _el$14 = _el$13.nextSibling, _el$15 = _el$14.nextSibling, _el$16 = _el$15.firstChild, _el$17 = _el$16.firstChild;
return insert(_el$11, createComponent(For, {
get each() {
return props.downloadInfos;
},
children: (downloadInfo) => (() => {
var _el$18 = _tmpl$92();
return insert(_el$18, createComponent(Button, {
variant: "option",
get disabled() {
return !props.customization?.download;
},
onClick: () => {
startImageDownload(downloadInfo.currentImageUrl, downloadInfo.currentFileName) && setDownloadDialogPageNum(null);
},
get children() {
return [(() => {
var _el$19 = _tmpl$62();
return insert(_el$19, () => `${texts.reader.downloadDisplayedImage} · ${downloadInfo.pageNum}`), _el$19;
})(), (() => {
var _el$20 = _tmpl$72();
return insert(_el$20, () => downloadInfo.currentFileName), _el$20;
})()];
}
}), null), insert(_el$18, createComponent(Button, {
variant: "option",
get disabled() {
return !downloadInfo.originalImageUrl || !props.customization?.download;
},
onClick: () => {
downloadInfo.originalImageUrl && startImageDownload(downloadInfo.originalImageUrl, downloadInfo.originalFileName) && setDownloadDialogPageNum(null);
},
get children() {
return [(() => {
var _el$21 = _tmpl$62();
return insert(_el$21, () => `${texts.reader.downloadOriginalImage} · ${downloadInfo.pageNum}`), _el$21;
})(), (() => {
var _el$22 = _tmpl$82();
return insert(_el$22, (() => {
var _c$ = memo(() => !!downloadInfo.originalImageUrl);
return () => _c$() ? texts.reader.originalImageSource : texts.reader.originalImageUnavailable;
})()), _el$22;
})()];
}
}), null), _el$18;
})()
}), _el$12), insert(_el$13, () => texts.reader.downloadHelpLabel), insert(_el$14, () => props.customization?.downloadHelp?.()), insert(_el$16, () => texts.reader.openImage, _el$17), insert(_el$15, createComponent(For, {
get each() {
return props.downloadInfos;
},
children: (downloadInfo) => [(() => {
var _el$23 = _tmpl$0();
return insert(_el$23, () => `${texts.reader.displayedImageShort} ${downloadInfo.pageNum}`), createRenderEffect(() => setAttribute(_el$23, "href", downloadInfo.currentImageUrl)), _el$23;
})(), createComponent(Show, {
get when() {
return downloadInfo.originalImageUrl;
},
children: (originalImageUrl) => (() => {
var _el$24 = _tmpl$0();
return insert(_el$24, () => `${texts.reader.originalImageShort} ${downloadInfo.pageNum}`), createRenderEffect(() => setAttribute(_el$24, "href", originalImageUrl())), _el$24;
})()
})]
}), null), _el$11;
}
});
}
})];
}
function createFullscreenTime(enabled) {
let [time, setTime] = createSignal(TIME_FORMATTER.format(/* @__PURE__ */ new Date()));
return createEffect(() => {
if (!enabled())
return;
let updateTime = () => setTime(TIME_FORMATTER.format(/* @__PURE__ */ new Date()));
updateTime();
let interval = null, timeout = window.setTimeout(() => {
updateTime(), interval = window.setInterval(updateTime, 6e4);
}, 6e4 - Date.now() % 6e4);
onCleanup(() => {
window.clearTimeout(timeout), interval !== null && window.clearInterval(interval);
});
}), time;
}
function progressFillPercent(progress) {
let max = Math.max(1, progress.maxProgressPageNum), value = Math.min(max, Math.max(1, progress.pageNum));
return max > 1 ? (value - 1) / (max - 1) * 100 : 100;
}
function pageNumberText(texts, pageNum, totalPages, navigationMode, pageLayout, firstPageSeparate) {
if (totalPages && pageNum === totalPages + 1)
return texts.reader.endPage;
let doublePage = navigationMode === "paged" && pageLayout === "double" && !(firstPageSeparate && pageNum === 1);
if (!totalPages)
return doublePage ? `${pageNum}–${pageNum + 1}` : String(pageNum);
let doublePageEnd = Math.min(totalPages, pageNum + 1);
return doublePage && doublePageEnd > pageNum ? `${pageNum}–${doublePageEnd} / ${totalPages}` : `${pageNum} / ${totalPages}`;
}
var _tmpl$14, _tmpl$27, _tmpl$35, _tmpl$43, _tmpl$52, _tmpl$62, _tmpl$72, _tmpl$82, _tmpl$92, _tmpl$0, FULLSCREEN_SUPPORTED, READER_TOOLBAR_BUTTON_CLASS, READER_FLOATING_ICON_ACTION_CLASS, READER_ICON_SIZE, TIME_FORMATTER, init_chunk_7DN2G2IN = __esm({
"../reader/dist/chunk-7DN2G2IN.js"() {
"use strict";
init_chunk_QXLQXDIQ();
init_chunk_PV2I4MKV();
init_chunk_QUSU3A2M();
init_chunk_I2UURCWR();
init_chunk_4Y6MOAXB();
init_chunk_UPVG5Y6S();
init_chunk_JXES5MWD();
init_chunk_TRAUK5J2();
init_chunk_E6UKP7HT();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_solid();
_tmpl$14 = /* @__PURE__ */ template("<div class=ehpeek-reader-toolbar-more>"), _tmpl$27 = /* @__PURE__ */ template("<div class=ehpeek-reader-fullscreen-status role=status><span>"), _tmpl$35 = /* @__PURE__ */ template("<div class=ehpeek-reader-tools><div class=ehpeek-reader-floating-toolbar><div class=ehpeek-reader-floating-actions></div></div><div class=ehpeek-reader-toolbar><div class=ehpeek-reader-toolbar-controls><div class=ehpeek-reader-toolbar-row></div></div></div><div class=ehpeek-reader-page-number></div><div class=ehpeek-reader-progress>"), _tmpl$43 = /* @__PURE__ */ template("<div class=ehpeek-reader-control-notice>"), _tmpl$52 = /* @__PURE__ */ template("<div class=ehpeek-reader-download-options><details class=ehpeek-reader-download-detail><summary class=ehpeek-reader-download-summary></summary><p class=ehpeek-reader-download-help></p><div class=ehpeek-reader-download-links><strong>:"), _tmpl$62 = /* @__PURE__ */ template("<span class=ehpeek-reader-download-title>"), _tmpl$72 = /* @__PURE__ */ template("<span class=ehpeek-reader-download-filename>"), _tmpl$82 = /* @__PURE__ */ template("<span class=ehpeek-reader-download-detail>"), _tmpl$92 = /* @__PURE__ */ template("<div class=ehpeek-reader-download-page>"), _tmpl$0 = /* @__PURE__ */ template('<a class=ehpeek-reader-download-link rel="noopener noreferrer"target=_blank>'), FULLSCREEN_SUPPORTED = typeof document < "u" && (document.fullscreenEnabled || typeof document.documentElement.requestFullscreen == "function" || typeof document.documentElement.webkitRequestFullscreen == "function"), READER_TOOLBAR_BUTTON_CLASS = "ehpeek-reader-toolbar-button", READER_FLOATING_ICON_ACTION_CLASS = "ehpeek-reader-floating-button", READER_ICON_SIZE = "var(--ui-icon-size-md)", TIME_FORMATTER = new Intl.DateTimeFormat(void 0, {
hour: "2-digit",
minute: "2-digit"
});
delegateEvents(["click", "pointerdown"]);
}
});
// ../reader/dist/chunk-FUW3K55A.js
function createPagesScroller(element) {
let clampedTop = (scrollTop, bounds) => bounds ? clamp(scrollTop, bounds.min ?? Number.NEGATIVE_INFINITY, bounds.max ?? Number.POSITIVE_INFINITY) : scrollTop;
return {
element,
resetPosition() {
element.scrollLeft = 0, element.scrollTop = 0;
},
scrollLeft() {
return element.scrollLeft;
},
scrollTop() {
return element.scrollTop;
},
viewportWidth() {
return element.clientWidth || window.innerWidth || 1;
},
viewportHeight() {
return element.clientHeight;
},
viewportXRatio(clientX) {
let bounds = element.getBoundingClientRect();
return (clientX - bounds.left) / Math.max(1, bounds.width);
},
moveToLeft(scrollLeft) {
element.scrollLeft !== scrollLeft && (element.scrollLeft = scrollLeft);
},
centerHorizontal() {
element.scrollLeft = Math.max(0, (element.scrollWidth - element.clientWidth) / 2);
},
centerVertical() {
element.scrollTop = Math.max(0, (element.scrollHeight - element.clientHeight) / 2);
},
centerAnchor() {
let viewportRect = element.getBoundingClientRect(), centerX = viewportRect.left + viewportRect.width / 2, centerY = viewportRect.top + viewportRect.height / 2, pages = Array.from(element.querySelectorAll(".ehpeek-page")), closest = null;
for (let node of pages) {
let rect2 = node.getBoundingClientRect(), dx = centerX < rect2.left ? rect2.left - centerX : centerX > rect2.right ? centerX - rect2.right : 0, dy = centerY < rect2.top ? rect2.top - centerY : centerY > rect2.bottom ? centerY - rect2.bottom : 0, distance = Math.hypot(dx, dy);
(!closest || distance < closest.distance) && (closest = { distance, node });
}
if (!closest)
return null;
let rect = closest.node.getBoundingClientRect(), pageNum = Number(closest.node.dataset.ehpeekPageNum || "");
return Number.isFinite(pageNum) && rect.width > 0 && rect.height > 0 ? {
pageNum,
xRatio: (centerX - rect.left) / rect.width,
yRatio: (centerY - rect.top) / rect.height
} : null;
},
restoreCenterAnchor(anchor2) {
let node = element.querySelector(`.ehpeek-page[data-ehpeek-page-num="${anchor2.pageNum}"]`);
if (!node)
return;
let viewportRect = element.getBoundingClientRect(), pageRect = node.getBoundingClientRect(), centerX = viewportRect.left + viewportRect.width / 2, centerY = viewportRect.top + viewportRect.height / 2, leftDelta = pageRect.left + pageRect.width * anchor2.xRatio - centerX, topDelta = pageRect.top + pageRect.height * anchor2.yRatio - centerY;
Math.abs(leftDelta) >= 0.5 && (element.scrollLeft += leftDelta), Math.abs(topDelta) >= 0.5 && (element.scrollTop += topDelta);
},
moveToTop(scrollTop, bounds) {
let nextScrollTop = clampedTop(scrollTop, bounds);
element.scrollTop !== nextScrollTop && (element.scrollTop = nextScrollTop);
},
slotTop(elements) {
let elementsRect = elements.node.getBoundingClientRect(), scrollerRect = element.getBoundingClientRect();
return element.scrollTop + elementsRect.top - scrollerRect.top;
},
slotLeft(elements) {
let elementsRect = elements.node.getBoundingClientRect(), scrollerRect = element.getBoundingClientRect();
return element.scrollLeft + elementsRect.left - scrollerRect.left;
},
slotOffset(elements, navigationMode, direction, pageLayout) {
let pageRect = elements.node.getBoundingClientRect(), scrollerRect = element.getBoundingClientRect();
return direction === "ttb" ? pageRect.top - scrollerRect.top : direction === "rtl" && (navigationMode === "scroll" || pageLayout === "double") ? pageRect.right - scrollerRect.right : pageRect.left - scrollerRect.left;
},
slotContainsViewportTarget(elements, direction) {
let scrollerRect = element.getBoundingClientRect(), rect = elements.node.getBoundingClientRect();
if (direction === "ttb") {
let target2 = scrollerRect.top + Math.min(80, scrollerRect.height * 0.14);
return rect.top <= target2 && rect.bottom > target2;
}
let offset = Math.min(80, scrollerRect.width * 0.14), target = direction === "rtl" ? scrollerRect.right - offset : scrollerRect.left + offset;
return rect.left <= target && rect.right > target;
},
slotViewportStartDistance(elements, direction) {
let scrollerRect = element.getBoundingClientRect(), rect = elements.node.getBoundingClientRect();
return rect.bottom <= scrollerRect.top || rect.top >= scrollerRect.bottom || rect.right <= scrollerRect.left || rect.left >= scrollerRect.right ? null : direction === "ttb" ? Math.max(0, rect.top - scrollerRect.top) : direction === "rtl" ? Math.max(0, scrollerRect.right - rect.right) : Math.max(0, rect.left - scrollerRect.left);
}
};
}
var init_chunk_FUW3K55A = __esm({
"../reader/dist/chunk-FUW3K55A.js"() {
"use strict";
init_chunk_E6UKP7HT();
}
});
// ../reader/dist/chunk-NP6I7EK4.js
var SCROLL_ANIMATION_MS, SCROLL_EASING_POWER, ANIMATION_FRAME_MIN_DELTA_MS, ANIMATION_FRAME_MAX_DELTA_MS, SCROLL_FLING_MIN_VELOCITY, SCROLL_FLING_STOP_VELOCITY, SCROLL_FLING_DECAY, VERTICAL_SCROLL_FLING_INITIAL_VELOCITY_FACTOR, ScrollAnimator, ScrollFlingAnimator, init_chunk_NP6I7EK4 = __esm({
"../reader/dist/chunk-NP6I7EK4.js"() {
"use strict";
init_chunk_E6UKP7HT();
SCROLL_ANIMATION_MS = 180, SCROLL_EASING_POWER = 3, ANIMATION_FRAME_MIN_DELTA_MS = 1, ANIMATION_FRAME_MAX_DELTA_MS = 32, SCROLL_FLING_MIN_VELOCITY = 0.35, SCROLL_FLING_STOP_VELOCITY = 0.02, SCROLL_FLING_DECAY = 45e-4, VERTICAL_SCROLL_FLING_INITIAL_VELOCITY_FACTOR = 1.2, ScrollAnimator = class {
constructor(axis) {
this.axis = axis, this.frame = null;
}
scrollTo(scroller, target, motion = "instant", onComplete) {
if (this.cancel(), motion !== "animated") {
this.setScrollPosition(scroller, target), onComplete?.();
return;
}
this.scrollWithRaf(scroller, target, onComplete);
}
cancel() {
this.frame !== null && (window.cancelAnimationFrame(this.frame), this.frame = null);
}
scrollWithRaf(scroller, target, onComplete) {
let start2 = this.scrollPosition(scroller), delta = target - start2, lastFrameTime = performance.now(), animationTime = 0, step = (time) => {
let elapsed = clamp(time - lastFrameTime, ANIMATION_FRAME_MIN_DELTA_MS, ANIMATION_FRAME_MAX_DELTA_MS);
lastFrameTime = time, animationTime += elapsed;
let progress = clamp(animationTime / SCROLL_ANIMATION_MS, 0, 1), eased = 1 - Math.pow(1 - progress, SCROLL_EASING_POWER);
if (this.setScrollPosition(scroller, start2 + delta * eased), progress >= 1) {
this.frame = null, onComplete?.();
return;
}
this.frame = window.requestAnimationFrame(step);
};
this.frame = window.requestAnimationFrame(step);
}
scrollPosition(scroller) {
return this.axis === "x" ? scroller.scrollLeft : scroller.scrollTop;
}
setScrollPosition(scroller, value) {
this.axis === "x" ? scroller.scrollLeft = value : scroller.scrollTop = value;
}
}, ScrollFlingAnimator = class {
constructor() {
this.frame = null, this.velocity = 0, this.lastFrameTime = 0;
}
running() {
return this.frame !== null;
}
start(options) {
this.cancel();
let scaledInitialVelocity = options.initialVelocity * (options.axis === "y" ? VERTICAL_SCROLL_FLING_INITIAL_VELOCITY_FACTOR : 1), initialVelocity = options.maxVelocity ? clamp(scaledInitialVelocity, -options.maxVelocity, options.maxVelocity) : scaledInitialVelocity;
if (Math.abs(initialVelocity) < SCROLL_FLING_MIN_VELOCITY)
return;
this.velocity = initialVelocity, this.lastFrameTime = performance.now();
let step = (time) => {
if (!options.canRun()) {
this.cancel();
return;
}
let elapsed = clamp(
time - this.lastFrameTime,
ANIMATION_FRAME_MIN_DELTA_MS,
options.maxFrameDelta ?? ANIMATION_FRAME_MAX_DELTA_MS
);
this.lastFrameTime = time;
let previousPosition = options.axis === "x" ? options.scroller.scrollLeft : options.scroller.scrollTop;
if (options.setScrollPosition(previousPosition + this.velocity * elapsed), (options.axis === "x" ? options.scroller.scrollLeft : options.scroller.scrollTop) === previousPosition) {
this.cancel(), options.onStop();
return;
}
if (this.velocity *= Math.exp(-(options.decay ?? SCROLL_FLING_DECAY) * elapsed), Math.abs(this.velocity) < SCROLL_FLING_STOP_VELOCITY) {
this.cancel(), options.onStop();
return;
}
this.frame = window.requestAnimationFrame(step);
};
this.frame = window.requestAnimationFrame(step);
}
cancel() {
let running = this.frame !== null;
return this.frame !== null && (window.cancelAnimationFrame(this.frame), this.frame = null), this.velocity = 0, running;
}
};
}
});
// ../reader/dist/chunk-MLGDT3ZG.js
function ReaderPageView(props) {
let ctx = useReaderContext(), texts = useReaderTexts(), resource = () => ctx.loading.page(props.pageNum), kind = () => props.pageNum < 1 ? "blank" : ctx.source.totalPages && props.pageNum === ctx.source.totalPages + 1 ? "end" : ctx.source.totalPages && props.pageNum > ctx.source.totalPages ? "blank" : "page", state2 = () => kind() === "page" ? resource()?.status ?? "idle" : "ready", text = () => kind() === "end" ? texts.reader.end : kind() === "blank" ? "" : String(props.pageNum), image2 = () => resource()?.element, stop = (event) => {
event.preventDefault(), event.stopPropagation();
};
return [createComponent(Show, {
get when() {
return image2();
},
keyed: !0,
get fallback() {
return (() => {
var _el$2 = _tmpl$53();
return insert(_el$2, createComponent(Show, {
get when() {
return state2() === "error";
},
get fallback() {
return createComponent(Show, {
get when() {
return state2() === "loading";
},
get fallback() {
return text();
},
get children() {
var _el$6 = _tmpl$63(), _el$7 = _el$6.firstChild;
return insert(_el$7, text), _el$6;
}
});
},
get children() {
return [(() => {
var _el$3 = _tmpl$28();
return _el$3.$$click = (event) => {
stop(event), ctx.disabled() || ctx.loading.retry(props.pageNum);
}, _el$3.$$pointerdown = stop, insert(_el$3, createComponent(Icon2, {
name: "refresh",
size: "var(--ui-icon-size-xl)"
})), createRenderEffect((_p$) => {
var _v$ = `${texts.reader.reloadPage} ${props.pageNum}`, _v$2 = texts.reader.reloadPage;
return _v$ !== _p$.e && setAttribute(_el$3, "aria-label", _p$.e = _v$), _v$2 !== _p$.t && setAttribute(_el$3, "title", _p$.t = _v$2), _p$;
}, {
e: void 0,
t: void 0
}), _el$3;
})(), (() => {
var _el$4 = _tmpl$36();
return insert(_el$4, () => texts.common.status.failed), _el$4;
})(), createComponent(Show, {
get when() {
return resource()?.error;
},
get children() {
var _el$5 = _tmpl$44();
return insert(_el$5, () => resource()?.error), _el$5;
}
})];
}
})), createRenderEffect((_p$) => {
var _v$3 = state2(), _v$4 = kind(), _v$5 = state2() === "loading" ? "status" : void 0, _v$6 = state2() === "loading" ? `${texts.common.status.loading} ${text()}` : void 0;
return _v$3 !== _p$.e && setAttribute(_el$2, "data-state", _p$.e = _v$3), _v$4 !== _p$.t && setAttribute(_el$2, "data-kind", _p$.t = _v$4), _v$5 !== _p$.a && setAttribute(_el$2, "role", _p$.a = _v$5), _v$6 !== _p$.o && setAttribute(_el$2, "aria-label", _p$.o = _v$6), _p$;
}, {
e: void 0,
t: void 0,
a: void 0,
o: void 0
}), _el$2;
})();
},
children: (element) => element
}), createComponent(Show, {
get when() {
return memo(() => state2() === "loading")() && image2();
},
get children() {
var _el$ = _tmpl$15();
return createRenderEffect(() => setAttribute(_el$, "aria-label", texts.common.status.loading)), _el$;
}
})];
}
var _tmpl$15, _tmpl$28, _tmpl$36, _tmpl$44, _tmpl$53, _tmpl$63, init_chunk_MLGDT3ZG = __esm({
"../reader/dist/chunk-MLGDT3ZG.js"() {
"use strict";
init_chunk_UPVG5Y6S();
init_chunk_JXES5MWD();
init_chunk_TRAUK5J2();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_solid();
_tmpl$15 = /* @__PURE__ */ template("<span class=ehpeek-reader-page-loading role=status>"), _tmpl$28 = /* @__PURE__ */ template("<button type=button class=ehpeek-reader-page-reload>"), _tmpl$36 = /* @__PURE__ */ template("<div class=ehpeek-reader-page-error>"), _tmpl$44 = /* @__PURE__ */ template("<div class=ehpeek-reader-page-error-detail>"), _tmpl$53 = /* @__PURE__ */ template("<div class=ehpeek-reader-placeholder>"), _tmpl$63 = /* @__PURE__ */ template("<span class=ehpeek-reader-placeholder-loading aria-hidden=true><span class=ehpeek-reader-placeholder-number></span><span class=ehpeek-reader-placeholder-spinner>");
delegateEvents(["pointerdown", "click"]);
}
});
// ../reader/dist/chunk-F33WVP3N.js
function ReaderPositionBar(props) {
let ctx = useReaderContext(), [visible, setVisible] = createSignal(!1), [expanded, setExpanded] = createSignal(!1), previous = null, distance = 0, gestureTimer, hideTimer, cancelTimers = () => {
window.clearTimeout(gestureTimer), window.clearTimeout(hideTimer);
};
return createEffect(on(() => props.scrollOffset, (offset) => {
if (previous === null) {
previous = offset;
return;
}
distance += Math.abs(offset - previous), previous = offset, distance >= 48 && setVisible(!0), distance >= props.viewportLength * 2 && setExpanded(!0), cancelTimers(), gestureTimer = window.setTimeout(() => {
distance = 0;
}, 160), hideTimer = window.setTimeout(() => {
distance = 0, setExpanded(!1), setVisible(!1);
}, 900);
})), createEffect(() => {
ctx.disabled() && (cancelTimers(), distance = 0, setExpanded(!1), setVisible(!1));
}), onCleanup(cancelTimers), createComponent(PositionBar, {
get disabled() {
return ctx.disabled();
},
ariaLabel: "Reader position",
axis: "vertical",
get currentValue() {
return ctx.position.page();
},
get expanded() {
return expanded();
},
get maxValue() {
return ctx.source.totalPages ?? 1;
},
get onCommit() {
return ctx.position.commitSeek;
},
get onInput() {
return ctx.position.seek;
},
onPointerDown: (event) => {
event.stopPropagation(), ctx.position.beginSeek();
},
position: "fixed",
get thickness() {
return props.narrow ? "narrow" : "normal";
},
trackClickEnabled: !1,
trackVisible: !1,
get visible() {
return visible();
},
visibleValueCount: 1
});
}
var init_chunk_F33WVP3N = __esm({
"../reader/dist/chunk-F33WVP3N.js"() {
"use strict";
init_chunk_NU4SG75H();
init_chunk_TRAUK5J2();
init_web();
init_solid();
}
});
// ../reader/dist/chunk-W6Q6Q5LD.js
function ZoomOverlay(props) {
let [transform, setTransform] = createSignal("translate3d(0px, 0px, 0) scale(1)"), element, scale = 1, requestedScale = 1, closeScale = CLOSE_SCALE, minScale = MIN_SCALE, maxScale = MAX_SCALE, offsetX = 0, offsetY = 0, pinchStartScale = 1, pinchStartOffsetX = 0, pinchStartOffsetY = 0, pinchStartCenterX = 0, pinchStartCenterY = 0, dragStartOffsetX = 0, dragStartOffsetY = 0, renderTransform = () => {
setTransform(`translate3d(${offsetX}px, ${offsetY}px, 0) scale(${scale})`);
}, startPinch = (pinch) => {
pinchStartScale = scale, pinchStartOffsetX = offsetX, pinchStartOffsetY = offsetY, pinchStartCenterX = pinch.centerX, pinchStartCenterY = pinch.centerY;
}, actions = {
reset(reset2) {
scale = Math.max(0.01, reset2.scale), requestedScale = scale, closeScale = scale * CLOSE_SCALE, minScale = Math.min(MIN_SCALE, scale), maxScale = Math.max(MAX_SCALE, scale * MAX_SCALE), offsetX = 0, offsetY = 0, startPinch(reset2), renderTransform();
},
startPinch,
movePinch(pinch) {
if (!props.image)
return;
requestedScale = pinchStartScale * pinch.scale, scale = clamp(requestedScale, minScale, maxScale);
let rect = element.getBoundingClientRect(), viewportCenterX = rect.left + rect.width / 2, viewportCenterY = rect.top + rect.height / 2, ratio = scale / pinchStartScale;
offsetX = pinch.centerX - viewportCenterX - (pinchStartCenterX - viewportCenterX - pinchStartOffsetX) * ratio, offsetY = pinch.centerY - viewportCenterY - (pinchStartCenterY - viewportCenterY - pinchStartOffsetY) * ratio, renderTransform();
},
moveWheel(wheel) {
if (!props.image)
return;
let nextScale = clamp(scale * Math.exp(-clamp(wheel.delta, -100, 100) * 25e-4), minScale, maxScale);
if (nextScale === scale)
return;
let rect = element.getBoundingClientRect(), viewportCenterX = rect.left + rect.width / 2, viewportCenterY = rect.top + rect.height / 2, ratio = nextScale / scale;
offsetX = wheel.centerX - viewportCenterX - (wheel.centerX - viewportCenterX - offsetX) * ratio, offsetY = wheel.centerY - viewportCenterY - (wheel.centerY - viewportCenterY - offsetY) * ratio, scale = nextScale, requestedScale = nextScale, renderTransform();
},
endPinch() {
if (requestedScale <= closeScale) {
props.onClose();
return;
}
renderTransform();
},
startDrag() {
dragStartOffsetX = offsetX, dragStartOffsetY = offsetY;
},
moveDrag(move) {
props.image && (offsetX = dragStartOffsetX + move.dx, offsetY = dragStartOffsetY + move.dy, renderTransform());
}
};
return untrack(() => props.actionsRef(actions)), (() => {
var _el$ = _tmpl$16(), _el$2 = _el$.firstChild, _ref$ = element;
return typeof _ref$ == "function" ? use(_ref$, _el$) : element = _el$, createRenderEffect((_p$) => {
var _v$ = !props.image, _v$2 = props.image ? "" : "none", _v$3 = props.image?.imageUrl, _v$4 = props.image ? `Page ${props.image.pageNum}` : "", _v$5 = props.image?.width ?? void 0, _v$6 = props.image?.height ?? void 0, _v$7 = transform();
return _v$ !== _p$.e && (_el$.hidden = _p$.e = _v$), _v$2 !== _p$.t && setStyleProperty(_el$, "display", _p$.t = _v$2), _v$3 !== _p$.a && setAttribute(_el$2, "src", _p$.a = _v$3), _v$4 !== _p$.o && setAttribute(_el$2, "alt", _p$.o = _v$4), _v$5 !== _p$.i && setAttribute(_el$2, "width", _p$.i = _v$5), _v$6 !== _p$.n && setAttribute(_el$2, "height", _p$.n = _v$6), _v$7 !== _p$.s && setStyleProperty(_el$2, "transform", _p$.s = _v$7), _p$;
}, {
e: void 0,
t: void 0,
a: void 0,
o: void 0,
i: void 0,
n: void 0,
s: void 0
}), _el$;
})();
}
var _tmpl$16, MIN_SCALE, MAX_SCALE, CLOSE_SCALE, init_chunk_W6Q6Q5LD = __esm({
"../reader/dist/chunk-W6Q6Q5LD.js"() {
"use strict";
init_chunk_E6UKP7HT();
init_web();
init_web();
init_web();
init_web();
init_web();
init_solid();
_tmpl$16 = /* @__PURE__ */ template("<div class=ehpeek-reader-zoom><img class=ehpeek-reader-zoom-image>"), MIN_SCALE = 1, MAX_SCALE = 5, CLOSE_SCALE = 1.02;
}
});
// ../reader/dist/chunk-WH3QJFUT.js
function suppressTrailingClick() {
let swallow = (event) => {
event.stopPropagation(), event.preventDefault(), window.removeEventListener("click", swallow, !0);
};
window.addEventListener("click", swallow, !0), window.setTimeout(() => window.removeEventListener("click", swallow, !0), GHOST_CLICK_WINDOW_MS);
}
function createReaderGestures(options) {
let ctx = useReaderContext(), { viewport, zoom } = options, [zoomImage, setZoomImage] = options.zoomImage, controls = () => getReaderControls(ctx), pagedMode = () => controls().navigationMode === "paged", lastZoomTap = null, pinchStart = null, startPinch = () => {
let percent = ctx.scrollScale.percent();
return pinchStart = percent === null ? null : percent / 100, pinchStart !== null;
}, movePinch = (scale) => {
pinchStart !== null && ctx.scrollScale.resize(clamp(pinchStart * scale, 0.1, 5));
}, endPinch = () => {
pinchStart = null;
}, imageAtPoint = (point) => {
let pageNum = viewport.pageNumAtPoint(point), resource = pageNum === null ? null : ctx.loading.page(pageNum);
return resource?.status === "ready" && resource.image && pageNum !== null ? {
pageNum,
imageUrl: resource.image.imageUrl,
width: resource.element?.naturalWidth || resource.image.width || null,
height: resource.element?.naturalHeight || resource.image.height || null
} : null;
}, prepareZoom = (point, multiplier = 1) => {
let image2 = imageAtPoint(point);
return image2 ? (viewport.stopMotion(), viewport.cancelDrag(), setZoomImage(image2), zoom.reset({ centerX: point.clientX, centerY: point.clientY, scale: viewport.pageZoomScale(image2.pageNum) * multiplier }), !0) : !1;
}, isZoomDoubleTap = (info, event) => {
let now = event.timeStamp || performance.now(), doubleTap = lastZoomTap !== null && now - lastZoomTap.time <= ZOOM_DOUBLE_TAP_MS && Math.hypot(
info.clientX - lastZoomTap.clientX,
info.clientY - lastZoomTap.clientY
) <= ZOOM_DOUBLE_TAP_DISTANCE;
return lastZoomTap = doubleTap ? null : { clientX: info.clientX, clientY: info.clientY, time: now }, doubleTap;
}, isPageReloadButtonTarget = (event) => event.target instanceof Element && event.target.closest(".ehpeek-reader-page-reload") !== null, shouldStartDrag = (event) => zoomImage() !== null || pagedMode() || event.pointerType === "mouse", isPreviewSwipe = (info) => pagedMode() ? controls().direction === "ttb" ? Math.abs(info.dx) >= PAGED_PREVIEW_SWIPE_THRESHOLD && Math.abs(info.dy) <= PAGED_PREVIEW_SWIPE_AXIS_LIMIT : info.dy >= PAGED_PREVIEW_SWIPE_THRESHOLD && Math.abs(info.dx) <= PAGED_PREVIEW_SWIPE_AXIS_LIMIT : !1, runSingleTap = (info, event) => {
if (zoomImage() !== null)
event.preventDefault();
else if (viewport.isHitEndPage(info))
suppressTrailingClick(), ctx.finish();
else {
let zone = viewport.viewportXRatio(info.clientX);
zone >= 1 / 3 && zone <= 2 / 3 ? options.onToggleToolbar() : ctx.position.turnPage(zone < 1 / 3 ? controls().rightTapAction === "previous" ? 1 : -1 : controls().rightTapAction === "previous" ? -1 : 1);
}
}, pointer = {
dragAxis: "any",
onMouseDown: () => viewport.cancelSimulatedScroll(),
onNonMouseDown: () => !pagedMode() && zoomImage() === null && viewport.hasRecentNativeScroll(),
onTap: (info, event) => {
if (viewport.cancelDrag(), zoomImage() !== null) {
isZoomDoubleTap(info, event) && setZoomImage(null), event.preventDefault();
return;
}
let zone = viewport.viewportXRatio(info.clientX);
if (zone >= 1 / 3 && zone <= 2 / 3) {
if (isZoomDoubleTap(info, event) && prepareZoom(info, ZOOM_DOUBLE_TAP_SCALE)) {
options.onHideToolbar(), event.preventDefault();
return;
}
} else
lastZoomTap = null;
runSingleTap(info, event);
},
holdDelay: MOUSE_HOLD_ZOOM_MS,
onHold: (info, event) => (event instanceof PointerEvent ? event.pointerType === "mouse" : event instanceof MouseEvent) ? (lastZoomTap = null, zoomImage() !== null ? (setZoomImage(null), "consume") : prepareZoom(info) ? (zoom.movePinch({ centerX: info.clientX, centerY: info.clientY, scale: 2 }), zoom.endPinch(), "drag") : !1) : !1,
onStart: () => {
if (zoomImage() !== null) {
zoom.startDrag();
return;
}
viewport.stopMotion(), viewport.beginDrag();
},
onMove: (info) => {
if (zoomImage() !== null) {
zoom.moveDrag(info);
return;
}
viewport.moveDrag({ dx: info.dx, dy: info.dy });
},
onEnd: (info) => {
if (zoomImage() === null) {
if (viewport.cancelDrag(), isPreviewSwipe(info)) {
viewport.moveToPage(ctx.position.page()).then((completed) => {
completed && ctx.openPreview();
});
return;
}
if (!pagedMode()) {
controls().direction === "ttb" ? (viewport.moveToTop(viewport.scrollTop()), viewport.startVerticalFlingFromDragVelocity(info.velocityY, () => options.followScroll())) : (viewport.moveToLeft(viewport.scrollLeft()), viewport.startHorizontalFlingFromDragVelocity(info.velocityX, () => options.followScroll())), options.followScroll();
return;
}
if (controls().direction === "ttb") {
info.dy >= PAGED_SWIPE_THRESHOLD ? ctx.position.turnPage(-1) : info.dy <= -PAGED_SWIPE_THRESHOLD ? ctx.position.turnPage(1) : viewport.moveToPage(ctx.position.page(), "animated");
return;
}
info.dx >= PAGED_SWIPE_THRESHOLD ? ctx.position.turnPage(controls().direction === "rtl" ? 1 : -1) : info.dx <= -PAGED_SWIPE_THRESHOLD ? ctx.position.turnPage(controls().direction === "rtl" ? -1 : 1) : viewport.moveToPage(ctx.position.page(), "animated");
}
},
onPinchStart: (info) => {
if (lastZoomTap = null, viewport.stopMotion(), viewport.cancelDrag(), !pagedMode() && zoomImage() === null)
return startPinch();
if (zoomImage() !== null)
return zoom.startPinch({ centerX: info.clientX, centerY: info.clientY }), !0;
let image2 = imageAtPoint(info);
if (!image2)
return !1;
let zoomScale = viewport.pageZoomScale(image2.pageNum);
return setZoomImage(image2), zoom.reset({ centerX: info.clientX, centerY: info.clientY, scale: zoomScale }), !0;
},
onPinchMove: (info) => {
if (pinchStart !== null) {
movePinch(info.scale);
return;
}
zoom.movePinch({
centerX: info.clientX,
centerY: info.clientY,
scale: info.scale
});
},
onPinchEnd: () => {
if (pinchStart !== null) {
endPinch();
return;
}
zoom.endPinch();
},
shouldCaptureDrag: (event) => isPageReloadButtonTarget(event) || !(event instanceof PointerEvent) || event.pointerType === "mouse" && event.button !== 0 ? !1 : shouldStartDrag(event),
shouldObserveTap: (event) => event instanceof PointerEvent && !isPageReloadButtonTarget(event) && event.pointerType !== "mouse" && !shouldStartDrag(event),
dragStartThreshold: TAP_CANCEL_DISTANCE,
tapMoveThreshold: TAP_CANCEL_DISTANCE
}, wheel = (event) => {
if (ctx.disabled()) return;
let delta = Math.abs(event.deltaX) > Math.abs(event.deltaY) ? event.deltaX : event.deltaY, pixels = delta * (event.deltaMode === 1 ? 16 : event.deltaMode === 2 ? window.innerHeight : 1);
zoomImage() ? (event.preventDefault(), zoom.moveWheel({ centerX: event.clientX, centerY: event.clientY, delta: pixels })) : event.ctrlKey || event.metaKey ? (event.preventDefault(), pagedMode() ? prepareZoom(event) && zoom.moveWheel({ centerX: event.clientX, centerY: event.clientY, delta: pixels }) : startPinch() && (movePinch(Math.exp(-clamp(pixels, -100, 100) * 25e-4)), endPinch())) : pagedMode() ? (event.preventDefault(), !viewport.isDragging() && Math.abs(delta) >= 8 && ctx.position.turnPage(delta > 0 ? 1 : -1)) : controls().direction !== "ttb" && (event.preventDefault(), viewport.moveToLeft(viewport.scrollLeft() + pixels * (controls().direction === "rtl" ? -1 : 1) * 0.5));
}, keydown = (event) => {
if (!(ctx.disabled() || event.isComposing || event.target instanceof Element && event.target.closest("input, textarea, select, [contenteditable='true'], [contenteditable='']"))) {
if (event.key === "Escape")
event.preventDefault(), ctx.close();
else if (event.key === "ArrowLeft" || event.key === "ArrowRight" || controls().direction === "ttb" && (event.key === "ArrowUp" || event.key === "ArrowDown")) {
if (event.preventDefault(), zoomImage()) return;
ctx.position.turnPage(event.key === "ArrowUp" ? -1 : event.key === "ArrowDown" ? 1 : event.key === "ArrowLeft" ? controls().rightTapAction === "previous" ? 1 : -1 : controls().rightTapAction === "previous" ? -1 : 1);
}
}
};
return document.addEventListener("keydown", keydown, !0), onCleanup(() => document.removeEventListener("keydown", keydown, !0)), createEffect(() => {
ctx.disabled() && untrack(() => {
endPinch(), lastZoomTap = null, viewport.stopMotion(), viewport.cancelDrag();
});
}), { pointer, wheel };
}
var PAGED_SWIPE_THRESHOLD, PAGED_PREVIEW_SWIPE_THRESHOLD, PAGED_PREVIEW_SWIPE_AXIS_LIMIT, MOUSE_HOLD_ZOOM_MS, ZOOM_DOUBLE_TAP_MS, ZOOM_DOUBLE_TAP_DISTANCE, ZOOM_DOUBLE_TAP_SCALE, TAP_CANCEL_DISTANCE, GHOST_CLICK_WINDOW_MS, init_chunk_WH3QJFUT = __esm({
"../reader/dist/chunk-WH3QJFUT.js"() {
"use strict";
init_chunk_TRAUK5J2();
init_chunk_E6UKP7HT();
init_solid();
PAGED_SWIPE_THRESHOLD = 24, PAGED_PREVIEW_SWIPE_THRESHOLD = 48, PAGED_PREVIEW_SWIPE_AXIS_LIMIT = 32, MOUSE_HOLD_ZOOM_MS = 400, ZOOM_DOUBLE_TAP_MS = 300, ZOOM_DOUBLE_TAP_DISTANCE = 36, ZOOM_DOUBLE_TAP_SCALE = 1.2, TAP_CANCEL_DISTANCE = 8, GHOST_CLICK_WINDOW_MS = 500;
}
});
// ../reader/dist/chunk-IFEJ2BNL.js
function ReaderViewport(props) {
let ctx = useReaderContext(), controls = () => getReaderControls(ctx), pageLayout = () => controls().pageLayout === "double" && controls().firstPageSeparate && ctx.position.page() === 1 ? "single" : controls().pageLayout, pagedMode = () => controls().navigationMode === "paged", initPageNum = untrack(() => props.initPage), horizontalAxis = () => controls().direction !== "ttb", [slots, setSlots] = createSignal([]), [revision, setRevision] = createSignal(0), [size, setSize] = createSignal(null), [firstVisiblePage, setFirstVisiblePage] = createSignal(null), [scrollOffset, setScrollOffset] = createSignal(0), [zoomImage, setZoomImage] = createSignal(null), scroller, scrollerApi, gestures, disposed = !1, resizeFrame, scrollFrame, programmaticFrame, programmatic = !1, lastNativeScrollAt = Number.NEGATIVE_INFINITY, syncingRevision = 0, pages = {
items: []
}, slotFor = (pageNum) => pages.items.find((slot) => slot.pageNum === pageNum), refresh = () => setRevision((value) => value + 1), viewportWidth = () => size()?.width ?? 1, viewportHeight = () => size()?.height ?? 1, scrollTop = () => scrollerApi.scrollTop(), aspectRatio = (pageNum) => {
let resource = ctx.loading.page(pageNum), width = resource?.element?.naturalWidth || resource?.image?.width, height = resource?.element?.naturalHeight || resource?.image?.height;
return width && height ? height / width : normalizedAspectRatio(resource?.page?.aspectRatio, FALLBACK_ASPECT_RATIO);
}, horizontalAnchorOffset = (pageSlots2, anchor2, leadingSpacerWidth) => {
let orderedSlots = controls().direction === "rtl" ? pageSlots2.slice().reverse() : pageSlots2, offset = leadingSpacerWidth;
for (let slot of orderedSlots) {
let extent = slot.frameWidth + PAGE_SLOT_SPACING;
if (slot.pageNum === anchor2.pageNum)
return offset + extent * anchor2.xRatio;
offset += extent;
}
return null;
}, verticalAnchorOffset = (pageSlots2, anchor2, topSpacerHeight) => {
let offset = topSpacerHeight;
for (let slot of pageSlots2) {
let extent = slot.frameHeight + PAGE_SLOT_SPACING;
if (slot.pageNum === anchor2.pageNum)
return offset + extent * anchor2.yRatio;
offset += extent;
}
return null;
}, frameSize = (slot, pageAspectRatio = aspectRatio(slot.pageNum)) => {
let scrolling = controls().navigationMode === "scroll", reference = scrolling ? ctx.scrollScale.referenceImageSize() : null;
return pageFrameSize({
aspectRatio: pageAspectRatio,
contentPage: slot.kind === "page",
viewportWidth: viewportWidth(),
viewportHeight: viewportHeight(),
navigationMode: controls().navigationMode,
pageLayout: pageLayout(),
sizeScale: scrolling ? ctx.scrollScale.value() : null,
reference,
referenceAspectRatio: reference ? reference.height / reference.width : scrolling ? ctx.loading.page(props.initPage)?.page?.aspectRatio ?? FALLBACK_ASPECT_RATIO : FALLBACK_ASPECT_RATIO,
horizontal: scrolling && horizontalAxis()
});
}, applySlotSize = (slot, pageAspectRatio) => {
let frame = frameSize(slot, pageAspectRatio);
slot.frameWidth = frame.width, slot.frameHeight = frame.height;
}, verticalDefaultExtent = () => frameSize({
pageNum: 0,
index: 0,
kind: "page",
frameWidth: 1,
frameHeight: 1,
elements: null
}, FALLBACK_ASPECT_RATIO).height + PAGE_SLOT_SPACING, verticalSpacerExtent = 1, verticalTopSpacerHeight = (pageSlots2 = pages.items, extent = verticalSpacerExtent) => Math.max(0, (pageSlots2[0]?.pageNum ?? 1) - 1) * extent, renderedVerticalTopSpacerHeight = () => (revision(), verticalTopSpacerHeight()), horizontalDefaultExtent = () => frameSize({
pageNum: 0,
index: 0,
kind: "page",
frameWidth: 1,
frameHeight: 1,
elements: null
}, FALLBACK_ASPECT_RATIO).width + PAGE_SLOT_SPACING, horizontalSpacerExtent = 1, horizontalLeadingSpacerWidth = (pageSlots2 = pages.items, extent = horizontalSpacerExtent) => pageSlots2.length === 0 ? 0 : controls().direction === "rtl" ? ctx.source.totalPages ? Math.max(0, ctx.source.totalPages + 1 - pageSlots2[pageSlots2.length - 1].pageNum) * extent : 0 : Math.max(0, pageSlots2[0].pageNum - 1) * extent, renderedHorizontalLeadingSpacerWidth = () => (revision(), horizontalLeadingSpacerWidth()), pageOffset = (pageNum) => {
let elements = slotFor(pageNum)?.elements;
return elements ? scrollerApi.slotOffset(elements, controls().navigationMode, controls().direction, pageLayout()) : null;
}, verticalScrollBoundsForElements = (firstElements, lastElements) => {
let bounds = {};
if (firstElements && (bounds.min = scrollerApi.slotTop(firstElements)), lastElements) {
let lastElementsRect = lastElements.node.getBoundingClientRect(), lastElementsTop = scrollerApi.slotTop(lastElements);
bounds.max = lastElementsTop + lastElementsRect.height - viewportHeight();
}
return bounds.min === void 0 && bounds.max === void 0 ? null : (bounds.min !== void 0 && bounds.max !== void 0 && (bounds.max = Math.max(bounds.min, bounds.max)), bounds);
}, verticalScrollBounds = () => controls().navigationMode !== "scroll" || horizontalAxis() ? null : verticalScrollBoundsForElements(slotFor(1)?.elements, ctx.source.totalPages ? slotFor(ctx.source.totalPages + 1)?.elements : null), moveToTop = (nextScrollTop) => {
scrollerApi.moveToTop(nextScrollTop, verticalScrollBounds());
}, horizontalScrollBounds = () => {
if (controls().navigationMode !== "scroll" || !horizontalAxis())
return null;
let firstElements = slotFor(1)?.elements, endElements = ctx.source.totalPages ? slotFor(ctx.source.totalPages + 1)?.elements : null, bounds = {};
return controls().direction === "rtl" ? (firstElements && (bounds.max = scrollerApi.slotLeft(firstElements) + firstElements.node.getBoundingClientRect().width - viewportWidth()), endElements && (bounds.min = scrollerApi.slotLeft(endElements))) : (firstElements && (bounds.min = scrollerApi.slotLeft(firstElements)), endElements && (bounds.max = scrollerApi.slotLeft(endElements) + endElements.node.getBoundingClientRect().width - viewportWidth())), bounds.min !== void 0 && bounds.max !== void 0 && (bounds.max = Math.max(bounds.min, bounds.max)), bounds.min === void 0 && bounds.max === void 0 ? null : bounds;
}, moveToLeft = (nextScrollLeft) => {
let bounds = horizontalScrollBounds();
scrollerApi.moveToLeft(bounds ? clamp(nextScrollLeft, bounds.min ?? Number.NEGATIVE_INFINITY, bounds.max ?? Number.POSITIVE_INFINITY) : nextScrollLeft);
}, pageNumAtPoint = (point) => {
let element = document.elementFromPoint(point.clientX, point.clientY), pageNode = element instanceof Element ? element.closest(".ehpeek-page") : null;
if (!pageNode || !scroller.contains(pageNode))
return null;
let pageNum = Number(pageNode.dataset.ehpeekPageNum || "");
return Number.isFinite(pageNum) ? pageNum : null;
}, horizontalAnimator = new ScrollAnimator("x"), verticalAnimator = new ScrollAnimator("y"), flingAnimator = new ScrollFlingAnimator(), dragStartPosition = null, settleMove = null, moveRevision = 0, initialSeekActive = !0, suppressScrollObservation = () => {
programmatic = !0, window.cancelAnimationFrame(programmaticFrame ?? 0), programmaticFrame = window.requestAnimationFrame(() => {
programmaticFrame = window.requestAnimationFrame(() => {
programmatic = !1;
});
});
}, stopMotion = () => {
moveRevision++, dragStartPosition = null, flingAnimator.cancel(), horizontalAnimator.cancel(), verticalAnimator.cancel(), settleMove?.(!1), settleMove = null;
}, moveToPage = (pageNum, motion = "instant") => {
pageNum !== initPageNum && (initialSeekActive = !1), stopMotion(), suppressScrollObservation();
let token = moveRevision;
return new Promise((resolve) => {
settleMove = resolve, queueMicrotask(() => untrack(() => {
if (disposed || token !== moveRevision) return;
let delta = pageOffset(pageNum), complete = () => {
token === moveRevision && (settleMove = null, suppressScrollObservation(), setFirstVisiblePage(measureFirstVisiblePage()), resolve(!0));
};
if (delta === null) {
settleMove = null, resolve(!1);
return;
}
programmatic = !0, window.cancelAnimationFrame(programmaticFrame ?? 0), horizontalAxis() ? horizontalAnimator.scrollTo(scroller, scrollerApi.scrollLeft() + delta, motion, complete) : pagedMode() ? verticalAnimator.scrollTo(scroller, scrollTop() + delta, motion, complete) : (moveToTop(scrollTop() + delta), complete());
}));
});
}, gestureDragging = createPointerGestureElement(() => ctx.disabled() || ctx.scrollScale.adjusting() ? null : scroller ?? null, () => gestures.pointer), centerPageNum = () => {
for (let slot of pages.items)
if (slot.elements && slot.kind !== "blank" && scrollerApi.slotContainsViewportTarget(slot.elements, controls().direction))
return slot.pageNum;
return null;
}, measureFirstVisiblePage = () => {
let first = null;
for (let slot of pages.items) {
if (!slot.elements || slot.kind !== "page")
continue;
let distance = scrollerApi.slotViewportStartDistance(slot.elements, controls().direction);
distance !== null && (!first || distance < first.distance) && (first = {
distance,
pageNum: slot.pageNum
});
}
return first?.pageNum ?? null;
}, actions = {
// Movement and its cancellation share the same motion owner.
isDragging: gestureDragging,
beginDrag() {
initialSeekActive = !1, stopMotion(), programmatic = !1, dragStartPosition = {
left: scrollerApi.scrollLeft(),
top: scrollTop()
};
},
cancelDrag: () => {
dragStartPosition = null;
},
moveDrag(delta) {
return dragStartPosition === null ? !1 : (pagedMode() ? horizontalAxis() ? scrollerApi.moveToLeft(dragStartPosition.left - delta.dx) : moveToTop(dragStartPosition.top - delta.dy) : (moveToLeft(dragStartPosition.left - delta.dx), moveToTop(dragStartPosition.top - delta.dy)), !0);
},
moveToLeft,
moveToTop,
moveToPage,
stopMotion,
cancelSimulatedScroll: () => flingAnimator.cancel(),
hasRecentNativeScroll: () => performance.now() - lastNativeScrollAt <= NATIVE_SCROLL_TAP_GUARD_MS,
startVerticalFlingFromDragVelocity(dragVelocityY, onStop) {
flingAnimator.start({
axis: "y",
scroller,
initialVelocity: -dragVelocityY * VERTICAL_FLING_VELOCITY_MULTIPLIER,
maxVelocity: VERTICAL_FLING_MAX_VELOCITY,
decay: VERTICAL_FLING_DECAY,
maxFrameDelta: VERTICAL_FLING_MAX_FRAME_DELTA_MS,
setScrollPosition: moveToTop,
canRun: () => !disposed && controls().navigationMode === "scroll" && !horizontalAxis(),
onStop
});
},
startHorizontalFlingFromDragVelocity(dragVelocityX, onStop) {
flingAnimator.start({
axis: "x",
scroller,
initialVelocity: -dragVelocityX * HORIZONTAL_FLING_VELOCITY_MULTIPLIER,
maxVelocity: HORIZONTAL_FLING_MAX_VELOCITY,
setScrollPosition: moveToLeft,
canRun: () => !disposed && controls().navigationMode === "scroll" && horizontalAxis(),
onStop
});
},
// Read-only measurements translate rendered slots into reader coordinates.
scrollLeft: () => scrollerApi.scrollLeft(),
scrollTop,
viewportXRatio: (clientX) => scrollerApi.viewportXRatio(clientX),
isHitEndPage(point) {
let pageNum = pageNumAtPoint(point);
return pageNum !== null && slotFor(pageNum)?.kind === "end";
},
pageZoomScale(pageNum) {
let frameRect = slotFor(pageNum)?.elements?.frame.getBoundingClientRect(), resource = ctx.loading.page(pageNum), imageWidth = resource?.element?.naturalWidth || resource?.image?.width, imageHeight = resource?.element?.naturalHeight || resource?.image?.height;
if (!frameRect || !imageWidth || !imageHeight)
return 1;
let readerScale = Math.min(frameRect.width / imageWidth, frameRect.height / imageHeight), overlayScale = Math.min(1, viewportWidth() / imageWidth, viewportHeight() / imageHeight);
return readerScale > 0 && overlayScale > 0 ? readerScale / overlayScale : 1;
},
pageNumAtPoint
}, followScroll = () => {
if (setFirstVisiblePage(measureFirstVisiblePage()), ctx.disabled() || ctx.scrollScale.adjusting() || zoomImage() || pagedMode() || programmatic) return;
let page2 = centerPageNum();
page2 !== null && page2 !== ctx.position.page() && props.onScrollPageChange(page2);
}, onScroll = () => {
!pagedMode() && !ctx.scrollScale.adjusting() && !zoomImage() && (horizontalAxis() ? moveToLeft(scrollerApi.scrollLeft()) : moveToTop(scrollTop())), setScrollOffset(horizontalAxis() ? scrollerApi.scrollLeft() : scrollTop()), !programmatic && (!gestureDragging() && !flingAnimator.running() && (lastNativeScrollAt = performance.now()), initialSeekActive = !1, pagedMode() || props.onScrollActivity(horizontalAxis() ? "horizontal" : "vertical"), !(gestureDragging() || scrollFrame !== void 0) && (scrollFrame = window.requestAnimationFrame(() => untrack(() => {
scrollFrame = void 0, followScroll();
}))));
}, previousMode = "", previousDirection = "", previousPageLayout = "", previousViewportSize = null;
createEffect(() => {
let windowNumbers = ctx.loading.windowPages(), mode = controls().navigationMode, direction = controls().direction, layout = pageLayout(), viewportSize = size(), verticalScrolling = mode === "scroll" && direction === "ttb", horizontalScrolling = mode === "scroll" && direction !== "ttb", scrollAxis = verticalScrolling ? "vertical" : horizontalScrolling ? "horizontal" : null, retainWindow = scrollAxis !== null && props.retainScrollWindow === scrollAxis, oldTopSpacerHeight = verticalScrolling ? verticalTopSpacerHeight() : 0, oldLeadingSpacerWidth = horizontalScrolling ? horizontalLeadingSpacerWidth() : 0, nextVerticalSpacerExtent = verticalScrolling && (!retainWindow || verticalSpacerExtent === 1) ? verticalDefaultExtent() : verticalSpacerExtent, nextHorizontalSpacerExtent = horizontalScrolling && (!retainWindow || horizontalSpacerExtent === 1) ? horizontalDefaultExtent() : horizontalSpacerExtent, scrollWindowNumbers = mode === "scroll" ? windowNumbers.filter((pageNum) => pageNum >= 1 && (!ctx.source.totalPages || pageNum <= ctx.source.totalPages + 1)) : windowNumbers, numbers = retainWindow ? [.../* @__PURE__ */ new Set([...pages.items.map((slot) => slot.pageNum), ...scrollWindowNumbers])].sort((left, right) => left - right) : scrollWindowNumbers, anchorMoveRevision = moveRevision, windowChanged = pages.items.length !== numbers.length || pages.items.some((slot, index) => slot.pageNum !== numbers[index]), nativeScrollWindowChange = scrollAxis !== null && windowChanged && previousMode === mode && previousDirection === direction && previousPageLayout === layout && previousViewportSize?.width === viewportSize?.width && previousViewportSize?.height === viewportSize?.height, anchor2 = settleMove ? null : scrollerApi.centerAnchor(), oldOffset = anchor2 && nativeScrollWindowChange && horizontalAxis() ? horizontalAnchorOffset(pages.items, anchor2, oldLeadingSpacerWidth) : null, oldLeft = scrollerApi.scrollLeft(), oldVerticalOffset = anchor2 && nativeScrollWindowChange && verticalScrolling ? verticalAnchorOffset(pages.items, anchor2, oldTopSpacerHeight) : null, oldTop = scrollTop(), previous = new Map(pages.items.map((slot) => [slot.pageNum, slot])), previousSizes = pages.items.map((slot) => ({
page: slot.pageNum,
width: slot.frameWidth,
height: slot.frameHeight
})), previousFirstPage = previousSizes[0]?.page, previousLastPage = previousSizes[previousSizes.length - 1]?.page;
pages.items = numbers.map((pageNum, index) => {
let previousSlot = previous.get(pageNum), slot = previousSlot ?? {
pageNum,
index,
kind: pageNum < 1 || ctx.source.totalPages && pageNum > ctx.source.totalPages + 1 ? "blank" : ctx.source.totalPages && pageNum === ctx.source.totalPages + 1 ? "end" : "page",
frameWidth: 1,
frameHeight: 1,
elements: null
};
if (slot.index = index, !previousSlot && retainWindow && horizontalScrolling && (direction === "rtl" ? pageNum > (previousLastPage ?? pageNum) : pageNum < (previousFirstPage ?? pageNum))) {
let fallbackFrame = frameSize(slot, FALLBACK_ASPECT_RATIO);
slot.frameWidth = Math.max(1, nextHorizontalSpacerExtent - PAGE_SLOT_SPACING), slot.frameHeight = fallbackFrame.height;
}
if (!previousSlot && retainWindow && verticalScrolling && pageNum < (previousFirstPage ?? pageNum)) {
let fallbackFrame = frameSize(slot, FALLBACK_ASPECT_RATIO);
slot.frameWidth = fallbackFrame.width, slot.frameHeight = Math.max(1, nextVerticalSpacerExtent - PAGE_SLOT_SPACING);
}
return slot;
});
for (let slot of pages.items)
retainWindow ? slot.frameWidth === 1 && slot.frameHeight === 1 && applySlotSize(slot) : applySlotSize(slot);
let nextTopSpacerHeight = verticalScrolling ? verticalTopSpacerHeight(pages.items, nextVerticalSpacerExtent) : 0, nextLeadingSpacerWidth = horizontalScrolling ? horizontalLeadingSpacerWidth(pages.items, nextHorizontalSpacerExtent) : 0;
if (!(previousMode !== mode || previousDirection !== direction || previousPageLayout !== layout || previousViewportSize?.width !== viewportSize?.width || previousViewportSize?.height !== viewportSize?.height || oldTopSpacerHeight !== nextTopSpacerHeight || oldLeadingSpacerWidth !== nextLeadingSpacerWidth || previousSizes.length !== pages.items.length || pages.items.some((slot, index) => {
let old = previousSizes[index];
return !old || old.page !== slot.pageNum || old.width !== slot.frameWidth || old.height !== slot.frameHeight;
}))) return;
previousMode = mode, previousDirection = direction, previousPageLayout = layout, previousViewportSize = viewportSize, verticalSpacerExtent = nextVerticalSpacerExtent, horizontalSpacerExtent = nextHorizontalSpacerExtent, setSlots(pages.items.slice()), refresh();
let nextOffset = anchor2 && nativeScrollWindowChange && horizontalAxis() ? horizontalAnchorOffset(pages.items, anchor2, nextLeadingSpacerWidth) : null, nextVerticalOffset = anchor2 && nativeScrollWindowChange && verticalScrolling ? verticalAnchorOffset(pages.items, anchor2, nextTopSpacerHeight) : null, token = ++syncingRevision, horizontallyReanchored = oldOffset !== null && nextOffset !== null;
if (horizontallyReanchored) {
let nextLeft = oldLeft + nextOffset - oldOffset;
Math.abs(nextLeft - oldLeft) >= 0.5 && (suppressScrollObservation(), moveToLeft(nextLeft));
}
let verticallyReanchored = oldVerticalOffset !== null && nextVerticalOffset !== null;
if (verticallyReanchored) {
let nextTop = oldTop + nextVerticalOffset - oldVerticalOffset;
Math.abs(nextTop - oldTop) >= 0.5 && (suppressScrollObservation(), moveToTop(nextTop));
}
queueMicrotask(() => {
disposed || token !== syncingRevision || (initialSeekActive && !settleMove ? moveToPage(initPageNum) : anchor2 && !horizontallyReanchored && !verticallyReanchored && !settleMove && anchorMoveRevision === moveRevision && (suppressScrollObservation(), scrollerApi.restoreCenterAnchor(anchor2)), setFirstVisiblePage(measureFirstVisiblePage()));
});
}), createEffect(() => {
zoomImage() && (initialSeekActive = !1);
});
let stripStyle = () => (revision(), pagedMode() ? {} : horizontalAxis() ? {
height: `${Math.max(viewportHeight(), ...pages.items.map((slot) => slot.frameHeight))}px`,
width: "max-content"
} : {
width: `${Math.max(viewportWidth(), ...pages.items.map((slot) => slot.frameWidth))}px`
});
return onMount(() => {
let measure = () => {
setSize({
width: Math.max(1, scroller.clientWidth || window.innerWidth),
height: Math.max(1, scroller.clientHeight || window.innerHeight)
});
};
measure();
let observer = new ResizeObserver(() => {
resizeFrame === void 0 && (resizeFrame = window.requestAnimationFrame(() => {
resizeFrame = void 0, measure();
}));
});
observer.observe(scroller), onCleanup(() => observer.disconnect()), ctx.refs.bindViewport({
size,
firstVisiblePage,
moveToPage,
stopMotion,
closeZoom() {
return zoomImage() ? (setZoomImage(null), !0) : !1;
}
}), scroller.focus({
preventScroll: !0
}), moveToPage(props.initPage);
}), onCleanup(() => {
disposed = !0, stopMotion(), window.cancelAnimationFrame(resizeFrame ?? 0), window.cancelAnimationFrame(scrollFrame ?? 0), window.cancelAnimationFrame(programmaticFrame ?? 0), ctx.refs.bindViewport(null);
}), [createComponent(ZoomOverlay, {
get image() {
return zoomImage();
},
onClose: () => setZoomImage(null),
actionsRef: (zoom) => {
gestures = createReaderGestures({
viewport: actions,
zoom,
zoomImage: [zoomImage, setZoomImage],
onToggleToolbar: () => props.onToggleToolbar(),
onHideToolbar: () => props.onHideToolbar(),
followScroll
});
}
}), (() => {
var _el$ = _tmpl$17(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.firstChild, _el$5 = _el$4.nextSibling;
return _el$2.addEventListener("wheel", (event) => gestures.wheel(event)), _el$2.addEventListener("scroll", onScroll), use((element) => {
scroller = element, scrollerApi = createPagesScroller(element);
}, _el$2), insert(_el$3, createComponent(For, {
get each() {
return slots();
},
children: (slot) => createComponent(PageFrame, {
slot,
get revision() {
return revision();
},
get visualIndex() {
return memo(() => controls().direction === "rtl")() ? slots().length - 1 - slot.index : slot.index;
},
get side() {
return memo(() => !pagedMode() || pageLayout() !== "double")() ? null : Math.abs(slot.pageNum - ctx.position.page()) % 2 === 0 == (controls().direction === "rtl") ? "right" : "left";
}
})
}), null), createRenderEffect((_p$) => {
var _v$ = controls().navigationMode, _v$2 = controls().direction, _v$3 = pageLayout(), _v$4 = zoomImage() !== null, _v$5 = stripStyle(), _v$6 = `${renderedHorizontalLeadingSpacerWidth()}px`, _v$7 = `${renderedVerticalTopSpacerHeight()}px`;
return _v$ !== _p$.e && setAttribute(_el$2, "data-navigation-mode", _p$.e = _v$), _v$2 !== _p$.t && setAttribute(_el$2, "data-read-direction", _p$.t = _v$2), _v$3 !== _p$.a && setAttribute(_el$2, "data-page-layout", _p$.a = _v$3), _v$4 !== _p$.o && setAttribute(_el$2, "data-zoom-active", _p$.o = _v$4), _p$.i = style(_el$3, _v$5, _p$.i), _v$6 !== _p$.n && setStyleProperty(_el$4, "--reader-horizontal-spacer-width", _p$.n = _v$6), _v$7 !== _p$.s && setStyleProperty(_el$5, "--reader-vertical-spacer-height", _p$.s = _v$7), _p$;
}, {
e: void 0,
t: void 0,
a: void 0,
o: void 0,
i: void 0,
n: void 0,
s: void 0
}), _el$;
})(), createComponent(Show, {
get when() {
return memo(() => !pagedMode() && controls().direction === "ttb")() && (ctx.source.totalPages ?? 0) > 1;
},
get children() {
return createComponent(ReaderPositionBar, {
get scrollOffset() {
return scrollOffset();
},
get viewportLength() {
return viewportHeight();
},
get narrow() {
return viewportWidth() < window.innerWidth;
}
});
}
})];
}
function PageFrame(props) {
let node, style2 = () => {
props.revision;
let short = Math.min(props.slot.frameWidth, props.slot.frameHeight);
return {
"--reader-page-height": `${props.slot.frameHeight + PAGE_SLOT_SPACING}px`,
"--reader-page-width": `${props.slot.frameWidth + PAGE_SLOT_SPACING}px`,
"--reader-frame-width": `${props.slot.frameWidth}px`,
"--reader-frame-height": `${props.slot.frameHeight}px`,
"--reader-end-font-size": `${Math.max(10, short * 0.11)}px`,
"--reader-end-padding": `${Math.min(24, Math.max(4, short * 0.06))}px`,
order: String(props.visualIndex)
};
};
return onCleanup(() => {
props.slot.elements = null;
}), (() => {
var _el$6 = _tmpl$29(), _el$7 = _el$6.firstChild, _ref$ = node;
return typeof _ref$ == "function" ? use(_ref$, _el$6) : node = _el$6, use((frame) => {
props.slot.elements = {
node,
frame
};
}, _el$7), insert(_el$7, createComponent(ReaderPageView, {
get pageNum() {
return props.slot.pageNum;
}
})), createRenderEffect((_p$) => {
var _v$8 = props.side, _v$9 = String(props.slot.pageNum), _v$0 = style2();
return _v$8 !== _p$.e && setAttribute(_el$6, "data-pair-side", _p$.e = _v$8), _v$9 !== _p$.t && setAttribute(_el$6, "data-ehpeek-page-num", _p$.t = _v$9), _p$.a = style(_el$6, _v$0, _p$.a), _p$;
}, {
e: void 0,
t: void 0,
a: void 0
}), _el$6;
})();
}
var _tmpl$17, _tmpl$29, PAGE_SLOT_SPACING, FALLBACK_ASPECT_RATIO, HORIZONTAL_FLING_VELOCITY_MULTIPLIER, HORIZONTAL_FLING_MAX_VELOCITY, VERTICAL_FLING_VELOCITY_MULTIPLIER, VERTICAL_FLING_MAX_VELOCITY, VERTICAL_FLING_DECAY, VERTICAL_FLING_MAX_FRAME_DELTA_MS, NATIVE_SCROLL_TAP_GUARD_MS, init_chunk_IFEJ2BNL = __esm({
"../reader/dist/chunk-IFEJ2BNL.js"() {
"use strict";
init_chunk_FUW3K55A();
init_chunk_NP6I7EK4();
init_chunk_V7QAVQKV();
init_chunk_MLGDT3ZG();
init_chunk_F33WVP3N();
init_chunk_GUZXW3OF();
init_chunk_W6Q6Q5LD();
init_chunk_WH3QJFUT();
init_chunk_TRAUK5J2();
init_chunk_E6UKP7HT();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_solid();
_tmpl$17 = /* @__PURE__ */ template("<div class=ehpeek-reader-canvas><div class=ehpeek-reader-scroller tabindex=-1><main class=ehpeek-reader-page-strip><div class=ehpeek-reader-horizontal-spacer aria-hidden=true></div><div class=ehpeek-reader-vertical-spacer aria-hidden=true>"), _tmpl$29 = /* @__PURE__ */ template("<section class=ehpeek-page><div class=ehpeek-reader-page-frame>"), PAGE_SLOT_SPACING = 8, FALLBACK_ASPECT_RATIO = 1.42, HORIZONTAL_FLING_VELOCITY_MULTIPLIER = 1.4, HORIZONTAL_FLING_MAX_VELOCITY = 1.8, VERTICAL_FLING_VELOCITY_MULTIPLIER = 1.35, VERTICAL_FLING_MAX_VELOCITY = 2.4, VERTICAL_FLING_DECAY = 1e-3, VERTICAL_FLING_MAX_FRAME_DELTA_MS = 96, NATIVE_SCROLL_TAP_GUARD_MS = 120;
}
});
// ../reader/dist/chunk-CFKOVVT2.js
function Reader(props) {
let source = untrack(() => props.source), settings2 = untrack(() => props.settings), [orientation, setOrientation] = createSignal(currentReaderOrientation()), [firstPageSeparate, setFirstPageSeparate] = createSignal(!1), initial = untrack(() => {
let controls2 = settings2[`${orientation()}Controls`];
return normalizeReadingPage(props.initPage ?? source.initialPageNum, source.totalPages, controls2.navigationMode.value(), controls2.pageLayout.value(), !1);
}), [page2, setPage] = createSignal(initial), [scrollWindowMode, setScrollWindowMode] = createSignal(null), windowSettleTimer, [seeking, setSeeking] = createSignal(!1), [closing, setClosing] = createSignal(!1), [toolbarOpen, setToolbarOpen] = createSignal(!1), [viewport, setViewport] = createSignal(null), refs = {
viewport,
bindViewport: setViewport
}, [notifyIntent, setNotifyIntent] = createSignal(!0), publisher = createReadProgressPublisher(), element, disposed = !1, turnTarget = null, turnRevision = 0, seekTimer, lastReported = null, disabled = () => (props.disabled ?? !1) || closing(), controls = () => getReaderControls(ctx), normalize = (pageNum) => normalizeReadingPage(pageNum, source.totalPages, controls().navigationMode, controls().pageLayout, firstPageSeparate()), cancelTurn = () => {
turnRevision++, turnTarget = null, refs.viewport()?.stopMotion();
}, cancelSeek = () => {
window.clearTimeout(seekTimer), seekTimer = void 0, setSeeking(!1);
};
function gotoPage(pageNum, publish = !0) {
if (disposed || closing() || !Number.isFinite(pageNum)) return;
let target = normalize(pageNum);
publish || (lastReported = target), cancelTurn(), batch(() => {
window.clearTimeout(windowSettleTimer), setScrollWindowMode(null), cancelSeek(), setNotifyIntent(publish), setPage(target);
}), refs.viewport()?.moveToPage(page2());
}
let position = {
page: page2,
seeking,
contentPages() {
let current = page2();
return (controls().navigationMode === "paged" && controls().pageLayout === "double" && !(firstPageSeparate() && current === 1) ? [current, current + 1] : [current]).filter((number) => number >= 1 && (!source.totalPages || number <= source.totalPages));
},
gotoPage,
turnPage(step) {
if (disabled()) return;
if (controls().navigationMode !== "paged") {
gotoPage(page2() + step);
return;
}
let base = turnTarget ?? page2(), target = nextReadingPage(base, step, source.totalPages, controls().pageLayout, firstPageSeparate());
if (target === base) {
turnTarget === null && refs.viewport()?.moveToPage(page2(), "animated");
return;
}
cancelSeek();
let token = ++turnRevision;
turnTarget = target, loading.windowPages().includes(target) || batch(() => {
setNotifyIntent(!0), setPage(target);
}), refs.viewport()?.moveToPage(target, "animated").then((completed) => untrack(() => {
disposed || token !== turnRevision || (turnTarget = null, completed && (batch(() => {
setNotifyIntent(!0), setPage(target);
}), refs.viewport()?.moveToPage(target)));
}));
},
beginSeek() {
disabled() || (cancelTurn(), window.clearTimeout(seekTimer), setNotifyIntent(!1), setSeeking(!0));
},
seek(pageNum) {
disabled() || !Number.isFinite(pageNum) || pageNum <= 0 || (position.beginSeek(), setPage(normalize(Math.min(pageNum, source.totalPages || Number.MAX_SAFE_INTEGER))), refs.viewport()?.moveToPage(page2()), seekTimer = window.setTimeout(position.commitSeek, 180));
},
commitSeek() {
disabled() || !seeking() || gotoPage(page2());
}
}, loading = untrack(() => createReaderLoading({
source,
requestedPage: page2,
priorityPages: position.contentPages,
firstVisiblePage: () => refs.viewport()?.firstVisiblePage() ?? null,
seeking,
closing,
renderWindowSize: props.renderWindowSize,
preloadWindowSize: props.preloadWindowSize,
concurrentLoads: props.concurrentLoads,
decodedImageCacheLimit: props.decodedImageCacheLimit
})), referenceImageSize = createMemo((previous) => {
if (previous) return previous;
let resource = loading.page(initial), width = resource?.element?.naturalWidth || resource?.image?.width, height = resource?.element?.naturalHeight || resource?.image?.height;
return width && height ? {
width,
height
} : null;
}, null), scrollScale = untrack(() => createReaderScrollScale({
settings: settings2,
direction: () => {
let current = settings2[`${orientation()}Controls`];
return current.navigationMode.value() === "scroll" ? current.scrollDirection.value() : current.pagedDirection.value();
},
viewportSize: () => refs.viewport()?.size() ?? null,
referenceImageSize
}));
function close() {
closing() || refs.viewport()?.closeZoom() || props.onClose() && (cancelTurn(), cancelSeek(), setClosing(!0));
}
let ctx = {
source,
settings: settings2,
orientation,
position,
loading,
scrollScale,
firstPageSeparate: [firstPageSeparate, setFirstPageSeparate],
disabled,
refs,
customization: untrack(() => props.customization) ?? {},
close,
openPreview: () => props.onOpenPreview(page2()),
finish: () => {
props.onEnd(), close();
}
};
return createEffect(() => {
let current = page2(), resource = loading.page(current);
seeking() || closing() || !notifyIntent() || !resource?.page || lastReported === current || (lastReported = current, untrack(() => {
publisher.publish(current), props.onProgress(resource.page);
}));
}), createEffect(on(controls, (next, previous) => {
previous && next.navigationMode === previous.navigationMode && next.pageLayout === previous.pageLayout && next.direction === previous.direction && next.firstPageSeparate === previous.firstPageSeparate || (cancelTurn(), controls().navigationMode !== "scroll" && scrollScale.apply(), batch(() => {
setNotifyIntent(!0), setPage(normalize(page2()));
}), refs.viewport()?.moveToPage(page2()));
}, {
defer: !0
})), createEffect(() => {
disabled() && untrack(() => {
cancelTurn(), cancelSeek(), setNotifyIntent(!1);
});
}), untrack(() => bindInteractionGate(() => element, disabled)), onMount(() => {
let updateOrientation = () => setOrientation(currentReaderOrientation());
window.addEventListener("resize", updateOrientation), onCleanup(() => window.removeEventListener("resize", updateOrientation)), props.ref?.({
gotoPage,
progress: {
current: page2,
subscribe: publisher.subscribe,
setProgress: (number) => gotoPage(number, !1)
}
});
}), onCleanup(() => {
disposed = !0, window.clearTimeout(windowSettleTimer), cancelTurn(), cancelSeek(), props.ref?.(null);
}), createComponent(ReaderContextKey.Provider, {
value: ctx,
get children() {
var _el$ = _tmpl$210(), _ref$ = element;
return typeof _ref$ == "function" ? use(_ref$, _el$) : element = _el$, insert(_el$, createComponent(Show, {
get when() {
return !scrollScale.adjusting();
},
get children() {
var _el$2 = _tmpl$18();
return insert(_el$2, createComponent(ReaderToolbar, {
get open() {
return toolbarOpen();
},
get fullscreenActive() {
return props.fullscreenActive;
},
get onToggleFullscreen() {
return props.onToggleFullscreen;
}
})), _el$2;
}
}), null), insert(_el$, createComponent(ReaderViewport, {
initPage: initial,
get retainScrollWindow() {
return scrollWindowMode();
},
onScrollActivity: (axis) => {
setScrollWindowMode(axis), window.clearTimeout(windowSettleTimer), windowSettleTimer = window.setTimeout(() => setScrollWindowMode(null), SCROLL_WINDOW_SETTLE_MS);
},
onScrollPageChange: (number) => {
seeking() || closing() || (turnTarget = null, batch(() => {
setNotifyIntent(!0), setPage(number);
}));
},
onToggleToolbar: () => setToolbarOpen((value) => !value),
onHideToolbar: () => setToolbarOpen(!1)
}), null), insert(_el$, createComponent(ReaderScrollScaleControls, {}), null), createRenderEffect((_p$) => {
var _v$ = controls().navigationMode, _v$2 = controls().pageLayout === "double" && firstPageSeparate() && page2() === 1 ? "single" : controls().pageLayout, _v$3 = controls().direction;
return _v$ !== _p$.e && setAttribute(_el$, "data-navigation-mode", _p$.e = _v$), _v$2 !== _p$.t && setAttribute(_el$, "data-page-layout", _p$.t = _v$2), _v$3 !== _p$.a && setAttribute(_el$, "data-read-direction", _p$.a = _v$3), _p$;
}, {
e: void 0,
t: void 0,
a: void 0
}), _el$;
}
});
}
var _tmpl$18, _tmpl$210, SCROLL_WINDOW_SETTLE_MS, init_chunk_CFKOVVT2 = __esm({
"../reader/dist/chunk-CFKOVVT2.js"() {
"use strict";
init_chunk_I4HV7TJW();
init_chunk_PBZTMYEM();
init_chunk_FRCEUGG2();
init_chunk_CK6USHZG();
init_chunk_WWFOV7YA();
init_chunk_7DN2G2IN();
init_chunk_IFEJ2BNL();
init_chunk_GUZXW3OF();
init_chunk_TRAUK5J2();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_solid();
_tmpl$18 = /* @__PURE__ */ template("<header class=ehpeek-reader-header>"), _tmpl$210 = /* @__PURE__ */ template("<div id=ehpeek-reader class=ehpeek-reader>"), SCROLL_WINDOW_SETTLE_MS = 250;
}
});
// ../reader/dist/chunk-R253JGHC.js
function createPreviewLoading(options) {
let queue = new PriorityLoadQueue(
PREVIEW_CONCURRENT_LOADS
), requestedBatches = /* @__PURE__ */ new Set(), [failedBatches, setFailedBatches] = createSignal(/* @__PURE__ */ new Set()), [loadingCount, setLoadingCount] = createSignal(0), loadToken = 0, sync = (centerIndex, retryIndex) => {
let firstIndex = Math.max(0, centerIndex - PREVIEW_LOAD_RADIUS), lastIndex = Math.min(options.previewCache.maxBatch, centerIndex + PREVIEW_LOAD_RADIUS), targets = [];
for (let batchIndex = firstIndex; batchIndex <= lastIndex; batchIndex += 1)
targets.push({
key: batchIndex,
priority: batchIndex === retryIndex ? -1 : Math.abs(batchIndex - centerIndex),
target: batchIndex
});
queue.sync(targets);
};
return queue.updateCallbacks({
loadTarget: (batchIndex) => options.previewCache.load(batchIndex),
markLoading: (batchIndex) => requestedBatches.has(batchIndex) ? null : (requestedBatches.add(batchIndex), setFailedBatches((current) => {
if (!current.has(batchIndex))
return current;
let next = new Set(current);
return next.delete(batchIndex), next;
}), setLoadingCount((count) => count + 1), ++loadToken),
onLoaded: () => {
setLoadingCount((count) => Math.max(0, count - 1));
},
onError: (batchIndex, error) => {
requestedBatches.delete(batchIndex), setFailedBatches((current) => new Set(current).add(batchIndex)), setLoadingCount((count) => Math.max(0, count - 1)), options.onLoadError(error);
}
}), createEffect(() => {
options.ready() && sync(options.previewCache.batchForPage(options.centeredPageNum()));
}), onCleanup(() => queue.dispose()), {
failedBatches,
loadingCount,
retry(pageNum) {
let retryIndex = options.previewCache.batchForPage(pageNum);
sync(
options.previewCache.batchForPage(options.centeredPageNum()),
retryIndex
);
}
};
}
var PREVIEW_CONCURRENT_LOADS, PREVIEW_LOAD_RADIUS, init_chunk_R253JGHC = __esm({
"../reader/dist/chunk-R253JGHC.js"() {
"use strict";
init_chunk_UVKXFJHK();
init_solid();
PREVIEW_CONCURRENT_LOADS = 2, PREVIEW_LOAD_RADIUS = 2;
}
});
// ../reader/dist/chunk-ABQJ4E5U.js
function useScrollPreviewContext() {
let ctx = useContext(ScrollPreviewContextKey);
if (!ctx) throw new Error("ScrollPreview context is unavailable.");
return ctx;
}
var ScrollPreviewContextKey, init_chunk_ABQJ4E5U = __esm({
"../reader/dist/chunk-ABQJ4E5U.js"() {
"use strict";
init_solid();
ScrollPreviewContextKey = createContext();
}
});
// ../reader/dist/chunk-IECOMI6N.js
function PreviewToolbar(props) {
let ctx = useScrollPreviewContext(), texts = useReaderTexts(), crossCount = () => ctx.refs.viewport()?.crossCount() ?? 1, crossCountLimits = () => ctx.refs.viewport()?.crossCountLimits() ?? {
min: 1,
max: 1
}, direction = () => ctx.settings[0].direction, directionIcon = () => direction() === "ttb" ? "arrow-down" : direction() === "rtl" ? "arrow-left" : "arrow-right", directionLabel = () => direction() === "ttb" ? texts.gallery.scrollPreviewDirectionTtb : direction() === "rtl" ? texts.gallery.scrollPreviewDirectionRtl : texts.gallery.scrollPreviewDirectionLtr, changeDirection = () => {
window.confirm(texts.gallery.confirmScrollPreviewDirection) && ctx.settings[1]("direction", NEXT_DIRECTION[direction()]);
}, range2 = () => {
let pages = ctx.refs.viewport()?.visiblePages();
return pages ? `${pages.first}–${pages.last} / ${ctx.previewCache.source.totalPages}` : `— / ${ctx.previewCache.source.totalPages}`;
};
return (() => {
var _el$ = _tmpl$211(), _el$2 = _el$.firstChild, _el$4 = _el$2.nextSibling;
return insert(_el$2, createComponent(Show, {
get when() {
return ctx.loading.loadingCount() > 0;
},
get children() {
return _tmpl$19();
}
}), null), insert(_el$2, range2, null), insert(_el$4, createComponent(IconButton, {
variant: "subtle",
size: "md",
get "aria-label"() {
return directionLabel();
},
get title() {
return directionLabel();
},
onClick: changeDirection,
get children() {
return createComponent(Icon2, {
get name() {
return directionIcon();
},
size: "var(--ui-icon-size-md)"
});
}
}), null), insert(_el$4, createComponent(IconButton, {
variant: "subtle",
size: "md",
get "aria-label"() {
return texts.common.actions.zoomOut;
},
get title() {
return texts.common.actions.zoomOut;
},
get disabled() {
return crossCount() >= crossCountLimits().max;
},
onClick: () => ctx.settings[1]("crossCount", clamp(crossCount() + 1, crossCountLimits().min, crossCountLimits().max)),
get children() {
return createComponent(Icon2, {
name: "zoom-out",
size: "var(--ui-icon-size-md)"
});
}
}), null), insert(_el$4, createComponent(IconButton, {
variant: "subtle",
size: "md",
get "aria-label"() {
return texts.common.actions.zoomIn;
},
get title() {
return texts.common.actions.zoomIn;
},
get disabled() {
return crossCount() <= crossCountLimits().min;
},
onClick: () => ctx.settings[1]("crossCount", clamp(crossCount() - 1, crossCountLimits().min, crossCountLimits().max)),
get children() {
return createComponent(Icon2, {
name: "zoom-in",
size: "var(--ui-icon-size-md)"
});
}
}), null), insert(_el$4, createComponent(IconButton, {
variant: "subtle",
size: "md",
get "aria-label"() {
return texts.common.actions.current;
},
get title() {
return texts.common.actions.current;
},
get disabled() {
return ctx.progress.current() === null;
},
onClick: () => ctx.locateHighlightedPage(),
get children() {
return createComponent(Icon2, {
name: "locate",
size: "var(--ui-icon-size-md)"
});
}
}), null), insert(_el$4, createComponent(Show, {
get when() {
return ctx.resize;
},
get children() {
return createComponent(IconButton, {
variant: "subtle",
size: "md",
get "aria-label"() {
return texts.gallery.openScrollPreview;
},
get title() {
return texts.gallery.openScrollPreview;
},
onClick: () => ctx.resize?.(),
get children() {
return createComponent(Icon2, {
name: "fullscreen",
size: "var(--ui-icon-size-md)"
});
}
});
}
}), null), insert(_el$4, createComponent(Show, {
get when() {
return ctx.close;
},
get children() {
return createComponent(IconButton, {
variant: "subtle",
size: "md",
get "aria-label"() {
return texts.common.actions.close;
},
get title() {
return texts.common.actions.close;
},
onClick: () => ctx.close?.(),
get children() {
return createComponent(Icon2, {
name: "close",
size: "var(--ui-icon-size-md)"
});
}
});
}
}), null), createRenderEffect((_p$) => {
var _v$ = `ehpeek-preview-toolbar${props.class ? ` ${props.class}` : ""}`, _v$2 = props.style, _v$3 = ctx.leftHanded();
return _v$ !== _p$.e && className(_el$, _p$.e = _v$), _p$.t = style(_el$, _v$2, _p$.t), _v$3 !== _p$.a && setAttribute(_el$, "data-left-handed", _p$.a = _v$3), _p$;
}, {
e: void 0,
t: void 0,
a: void 0
}), _el$;
})();
}
var _tmpl$19, _tmpl$211, NEXT_DIRECTION, init_chunk_IECOMI6N = __esm({
"../reader/dist/chunk-IECOMI6N.js"() {
"use strict";
init_chunk_ABQJ4E5U();
init_chunk_4Y6MOAXB();
init_chunk_UPVG5Y6S();
init_chunk_JXES5MWD();
init_chunk_E6UKP7HT();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_solid();
_tmpl$19 = /* @__PURE__ */ template("<span class=ehpeek-preview-loading>"), _tmpl$211 = /* @__PURE__ */ template("<div><span class=ehpeek-preview-range></span><div class=ehpeek-preview-toolbar-actions>"), NEXT_DIRECTION = {
ltr: "rtl",
rtl: "ttb",
ttb: "ltr"
};
}
});
// ../reader/dist/chunk-WGECFBEU.js
function PreviewGrid(props) {
return (() => {
var _el$ = _tmpl$20();
return insert(_el$, createComponent(For, {
get each() {
return props.tiles;
},
children: (tile) => createComponent(PreviewTile, mergeProps(tile, {
get maximumScale() {
return props.maximumScale;
}
}))
})), createRenderEffect((_p$) => {
var _v$ = `${props.contentSize.height}px`, _v$2 = `${props.contentSize.width}px`;
return _v$ !== _p$.e && setStyleProperty(_el$, "height", _p$.e = _v$), _v$2 !== _p$.t && setStyleProperty(_el$, "width", _p$.t = _v$2), _p$;
}, {
e: void 0,
t: void 0
}), _el$;
})();
}
function PreviewTile(props) {
let ctx = useScrollPreviewContext(), failed = () => ctx.loading.failedBatches().has(ctx.previewCache.batchForPage(props.pageNum)), item = () => (ctx.previewCache.version(), ctx.previewCache.item(props.pageNum)), releaseDecodedImage = null;
return createEffect(() => {
releaseDecodedImage?.();
let current = item();
releaseDecodedImage = current?.thumbnail.url ? ctx.decodeCache.retain(current.thumbnail.url) : null;
}), onCleanup(() => releaseDecodedImage?.()), (() => {
var _el$2 = _tmpl$212(), _el$3 = _el$2.firstChild;
return insert(_el$3, createComponent(Show, {
get when() {
return item();
},
keyed: !0,
get fallback() {
return (() => {
var _el$4 = _tmpl$37(), _el$5 = _el$4.firstChild;
return _el$4.$$click = () => ctx.loading.retry(props.pageNum), insert(_el$4, createComponent(Show, {
get when() {
return failed();
},
get children() {
return createComponent(Icon2, {
name: "refresh",
size: "var(--ui-icon-size-lg)"
});
}
}), _el$5), insert(_el$5, () => props.pageNum), createRenderEffect(() => _el$4.disabled = !failed()), _el$4;
})();
},
children: (loaded) => {
let imageScale = () => Math.min(props.maximumScale, props.height / loaded.thumbnail.height, props.width / loaded.thumbnail.width);
return [createComponent(Show, {
get when() {
return loaded.thumbnail.kind === "background";
},
get fallback() {
return (() => {
var _el$9 = _tmpl$73();
return setAttribute(_el$9, "draggable", !1), createRenderEffect((_p$) => {
var _v$17 = loaded.thumbnail.url, _v$18 = loaded.thumbnail.width, _v$19 = loaded.thumbnail.height, _v$20 = `${loaded.thumbnail.height * imageScale()}px`, _v$21 = `${loaded.thumbnail.width * imageScale()}px`;
return _v$17 !== _p$.e && setAttribute(_el$9, "src", _p$.e = _v$17), _v$18 !== _p$.t && setAttribute(_el$9, "width", _p$.t = _v$18), _v$19 !== _p$.a && setAttribute(_el$9, "height", _p$.a = _v$19), _v$20 !== _p$.o && setStyleProperty(_el$9, "height", _p$.o = _v$20), _v$21 !== _p$.i && setStyleProperty(_el$9, "width", _p$.i = _v$21), _p$;
}, {
e: void 0,
t: void 0,
a: void 0,
o: void 0,
i: void 0
}), _el$9;
})();
},
get children() {
var _el$6 = _tmpl$45();
return createRenderEffect((_p$) => {
var _v$8 = `url(${JSON.stringify(loaded.thumbnail.url)})`, _v$9 = loaded.thumbnail.backgroundPosition, _v$0 = loaded.thumbnail.backgroundRepeat, _v$1 = loaded.thumbnail.backgroundSize, _v$10 = `${loaded.thumbnail.height}px`, _v$11 = `scale(${imageScale()})`, _v$12 = `${loaded.thumbnail.width}px`, _v$13 = `Page ${loaded.pageNum}`;
return _v$8 !== _p$.e && setStyleProperty(_el$6, "background-image", _p$.e = _v$8), _v$9 !== _p$.t && setStyleProperty(_el$6, "background-position", _p$.t = _v$9), _v$0 !== _p$.a && setStyleProperty(_el$6, "background-repeat", _p$.a = _v$0), _v$1 !== _p$.o && setStyleProperty(_el$6, "background-size", _p$.o = _v$1), _v$10 !== _p$.i && setStyleProperty(_el$6, "height", _p$.i = _v$10), _v$11 !== _p$.n && setStyleProperty(_el$6, "transform", _p$.n = _v$11), _v$12 !== _p$.s && setStyleProperty(_el$6, "width", _p$.s = _v$12), _v$13 !== _p$.h && setAttribute(_el$6, "aria-label", _p$.h = _v$13), _p$;
}, {
e: void 0,
t: void 0,
a: void 0,
o: void 0,
i: void 0,
n: void 0,
s: void 0,
h: void 0
}), _el$6;
}
}), (() => {
var _el$7 = _tmpl$54();
return _el$7.$$click = (event) => {
event.preventDefault(), event.stopPropagation(), ctx.selectPage(props.pageNum);
}, setAttribute(_el$7, "draggable", !1), createRenderEffect((_p$) => {
var _v$14 = loaded.pageUrl, _v$15 = `Page ${loaded.pageNum}`, _v$16 = ctx.progress.current() === props.pageNum ? "page" : void 0;
return _v$14 !== _p$.e && setAttribute(_el$7, "href", _p$.e = _v$14), _v$15 !== _p$.t && setAttribute(_el$7, "aria-label", _p$.t = _v$15), _v$16 !== _p$.a && setAttribute(_el$7, "aria-current", _p$.a = _v$16), _p$;
}, {
e: void 0,
t: void 0,
a: void 0
}), _el$7;
})(), createComponent(Show, {
get when() {
return ctx.progress.current() === props.pageNum;
},
get children() {
return _tmpl$64();
}
})];
}
})), createRenderEffect((_p$) => {
var _v$3 = `${props.height}px`, _v$4 = `${props.x}px`, _v$5 = `${props.y}px`, _v$6 = `${props.width}px`, _v$7 = `${props.height}px`;
return _v$3 !== _p$.e && setStyleProperty(_el$2, "height", _p$.e = _v$3), _v$4 !== _p$.t && setStyleProperty(_el$2, "left", _p$.t = _v$4), _v$5 !== _p$.a && setStyleProperty(_el$2, "top", _p$.a = _v$5), _v$6 !== _p$.o && setStyleProperty(_el$2, "width", _p$.o = _v$6), _v$7 !== _p$.i && setStyleProperty(_el$3, "height", _p$.i = _v$7), _p$;
}, {
e: void 0,
t: void 0,
a: void 0,
o: void 0,
i: void 0
}), _el$2;
})();
}
var _tmpl$20, _tmpl$212, _tmpl$37, _tmpl$45, _tmpl$54, _tmpl$64, _tmpl$73, init_chunk_WGECFBEU = __esm({
"../reader/dist/chunk-WGECFBEU.js"() {
"use strict";
init_chunk_ABQJ4E5U();
init_chunk_UPVG5Y6S();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_solid();
_tmpl$20 = /* @__PURE__ */ template("<div class=ehpeek-preview-canvas>"), _tmpl$212 = /* @__PURE__ */ template("<div class=ehpeek-preview-slot><div class=ehpeek-preview-tile>"), _tmpl$37 = /* @__PURE__ */ template("<button type=button class=ehpeek-preview-placeholder><span>"), _tmpl$45 = /* @__PURE__ */ template("<span class=ehpeek-preview-image role=img style=transform-origin:center>"), _tmpl$54 = /* @__PURE__ */ template("<a class=ehpeek-preview-page-link>"), _tmpl$64 = /* @__PURE__ */ template("<span class=ehpeek-preview-highlight aria-hidden=true>"), _tmpl$73 = /* @__PURE__ */ template("<img class=ehpeek-preview-image alt decoding=async>");
delegateEvents(["click"]);
}
});
// ../reader/dist/chunk-O4OUM2TM.js
function layoutAspectRatio(aspectRatio) {
return clamp(
aspectRatio,
1 / MAX_LAYOUT_ASPECT_RATIO,
MAX_LAYOUT_ASPECT_RATIO
);
}
function layoutThumbnailSize(item) {
let aspectRatio = layoutAspectRatio(item.aspectRatio);
return {
height: Math.max(
item.thumbnail.height,
item.thumbnail.width * aspectRatio
),
width: Math.max(
item.thumbnail.width,
item.thumbnail.height / aspectRatio
)
};
}
function medianSize(sizes, estimatedSize) {
let sorted = [...sizes].sort((left, right) => left - right), middle = (sorted.length - 1) / 2, lower = sorted[Math.floor(middle)] ?? estimatedSize, upper = sorted[Math.ceil(middle)] ?? lower;
return (lower + upper) / 2;
}
function buildGroupGeometry(options) {
let estimatedGroupSize = options.horizontal ? options.tileCrossSize / options.estimatedAspectRatio : options.tileCrossSize * options.estimatedAspectRatio, totalGroups = Math.ceil(options.totalImages / options.crossCount), groupOffsets = [], groupSizes = [], offset = 0;
for (let group = 0; group < totalGroups; group += 1) {
let itemMainSizes = [], startPageNum = group * options.crossCount + 1, endPageNum = Math.min(
options.totalImages,
startPageNum + options.crossCount - 1
);
for (let pageNum = startPageNum; pageNum <= endPageNum; pageNum += 1) {
let item = options.item(pageNum);
if (item === null)
continue;
let aspectRatio = layoutAspectRatio(item.aspectRatio), thumbnailSize = layoutThumbnailSize(item), itemCrossSize = (options.horizontal ? thumbnailSize.height : thumbnailSize.width) * options.itemScaleLimit;
itemMainSizes.push(options.horizontal ? itemCrossSize / aspectRatio : itemCrossSize * aspectRatio);
}
let groupSize = itemMainSizes.length === 0 ? estimatedGroupSize : Math.max(...itemMainSizes);
groupOffsets.push(offset), groupSizes.push(groupSize), offset += groupSize + options.gap;
}
return {
estimatedGroupSize,
gap: options.gap,
groupOffsets,
groupSizes,
totalMainSize: Math.max(1, offset - options.gap)
};
}
function groupAtOffset(geometry, offset) {
let lastGroup = geometry.groupOffsets.length - 1;
if (lastGroup <= 0 || offset <= 0)
return 0;
let low = 0, high = lastGroup;
for (; low < high; ) {
let middle = Math.ceil((low + high) / 2);
groupOffsetAt(geometry, middle) <= offset ? low = middle : high = middle - 1;
}
return low;
}
function groupOffsetAt(geometry, group) {
let offset = geometry.groupOffsets[group];
if (offset === void 0)
throw new RangeError(`Invalid preview group: ${group}`);
return offset;
}
function groupSizeAt(geometry, group) {
let size = geometry.groupSizes[group];
if (size === void 0)
throw new RangeError(`Invalid preview group: ${group}`);
return size;
}
function logicalGroupOffset(geometry, offset) {
let group = groupAtOffset(geometry, offset), stride = groupSizeAt(geometry, group) + geometry.gap;
return group + clamp((offset - groupOffsetAt(geometry, group)) / stride, 0, 1);
}
function physicalGroupOffset(geometry, logicalOffset) {
let lastGroup = geometry.groupOffsets.length - 1, group = clamp(Math.floor(logicalOffset), 0, lastGroup), fraction = clamp(logicalOffset - group, 0, 1);
return groupOffsetAt(geometry, group) + fraction * (groupSizeAt(geometry, group) + geometry.gap);
}
function previewMainViewportSize(layout) {
return layout.horizontal ? layout.viewportWidth : layout.viewportHeight;
}
function previewPageAtCenter(layout, scrollOffset, totalPages) {
let group = groupAtOffset(
layout,
scrollOffset + previewMainViewportSize(layout) / 2
);
return clamp(
group * layout.crossCount + Math.floor(layout.crossCount / 2) + 1,
1,
totalPages
);
}
function previewVisiblePages(layout, scrollOffset, totalPages) {
let first = clamp(
groupAtOffset(layout, scrollOffset) * layout.crossCount + 1,
1,
totalPages
), endOffset = Math.max(
scrollOffset,
scrollOffset + previewMainViewportSize(layout) - 1
);
return {
first,
last: clamp(
(groupAtOffset(layout, endOffset) + 1) * layout.crossCount,
first,
totalPages
)
};
}
function previewZoomAnchor(layout, scrollOffset, totalPages, highlightedPage) {
let visible = previewVisiblePages(layout, scrollOffset, totalPages);
return highlightedPage !== null && highlightedPage >= visible.first && highlightedPage <= visible.last ? highlightedPage : previewPageAtCenter(layout, scrollOffset, totalPages);
}
function previewCrossCountLimits(layout, aspectRatio, totalPages) {
return {
min: layout ? minimumPreviewCrossCount(
layout.horizontal,
layoutAspectRatio(aspectRatio),
layout.viewportWidth,
layout.viewportHeight,
layout.gap
) : 1,
max: layout?.horizontal ? Math.min(MAX_PREVIEW_CROSS_COUNT, totalPages) : MAX_PREVIEW_CROSS_COUNT
};
}
function previewPageScrollOffset(layout, pageNum, totalPages) {
let group = Math.floor(
(clamp(pageNum, 1, totalPages) - 1) / layout.crossCount
);
return groupOffsetAt(layout, group) - (previewMainViewportSize(layout) - groupSizeAt(layout, group)) / 2;
}
function previewContentSize(layout) {
return {
width: layout.horizontal ? Math.max(layout.totalMainSize, layout.viewportWidth) : layout.viewportWidth,
height: layout.horizontal ? layout.viewportHeight : Math.max(layout.totalMainSize, layout.viewportHeight)
};
}
function previewTilePlacements(options) {
let { layout } = options, contentWidth = previewContentSize(layout).width, placements = [], firstPage = options.firstGroup * layout.crossCount + 1, lastPage = Math.min(
options.totalPages,
(options.lastGroup + 1) * layout.crossCount
);
for (let pageNum = firstPage; pageNum <= lastPage; pageNum += 1) {
let index = pageNum - 1, group = Math.floor(index / layout.crossCount), crossIndex = index % layout.crossCount, groupSize = groupSizeAt(layout, group), groupOffset = groupOffsetAt(layout, group);
placements.push({
pageNum,
x: layout.horizontal ? options.rightToLeft ? contentWidth - groupSize - groupOffset : groupOffset : crossIndex * (layout.tileCrossSize + layout.gap),
y: layout.horizontal ? crossIndex * (layout.tileCrossSize + layout.gap) : groupOffset,
width: layout.horizontal ? groupSize : layout.tileCrossSize,
height: layout.horizontal ? layout.tileCrossSize : groupSize
});
}
return placements;
}
function calculatePreviewLayout(options) {
let { width, height, horizontal, totalImages } = options, scale = options.pixelScale, gap = options.gap * scale, aspectRatio = options.estimatedAspectRatio, maxTileWidth = options.maxTileWidth * scale, itemsPerRow = Math.max(
1,
Math.ceil((width + gap) / (maxTileWidth + gap))
), itemWidth = Math.max(
1,
(width - gap * (itemsPerRow - 1)) / itemsPerRow
), itemHeight = Math.max(1, Math.round(itemWidth * aspectRatio)), availableRows = Math.max(
1,
Math.ceil((height + gap) / (itemHeight + gap))
), fittedCrossCount = horizontal ? Math.min(availableRows, Math.ceil(totalImages / itemsPerRow)) : Math.min(itemsPerRow, options.maximumCrossCount), crossCount = clamp(
options.crossCountOverride ?? fittedCrossCount,
1,
options.maximumCrossCount
), availableTileHeight = Math.max(
1,
(height - gap * (crossCount - 1)) / crossCount
), crossCountOverridden = options.crossCountOverride !== null, overriddenTileWidth = Math.min(
Math.max(1, (width - gap * (crossCount - 1)) / crossCount),
width,
height / aspectRatio
), tileHeight = horizontal ? crossCountOverridden ? Math.min(availableTileHeight, height, width * aspectRatio) : Math.min(itemHeight, availableTileHeight) : Math.max(
1,
Math.round(
(crossCountOverridden ? overriddenTileWidth : Math.max(1, (width - gap * (crossCount - 1)) / crossCount)) * aspectRatio
)
), tileWidth = horizontal ? crossCountOverridden ? tileHeight / aspectRatio : clamp(tileHeight / aspectRatio, 1, maxTileWidth) : crossCountOverridden ? overriddenTileWidth : Math.max(1, (width - gap * (crossCount - 1)) / crossCount), tileCrossSize = horizontal ? tileHeight : tileWidth, itemScaleLimit = tileCrossSize / options.referenceThumbnailCrossSize, geometry = buildGroupGeometry({
crossCount,
estimatedAspectRatio: aspectRatio,
gap,
horizontal,
item: options.item,
itemScaleLimit,
tileCrossSize,
totalImages
});
return {
crossCount,
horizontal,
itemScaleLimit,
tileCrossSize,
viewportWidth: width,
viewportHeight: height,
...geometry
};
}
function minimumPreviewCrossCount(horizontal, aspectRatio, viewportWidth, viewportHeight, gap) {
let crossSize = horizontal ? viewportHeight : viewportWidth, maximumTileCrossSize = horizontal ? Math.min(viewportHeight, viewportWidth * aspectRatio) : Math.min(viewportWidth, viewportHeight / aspectRatio);
return Math.max(1, Math.ceil((crossSize + gap) / (maximumTileCrossSize + gap)));
}
var MAX_LAYOUT_ASPECT_RATIO, MAX_PREVIEW_CROSS_COUNT, init_chunk_O4OUM2TM = __esm({
"../reader/dist/chunk-O4OUM2TM.js"() {
"use strict";
init_chunk_E6UKP7HT();
MAX_LAYOUT_ASPECT_RATIO = 3, MAX_PREVIEW_CROSS_COUNT = 12;
}
});
// ../reader/dist/chunk-YD563ASB.js
function PreviewPositionBar(props) {
let ctx = useScrollPreviewContext(), texts = useReaderTexts(), horizontal = untrack(() => ctx.settings[0].direction !== "ttb");
createEffect(() => {
(ctx.disabled() || !ctx.visible()) && props.setInteracting(!1);
}), onCleanup(() => props.setInteracting(!1));
let mainViewportSize = () => horizontal ? props.layout().viewportWidth : props.layout().viewportHeight, totalGroups = () => props.layout().groupSizes.length, maxScrollOffset = () => Math.max(0, props.layout().totalMainSize - mainViewportSize()), maxLogicalScrollOffset = () => logicalGroupOffset(props.layout(), maxScrollOffset()), value = () => {
let maximum = maxLogicalScrollOffset();
return maximum === 0 ? 0 : clamp(logicalGroupOffset(props.layout(), props.scrollOffset()) / maximum, 0, 1);
}, visibleRatio = () => clamp(mainViewportSize() / (props.layout().estimatedGroupSize + props.layout().gap) / totalGroups(), 0, 1), scrollToValue = (nextValue) => {
let ratio = clamp(nextValue, 0, 1);
props.scrollTo(ratio === 1 ? maxScrollOffset() : physicalGroupOffset(props.layout(), ratio * maxLogicalScrollOffset()));
};
return createComponent(Show, {
get when() {
return memo(() => totalGroups() > 0 && maxScrollOffset() > SCROLL_PIXEL_EPSILON)() && visibleRatio() < 1;
},
get children() {
return createComponent(PositionBar, {
get disabled() {
return ctx.disabled();
},
get ariaLabel() {
return texts.gallery.scrollPreview;
},
axis: horizontal ? "horizontal" : "vertical",
get currentValue() {
return value();
},
expanded: !horizontal,
maxValue: 1,
minValue: 0,
onCommit: () => props.setInteracting(!1),
onInput: scrollToValue,
onPointerDown: () => props.setInteracting(!0),
position: horizontal ? void 0 : "absolute",
get reversed() {
return horizontal && props.rightToLeft;
},
thickness: horizontal ? "normal" : "narrow",
trackClickEnabled: !1,
trackVisible: !1,
get visibleRatio() {
return visibleRatio();
}
});
}
});
}
var SCROLL_PIXEL_EPSILON, init_chunk_YD563ASB = __esm({
"../reader/dist/chunk-YD563ASB.js"() {
"use strict";
init_chunk_O4OUM2TM();
init_chunk_ABQJ4E5U();
init_chunk_NU4SG75H();
init_chunk_JXES5MWD();
init_chunk_E6UKP7HT();
init_web();
init_web();
init_solid();
SCROLL_PIXEL_EPSILON = 1;
}
});
// ../reader/dist/chunk-XNXFHHML.js
function createPreviewGestures(options) {
let { preview } = options, horizontal = () => preview.settings[0].direction !== "ttb", enabled = () => preview.visible() && !preview.disabled(), [active, setActive] = createSignal(!1), [resizeAnchor, setResizeAnchor] = createSignal(null), fling = new ScrollFlingAnimator(), dragDirection = null, dragStartPosition = 0, pointerType = "mouse", lastNativeScrollAt = Number.NEGATIVE_INFINITY, cancelMotion = () => {
fling.cancel();
}, dismissOffset = 0, dismissAnimation = null, resetDismiss = () => {
dismissAnimation?.cancel(), dismissAnimation = null, dismissOffset = 0;
let panel = options.panel();
panel.style.removeProperty("opacity"), panel.style.removeProperty("transform");
}, dismissSize = () => Math.max(
1,
horizontal() ? options.panel().clientHeight : options.panel().clientWidth
), dragDismiss = (offset) => {
dismissAnimation?.cancel(), dismissAnimation = null, dismissOffset = offset;
let ratio = Math.abs(offset) / dismissSize(), panel = options.panel();
panel.style.opacity = `${1 - Math.min(0.15, ratio * 0.15)}`, panel.style.transform = `translate3d(${horizontal() ? 0 : offset}px, ${horizontal() ? offset : 0}px, 0) scale(${1 - Math.min(0.03, ratio * 0.03)})`;
}, finishDismiss = (velocity) => {
let shouldClose = Math.abs(dismissOffset) >= dismissSize() * 0.2 || Math.abs(velocity) >= 0.6, direction = Math.sign(dismissOffset) || Math.sign(velocity) || 1, panel = options.panel(), endTransform = shouldClose ? horizontal() ? `translate3d(0, ${direction * 100}%, 0) scale(0.97)` : `translate3d(${direction * 100}%, 0, 0) scale(0.97)` : "translate3d(0, 0, 0) scale(1)";
dismissAnimation?.cancel();
let animation = panel.animate([
{ opacity: panel.style.opacity, transform: panel.style.transform },
{ opacity: shouldClose ? 0.7 : 1, transform: endTransform }
], { duration: 180, easing: "cubic-bezier(0.2, 0.8, 0.2, 1)", fill: "forwards" });
dismissAnimation = animation, animation.finished.then(() => {
dismissAnimation !== animation || !untrack(enabled) || (shouldClose ? preview.close?.() : resetDismiss());
}).catch(() => {
});
}, pinchStartCrossCount = 1, pinchMinimumCrossCount = 1, pointer = {
get dragAxis() {
return pointerType === "mouse" ? preview.close ? "any" : horizontal() ? "x" : "y" : preview.close ? horizontal() ? "y" : "x" : horizontal() ? "x" : "y";
},
shouldCaptureDrag(event) {
return pointerType = "pointerType" in event ? event.pointerType : "mouse", !!preview.close || pointerType === "mouse";
},
shouldObserveTap: () => !0,
onMouseDown: () => fling.cancel(),
onNonMouseDown: () => performance.now() - lastNativeScrollAt <= NATIVE_SCROLL_TAP_GUARD_MS2,
onStart() {
cancelMotion(), resetDismiss(), setActive(!0), dragDirection = null;
let scroller = options.scroller();
dragStartPosition = horizontal() ? scroller.scrollLeft : scroller.scrollTop;
},
onMove(info) {
if (dragDirection === null) {
let mainDelta = horizontal() ? Math.abs(info.dx) : Math.abs(info.dy), crossDelta = horizontal() ? Math.abs(info.dy) : Math.abs(info.dx);
dragDirection = preview.close && crossDelta > mainDelta ? "dismiss" : "scroll";
}
if (dragDirection === "dismiss") {
dragDismiss(horizontal() ? info.dy : info.dx);
return;
}
let scroller = options.scroller();
horizontal() ? scroller.scrollLeft = dragStartPosition - info.dx : scroller.scrollTop = dragStartPosition - info.dy;
},
onEnd(info, event) {
let dismiss = dragDirection === "dismiss";
if (dragDirection = null, setActive(!1), event.type === "pointercancel") {
resetDismiss();
return;
}
if (dismiss) {
finishDismiss(horizontal() ? info.velocityY : info.velocityX);
return;
}
let scroller = options.scroller(), axis = horizontal() ? "x" : "y";
fling.start({
axis,
scroller,
initialVelocity: -(horizontal() ? info.velocityX * HORIZONTAL_FLING_VELOCITY_FACTOR : info.velocityY),
setScrollPosition(position) {
axis === "x" ? scroller.scrollLeft = position : scroller.scrollTop = position;
},
canRun: () => enabled() && scroller.isConnected,
onStop() {
}
});
},
onPinchStart() {
let layout = options.layout();
return layout ? (cancelMotion(), resetDismiss(), dragDirection = null, pinchStartCrossCount = layout.crossCount, pinchMinimumCrossCount = Math.min(layout.crossCount, previewCrossCountLimits(
layout,
preview.previewCache.source.aspectRatio,
preview.previewCache.source.totalPages
).min), batch(() => {
setActive(!0), setResizeAnchor(previewZoomAnchor(
layout,
options.scrollOffset(),
preview.previewCache.source.totalPages,
preview.progress.current()
));
}), !0) : !1;
},
onPinchMove(info) {
preview.settings[1]("crossCount", clamp(
Math.round(pinchStartCrossCount / info.scale),
pinchMinimumCrossCount,
MAX_PREVIEW_CROSS_COUNT
));
},
onPinchEnd() {
batch(() => {
setResizeAnchor(null), setActive(!1);
});
}
};
return createPointerGestureElement(
() => enabled() ? options.scroller() : null,
() => pointer
), createEffect(on(() => preview.settings[0].crossCount, cancelMotion)), createEffect(() => {
let scroller = options.scroller();
if (!scroller || !enabled()) return;
let stopOnWheel = () => cancelMotion();
scroller.addEventListener("wheel", stopOnWheel, { passive: !0 }), onCleanup(() => {
scroller.removeEventListener("wheel", stopOnWheel), cancelMotion(), resetDismiss(), batch(() => {
setActive(!1), setResizeAnchor(null);
});
});
}), {
active,
resizeAnchor,
cancelMotion,
reportScroll() {
!active() && !fling.running() && (lastNativeScrollAt = performance.now());
}
};
}
var HORIZONTAL_FLING_VELOCITY_FACTOR, NATIVE_SCROLL_TAP_GUARD_MS2, init_chunk_XNXFHHML = __esm({
"../reader/dist/chunk-XNXFHHML.js"() {
"use strict";
init_chunk_O4OUM2TM();
init_chunk_NP6I7EK4();
init_chunk_V7QAVQKV();
init_chunk_E6UKP7HT();
init_solid();
HORIZONTAL_FLING_VELOCITY_FACTOR = 1.6, NATIVE_SCROLL_TAP_GUARD_MS2 = 120;
}
});
// ../reader/dist/chunk-SEW7F2R2.js
function PreviewViewport(props) {
let ctx = useScrollPreviewContext();
return createComponent(Show, {
get when() {
return ctx.settings[0].direction;
},
keyed: !0,
children: (_direction) => createComponent(Viewport, props)
});
}
function Viewport(props) {
let ctx = useScrollPreviewContext(), source = ctx.previewCache.source, direction = untrack(() => ctx.settings[0].direction), horizontal = direction !== "ttb", rightToLeft = direction === "rtl", initPage = untrack(ctx.currentPage), panel = ctx.refs.panel, pixelScale = useUiPixelScale(), estimatedAspectRatio = layoutAspectRatio(source.aspectRatio), referenceThumbnailCrossSize = medianSize(source.initialPreviewItems.map((item) => {
let size = layoutThumbnailSize(item);
return horizontal ? size.height : size.width;
}), horizontal ? MAX_TILE_WIDTH * estimatedAspectRatio : MAX_TILE_WIDTH), scroller, [layout, setLayout] = createSignal(null), [scrollOffset, setScrollOffset] = createSignal(0), [ready, setReady] = createSignal(!1), [positionBarActive, setPositionBarActive] = createSignal(!1), [nativeScrolling, setNativeScrolling] = createSignal(!1), gestures = createPreviewGestures({
scroller: () => scroller ?? null,
panel: () => panel,
preview: ctx,
layout,
scrollOffset
}), maximumOffset = (layout2) => Math.max(0, layout2.totalMainSize - previewMainViewportSize(layout2)), readScrollOffset = () => {
let current = layout();
if (!current) return 0;
let maximum = maximumOffset(current);
return clamp(horizontal ? rightToLeft ? maximum - scroller.scrollLeft : scroller.scrollLeft : scroller.scrollTop, 0, maximum);
}, restoreScrollOffset = () => {
let current = layout();
if (!current) return;
let maximum = maximumOffset(current), offset = clamp(scrollOffset(), 0, maximum);
horizontal ? scroller.scrollLeft = rightToLeft ? maximum - offset : offset : scroller.scrollTop = offset, setScrollOffset(offset);
}, scrollToPage = (pageNum) => {
let current = layout();
current && (gestures.cancelMotion(), setScrollOffset(clamp(previewPageScrollOffset(current, pageNum, source.totalPages), 0, maximumOffset(current))));
}, scrollFrame = null, scrollSettleTimer, reportScroll = () => {
layoutFrame === null && (gestures.reportScroll(), setNativeScrolling(!0), window.clearTimeout(scrollSettleTimer), scrollSettleTimer = window.setTimeout(() => setNativeScrolling(!1), NATIVE_SCROLL_SETTLE_MS), scrollFrame === null && (scrollFrame = window.requestAnimationFrame(() => {
scrollFrame = null, layoutFrame === null && setScrollOffset(untrack(readScrollOffset));
})));
}, metadataDirty = !1, layoutFrame = null, updateLayout = (preserveScreenPosition) => {
if (!ctx.visible()) return;
let previous = layout(), anchor2 = previous ? preserveScreenPosition ? previewPageAtCenter(previous, scrollOffset(), source.totalPages) : gestures.resizeAnchor() ?? previewZoomAnchor(previous, scrollOffset(), source.totalPages, ctx.progress.current()) : initPage, screenRatio = 0.5;
if (previous && preserveScreenPosition) {
let group = Math.floor((anchor2 - 1) / previous.crossCount);
screenRatio = (groupOffsetAt(previous, group) + groupSizeAt(previous, group) / 2 - scrollOffset()) / previewMainViewportSize(previous);
}
panel.style.removeProperty("height");
let next = calculatePreviewLayout({
width: Math.max(1, scroller.clientWidth),
height: Math.max(1, scroller.clientHeight),
horizontal,
totalImages: source.totalPages,
pixelScale: pixelScale(),
gap: GRID_GAP,
estimatedAspectRatio,
maxTileWidth: MAX_TILE_WIDTH,
referenceThumbnailCrossSize,
crossCountOverride: ctx.settings[0].crossCount,
maximumCrossCount: horizontal ? Math.min(MAX_PREVIEW_CROSS_COUNT, source.totalPages) : MAX_PREVIEW_CROSS_COUNT,
item: ctx.previewCache.item
});
if (ctx.fitContentHeight()) {
let contentHeight = horizontal ? next.crossCount * next.tileCrossSize + (next.crossCount - 1) * next.gap : next.totalMainSize, height = Math.min(next.viewportHeight, contentHeight);
panel.style.height = `${Math.ceil(panel.clientHeight - scroller.clientHeight + height)}px`, next.viewportHeight = height;
}
let offset = previewPageScrollOffset(next, anchor2, source.totalPages) + (0.5 - screenRatio) * previewMainViewportSize(next);
metadataDirty = !1, layoutFrame !== null && window.cancelAnimationFrame(layoutFrame), layoutFrame = window.requestAnimationFrame(() => {
layoutFrame = null, untrack(restoreScrollOffset), setReady(!0);
}), batch(() => {
setLayout(next), setScrollOffset(clamp(offset, 0, maximumOffset(next))), setReady(!1);
});
};
onMount(() => {
ctx.refs.bindViewport(reference), createEffect(on([ctx.visible, () => ctx.settings[0].crossCount, pixelScale, ctx.fitContentHeight], ([visible], previous) => {
if (!visible) {
setReady(!1);
return;
}
updateLayout(previous !== void 0 && !previous[0]);
})), createEffect(on([ctx.previewCache.version, () => gestures.active() || positionBarActive() || nativeScrolling(), ctx.visible], ([version, interacting, visible], previous) => {
previous && version !== previous[0] && (metadataDirty = !0), metadataDirty && !interacting && visible && updateLayout(!0);
})), createEffect(on(scrollOffset, (offset) => {
layoutFrame === null && ctx.visible() && readScrollOffset() !== offset && restoreScrollOffset();
}));
let observer = new ResizeObserver(() => {
let current = layout();
current && Math.abs(scroller.clientWidth - current.viewportWidth) <= 1 && Math.abs(scroller.clientHeight - current.viewportHeight) <= 1 || updateLayout(!1);
});
observer.observe(scroller), onCleanup(() => {
observer.disconnect(), window.clearTimeout(scrollSettleTimer), layoutFrame !== null && window.cancelAnimationFrame(layoutFrame), scrollFrame !== null && window.cancelAnimationFrame(scrollFrame), ctx.refs.bindViewport(null);
});
});
let tiles = createMemo(() => {
let current = layout();
if (!current) return [];
let lastGroup = Math.max(0, current.groupSizes.length - 1), first = clamp(groupAtOffset(current, scrollOffset()) - OVERSCAN_GROUPS, 0, lastGroup), last = clamp(groupAtOffset(current, scrollOffset() + previewMainViewportSize(current)) + OVERSCAN_GROUPS, first, lastGroup);
return previewTilePlacements({
layout: current,
firstGroup: first,
lastGroup: last,
totalPages: source.totalPages,
rightToLeft
});
}), currentPage = createMemo(() => {
let current = layout();
return current ? previewPageAtCenter(current, scrollOffset(), source.totalPages) : initPage;
}), visiblePages = createMemo(() => {
let current = layout();
return current ? previewVisiblePages(current, scrollOffset(), source.totalPages) : null;
}), reference = {
currentPage,
visiblePages,
crossCount: () => layout()?.crossCount ?? 1,
crossCountLimits: () => previewCrossCountLimits(layout(), source.aspectRatio, source.totalPages),
ready,
scrollToPage
};
return (() => {
var _el$ = _tmpl$21(), _el$2 = _el$.firstChild;
_el$2.addEventListener("scroll", reportScroll);
var _ref$ = scroller;
return typeof _ref$ == "function" ? use(_ref$, _el$2) : scroller = _el$2, _el$2.classList.toggle("ehpeek-preview-scroller--horizontal", !!horizontal), insert(_el$2, createComponent(Show, {
get when() {
return layout();
},
children: (current) => createComponent(PreviewGrid, {
get contentSize() {
return previewContentSize(current());
},
get tiles() {
return tiles();
},
get maximumScale() {
return current().itemScaleLimit;
}
})
})), insert(_el$, createComponent(Show, {
get when() {
return layout();
},
children: (current) => createComponent(PreviewPositionBar, {
layout: current,
scrollOffset,
rightToLeft,
scrollTo: (offset) => {
gestures.cancelMotion(), setScrollOffset(offset);
},
setInteracting: setPositionBarActive
})
}), null), createRenderEffect((_p$) => {
var _v$ = `ehpeek-preview-viewport${props.class ? ` ${props.class}` : ""}`, _v$2 = props.style, _v$3 = ctx.close ? horizontal ? "pan-x" : "pan-y" : "pan-x pan-y", _v$4 = ctx.close ? "contain" : "auto";
return _v$ !== _p$.e && className(_el$, _p$.e = _v$), _p$.t = style(_el$, _v$2, _p$.t), _v$3 !== _p$.a && setStyleProperty(_el$2, "touch-action", _p$.a = _v$3), _v$4 !== _p$.o && setStyleProperty(_el$2, "overscroll-behavior", _p$.o = _v$4), _p$;
}, {
e: void 0,
t: void 0,
a: void 0,
o: void 0
}), _el$;
})();
}
var _tmpl$21, GRID_GAP, MAX_TILE_WIDTH, OVERSCAN_GROUPS, NATIVE_SCROLL_SETTLE_MS, init_chunk_SEW7F2R2 = __esm({
"../reader/dist/chunk-SEW7F2R2.js"() {
"use strict";
init_chunk_WGECFBEU();
init_chunk_YD563ASB();
init_chunk_XNXFHHML();
init_chunk_O4OUM2TM();
init_chunk_ABQJ4E5U();
init_chunk_W6BYXZGJ();
init_chunk_E6UKP7HT();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_solid();
_tmpl$21 = /* @__PURE__ */ template("<div><div class=ehpeek-preview-scroller>"), GRID_GAP = 8, MAX_TILE_WIDTH = 220, OVERSCAN_GROUPS = 4, NATIVE_SCROLL_SETTLE_MS = 250;
}
});
// ../reader/dist/chunk-DIPUDBVX.js
function DefaultScrollPreview(props) {
return createComponent(ScrollPreview.Root, mergeProps(props, {
get children() {
return [createComponent(ScrollPreview.Toolbar, {}), createComponent(ScrollPreview.Viewport, {})];
}
}));
}
function PreviewRoot(props) {
let previewCache = untrack(() => props.previewCache), decodeCache = untrack(() => props.decodeCache), onResize = untrack(() => props.onResize), onClose = untrack(() => props.onClose), onSelectPage = untrack(() => props.onSelectPage), setRef = untrack(() => props.ref), onError = untrack(() => props.onError) ?? ((error) => console.error("[reader]", error)), visible = () => props.visible, disabled = () => props.disabled, leftHanded = () => props.leftHanded, totalPages = previewCache.source.totalPages;
if (!Number.isSafeInteger(totalPages) || totalPages < 1)
throw new RangeError("A Scroll Preview needs a positive, finite number of pages.");
let publisher = createReadProgressPublisher(), [highlightedPage, setHighlightedPage] = createSignal(normalizeOptionalPage(untrack(() => props.initialProgress), totalPages)), retainedPage = normalizePage(untrack(() => props.initPage), totalPages), [viewport, setViewport] = createSignal(null), currentPage = createMemo(() => viewport()?.currentPage() ?? retainedPage), bindViewport = (next) => {
next === null && (retainedPage = viewport()?.currentPage() ?? retainedPage), setViewport(next);
}, loading = createPreviewLoading({
centeredPageNum: currentPage,
onLoadError: onError,
previewCache,
ready: () => visible() && viewport()?.ready() === !0
}), panel, progress = {
current: highlightedPage,
subscribe: publisher.subscribe,
setProgress(pageNum) {
setHighlightedPage(normalizePage(pageNum, totalPages));
}
}, scrollToPage = (pageNum) => {
viewport()?.scrollToPage(normalizePage(pageNum, totalPages));
}, context = untrack(() => ({
previewCache,
decodeCache,
progress,
settings: props.settings,
loading,
visible,
disabled,
leftHanded,
fitContentHeight: () => props.fitContentHeight ?? !1,
refs: {
viewport,
get panel() {
return panel;
},
bindViewport
},
currentPage,
scrollToPage,
locateHighlightedPage() {
let pageNum = highlightedPage();
pageNum !== null && scrollToPage(pageNum);
},
selectPage(pageNum) {
let next = normalizePage(pageNum, totalPages);
setHighlightedPage(next), publisher.publish(next), onSelectPage(next);
},
resize: onResize ? () => onResize(untrack(currentPage)) : void 0,
close: onClose ? () => onClose(untrack(currentPage)) : void 0
}));
return setRef?.({
progress,
currentPage,
scrollToPage
}), untrack(() => bindInteractionGate(() => panel, disabled)), onMount(() => {
let onKeydown = (event) => {
event.key !== "Escape" || !visible() || disabled() || !context.close || (event.preventDefault(), event.stopImmediatePropagation(), context.close());
};
document.addEventListener("keydown", onKeydown, !0), onCleanup(() => document.removeEventListener("keydown", onKeydown, !0));
}), onCleanup(() => setRef?.(null)), createComponent(ScrollPreviewContextKey.Provider, {
value: context,
get children() {
var _el$ = _tmpl$30(), _ref$ = panel;
return typeof _ref$ == "function" ? use(_ref$, _el$) : panel = _el$, insert(_el$, () => props.children), createRenderEffect((_p$) => {
var _v$ = `ehpeek-preview-panel${props.class ? ` ${props.class}` : ""}`, _v$2 = props.style, _v$3 = !props.visible;
return _v$ !== _p$.e && className(_el$, _p$.e = _v$), _p$.t = style(_el$, _v$2, _p$.t), _v$3 !== _p$.a && (_el$.hidden = _p$.a = _v$3), _p$;
}, {
e: void 0,
t: void 0,
a: void 0
}), _el$;
}
});
}
function normalizePage(pageNum, totalPages) {
return clamp(Number.isFinite(pageNum) ? Math.round(pageNum) : 1, 1, totalPages);
}
function normalizeOptionalPage(pageNum, totalPages) {
return pageNum == null ? null : normalizePage(pageNum, totalPages);
}
var _tmpl$30, ScrollPreview, init_chunk_DIPUDBVX = __esm({
"../reader/dist/chunk-DIPUDBVX.js"() {
"use strict";
init_chunk_R253JGHC();
init_chunk_IECOMI6N();
init_chunk_SEW7F2R2();
init_chunk_PBZTMYEM();
init_chunk_FRCEUGG2();
init_chunk_ABQJ4E5U();
init_chunk_E6UKP7HT();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_solid();
_tmpl$30 = /* @__PURE__ */ template("<section data-scroll-preview-instance>");
ScrollPreview = Object.assign(DefaultScrollPreview, {
Root: PreviewRoot,
Toolbar: PreviewToolbar,
Viewport: PreviewViewport
});
}
});
// ../reader/dist/chunk-5OWZ2GGT.js
var PreviewDecodeCache, init_chunk_5OWZ2GGT = __esm({
"../reader/dist/chunk-5OWZ2GGT.js"() {
"use strict";
PreviewDecodeCache = class {
constructor(byteLimit, itemLimit, maxConcurrent = 3) {
this.byteLimit = byteLimit, this.itemLimit = itemLimit, this.maxConcurrent = maxConcurrent, this.bytes = 0, this.activeLoads = 0, this.pending = [], this.entries = /* @__PURE__ */ new Map();
}
retain(url) {
let entry = this.ensure(url);
return entry.pins += 1, this.touch(url, entry), this.prune(), () => {
let current = this.entries.get(url);
current === entry && (current.pins = Math.max(0, current.pins - 1), this.prune());
};
}
dispose() {
for (let entry of this.entries.values())
entry.image.onload = null, entry.image.onerror = null, entry.image.removeAttribute("src");
this.entries.clear(), this.pending.length = 0, this.bytes = 0, this.activeLoads = 0;
}
ensure(url) {
let cached = this.entries.get(url);
if (cached)
return cached;
let image2 = new Image();
image2.decoding = "async";
let entry = { bytes: 0, image: image2, pins: 0, status: "queued" };
return this.entries.set(url, entry), this.pending.push(url), this.pump(), entry;
}
/** Starts queued loads up to the concurrency limit, newest (last pinned) first. */
pump() {
for (; this.activeLoads < this.maxConcurrent && this.pending.length > 0; ) {
let url = this.pending.pop(), entry = this.entries.get(url);
if (!entry || entry.status !== "queued")
continue;
entry.status = "loading", this.activeLoads += 1;
let { image: image2 } = entry;
image2.onload = () => {
let bytes = Math.max(1, image2.naturalWidth) * Math.max(1, image2.naturalHeight) * 4;
this.bytes += bytes - entry.bytes, entry.bytes = bytes, image2.decode().catch(() => {
}).finally(() => this.finishLoad(entry));
}, image2.onerror = () => {
this.finishLoad(entry), entry.pins === 0 && this.evict(url, entry);
}, image2.src = url;
}
}
/** Frees the load slot exactly once, then lets pruning/pumping continue. */
finishLoad(entry) {
entry.status === "loading" && (entry.status = "done", this.activeLoads = Math.max(0, this.activeLoads - 1), this.prune(), this.pump());
}
touch(url, entry) {
this.entries.delete(url), this.entries.set(url, entry);
}
prune() {
for (; this.entries.size > this.itemLimit || this.bytes > this.byteLimit; ) {
let removable = Array.from(this.entries).find(([, entry]) => entry.pins === 0);
if (!removable)
break;
this.evict(removable[0], removable[1]);
}
}
evict(url, entry) {
if (this.entries.get(url) === entry) {
if (this.entries.delete(url), this.bytes = Math.max(0, this.bytes - entry.bytes), entry.status === "loading")
this.activeLoads = Math.max(0, this.activeLoads - 1);
else if (entry.status === "queued") {
let index = this.pending.lastIndexOf(url);
index !== -1 && this.pending.splice(index, 1);
}
entry.status = "done", entry.image.onload = null, entry.image.onerror = null, entry.image.removeAttribute("src"), this.pump();
}
}
};
}
});
// ../../node_modules/.pnpm/[email protected]/node_modules/solid-js/store/dist/store.js
function wrap$1(value) {
let p = value[$PROXY];
if (!p && (Object.defineProperty(value, $PROXY, {
value: p = new Proxy(value, proxyTraps$1)
}), !Array.isArray(value))) {
let keys = Object.keys(value), desc = Object.getOwnPropertyDescriptors(value), proto = Object.getPrototypeOf(value), isClass = proto !== null && value !== null && typeof value == "object" && !Array.isArray(value) && proto !== Object.prototype;
if (isClass) {
let descriptors = Object.getOwnPropertyDescriptors(proto);
keys.push(...Object.keys(descriptors)), Object.assign(desc, descriptors);
}
for (let i = 0, l = keys.length; i < l; i++) {
let prop = keys[i];
isClass && prop === "constructor" || desc[prop].get && Object.defineProperty(value, prop, {
configurable: !0,
enumerable: desc[prop].enumerable,
get: desc[prop].get.bind(p)
});
}
}
return p;
}
function isWrappable(obj) {
let proto;
return obj != null && typeof obj == "object" && (obj[$PROXY] || !(proto = Object.getPrototypeOf(obj)) || proto === Object.prototype || Array.isArray(obj));
}
function unwrap(item, set = /* @__PURE__ */ new Set()) {
let result, unwrapped, v, prop;
if (result = item != null && item[$RAW]) return result;
if (!isWrappable(item) || set.has(item)) return item;
if (Array.isArray(item)) {
Object.isFrozen(item) ? item = item.slice(0) : set.add(item);
for (let i = 0, l = item.length; i < l; i++)
v = item[i], (unwrapped = unwrap(v, set)) !== v && (item[i] = unwrapped);
} else {
Object.isFrozen(item) ? item = Object.assign({}, item) : set.add(item);
let keys = Object.keys(item), desc = Object.getOwnPropertyDescriptors(item);
for (let i = 0, l = keys.length; i < l; i++)
prop = keys[i], !desc[prop].get && (v = item[prop], (unwrapped = unwrap(v, set)) !== v && (item[prop] = unwrapped));
}
return item;
}
function getNodes(target, symbol) {
let nodes = target[symbol];
return nodes || Object.defineProperty(target, symbol, {
value: nodes = /* @__PURE__ */ Object.create(null)
}), nodes;
}
function getNode(nodes, property, value) {
if (nodes[property]) return nodes[property];
let [s, set] = createSignal(value, {
equals: !1,
internal: !0
});
return s.$ = set, nodes[property] = s;
}
function proxyDescriptor$1(target, property) {
let desc = Reflect.getOwnPropertyDescriptor(target, property);
return !desc || desc.get || !desc.configurable || property === $PROXY || property === $NODE || (delete desc.value, delete desc.writable, desc.get = () => target[$PROXY][property]), desc;
}
function trackSelf(target) {
getListener() && getNode(getNodes(target, $NODE), $SELF)();
}
function ownKeys(target) {
return trackSelf(target), Reflect.ownKeys(target);
}
function setProperty(state2, property, value, deleting = !1) {
if (property === "__proto__" || !deleting && state2[property] === value) return;
let prev = state2[property], len = state2.length;
value === void 0 ? (delete state2[property], state2[$HAS] && state2[$HAS][property] && prev !== void 0 && state2[$HAS][property].$()) : (state2[property] = value, state2[$HAS] && state2[$HAS][property] && prev === void 0 && state2[$HAS][property].$());
let nodes = getNodes(state2, $NODE), node;
if ((node = getNode(nodes, property, prev)) && node.$(() => value), Array.isArray(state2) && state2.length !== len) {
for (let i = state2.length; i < len; i++) (node = nodes[i]) && node.$();
(node = getNode(nodes, "length", len)) && node.$(state2.length);
}
(node = nodes[$SELF]) && node.$();
}
function mergeStoreNode(state2, value) {
let keys = Object.keys(value);
for (let i = 0; i < keys.length; i += 1) {
let key = keys[i];
isUnsafeKey$1(key) || setProperty(state2, key, value[key]);
}
}
function isUnsafeKey$1(property) {
return property === "__proto__" || property === "constructor" || property === "prototype";
}
function updateArray(current, next) {
if (typeof next == "function" && (next = next(current)), next = unwrap(next), Array.isArray(next)) {
if (current === next) return;
let i = 0, len = next.length;
for (; i < len; i++) {
let value = next[i];
current[i] !== value && setProperty(current, i, value);
}
setProperty(current, "length", len);
} else mergeStoreNode(current, next);
}
function updatePath(current, path, traversed = []) {
let part, prev = current;
if (path.length > 1) {
part = path.shift();
let partType = typeof part, isArray = Array.isArray(current);
if (partType === "string" && (part === "__proto__" || path.length > 1 && isUnsafeKey$1(part)))
return;
if (Array.isArray(part)) {
for (let i = 0; i < part.length; i++)
updatePath(current, [part[i]].concat(path), traversed);
return;
} else if (isArray && partType === "function") {
for (let i = 0; i < current.length; i++)
part(current[i], i) && updatePath(current, [i].concat(path), traversed);
return;
} else if (isArray && partType === "object") {
let {
from = 0,
to = current.length - 1,
by = 1
} = part;
for (let i = from; i <= to; i += by)
updatePath(current, [i].concat(path), traversed);
return;
} else if (path.length > 1) {
updatePath(current[part], path, [part].concat(traversed));
return;
}
prev = current[part], traversed = [part].concat(traversed);
}
let value = path[0];
typeof value == "function" && (value = value(prev, traversed), value === prev) || part === void 0 && value == null || (value = unwrap(value), part === void 0 || isWrappable(prev) && isWrappable(value) && !Array.isArray(value) ? mergeStoreNode(prev, value) : setProperty(current, part, value));
}
function createStore(...[store, options]) {
let unwrappedStore = unwrap(store || {}), isArray = Array.isArray(unwrappedStore), wrappedStore = wrap$1(unwrappedStore);
function setStore(...args) {
batch(() => {
isArray && args.length === 1 ? updateArray(unwrappedStore, args[0]) : updatePath(unwrappedStore, args);
});
}
return [wrappedStore, setStore];
}
var $RAW, $NODE, $HAS, $SELF, proxyTraps$1, init_store = __esm({
"../../node_modules/.pnpm/[email protected]/node_modules/solid-js/store/dist/store.js"() {
init_solid();
$RAW = /* @__PURE__ */ Symbol("store-raw"), $NODE = /* @__PURE__ */ Symbol("store-node"), $HAS = /* @__PURE__ */ Symbol("store-has"), $SELF = /* @__PURE__ */ Symbol("store-self");
proxyTraps$1 = {
get(target, property, receiver) {
if (property === $RAW) return target;
if (property === $PROXY) return receiver;
if (property === $TRACK)
return trackSelf(target), receiver;
let nodes = getNodes(target, $NODE), tracked = nodes[property], value = tracked ? tracked() : target[property];
if (property === $NODE || property === $HAS || property === "__proto__") return value;
if (!tracked) {
let desc = Object.getOwnPropertyDescriptor(target, property);
getListener() && (typeof value != "function" || Object.prototype.hasOwnProperty.call(target, property)) && !(desc && desc.get) && (value = getNode(nodes, property, value)());
}
return isWrappable(value) ? wrap$1(value) : value;
},
has(target, property) {
return property === $RAW || property === $PROXY || property === $TRACK || property === $NODE || property === $HAS || property === "__proto__" ? !0 : (getListener() && getNode(getNodes(target, $HAS), property)(), property in target);
},
set() {
return !0;
},
deleteProperty() {
return !0;
},
ownKeys,
getOwnPropertyDescriptor: proxyDescriptor$1
};
}
});
// ../reader/dist/chunk-DDSH64V2.js
function ReadingPreview(props) {
let texts = useReaderTexts(), cache = untrack(() => props.previewCache), embeddedDisabled = () => props.disabled || props.embeddedDisabled, decodeCache = new PreviewDecodeCache(64 * 1024 * 1024, 160);
onCleanup(() => decodeCache.dispose());
let [embedded, setEmbedded] = createSignal(null), [overlay, setOverlay] = createSignal(null), [embeddedSettings, setEmbeddedSettings] = createStore({
direction: untrack(() => props.embeddedDirection),
crossCount: null
}), [overlaySettings, setOverlaySettings] = createStore({
direction: untrack(() => props.readDirection),
crossCount: null
});
createEffect(on(() => props.embeddedDirection, (next) => setEmbeddedSettings("direction", next))), createEffect(on(() => props.readDirection, (next) => setOverlaySettings("direction", next))), createEffect(on(() => embeddedSettings.direction, (next) => props.onEmbeddedDirectionChange(next), {
defer: !0
})), createEffect(on(() => overlaySettings.direction, (next) => props.onReadDirectionChange(next), {
defer: !0
}));
let [highlightedPage, setHighlightedPage] = createSignal(untrack(() => props.initialProgress ?? null)), publisher = createReadProgressPublisher(), progress = {
current: highlightedPage,
subscribe: publisher.subscribe,
setProgress(pageNum) {
setHighlightedPage(pageNum), embedded()?.progress.setProgress(pageNum), overlay()?.progress.setProgress(pageNum), props.openState || embedded()?.scrollToPage(pageNum);
}
}, selectPage = (pageNum) => {
progress.setProgress(pageNum), publisher.publish(pageNum), props.onSelectPage(pageNum);
};
untrack(() => props.progressRef(progress)), onCleanup(() => props.progressRef(null)), createEffect(on([() => props.openState, embedded, overlay], ([view, inline, full]) => {
if (view) (view.mode === "embedded" ? inline : full)?.scrollToPage(view.pageNum);
else {
let page2 = highlightedPage();
page2 !== null && inline?.scrollToPage(page2);
}
})), createEffect(() => {
let view = props.openState, active = view?.mode === "embedded" ? embedded() : overlay();
view && active && props.onReturnPageChange(active.currentPage());
}), onMount(() => {
let onKeydown = (event) => {
event.key !== "Escape" || props.disabled || props.embeddedDisabled || props.openState?.mode !== "embedded" || (event.preventDefault(), event.stopImmediatePropagation(), props.onClose(embedded()?.currentPage() ?? props.openState.pageNum));
};
document.addEventListener("keydown", onKeydown, !0), onCleanup(() => document.removeEventListener("keydown", onKeydown, !0));
});
function OverlayPreview() {
let initPage = untrack(() => props.openState.pageNum), host;
return onCleanup(lockPageScroll()), onMount(() => {
let horizontal = untrack(() => overlaySettings.direction !== "ttb"), animation = host.animate([{
opacity: 0.72,
transform: horizontal ? "translate3d(0, -32px, 0) scale(0.99)" : "translate3d(32px, 0, 0) scale(0.99)"
}, {
opacity: 1,
transform: "translate3d(0, 0, 0) scale(1)"
}], {
duration: 120,
easing: "cubic-bezier(0.2, 0.8, 0.2, 1)"
});
animation.finished.catch(() => {
}), onCleanup(() => animation.cancel());
}), (() => {
var _el$ = _tmpl$31(), _ref$ = host;
return typeof _ref$ == "function" ? use(_ref$, _el$) : host = _el$, insert(_el$, createComponent(ScrollPreview, {
previewCache: cache,
decodeCache,
settings: [overlaySettings, setOverlaySettings],
initPage,
get initialProgress() {
return highlightedPage();
},
visible: !0,
get disabled() {
return props.disabled;
},
get leftHanded() {
return props.leftHandedControls();
},
ref: setOverlay,
onSelectPage: selectPage,
get onClose() {
return props.onClose;
},
get onError() {
return props.onLoadError;
}
})), _el$;
})();
}
return [createComponent(Show, {
get when() {
return props.replaceOriginalPreview;
},
get fallback() {
return (() => {
var _el$3 = _tmpl$38();
return use((element) => bindInteractionGate(() => element, embeddedDisabled), _el$3), insert(_el$3, createComponent(LauncherButton, {
icon: "grid",
get label() {
return texts.gallery.scrollPreview;
},
onClick: () => props.onOpenOverlay(highlightedPage() ?? 1)
})), _el$3;
})();
},
get children() {
var _el$2 = _tmpl$213();
return insert(_el$2, createComponent(ScrollPreview, {
previewCache: cache,
decodeCache,
settings: [embeddedSettings, setEmbeddedSettings],
get initPage() {
return highlightedPage() ?? 1;
},
get initialProgress() {
return highlightedPage();
},
visible: !0,
get disabled() {
return embeddedDisabled();
},
get leftHanded() {
return props.leftHandedControls();
},
get fitContentHeight() {
return !props.fillEmbeddedContainer();
},
ref: setEmbedded,
onSelectPage: selectPage,
get onResize() {
return props.onOpenOverlay;
},
get onError() {
return props.onLoadError;
}
})), _el$2;
}
}), createComponent(Show, {
get when() {
return props.openState?.mode === "overlay";
},
get children() {
return createComponent(OverlayPortal, {
get children() {
return createComponent(OverlayPreview, {});
}
});
}
})];
}
var _tmpl$31, _tmpl$213, _tmpl$38, init_chunk_DDSH64V2 = __esm({
"../reader/dist/chunk-DDSH64V2.js"() {
"use strict";
init_chunk_M65F42KE();
init_chunk_DIPUDBVX();
init_chunk_5OWZ2GGT();
init_chunk_PBZTMYEM();
init_chunk_FRCEUGG2();
init_chunk_ENSDPUNG();
init_chunk_6JKLIWFA();
init_chunk_JXES5MWD();
init_web();
init_web();
init_web();
init_web();
init_solid();
init_store();
_tmpl$31 = /* @__PURE__ */ template("<div class=ehpeek-preview-host data-embedded=false>"), _tmpl$213 = /* @__PURE__ */ template("<div class=ehpeek-preview-host data-embedded=true>"), _tmpl$38 = /* @__PURE__ */ template("<div class=ehpeek-preview-launcher>");
}
});
// ../reader/dist/chunk-25OOXIQ6.js
function createPreviewCache(source) {
let items = new Map(
source.initialPreviewItems.map((item) => [item.pageNum, item])
), [version, setVersion] = createSignal(0), controller = new AbortController(), pending = /* @__PURE__ */ new Map(), maxBatch = Math.max(0, Math.ceil(source.totalPages / BATCH_SIZE) - 1);
return {
source,
maxBatch,
batchForPage: (page2) => clamp(Math.floor((page2 - 1) / BATCH_SIZE), 0, maxBatch),
pageForBatch: (index) => index * BATCH_SIZE + 1,
version,
item: (page2) => (version(), items.get(page2) ?? null),
load: (index) => {
let existing = pending.get(index);
if (existing) return existing;
let pages = Array.from(
{
length: Math.min(BATCH_SIZE, source.totalPages - index * BATCH_SIZE)
},
(_, offset) => index * BATCH_SIZE + offset + 1
).filter((page2) => !items.has(page2));
if (pages.length === 0) return Promise.resolve();
let request = source.getPreviewItems(pages, controller.signal).then((incoming) => {
if (!controller.signal.aborted) {
for (let item of incoming) items.set(item.pageNum, item);
setVersion((v) => v + 1);
}
}).finally(() => pending.delete(index));
return pending.set(index, request), request;
},
dispose: () => controller.abort()
};
}
var BATCH_SIZE, init_chunk_25OOXIQ6 = __esm({
"../reader/dist/chunk-25OOXIQ6.js"() {
"use strict";
init_chunk_E6UKP7HT();
init_solid();
BATCH_SIZE = 40;
}
});
// ../reader/dist/ReadingView.js
function ReadingView(props) {
let options = untrack(() => props.options);
if (!Number.isSafeInteger(options.source.totalPages) || options.source.totalPages < 1)
throw new RangeError("A reader needs a positive, finite number of pages.");
let host = options.host ?? createOverlayHost(document.body, options.uiScale, options.texts), settings2 = createReaderSettings(options.settings, options.onSettingChange), cache = createPreviewCache(options.source), [progress, setProgress] = createSignal(options.initialProgress ?? null), [readerActions, setReaderActions] = createSignal(null), [previewProgress, setPreviewProgress] = createSignal(null), [fullscreenActive, setFullscreenActive] = createSignal(host.fullscreen.active()), onError = options.onError ?? ((error) => console.error("[reader]", error)), previewRoot, [readerView, setReaderView] = createSignal(null), [preview, setPreview] = createSignal(null), disposed = !1, closing = Promise.resolve(), pendingBack = null, previewReturnPage = options.source.initialPageNum, historyDepth = () => +(readerView() !== null) + +(preview() !== null), stopHistory = options.history?.subscribe((depth) => {
let notifyReturn = pendingBack?.notifyReturn ?? !0;
closing = closing.then(() => untrack(() => {
if (depth < historyDepth()) return removeViews(depth < 1, notifyReturn);
})).catch(onError).finally(() => {
pendingBack?.resolve(), pendingBack = null;
});
}) ?? (() => {
});
async function removeViews(closeReader, notifyReturn) {
disposed || (preview() && (setPreview(null), notifyReturn && (!closeReader || !readerView()) && options.onPreviewClosed?.(previewReturnPage)), closeReader && readerView() && (setReaderView(null), options.onReaderMount?.(!1), await exitFullscreen(), disposed || await options.onReaderClosed?.()));
}
function closeViews(closeReader, notifyReturn) {
if (disposed) return Promise.resolve();
if (pendingBack) return pendingBack.done;
if (!preview() && (!closeReader || !readerView())) return closing;
if (options.history) {
let resolve, done = new Promise((finish) => {
resolve = finish;
});
return pendingBack = {
done,
resolve,
notifyReturn
}, options.history.back(closeReader ? historyDepth() : 1), done;
}
let completion = closing.then(() => untrack(() => removeViews(closeReader, notifyReturn)));
return closing = completion.catch(onError), completion;
}
let opening = null, pendingMount = null;
function openReader(pageNum, configuredFullscreen) {
if (disposed) return Promise.resolve();
if (opening)
return opening.then(() => untrack(() => {
disposed || readerActions()?.gotoPage(pageNum);
}));
let request = (async () => {
options.beforeOpen && !await options.beforeOpen(pageNum) || disposed || await navi.openReader(pageNum, configuredFullscreen);
})();
return opening = request, request.finally(() => {
opening = null;
});
}
async function mountReader(pageNum, configuredFullscreen) {
if (await (pendingBack?.done ?? closing), disposed) return;
if (readerView()) {
readerActions()?.gotoPage(pageNum);
return;
}
let placement = options.placement?.() ?? null;
if (!placement && configuredFullscreen && options.fullscreenOnOpen) {
let canOpen = await enterFullscreen();
if (disposed || !canOpen) return;
}
options.history?.push(1, "reader");
try {
options.onReaderOpen?.(pageNum, placement !== null), options.onReaderMount?.(!0), await new Promise((resolve, reject) => {
pendingMount = {
resolve,
reject
}, setReaderView({
pageNum,
placement
});
});
} catch (error) {
throw setReaderView(null), options.onReaderMount?.(!1), options.history?.back(1), await exitFullscreen(), error;
} finally {
pendingMount = null;
}
}
let topPanel = () => disposed ? null : preview()?.mode === "overlay" ? "overlay-preview" : preview()?.mode === "embedded" ? "embedded-preview" : readerView() ? "reader" : null, navi = ReaderPreviewNavi({
top: topPanel,
previewMode: () => {
let placement = readerView()?.placement;
return placement?.coversPreview && placement.container.available() && !fullscreenActive() ? "embedded" : "overlay";
},
openReader: mountReader,
openPreview(pageNum, mode) {
disposed || (previewReturnPage = pageNum, preview() || options.history?.push(historyDepth() + 1, "preview"), setPreview({
mode,
pageNum
}));
},
focusPreview: (pageNum) => previewProgress()?.setProgress(pageNum),
closePreview: (notifyReturn) => closeViews(!1, notifyReturn),
closeReader: () => closeViews(!0, !1),
onError
});
createEffect(() => {
let reader = readerActions(), target = previewProgress();
if (!reader || !target) return;
let syncer = new ReadProgressSyncer(reader.progress, target);
onCleanup(() => syncer.dispose());
}), createEffect(() => applyUiScale(host.uiScale(), previewRoot)), createEffect(() => {
props.embeddedDirection !== void 0 && settings2.embeddedPreviewDirection.set(props.embeddedDirection), props.leftHandedControls !== void 0 && settings2.leftHandedControls.set(props.leftHandedControls);
});
function publishProgress(page2) {
page2.pageNum && setProgress(page2.pageNum), options.onProgress?.(page2);
}
let embeddedPreviewDisabled = () => {
if (preview()?.mode === "overlay") return !0;
if (preview()?.mode === "embedded") return !1;
let view = readerView();
return !!(view && (fullscreenActive() || !view.placement || view.placement.coversPreview));
}, preservingFullscreen = !1, stopFullscreen = host.fullscreen.subscribe((active) => untrack(() => {
let wasFullscreen = fullscreenActive();
setFullscreenActive(active), wasFullscreen && !active && !preservingFullscreen && options.exitOnFullscreenExit && readerView() && navi.closeAll();
}));
async function enterFullscreen() {
if (document.fullscreenElement || !document.fullscreenEnabled || typeof host.element.requestFullscreen != "function") return !0;
try {
return await host.fullscreen.enter(), host.fullscreen.active();
} catch (error) {
return console.warn("[reader] Fullscreen request failed", error), !0;
}
}
async function exitFullscreen() {
preservingFullscreen = !0;
try {
await host.fullscreen.exit();
} finally {
preservingFullscreen = !1;
}
}
function toggleFullscreen() {
(host.fullscreen.active() ? exitFullscreen() : host.fullscreen.enter()).catch(onError);
}
function ReaderOverlay(view) {
let container = untrack(() => view.placement?.container), [bounds, setBounds] = createSignal(null), updateBounds = () => setBounds(fullscreenActive() ? null : container?.bounds() ?? null);
createEffect(updateBounds), onCleanup(lockPageScroll()), onCleanup(lockPageThemeColor("#070707")), container && onCleanup(container.listen({
onBoundsChange: updateBounds
})), onCleanup(() => setReaderActions(null));
let element = (() => {
var _el$ = _tmpl$39();
return _el$.classList.toggle("ehpeek-reader-panel", container !== void 0), insert(_el$, createComponent(Reader, {
get disabled() {
return props.disabled || preview() !== null;
},
ref: setReaderActions,
onClose: () => navi.back(),
onProgress: publishProgress,
onEnd: () => options.onEnd?.(),
onOpenPreview: (pageNum) => navi.openPreview(pageNum, !0),
onToggleFullscreen: toggleFullscreen,
settings: settings2,
get customization() {
return {
...options.customization,
onOpenOriginalPage: options.customization?.onOpenOriginalPage ? (url, page2) => {
exitFullscreen().then(() => options.customization?.onOpenOriginalPage?.(url, page2)).catch(onError);
} : void 0
};
},
get fullscreenActive() {
return fullscreenActive();
},
get initPage() {
return view.pageNum;
},
get source() {
return options.source;
}
})), createRenderEffect((_$p) => style(_el$, {
...bounds() ? {
height: `${bounds().height}px`,
left: `${bounds().left}px`,
overflow: "hidden",
position: "fixed",
top: `${bounds().top}px`,
transform: "translateZ(0)",
width: `${bounds().width}px`
} : {},
visibility: preview()?.mode === "embedded" ? "hidden" : void 0
}, _$p)), _el$;
})();
return onMount(() => {
pendingMount && queueMicrotask(pendingMount.resolve);
}), element;
}
onCleanup(() => {
disposed = !0, stopFullscreen(), stopHistory(), pendingBack?.resolve(), pendingBack = null, pendingMount?.resolve(), pendingMount = null, options.onReaderMount?.(!1), cache.dispose(), props.instanceRef?.(null), (async () => {
await opening?.catch(onError), await exitFullscreen();
})().catch(onError).finally(() => {
options.host || host.element.remove();
});
});
let instance = {
settings: settings2,
progress,
get activeView() {
let top = topPanel();
return top === "overlay-preview" || top === "embedded-preview" ? "preview" : top;
},
open: (pageNum = options.source.initialPageNum, fullscreen = !1) => openReader(pageNum, fullscreen),
openPreview: (pageNum = progress() ?? options.source.initialPageNum) => navi.openPreview(pageNum)
};
return onMount(() => props.instanceRef?.(instance)), createComponent(OverlayHostProvider, {
host,
get children() {
return [(() => {
var _el$2 = _tmpl$214(), _ref$ = previewRoot;
return typeof _ref$ == "function" ? use(_ref$, _el$2) : previewRoot = _el$2, insert(_el$2, createComponent(ReadingPreview, {
get disabled() {
return props.disabled ?? !1;
},
get embeddedDisabled() {
return embeddedPreviewDisabled();
},
get openState() {
return preview();
},
progressRef: (port) => {
setPreviewProgress(port);
let page2 = progress();
page2 !== null && port?.setProgress(page2);
},
get initialProgress() {
return options.initialProgress;
},
get embeddedDirection() {
return settings2.embeddedPreviewDirection.value();
},
get fillEmbeddedContainer() {
return props.fillPreviewContainer ?? (() => !1);
},
get leftHandedControls() {
return settings2.leftHandedControls.value;
},
onReturnPageChange: (pageNum) => {
previewReturnPage = pageNum;
},
onClose: (pageNum) => {
previewReturnPage = pageNum, navi.back();
},
onOpenOverlay: (pageNum) => navi.openPreview(pageNum),
onSelectPage: (page2) => {
openReader(page2, !0).catch(onError);
},
onLoadError: onError,
get onEmbeddedDirectionChange() {
return settings2.embeddedPreviewDirection.set;
},
get onReadDirectionChange() {
return settings2.previewDirection.set;
},
previewCache: cache,
get readDirection() {
return settings2.previewDirection.value();
},
get replaceOriginalPreview() {
return props.embeddedPreview ?? !1;
}
})), _el$2;
})(), createComponent(Show, {
get when() {
return readerView();
},
keyed: !0,
children: (view) => createComponent(ErrorBoundary, {
fallback: (error) => (pendingMount ? pendingMount.reject(error) : queueMicrotask(() => untrack(() => {
disposed || readerView() !== view || (onError(error), navi.closeAll());
})), null),
get children() {
return createComponent(OverlayPortal, {
get children() {
return createComponent(ReaderOverlay, view);
}
});
}
})
})];
}
});
}
var _tmpl$39, _tmpl$214, init_ReadingView = __esm({
"../reader/dist/ReadingView.js"() {
"use strict";
init_chunk_JM34DFW3();
init_chunk_CFKOVVT2();
init_chunk_I4HV7TJW();
init_chunk_DDSH64V2();
init_chunk_M65F42KE();
init_chunk_DIPUDBVX();
init_chunk_R253JGHC();
init_chunk_25OOXIQ6();
init_chunk_5OWZ2GGT();
init_chunk_IECOMI6N();
init_chunk_SEW7F2R2();
init_chunk_WGECFBEU();
init_chunk_YD563ASB();
init_chunk_XNXFHHML();
init_chunk_O4OUM2TM();
init_chunk_PBZTMYEM();
init_chunk_FRCEUGG2();
init_chunk_ABQJ4E5U();
init_chunk_CK6USHZG();
init_chunk_WWFOV7YA();
init_chunk_7DN2G2IN();
init_chunk_QXLQXDIQ();
init_chunk_PV2I4MKV();
init_chunk_QUSU3A2M();
init_chunk_I2UURCWR();
init_chunk_ENSDPUNG();
init_chunk_A6WI3YS4();
init_chunk_6JKLIWFA();
init_chunk_UVKXFJHK();
init_chunk_4Y6MOAXB();
init_chunk_IFEJ2BNL();
init_chunk_FUW3K55A();
init_chunk_NP6I7EK4();
init_chunk_V7QAVQKV();
init_chunk_MLGDT3ZG();
init_chunk_F33WVP3N();
init_chunk_NU4SG75H();
init_chunk_GUZXW3OF();
init_chunk_UPVG5Y6S();
init_chunk_W6BYXZGJ();
init_chunk_JXES5MWD();
init_chunk_VWKAYSAY();
init_chunk_W6Q6Q5LD();
init_chunk_WH3QJFUT();
init_chunk_TRAUK5J2();
init_chunk_E6UKP7HT();
init_chunk_PKBMQBKP();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_solid();
_tmpl$39 = /* @__PURE__ */ template("<div>"), _tmpl$214 = /* @__PURE__ */ template('<div class="ehpeek-ui-root ehpeek-reading-view">');
}
});
// src/components/Enhance/ScrollPageBar.tsx
function GalleryPageDescription(props) {
return (() => {
var _el$ = _tmpl$40();
return insert(_el$, () => props.text), _el$;
})();
}
function ScrollPageBar(props) {
let maxIndex = createMemo(() => Math.max(0, props.maxIndex)), currentIndex = createMemo(() => clamp(props.currentIndex, 0, maxIndex())), [visibleCenterIndex, setVisibleCenterIndex] = createSignal(untrack(currentIndex)), gestureHost, dragStartVisibleCenterIndex = untrack(visibleCenterIndex), draggable = () => maxIndex() + 1 > 7, slots = createMemo(() => pageSlots(visibleCenterIndex(), maxIndex())), firstSlotIndex = createMemo(() => slots()[0] ?? currentIndex()), lastSlotIndex = createMemo(() => slots()[slots().length - 1] ?? currentIndex()), currentBeforeWindow = () => currentIndex() < firstSlotIndex(), currentAfterWindow = () => currentIndex() > lastSlotIndex(), scrollTargetForIndex = (pageIndex) => pageIndex === currentIndex() - 1 || pageIndex === maxIndex() ? "bottom" : "top";
createEffect(() => {
setVisibleCenterIndex(currentIndex());
});
let linkCell = (text, pageIndex, itemState = () => "link") => {
let resolvedText = () => typeof text == "function" ? text() : text, resolvedPageIndex = () => typeof pageIndex == "function" ? pageIndex() : pageIndex;
return (() => {
var _el$2 = _tmpl$310();
return insert(_el$2, createComponent(Show, {
get when() {
return itemState() === "link";
},
get fallback() {
return (() => {
var _el$4 = _tmpl$46();
return insert(_el$4, resolvedText), createRenderEffect((_p$) => {
var _v$ = `${PAGE_BAR_LINK_CLASS} ${itemState() === "current" ? PAGE_BAR_CURRENT_COLOR_CLASS : PAGE_BAR_DISABLED_COLOR_CLASS}`, _v$2 = itemState() === "current" ? "page" : void 0, _v$3 = itemState() === "disabled" ? "true" : void 0;
return _v$ !== _p$.e && className(_el$4, _p$.e = _v$), _v$2 !== _p$.t && setAttribute(_el$4, "aria-current", _p$.t = _v$2), _v$3 !== _p$.a && setAttribute(_el$4, "aria-disabled", _p$.a = _v$3), _p$;
}, {
e: void 0,
t: void 0,
a: void 0
}), _el$4;
})();
},
get children() {
var _el$3 = _tmpl$215();
return _el$3.$$click = (event) => {
event.preventDefault(), event.stopPropagation(), props.onNavigate(resolvedPageIndex(), scrollTargetForIndex(resolvedPageIndex()));
}, setAttribute(_el$3, "draggable", !1), insert(_el$3, resolvedText), createRenderEffect(() => setAttribute(_el$3, "href", props.urlForIndex(resolvedPageIndex()))), _el$3;
}
})), _el$2;
})();
}, emptyCell = () => (() => {
var _el$5 = _tmpl$55(), _el$6 = _el$5.firstChild;
return _el$5;
})();
return createPointerGestureElement(() => gestureHost, () => ({
shouldCaptureDrag: draggable,
dragAxis: "x",
onStart: () => {
dragStartVisibleCenterIndex = visibleCenterIndex();
},
onMove: (info) => {
if (Math.abs(info.dx) < Math.abs(info.dy))
return;
let nextIndex = clamp(dragStartVisibleCenterIndex - acceleratedPageOffset(info.dx), 0, maxIndex());
nextIndex !== visibleCenterIndex() && setVisibleCenterIndex(nextIndex);
}
})), (() => {
var _el$7 = _tmpl$65(), _el$8 = _el$7.firstChild, _el$9 = _el$8.firstChild, _el$0 = _el$9.firstChild, _ref$ = gestureHost;
return typeof _ref$ == "function" ? use(_ref$, _el$7) : gestureHost = _el$7, insert(_el$0, () => linkCell("<<", 0, () => currentIndex() === 0 ? "disabled" : "link"), null), insert(_el$0, createComponent(Show, {
get when() {
return currentBeforeWindow();
},
get fallback() {
return emptyCell();
},
get children() {
return linkCell(() => String(currentIndex() + 1), currentIndex, () => "current");
}
}), null), insert(_el$0, () => linkCell("<", () => Math.max(0, currentIndex() - 1), () => currentIndex() === 0 ? "disabled" : "link"), null), insert(_el$0, createComponent(For, {
get each() {
return slots();
},
children: (pageIndex) => {
let itemState = createMemo(() => pageIndex === currentIndex() ? "current" : "link");
return pageIndex !== null ? (() => {
var _el$1 = _tmpl$310();
return insert(_el$1, createComponent(Show, {
get when() {
return itemState() === "link";
},
get fallback() {
return (() => {
var _el$11 = _tmpl$74();
return insert(_el$11, pageIndex + 1), _el$11;
})();
},
get children() {
var _el$10 = _tmpl$215();
return _el$10.$$click = (event) => {
event.preventDefault(), event.stopPropagation(), props.onNavigate(pageIndex, scrollTargetForIndex(pageIndex));
}, setAttribute(_el$10, "draggable", !1), insert(_el$10, pageIndex + 1), createRenderEffect(() => setAttribute(_el$10, "href", props.urlForIndex(pageIndex))), _el$10;
}
})), _el$1;
})() : emptyCell();
}
}), null), insert(_el$0, () => linkCell(">", () => Math.min(maxIndex(), currentIndex() + 1), () => currentIndex() === maxIndex() ? "disabled" : "link"), null), insert(_el$0, createComponent(Show, {
get when() {
return currentAfterWindow();
},
get fallback() {
return emptyCell();
},
get children() {
return linkCell(() => String(currentIndex() + 1), currentIndex, () => "current");
}
}), null), insert(_el$0, () => linkCell(">>", maxIndex, () => currentIndex() === maxIndex() ? "disabled" : "link"), null), _el$7;
})();
}
function pageSlots(visibleCenterIndex, maxIndex) {
if (maxIndex + 1 <= 7)
return range(0, maxIndex);
let visibleStartIndex = clamp(visibleCenterIndex - 3, -1, maxIndex - 5);
return range(visibleStartIndex, visibleStartIndex + 6).map((pageIndex) => pageIndex >= 0 && pageIndex <= maxIndex ? pageIndex : null);
}
function range(start2, end) {
let output = [];
for (let index = start2; index <= end; index += 1)
output.push(index);
return output;
}
function acceleratedPageOffset(dx) {
let distance = Math.abs(dx), direction = dx > 0 ? 1 : -1, pages = Math.floor((distance / DRAG_PIXEL_STEP) ** 1.35);
return direction * pages;
}
var _tmpl$40, _tmpl$215, _tmpl$310, _tmpl$46, _tmpl$55, _tmpl$65, _tmpl$74, DRAG_PIXEL_STEP, PAGE_BAR_LINK_CLASS, PAGE_BAR_CURRENT_COLOR_CLASS, PAGE_BAR_DISABLED_COLOR_CLASS, init_ScrollPageBar = __esm({
"src/components/Enhance/ScrollPageBar.tsx"() {
"use strict";
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_solid();
init_helpers();
init_PointerGesture();
_tmpl$40 = /* @__PURE__ */ template('<div class="w-full ui-mb-xs text-center textsize-sm">'), _tmpl$215 = /* @__PURE__ */ template('<a class="flex !ui-hit-w-sm !ui-hit-h-sm items-center justify-center box-border !p-0 ui-rounded-sm !border textsize-sm font-inherit no-underline hover:no-underline active:no-underline !border-transparent !bg-transparent !text-[var(--color-site-text)] visited:!text-[var(--color-site-text)] hover:!bg-[var(--color-site-item-hover)] hover:!text-[var(--color-site-text)] active:!text-[var(--color-site-text)]">'), _tmpl$310 = /* @__PURE__ */ template('<td class="!ui-hit-w-sm !ui-hit-h-sm !p-0 ui-rounded-sm cursor-pointer text-center align-middle select-none">'), _tmpl$46 = /* @__PURE__ */ template("<span>"), _tmpl$55 = /* @__PURE__ */ template('<td class="!ui-hit-w-sm !ui-hit-h-sm !p-0 ui-rounded-sm cursor-pointer text-center align-middle select-none cursor-default"><span class="flex !ui-hit-w-sm !ui-hit-h-sm items-center justify-center box-border !p-0 ui-rounded-sm !border textsize-sm font-inherit no-underline hover:no-underline active:no-underline !border-transparent !bg-transparent !text-[var(--color-site-text)] visited:!text-[var(--color-site-text)] hover:!bg-[var(--color-site-item-hover)] hover:!text-[var(--color-site-text)] active:!text-[var(--color-site-text)] invisible">'), _tmpl$65 = /* @__PURE__ */ template('<div class=touch-pan-y><table class="border-separate border-spacing-[var(--ui-space-xs)]"><tbody><tr>'), _tmpl$74 = /* @__PURE__ */ template('<span class="flex !ui-hit-w-sm !ui-hit-h-sm items-center justify-center box-border !p-0 ui-rounded-sm !border textsize-sm font-inherit no-underline hover:no-underline active:no-underline !border-transparent !bg-[color-mix(in_srgb,var(--color-site-page)_82%,black)] !text-[var(--color-site-text)]"aria-current=page>'), DRAG_PIXEL_STEP = 18, PAGE_BAR_LINK_CLASS = "flex !ui-hit-w-sm !ui-hit-h-sm items-center justify-center box-border !p-0 ui-rounded-sm !border textsize-sm font-inherit no-underline hover:no-underline active:no-underline", PAGE_BAR_CURRENT_COLOR_CLASS = "!border-transparent !bg-[color-mix(in_srgb,var(--color-site-page)_82%,black)] !text-[var(--color-site-text)]", PAGE_BAR_DISABLED_COLOR_CLASS = "!border-transparent !bg-[color-mix(in_srgb,var(--color-site-page)_82%,black)] !text-[var(--color-site-text)] opacity-40 cursor-default";
delegateEvents(["click"]);
}
});
// src/components/Enhance/EnhanceThumbsGrids.tsx
function ThumbsGrids(props) {
let pageBarSource = untrack(() => props.previewCache.current()), [pageBarCurrentIndex, setPageBarCurrentIndex] = createSignal(pageBarSource.data.currentIndex), [swipeIndicatorState, setSwipeIndicatorState] = createSignal({
blocked: !1,
direction: "left",
progress: 0
}), pageBarMaxIndex = () => props.previewCache.current().data.maxIndex, requestPreviewPage = (previewIndex, scrollToPageBar) => {
let current = props.previewCache.current(), onLoadError = props.onLoadError;
pageBarSource.handle.scrollPreviewPageBarIntoView(scrollToPageBar), previewIndex !== current.data.currentIndex && (setPageBarCurrentIndex(previewIndex), props.previewCache.select(previewIndex).then((next) => {
untrack(() => props.previewCache.current()) === next && pageBarSource.handle.scrollPreviewPageBarIntoView(scrollToPageBar);
}, (error) => {
let cacheIndex = untrack(() => props.previewCache.current().data.currentIndex);
setPageBarCurrentIndex((currentIndex) => currentIndex === previewIndex ? cacheIndex : currentIndex), onLoadError(error);
}));
}, swipeIndexForDelta = (dx) => {
let current = props.previewCache.current().data, nextIndex = dx < 0 ? current.currentIndex + 1 : current.currentIndex - 1;
return nextIndex < 0 || nextIndex > current.maxIndex ? null : nextIndex;
}, hideSwipeIndicator = () => {
setSwipeIndicatorState((current) => ({
...current,
blocked: !1,
progress: 0
}));
}, updateSwipeIndicator = (info) => {
setSwipeIndicatorState({
blocked: swipeIndexForDelta(info.dx) === null,
direction: info.dx < 0 ? "left" : "right",
progress: Math.min(1, Math.max(0, (Math.abs(info.dx) - SWIPE_INTENT_DISTANCE2) / (SWIPE_MIN_DISTANCE2 - SWIPE_INTENT_DISTANCE2)))
});
}, navigateBySwipe = (info, event) => {
let absX = Math.abs(info.dx), absY = Math.abs(info.dy);
if (absX < SWIPE_MIN_DISTANCE2 || absY > absX * SWIPE_MAX_VERTICAL_RATIO2)
return;
let previewIndex = swipeIndexForDelta(info.dx);
previewIndex !== null && (event.preventDefault(), requestPreviewPage(previewIndex, info.dx < 0 ? "top" : "bottom"));
}, actions = {
gotoPreview: setPageBarCurrentIndex
};
untrack(() => props.actionsRef)(actions), createEffect((previous) => {
let current = props.previewCache.current();
return setPageBarCurrentIndex(current.data.currentIndex), current.handle.ensurePreviewSwipeInput(), current !== previous && pageBarSource.handle.replacePreviewThumbs(current.elems.thumbItems), current;
}, pageBarSource), createEffect(() => {
pageBarSource.handle.updatePreviewLoading(props.previewCache.loading());
}), onCleanup(() => {
pageBarSource.handle.updatePreviewLoading(!1);
}), createPointerGestureElement(() => pageBarSource.elems.thumbs?.Component() ?? null, () => ({
onStart: hideSwipeIndicator,
onMove: updateSwipeIndicator,
onEnd: (info, event) => {
navigateBySwipe(info, event), hideSwipeIndicator();
},
dragAxis: "x",
dragIntentRatio: HORIZONTAL_INTENT_RATIO2,
dragStartThreshold: SWIPE_INTENT_DISTANCE2
})), pageBarSource.handle.installPreviewPageBars(), pageBarSource.elems.pageBarDescription?.mount(() => createComponent(GalleryPageDescription, {
get text() {
return props.previewCache.current().data.descriptionText;
}
}));
for (let element of [pageBarSource.elems.pageBarTop, pageBarSource.elems.pageBarBottom])
element && element.mount(() => createComponent(ScrollPageBar, {
get currentIndex() {
return pageBarCurrentIndex();
},
get maxIndex() {
return pageBarMaxIndex();
},
onNavigate: requestPreviewPage,
urlForIndex: (index) => previewUrlForIndex(index, props.previewCache.current().data.currentUrl)
}));
return onCleanup(() => {
pageBarSource.elems.pageBarDescription?.remove(), pageBarSource.elems.pageBarTop?.remove(), pageBarSource.elems.pageBarBottom?.remove();
}), [createComponent(LoadingOverlay, {
get label() {
return activeTexts.common.status.loading;
},
get visible() {
return props.previewCache.loading();
}
}), createComponent(SwipeIndicator, {
get state() {
return swipeIndicatorState();
}
})];
}
var SWIPE_MIN_DISTANCE2, SWIPE_INTENT_DISTANCE2, HORIZONTAL_INTENT_RATIO2, SWIPE_MAX_VERTICAL_RATIO2, init_EnhanceThumbsGrids = __esm({
"src/components/Enhance/EnhanceThumbsGrids.tsx"() {
"use strict";
init_web();
init_solid();
init_eh();
init_i18n2();
init_PointerGesture();
init_Loading();
init_Widgets();
init_ScrollPageBar();
SWIPE_MIN_DISTANCE2 = 96, SWIPE_INTENT_DISTANCE2 = 28, HORIZONTAL_INTENT_RATIO2 = 2.2, SWIPE_MAX_VERTICAL_RATIO2 = 0.38;
}
});
// src/state/readHistory.ts
async function galleryReadHistory(galleryId, token) {
let history = new GalleryReadHistory(galleryId, token);
return await history.reload(), history;
}
function mergeGalleryInfo(previous, current) {
let merged = {
category: current?.category ?? previous?.category,
categoryClass: current?.categoryClass ?? previous?.categoryClass,
coverUrl: current?.coverUrl ?? previous?.coverUrl,
language: current?.language ?? previous?.language,
postedAt: current?.postedAt ?? (typeof previous?.postedAt == "number" ? previous.postedAt : void 0),
rating: current?.rating ?? (typeof previous?.rating == "number" ? previous.rating : void 0),
title: current?.title ?? previous?.title,
titleSub: current?.titleSub ?? previous?.titleSub,
uploader: current?.uploader ?? previous?.uploader
}, entries = Object.entries(merged).filter((entry) => entry[1] !== void 0);
return entries.length > 0 ? Object.fromEntries(entries) : void 0;
}
async function loadDisplayReadHistoryRecords() {
let keys = await GM.listValues();
return await clearLegacyHistoryQueue(keys), (await loadAllReadHistoryRecords(keys)).filter((record) => record.gallery !== void 0).slice(0, READ_HISTORY_LIMIT);
}
async function clearReadHistory() {
let keys = await GM.listValues();
await Promise.all(keys.filter((key) => key.startsWith(HISTORY_KEY_PREFIX) || key.startsWith(HISTORY_QUEUE_KEY_PREFIX)).map((key) => GM.deleteValue(key))), state.gallery.readHistoryCompactEstimate.set(0);
}
async function removeReadHistory(galleryId, token) {
let history = await galleryReadHistory(galleryId, token);
history.value && (await history.clear(), state.gallery.readHistoryCompactEstimate.set(
Math.max(0, await state.gallery.readHistoryCompactEstimate.reload() - 1)
));
}
async function incrementReadHistoryEstimate() {
let estimate = await state.gallery.readHistoryCompactEstimate.reload() + 1;
state.gallery.readHistoryCompactEstimate.set(estimate), estimate >= HISTORY_COMPACT_THRESHOLD && await pruneReadHistory();
}
function historyKey(galleryId, token) {
return `${HISTORY_KEY_PREFIX}${historyReference(galleryId, token)}`;
}
async function loadAllReadHistoryRecords(keys) {
let storageKeys = keys ?? await GM.listValues();
return (await Promise.all(storageKeys.filter((key) => key.startsWith(HISTORY_KEY_PREFIX)).map((key) => GM.getValue(key, null)))).filter((record) => record !== null).sort((left, right) => right.updatedAt - left.updatedAt);
}
async function clearLegacyHistoryQueue(keys) {
await Promise.all(keys.filter((key) => key.startsWith(HISTORY_QUEUE_KEY_PREFIX)).map((key) => GM.deleteValue(key)));
}
async function pruneReadHistory() {
let keys = await GM.listValues(), records = (await Promise.all(keys.filter((key) => key.startsWith(HISTORY_KEY_PREFIX)).map(async (key) => ({
key,
record: await GM.getValue(key, null)
})))).filter(
(entry) => entry.record !== null
).sort((left, right) => right.record.updatedAt - left.record.updatedAt), retained = records.slice(0, READ_HISTORY_LIMIT);
await Promise.all(records.slice(retained.length).map((entry) => GM.deleteValue(entry.key))), state.gallery.readHistoryCompactEstimate.set(retained.length);
}
function historyReference(galleryId, token) {
return `${galleryId}:${token}`;
}
function storedReadHistoryRecord(record) {
return {
galleryId: record.galleryId,
gallery: record.gallery,
token: record.token,
pageNum: record.pageNum,
totalPages: record.totalPages,
updatedAt: record.updatedAt
};
}
async function exportReadHistory() {
let archive = {
type: READ_HISTORY_ARCHIVE_TYPE,
version: READ_HISTORY_ARCHIVE_VERSION,
records: (await loadAllReadHistoryRecords()).map((record) => ({
galleryId: record.galleryId,
gallery: mergeGalleryInfo(void 0, record.gallery),
pageNum: record.pageNum,
token: record.token,
totalPages: record.totalPages,
updatedAt: record.updatedAt
}))
};
return JSON.stringify(archive, null, 2);
}
async function importReadHistory(source) {
let archive = parseReadHistoryArchive(JSON.parse(source)), imported = /* @__PURE__ */ new Map();
for (let archived of archive.records) {
let record = archiveRecordToHistory(archived), reference = historyReference(record.galleryId, record.token), previous = imported.get(reference);
if (!previous) {
imported.set(reference, record);
continue;
}
let newer = record.updatedAt >= previous.updatedAt ? record : previous, older = newer === record ? previous : record;
imported.set(reference, {
...newer,
gallery: mergeGalleryInfo(older.gallery, newer.gallery)
});
}
return await Promise.all(Array.from(imported, async ([reference, record]) => {
let key = `${HISTORY_KEY_PREFIX}${reference}`, previous = await GM.getValue(key, null), importedIsNewer = !previous || record.updatedAt >= previous.updatedAt, retained = importedIsNewer ? record : previous;
await GM.setValue(key, storedReadHistoryRecord({
...retained,
gallery: importedIsNewer ? mergeGalleryInfo(previous?.gallery, record.gallery) : mergeGalleryInfo(record.gallery, previous.gallery)
}));
})), await pruneReadHistory(), Math.min(imported.size, READ_HISTORY_LIMIT);
}
function parseReadHistoryArchive(source) {
if (!isRecord(source) || source.type !== READ_HISTORY_ARCHIVE_TYPE || source.version !== READ_HISTORY_ARCHIVE_VERSION || !Array.isArray(source.records))
throw new Error("Invalid EhPeek history archive.");
return {
type: READ_HISTORY_ARCHIVE_TYPE,
version: READ_HISTORY_ARCHIVE_VERSION,
records: source.records.map(parseReadHistoryRecord)
};
}
function parseReadHistoryRecord(source) {
if (!isRecord(source) || !Number.isSafeInteger(source.galleryId) || source.galleryId <= 0 || typeof source.token != "string" || source.token.length === 0 || !Number.isSafeInteger(source.pageNum) || source.pageNum < -1 || typeof source.updatedAt != "number" || !Number.isFinite(source.updatedAt) || source.updatedAt <= 0 || source.totalPages !== void 0 && (!Number.isSafeInteger(source.totalPages) || source.totalPages <= 0))
throw new Error("Invalid EhPeek history record.");
return {
galleryId: source.galleryId,
gallery: parseArchiveGallery(source.gallery),
pageNum: source.pageNum,
token: source.token,
totalPages: source.totalPages,
updatedAt: source.updatedAt
};
}
function archiveRecordToHistory(source) {
return {
galleryId: source.galleryId,
gallery: source.gallery,
pageNum: source.pageNum,
token: source.token,
totalPages: source.totalPages,
updatedAt: source.updatedAt
};
}
function parseArchiveGallery(source) {
if (source === void 0)
return;
if (!isRecord(source))
throw new Error("Invalid gallery information in EhPeek history archive.");
let gallery2 = {
category: optionalString(source, "category"),
categoryClass: optionalString(source, "categoryClass"),
coverUrl: optionalString(source, "coverUrl"),
language: optionalString(source, "language"),
postedAt: optionalPositiveNumber(source, "postedAt"),
rating: optionalNumber(source, "rating"),
title: optionalString(source, "title"),
titleSub: optionalString(source, "titleSub"),
uploader: optionalString(source, "uploader")
};
return Object.values(gallery2).some((value) => value !== void 0) ? gallery2 : void 0;
}
function optionalString(source, key) {
let value = source[key];
if (value !== void 0 && typeof value != "string")
throw new Error("Invalid EhPeek history record.");
return value;
}
function optionalNumber(source, key) {
let value = source[key];
if (value !== void 0 && (typeof value != "number" || !Number.isFinite(value)))
throw new Error("Invalid EhPeek history record.");
return value;
}
function optionalPositiveNumber(source, key) {
let value = optionalNumber(source, key);
if (value !== void 0 && value <= 0)
throw new Error("Invalid EhPeek history record.");
return value;
}
function isRecord(source) {
return typeof source == "object" && source !== null && !Array.isArray(source);
}
var HISTORY_KEY_PREFIX, HISTORY_QUEUE_KEY_PREFIX, READ_HISTORY_LIMIT, HISTORY_COMPACT_THRESHOLD, READ_HISTORY_ARCHIVE_TYPE, READ_HISTORY_ARCHIVE_VERSION, GalleryReadHistory, init_readHistory = __esm({
"src/state/readHistory.ts"() {
"use strict";
init_state();
init_storage();
HISTORY_KEY_PREFIX = "ehpeek:history:", HISTORY_QUEUE_KEY_PREFIX = "ehpeek:hist_q:", READ_HISTORY_LIMIT = 3e3, HISTORY_COMPACT_THRESHOLD = 4e3, READ_HISTORY_ARCHIVE_TYPE = "ehpeek-read-history", READ_HISTORY_ARCHIVE_VERSION = 1, GalleryReadHistory = class {
constructor(galleryId, token) {
this.galleryId = galleryId;
this.token = token;
this.store = persisted(
historyKey(galleryId, token),
null
);
}
get value() {
return this.store.value;
}
clear() {
return this.store.clear();
}
reload() {
return this.store.reload();
}
recordVisit(totalPages, gallery2) {
let previous = this.value;
return this.save(previous ? {
...previous,
gallery: mergeGalleryInfo(previous.gallery, gallery2),
totalPages,
updatedAt: Date.now()
} : {
gallery: gallery2,
galleryId: this.galleryId,
pageNum: -1,
token: this.token,
totalPages,
updatedAt: Date.now()
});
}
async save(record) {
let previous = this.value, exists = previous !== null, saved = previous && previous.updatedAt > record.updatedAt ? storedReadHistoryRecord({
...previous,
gallery: mergeGalleryInfo(previous.gallery, record.gallery)
}) : storedReadHistoryRecord({
...record,
gallery: mergeGalleryInfo(previous?.gallery, record.gallery)
});
return await this.store.setAsync(saved), exists || incrementReadHistoryEstimate().catch((error) => {
console.error("[ehpeek] Failed to update reading history count", error);
}), saved;
}
async updateGalleryInfo(gallery2) {
let previous = this.value;
return previous ? this.save({
...previous,
gallery: mergeGalleryInfo(previous.gallery, gallery2)
}) : null;
}
};
}
});
// src/components/Enhance/ReadHistory.tsx
function ReadHistoryPage(props) {
let [items, setItems] = createSignal(untrack(() => props.items)), pageCount = createMemo(() => Math.max(1, Math.ceil(items().length / props.pageSize))), [pageIndex, setPageIndex] = createSignal(Math.min(props.initialPageIndex, untrack(pageCount) - 1)), [transferStatus, setTransferStatus] = createSignal(""), historyFileInput, pageItems = createMemo(() => {
let start2 = pageIndex() * props.pageSize;
return items().slice(start2, start2 + props.pageSize);
}), visibleRange = createMemo(() => {
if (items().length === 0)
return "0 / 0";
let start2 = pageIndex() * props.pageSize + 1, end = Math.min(start2 + props.pageSize - 1, items().length);
return activeTexts.history.range.replace("{start}", String(start2)).replace("{end}", String(end)).replace("{total}", String(items().length));
}), navigate = (nextPageIndex, scrollToPageBar = "top", updateUrl = !0) => {
let nextIndex = Math.max(0, Math.min(nextPageIndex, pageCount() - 1));
nextIndex !== pageIndex() && (setPageIndex(nextIndex), updateUrl && window.history.pushState(window.history.state, "", readHistoryUrl(nextIndex)), props.source.handle.scrollReadHistoryPage(scrollToPageBar));
}, clearHistory = async () => {
window.confirm(activeTexts.history.clearConfirm) && (await clearReadHistory(), setItems([]), setPageIndex(0), setTransferStatus(""), window.history.replaceState(window.history.state, "", readHistoryUrl()));
}, importHistoryFile = async (file) => {
try {
let count = await importReadHistory(await file.text());
setItems((await loadDisplayReadHistoryRecords()).map((record) => ({
currentPage: record.pageNum,
galleryId: record.galleryId,
info: record.gallery,
token: record.token,
totalPages: record.totalPages,
updatedAt: record.updatedAt
}))), setPageIndex(0), setTransferStatus(activeTexts.history.imported.replace("{count}", String(count))), window.history.replaceState(window.history.state, "", readHistoryUrl());
} catch {
setTransferStatus(activeTexts.history.importFailed);
}
}, exportHistoryFile = async () => {
let url = URL.createObjectURL(new Blob([await exportReadHistory()], {
type: "application/json"
})), link = document.createElement("a");
link.href = url, link.download = `ehpeek-history-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.json`, link.click(), URL.revokeObjectURL(url), setTransferStatus(activeTexts.history.exported);
}, removeHistoryItem = async (item) => {
if (!window.confirm(activeTexts.history.removeConfirm))
return;
await removeReadHistory(item.galleryId, item.token);
let nextItems = items().filter((candidate) => candidate.galleryId !== item.galleryId || candidate.token !== item.token), nextPageCount = Math.max(1, Math.ceil(nextItems.length / props.pageSize)), nextPageIndex = Math.min(pageIndex(), nextPageCount - 1);
setItems(nextItems), setPageIndex(nextPageIndex), window.history.replaceState(window.history.state, "", readHistoryUrl(nextPageIndex));
};
createEffect(() => {
props.source.handle.updateReadHistoryItems(pageItems());
}), onMount(() => {
let syncFromHistory = () => {
let page2 = extractPageType();
page2.type === "readHistory" && navigate(page2.pageIndex, "top", !1);
};
window.addEventListener("popstate", syncFromHistory);
let stopRemoval = props.source.handle.listenForReadHistoryRemoval(removeHistoryItem);
onCleanup(() => {
stopRemoval(), window.removeEventListener("popstate", syncFromHistory);
});
});
let navigation = (showHeader) => (() => {
var _el$ = _tmpl$41();
return insert(_el$, showHeader && [(() => {
var _el$2 = _tmpl$216(), _el$3 = _el$2.firstChild;
return insert(_el$2, visibleRange, _el$3), insert(_el$3, () => activeTexts.history.limit.replace("{limit}", String(READ_HISTORY_LIMIT))), _el$2;
})(), (() => {
var _el$4 = _tmpl$311(), _el$5 = _el$4.firstChild, _el$6 = _el$5.nextSibling, _el$7 = _el$6.nextSibling;
_el$5.addEventListener("change", (event) => {
let input2 = event.currentTarget, file = input2.files?.[0];
input2.value = "", file && importHistoryFile(file);
});
var _ref$ = historyFileInput;
return typeof _ref$ == "function" ? use(_ref$, _el$5) : historyFileInput = _el$5, _el$6.$$click = () => historyFileInput.click(), insert(_el$6, () => activeTexts.history.actions.import), _el$7.$$click = exportHistoryFile, insert(_el$7, () => activeTexts.history.actions.export), insert(_el$4, (() => {
var _c$2 = memo(() => items().length > 0);
return () => _c$2() && (() => {
var _el$8 = _tmpl$47();
return _el$8.$$click = clearHistory, insert(_el$8, () => activeTexts.history.actions.clear), _el$8;
})();
})(), null), _el$4;
})(), memo(() => memo(() => !!transferStatus())() && (() => {
var _el$9 = _tmpl$56();
return insert(_el$9, transferStatus), _el$9;
})())], null), insert(_el$, (() => {
var _c$ = memo(() => pageCount() > 1);
return () => _c$() && createComponent(ScrollPageBar, {
get currentIndex() {
return pageIndex();
},
get maxIndex() {
return pageCount() - 1;
},
onNavigate: navigate,
urlForIndex: readHistoryUrl
});
})(), null), _el$;
})();
return (() => {
var _el$0 = _tmpl$66();
return insert(_el$0, createComponent(PageSwipe, {
canNavigate: (direction) => direction === "next" ? pageIndex() + 1 < pageCount() : pageIndex() > 0,
onNavigate: (direction) => navigate(direction === "next" ? pageIndex() + 1 : pageIndex() - 1),
target: () => props.source.elems.resultList.Component()
}), null), insert(_el$0, () => navigation(!0), null), insert(_el$0, (() => {
var _c$3 = memo(() => items().length === 0);
return () => _c$3() && (() => {
var _el$1 = _tmpl$75();
return insert(_el$1, () => activeTexts.history.empty), _el$1;
})();
})(), null), insert(_el$0, (() => {
var _c$4 = memo(() => pageCount() > 1);
return () => _c$4() && createComponent(Portal, {
get mount() {
return props.source.elems.navigationBottomMount.Component();
},
get children() {
return navigation(!1);
}
});
})(), null), _el$0;
})();
}
var _tmpl$41, _tmpl$216, _tmpl$311, _tmpl$47, _tmpl$56, _tmpl$66, _tmpl$75, init_ReadHistory = __esm({
"src/components/Enhance/ReadHistory.tsx"() {
"use strict";
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_solid();
init_web();
init_eh();
init_url();
init_readHistory();
init_i18n2();
init_PageSwipe();
init_ScrollPageBar();
_tmpl$41 = /* @__PURE__ */ template('<nav class="flex flex-col items-center ui-gap-sm border-0 border-y border-solid ehp-color-site-border-subtle-b ui-p-md">'), _tmpl$216 = /* @__PURE__ */ template('<span class="text-center textsize-md font-600 ehp-color-site-text"><span class=block>'), _tmpl$311 = /* @__PURE__ */ template('<div class="flex flex-wrap items-center justify-center ui-gap-sm"><input class=hidden type=file accept=application/json,.json><button type=button class="ui-hit-min-h-xs ui-px-sm ui-rounded-sm border-0 bg-transparent ehp-color-site-text textsize-md font-600 cursor-pointer [touch-action:manipulation] hover:bg-[var(--color-site-item-hover)]"></button><button type=button class="ui-hit-min-h-xs ui-px-sm ui-rounded-sm border-0 bg-transparent ehp-color-site-text textsize-md font-600 cursor-pointer [touch-action:manipulation] hover:bg-[var(--color-site-item-hover)]">'), _tmpl$47 = /* @__PURE__ */ template('<button type=button class="ui-hit-min-h-xs ui-px-sm ui-rounded-sm border-0 bg-transparent ehp-color-site-text textsize-md font-600 cursor-pointer [touch-action:manipulation] hover:bg-[var(--color-site-item-hover)]">'), _tmpl$56 = /* @__PURE__ */ template('<span class="textsize-sm ehp-color-site-text opacity-75">'), _tmpl$66 = /* @__PURE__ */ template("<div>"), _tmpl$75 = /* @__PURE__ */ template('<div class="ui-p-xl text-center textsize-md ehp-color-site-text opacity-72">');
delegateEvents(["click"]);
}
});
// src/components/Enhance/SearchHistory.tsx
function SearchHistory(props) {
let dropdown, [searchValue, setSearchValue] = createSignal(untrack(() => props.source.data.value)), [history, setHistory] = createSignal([]), [open, setOpen] = createSignal(!1), [activeIndex, setActiveIndex] = createSignal(-1), [position, setPosition] = createSignal(null), itemButtons = [], visiblePosition = () => open() && !searchValue().trim() && history().length > 0 ? position() : null, selectHistory = (item) => {
props.source.handle.applySearchSelection(item), setOpen(!1);
};
return onMount(() => {
loadSearchHistory().then(setHistory).catch((error) => {
console.error("[ehpeek] Failed to load search history", error);
});
let updatePosition = () => {
setPosition(props.source.handle.readSearchOverlayPosition());
}, showHistory = () => {
updatePosition(), setActiveIndex(-1), setOpen(!0);
}, moveSelection = (offset) => {
let items = history();
if (items.length === 0)
return;
let current = activeIndex(), next = current < 0 ? offset > 0 ? 0 : items.length - 1 : (current + offset + items.length) % items.length;
setActiveIndex(next), window.requestAnimationFrame(() => itemButtons[next]?.scrollIntoView({
block: "nearest"
}));
}, onInputKeyDown = (event) => {
if (visiblePosition())
if (event.key === "ArrowDown" || event.key === "ArrowUp")
event.preventDefault(), moveSelection(event.key === "ArrowDown" ? 1 : -1);
else if (event.key === "Enter" && activeIndex() >= 0) {
event.preventDefault();
let item = history()[activeIndex()];
item !== void 0 && selectHistory(item);
} else event.key === "Escape" && (event.preventDefault(), setOpen(!1));
}, updateSearchValue = (value, focused) => {
setSearchValue(value), !value.trim() && focused && showHistory();
}, recordSearch = (sourceValue) => {
let value = sourceValue.trim();
value && addSearchHistory(value).then(setHistory).catch((error) => {
console.error("[ehpeek] Failed to save search history", error);
});
}, disconnect = props.source.handle.listenSearchHistoryOverlay({
onFocus: showHistory,
onInput: updateSearchValue,
onKeyDown: onInputKeyDown,
onOutsidePointer: () => setOpen(!1),
onPositionChange: updatePosition,
onSubmit: recordSearch
}, () => dropdown ?? null);
updateSearchValue(props.source.data.value, !1), onCleanup(disconnect);
}), createComponent(Show, {
get when() {
return visiblePosition();
},
children: (currentPosition) => (() => {
var _el$ = _tmpl$48(), _ref$ = dropdown;
return typeof _ref$ == "function" ? use(_ref$, _el$) : dropdown = _el$, insert(_el$, createComponent(For, {
get each() {
return history();
},
children: (item, index) => (() => {
var _el$2 = _tmpl$217(), _el$3 = _el$2.firstChild, _el$4 = _el$3.nextSibling;
return _el$3.$$click = () => selectHistory(item), _el$3.addEventListener("pointerenter", () => setActiveIndex(index())), use((button2) => {
itemButtons[index()] = button2;
}, _el$3), setAttribute(_el$3, "title", item), insert(_el$3, item), _el$4.$$click = () => {
removeSearchHistory(item).then(setHistory).catch((error) => {
console.error("[ehpeek] Failed to remove search history", error);
});
}, createRenderEffect(() => className(_el$3, `appearance-none block min-w-0 ui-hit-min-h-lg flex-1 overflow-hidden text-ellipsis whitespace-nowrap ui-px-lg border-0 ehp-color-site-text text-left textsize-lg font-inherit cursor-pointer [touch-action:manipulation] active:bg-[var(--color-site-item-hover)] ${activeIndex() === index() ? "bg-[var(--color-site-item-hover)]" : "bg-transparent"}`)), _el$2;
})()
})), createRenderEffect((_p$) => {
var _v$ = `${currentPosition().left}px`, _v$2 = `${currentPosition().top}px`, _v$3 = `${currentPosition().width}px`;
return _v$ !== _p$.e && setStyleProperty(_el$, "left", _p$.e = _v$), _v$2 !== _p$.t && setStyleProperty(_el$, "top", _p$.t = _v$2), _v$3 !== _p$.a && setStyleProperty(_el$, "width", _p$.a = _v$3), _p$;
}, {
e: void 0,
t: void 0,
a: void 0
}), _el$;
})()
});
}
var _tmpl$48, _tmpl$217, init_SearchHistory = __esm({
"src/components/Enhance/SearchHistory.tsx"() {
"use strict";
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_solid();
init_state();
_tmpl$48 = /* @__PURE__ */ template('<section class="absolute z-ui flex box-border max-h-[60dvh] flex-col overflow-x-hidden overflow-y-auto overscroll-contain ui-rounded-md border ehp-color-site-border ehp-color-site-elevated ehp-color-site-text font-sans"role=list>'), _tmpl$217 = /* @__PURE__ */ template('<div class="flex min-w-0 flex-none items-stretch border-0 border-b ehp-color-site-border-subtle-b last:border-b-0"role=listitem><button type=button></button><button type=button class="appearance-none inline-flex ui-hit-w-lg ui-hit-min-h-lg flex-none items-center justify-center border-0 border-l ehp-color-site-border-subtle-b bg-transparent ehp-color-site-text textsize-xl font-inherit leading-1 cursor-pointer [touch-action:manipulation] active:bg-[var(--color-site-item-hover)]">×');
delegateEvents(["click"]);
}
});
// src/state/myTags.ts
async function loadMyTagsPage(tagSet) {
let url = new URL("/mytags", window.location.origin);
tagSet && url.searchParams.set("tagset", tagSet);
let response = await requestPage(url.href);
return extractMyTagsPageData(response.document, tagSet);
}
function loadMyTagAppearances() {
return state.gallery.myTags.value && state.gallery.myTagAppearances.stored() ? state.gallery.myTagAppearances.reload() : null;
}
async function refreshMyTags(initialPage) {
if (!state.gallery.myTags.value)
return null;
try {
let initialData = initialPage ?? await loadMyTagsPage(), options = initialData.options;
state.gallery.myTagSets.set(options);
let appearances = (options.length > 0 ? await Promise.all(options.map(async (option2) => option2.selected ? initialData : loadMyTagsPage(option2.value))) : [initialData]).flatMap((page2) => page2.enabled ? page2.appearances : []), unique = Array.from(new Map(appearances.map((appearance) => [appearance.name, appearance])).values());
return state.gallery.myTagAppearances.set(unique), unique;
} catch (error) {
return console.error("[ehpeek] Could not load My Tags", error), null;
}
}
var init_myTags = __esm({
"src/state/myTags.ts"() {
"use strict";
init_eh();
init_state();
}
});
// src/components/SettingsMenu.tsx
function SwitchButton(props) {
let [helpOpen, setHelpOpen] = createSignal(!1);
return (() => {
var _el$ = _tmpl$218(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.firstChild, _el$5 = _el$4.nextSibling, _el$6 = _el$5.firstChild, _el$7 = _el$6.nextSibling, _el$8 = _el$3.nextSibling;
return _el$3.$$click = (event) => {
event.stopPropagation(), props.onChange(!props.checked);
}, insert(_el$4, () => props.label), insert(_el$6, (() => {
var _c$ = memo(() => !!props.checked);
return () => _c$() ? activeTexts.settings.on : activeTexts.settings.off;
})()), _el$8.$$click = (event) => {
event.stopPropagation(), setHelpOpen((open) => !open);
}, insert(_el$, createComponent(Show, {
get when() {
return helpOpen();
},
get children() {
var _el$9 = _tmpl$49();
return insert(_el$9, () => props.description), _el$9;
}
}), null), createRenderEffect(() => className(_el$7, `${SETTINGS_DOT_CLASS} ${props.checked ? "bg-[var(--color-state-on)]" : "bg-[var(--color-state-off)]"}`)), _el$;
})();
}
function SelectSetting(props) {
return (() => {
var _el$0 = _tmpl$312(), _el$1 = _el$0.firstChild, _el$10 = _el$1.nextSibling;
return insert(_el$1, () => props.label), _el$10.addEventListener("change", (event) => {
let value = props.options.find((option2) => option2.value === event.currentTarget.value)?.value;
value && props.onChange(value);
}), insert(_el$10, createComponent(For, {
get each() {
return props.options;
},
children: (option2) => (() => {
var _el$11 = _tmpl$410();
return insert(_el$11, () => option2.label), createRenderEffect(() => _el$11.value = option2.value), _el$11;
})()
})), createRenderEffect(() => setAttribute(_el$0, "translate", props.noTranslate ? "no" : void 0)), createRenderEffect(() => _el$10.value = props.value), _el$0;
})();
}
function SettingsMenu(props) {
let [draft, setDraft] = createStore(untrack(() => ({
...props.initState
}))), [activeTab, setActiveTab] = createSignal("general"), [changed, setChanged] = createSignal(!1), updateDraft = (key, value) => {
setChanged(!0), setDraft({
[key]: value
});
}, close = () => changed() && !window.confirm(activeTexts.settings.discardChanges) ? !1 : (props.onOpenChange(!1), !0);
return createEffect(() => {
props.open && (setDraft(untrack(() => ({
...props.initState
}))), setActiveTab("general"), setChanged(!1));
}), onMount(() => {
let onKeyDown = (event) => {
props.open && event.key === "Escape" && (close() || (event.preventDefault(), event.stopImmediatePropagation()));
};
document.addEventListener("keydown", onKeyDown), onCleanup(() => {
document.removeEventListener("keydown", onKeyDown);
});
}), createComponent(Show, {
get when() {
return props.open;
},
get children() {
return createComponent(Popover, {
outsideEvent: "pointerdown",
onOutsidePress: (event) => {
close() || (event.preventDefault(), event.stopImmediatePropagation());
},
class: "pointer-events-auto fixed safe-top-sm safe-right-sm box-border flex w-[calc(var(--ui-control-size-xl)*6)] max-w-[calc(100vw-16px)] max-h-[calc(100dvh-16px)] flex-col ui-p-md ehp-color-site-text [font-size:var(--ui-font-size-md)] leading-[1.2]",
get classList() {
return {
"!right-auto safe-left-sm": props.leftHandedControls()
};
},
get children() {
return [(() => {
var _el$12 = _tmpl$57();
return insert(_el$12, createComponent(For, {
each: SETTINGS_SECTIONS,
children: ([tab, label, icon]) => (() => {
var _el$19 = _tmpl$83();
return _el$19.$$click = () => setActiveTab(tab), setAttribute(_el$19, "aria-controls", `ehpeek-settings-panel-${tab}`), setAttribute(_el$19, "title", label), insert(_el$19, createComponent(Icon2, {
name: icon,
size: "var(--ui-icon-size-md)"
})), createRenderEffect((_p$) => {
var _v$ = `flex min-w-0 min-h-[var(--ui-control-size-md)] items-center justify-center ui-gap-sm ui-px-sm border-0 ehp-color-site-text font-inherit [font-size:var(--ui-font-size-sm)] cursor-pointer ${activeTab() === tab ? "bg-[var(--color-site-item-hover)] font-700" : "bg-transparent hover:bg-[var(--color-site-item-hover)]"}`, _v$2 = activeTab() === tab;
return _v$ !== _p$.e && className(_el$19, _p$.e = _v$), _v$2 !== _p$.t && setAttribute(_el$19, "aria-selected", _p$.t = _v$2), _p$;
}, {
e: void 0,
t: void 0
}), _el$19;
})()
})), createRenderEffect(() => setAttribute(_el$12, "aria-label", activeTexts.settings.openSettings)), _el$12;
})(), (() => {
var _el$13 = _tmpl$67(), _el$14 = _el$13.firstChild;
return insert(_el$14, () => SETTINGS_SECTIONS.find(([tab]) => tab === activeTab())?.[1]), insert(_el$13, createComponent(GeneralSettings, {
get active() {
return activeTab() === "general";
},
draft,
onUpdate: updateDraft,
get historyHref() {
return props.historyHref;
}
}), null), insert(_el$13, createComponent(EnhancementSettings, {
get active() {
return activeTab() === "enhance";
},
draft,
onUpdate: updateDraft
}), null), insert(_el$13, createComponent(ReaderOptionsSettings, {
get active() {
return activeTab() === "options";
},
draft,
onUpdate: updateDraft
}), null), insert(_el$13, createComponent(AboutSettings, {
get active() {
return activeTab() === "about";
}
}), null), _el$13;
})(), (() => {
var _el$15 = _tmpl$76(), _el$16 = _el$15.firstChild, _el$17 = _el$16.nextSibling, _el$18 = _el$17.nextSibling;
return _el$16.$$click = (event) => {
event.stopPropagation(), props.onApply({
...draft
});
}, insert(_el$16, () => activeTexts.common.actions.apply), _el$17.$$click = (event) => {
event.stopPropagation(), setChanged(!0), setDraft({
...props.defaultState
});
}, insert(_el$17, () => activeTexts.common.actions.default), _el$18.$$click = (event) => {
event.stopPropagation(), close();
}, insert(_el$18, () => activeTexts.common.actions.close), _el$15;
})()];
}
});
}
});
}
function GeneralSettings(props) {
return (() => {
var _el$20 = _tmpl$02();
return insert(_el$20, createComponent(SwitchButton, {
get checked() {
return props.draft.readerEnabled;
},
get description() {
return activeTexts.settings.readerHelp;
},
get label() {
return activeTexts.settings.readerLabel;
},
onChange: (value) => props.onUpdate("readerEnabled", value)
}), null), insert(_el$20, createComponent(SwitchButton, {
get checked() {
return props.draft.touchUiEnabled;
},
get description() {
return activeTexts.settings.touchUiHelp;
},
get label() {
return activeTexts.settings.touchUiLabel;
},
onChange: (value) => props.onUpdate("touchUiEnabled", value)
}), null), insert(_el$20, createComponent(Show, {
get when() {
return props.draft.readHistoryEnabled;
},
get children() {
var _el$21 = _tmpl$93();
return insert(_el$21, () => activeTexts.settings.historyLabel), createRenderEffect(() => setAttribute(_el$21, "href", props.historyHref)), _el$21;
}
}), null), createRenderEffect(() => _el$20.hidden = !props.active), _el$20;
})();
}
function EnhancementSettings(props) {
return (() => {
var _el$22 = _tmpl$1();
return insert(_el$22, createComponent(SwitchButton, {
get checked() {
return props.draft.enhanceSearchGridsEnabled;
},
get description() {
return activeTexts.settings.enhanceSearchHelp;
},
get label() {
return activeTexts.settings.enhanceSearchLabel;
},
onChange: (value) => props.onUpdate("enhanceSearchGridsEnabled", value)
}), null), insert(_el$22, createComponent(SwitchButton, {
get checked() {
return props.draft.enhanceThumbsGridsEnabled;
},
get description() {
return activeTexts.settings.enhanceThumbsHelp;
},
get label() {
return activeTexts.settings.enhanceThumbsLabel;
},
onChange: (value) => props.onUpdate("enhanceThumbsGridsEnabled", value)
}), null), insert(_el$22, createComponent(Show, {
get when() {
return props.draft.touchUiEnabled;
},
get children() {
return createComponent(SwitchButton, {
get checked() {
return props.draft.fitToViewport;
},
get description() {
return activeTexts.settings.fitToViewportHelp;
},
get label() {
return activeTexts.settings.fitToViewportLabel;
},
onChange: (value) => props.onUpdate("fitToViewport", value)
});
}
}), null), insert(_el$22, createComponent(SwitchButton, {
get checked() {
return props.draft.replacePreviewWithScroll;
},
get description() {
return activeTexts.settings.replacePreviewWithScrollHelp;
},
get label() {
return activeTexts.settings.replacePreviewWithScrollLabel;
},
onChange: (value) => props.onUpdate("replacePreviewWithScroll", value)
}), null), insert(_el$22, createComponent(SwitchButton, {
get checked() {
return props.draft.myTagsEnabled;
},
get description() {
return activeTexts.settings.myTagsHelp;
},
get label() {
return activeTexts.settings.myTagsLabel;
},
onChange: (value) => props.onUpdate("myTagsEnabled", value)
}), null), insert(_el$22, createComponent(SwitchButton, {
get checked() {
return props.draft.readHistoryEnabled;
},
get description() {
return activeTexts.settings.readHistoryHelp;
},
get label() {
return activeTexts.settings.readHistoryLabel;
},
onChange: (value) => props.onUpdate("readHistoryEnabled", value)
}), null), insert(_el$22, createComponent(SwitchButton, {
get checked() {
return props.draft.searchHistoryEnabled;
},
get description() {
return activeTexts.settings.searchHistoryHelp;
},
get label() {
return activeTexts.settings.searchHistoryLabel;
},
onChange: (value) => props.onUpdate("searchHistoryEnabled", value)
}), null), createRenderEffect(() => _el$22.hidden = !props.active), _el$22;
})();
}
function ReaderOptionsSettings(props) {
let [moreOptionsOpen, setMoreOptionsOpen] = createSignal(!1);
return (() => {
var _el$23 = _tmpl$102(), _el$24 = _el$23.firstChild, _el$25 = _el$24.firstChild, _el$26 = _el$25.nextSibling;
return insert(_el$23, createComponent(Show, {
get when() {
return !moreOptionsOpen();
},
get children() {
return [createComponent(SwitchButton, {
get checked() {
return props.draft.readerFullscreenEnabled;
},
get description() {
return activeTexts.settings.readerFullscreenHelp;
},
get label() {
return activeTexts.settings.readerFullscreenLabel;
},
onChange: (value) => props.onUpdate("readerFullscreenEnabled", value)
}), createComponent(SwitchButton, {
get checked() {
return props.draft.exitReaderOnFullscreenExit;
},
get description() {
return activeTexts.settings.exitReaderOnFullscreenExitHelp;
},
get label() {
return activeTexts.settings.exitReaderOnFullscreenExitLabel;
},
onChange: (value) => props.onUpdate("exitReaderOnFullscreenExit", value)
}), createComponent(SwitchButton, {
get checked() {
return props.draft.openGalleryInNewTab;
},
get description() {
return activeTexts.settings.openGalleryInNewTabHelp;
},
get label() {
return activeTexts.settings.openGalleryInNewTabLabel;
},
onChange: (value) => props.onUpdate("openGalleryInNewTab", value)
}), createComponent(SwitchButton, {
get checked() {
return props.draft.includeUnreadHistoryEnabled;
},
get description() {
return activeTexts.settings.includeUnreadHistoryHelp;
},
get label() {
return activeTexts.settings.includeUnreadHistoryLabel;
},
onChange: (value) => props.onUpdate("includeUnreadHistoryEnabled", value)
}), createComponent(SelectSetting, {
get label() {
return activeTexts.settings.twoColumnsReaderModeLabel;
},
options: TWO_COLUMNS_READER_MODE_OPTIONS,
get value() {
return props.draft.twoColumnsReaderMode;
},
onChange: (value) => {
props.onUpdate("twoColumnsReaderMode", value);
}
}), createComponent(SelectSetting, {
label: "Language",
noTranslate: !0,
options: APP_LOCALE_OPTIONS,
get value() {
return props.draft.locale;
},
onChange: (value) => {
props.onUpdate("locale", value);
}
})];
}
}), _el$24), _el$24.$$click = () => setMoreOptionsOpen((open) => !open), insert(_el$25, () => activeTexts.settings.more), insert(_el$26, createComponent(Icon2, {
name: "chevron-right",
size: "var(--ui-icon-size-sm)"
})), insert(_el$23, createComponent(Show, {
get when() {
return moreOptionsOpen();
},
get children() {
return [createComponent(SelectSetting, {
get label() {
return activeTexts.settings.portraitUiScaleLabel;
},
options: UI_SCALE_OPTIONS,
get value() {
return props.draft.portraitUiScale;
},
onChange: (value) => {
props.onUpdate("portraitUiScale", value);
}
}), createComponent(SelectSetting, {
get label() {
return activeTexts.settings.landscapeUiScaleLabel;
},
options: UI_SCALE_OPTIONS,
get value() {
return props.draft.landscapeUiScale;
},
onChange: (value) => {
props.onUpdate("landscapeUiScale", value);
}
}), createComponent(SwitchButton, {
get checked() {
return props.draft.includeReaderPageInUrl;
},
get description() {
return activeTexts.settings.includeReaderPageInUrlHelp;
},
get label() {
return activeTexts.settings.includeReaderPageInUrlLabel;
},
onChange: (value) => props.onUpdate("includeReaderPageInUrl", value)
})];
}
}), null), createRenderEffect((_p$) => {
var _v$3 = !props.active, _v$4 = moreOptionsOpen(), _v$5 = !!moreOptionsOpen();
return _v$3 !== _p$.e && (_el$23.hidden = _p$.e = _v$3), _v$4 !== _p$.t && setAttribute(_el$24, "aria-expanded", _p$.t = _v$4), _v$5 !== _p$.a && _el$26.classList.toggle("rotate-90", _p$.a = _v$5), _p$;
}, {
e: void 0,
t: void 0,
a: void 0
}), _el$23;
})();
}
function AboutSettings(props) {
let [helpOpen, setHelpOpen] = createSignal(!1), [licensesOpen, setLicensesOpen] = createSignal(!1);
return [(() => {
var _el$27 = _tmpl$112(), _el$28 = _el$27.firstChild, _el$29 = _el$28.nextSibling, _el$30 = _el$29.firstChild, _el$31 = _el$29.nextSibling, _el$32 = _el$31.firstChild, _el$33 = _el$31.nextSibling, _el$34 = _el$33.firstChild, _el$35 = _el$34.nextSibling;
return insert(_el$28, "EhPeek"), insert(_el$29, "260912.1746", null), _el$31.$$click = () => setHelpOpen(!0), insert(_el$32, () => activeTexts.help.title), _el$33.$$click = () => setLicensesOpen(!0), insert(_el$34, () => activeTexts.settings.licenses), insert(_el$35, createComponent(Icon2, {
name: "chevron-right",
size: "var(--ui-icon-size-sm)"
})), createRenderEffect(() => _el$27.hidden = !props.active), _el$27;
})(), createComponent(Show, {
get when() {
return helpOpen();
},
get children() {
return createComponent(InteractionHelp, {
variant: "site",
onClose: () => setHelpOpen(!1)
});
}
}), createComponent(Show, {
get when() {
return licensesOpen();
},
get children() {
return createComponent(Dialog, {
get label() {
return activeTexts.settings.licenses;
},
onClose: () => setLicensesOpen(!1),
get title() {
return activeTexts.settings.licenses;
},
variant: "site",
width: "lg",
get children() {
return createComponent(For, {
each: LICENSES,
children: (license) => (() => {
var _el$36 = _tmpl$122(), _el$37 = _el$36.firstChild, _el$38 = _el$37.nextSibling;
return insert(_el$37, () => license.name), insert(_el$38, () => license.license, null), insert(_el$38, createComponent(Icon2, {
name: "external-link",
size: "var(--ui-icon-size-sm)"
}), null), createRenderEffect(() => setAttribute(_el$36, "href", license.href)), _el$36;
})()
});
}
});
}
})];
}
var _tmpl$49, _tmpl$218, _tmpl$312, _tmpl$410, _tmpl$57, _tmpl$67, _tmpl$76, _tmpl$83, _tmpl$93, _tmpl$02, _tmpl$1, _tmpl$102, _tmpl$112, _tmpl$122, SETTINGS_SECTIONS, SETTINGS_DOT_CLASS, UI_SCALE_OPTIONS, TWO_COLUMNS_READER_MODE_OPTIONS, LICENSES, init_SettingsMenu = __esm({
"src/components/SettingsMenu.tsx"() {
"use strict";
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_solid();
init_store();
init_i18n2();
init_ui2();
init_Widgets();
_tmpl$49 = /* @__PURE__ */ template('<p class="box-border w-full m-0 ui-px-md ui-pb-md text-left whitespace-normal [overflow-wrap:anywhere] [contain:inline-size] [font-size:var(--ui-font-size-sm)] leading-[1.35] opacity-75">'), _tmpl$218 = /* @__PURE__ */ template('<div class="border-0 border-b ehp-color-site-border-subtle-b"><div class="flex items-stretch"><button type=button class="flex min-w-0 flex-1 min-h-[var(--ui-control-size-lg)] items-center justify-between ui-gap-md ui-py-sm ui-pl-md ui-pr-sm ui-rounded-xs border-0 !bg-transparent hover:!bg-[var(--color-site-item-hover)] active:!bg-[var(--color-site-item-hover)] ehp-color-site-text font-inherit text-left [font-size:var(--ui-font-size-md)] cursor-pointer [-webkit-tap-highlight-color:transparent]"><span></span><span class="flex flex-none items-center ui-gap-sm"><span class="[font-size:var(--ui-font-size-sm)] opacity-70"></span><span></span></span></button><button type=button class="flex flex-none w-[var(--ui-control-size-sm)] min-h-[var(--ui-control-size-lg)] items-center justify-center p-0 ui-rounded-xs border-0 !bg-transparent hover:!bg-[var(--color-site-item-hover)] active:!bg-[var(--color-site-item-hover)] ehp-color-site-text cursor-pointer font-inherit [font-size:var(--ui-font-size-md)] font-700 [-webkit-tap-highlight-color:transparent]"><span class="flex w-[var(--ui-icon-size-md)] h-[var(--ui-icon-size-md)] items-center justify-center rounded-full border border-[var(--color-site-border-subtle)] leading-none">?'), _tmpl$312 = /* @__PURE__ */ template('<label class="flex box-border w-full min-h-[var(--ui-control-size-lg)] items-center justify-between ui-gap-md ui-px-md border-0 border-b ehp-color-site-border-subtle-b ehp-color-site-text text-left [font-size:var(--ui-font-size-md)] cursor-pointer"><span></span><select class="box-border min-h-[var(--ui-control-size-sm)] min-w-[calc(var(--ui-control-size-xl)*2)] ui-px-sm ui-rounded-xs border ehp-color-site-border bg-[var(--color-site-surface)] ehp-color-site-text font-inherit [font-size:var(--ui-font-size-sm)] cursor-pointer">'), _tmpl$410 = /* @__PURE__ */ template("<option>"), _tmpl$57 = /* @__PURE__ */ template('<div class="grid grid-cols-4 flex-none ui-gap-xs ui-mb-sm ui-rounded-md border ehp-color-site-border overflow-hidden"role=tablist>'), _tmpl$67 = /* @__PURE__ */ template('<div class="min-h-0 overflow-x-hidden overflow-y-auto overscroll-contain"><h2 class="m-0 ui-px-md ui-py-sm border-0 border-b ehp-color-site-border-subtle-b [font-size:var(--ui-font-size-md)] font-700">'), _tmpl$76 = /* @__PURE__ */ template('<div class="grid grid-cols-3 flex-none ui-gap-sm ui-mt-md ui-pt-md border-0 border-t border-t-[var(--color-site-border-subtle)]"><button type=button class="block w-full min-h-[var(--ui-control-size-md)] ui-py-xs ui-px-md ui-rounded-md border cursor-pointer font-inherit text-center [font-size:var(--ui-font-size-md)] font-700 leading-[1.1] transition-[filter,transform,box-shadow] duration-120 active:scale-98 border-[var(--color-site-accent)] bg-[var(--color-site-accent)] text-[var(--color-site-surface)] shadow-[0_2px_8px_var(--color-shadow-panel)] hover:brightness-108"></button><button type=button class="block w-full min-h-[var(--ui-control-size-md)] ui-py-xs ui-px-md ui-rounded-md border cursor-pointer font-inherit text-center [font-size:var(--ui-font-size-md)] font-700 leading-[1.1] transition-[filter,transform,box-shadow] duration-120 active:scale-98 border-[var(--color-site-border-subtle)] bg-[var(--color-site-surface)] text-[var(--color-site-text)] hover:bg-[var(--color-site-item-hover)]"></button><button type=button class="block w-full min-h-[var(--ui-control-size-md)] ui-py-xs ui-px-md ui-rounded-md border cursor-pointer font-inherit text-center [font-size:var(--ui-font-size-md)] font-700 leading-[1.1] transition-[filter,transform,box-shadow] duration-120 active:scale-98 border-[var(--color-site-border-subtle)] bg-[var(--color-site-surface)] text-[var(--color-site-text)] hover:bg-[var(--color-site-item-hover)]">'), _tmpl$83 = /* @__PURE__ */ template("<button type=button role=tab>"), _tmpl$93 = /* @__PURE__ */ template('<a class="flex w-full min-h-[var(--ui-control-size-lg)] items-center ui-gap-md ui-px-md border-0 border-b ehp-color-site-border-subtle-b !bg-transparent hover:!bg-[var(--color-site-item-hover)] ehp-color-site-text no-underline text-left [font-size:var(--ui-font-size-md)] cursor-pointer">'), _tmpl$02 = /* @__PURE__ */ template("<div id=ehpeek-settings-panel-general data-ehpeek-settings-tab=general role=tabpanel>"), _tmpl$1 = /* @__PURE__ */ template("<div id=ehpeek-settings-panel-enhance data-ehpeek-settings-tab=enhance role=tabpanel>"), _tmpl$102 = /* @__PURE__ */ template('<div id=ehpeek-settings-panel-options data-ehpeek-settings-tab=options role=tabpanel><button type=button class="flex w-full min-h-[var(--ui-control-size-lg)] items-center justify-between ui-gap-md ui-px-md border-0 border-b ehp-color-site-border-subtle-b !bg-transparent hover:!bg-[var(--color-site-item-hover)] ehp-color-site-text font-inherit text-left [font-size:var(--ui-font-size-md)] cursor-pointer"><span></span><span class="flex flex-none transition-transform duration-120"aria-hidden=true>'), _tmpl$112 = /* @__PURE__ */ template('<div id=ehpeek-settings-panel-about data-ehpeek-settings-tab=about role=tabpanel><div class="flex w-full min-h-[var(--ui-control-size-lg)] items-center ui-px-md border-0 border-b ehp-color-site-border-subtle-b ehp-color-site-text [font-size:var(--ui-font-size-md)] font-700"></div><a class="flex w-full min-h-[var(--ui-control-size-lg)] items-center overflow-hidden text-ellipsis whitespace-nowrap ui-px-md border-0 border-b ehp-color-site-border-subtle-b ehp-color-site-text no-underline [font-size:var(--ui-font-size-md)] font-700 hover:bg-[var(--color-site-item-hover)]"href=https://github.com/yamipot/ehpeek target=_blank rel="noopener noreferrer">v</a><button type=button class="flex w-full min-h-[var(--ui-control-size-lg)] items-center ui-gap-md ui-px-md border-0 border-b ehp-color-site-border-subtle-b !bg-transparent hover:!bg-[var(--color-site-item-hover)] ehp-color-site-text font-inherit text-left [font-size:var(--ui-font-size-md)] cursor-pointer"><span></span></button><button type=button class="flex w-full min-h-[var(--ui-control-size-lg)] items-center justify-between ui-gap-md ui-px-md border-0 border-b ehp-color-site-border-subtle-b !bg-transparent hover:!bg-[var(--color-site-item-hover)] ehp-color-site-text font-inherit text-left [font-size:var(--ui-font-size-md)] cursor-pointer"><span></span><span class="flex flex-none"aria-hidden=true>'), _tmpl$122 = /* @__PURE__ */ template('<a class="flex min-h-[var(--ui-control-size-lg)] items-center justify-between ui-gap-md ui-px-md ui-py-sm border-0 border-b last:border-b-0 ehp-color-site-border-subtle-b !bg-transparent hover:!bg-[var(--color-site-item-hover)] ehp-color-site-text no-underline text-left"target=_blank rel="noopener noreferrer"><span class="min-w-0 [font-size:var(--ui-font-size-md)] font-700"></span><span class="flex flex-none items-center ui-gap-sm [font-size:var(--ui-font-size-sm)]">'), SETTINGS_SECTIONS = [["general", activeTexts.settings.general, "book-open"], ["enhance", activeTexts.settings.enhance, "sparkles"], ["options", activeTexts.settings.options, "settings"], ["about", activeTexts.settings.about, "info"]], SETTINGS_DOT_CLASS = "block flex-none ui-w-md ui-h-md rounded-full", UI_SCALE_OPTIONS = UI_SCALE_NAMES.map((value) => ({
label: String(uiScaleLevel(value)),
value
})), TWO_COLUMNS_READER_MODE_OPTIONS = [{
label: activeTexts.settings.readerModeFullView,
value: "full-view"
}, {
label: activeTexts.settings.readerModeOnPreview,
value: "on-preview"
}, {
label: activeTexts.settings.readerModeReaderPreview,
value: "reader-preview"
}], LICENSES = [{
href: "https://github.com/yamipot/ehpeek/blob/master/LICENSE",
license: "MIT",
name: "EhPeek"
}, {
href: "https://github.com/solidjs/solid/blob/main/LICENSE",
license: "MIT",
name: "SolidJS"
}, {
href: "https://github.com/lucide-icons/lucide/blob/main/LICENSE",
license: "ISC",
name: "Lucide Icons"
}, {
href: "https://github.com/adobe/spectrum-design-data/blob/main/LICENSE",
license: "Apache-2.0",
name: "Adobe Spectrum Tokens"
}];
delegateEvents(["click"]);
}
});
// src/components/Widgets/GalleryColumnsResizeHandle.tsx
function GalleryColumnsResizeHandle(props) {
let handle, root, draggingPointerId = null, normalizedRatio = (ratio) => clamp(ratio, GALLERY_COLUMNS_RATIO_MIN, GALLERY_COLUMNS_RATIO_MAX), ratioAt = (clientX) => {
let bounds = root.parentElement?.getBoundingClientRect();
return bounds ? normalizedRatio((clientX - bounds.left) / Math.max(1, bounds.width)) : props.ratio;
}, inputAt = (clientX) => {
let ratio = ratioAt(clientX);
return props.onInput(ratio), ratio;
}, applyAndCommit = (ratio) => {
let normalized = normalizedRatio(ratio);
props.onInput(normalized), props.onCommit(normalized);
}, onPointerEnd = (event) => {
if (draggingPointerId !== event.pointerId)
return;
let ratio = inputAt(event.clientX);
draggingPointerId = null, handle.hasPointerCapture(event.pointerId) && handle.releasePointerCapture(event.pointerId), props.onCommit(ratio);
}, onPointerCancel = (event) => {
draggingPointerId === event.pointerId && (draggingPointerId = null, handle.hasPointerCapture(event.pointerId) && handle.releasePointerCapture(event.pointerId), props.onCommit(props.ratio));
};
return createComponent(Show, {
get when() {
return props.visible;
},
get children() {
var _el$ = _tmpl$50(), _el$2 = _el$.firstChild, _el$3 = _el$2.nextSibling, _el$4 = _el$3.firstChild, _el$5 = _el$4.nextSibling, _ref$ = root;
typeof _ref$ == "function" ? use(_ref$, _el$) : root = _el$, _el$2.$$pointerup = onPointerEnd, _el$2.$$pointermove = (event) => {
draggingPointerId === event.pointerId && inputAt(event.clientX);
}, _el$2.$$pointerdown = (event) => {
event.preventDefault(), event.stopPropagation(), draggingPointerId = event.pointerId, handle.setPointerCapture(event.pointerId), inputAt(event.clientX);
}, _el$2.addEventListener("pointercancel", onPointerCancel), _el$2.$$keydown = (event) => {
let ratio = null;
event.key === "ArrowLeft" ? ratio = props.ratio - KEYBOARD_STEP : event.key === "ArrowRight" ? ratio = props.ratio + KEYBOARD_STEP : event.key === "Home" ? ratio = GALLERY_COLUMNS_RATIO_MIN : event.key === "End" && (ratio = GALLERY_COLUMNS_RATIO_MAX), ratio !== null && (event.preventDefault(), event.stopPropagation(), applyAndCommit(ratio));
};
var _ref$2 = handle;
return typeof _ref$2 == "function" ? use(_ref$2, _el$2) : handle = _el$2, _el$4.$$click = () => props.onReset(), insert(_el$4, createComponent(Icon2, {
name: "refresh",
size: "var(--ui-icon-size-sm)"
})), _el$5.$$click = () => props.onClose(), insert(_el$5, createComponent(Icon2, {
name: "close",
size: "var(--ui-icon-size-sm)"
})), createRenderEffect((_p$) => {
var _v$ = `${props.ratio * 100}%`, _v$2 = activeTexts.gallery.resizeColumns, _v$3 = Math.round(GALLERY_COLUMNS_RATIO_MAX * 100), _v$4 = Math.round(GALLERY_COLUMNS_RATIO_MIN * 100), _v$5 = Math.round(props.ratio * 100), _v$6 = activeTexts.gallery.resizeColumns, _v$7 = activeTexts.gallery.resetColumns, _v$8 = props.resetDisabled, _v$9 = activeTexts.gallery.resetColumns, _v$0 = activeTexts.common.actions.close, _v$1 = activeTexts.common.actions.close;
return _v$ !== _p$.e && setStyleProperty(_el$, "left", _p$.e = _v$), _v$2 !== _p$.t && setAttribute(_el$2, "aria-label", _p$.t = _v$2), _v$3 !== _p$.a && setAttribute(_el$2, "aria-valuemax", _p$.a = _v$3), _v$4 !== _p$.o && setAttribute(_el$2, "aria-valuemin", _p$.o = _v$4), _v$5 !== _p$.i && setAttribute(_el$2, "aria-valuenow", _p$.i = _v$5), _v$6 !== _p$.n && setAttribute(_el$2, "title", _p$.n = _v$6), _v$7 !== _p$.s && setAttribute(_el$4, "aria-label", _p$.s = _v$7), _v$8 !== _p$.h && (_el$4.disabled = _p$.h = _v$8), _v$9 !== _p$.r && setAttribute(_el$4, "title", _p$.r = _v$9), _v$0 !== _p$.d && setAttribute(_el$5, "aria-label", _p$.d = _v$0), _v$1 !== _p$.l && setAttribute(_el$5, "title", _p$.l = _v$1), _p$;
}, {
e: void 0,
t: void 0,
a: void 0,
o: void 0,
i: void 0,
n: void 0,
s: void 0,
h: void 0,
r: void 0,
d: void 0,
l: void 0
}), _el$;
}
});
}
var _tmpl$50, KEYBOARD_STEP, init_GalleryColumnsResizeHandle = __esm({
"src/components/Widgets/GalleryColumnsResizeHandle.tsx"() {
"use strict";
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_solid();
init_i18n2();
init_state();
init_helpers();
init_Widgets();
_tmpl$50 = /* @__PURE__ */ template('<div class="pointer-events-none absolute inset-y-0 z-ui flex -translate-x-1/2 flex-col items-center justify-center ui-gap-xs"><button type=button class="pointer-events-auto flex h-[calc(var(--ui-control-size-xs)*8)] max-h-[70%] w-16px flex-none touch-none select-none items-center justify-center p-0 border-0 !bg-transparent ehp-color-site-accent cursor-ew-resize"aria-orientation=horizontal role=slider><span class="flex h-full w-full items-center justify-between"><span class="block h-full w-2px rounded-full bg-current opacity-70 shadow-[0_1px_4px_var(--color-shadow-control)]"></span><span class="block h-full w-2px rounded-full bg-current opacity-70 shadow-[0_1px_4px_var(--color-shadow-control)]"></span><span class="block h-full w-2px rounded-full bg-current opacity-70 shadow-[0_1px_4px_var(--color-shadow-control)]"></span></span></button><div class="flex flex-col items-center ui-gap-xs"><button type=button class="pointer-events-auto inline-flex ui-hit-square-xs items-center justify-center p-0 ui-rounded-sm border-0 bg-[var(--color-site-elevated)] ehp-color-site-accent shadow-[0_1px_4px_var(--color-shadow-control)] cursor-pointer disabled:opacity-40 disabled:cursor-default enabled:active:scale-96"></button><button type=button class="pointer-events-auto inline-flex ui-hit-square-xs items-center justify-center p-0 ui-rounded-sm border-0 bg-[var(--color-site-elevated)] ehp-color-site-accent shadow-[0_1px_4px_var(--color-shadow-control)] cursor-pointer disabled:opacity-40 disabled:cursor-default enabled:active:scale-96">'), KEYBOARD_STEP = 0.05;
delegateEvents(["keydown", "pointerdown", "pointermove", "pointerup", "click"]);
}
});
// src/components/Widgets/BackToTop.tsx
function BackToTop(props) {
return createComponent(MovableBackToTop, {
get leftHanded() {
return props.leftHanded;
},
get positionState() {
return state.widgets.backToTopPosition;
}
});
}
function GalleryColumnsBackToTop(props) {
return createComponent(MovableBackToTop, {
get leftHanded() {
return props.leftHanded;
},
get positionState() {
return state.widgets.galleryColumnsBackToTopPosition;
},
get scope() {
return props.scope;
}
});
}
function MovableBackToTop(props) {
let button2, drag = null, dragged = !1, scopedBounds = null, [visible, setVisible] = createSignal(!1), [position, setPosition] = createSignal(null), [boundsVersion, setBoundsVersion] = createSignal(0), bounds = () => props.scope ? scopedBounds : {
bottom: window.innerHeight,
height: window.innerHeight,
left: 0,
right: window.innerWidth,
width: window.innerWidth
}, positionStyle = () => {
boundsVersion();
let currentBounds = bounds();
if (!currentBounds)
return {
display: "none"
};
let current = position();
if (!props.scope)
return current ? {
bottom: `${current.bottom}px`,
right: `${current.right}px`
} : void 0;
let viewportBottom = window.innerHeight - currentBounds.bottom;
if (current) {
let clamped = button2 ? clampPosition(current, button2, currentBounds) : current;
return {
bottom: `${viewportBottom + clamped.bottom}px`,
right: `${window.innerWidth - currentBounds.right + clamped.right}px`
};
}
return props.leftHanded() ? {
bottom: `calc(${viewportBottom}px + var(--ui-space-lg))`,
left: `calc(${currentBounds.left}px + var(--ui-space-lg))`,
right: "auto"
} : {
bottom: `calc(${viewportBottom}px + var(--ui-space-lg))`,
right: `calc(${window.innerWidth - currentBounds.right}px + var(--ui-space-lg))`
};
};
return onMount(() => {
setPosition(props.positionState.value);
let updateVisibility = () => {
let currentBounds = bounds();
setVisible(currentBounds !== null && (props.scope?.scrollTop() ?? window.scrollY) > Math.max(320, currentBounds.height * 0.5));
}, updateBounds = () => {
scopedBounds = props.scope?.bounds() ?? null, setBoundsVersion((version) => version + 1), updateVisibility();
};
if (props.scope ? updateBounds() : updateVisibility(), props.scope) {
let stopListening = props.scope.listen({
onBoundsChange: updateBounds,
onScroll: updateVisibility
});
onCleanup(stopListening);
} else
window.addEventListener("scroll", updateVisibility, {
passive: !0
}), onCleanup(() => window.removeEventListener("scroll", updateVisibility));
}), createComponent(Show, {
get when() {
return visible();
},
get children() {
var _el$ = _tmpl$51();
_el$.$$click = (event) => {
if (dragged) {
event.preventDefault(), dragged = !1;
return;
}
props.scope ? props.scope.scrollToTop() : window.scrollTo({
top: 0,
behavior: "smooth"
});
}, _el$.$$pointerup = (event) => {
if (!drag || drag.pointerId !== event.pointerId)
return;
button2.releasePointerCapture(event.pointerId), drag = null;
let current = position();
dragged && current && props.positionState.set(current);
}, _el$.$$pointermove = (event) => {
if (!drag || drag.pointerId !== event.pointerId)
return;
let dx = event.clientX - drag.x, dy = event.clientY - drag.y;
dragged || (dragged = Math.hypot(dx, dy) > 4);
let currentBounds = bounds();
currentBounds && setPosition(clampPosition({
bottom: drag.bottom - dy,
right: drag.right - dx
}, button2, currentBounds));
}, _el$.$$pointerdown = (event) => {
let currentBounds = bounds();
if (!currentBounds)
return;
let buttonRect = button2.getBoundingClientRect();
dragged = !1, drag = {
bottom: currentBounds.bottom - buttonRect.bottom,
pointerId: event.pointerId,
right: currentBounds.right - buttonRect.right,
x: event.clientX,
y: event.clientY
}, button2.setPointerCapture(event.pointerId);
};
var _ref$ = button2;
return typeof _ref$ == "function" ? use(_ref$, _el$) : button2 = _el$, insert(_el$, createComponent(Icon2, {
name: "arrow-up",
size: "var(--ui-icon-size-lg)"
})), createRenderEffect((_p$) => {
var _v$ = {
"safe-right-lg bottom-[calc(max(16px,env(safe-area-inset-bottom,0px))_+_var(--ui-hit-size-lg)_+_var(--ui-space-md))]": !props.scope,
"!right-auto safe-left-lg": !props.scope && props.leftHanded() && position() === null
}, _v$2 = positionStyle();
return _p$.e = classList(_el$, _v$, _p$.e), _p$.t = style(_el$, _v$2, _p$.t), _p$;
}, {
e: void 0,
t: void 0
}), _el$;
}
});
}
function clampPosition(position, button2, bounds) {
return {
bottom: Math.min(Math.max(0, position.bottom), Math.max(0, bounds.height - button2.offsetHeight)),
right: Math.min(Math.max(0, position.right), Math.max(0, bounds.width - button2.offsetWidth))
};
}
var _tmpl$51, init_BackToTop = __esm({
"src/components/Widgets/BackToTop.tsx"() {
"use strict";
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_solid();
init_state();
init_Widgets();
_tmpl$51 = /* @__PURE__ */ template('<button type=button class="fixed z-[800] inline-flex ui-hit-square-lg items-center justify-center rounded-full border-0 bg-[var(--color-site-elevated)] ehp-color-site-accent shadow-[0_4px_14px_var(--color-shadow-floating)] cursor-pointer [touch-action:none] active:scale-96">');
delegateEvents(["pointerdown", "pointermove", "pointerup", "click"]);
}
});
// src/components/Widgets/ExternalDom.tsx
function DomNode2(props) {
let Component = createMemo(() => props.node?.Component);
return createComponent(Show, {
get when() {
return Component();
},
children: (Current) => createComponent(Dynamic, {
get component() {
return Current();
}
})
});
}
function DomNodes(props) {
return createComponent(For, {
get each() {
return props.nodes;
},
children: (node) => {
let Component = node.Component;
return createComponent(Component, {});
}
});
}
var init_ExternalDom = __esm({
"src/components/Widgets/ExternalDom.tsx"() {
"use strict";
init_web();
init_solid();
init_web();
}
});
// src/components/TouchUI/GalleryInfoPanel.tsx
function exactTagQuery(name) {
let separator = name.indexOf(":");
if (separator < 0)
return `tag:${name}$`;
let namespace = name.slice(0, separator).toLowerCase();
return `${TAG_NAMESPACE_PREFIXES[namespace] ?? namespace}:${name.slice(separator + 1)}$`;
}
function GalleryInfoPanel(props) {
let source = untrack(() => props.source), hasCover = source.elems.cover !== null, initialTagGroups = source.data.tagGroups.map((group) => ({
...group,
tags: group.tags.flatMap(({
contentSourceIndex,
...tag2
}) => {
let contentSource = source.elems.tagContents[contentSourceIndex];
return contentSource ? [{
...tag2,
contentSource
}] : [];
})
})), [tagGroups, setTagGroups] = createSignal(initialTagGroups), [selectedTag, setSelectedTag] = createSignal(null), [tagging, setTagging] = createSignal(!1), hasNewTag = () => source.elems.newTag !== null;
onMount(() => {
let stopObservingTags = source.handle.observeGalleryTagGroups(setTagGroups);
onCleanup(stopObservingTags);
});
let openTagMenu = (tag2) => {
try {
source.handle.openGalleryTagMenu(tag2), setSelectedTag(tag2);
} catch (error) {
console.error("[ehpeek] Gallery tag actions failed", error), window.alert(error instanceof Error ? error.message : activeTexts.errors.loadFailed);
}
}, closeTagMenu = () => {
selectedTag() && (source.handle.closeGalleryTagMenu(), setSelectedTag(null));
}, updateTag = (updatedTag) => {
setTagGroups((groups) => groups.map((group) => ({
...group,
tags: group.tags.map((tag2) => tag2.url === updatedTag.url ? updatedTag : tag2)
}))), setSelectedTag((tag2) => tag2?.url === updatedTag.url ? updatedTag : tag2);
};
return (() => {
var _el$ = _tmpl$219(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.firstChild, _el$5 = _el$4.firstChild, _el$6 = _el$5.firstChild, _el$7 = _el$6.nextSibling, _el$8 = _el$5.nextSibling, _el$9 = _el$8.firstChild, _el$0 = _el$4.nextSibling, _el$1 = _el$0.firstChild, _el$10 = _el$1.nextSibling, _el$11 = _el$2.nextSibling, _el$12 = _el$11.firstChild;
return className(_el$3, `ehpeek-touch-gallery-summary grid ui-gap-sm items-stretch ${hasCover ? "ehpeek-touch-gallery-summary-has-cover" : "grid-cols-1"}`), insert(_el$3, hasCover && (() => {
var _el$14 = _tmpl$313();
return insert(_el$14, createComponent(DomNode2, {
get node() {
return source.elems.cover;
}
})), _el$14;
})(), _el$4), insert(_el$6, () => source.data.titleMain), insert(_el$7, () => source.data.titleSub), insert(_el$9, () => source.data.category), insert(_el$8, (() => {
var _c$ = memo(() => !!source.data.uploader);
return () => _c$() && (() => {
var _el$15 = _tmpl$411();
return insert(_el$15, () => source.data.uploader), createRenderEffect(() => setAttribute(_el$15, "href", source.data.uploaderUrl)), _el$15;
})();
})(), null), insert(_el$4, createComponent(GalleryRating, {
source
}), null), _el$0.addEventListener("dragstart", (event) => event.preventDefault()), insert(_el$1, createComponent(TouchGalleryFavoriteButton, {
source
})), insert(_el$10, () => props.primaryAction), insert(_el$12, createComponent(For, {
get each() {
return source.data.summary;
},
children: (item) => (() => {
var _el$16 = _tmpl$59();
return insert(_el$16, () => item.value), _el$16;
})()
}), null), insert(_el$12, createComponent(TouchGalleryActionsMenu, {
get items() {
return source.elems.actionItems;
}
}), null), insert(_el$11, (() => {
var _c$2 = memo(() => !!(tagGroups().length > 0 || hasNewTag()));
return () => _c$2() && (() => {
var _el$17 = _tmpl$77(), _el$18 = _el$17.firstChild, _el$19 = _el$18.firstChild, _el$20 = _el$19.nextSibling;
return _el$17.addEventListener("dragstart", (event) => event.preventDefault()), _el$18.$$click = () => {
setTagging((enabled) => !enabled);
}, insert(_el$19, () => activeTexts.gallery.tagging), insert(_el$17, createComponent(Show, {
get when() {
return tagGroups().length > 0;
},
get children() {
var _el$21 = _tmpl$68();
return insert(_el$21, createComponent(For, {
get each() {
return tagGroups();
},
children: (group) => createComponent(TouchGalleryTagGroup, {
group,
get tagging() {
return tagging();
},
onTagOpen: openTagMenu
})
})), _el$21;
}
}), null), createRenderEffect((_p$) => {
var _v$6 = `inline-flex self-end ui-hit-min-h-xs items-center justify-center ui-gap-sm ui-mb-xs ui-rounded-xl border-0 ui-px-md font-inherit font-700 textsize-sm cursor-pointer transition-[background-color,color] duration-120 ${tagging() ? "bg-[var(--color-site-accent-hover)] ehp-color-site-accent" : "bg-[var(--color-site-surface)] ehp-color-site-text"}`, _v$7 = tagging(), _v$8 = `block flex-none ui-w-md ui-h-md rounded-full ${tagging() ? "bg-[var(--color-state-on)]" : "bg-[var(--color-state-off)]"}`;
return _v$6 !== _p$.e && className(_el$18, _p$.e = _v$6), _v$7 !== _p$.t && setAttribute(_el$18, "aria-pressed", _p$.t = _v$7), _v$8 !== _p$.a && className(_el$20, _p$.a = _v$8), _p$;
}, {
e: void 0,
t: void 0,
a: void 0
}), _el$17;
})();
})(), null), insert(_el$11, createComponent(Show, {
get when() {
return hasNewTag();
},
get children() {
var _el$13 = _tmpl$58();
return insert(_el$13, createComponent(TouchGalleryNewTag, {
source
})), createRenderEffect(() => className(_el$13, tagging() ? "block" : "hidden")), _el$13;
}
}), null), insert(_el$, createComponent(Show, {
get when() {
return props.columnsEnabled();
},
get children() {
return createComponent(GalleryColumnsBackToTop, {
get leftHanded() {
return props.leftHandedControls;
},
get scope() {
return props.columnScope;
}
});
}
}), null), insert(_el$, createComponent(TouchGalleryTagMenu, {
source,
get tag() {
return selectedTag();
},
onClose: closeTagMenu,
onTagUpdated: updateTag
}), null), createRenderEffect((_p$) => {
var _v$ = source.data.categoryUrl ?? void 0, _v$2 = source.data.categoryAppearance, _v$3 = {
"[direction:rtl]": props.leftHandedControls()
}, _v$4 = !!props.leftHandedControls(), _v$5 = !props.leftHandedControls();
return _v$ !== _p$.e && setAttribute(_el$9, "href", _p$.e = _v$), _p$.t = style(_el$9, _v$2, _p$.t), _p$.a = classList(_el$0, _v$3, _p$.a), _v$4 !== _p$.o && _el$10.classList.toggle("border-r-6", _p$.o = _v$4), _v$5 !== _p$.i && _el$10.classList.toggle("border-l-6", _p$.i = _v$5), _p$;
}, {
e: void 0,
t: void 0,
a: void 0,
o: void 0,
i: void 0
}), _el$;
})();
}
function GalleryRating(props) {
let source = untrack(() => props.source), rating = source.data.rating, [ratingValue, setRatingValue] = createSignal(rating?.value ?? 0), [ratingPreview, setRatingPreview] = createSignal(null), [ratingPickerOpen, setRatingPickerOpen] = createSignal(!1), [ratingSubmitted, setRatingSubmitted] = createSignal(rating?.rated ?? !1), [ratingCount] = createSignal(rating?.count ?? ""), [ratingValueLabel] = createSignal(rating?.label ?? ""), ratingPointerType = "", displayedRating = createMemo(() => ratingPreview() ?? ratingValue()), closeRatingPicker = () => {
setRatingPreview(null), setRatingPickerOpen(!1);
}, ratingLabel = createMemo(() => {
let preview = ratingPreview();
return preview !== null ? `Rate as ${preview.toFixed(1)} stars` : ratingSubmitted() ? `Rated ${ratingValue().toFixed(1)} stars` : ratingValueLabel();
}), previewRatingFromPointer = (event) => {
event.pointerType === "mouse" && setRatingPreview(ratingFromPointer(event.clientX, event.currentTarget));
}, submitRating = (value) => {
if (!rating)
return !1;
try {
return source.handle.submitGalleryRating(value), setRatingValue(value), setRatingPreview(null), setRatingSubmitted(!0), !0;
} catch (error) {
return setRatingPreview(null), console.error("[ehpeek]", error), window.alert(error instanceof Error ? error.message : activeTexts.errors.loadFailed), !1;
}
};
return [rating && (() => {
var _el$29 = _tmpl$110(), _el$30 = _el$29.firstChild, _el$31 = _el$30.firstChild, _el$32 = _el$31.nextSibling, _el$33 = _el$30.nextSibling, _el$34 = _el$33.firstChild;
return _el$29.$$pointerdown = (event) => {
ratingPointerType = event.pointerType, event.pointerType !== "mouse" && setRatingPreview(null);
}, _el$29.addEventListener("pointercancel", () => {
ratingPointerType = "", setRatingPreview(null);
}), _el$29.addEventListener("blur", () => {
setRatingPreview(null);
}), _el$29.$$click = () => {
let preview = ratingPointerType === "mouse" ? ratingPreview() : null;
if (ratingPointerType = "", preview !== null) {
submitRating(preview);
return;
}
setRatingPreview(null), setRatingPickerOpen(!0);
}, _el$30.addEventListener("pointerleave", () => setRatingPreview(null)), _el$30.$$pointermove = previewRatingFromPointer, _el$30.$$pointerdown = previewRatingFromPointer, insert(_el$31, createComponent(For, {
each: RATING_STAR_INDEXES,
children: () => createComponent(Icon2, {
name: "star"
})
})), insert(_el$32, createComponent(For, {
each: RATING_STAR_INDEXES,
children: () => createComponent(Icon2, {
name: "star",
filled: !0
})
})), insert(_el$34, ratingLabel), insert(_el$33, (() => {
var _c$3 = memo(() => !!ratingCount());
return () => _c$3() && (() => {
var _el$35 = _tmpl$103();
return insert(_el$35, ratingCount), _el$35;
})();
})(), null), createRenderEffect((_p$) => {
var _v$10 = activeTexts.gallery.rate, _v$11 = `absolute top-0 left-0 flex gap-1px overflow-hidden ${ratingSubmitted() ? "text-[var(--color-rating-submitted)]" : "ehp-color-site-accent"}`, _v$12 = `${displayedRating() / 5 * 100}%`;
return _v$10 !== _p$.e && setAttribute(_el$29, "aria-label", _p$.e = _v$10), _v$11 !== _p$.t && className(_el$32, _p$.t = _v$11), _v$12 !== _p$.a && setStyleProperty(_el$32, "width", _p$.a = _v$12), _p$;
}, {
e: void 0,
t: void 0,
a: void 0
}), _el$29;
})(), createComponent(Show, {
get when() {
return ratingPickerOpen();
},
get children() {
return createComponent(Dialog, {
bodyClass: "flex flex-col ui-gap-lg ui-pt-lg ui-px-lg",
get label() {
return activeTexts.gallery.rate;
},
lockPageScroll: !0,
onClose: closeRatingPicker,
get title() {
return activeTexts.gallery.rate;
},
variant: "site",
width: "md",
get children() {
return [(() => {
var _el$22 = _tmpl$84(), _el$23 = _el$22.firstChild, _el$24 = _el$23.nextSibling;
return _el$22.$$click = (event) => {
setRatingPreview(ratingFromPointer(event.clientX, event.currentTarget));
}, insert(_el$23, createComponent(For, {
each: RATING_STAR_INDEXES,
children: () => createComponent(Icon2, {
name: "star",
size: "var(--ui-control-size-lg)"
})
})), insert(_el$24, createComponent(For, {
each: RATING_STAR_INDEXES,
children: () => createComponent(Icon2, {
name: "star",
size: "var(--ui-control-size-lg)",
filled: !0
})
})), createRenderEffect((_p$) => {
var _v$9 = activeTexts.gallery.rateWithStars.replace("{rating}", displayedRating().toFixed(1)), _v$0 = `absolute top-0 left-0 flex gap-1px overflow-hidden pointer-events-none ${ratingSubmitted() || ratingPreview() !== null ? "text-[var(--color-rating-submitted)]" : "ehp-color-site-accent"}`, _v$1 = `${displayedRating() / 5 * 100}%`;
return _v$9 !== _p$.e && setAttribute(_el$22, "aria-label", _p$.e = _v$9), _v$0 !== _p$.t && className(_el$24, _p$.t = _v$0), _v$1 !== _p$.a && setStyleProperty(_el$24, "width", _p$.a = _v$1), _p$;
}, {
e: void 0,
t: void 0,
a: void 0
}), _el$22;
})(), (() => {
var _el$25 = _tmpl$94();
return insert(_el$25, ratingLabel), _el$25;
})(), (() => {
var _el$26 = _tmpl$03(), _el$27 = _el$26.firstChild, _el$28 = _el$27.nextSibling;
return _el$27.$$click = () => {
let value = ratingPreview();
value !== null && submitRating(value) && setRatingPickerOpen(!1);
}, insert(_el$27, () => activeTexts.common.actions.submit), _el$28.$$click = closeRatingPicker, insert(_el$28, () => activeTexts.common.actions.close), createRenderEffect(() => _el$27.disabled = ratingPreview() === null), _el$26;
})()];
}
});
}
})];
}
function ratingFromPointer(clientX, element) {
let rect = element.getBoundingClientRect(), progress = Math.min(1, Math.max(0, (clientX - rect.left) / rect.width));
return Math.max(0.5, Math.ceil(progress * 10) / 2);
}
function TouchGalleryActionsMenu(props) {
let [open, setOpen] = createSignal(!1), root;
return (() => {
var _el$36 = _tmpl$113(), _el$37 = _el$36.firstChild, _ref$ = root;
return typeof _ref$ == "function" ? use(_ref$, _el$36) : root = _el$36, _el$37.$$click = (event) => {
event.stopPropagation(), setOpen((value) => !value);
}, insert(_el$37, createComponent(Icon2, {
name: "menu"
})), insert(_el$36, createComponent(Show, {
get when() {
return open();
},
get children() {
return createComponent(Popover, {
contains: (target) => root.contains(target),
onOutsidePress: () => setOpen(!1),
class: "absolute top-[calc(var(--ui-control-size-md)+var(--ui-space-sm))] right-0 flex w-[min(78vw,calc(var(--ui-control-size-xl)*4))] flex-col",
get children() {
return createComponent(DomNodes, {
get nodes() {
return props.items;
}
});
}
});
}
}), null), createRenderEffect(() => setAttribute(_el$37, "aria-expanded", open())), _el$36;
})();
}
function TouchGalleryTagGroup(props) {
return (() => {
var _el$38 = _tmpl$123(), _el$39 = _el$38.firstChild, _el$40 = _el$39.nextSibling;
return insert(_el$39, () => props.group.namespace), _el$40.$$click = (event) => {
if (!props.tagging || event.defaultPrevented || event.button !== 0 || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey)
return;
let href = (event.target instanceof Element ? event.target.closest("a.ehpeek-touch-gallery-tag") : null)?.getAttribute("href"), tag2 = props.group.tags.find((candidate) => candidate.url === href);
tag2 && (event.preventDefault(), props.onTagOpen(tag2));
}, insert(_el$40, createComponent(For, {
get each() {
return props.group.tags;
},
children: (tag2) => createComponent(TouchGalleryTag, {
tag: tag2
})
})), _el$38;
})();
}
function TouchGalleryTag(props) {
return (() => {
var _el$41 = _tmpl$132();
return setAttribute(_el$41, "draggable", !1), insert(_el$41, createComponent(TouchGalleryTagContent, {
get tag() {
return props.tag;
}
})), createRenderEffect((_p$) => {
var _v$13 = props.tag.url, _v$14 = props.tag.appearance.backgroundColor, _v$15 = props.tag.appearance.borderColor, _v$16 = props.tag.appearance.color, _v$17 = props.tag.label;
return _v$13 !== _p$.e && setAttribute(_el$41, "href", _p$.e = _v$13), _v$14 !== _p$.t && setStyleProperty(_el$41, "background-color", _p$.t = _v$14), _v$15 !== _p$.a && setStyleProperty(_el$41, "border-color", _p$.a = _v$15), _v$16 !== _p$.o && setStyleProperty(_el$41, "color", _p$.o = _v$16), _v$17 !== _p$.i && setAttribute(_el$41, "aria-label", _p$.i = _v$17), _p$;
}, {
e: void 0,
t: void 0,
a: void 0,
o: void 0,
i: void 0
}), _el$41;
})();
}
function TouchGalleryTagMenu(props) {
let source = untrack(() => props.source), onClose = untrack(() => props.onClose), onTagUpdated = untrack(() => props.onTagUpdated);
onMount(() => {
let onKeyDown = (event) => {
event.key === "Escape" && props.tag && props.onClose();
};
document.addEventListener("keydown", onKeyDown), onCleanup(() => {
document.removeEventListener("keydown", onKeyDown);
});
});
let [favoriteDialogOpen, setFavoriteDialogOpen] = createSignal(!1), [favoriteTag, setFavoriteTag] = createSignal(null), [updating, setUpdating] = createSignal(!1), updateFavoriteTag = async (tag2, submit) => {
if (!updating()) {
setUpdating(!0);
try {
let myTagsPage = await submit(), updateAppearance = (appearance) => onTagUpdated({
...tag2,
appearance: appearance ? {
...tag2.appearance,
backgroundColor: appearance.backgroundColor,
color: appearance.color
} : {
backgroundColor: "",
borderColor: "",
color: ""
},
myTag: appearance ? {
id: appearance.id,
tagSet: appearance.tagSet
} : null
});
updateAppearance(myTagsPage.appearances.find((item) => item.name === tag2.name)), setFavoriteDialogOpen(!1), onClose(), refreshMyTags(myTagsPage).then((appearances) => {
appearances && updateAppearance(appearances.find((item) => item.name === tag2.name));
});
} catch (error) {
console.error("[ehpeek]", error), window.alert(error instanceof Error ? error.message : activeTexts.errors.loadFailed);
} finally {
setUpdating(!1);
}
}
};
return [(() => {
var _el$42 = _tmpl$142(), _el$43 = _el$42.firstChild;
return _el$42.$$click = (event) => {
event.target === event.currentTarget && props.onClose();
}, _el$43.$$click = () => {
updating() || props.onClose();
}, insert(_el$43, createComponent(Show, {
get when() {
return !updating();
},
get fallback() {
return createComponent(WelcomeIcon, {
embedded: !0,
get label() {
return activeTexts.common.status.loading;
},
showIcon: !1
});
},
get children() {
return [createComponent(DomNode2, {
get node() {
return props.source.elems.tagMenuAction;
}
}), createComponent(Show, {
get when() {
return props.tag;
},
children: (tag2) => (() => {
var _el$44 = _tmpl$152(), _el$45 = _el$44.firstChild;
return _el$44.$$click = (event) => {
event.stopPropagation(), navigator.clipboard.writeText(exactTagQuery(tag2().name)).then(onClose, (error) => {
console.error("[ehpeek] Copy gallery tag failed", error), window.alert(error instanceof Error ? error.message : activeTexts.errors.loadFailed);
});
}, insert(_el$44, createComponent(Icon2, {
name: "copy"
}), _el$45), insert(_el$45, () => activeTexts.gallery.copyOriginalTag), createRenderEffect(() => className(_el$44, sharedApply.galleryTagMenuItem)), _el$44;
})()
}), createComponent(Show, {
get when() {
return state.gallery.myTags.value;
},
get children() {
return createComponent(Show, {
get when() {
return props.tag;
},
children: (tag2) => createComponent(Show, {
get when() {
return !tag2().myTag;
},
get fallback() {
return (() => {
var _el$48 = _tmpl$152(), _el$49 = _el$48.firstChild;
return _el$48.$$click = (event) => {
event.stopPropagation();
let selected = tag2();
updateFavoriteTag(selected, () => source.handle.removeFavoriteTag(selected));
}, insert(_el$48, createComponent(Icon2, {
name: "heart",
filled: !0
}), _el$49), insert(_el$49, () => activeTexts.gallery.removeFavoriteTag), createRenderEffect(() => className(_el$48, sharedApply.galleryTagMenuItem)), _el$48;
})();
},
get children() {
var _el$46 = _tmpl$152(), _el$47 = _el$46.firstChild;
return _el$46.$$click = () => {
setFavoriteTag(tag2()), setFavoriteDialogOpen(!0);
}, insert(_el$46, createComponent(Icon2, {
name: "heart"
}), _el$47), insert(_el$47, () => activeTexts.gallery.favoriteTag), createRenderEffect(() => className(_el$46, sharedApply.galleryTagMenuItem)), _el$46;
}
})
});
}
})];
}
})), createRenderEffect((_p$) => {
var _v$18 = `fixed inset-0 z-overlay flex items-center justify-center ui-p-lg bg-black/65 transition-opacity duration-120 ${props.tag ? "visible opacity-100" : "invisible opacity-0 pointer-events-none"}`, _v$19 = !props.tag, _v$20 = props.tag?.label ?? "";
return _v$18 !== _p$.e && className(_el$42, _p$.e = _v$18), _v$19 !== _p$.t && setAttribute(_el$42, "aria-hidden", _p$.t = _v$19), _v$20 !== _p$.a && setAttribute(_el$42, "aria-label", _p$.a = _v$20), _p$;
}, {
e: void 0,
t: void 0,
a: void 0
}), _el$42;
})(), createComponent(FavoriteTagDialog, {
get open() {
return favoriteDialogOpen();
},
get updating() {
return updating();
},
onClose: () => setFavoriteDialogOpen(!1),
onSubmit: (tagSet, mode) => {
let tag2 = favoriteTag();
tag2 && updateFavoriteTag(tag2, () => source.handle.submitFavoriteTag(tag2, tagSet, mode));
}
})];
}
function FavoriteTagDialog(props) {
let tagSets = state.gallery.myTagSets.reload(), [selectedTagSet, setSelectedTagSet] = createSignal(tagSets.find((option2) => option2.selected)?.value ?? tagSets[0]?.value ?? "1"), [collectionOpen, setCollectionOpen] = createSignal(!1), [tagMode, setTagMode] = createSignal("marked"), closeFavoriteTagDialog = () => {
setCollectionOpen(!1), props.onClose();
};
return createEffect(() => {
props.open && setCollectionOpen(!1);
}), createComponent(Show, {
get when() {
return props.open;
},
get children() {
return createComponent(Dialog, {
bodyClass: "flex flex-col ui-gap-lg ui-pt-lg ui-px-lg",
get label() {
return activeTexts.gallery.favoriteTag;
},
lockPageScroll: !0,
onClose: closeFavoriteTagDialog,
get title() {
return activeTexts.gallery.favoriteTag;
},
variant: "site",
width: "md",
get children() {
return createComponent(Show, {
get when() {
return !props.updating;
},
get fallback() {
return createComponent(WelcomeIcon, {
embedded: !0,
get label() {
return activeTexts.common.status.loading;
},
showIcon: !1
});
},
get children() {
return [(() => {
var _el$50 = _tmpl$172(), _el$51 = _el$50.firstChild, _el$52 = _el$51.nextSibling, _el$53 = _el$52.firstChild, _el$54 = _el$53.firstChild, _el$55 = _el$54.nextSibling;
return insert(_el$51, () => activeTexts.gallery.tagCollection), _el$53.$$click = () => setCollectionOpen((open) => !open), insert(_el$54, () => tagSets.find((option2) => option2.value === selectedTagSet())?.label ?? selectedTagSet()), insert(_el$55, () => collectionOpen() ? "▴" : "▾"), insert(_el$52, createComponent(Show, {
get when() {
return collectionOpen();
},
get children() {
var _el$56 = _tmpl$162();
return insert(_el$56, createComponent(For, {
each: tagSets,
children: (option2) => (() => {
var _el$64 = _tmpl$202(), _el$65 = _el$64.firstChild;
return _el$64.$$click = () => {
setSelectedTagSet(option2.value), setCollectionOpen(!1);
}, insert(_el$65, () => option2.label), insert(_el$64, createComponent(Show, {
get when() {
return selectedTagSet() === option2.value;
},
get children() {
return createComponent(Icon2, {
name: "check"
});
}
}), null), createRenderEffect((_p$) => {
var _v$21 = `flex box-border w-full min-h-[var(--ui-control-size-md)] items-center justify-between ui-gap-md ui-px-md border-0 border-b last:border-b-0 ehp-color-site-border-subtle-b ehp-color-site-text font-inherit text-left textsize-md cursor-pointer ${selectedTagSet() === option2.value ? "bg-[var(--color-site-item-hover)] font-700" : "!bg-transparent hover:!bg-[var(--color-site-item-hover)]"}`, _v$22 = selectedTagSet() === option2.value;
return _v$21 !== _p$.e && className(_el$64, _p$.e = _v$21), _v$22 !== _p$.t && setAttribute(_el$64, "aria-selected", _p$.t = _v$22), _p$;
}, {
e: void 0,
t: void 0
}), _el$64;
})()
})), createRenderEffect(() => setAttribute(_el$56, "aria-label", activeTexts.gallery.tagCollection)), _el$56;
}
}), null), createRenderEffect(() => setAttribute(_el$53, "aria-expanded", collectionOpen())), _el$50;
})(), (() => {
var _el$57 = _tmpl$182(), _el$58 = _el$57.firstChild, _el$59 = _el$58.nextSibling;
return insert(_el$58, () => activeTexts.gallery.tagBehavior), insert(_el$59, createComponent(For, {
get each() {
return [["marked", activeTexts.gallery.markTag], ["watched", activeTexts.gallery.watchTag], ["hidden", activeTexts.gallery.hideTag]];
},
children: ([value, label]) => (() => {
var _el$66 = _tmpl$2110(), _el$67 = _el$66.firstChild;
return _el$66.$$click = () => setTagMode(value), insert(_el$67, label), insert(_el$66, createComponent(Show, {
get when() {
return tagMode() === value;
},
get children() {
return createComponent(Icon2, {
name: "check"
});
}
}), null), createRenderEffect((_p$) => {
var _v$23 = `flex box-border w-full min-h-[var(--ui-control-size-md)] items-center justify-between ui-gap-md ui-px-md border-0 border-b last:border-b-0 ehp-color-site-border-subtle-b ehp-color-site-text font-inherit text-left textsize-md cursor-pointer ${tagMode() === value ? "bg-[var(--color-site-item-hover)] font-700" : "!bg-transparent hover:!bg-[var(--color-site-item-hover)]"}`, _v$24 = tagMode() === value;
return _v$23 !== _p$.e && className(_el$66, _p$.e = _v$23), _v$24 !== _p$.t && setAttribute(_el$66, "aria-checked", _p$.t = _v$24), _p$;
}, {
e: void 0,
t: void 0
}), _el$66;
})()
})), createRenderEffect(() => setAttribute(_el$59, "aria-label", activeTexts.gallery.tagBehavior)), _el$57;
})(), (() => {
var _el$60 = _tmpl$192(), _el$61 = _el$60.firstChild, _el$62 = _el$61.nextSibling, _el$63 = _el$62.firstChild;
return _el$61.$$click = closeFavoriteTagDialog, insert(_el$61, () => activeTexts.common.actions.close), _el$62.$$click = () => {
props.onSubmit(selectedTagSet(), tagMode());
}, insert(_el$62, createComponent(Icon2, {
name: "heart"
}), _el$63), insert(_el$63, () => activeTexts.common.actions.confirm), _el$60;
})()];
}
});
}
});
}
});
}
function TouchGalleryNewTag(props) {
return createComponent(DomNode2, {
get node() {
return props.source.elems.newTag;
}
});
}
function TouchGalleryTagContent(props) {
let host;
return onMount(() => {
onCleanup(props.tag.contentSource.mirrorContentTo(host));
}), (() => {
var _el$68 = _tmpl$222(), _ref$2 = host;
return typeof _ref$2 == "function" ? use(_ref$2, _el$68) : host = _el$68, _el$68;
})();
}
function TouchGalleryFavoriteButton(props) {
let [favorite, setFavorite] = createSignal(untrack(() => ({
...props.source.data.favorite
}))), [open, setOpen] = createSignal(!1), [loadingState, setLoadingState] = createSignal("idle"), [options, setOptions] = createSignal([]), [note, setNote] = createSignal(""), [noteDraft, setNoteDraft] = createSignal(""), [editingNote, setEditingNote] = createSignal(!1), favorited = () => favorite().favorited, closeMenu = () => {
noteDraft() !== note() && !window.confirm(activeTexts.gallery.discardFavoriteNote) || (setNoteDraft(note()), setEditingNote(!1), setOpen(!1));
}, openMenu = async () => {
let currentFavorite = favorite();
if (currentFavorite.actionUrl) {
setOpen(!0), setEditingNote(!1), setNote(""), setNoteDraft(""), setLoadingState("loading");
try {
let dialog = await props.source.handle.loadGalleryFavoriteDialog(currentFavorite.actionUrl, currentFavorite.favorited);
if (!dialog.authenticated) {
setLoadingState("unauthenticated");
return;
}
setOptions(dialog.options), setNote(dialog.note), setNoteDraft(dialog.note), setLoadingState("idle");
} catch (error) {
console.error("[ehpeek]", error), setLoadingState("failed");
}
}
}, updateFavorite = async (option2) => {
let actionUrl = favorite().actionUrl;
if (!(!actionUrl || loadingState() === "loading")) {
setLoadingState("loading");
try {
await props.source.handle.updateGalleryFavorite(actionUrl, option2.value, noteDraft()), setFavorite({
...favorite(),
color: option2.color,
favorited: option2.value !== "favdel",
label: option2.value === "favdel" ? activeTexts.gallery.notFavorited : option2.label
}), setNote(noteDraft()), setLoadingState("idle"), setOpen(!1);
} catch (error) {
console.error("[ehpeek]", error), setLoadingState("failed");
}
}
};
return (() => {
var _el$69 = _tmpl$242(), _el$70 = _el$69.firstChild, _el$71 = _el$70.firstChild, _el$72 = _el$71.nextSibling;
return _el$70.$$click = (event) => {
event.stopPropagation(), open() ? closeMenu() : openMenu();
}, insert(_el$71, () => favorite().label), insert(_el$72, createComponent(Icon2, {
name: "heart",
size: "var(--ui-icon-size-lg)",
get filled() {
return favorited();
}
})), insert(_el$69, createComponent(Show, {
get when() {
return open();
},
get children() {
return createComponent(Dialog, {
get label() {
return favorite().label;
},
onClose: closeMenu,
get title() {
return memo(() => !!editingNote())() ? activeTexts.gallery.editFavoriteNote : favorite().label;
},
variant: "site",
width: "md",
get children() {
return [createComponent(Show, {
get when() {
return loadingState() === "loading";
},
get children() {
return createComponent(WelcomeIcon, {
embedded: !0,
get label() {
return activeTexts.common.status.loading;
},
showIcon: !1
});
}
}), createComponent(Show, {
get when() {
return loadingState() === "failed";
},
get children() {
return createComponent(TouchGalleryFavoriteStatus, {
get text() {
return activeTexts.common.status.failed;
}
});
}
}), createComponent(Show, {
get when() {
return loadingState() === "unauthenticated";
},
get children() {
return createComponent(TouchGalleryFavoriteStatus, {
get text() {
return activeTexts.gallery.favoriteRequiresLogin;
}
});
}
}), createComponent(Show, {
get when() {
return loadingState() === "idle";
},
get children() {
return createComponent(Show, {
get when() {
return editingNote();
},
get fallback() {
return [createComponent(For, {
get each() {
return options().filter((option2) => option2.value !== "favdel");
},
children: (option2) => createComponent(TouchGalleryFavoriteOption, {
option: option2,
onSelect: () => {
updateFavorite(option2);
}
})
}), (() => {
var _el$77 = _tmpl$252(), _el$78 = _el$77.firstChild, _el$79 = _el$78.nextSibling;
return _el$77.$$click = () => setEditingNote(!0), insert(_el$78, createComponent(Icon2, {
name: "edit",
size: GALLERY_FAVORITE_ICON_SIZE
})), insert(_el$79, () => activeTexts.gallery.editFavoriteNote), _el$77;
})(), createComponent(For, {
get each() {
return options().filter((option2) => option2.value === "favdel");
},
children: (option2) => createComponent(TouchGalleryFavoriteOption, {
option: option2,
onSelect: () => {
updateFavorite(option2);
}
})
})];
},
get children() {
var _el$73 = _tmpl$232(), _el$74 = _el$73.firstChild, _el$75 = _el$74.nextSibling, _el$76 = _el$75.firstChild;
return _el$74.$$input = (event) => setNoteDraft(event.currentTarget.value), _el$76.$$click = () => setEditingNote(!1), insert(_el$76, () => activeTexts.common.actions.confirm), createRenderEffect(() => _el$74.value = noteDraft()), _el$73;
}
});
}
})];
}
});
}
}), null), createRenderEffect((_p$) => {
var _v$25 = favorite().color ?? void 0, _v$26 = open();
return _v$25 !== _p$.e && setStyleProperty(_el$70, "color", _p$.e = _v$25), _v$26 !== _p$.t && setAttribute(_el$70, "aria-expanded", _p$.t = _v$26), _p$;
}, {
e: void 0,
t: void 0
}), _el$69;
})();
}
function TouchGalleryFavoriteStatus(props) {
return (() => {
var _el$80 = _tmpl$262();
return insert(_el$80, () => props.text), _el$80;
})();
}
function TouchGalleryFavoriteOption(props) {
return (() => {
var _el$81 = _tmpl$272(), _el$82 = _el$81.firstChild, _el$83 = _el$82.nextSibling, _el$84 = _el$83.nextSibling;
return _el$81.$$click = (event) => {
event.stopPropagation(), props.onSelect();
}, insert(_el$82, createComponent(Icon2, {
name: "heart",
size: GALLERY_FAVORITE_ICON_SIZE,
get filled() {
return props.option.value !== "favdel";
}
})), insert(_el$83, () => props.option.label), insert(_el$84, createComponent(Icon2, {
name: "check",
size: "var(--ui-icon-size-sm)"
})), createRenderEffect((_p$) => {
var _v$27 = props.option.selected, _v$28 = props.option.color ?? void 0, _v$29 = `ml-auto flex-none ehp-color-site-text ${props.option.selected ? "visible" : "invisible"}`, _v$30 = props.option.color ?? void 0;
return _v$27 !== _p$.e && setAttribute(_el$81, "aria-pressed", _p$.e = _v$27), _v$28 !== _p$.t && setStyleProperty(_el$82, "color", _p$.t = _v$28), _v$29 !== _p$.a && className(_el$84, _p$.a = _v$29), _v$30 !== _p$.o && setStyleProperty(_el$84, "color", _p$.o = _v$30), _p$;
}, {
e: void 0,
t: void 0,
a: void 0,
o: void 0
}), _el$81;
})();
}
var _tmpl$58, _tmpl$219, _tmpl$313, _tmpl$411, _tmpl$59, _tmpl$68, _tmpl$77, _tmpl$84, _tmpl$94, _tmpl$03, _tmpl$110, _tmpl$103, _tmpl$113, _tmpl$123, _tmpl$132, _tmpl$142, _tmpl$152, _tmpl$162, _tmpl$172, _tmpl$182, _tmpl$192, _tmpl$202, _tmpl$2110, _tmpl$222, _tmpl$232, _tmpl$242, _tmpl$252, _tmpl$262, _tmpl$272, RATING_STAR_INDEXES, GALLERY_FAVORITE_ICON_SIZE, TAG_NAMESPACE_PREFIXES, init_GalleryInfoPanel = __esm({
"src/components/TouchUI/GalleryInfoPanel.tsx"() {
"use strict";
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_solid();
init_eh();
init_i18n2();
init_state();
init_myTags();
init_WelcomeIcon();
init_BackToTop();
init_Widgets();
init_ExternalDom();
_tmpl$58 = /* @__PURE__ */ template("<div>"), _tmpl$219 = /* @__PURE__ */ template('<section class="flex box-border w-full flex-col ui-mb-sm ehp-color-site-text font-sans"><div class="ehpeek-touch-gallery-summary-container relative grid min-h-[clamp(130px,21vh,170px)] ui-pt-sm safe-pr-sm safe-pl-sm ehp-color-site-surface ehp-color-site-text"><div><div class="ehpeek-touch-gallery-summary-details flex self-stretch min-w-0 flex-col items-start ui-gap-xs pt-1px"><div class="flex min-w-0 w-full flex-none flex-col ui-gap-xs items-start pb-2px"><div class="line-clamp-4 flex-none overflow-hidden [font-size:var(--ui-font-size-lg)] font-400 leading-[1.16] text-left break-anywhere"></div><div class="line-clamp-3 flex-none overflow-hidden opacity-82 textsize-md leading-[1.2] text-left break-anywhere"></div></div><div class="flex min-w-0 max-w-full flex-none items-center ui-gap-sm"><a class="box-border flex-none whitespace-nowrap ui-rounded-xs border border-solid ui-py-xs ui-px-xs text-center textsize-md font-700 leading-[1.1] uppercase no-underline hover:no-underline active:no-underline"></a></div></div><div class="ehpeek-touch-gallery-primary-actions relative z-1 grid grid-cols-[1fr_1fr] min-h-[var(--ui-control-size-xl)] overflow-visible ui-rounded-xs bg-[var(--color-site-elevated)] shadow-[0_2px_10px_var(--color-shadow-panel)]"><div class="contents [direction:ltr]"></div><div class="flex min-w-0 border-0 border-solid border-[var(--color-site-page)] [direction:ltr]"></div></div></div></div><div class="flex flex-col ui-gap-sm ui-pt-md safe-pr-sm ui-pb-sm safe-pl-sm ehp-color-site-page ehp-color-site-text"><div class="grid grid-cols-[repeat(3,minmax(0,1fr))] ui-gap-y-sm ui-gap-x-sm items-center [font-size:var(--ui-font-size-lg)] leading-[1.2] text-center">'), _tmpl$313 = /* @__PURE__ */ template('<div class="ehpeek-touch-gallery-summary-cover flex self-center justify-self-stretch w-full max-h-full aspect-[2/3] items-center justify-center overflow-hidden rounded-3px">'), _tmpl$411 = /* @__PURE__ */ template('<a class="min-w-0 overflow-hidden text-ellipsis whitespace-nowrap opacity-82 textsize-md font-700 leading-[1.1] no-underline hover:underline active:underline">'), _tmpl$59 = /* @__PURE__ */ template('<div class="line-clamp-2 min-w-0 overflow-hidden whitespace-normal break-normal">'), _tmpl$68 = /* @__PURE__ */ template('<div class="grid min-w-0 w-full grid-cols-[max-content_minmax(0,1fr)] items-start ui-gap-x-xs ui-gap-y-sm">'), _tmpl$77 = /* @__PURE__ */ template('<div class="flex flex-col pt-2px"><button type=button><span></span><span aria-hidden=true>'), _tmpl$84 = /* @__PURE__ */ template('<button type=button class="relative inline-flex self-center max-w-full overflow-hidden p-0 border-0 bg-transparent cursor-pointer select-none [touch-action:manipulation] [-webkit-tap-highlight-color:transparent] focus-visible:ui-rounded-xs focus-visible:outline focus-visible:outline-2 focus-visible:outline-[var(--color-site-accent)] focus-visible:outline-offset-3px"><span class="flex gap-1px pointer-events-none text-[var(--color-muted)] opacity-40"aria-hidden=true></span><span aria-hidden=true>'), _tmpl$94 = /* @__PURE__ */ template('<div class="text-center textsize-md font-700"aria-live=polite>'), _tmpl$03 = /* @__PURE__ */ template('<div class="grid grid-cols-2 ui-gap-sm ui-pt-md border-0 border-t border-t-[var(--color-site-border-subtle)]"><button type=button class="flex w-full min-h-[var(--ui-control-size-md)] items-center justify-center ui-py-xs ui-px-md ui-rounded-md border cursor-pointer font-inherit text-center textsize-md font-700 leading-[1.1] transition-[filter,transform,box-shadow] duration-120 active:scale-98 disabled:opacity-50 disabled:cursor-default border-[var(--color-site-accent)] bg-[var(--color-site-accent)] text-[var(--color-site-surface)] shadow-[0_2px_8px_var(--color-shadow-panel)] hover:brightness-108"></button><button type=button class="flex w-full min-h-[var(--ui-control-size-md)] items-center justify-center ui-py-xs ui-px-md ui-rounded-md border cursor-pointer font-inherit text-center textsize-md font-700 leading-[1.1] transition-[filter,transform,box-shadow] duration-120 active:scale-98 disabled:opacity-50 disabled:cursor-default border-[var(--color-site-border-subtle)] bg-[var(--color-site-surface)] text-[var(--color-site-text)] hover:bg-[var(--color-site-item-hover)]">'), _tmpl$110 = /* @__PURE__ */ template('<button type=button class="flex w-[65%] max-w-full flex-none self-end flex-col items-end ui-gap-xs mt-auto p-0 border-0 bg-transparent ehp-color-site-text font-inherit text-right cursor-pointer select-none [touch-action:manipulation] [-webkit-tap-highlight-color:transparent] focus-visible:ui-rounded-xs focus-visible:outline focus-visible:outline-2 focus-visible:outline-[var(--color-site-accent)] focus-visible:outline-offset-3px"><div class="relative inline-flex [&_.ehpeek-icon]:w-[var(--ui-icon-size-lg)] [&_.ehpeek-icon]:h-[var(--ui-icon-size-lg)]"><span class="flex gap-1px text-[var(--color-muted)] opacity-40"aria-hidden=true></span><span aria-hidden=true></span></div><div class="flex items-center justify-end ui-gap-xs text-[var(--color-muted)] [font-size:var(--ui-font-size-lg)] leading-[1.15] whitespace-nowrap"><span aria-live=polite>'), _tmpl$103 = /* @__PURE__ */ template('<span class="flex-none ui-pl-xs border-0 border-l border-[var(--color-site-border-subtle)] opacity-75">'), _tmpl$113 = /* @__PURE__ */ template('<div class="relative flex min-w-0 items-center justify-center"><button type=button class="inline-flex w-[var(--ui-control-size-md)] h-[var(--ui-control-size-md)] items-center justify-center border-0 bg-transparent ehp-color-site-text"aria-haspopup=menu>'), _tmpl$123 = /* @__PURE__ */ template('<section class=contents><div class="box-border min-h-[var(--ui-control-size-sm)] whitespace-nowrap ui-rounded-xl bg-[var(--color-site-elevated)] ui-py-xs ui-px-md text-center lowercase ehp-color-site-accent textsize-md font-600"></div><div class="flex flex-wrap ui-gap-xs">'), _tmpl$132 = /* @__PURE__ */ template('<a class="ehpeek-touch-gallery-tag inline-flex flex-none box-border max-w-full min-h-[var(--ui-control-size-sm)] items-center overflow-hidden text-ellipsis whitespace-nowrap appearance-none m-0 py-0 ui-rounded-xl border border-[var(--color-site-border-subtle)] bg-[var(--color-site-surface)] ui-px-lg ehp-color-site-text font-inherit font-700 textsize-md cursor-pointer select-text no-underline transition-[border-color,background-color,color] duration-120 hover:border-[var(--color-site-border)] hover:bg-[var(--color-site-accent-hover)] hover:ehp-color-site-accent">'), _tmpl$142 = /* @__PURE__ */ template('<div role=dialog aria-modal=true><div class="box-border flex w-full max-w-[calc(var(--ui-control-size-xl)*5.25)] max-h-[calc(100dvh-(var(--ui-space-lg)*2))] flex-col overflow-x-hidden overflow-y-auto overscroll-contain whitespace-nowrap border ehp-color-site-border ui-rounded-md ehp-color-site-elevated shadow-xl"role=menu>'), _tmpl$152 = /* @__PURE__ */ template("<button type=button role=menuitem><span>"), _tmpl$162 = /* @__PURE__ */ template('<div class="absolute top-full left-0 right-0 z-2 ui-mt-xs max-h-240px overflow-y-auto overscroll-contain ui-rounded-md border ehp-color-site-border ehp-color-site-elevated shadow-xl"role=listbox>'), _tmpl$172 = /* @__PURE__ */ template('<div class="flex flex-col ui-gap-sm ehp-color-site-text textsize-md font-600"><span></span><div class=relative><button type=button class="flex box-border w-full min-h-[var(--ui-control-size-md)] items-center justify-between ui-gap-md ui-rounded-md border ehp-color-site-border !bg-transparent hover:!bg-[var(--color-site-item-hover)] active:!bg-[var(--color-site-item-hover)] ehp-color-site-text ui-px-md font-inherit text-left textsize-md cursor-pointer"aria-haspopup=listbox><span class="min-w-0 overflow-hidden text-ellipsis whitespace-nowrap"></span><span class=flex-none aria-hidden=true>'), _tmpl$182 = /* @__PURE__ */ template('<div class="flex flex-col ui-gap-sm ehp-color-site-text textsize-md font-600"><span></span><div class="overflow-hidden ui-rounded-md border ehp-color-site-border"role=radiogroup>'), _tmpl$192 = /* @__PURE__ */ template('<div class="grid grid-cols-2 ui-gap-md"><button type=button class="flex w-full min-h-[var(--ui-control-size-md)] items-center justify-center ui-py-xs ui-px-md ui-rounded-md border cursor-pointer font-inherit text-center textsize-md font-700 leading-[1.1] transition-[filter,transform,box-shadow] duration-120 active:scale-98 disabled:opacity-50 disabled:cursor-default border-[var(--color-site-border-subtle)] bg-[var(--color-site-surface)] text-[var(--color-site-text)] hover:bg-[var(--color-site-item-hover)]"></button><button type=button class="flex w-full min-h-[var(--ui-control-size-md)] items-center justify-center ui-py-xs ui-px-md ui-rounded-md border cursor-pointer font-inherit text-center textsize-md font-700 leading-[1.1] transition-[filter,transform,box-shadow] duration-120 active:scale-98 disabled:opacity-50 disabled:cursor-default ui-gap-md border-[var(--color-site-accent)] bg-[var(--color-site-accent)] text-[var(--color-site-surface)] shadow-[0_2px_8px_var(--color-shadow-panel)] hover:brightness-108"><span>'), _tmpl$202 = /* @__PURE__ */ template("<button type=button role=option><span>"), _tmpl$2110 = /* @__PURE__ */ template("<button type=button role=radio><span>"), _tmpl$222 = /* @__PURE__ */ template('<span class="contents [&_*]:!bg-transparent [&_*]:!text-inherit"translate=no>'), _tmpl$232 = /* @__PURE__ */ template('<div class="flex flex-col ui-gap-md ui-pt-lg ui-px-lg"><textarea class="box-border min-h-[calc(var(--ui-control-size-xl)*3)] w-full resize-y ui-rounded-md border ehp-color-site-border bg-[var(--color-site-surface)] ui-p-md ehp-color-site-text font-inherit textsize-md leading-[1.4]"></textarea><div class="grid grid-cols-1 ui-gap-md"><button type=button class="min-h-[var(--ui-control-size-md)] ui-rounded-md border border-[var(--color-site-accent)] bg-[var(--color-site-accent)] text-[var(--color-site-surface)] font-inherit textsize-md font-700">'), _tmpl$242 = /* @__PURE__ */ template('<div class="relative z-2 min-w-0"><button type=button class="flex min-w-0 w-full h-full ui-hit-min-h-xl flex-col items-center justify-center ui-gap-xs ui-py-md ui-px-lg border-0 bg-transparent ehp-color-site-text text-center uppercase [touch-action:manipulation] [font-size:var(--ui-font-size-lg)] font-700 normal-case"aria-haspopup=menu><span class="block leading-[1.15]"></span><span class="block opacity-78 normal-case"aria-hidden=true>'), _tmpl$252 = /* @__PURE__ */ template('<button type=button class="flex box-border w-full ui-hit-min-h-md items-center ui-gap-md ui-py-xs ui-px-lg border-0 border-b ehp-color-site-border-subtle-b bg-transparent ehp-color-site-text font-inherit textsize-md leading-[1.2] text-left cursor-pointer"><span class="flex-none ehp-color-site-text"aria-hidden=true></span><span>'), _tmpl$262 = /* @__PURE__ */ template('<div class="flex box-border w-full ui-hit-min-h-md items-center ui-gap-md ui-py-xs ui-px-lg border-0 border-b ehp-color-site-border-subtle-b bg-transparent ehp-color-site-text font-inherit textsize-md leading-[1.2] text-left">'), _tmpl$272 = /* @__PURE__ */ template('<button type=button class="flex box-border w-full ui-hit-min-h-md items-center ui-gap-md ui-py-xs ui-px-lg border-0 border-b ehp-color-site-border-subtle-b bg-transparent ehp-color-site-text font-inherit textsize-md leading-[1.2] text-left cursor-pointer"><span class="flex-none ehp-color-site-text"aria-hidden=true></span><span></span><span aria-hidden=true>'), RATING_STAR_INDEXES = [0, 1, 2, 3, 4], GALLERY_FAVORITE_ICON_SIZE = "var(--ui-icon-size-lg)", TAG_NAMESPACE_PREFIXES = {
artist: "a",
character: "c",
cosplayer: "cos",
female: "f",
group: "g",
language: "l",
location: "loc",
male: "m",
mixed: "x",
other: "o",
parody: "p",
reclass: "r"
};
delegateEvents(["click", "pointerdown", "pointermove", "input"]);
}
});
// src/components/TouchUI/FavoritesPanel.tsx
function FavoritesCategorySelect(props) {
let container, [open, setOpen] = createSignal(!1), selected = () => props.source.data.favoritesCategory?.categories.find((category) => category.selected) ?? props.source.data.favoritesCategory?.categories[0] ?? null;
return onMount(() => {
let closeOnOutsidePointer = (event) => {
event.target instanceof Node && !container.contains(event.target) && setOpen(!1);
};
document.addEventListener("pointerdown", closeOnOutsidePointer, !0), onCleanup(() => document.removeEventListener("pointerdown", closeOnOutsidePointer, !0));
}), (() => {
var _el$ = _tmpl$220(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.firstChild, _el$5 = _el$4.firstChild, _el$7 = _el$5.nextSibling, _el$6 = _el$7.nextSibling, _el$8 = _el$3.nextSibling, _ref$ = container;
return typeof _ref$ == "function" ? use(_ref$, _el$) : container = _el$, _el$2.$$click = () => setOpen((value) => !value), insert(_el$3, () => categoryIndicator(selected()?.appearance), _el$4), insert(_el$4, () => selected()?.label, _el$5), insert(_el$4, () => selected()?.count, _el$7), insert(_el$8, () => open() ? "−" : "+"), insert(_el$, createComponent(Show, {
get when() {
return open();
},
get children() {
var _el$9 = _tmpl$60();
return insert(_el$9, createComponent(For, {
get each() {
return props.source.data.favoritesCategory?.categories;
},
children: (category, index) => (() => {
var _el$0 = _tmpl$314(), _el$1 = _el$0.firstChild, _el$10 = _el$1.firstChild, _el$11 = _el$10.firstChild, _el$13 = _el$11.nextSibling, _el$12 = _el$13.nextSibling;
return _el$0.$$click = () => props.source.handle.activateFavoriteCategory(index()), insert(_el$1, () => categoryIndicator(category.appearance), _el$10), insert(_el$10, () => category.label, _el$11), insert(_el$10, () => category.count, _el$13), createRenderEffect(() => className(_el$0, `flex box-border w-full ui-hit-min-h-lg items-center ui-px-sm ui-py-xs border-0 border-b ehp-color-site-border-subtle-b last:border-b-0 text-left textsize-sm font-inherit no-underline cursor-pointer ${category.selected ? "bg-[var(--color-site-accent-hover)] ehp-color-site-accent font-700" : "!bg-transparent ehp-color-site-text hover:!bg-[var(--color-site-item-hover)]"}`)), _el$0;
})()
})), _el$9;
}
}), null), createRenderEffect(() => setAttribute(_el$2, "aria-expanded", open())), _el$;
})();
}
function categoryIndicator(appearance) {
return (() => {
var _el$14 = _tmpl$412();
return createRenderEffect((_$p) => style(_el$14, appearance ? {
"background-image": appearance.backgroundImage,
"background-position": appearance.backgroundPosition,
"background-size": appearance.backgroundSize
} : void 0, _$p)), _el$14;
})();
}
var _tmpl$60, _tmpl$220, _tmpl$314, _tmpl$412, init_FavoritesPanel = __esm({
"src/components/TouchUI/FavoritesPanel.tsx"() {
"use strict";
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_solid();
_tmpl$60 = /* @__PURE__ */ template('<div class="border-0 border-t border-t-[var(--color-site-border-subtle)]">'), _tmpl$220 = /* @__PURE__ */ template('<div class="box-border w-full min-w-0 overflow-hidden ui-rounded-xs border ehp-color-site-border bg-[var(--color-site-elevated)]"><button type=button class="flex box-border w-full ui-hit-min-h-lg items-center justify-between ui-gap-sm ui-px-sm ui-py-xs ui-rounded-xs border-0 !bg-transparent ehp-color-site-text text-left textsize-sm font-700 font-inherit cursor-pointer hover:!bg-[var(--color-site-item-hover)] active:!bg-[var(--color-site-item-hover)]"><span class="flex min-w-0 items-center ui-gap-sm overflow-hidden"><span class="min-w-0 overflow-hidden text-ellipsis whitespace-nowrap"> [<!>]</span></span><span class="flex w-[var(--ui-icon-size-md)] h-[var(--ui-icon-size-md)] flex-none items-center justify-center leading-none"aria-hidden=true>'), _tmpl$314 = /* @__PURE__ */ template('<button type=button><span class="flex min-w-0 items-center ui-gap-sm"><span class="min-w-0 overflow-hidden text-ellipsis whitespace-nowrap"> [<!>]'), _tmpl$412 = /* @__PURE__ */ template('<span class="block h-15px w-15px flex-none bg-no-repeat"aria-hidden=true>');
delegateEvents(["click"]);
}
});
// src/components/TouchUI/SearchPanel.tsx
function TouchSearchPanel(props) {
return (() => {
var _el$ = _tmpl$61();
return insert(_el$, createComponent(DomNode2, {
get node() {
return props.source.elems.searchBox;
}
}), null), insert(_el$, createComponent(DomNode2, {
get node() {
return props.source.elems.fileSearch;
}
}), null), insert(_el$, () => props.after, null), _el$;
})();
}
function TouchSearchCategoryToggle(props) {
let [open, setOpen] = createSignal(!1);
return createEffect(() => props.source.handle.updateCategoryVisibility(open())), createComponent(ToggleButton, {
get expanded() {
return open();
},
get label() {
return activeTexts.search.categories;
},
onClick: () => setOpen((value) => !value)
});
}
function TouchSearchOptionToggle(props) {
let [open, setOpen] = createSignal(!1);
return createComponent(ToggleButton, {
get expanded() {
return open();
},
get label() {
return activeTexts.search[props.option];
},
onClick: () => {
props.option === "advancedOptions" ? props.source.handle.toggleAdvancedOptions() : props.source.handle.toggleFileSearch(), setOpen((value) => !value);
}
});
}
function ToggleButton(props) {
return (() => {
var _el$2 = _tmpl$221();
return _el$2.$$click = () => props.onClick(), insert(_el$2, () => props.label), createRenderEffect(() => setAttribute(_el$2, "aria-expanded", props.expanded)), _el$2;
})();
}
function TouchSearchAction(props) {
let source = untrack(() => props.source), search2 = untrack(() => props.action === "search"), label = search2 ? source.data.searchLabel : source.data.clearLabel ?? "";
return (() => {
var _el$3 = _tmpl$315();
return _el$3.$$click = (event) => {
event.preventDefault(), search2 ? source.handle.activateSearch() : source.handle.clearSearchText();
}, setAttribute(_el$3, "type", search2 ? "submit" : "button"), setAttribute(_el$3, "aria-label", label), setAttribute(_el$3, "title", label), insert(_el$3, createComponent(Icon2, {
name: search2 ? "search" : "close",
size: "var(--ehpeek-touch-search-icon-size)"
})), createRenderEffect(() => className(_el$3, search2 ? `${TOUCH_SEARCH_ACTION_CLASS} z-1 ${source.data.hasClear ? "col-start-3" : "col-start-2"} row-start-1 ehp-color-site-accent` : `${TOUCH_SEARCH_ACTION_CLASS} z-1 col-start-2 row-start-1 ehp-color-site-text`)), _el$3;
})();
}
var _tmpl$61, _tmpl$221, _tmpl$315, TOUCH_SEARCH_ACTION_CLASS, init_SearchPanel = __esm({
"src/components/TouchUI/SearchPanel.tsx"() {
"use strict";
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_solid();
init_i18n2();
init_ExternalDom();
init_Widgets();
_tmpl$61 = /* @__PURE__ */ template('<section class="ehpeek-touch-search-panel box-border flex w-[calc(100%_-_(var(--ui-space-sm)*2))] max-w-960px flex-col ui-gap-sm mx-auto ui-mb-sm ui-p-sm border ehp-color-site-border ui-rounded-sm ehp-color-site-surface ehp-color-site-text shadow-[0_8px_24px_var(--color-shadow-panel)] font-sans">'), _tmpl$221 = /* @__PURE__ */ template('<button type=button class="appearance-none inline-flex ui-hit-min-h-sm items-center ui-px-md border-0 ui-rounded-sm bg-transparent ehp-color-site-accent text-left textsize-md font-700 font-inherit leading-[1.2] no-underline cursor-pointer [touch-action:manipulation] active:bg-[var(--color-site-accent-hover)]">'), _tmpl$315 = /* @__PURE__ */ template("<button>"), TOUCH_SEARCH_ACTION_CLASS = "appearance-none inline-flex box-border w-[var(--ui-control-size-xl)] h-[var(--ui-control-size-xl)] items-center justify-center p-0 ui-rounded-sm border-0 bg-transparent cursor-pointer transition-[background-color,transform] duration-120 [touch-action:manipulation] active:scale-96 active:bg-[var(--color-site-item-hover)] [--ehpeek-touch-search-icon-size:var(--ui-icon-size-lg)]";
delegateEvents(["click"]);
}
});
// src/components/TouchUI/TopBar.tsx
function TouchTopBarUiMenu(props) {
let [open, setOpen] = createSignal(!1), root;
return (() => {
var _el$ = _tmpl$316(), _ref$ = root;
return typeof _ref$ == "function" ? use(_ref$, _el$) : root = _el$, insert(_el$, createComponent(IconButton, {
variant: "ghost",
size: "xl",
class: TOUCH_ICON_ACTION_CLASS,
get "aria-label"() {
return activeTexts.settings.uiControlsLabel;
},
"aria-haspopup": "menu",
get "aria-expanded"() {
return open();
},
get title() {
return activeTexts.settings.uiControlsLabel;
},
onClick: (event) => {
event.stopPropagation(), setOpen((value) => !value);
},
get children() {
return createComponent(Icon2, {
name: "palette",
size: TOUCH_TOP_BAR_ICON_SIZE,
strokeWidth: 1.75
});
}
}), null), insert(_el$, createComponent(Show, {
get when() {
return open();
},
get children() {
return createComponent(Popover, {
contains: (target) => root.contains(target),
onOutsidePress: () => setOpen(!1),
class: "absolute top-[calc(100%+var(--ui-space-xs))] left-0 flex ui-gap-xs ui-p-xs",
get classList() {
return {
"!left-auto right-0 flex-row-reverse": props.leftHandedControls.enabled()
};
},
role: "menu",
get children() {
return [createComponent(IconButton, {
variant: "ghost",
size: "xl",
class: TOUCH_ICON_ACTION_CLASS,
get "aria-label"() {
return `${activeTexts.settings.uiScaleLabel}: ${uiScaleLevel(props.uiScale.value())}`;
},
get title() {
return `${activeTexts.settings.uiScaleLabel}: ${uiScaleLevel(props.uiScale.value())}`;
},
onClick: () => props.uiScale.onChange(nextUiScale(props.uiScale.value())),
get children() {
return createComponent(Icon2, {
name: "viewport",
size: TOUCH_TOP_BAR_ICON_SIZE
});
}
}), createComponent(IconButton, {
variant: "ghost",
size: "xl",
class: TOUCH_ICON_ACTION_CLASS,
get "aria-label"() {
return activeTexts.settings.leftHandedControlsLabel;
},
get "aria-pressed"() {
return props.leftHandedControls.enabled();
},
get title() {
return activeTexts.settings.leftHandedControlsLabel;
},
onClick: () => props.leftHandedControls.onChange(!props.leftHandedControls.enabled()),
get children() {
var _el$2 = _tmpl$69();
return insert(_el$2, createComponent(Icon2, {
name: "hand",
size: TOUCH_TOP_BAR_ICON_SIZE
})), createRenderEffect(() => _el$2.classList.toggle("-scale-x-100", !!props.leftHandedControls.enabled())), _el$2;
}
}), createComponent(IconButton, {
variant: "ghost",
size: "xl",
class: TOUCH_ICON_ACTION_CLASS,
get "aria-label"() {
return activeTexts.settings.columnsLabel;
},
get "aria-pressed"() {
return memo(() => !!props.columns.available)() && props.columns.enabled();
},
get disabled() {
return !props.columns.available;
},
get title() {
return activeTexts.settings.columnsLabel;
},
onClick: () => props.columns.onChange(!props.columns.enabled()),
get children() {
return createComponent(Icon2, {
name: "pages",
get size() {
return props.columns.enabled() ? TOUCH_TOP_BAR_ICON_SIZE : TOUCH_TOP_BAR_SINGLE_COLUMN_ICON_SIZE;
}
});
}
}), createComponent(IconButton, {
variant: "ghost",
size: "xl",
class: TOUCH_ICON_ACTION_CLASS,
get "aria-label"() {
return memo(() => !!props.columns.resizeHandle?.visible())() ? activeTexts.settings.hideColumnsResizeHandle : activeTexts.settings.showColumnsResizeHandle;
},
get "aria-pressed"() {
return props.columns.resizeHandle?.visible() ?? !1;
},
get disabled() {
return !props.columns.available || !props.columns.enabled() || !props.columns.resizeHandle;
},
get title() {
return memo(() => !!props.columns.resizeHandle?.visible())() ? activeTexts.settings.hideColumnsResizeHandle : activeTexts.settings.showColumnsResizeHandle;
},
onClick: () => {
let resizeHandle = props.columns.resizeHandle;
resizeHandle && resizeHandle.onChange(!resizeHandle.visible());
},
get children() {
return _tmpl$223();
}
})];
}
});
}
}), null), _el$;
})();
}
function TouchTopBarMenu(props) {
let [open, setOpen] = createSignal(!1), [navItems, setNavItems] = createSignal([]), root, toggleMenu = () => {
setOpen((value) => {
let next = !value;
return next && setNavItems(props.source.handle.readNavigationItems()), next;
});
};
return (() => {
var _el$4 = _tmpl$316(), _ref$2 = root;
return typeof _ref$2 == "function" ? use(_ref$2, _el$4) : root = _el$4, insert(_el$4, createComponent(IconButton, {
variant: "ghost",
size: "xl",
class: TOUCH_ICON_ACTION_CLASS,
"aria-haspopup": "menu",
get "aria-expanded"() {
return open();
},
onClick: (event) => {
event.stopPropagation(), toggleMenu();
},
get children() {
return createComponent(Icon2, {
name: "menu",
size: TOUCH_TOP_BAR_ICON_SIZE
});
}
}), null), insert(_el$4, createComponent(Show, {
get when() {
return open();
},
get children() {
return createComponent(Popover, {
contains: (target) => root.contains(target),
onOutsidePress: () => setOpen(!1),
class: "absolute top-[calc(100%+var(--ui-space-xs))] right-0 flex w-max min-w-[calc(var(--ui-control-size-xl)*2.25)] max-w-[calc(100vw-var(--ui-space-md))] flex-col",
get classList() {
return {
"!right-auto left-0": props.leftHanded()
};
},
get children() {
return createComponent(For, {
get each() {
return navItems();
},
children: (item) => (() => {
var _el$5 = _tmpl$413();
return _el$5.$$click = (event) => {
event.preventDefault(), setOpen(!1), props.source.handle.activateNavigationItem(item.index);
}, insert(_el$5, () => item.label), createRenderEffect((_p$) => {
var _v$ = item.href, _v$2 = item.target ?? void 0;
return _v$ !== _p$.e && setAttribute(_el$5, "href", _p$.e = _v$), _v$2 !== _p$.t && setAttribute(_el$5, "target", _p$.t = _v$2), _p$;
}, {
e: void 0,
t: void 0
}), _el$5;
})()
});
}
});
}
}), null), _el$4;
})();
}
function TouchTopBar(props) {
return (() => {
var _el$6 = _tmpl$510(), _el$7 = _el$6.firstChild, _el$8 = _el$7.nextSibling;
return insert(_el$7, createComponent(IconLink, {
variant: "ghost",
size: "xl",
class: `${TOUCH_ICON_ACTION_CLASS} [--ehpeek-touch-top-bar-project-icon-size:var(--ui-control-size-sm)]`,
get href() {
return props.source.data.homeHref;
},
get children() {
return createComponent(Icon2, {
name: "panda-peek",
size: TOUCH_TOP_BAR_PROJECT_ICON_SIZE,
strokeWidth: 1.8
});
}
}), null), insert(_el$7, createComponent(TouchTopBarUiMenu, {
get leftHandedControls() {
return props.leftHandedControls;
},
get uiScale() {
return props.uiScale;
},
get columns() {
return props.columns;
}
}), null), insert(_el$8, createComponent(IconLink, {
variant: "ghost",
size: "xl",
class: TOUCH_ICON_ACTION_CLASS,
get href() {
return props.source.data.homeHref;
},
get children() {
return createComponent(Icon2, {
name: "search",
size: TOUCH_TOP_BAR_ICON_SIZE
});
}
}), null), insert(_el$8, createComponent(IconLink, {
variant: "ghost",
size: "xl",
class: TOUCH_ICON_ACTION_CLASS,
get href() {
return props.source.data.favoritesHref;
},
get children() {
return createComponent(Icon2, {
name: "heart",
size: TOUCH_TOP_BAR_ICON_SIZE
});
}
}), null), insert(_el$8, createComponent(Show, {
get when() {
return props.historyHref;
},
children: (historyHref) => createComponent(IconLink, {
variant: "ghost",
size: "xl",
class: TOUCH_ICON_ACTION_CLASS,
get href() {
return historyHref();
},
get children() {
return createComponent(Icon2, {
name: "history",
size: TOUCH_TOP_BAR_ICON_SIZE
});
}
})
}), null), insert(_el$8, createComponent(IconButton, {
variant: "ghost",
size: "xl",
class: TOUCH_ICON_ACTION_CLASS,
onClick: (event) => {
event.stopPropagation(), props.onSettingsMenuOpen();
},
get children() {
return createComponent(Icon2, {
name: "settings",
size: TOUCH_TOP_BAR_ICON_SIZE
});
}
}), null), insert(_el$8, createComponent(TouchTopBarMenu, {
get leftHanded() {
return props.leftHandedControls.enabled;
},
get source() {
return props.source;
}
}), null), createRenderEffect((_p$) => {
var _v$3 = !!props.leftHandedControls.enabled(), _v$4 = !!props.leftHandedControls.enabled(), _v$5 = !!props.leftHandedControls.enabled();
return _v$3 !== _p$.e && _el$6.classList.toggle("flex-row-reverse", _p$.e = _v$3), _v$4 !== _p$.t && _el$7.classList.toggle("flex-row-reverse", _p$.t = _v$4), _v$5 !== _p$.a && _el$8.classList.toggle("flex-row-reverse", _p$.a = _v$5), _p$;
}, {
e: void 0,
t: void 0,
a: void 0
}), _el$6;
})();
}
var _tmpl$69, _tmpl$223, _tmpl$316, _tmpl$413, _tmpl$510, TOUCH_TOP_BAR_ICON_SIZE, TOUCH_TOP_BAR_PROJECT_ICON_SIZE, TOUCH_TOP_BAR_SINGLE_COLUMN_ICON_SIZE, TOUCH_ICON_ACTION_CLASS, init_TopBar = __esm({
"src/components/TouchUI/TopBar.tsx"() {
"use strict";
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_solid();
init_ui2();
init_i18n2();
init_Widgets();
_tmpl$69 = /* @__PURE__ */ template("<span>"), _tmpl$223 = /* @__PURE__ */ template('<span class="flex items-center justify-center ui-gap-xs"><span class="block h-[var(--ui-icon-size-md)] w-2px rounded-full bg-current opacity-70"></span><span class="block h-[var(--ui-icon-size-md)] w-2px rounded-full bg-current opacity-70"></span><span class="block h-[var(--ui-icon-size-md)] w-2px rounded-full bg-current opacity-70">'), _tmpl$316 = /* @__PURE__ */ template("<div class=relative>"), _tmpl$413 = /* @__PURE__ */ template("<a class=ehpeek-layout-top-bar-menu-item>"), _tmpl$510 = /* @__PURE__ */ template('<nav class="relative z-ui flex box-border w-full h-[var(--ui-control-size-xl)] items-center justify-between safe-px-md ehp-color-site-surface ehp-color-site-text font-sans"><div class="flex items-center ui-gap-xs"></div><div class="flex items-center ui-gap-xs">'), TOUCH_TOP_BAR_ICON_SIZE = "var(--ehpeek-touch-top-bar-icon-size)", TOUCH_TOP_BAR_PROJECT_ICON_SIZE = "var(--ehpeek-touch-top-bar-project-icon-size)", TOUCH_TOP_BAR_SINGLE_COLUMN_ICON_SIZE = "calc(var(--ehpeek-touch-top-bar-icon-size) * 1.1)", TOUCH_ICON_ACTION_CLASS = "no-underline [touch-action:manipulation] [--ehpeek-touch-top-bar-icon-size:var(--ui-control-size-xs)]";
delegateEvents(["click"]);
}
});
// src/components/TouchUI/index.ts
var init_TouchUI = __esm({
"src/components/TouchUI/index.ts"() {
"use strict";
init_GalleryInfoPanel();
init_FavoritesPanel();
init_SearchPanel();
init_TopBar();
}
});
// src/state/events/index.ts
function dispatchReady() {
document.dispatchEvent(new Event(READY_EVENT));
}
var READY_EVENT, init_events = __esm({
"src/state/events/index.ts"() {
"use strict";
READY_EVENT = "ehpeek:ready";
}
});
// src/eh/dom/styles.css
var styles_default, init_styles = __esm({
"src/eh/dom/styles.css"() {
styles_default = `.ehpeek-external-autocomplete {
max-height: 60dvh !important;
padding-block: var(--ui-space-sm) !important;
}
.ehpeek-external-autocomplete-item {
box-sizing: border-box;
min-height: var(--ui-hit-size-lg);
padding: 0 var(--ui-space-lg) !important;
font-size: var(--ui-font-size-lg) !important;
line-height: inherit !important;
}
.ehpeek-external-autocomplete-text {
font-size: inherit !important;
line-height: inherit !important;
}
.ehpeek-external-autocomplete-item.auto-complete-item > .cn-name {
flex-grow: 1 !important;
}
/* Safari can retain pre-scaled intrinsic widths after EhPeek enlarges
highlighted flex content. */
.ehpeek-external-autocomplete-item.lolicon-autocomplete-item > .ac-main:only-child {
flex-grow: 1 !important;
text-align: left !important;
}
.ehpeek-external-autocomplete-item.lolicon-autocomplete-item > .ac-main > mark,
.ehpeek-external-autocomplete-text > mark {
display: inline-block !important;
}
/* This root mode is the single ownership signal for fitting original pages to the viewport. */
html.ehpeek-fit-to-viewport,
html.ehpeek-fit-to-viewport body {
min-width: 0 !important;
max-width: 100% !important;
overflow-x: hidden !important;
}
html.ehpeek-fit-to-viewport :is(
.ido,
.itg,
.ehpeek-expand-favorites-search
) {
box-sizing: border-box;
min-width: 0 !important;
width: 100% !important;
max-width: 100% !important;
}
html.ehpeek-fit-to-viewport #rangebar {
box-sizing: border-box;
max-width: 100% !important;
}
html.ehpeek-fit-to-viewport .searchnav {
box-sizing: border-box;
max-width: 100% !important;
overflow-x: auto;
}
html.ehpeek-fit-to-viewport > body.ehpeek-touch-gallery-page {
padding-left: 0 !important;
padding-right: 0 !important;
}
:where(html.ehpeek-fit-to-viewport)
body.ehpeek-touch-gallery-page
:is(.gm, #gdt[class]) {
box-sizing: border-box !important;
min-width: 0 !important;
width: calc(100% - (var(--touch-gallery-gutter) * 2)) !important;
max-width: none !important;
}
.ehpeek-hide-original-favorites-categories {
display: none !important;
}
:root .ehpeek-hide-original-node.ehpeek-hide-original-node {
display: none !important;
}
.ehpeek-scroll-preview-mount {
position: relative;
display: block;
box-sizing: border-box;
min-width: 0;
width: 100%;
}
.ehpeek-contain-search-results {
box-sizing: border-box;
overflow: visible;
}
.ehpeek-contain-favorites-results {
box-sizing: border-box;
overflow-x: auto;
overscroll-behavior-x: contain;
}
.ehpeek-enable-search-swipe-input {
overscroll-behavior-x: contain;
touch-action: pan-y;
}
.ehpeek-enable-search-swipe-input,
.ehpeek-enable-search-swipe-input * {
user-select: none !important;
-webkit-user-select: none !important;
}
/* Compact wide Favorites columns while preserving the original table structure. */
.ehpeek-compact-all-favorites-results {
table-layout: auto !important;
overflow-x: hidden !important;
}
.ehpeek-compact-all-favorites-results > tbody > tr > .gl2e {
width: auto !important;
overflow-wrap: anywhere !important;
}
.ehpeek-compact-all-favorites-results .glink {
white-space: normal !important;
overflow-wrap: anywhere !important;
}
.ehpeek-compact-all-favorites-results .gl4e table {
table-layout: fixed !important;
width: 100% !important;
max-width: 100% !important;
}
.ehpeek-compact-all-favorites-results .gl4e td {
min-width: 0 !important;
overflow-wrap: anywhere !important;
}
.ehpeek-compact-all-favorites-results .gl4e td.tc {
width: 4em !important;
white-space: nowrap !important;
}
.ehpeek-compact-all-favorites-results > tbody > tr > .glfe {
width: 1% !important;
white-space: nowrap !important;
}
@media (max-width: 849px) {
.ehpeek-contain-favorites-results {
table-layout: auto !important;
}
.ehpeek-contain-favorites-results > tbody > tr > .gl2e {
width: auto !important;
overflow-wrap: anywhere !important;
}
.ehpeek-contain-favorites-results .glink {
white-space: normal !important;
overflow-wrap: anywhere !important;
}
.ehpeek-contain-favorites-results .gl4e table {
table-layout: fixed !important;
width: 100% !important;
max-width: 100% !important;
}
.ehpeek-contain-favorites-results .gl4e td {
min-width: 0 !important;
overflow-wrap: anywhere !important;
}
.ehpeek-contain-favorites-results .gl4e td.tc {
width: 4em !important;
white-space: nowrap !important;
}
.ehpeek-contain-favorites-results > tbody > tr > .glfe {
width: 1% !important;
white-space: nowrap !important;
}
}
/* Present original Search rows through one shared EhPeek layout state. */
.ehpeek-layout-search-grid {
display: block !important;
table-layout: auto !important;
}
.ehpeek-layout-search-grid > tbody {
display: block !important;
}
.ehpeek-layout-search-grid.ehpeek-search-result-columns > tbody {
display: grid !important;
box-sizing: border-box !important;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
align-items: stretch;
min-width: 0 !important;
width: 100% !important;
gap: 8px;
}
.ehpeek-layout-search-grid.ehpeek-search-result-columns > tbody > tr {
box-sizing: border-box !important;
height: 100%;
min-width: 0 !important;
max-width: 100% !important;
}
.ehpeek-layout-search-grid > tbody > tr {
position: relative !important;
display: grid !important;
grid-template-columns: clamp(112px, 34%, 250px) minmax(0, 1fr) !important;
align-items: center !important;
column-gap: 0 !important;
width: 100% !important;
cursor: pointer !important;
}
.ehpeek-layout-search-grid > tbody > tr:has(> .glfe) {
grid-template-columns: clamp(112px, 34%, 250px) minmax(0, 1fr) auto !important;
}
.ehpeek-layout-search-grid > tbody > tr.ehpeek-expand-coverless-search-grid {
grid-template-columns: minmax(0, 1fr) !important;
}
.ehpeek-layout-search-grid > tbody > tr > .gl1e {
width: auto !important;
}
.ehpeek-layout-search-grid > tbody > tr > .gl2e {
box-sizing: border-box !important;
grid-column: auto;
align-self: stretch !important;
min-width: 0 !important;
width: auto !important;
height: 100% !important;
padding-left: 0 !important;
}
.ehpeek-layout-search-grid > tbody > tr.ehpeek-expand-coverless-search-grid > .gl2e {
grid-column: 1 !important;
}
.ehpeek-layout-search-grid > tbody > tr > .glfe {
width: auto !important;
margin-left: 6px !important;
}
.ehpeek-layout-search-grid > tbody > tr > .gl1e > div,
.ehpeek-layout-search-grid > tbody > tr > .gl1e img {
width: 100% !important;
height: auto !important;
}
.ehpeek-layout-search-grid > tbody > tr.ehpeek-contain-tall-search-grid-cover > .gl1e > div {
display: flex !important;
align-items: flex-start !important;
justify-content: center !important;
height: min(375px, 55dvh) !important;
}
.ehpeek-layout-search-grid > tbody > tr.ehpeek-contain-tall-search-grid-cover > .gl1e img {
width: auto !important;
max-width: 100% !important;
height: 100% !important;
object-fit: contain !important;
}
.ehpeek-layout-search-grid .gl4e {
box-sizing: border-box !important;
display: flex !important;
flex-direction: column !important;
align-items: stretch !important;
justify-content: flex-start !important;
gap: var(--ui-space-md) !important;
min-height: 0 !important;
width: 100% !important;
padding-left: 6px !important;
}
.ehpeek-layout-search-grid .gl4e:has(> .ehpeek-read-history-actions) {
display: grid !important;
grid-template-columns: minmax(0, 1fr);
grid-template-rows: auto auto minmax(0, 1fr);
}
.ehpeek-layout-search-grid .gl4e > .ehpeek-read-history-actions {
position: static !important;
align-self: end;
justify-self: stretch;
width: 100% !important;
}
.ehpeek-layout-search-grid .glink {
min-height: 0 !important;
height: auto !important;
overflow: visible !important;
overflow-wrap: anywhere !important;
white-space: normal !important;
word-break: normal !important;
text-align: left !important;
font-size: var(--ui-font-size-md) !important;
font-weight: 700 !important;
line-height: 1.35 !important;
}
.ehpeek-layout-search-grid .gl3e {
position: static !important;
display: grid !important;
grid-template-columns: max-content max-content minmax(0, 1fr);
grid-template-rows: auto auto;
align-items: center !important;
gap: var(--ui-space-xs) var(--ui-space-sm) !important;
float: none !important;
min-height: 0 !important;
width: 100% !important;
height: auto !important;
margin: 0 !important;
padding: 0 !important;
font-weight: 600 !important;
}
.ehpeek-layout-search-grid .gl3e > * {
position: static !important;
min-width: 0 !important;
width: auto !important;
height: auto !important;
margin: 0 !important;
padding: 0 !important;
font-size: var(--ui-font-size-sm) !important;
font-weight: 600 !important;
line-height: 1.3 !important;
}
.ehpeek-layout-search-grid .ehpeek-search-meta-category {
grid-column: 1;
grid-row: 1;
}
.ehpeek-layout-search-grid .ehpeek-search-meta-pages {
grid-column: 1;
grid-row: 2;
justify-self: center;
font-variant-numeric: tabular-nums;
font-weight: 700 !important;
white-space: nowrap;
}
.ehpeek-layout-search-grid .ehpeek-search-meta-posted {
position: relative !important;
top: auto !important;
right: auto !important;
bottom: auto !important;
left: auto !important;
grid-column: 2;
grid-row: 1;
text-align: center !important;
white-space: nowrap;
}
.ehpeek-layout-search-grid .ehpeek-search-meta-rating {
grid-column: 2;
grid-row: 2;
justify-self: center;
}
.ehpeek-layout-search-grid .ehpeek-search-meta-uploader {
grid-column: 3;
grid-row: 1;
width: 100% !important;
overflow: hidden;
text-overflow: ellipsis;
text-align: left !important;
white-space: nowrap;
}
.ehpeek-layout-search-grid .ehpeek-search-meta-download {
display: flex !important;
grid-column: 3;
grid-row: 2;
align-items: center !important;
align-self: center;
justify-self: start;
height: 16px !important;
line-height: 0 !important;
}
.ehpeek-layout-search-grid .ehpeek-search-meta-extra {
grid-column: 1 / -1;
justify-self: start;
text-align: left !important;
}
.ehpeek-layout-search-grid .ehpeek-search-meta-extra:has(> p) {
display: flex !important;
align-items: center;
gap: var(--ui-space-xs);
}
.ehpeek-layout-search-grid .ehpeek-search-meta-extra > p {
margin: 0 !important;
}
.ehpeek-layout-search-grid .gl3e > .ir {
width: 80px !important;
height: 16px !important;
background-repeat: no-repeat !important;
}
.ehpeek-layout-search-grid .gl3e > .gldown {
width: auto !important;
height: auto !important;
}
.ehpeek-layout-search-grid .gl3e > :is(.cn, .cs, [class*="ct"]) {
box-sizing: border-box !important;
display: inline-flex !important;
align-items: center !important;
justify-content: center !important;
width: max(72px, 6em) !important;
height: max(32px, 2.2em) !important;
padding: 0 0.6em !important;
}
.ehpeek-layout-search-grid .ehpeek-stack-search-grid-tags {
position: static !important;
flex: 0 0 auto !important;
min-height: 0 !important;
width: 100% !important;
height: auto !important;
margin: 0 !important;
padding: 0 !important;
}
.ehpeek-layout-search-grid .ehpeek-stack-search-grid-tags :is(table, tbody, tr) {
min-height: 0 !important;
height: auto !important;
margin: 0 !important;
}
.ehpeek-layout-search-grid .ehpeek-stack-search-grid-tags td {
min-height: 0 !important;
height: auto !important;
vertical-align: top !important;
}
.ehpeek-layout-search-grid .ehpeek-stack-search-grid-tags :is(.gt, .gtl, .gtw, td.tc) {
font-size: var(--ui-font-size-sm) !important;
line-height: 1.2 !important;
}
.ehpeek-layout-search-grid.ehpeek-layout-search-grid-lite {
--ehpeek-lite-cover-width: 23.8095%;
}
.ehpeek-layout-search-grid.ehpeek-layout-search-grid-lite > tbody > tr {
aspect-ratio: 3 / 1;
width: min(100%, 1134px) !important;
height: auto !important;
min-height: 0 !important;
max-height: none !important;
margin-inline: auto !important;
}
.ehpeek-layout-search-grid.ehpeek-layout-search-grid-lite
> tbody
> tr:not(.ehpeek-expand-coverless-search-grid) {
grid-template-columns:
var(--ehpeek-lite-cover-width)
minmax(0, 1fr) !important;
}
.ehpeek-layout-search-grid.ehpeek-layout-search-grid-lite
> tbody
> tr:has(> .glfe) {
grid-template-columns:
var(--ehpeek-lite-cover-width)
minmax(0, 1fr)
auto !important;
}
.ehpeek-layout-search-grid.ehpeek-layout-search-grid-lite
> tbody
> tr
> .gl1e {
box-sizing: border-box !important;
height: 100% !important;
overflow: hidden !important;
}
.ehpeek-layout-search-grid.ehpeek-layout-search-grid-lite
> tbody
> tr
> .gl1e
> div,
.ehpeek-layout-search-grid.ehpeek-layout-search-grid-lite
> tbody
> tr
> .gl1e
a {
box-sizing: border-box !important;
display: flex !important;
align-items: flex-start !important;
justify-content: center !important;
width: 100% !important;
height: 100% !important;
overflow: hidden !important;
}
.ehpeek-layout-search-grid.ehpeek-layout-search-grid-lite
> tbody
> tr
> .gl1e
img {
top: 0 !important;
width: 100% !important;
max-width: 100% !important;
height: 100% !important;
object-fit: contain !important;
object-position: top center !important;
}
.ehpeek-layout-search-grid-lite .gl4e {
gap: var(--ui-space-xs) !important;
height: 100% !important;
padding-block: var(--ui-space-xs) !important;
}
.ehpeek-layout-search-grid-lite .glink {
display: -webkit-box !important;
overflow: hidden !important;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.ehpeek-layout-search-grid-lite .ehpeek-stack-search-grid-tags {
display: flex !important;
flex: 1 1 auto !important;
flex-wrap: wrap;
align-items: flex-start;
overflow: hidden !important;
gap: var(--ui-space-xs) var(--ui-space-sm) !important;
}
.ehpeek-layout-search-grid-lite
.ehpeek-stack-search-grid-tags:not(
:has(:is(.gt, .gtl, .gtw)[style*="background"])
) {
display: none !important;
}
.ehpeek-layout-search-grid-lite
.ehpeek-stack-search-grid-tags
:is(table, tbody, tr, td) {
display: contents !important;
}
.ehpeek-layout-search-grid-lite .ehpeek-stack-search-grid-tags .tc,
.ehpeek-layout-search-grid-lite
.ehpeek-stack-search-grid-tags
:is(.gt, .gtl, .gtw) {
display: none !important;
}
.ehpeek-layout-search-grid-lite
.ehpeek-stack-search-grid-tags
:is(.gt, .gtl, .gtw)[style*="background"] {
display: inline-flex !important;
align-items: center;
}
.ehpeek-layout-search-grid-lite [data-ehpeek-lite-prefix]::before {
content: attr(data-ehpeek-lite-prefix) ":";
}
.ehpeek-cover-search-grid-row {
grid-column: 1 / 3;
grid-row: 1;
}
/* Reading state remains visual and never changes the original title text. */
.ehpeek-prefix-read-history-label::before {
box-sizing: border-box;
content: attr(data-ehpeek-history-label);
display: inline-flex;
align-items: center;
margin-right: var(--ui-space-xs);
padding: 0;
border: 0;
border-radius: 0;
outline: 0;
background: transparent;
box-shadow: none;
color: var(--color-site-accent);
vertical-align: middle;
font-weight: 700;
line-height: 1.3;
}
[data-ehpeek-read-history="visited"] {
--ehpeek-read-history-tint: color-mix(in srgb, var(--color-site-accent) 6%, transparent);
}
[data-ehpeek-read-history="reading"] {
--ehpeek-read-history-tint: color-mix(in srgb, var(--color-site-accent) 12%, transparent);
}
tr[data-ehpeek-read-history] > td:not(.glfe),
[data-ehpeek-read-history]:not(tr) {
box-shadow: inset 0 0 0 9999px var(--ehpeek-read-history-tint) !important;
}
/* Style retained Search controls without replacing their original classes. */
.ehpeek-reset-search-box-layout {
box-sizing: border-box !important;
min-width: 0 !important;
width: 100% !important;
height: auto !important;
margin: 0 !important;
padding: 0 !important;
border: 0 !important;
text-align: left !important;
font-size: var(--ui-font-size-md) !important;
}
.ehpeek-stack-search-form {
display: flex !important;
flex-direction: column !important;
gap: var(--ui-space-sm) !important;
width: 100% !important;
margin: 0 !important;
padding: 0 !important;
}
.ehpeek-overlay-search-actions {
box-sizing: border-box !important;
display: grid !important;
grid-template-columns: minmax(0, 1fr) var(--ui-control-size-xl) !important;
align-items: start !important;
gap: 0 !important;
min-width: 0 !important;
width: 100% !important;
margin: 0 !important;
padding: 0 !important;
}
.ehpeek-overlay-search-actions[data-ehpeek-has-clear="true"] {
grid-template-columns:
minmax(0, 1fr)
repeat(2, var(--ui-control-size-xl)) !important;
}
.ehpeek-expand-search-input {
appearance: none !important;
box-sizing: border-box !important;
grid-column: 1 / -1 !important;
grid-row: 1 !important;
min-width: 0 !important;
width: 100% !important;
height: var(--ui-control-size-xl) !important;
margin: 0 !important;
padding:
0
calc(var(--ui-control-size-xl) + var(--ui-space-lg))
0
var(--ui-space-md) !important;
border: 1px solid var(--color-site-border) !important;
border-radius: var(--ui-radius-sm) !important;
outline: none !important;
background: var(--color-site-elevated) !important;
color: var(--color-site-text) !important;
font-size: var(--ui-font-size-lg) !important;
line-height: 1.2 !important;
}
.ehpeek-overlay-search-actions[data-ehpeek-has-clear="true"] .ehpeek-expand-search-input {
padding-right:
calc((var(--ui-control-size-xl) * 2) + var(--ui-space-lg)) !important;
}
.ehpeek-expand-search-input:focus {
border-color: var(--color-site-accent) !important;
background: var(--color-site-elevated) !important;
box-shadow: 0 0 0 3px var(--color-site-accent-hover) !important;
}
.ehpeek-hide-original-search-action {
display: none !important;
}
.ehpeek-layout-search-categories {
width: 100% !important;
margin: 0 !important;
border-collapse: collapse !important;
}
.ehpeek-layout-search-categories[aria-hidden="true"] {
display: none !important;
}
.ehpeek-layout-search-categories > tbody {
display: grid !important;
grid-template-columns:
repeat(
auto-fit,
minmax(min(100%, calc(var(--ui-control-size-xl) * 2)), 1fr)
) !important;
gap: var(--ui-space-xs) !important;
}
.ehpeek-layout-search-categories tr {
display: contents !important;
}
.ehpeek-layout-search-categories td {
padding: 0 !important;
}
.ehpeek-layout-search-categories [id^="cat_"] {
box-sizing: border-box !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
min-width: 0 !important;
width: 100% !important;
height: var(--ui-hit-size-sm) !important;
padding-inline: var(--ui-space-sm) !important;
border: 1px solid var(--color-site-border) !important;
border-radius: var(--ui-radius-sm) !important;
color: #ffffff !important;
text-align: center !important;
white-space: nowrap !important;
font-size: var(--ui-font-size-md) !important;
font-weight: 700 !important;
line-height: 1.15 !important;
box-shadow: 0 2px 6px var(--color-shadow-control) !important;
cursor: pointer !important;
user-select: none !important;
touch-action: manipulation;
-webkit-tap-highlight-color: transparent;
transition: opacity 120ms;
}
.ehpeek-layout-search-categories [id^="cat_"]:active {
opacity: 0.7;
}
.ehpeek-layout-search-categories [id^="cat_"][data-disabled] {
opacity: 0.4;
}
.ehpeek-wrap-search-options {
display: flex !important;
flex-wrap: wrap !important;
align-items: center !important;
justify-content: flex-start !important;
gap:
var(--ui-space-xs)
var(--ui-space-sm) !important;
width: 100% !important;
padding: 0 !important;
font-size: 0 !important;
}
.ehpeek-wrap-search-options > a {
appearance: none !important;
display: inline-flex !important;
align-items: center !important;
min-height: var(--ui-hit-size-sm) !important;
padding-inline: var(--ui-space-md) !important;
border: 0 !important;
border-radius: var(--ui-radius-sm) !important;
background: transparent !important;
color: var(--color-site-accent) !important;
text-align: left !important;
text-decoration: none !important;
font: inherit !important;
font-size: var(--ui-font-size-md) !important;
font-weight: 700 !important;
line-height: 1.2 !important;
cursor: pointer !important;
touch-action: manipulation;
}
.ehpeek-wrap-search-options > a:active {
background: var(--color-site-accent-hover) !important;
}
.ehpeek-expand-search-advanced-options {
box-sizing: border-box !important;
width: 100% !important;
padding: 0 !important;
color: var(--color-site-text) !important;
}
.ehpeek-reset-search-box-layout .searchadv {
box-sizing: border-box !important;
width: 100% !important;
padding-top: var(--ui-space-sm) !important;
font-size: var(--ui-font-size-md) !important;
}
.ehpeek-reset-search-box-layout .searchadv > div,
.ehpeek-expand-file-search .searchadv > div {
flex-wrap: wrap !important;
justify-content: flex-start !important;
gap: var(--ui-space-xs) !important;
}
.ehpeek-reset-search-box-layout .searchadv > div > div,
.ehpeek-expand-file-search .searchadv > div > div {
padding: var(--ui-space-xs) !important;
}
.ehpeek-expand-file-search {
box-sizing: border-box !important;
width: 100% !important;
margin: 0 !important;
padding: var(--ui-space-sm) !important;
border: 1px solid var(--color-site-border) !important;
border-radius: var(--ui-radius-xs) !important;
background: var(--color-site-elevated) !important;
color: var(--color-site-text) !important;
text-align: left !important;
font-size: var(--ui-font-size-md) !important;
}
.ehpeek-expand-file-search form {
display: flex !important;
flex-direction: column !important;
gap: var(--ui-space-xs) !important;
}
.ehpeek-expand-file-search form > div {
padding: 0 !important;
}
/* Keep site vote-state foregrounds while applying dynamic My Tag colors. */
.ehpeek-color-my-tag {
background-color: var(--ehpeek-my-tag-background) !important;
}
.ehpeek-color-my-tag > a:not(.tup, .tdn) {
color: var(--ehpeek-my-tag-color) !important;
}
.ehpeek-expand-gallery-actions {
height: auto !important;
max-height: none !important;
overflow: visible !important;
}
.ehpeek-fit-gallery-cover {
display: block;
width: 100%;
max-width: 100%;
height: 100%;
max-height: 100%;
margin-inline: auto;
object-fit: contain;
object-position: center;
}
/* Hide original GalleryInfo content only while the TouchUI panel owns its host. */
.ehpeek-hide-original-gallery-info > :not([data-ehpeek-anchor="gallery-info"]) {
display: none !important;
}
.ehpeek-layout-gallery-action,
.ehpeek-layout-top-bar-menu-item {
box-sizing: border-box !important;
display: block !important;
position: static !important;
float: none !important;
min-height: var(--ui-hit-size-xl) !important;
width: 100% !important;
height: auto !important;
margin: 0 !important;
padding: var(--ui-space-md) var(--ui-space-lg) !important;
border: 0 !important;
border-bottom: 1px solid var(--color-site-border-subtle) !important;
background: transparent !important;
color: var(--color-site-text) !important;
text-align: left !important;
text-decoration: none !important;
white-space: normal !important;
font-size: var(--ui-font-size-md) !important;
line-height: 1.2 !important;
}
.ehpeek-hide-original-top-bar {
display: none !important;
}
.ehpeek-layout-top-bar-menu-item {
min-height: var(--ui-control-size-lg) !important;
padding: var(--ui-space-md) !important;
font-size: var(--ui-font-size-md) !important;
}
.ehpeek-layout-new-tag-form {
box-sizing: border-box !important;
display: block !important;
width: 100% !important;
height: auto !important;
padding-top: var(--ui-space-md) !important;
}
.ehpeek-layout-new-tag-form form {
display: flex !important;
align-items: center !important;
gap: var(--ui-space-sm) !important;
min-width: 0 !important;
width: 100% !important;
}
.ehpeek-layout-new-tag-form #newtagfield {
box-sizing: border-box !important;
flex: 1 1 auto !important;
min-width: 0 !important;
height: var(--ui-hit-size-md) !important;
padding-inline: var(--ui-space-md) !important;
border: 1px solid var(--color-site-border) !important;
border-radius: var(--ui-radius-xs) !important;
outline: none !important;
background: var(--color-site-surface) !important;
color: var(--color-site-text) !important;
font: inherit !important;
font-size: var(--ui-font-size-md) !important;
}
.ehpeek-layout-new-tag-form #newtagfield:focus {
border-color: var(--color-site-accent) !important;
}
.ehpeek-layout-new-tag-form #newtagbutton {
box-sizing: border-box !important;
flex: 0 0 auto !important;
height: var(--ui-hit-size-md) !important;
padding-inline: var(--ui-space-lg) !important;
border: 1px solid var(--color-site-accent) !important;
border-radius: var(--ui-radius-xs) !important;
background: var(--color-site-accent) !important;
color: var(--color-background) !important;
font: inherit !important;
font-size: var(--ui-font-size-md) !important;
font-weight: 700 !important;
cursor: pointer !important;
}
.ehpeek-layout-gallery-tag-menu {
box-sizing: border-box !important;
display: flex !important;
flex-direction: column !important;
float: none !important;
width: 100% !important;
height: auto !important;
margin: 0 !important;
padding: 0 !important;
font-size: var(--ui-font-size-md) !important;
}
.ehpeek-layout-gallery-tag-menu img {
display: none !important;
}
.ehpeek-layout-gallery-tag-menu a,
.ehpeek-layout-gallery-tag-menu-item {
box-sizing: border-box !important;
display: flex !important;
align-items: center !important;
gap: var(--ui-space-md) !important;
min-height: var(--ui-hit-size-xl) !important;
width: 100% !important;
padding: var(--ui-space-md) var(--ui-space-lg) !important;
border: 0 !important;
border-bottom: 1px solid var(--color-site-border-subtle) !important;
background: transparent !important;
color: var(--color-site-text) !important;
text-align: left !important;
text-decoration: none !important;
font: inherit !important;
font-size: var(--ui-font-size-md) !important;
cursor: pointer !important;
}
.ehpeek-enable-touch-comment-score .c5 {
white-space: nowrap !important;
}
.ehpeek-enable-touch-comment-score .c7[aria-hidden="true"] {
display: none !important;
}
.ehpeek-enable-touch-comment-score .c7[aria-hidden="false"] {
display: block !important;
}
.ehpeek-enable-preview-swipe-input {
touch-action: pan-y;
user-select: none;
}
.ehpeek-enable-preview-swipe-input img {
-webkit-user-drag: none;
}
.ehpeek-hide-original-preview-page-bars :is(.ptt, .ptb, .gpc) {
display: none !important;
}
.ehpeek-touch-gallery-summary-has-cover {
grid-template-columns:
minmax(60px, min(38%, 34dvh))
minmax(0, 1fr);
}
.ehpeek-touch-gallery-primary-actions {
grid-column: 1 / -1;
}
.ehpeek-touch-gallery-summary-container {
container-type: inline-size;
}
@container (min-width: 720px) {
.ehpeek-touch-gallery-summary {
grid-template-rows: minmax(0, 1fr) auto;
}
.ehpeek-touch-gallery-summary-cover {
grid-row: 1 / 3;
}
.ehpeek-touch-gallery-summary-details {
grid-column: 2;
grid-row: 1;
}
.ehpeek-touch-gallery-primary-actions {
grid-column: 2;
grid-row: 2;
justify-self: end;
width: min(100%, 90dvh);
}
}
.ehpeek-touch-search-panel {
container-type: inline-size;
}
/* The root state scopes original Gallery layout overrides to TouchUI pages. */
.ehpeek-touch-gallery-page {
--touch-gallery-gutter: clamp(16px, 2.5vw, 36px);
}
html.ehpeek-touch-gallery-page,
body.ehpeek-touch-gallery-page {
text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
html.ehpeek-touch-gallery-page.ehpeek-gallery-wide-layout-root,
body.ehpeek-touch-gallery-page.ehpeek-gallery-wide-layout-root {
height: 100dvh !important;
overflow-y: hidden !important;
}
body.ehpeek-touch-gallery-page.ehpeek-gallery-wide-layout-root {
padding-top: 0 !important;
padding-bottom: 0 !important;
}
body.ehpeek-touch-gallery-page {
box-sizing: border-box;
background: var(--color-site-page) !important;
font-size: var(--ui-font-size-sm) !important;
line-height: 1.35 !important;
}
body.ehpeek-touch-gallery-page #gdt[class] {
display: grid !important;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
align-items: start;
}
body.ehpeek-touch-gallery-page #gdt.ehpeek-hide-original-node {
display: none !important;
}
body.ehpeek-touch-gallery-page #gdt :is(.gdtm, .gdtl),
body.ehpeek-touch-gallery-page #gdt > div {
display: flex !important;
box-sizing: border-box !important;
min-width: 0 !important;
align-items: center !important;
justify-content: center !important;
justify-self: center;
}
body.ehpeek-touch-gallery-page #gdt a {
display: flex !important;
align-items: center;
justify-content: center;
}
body.ehpeek-touch-gallery-page #cdiv {
font-size: var(--ui-font-size-md) !important;
line-height: 1.5 !important;
}
body.ehpeek-touch-gallery-page #cdiv .c2 {
display: flex !important;
flex-wrap: wrap;
align-items: baseline;
justify-content: flex-end;
height: auto !important;
}
body.ehpeek-touch-gallery-page #cdiv .c2 > .c3 {
flex: 1 1 auto;
order: 1;
margin-right: auto;
}
body.ehpeek-touch-gallery-page #cdiv .c2 > .c5 {
order: 2;
width: auto !important;
white-space: nowrap;
}
body.ehpeek-touch-gallery-page #cdiv .c2 > .c4 {
order: 3;
width: auto !important;
white-space: nowrap;
}
body.ehpeek-touch-gallery-page #cdiv .c6 {
font-size: var(--ui-font-size-lg) !important;
line-height: 1.5 !important;
overflow-wrap: anywhere;
}
body.ehpeek-touch-gallery-page :is(
#cdiv .c3,
#cdiv .c4,
#cdiv .c5,
#cdiv .c7,
#formdiv
) {
font-size: var(--ui-font-size-sm) !important;
line-height: 1.4 !important;
}
body.ehpeek-touch-gallery-page #postnewcomment {
display: flex !important;
flex-wrap: wrap;
justify-content: center;
gap: var(--ui-space-md);
margin: var(--ui-space-lg) 0 !important;
font-size: 0 !important;
}
body.ehpeek-touch-gallery-page #postnewcomment a {
display: inline-flex !important;
min-height: var(--ui-hit-size-sm);
align-items: center;
padding: var(--ui-space-md) var(--ui-space-lg);
border: 1px solid var(--color-site-border);
border-radius: var(--ui-radius-md);
background: var(--color-site-elevated);
color: var(--color-site-accent);
font-size: var(--ui-font-size-md);
text-decoration: none;
}
body.ehpeek-touch-gallery-page #cdiv form {
display: flex !important;
flex-wrap: wrap;
gap: var(--ui-space-md);
align-items: center;
}
body.ehpeek-touch-gallery-page :is(#cdiv textarea, #commenttext) {
display: block !important;
box-sizing: border-box !important;
width: 100% !important;
min-height: calc(var(--ui-control-size-xl) * 2) !important;
flex: 1 0 100%;
padding: var(--ui-space-lg) !important;
border-radius: var(--ui-radius-md) !important;
font: inherit !important;
font-size: var(--ui-font-size-md) !important;
line-height: 1.5 !important;
}
body.ehpeek-touch-gallery-page #cdiv :is(
button,
input[type="button"],
input[type="submit"],
input[type="text"],
select
) {
box-sizing: border-box !important;
min-height: var(--ui-hit-size-sm) !important;
padding: var(--ui-space-md) var(--ui-space-lg) !important;
border-radius: var(--ui-radius-md) !important;
font: inherit !important;
font-size: var(--ui-font-size-md) !important;
}
body.ehpeek-touch-gallery-page #cdiv :is(
button,
input[type="button"],
input[type="submit"]
) {
flex: 1 1 12em;
cursor: pointer;
}
body.ehpeek-touch-gallery-page #cdiv input[type="text"] {
min-width: min(100%, 15em);
}
body.ehpeek-touch-gallery-page .ehpeek-touch-gallery-layout {
box-sizing: border-box;
position: relative;
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
grid-template-rows: minmax(0, 1fr) auto;
column-gap: var(--touch-gallery-gutter);
width: calc(100% - (var(--touch-gallery-gutter) * 2));
height: calc(100dvh - var(--ui-control-size-xl));
padding-bottom: env(safe-area-inset-bottom, 0px);
margin-inline: auto;
align-items: start;
overflow: hidden;
}
body.ehpeek-touch-gallery-page
.ehpeek-touch-gallery-layout-resizer {
pointer-events: none;
position: absolute;
z-index: 1;
grid-row: 1;
grid-column: 1 / -1;
top: 0;
right: 0;
bottom: 0;
left: 0;
min-width: 0;
}
body.ehpeek-touch-gallery-page :is(
.ehpeek-touch-gallery-layout-left,
.ehpeek-touch-gallery-layout-right
) {
grid-row: 1;
display: block;
min-width: 0;
min-height: 0;
height: 100%;
overflow-y: auto;
overscroll-behavior-y: contain;
scrollbar-width: none;
-ms-overflow-style: none;
}
body.ehpeek-touch-gallery-page
.ehpeek-touch-gallery-layout-right
> .ehpeek-scroll-preview-mount {
min-height: 0;
height: 100%;
}
body.ehpeek-touch-gallery-page :is(
.ehpeek-touch-gallery-layout-left,
.ehpeek-touch-gallery-layout-right
)::-webkit-scrollbar {
display: none;
}
body.ehpeek-touch-gallery-page .ehpeek-touch-gallery-layout :is(
.ehpeek-hide-original-gallery-info,
.gtb,
.contents,
.gpc,
#cdiv,
.ptt,
.ptb
) {
min-width: 0 !important;
width: 100% !important;
max-width: 100% !important;
}
body.ehpeek-touch-gallery-page .ehpeek-touch-gallery-layout #gdt[class] {
min-width: 0 !important;
width: 100% !important;
max-width: 100% !important;
}
body.ehpeek-touch-gallery-page
.ehpeek-touch-gallery-layout-left
> .ehpeek-hide-original-gallery-info {
padding-bottom: 0 !important;
}
body.ehpeek-touch-gallery-page
.ehpeek-touch-gallery-layout-left
.ehpeek-touch-gallery {
margin-bottom: 0;
}
body.ehpeek-touch-gallery-page .ehpeek-touch-gallery-layout > .dp {
box-sizing: border-box;
grid-row: 2;
grid-column: 1 / -1;
min-width: 0;
width: 100%;
}
`;
}
});
// ehpeek-uno-css:ehpeek:uno.css
var ehpeek_uno_default, init_ehpeek_uno = __esm({
"ehpeek-uno-css:ehpeek:uno.css"() {
ehpeek_uno_default = `/* layer: preflights */
*,::before,::after{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 rgb(0 0 0 / 0);--un-ring-shadow:0 0 rgb(0 0 0 / 0);--un-shadow-inset: ;--un-shadow:0 0 rgb(0 0 0 / 0);--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgb(147 197 253 / 0.5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: ;}::backdrop{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 rgb(0 0 0 / 0);--un-ring-shadow:0 0 rgb(0 0 0 / 0);--un-shadow-inset: ;--un-shadow:0 0 rgb(0 0 0 / 0);--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgb(147 197 253 / 0.5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: ;}
/* layer: shortcuts */
.container{width:100%;}
.container\\!{width:100% !important;}
.safe-left-lg{left:max(16px,env(safe-area-inset-left,0px));}
.safe-left-sm{left:max(8px,env(safe-area-inset-left,0px));}
.safe-right-lg{right:max(16px,env(safe-area-inset-right,0px));}
.safe-right-sm{right:max(8px,env(safe-area-inset-right,0px));}
.safe-top-sm{top:max(8px,env(safe-area-inset-top,0px));}
.z-overlay{z-index:2100;}
.z-ui{z-index:2000;}
.ui-my-sm{margin-top:var(--ui-space-sm);margin-bottom:var(--ui-space-sm);}
.ui-mb-sm{margin-bottom:var(--ui-space-sm);}
.ui-mb-xs{margin-bottom:var(--ui-space-xs);}
.ui-mt-md{margin-top:var(--ui-space-md);}
.ui-mt-xs{margin-top:var(--ui-space-xs);}
.min-h-sm{min-height:32px;}
.ui-h-md{height:var(--ui-space-md);}
.\\!ui-hit-h-sm{height:var(--ui-hit-size-sm) !important;}
.ui-hit-min-h-lg{min-height:var(--ui-hit-size-lg);}
.ui-hit-min-h-md{min-height:var(--ui-hit-size-md);}
.ui-hit-min-h-sm{min-height:var(--ui-hit-size-sm);}
.ui-hit-min-h-xl{min-height:var(--ui-hit-size-xl);}
.ui-hit-min-h-xs{min-height:var(--ui-hit-size-xs);}
.ui-hit-square-lg{width:var(--ui-hit-size-lg);height:var(--ui-hit-size-lg);}
.ui-hit-square-xs{width:var(--ui-hit-size-xs);height:var(--ui-hit-size-xs);}
.ui-hit-w-lg{width:var(--ui-hit-size-lg);}
.\\!ui-hit-w-sm{width:var(--ui-hit-size-sm) !important;}
.ui-w-md{width:var(--ui-space-md);}
.gap-sm{gap:8px;}
.ui-gap-lg{gap:var(--ui-space-lg);}
.ui-gap-md{gap:var(--ui-space-md);}
.ui-gap-sm{gap:var(--ui-space-sm);}
.ui-gap-xs{gap:var(--ui-space-xs);}
.ui-gap-x-sm{column-gap:var(--ui-space-sm);}
.ui-gap-x-xs{column-gap:var(--ui-space-xs);}
.ui-gap-y-sm{row-gap:var(--ui-space-sm);}
.ehp-color-site-border{border-color:var(--color-site-border);}
.ehp-color-spinner{border-color:var(--color-border);border-top-color:var(--color-accent);}
.ehp-color-site-border-subtle-b{border-bottom-color:var(--color-site-border-subtle);}
.ui-rounded-lg{border-radius:var(--ui-radius-lg);}
.ui-rounded-md{border-radius:var(--ui-radius-md);}
.ui-rounded-sm{border-radius:var(--ui-radius-sm);}
.ui-rounded-xl{border-radius:var(--ui-radius-xl);}
.ui-rounded-xs{border-radius:var(--ui-radius-xs);}
.focus-visible\\:ui-rounded-xs:focus-visible{border-radius:var(--ui-radius-xs);}
.ehp-color-site-elevated{background-color:var(--color-site-elevated);--un-shadow:0 8px 24px var(--un-shadow-color, var(--color-shadow-elevated));box-shadow:var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);}
.ehp-color-site-page{background-color:var(--color-site-page);}
.ehp-color-site-surface{background-color:var(--color-site-surface);}
.ui-p-lg{padding:var(--ui-space-lg);}
.ui-p-md{padding:var(--ui-space-md);}
.ui-p-sm{padding:var(--ui-space-sm);}
.ui-p-xl{padding:var(--ui-space-xl);}
.ui-p-xs{padding:var(--ui-space-xs);}
.px-sm{padding-left:8px;padding-right:8px;}
.px-xs{padding-left:4px;padding-right:4px;}
.py-sm{padding-top:8px;padding-bottom:8px;}
.ui-px-lg{padding-left:var(--ui-space-lg);padding-right:var(--ui-space-lg);}
.ui-px-md{padding-left:var(--ui-space-md);padding-right:var(--ui-space-md);}
.ui-px-sm{padding-left:var(--ui-space-sm);padding-right:var(--ui-space-sm);}
.ui-px-xl{padding-left:var(--ui-space-xl);padding-right:var(--ui-space-xl);}
.ui-px-xs{padding-left:var(--ui-space-xs);padding-right:var(--ui-space-xs);}
.ui-py-lg{padding-top:var(--ui-space-lg);padding-bottom:var(--ui-space-lg);}
.ui-py-md{padding-top:var(--ui-space-md);padding-bottom:var(--ui-space-md);}
.ui-py-sm{padding-top:var(--ui-space-sm);padding-bottom:var(--ui-space-sm);}
.ui-py-xs{padding-top:var(--ui-space-xs);padding-bottom:var(--ui-space-xs);}
.pb-sm{padding-bottom:8px;}
.pt-sm{padding-top:8px;}
.safe-pl-sm{padding-left:max(8px,env(safe-area-inset-left,0px));}
.safe-pr-sm{padding-right:max(8px,env(safe-area-inset-right,0px));}
.safe-px-md{padding-left:max(12px,env(safe-area-inset-left,0px));padding-right:max(12px,env(safe-area-inset-right,0px));}
.ui-pb-md{padding-bottom:var(--ui-space-md);}
.ui-pb-sm{padding-bottom:var(--ui-space-sm);}
.ui-pb-xs{padding-bottom:var(--ui-space-xs);}
.ui-pl-md{padding-left:var(--ui-space-md);}
.ui-pl-xs{padding-left:var(--ui-space-xs);}
.ui-pr-sm{padding-right:var(--ui-space-sm);}
.ui-pt-lg{padding-top:var(--ui-space-lg);}
.ui-pt-md{padding-top:var(--ui-space-md);}
.ui-pt-sm{padding-top:var(--ui-space-sm);}
.textsize-lg{font-size:var(--ui-font-size-lg);}
.textsize-md{font-size:var(--ui-font-size-md);}
.textsize-sm{font-size:var(--ui-font-size-sm);}
.textsize-xl{font-size:var(--ui-font-size-xl);}
.ehp-color-site-accent{color:var(--color-site-accent);}
.ehp-color-site-text{color:var(--color-site-text);}
html:has(#ehpeek-ui-state.ehpeek-pointer-mouse) .ehpeek-ui-root .hover\\:ehp-color-site-accent:hover{color:var(--color-site-accent);}
@media (min-width: 640px){
.container{max-width:640px;}
.container\\!{max-width:640px !important;}
}
@media (min-width: 768px){
.container{max-width:768px;}
.container\\!{max-width:768px !important;}
}
@media (min-width: 1024px){
.container{max-width:1024px;}
.container\\!{max-width:1024px !important;}
}
@media (min-width: 1280px){
.container{max-width:1280px;}
.container\\!{max-width:1280px !important;}
}
@media (min-width: 1536px){
.container{max-width:1536px;}
.container\\!{max-width:1536px !important;}
}
/* layer: default */
.\\[--ehpeek-touch-search-icon-size\\:var\\(--ui-icon-size-lg\\)\\]{--ehpeek-touch-search-icon-size:var(--ui-icon-size-lg);}
.\\[--ehpeek-touch-top-bar-icon-size\\:var\\(--ui-control-size-xs\\)\\]{--ehpeek-touch-top-bar-icon-size:var(--ui-control-size-xs);}
.\\[--ehpeek-touch-top-bar-project-icon-size\\:var\\(--ui-control-size-sm\\)\\]{--ehpeek-touch-top-bar-project-icon-size:var(--ui-control-size-sm);}
.\\[--scroll-preview-height\\:100\\%\\]{--scroll-preview-height:100%;}
.\\[--scroll-preview-height\\:100svh\\]{--scroll-preview-height:100svh;}
.\\[-webkit-overflow-scrolling\\:touch\\]{-webkit-overflow-scrolling:touch;}
.\\[-webkit-tap-highlight-color\\:transparent\\]{-webkit-tap-highlight-color:transparent;}
.\\[contain\\:inline-size\\]{contain:inline-size;}
.\\[container-type\\:inline-size\\],
.\\@container{container-type:inline-size;}
.\\[direction\\:ltr\\]{direction:ltr;}
.\\[direction\\:rtl\\]{direction:rtl;}
.\\[font-size\\:0\\.9em\\]{font-size:0.9em;}
.\\[font-size\\:1\\.05em\\]{font-size:1.05em;}
.\\[font-size\\:var\\(--ui-font-size-lg\\)\\]{font-size:var(--ui-font-size-lg);}
.\\[font-size\\:var\\(--ui-font-size-md\\)\\]{font-size:var(--ui-font-size-md);}
.\\[font-size\\:var\\(--ui-font-size-sm\\)\\]{font-size:var(--ui-font-size-sm);}
.\\[overflow-wrap\\:anywhere\\],
.break-anywhere{overflow-wrap:anywhere;}
.\\[touch-action\\:manipulation\\]{touch-action:manipulation;}
.\\[touch-action\\:none\\],
.touch-none{touch-action:none;}
.pointer-events-auto{pointer-events:auto;}
.pointer-events-none{pointer-events:none;}
.visible{visibility:visible;}
.invisible{visibility:hidden;}
.absolute{position:absolute;}
.fixed{position:fixed;}
.relative{position:relative;}
.static{position:static;}
.inset-0{inset:0;}
.inset-y-0{top:0;bottom:0;}
.\\!left-auto{left:auto !important;}
.\\!right-auto{right:auto !important;}
.bottom-\\[calc\\(max\\(16px\\,env\\(safe-area-inset-bottom\\,0px\\)\\)_\\+_var\\(--ui-hit-size-lg\\)_\\+_var\\(--ui-space-md\\)\\)\\]{bottom:calc(max(16px,env(safe-area-inset-bottom,0px)) + var(--ui-hit-size-lg) + var(--ui-space-md));}
.left-0{left:0;}
.left-1\\/2{left:50%;}
.right-0{right:0;}
.top-\\[calc\\(100\\%\\+var\\(--ui-space-xs\\)\\)\\]{top:calc(100% + var(--ui-space-xs));}
.top-\\[calc\\(var\\(--ui-control-size-md\\)\\+var\\(--ui-space-sm\\)\\)\\]{top:calc(var(--ui-control-size-md) + var(--ui-space-sm));}
.top-0{top:0;}
.top-1\\/2{top:50%;}
.top-full{top:100%;}
.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;}
.line-clamp-3{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;line-clamp:3;}
.line-clamp-4{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:4;line-clamp:4;}
.z-\\[2150\\]{z-index:2150;}
.z-\\[2200\\]{z-index:2200;}
.z-\\[800\\]{z-index:800;}
.z-1{z-index:1;}
.z-2{z-index:2;}
.grid{display:grid;}
.col-start-2{grid-column-start:2;}
.col-start-3{grid-column-start:3;}
.row-start-1{grid-row-start:1;}
.grid-cols-\\[1fr_1fr\\]{grid-template-columns:1fr 1fr;}
.grid-cols-\\[max-content_minmax\\(0\\,1fr\\)\\]{grid-template-columns:max-content minmax(0,1fr);}
.grid-cols-\\[repeat\\(3\\,minmax\\(0\\,1fr\\)\\)\\],
.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr));}
.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr));}
.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr));}
.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr));}
.m-0{margin:0;}
.mx-auto{margin-left:auto;margin-right:auto;}
.mb-0{margin-bottom:0;}
.mb-10px{margin-bottom:10px;}
.ml-auto{margin-left:auto;}
.mt-0{margin-top:0;}
.mt-2px{margin-top:2px;}
.mt-auto{margin-top:auto;}
.box-border{box-sizing:border-box;}
.inline{display:inline;}
.block{display:block;}
.inline-block{display:inline-block;}
.contents{display:contents;}
.hidden{display:none;}
.aspect-\\[2\\/3\\]{aspect-ratio:2/3;}
.\\[\\&_\\.ehpeek-icon\\]\\:h-\\[var\\(--ui-icon-size-lg\\)\\] .ehpeek-icon{height:var(--ui-icon-size-lg);}
.\\[\\&_\\.ehpeek-icon\\]\\:w-\\[var\\(--ui-icon-size-lg\\)\\] .ehpeek-icon{width:var(--ui-icon-size-lg);}
.h-\\[calc\\(var\\(--ui-control-size-xs\\)\\*8\\)\\]{height:calc(var(--ui-control-size-xs) * 8);}
.h-\\[var\\(--ui-control-size-md\\)\\]{height:var(--ui-control-size-md);}
.h-\\[var\\(--ui-control-size-xl\\)\\]{height:var(--ui-control-size-xl);}
.h-\\[var\\(--ui-icon-size-md\\)\\]{height:var(--ui-icon-size-md);}
.h-\\[var\\(--ui-icon-size-xl\\)\\]{height:var(--ui-icon-size-xl);}
.h-15px{height:15px;}
.h-full{height:100%;}
.h1{height:0.25rem;}
.max-h-\\[60dvh\\]{max-height:60dvh;}
.max-h-\\[70\\%\\]{max-height:70%;}
.max-h-\\[calc\\(100dvh-\\(var\\(--ui-space-lg\\)\\*2\\)\\)\\]{max-height:calc(100dvh - (var(--ui-space-lg) * 2));}
.max-h-\\[calc\\(100dvh-16px\\)\\]{max-height:calc(100dvh - 16px);}
.max-h-240px{max-height:240px;}
.max-h-full{max-height:100%;}
.max-w-\\[calc\\(100vw-16px\\)\\]{max-width:calc(100vw - 16px);}
.max-w-\\[calc\\(100vw-var\\(--ui-space-md\\)\\)\\]{max-width:calc(100vw - var(--ui-space-md));}
.max-w-\\[calc\\(var\\(--ui-control-size-xl\\)\\*5\\.25\\)\\]{max-width:calc(var(--ui-control-size-xl) * 5.25);}
.max-w-960px{max-width:960px;}
.max-w-full{max-width:100%;}
.min-h-\\[calc\\(var\\(--ui-control-size-xl\\)\\*3\\)\\]{min-height:calc(var(--ui-control-size-xl) * 3);}
.min-h-\\[clamp\\(130px\\,21vh\\,170px\\)\\]{min-height:clamp(130px,21vh,170px);}
.min-h-\\[var\\(--ui-control-size-lg\\)\\]{min-height:var(--ui-control-size-lg);}
.min-h-\\[var\\(--ui-control-size-md\\)\\]{min-height:var(--ui-control-size-md);}
.min-h-\\[var\\(--ui-control-size-sm\\)\\]{min-height:var(--ui-control-size-sm);}
.min-h-\\[var\\(--ui-control-size-xl\\)\\]{min-height:var(--ui-control-size-xl);}
.min-h-0{min-height:0;}
.min-w-\\[calc\\(var\\(--ui-control-size-xl\\)\\*2\\.25\\)\\]{min-width:calc(var(--ui-control-size-xl) * 2.25);}
.min-w-\\[calc\\(var\\(--ui-control-size-xl\\)\\*2\\)\\]{min-width:calc(var(--ui-control-size-xl) * 2);}
.min-w-0{min-width:0;}
.w-\\[65\\%\\]{width:65%;}
.w-\\[calc\\(100\\%_-_\\(var\\(--ui-space-sm\\)\\*2\\)\\)\\]{width:calc(100% - (var(--ui-space-sm) * 2));}
.w-\\[calc\\(100\\%-\\(var\\(--touch-gallery-gutter\\)\\*2\\)\\)\\]{width:calc(100% - (var(--touch-gallery-gutter) * 2));}
.w-\\[calc\\(100\\%-32px\\)\\]{width:calc(100% - 32px);}
.w-\\[calc\\(var\\(--ui-control-size-xl\\)\\*6\\)\\]{width:calc(var(--ui-control-size-xl) * 6);}
.w-\\[min\\(78vw\\,calc\\(var\\(--ui-control-size-xl\\)\\*4\\)\\)\\]{width:min(78vw,calc(var(--ui-control-size-xl) * 4));}
.w-\\[var\\(--ui-control-size-md\\)\\]{width:var(--ui-control-size-md);}
.w-\\[var\\(--ui-control-size-sm\\)\\]{width:var(--ui-control-size-sm);}
.w-\\[var\\(--ui-control-size-xl\\)\\]{width:var(--ui-control-size-xl);}
.w-\\[var\\(--ui-icon-size-md\\)\\]{width:var(--ui-icon-size-md);}
.w-\\[var\\(--ui-icon-size-xl\\)\\]{width:var(--ui-icon-size-xl);}
.w-15px{width:15px;}
.w-16px{width:16px;}
.w-2px{width:2px;}
.w-full{width:100%;}
.w-max{width:max-content;}
.flex{display:flex;}
.inline-flex{display:inline-flex;}
.flex-1{flex:1 1 0%;}
.flex-none{flex:none;}
.flex-grow{flex-grow:1;}
.flex-row-reverse{flex-direction:row-reverse;}
.flex-col{flex-direction:column;}
.flex-wrap{flex-wrap:wrap;}
.table{display:table;}
.border-collapse{border-collapse:collapse;}
.border-separate{border-collapse:separate;}
.border-spacing-\\[var\\(--ui-space-xs\\)\\]{--un-border-spacing-x:var(--ui-space-xs);--un-border-spacing-y:var(--ui-space-xs);border-spacing:var(--un-border-spacing-x) var(--un-border-spacing-y);}
.-translate-x-1\\/2{--un-translate-x:-50%;transform:translateX(var(--un-translate-x)) translateY(var(--un-translate-y)) translateZ(var(--un-translate-z)) rotate(var(--un-rotate)) rotateX(var(--un-rotate-x)) rotateY(var(--un-rotate-y)) rotateZ(var(--un-rotate-z)) skewX(var(--un-skew-x)) skewY(var(--un-skew-y)) scaleX(var(--un-scale-x)) scaleY(var(--un-scale-y)) scaleZ(var(--un-scale-z));}
.-translate-y-1\\/2{--un-translate-y:-50%;transform:translateX(var(--un-translate-x)) translateY(var(--un-translate-y)) translateZ(var(--un-translate-z)) rotate(var(--un-rotate)) rotateX(var(--un-rotate-x)) rotateY(var(--un-rotate-y)) rotateZ(var(--un-rotate-z)) skewX(var(--un-skew-x)) skewY(var(--un-skew-y)) scaleX(var(--un-scale-x)) scaleY(var(--un-scale-y)) scaleZ(var(--un-scale-z));}
.rotate-90{--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-rotate:90deg;transform:translateX(var(--un-translate-x)) translateY(var(--un-translate-y)) translateZ(var(--un-translate-z)) rotate(var(--un-rotate)) rotateX(var(--un-rotate-x)) rotateY(var(--un-rotate-y)) rotateZ(var(--un-rotate-z)) skewX(var(--un-skew-x)) skewY(var(--un-skew-y)) scaleX(var(--un-scale-x)) scaleY(var(--un-scale-y)) scaleZ(var(--un-scale-z));}
.active\\:scale-96:active{--un-scale-x:0.96;--un-scale-y:0.96;transform:translateX(var(--un-translate-x)) translateY(var(--un-translate-y)) translateZ(var(--un-translate-z)) rotate(var(--un-rotate)) rotateX(var(--un-rotate-x)) rotateY(var(--un-rotate-y)) rotateZ(var(--un-rotate-z)) skewX(var(--un-skew-x)) skewY(var(--un-skew-y)) scaleX(var(--un-scale-x)) scaleY(var(--un-scale-y)) scaleZ(var(--un-scale-z));}
.active\\:scale-98:active{--un-scale-x:0.98;--un-scale-y:0.98;transform:translateX(var(--un-translate-x)) translateY(var(--un-translate-y)) translateZ(var(--un-translate-z)) rotate(var(--un-rotate)) rotateX(var(--un-rotate-x)) rotateY(var(--un-rotate-y)) rotateZ(var(--un-rotate-z)) skewX(var(--un-skew-x)) skewY(var(--un-skew-y)) scaleX(var(--un-scale-x)) scaleY(var(--un-scale-y)) scaleZ(var(--un-scale-z));}
.enabled\\:active\\:scale-96:active:enabled{--un-scale-x:0.96;--un-scale-y:0.96;transform:translateX(var(--un-translate-x)) translateY(var(--un-translate-y)) translateZ(var(--un-translate-z)) rotate(var(--un-rotate)) rotateX(var(--un-rotate-x)) rotateY(var(--un-rotate-y)) rotateZ(var(--un-rotate-z)) skewX(var(--un-skew-x)) skewY(var(--un-skew-y)) scaleX(var(--un-scale-x)) scaleY(var(--un-scale-y)) scaleZ(var(--un-scale-z));}
.-scale-x-100{--un-scale-x:-1;transform:translateX(var(--un-translate-x)) translateY(var(--un-translate-y)) translateZ(var(--un-translate-z)) rotate(var(--un-rotate)) rotateX(var(--un-rotate-x)) rotateY(var(--un-rotate-y)) rotateZ(var(--un-rotate-z)) skewX(var(--un-skew-x)) skewY(var(--un-skew-y)) scaleX(var(--un-scale-x)) scaleY(var(--un-scale-y)) scaleZ(var(--un-scale-z));}
@keyframes spin{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}
.animate-spin{animation:spin 1s linear infinite;}
.cursor-default{cursor:default;}
.disabled\\:cursor-default:disabled{cursor:default;}
.cursor-pointer{cursor:pointer;}
.cursor-ew-resize{cursor:ew-resize;}
.touch-pan-y{--un-pan-y:pan-y;touch-action:var(--un-pan-x) var(--un-pan-y) var(--un-pinch-zoom);}
.select-text{-webkit-user-select:text;user-select:text;}
.\\[\\&\\[data-dragging\\=true\\]\\]\\:select-none[data-dragging=true],
.select-none{-webkit-user-select:none;user-select:none;}
.resize-y{resize:vertical;}
.resize{resize:both;}
.appearance-none{-webkit-appearance:none;appearance:none;}
.items-start{align-items:flex-start;}
.items-end{align-items:flex-end;}
.items-center{align-items:center;}
.items-stretch{align-items:stretch;}
.self-end{align-self:flex-end;}
.self-center{align-self:center;}
.self-stretch{align-self:stretch;}
.justify-end{justify-content:flex-end;}
.justify-center{justify-content:center;}
.justify-between{justify-content:space-between;}
.justify-self-stretch{justify-self:stretch;}
.gap-1px{gap:1px;}
.overflow-hidden{overflow:hidden;}
.overflow-visible{overflow:visible;}
.overflow-x-auto{overflow-x:auto;}
.overflow-x-hidden{overflow-x:hidden;}
.overflow-y-auto{overflow-y:auto;}
.overscroll-contain{overscroll-behavior:contain;}
.overscroll-x-contain{overscroll-behavior-x:contain;}
.text-ellipsis{text-overflow:ellipsis;}
.whitespace-normal{white-space:normal;}
.whitespace-nowrap{white-space:nowrap;}
.break-normal{overflow-wrap:normal;word-break:normal;}
.\\!border{border-width:1px !important;}
.border{border-width:1px;}
.border-0{border-width:0px;}
.border-4{border-width:4px;}
.border-y{border-top-width:1px;border-bottom-width:1px;}
.border-b{border-bottom-width:1px;}
.border-l{border-left-width:1px;}
.border-l-6{border-left-width:6px;}
.border-r-6{border-right-width:6px;}
.border-t{border-top-width:1px;}
.last\\:border-b-0:last-child{border-bottom-width:0px;}
.\\!border-transparent{border-color:transparent !important;}
.border-\\[var\\(--color-site-accent\\)\\]{border-color:var(--color-site-accent);}
.border-\\[var\\(--color-site-border-subtle\\)\\]{border-color:var(--color-site-border-subtle);}
.border-\\[var\\(--color-site-page\\)\\]{border-color:var(--color-site-page);}
html:has(#ehpeek-ui-state.ehpeek-pointer-mouse) .ehpeek-ui-root .hover\\:border-\\[var\\(--color-site-border\\)\\]:hover{border-color:var(--color-site-border);}
.border-t-\\[var\\(--color-site-border-subtle\\)\\]{border-top-color:var(--color-site-border-subtle);}
.rounded{border-radius:0.25rem;}
.rounded-3px{border-radius:3px;}
.rounded-full{border-radius:9999px;}
.border-solid{border-style:solid;}
.\\!bg-\\[color-mix\\(in_srgb\\,var\\(--color-site-page\\)_82\\%\\,black\\)\\]{background-color:color-mix(in srgb,var(--color-site-page) 82%,black) !important;}
.\\!bg-transparent,
.\\[\\&_\\*\\]\\:\\!bg-transparent *{background-color:transparent !important;}
.bg-\\[var\\(--color-loading\\)\\]{background-color:var(--color-loading);}
.bg-\\[var\\(--color-site-accent-hover\\)\\]{background-color:var(--color-site-accent-hover);}
.bg-\\[var\\(--color-site-accent\\)\\]{background-color:var(--color-site-accent);}
.bg-\\[var\\(--color-site-elevated\\)\\]{background-color:var(--color-site-elevated);}
.bg-\\[var\\(--color-site-item-hover\\)\\]{background-color:var(--color-site-item-hover);}
.bg-\\[var\\(--color-site-surface\\)\\]{background-color:var(--color-site-surface);}
.bg-\\[var\\(--color-state-off\\)\\]{background-color:var(--color-state-off);}
.bg-\\[var\\(--color-state-on\\)\\]{background-color:var(--color-state-on);}
.bg-black\\/65{background-color:rgb(0 0 0 / 0.65);}
.bg-current{background-color:currentColor;}
.bg-transparent{background-color:transparent;}
html:has(#ehpeek-ui-state.ehpeek-pointer-mouse) .ehpeek-ui-root .hover\\:\\!bg-\\[var\\(--color-site-item-hover\\)\\]:hover{background-color:var(--color-site-item-hover) !important;}
html:has(#ehpeek-ui-state.ehpeek-pointer-mouse) .ehpeek-ui-root .hover\\:bg-\\[var\\(--color-site-accent-hover\\)\\]:hover{background-color:var(--color-site-accent-hover);}
html:has(#ehpeek-ui-state.ehpeek-pointer-mouse) .ehpeek-ui-root .hover\\:bg-\\[var\\(--color-site-item-hover\\)\\]:hover{background-color:var(--color-site-item-hover);}
.active\\:\\!bg-\\[var\\(--color-site-item-hover\\)\\]:active{background-color:var(--color-site-item-hover) !important;}
.active\\:bg-\\[var\\(--color-site-accent-hover\\)\\]:active{background-color:var(--color-site-accent-hover);}
.active\\:bg-\\[var\\(--color-site-item-hover\\)\\]:active{background-color:var(--color-site-item-hover);}
.bg-no-repeat{background-repeat:no-repeat;}
.\\!p-0{padding:0 !important;}
.p-0{padding:0;}
.px{padding-left:1rem;padding-right:1rem;}
.py-0{padding-top:0;padding-bottom:0;}
.pb-2px{padding-bottom:2px;}
.pt-1px{padding-top:1px;}
.pt-2px{padding-top:2px;}
.text-center{text-align:center;}
.text-left{text-align:left;}
.text-right{text-align:right;}
.align-middle{vertical-align:middle;}
.\\!text-\\[var\\(--color-site-text\\)\\]{color:var(--color-site-text) !important;}
.text-\\[var\\(--color-muted\\)\\]{color:var(--color-muted);}
.text-\\[var\\(--color-rating-submitted\\)\\]{color:var(--color-rating-submitted);}
.text-\\[var\\(--color-site-accent\\)\\]{color:var(--color-site-accent);}
.text-\\[var\\(--color-site-surface\\)\\]{color:var(--color-site-surface);}
.text-\\[var\\(--color-site-text\\)\\]{color:var(--color-site-text);}
.visited\\:\\!text-\\[var\\(--color-site-text\\)\\]:visited{color:var(--color-site-text) !important;}
html:has(#ehpeek-ui-state.ehpeek-pointer-mouse) .ehpeek-ui-root .hover\\:\\!text-\\[var\\(--color-site-text\\)\\]:hover{color:var(--color-site-text) !important;}
.active\\:\\!text-\\[var\\(--color-site-text\\)\\]:active{color:var(--color-site-text) !important;}
.\\[\\&_\\*\\]\\:\\!text-inherit *{color:inherit !important;}
.font-400{font-weight:400;}
.font-600{font-weight:600;}
.font-700{font-weight:700;}
.leading-\\[1\\.1\\]{line-height:1.1;}
.leading-\\[1\\.15\\]{line-height:1.15;}
.leading-\\[1\\.16\\]{line-height:1.16;}
.leading-\\[1\\.2\\]{line-height:1.2;}
.leading-\\[1\\.35\\]{line-height:1.35;}
.leading-\\[1\\.4\\]{line-height:1.4;}
.leading-1{line-height:0.25rem;}
.leading-none{line-height:1;}
.font-inherit{font-family:inherit;}
.font-sans{font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";}
.uppercase{text-transform:uppercase;}
.lowercase{text-transform:lowercase;}
.normal-case{text-transform:none;}
.tabular-nums{--un-numeric-spacing:tabular-nums;font-variant-numeric:var(--un-ordinal) var(--un-slashed-zero) var(--un-numeric-figure) var(--un-numeric-spacing) var(--un-numeric-fraction);}
html:has(#ehpeek-ui-state.ehpeek-pointer-mouse) .ehpeek-ui-root .hover\\:underline:hover{text-decoration-line:underline;}
.active\\:underline:active{text-decoration-line:underline;}
.no-underline{text-decoration:none;}
html:has(#ehpeek-ui-state.ehpeek-pointer-mouse) .ehpeek-ui-root .hover\\:no-underline:hover{text-decoration:none;}
.active\\:no-underline:active{text-decoration:none;}
.tab{-moz-tab-size:4;-o-tab-size:4;tab-size:4;}
.opacity-0{opacity:0;}
.opacity-100{opacity:1;}
.opacity-40{opacity:0.4;}
.opacity-70{opacity:0.7;}
.opacity-72{opacity:0.72;}
.opacity-75{opacity:0.75;}
.opacity-78{opacity:0.78;}
.opacity-82{opacity:0.82;}
.disabled\\:opacity-40:disabled{opacity:0.4;}
.disabled\\:opacity-50:disabled{opacity:0.5;}
.shadow-\\[0_1px_4px_var\\(--color-shadow-control\\)\\]{--un-shadow:0 1px 4px var(--un-shadow-color, var(--color-shadow-control));box-shadow:var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);}
.shadow-\\[0_2px_10px_var\\(--color-shadow-panel\\)\\]{--un-shadow:0 2px 10px var(--un-shadow-color, var(--color-shadow-panel));box-shadow:var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);}
.shadow-\\[0_2px_8px_var\\(--color-shadow-panel\\)\\]{--un-shadow:0 2px 8px var(--un-shadow-color, var(--color-shadow-panel));box-shadow:var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);}
.shadow-\\[0_4px_14px_var\\(--color-shadow-floating\\)\\]{--un-shadow:0 4px 14px var(--un-shadow-color, var(--color-shadow-floating));box-shadow:var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);}
.shadow-\\[0_6px_20px_var\\(--color-shadow-floating\\)\\]{--un-shadow:0 6px 20px var(--un-shadow-color, var(--color-shadow-floating));box-shadow:var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);}
.shadow-\\[0_8px_24px_var\\(--color-shadow-panel\\)\\]{--un-shadow:0 8px 24px var(--un-shadow-color, var(--color-shadow-panel));box-shadow:var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);}
.shadow-none{--un-shadow:0 0 var(--un-shadow-color, rgb(0 0 0 / 0));box-shadow:var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);}
.shadow-xl{--un-shadow:var(--un-shadow-inset) 0 20px 25px -5px var(--un-shadow-color, rgb(0 0 0 / 0.1)),var(--un-shadow-inset) 0 8px 10px -6px var(--un-shadow-color, rgb(0 0 0 / 0.1));box-shadow:var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);}
.focus-visible\\:outline-2:focus-visible{outline-width:2px;}
.focus-visible\\:outline-\\[var\\(--color-site-accent\\)\\]:focus-visible{outline-color:var(--color-site-accent);}
.focus-visible\\:outline-offset-3px:focus-visible{outline-offset:3px;}
.outline{outline-style:solid;}
.focus-visible\\:outline:focus-visible{outline-style:solid;}
html:has(#ehpeek-ui-state.ehpeek-pointer-mouse) .ehpeek-ui-root .hover\\:brightness-108:hover{--un-brightness:brightness(1.08);filter:var(--un-blur) var(--un-brightness) var(--un-contrast) var(--un-drop-shadow) var(--un-grayscale) var(--un-hue-rotate) var(--un-invert) var(--un-saturate) var(--un-sepia);}
.filter{filter:var(--un-blur) var(--un-brightness) var(--un-contrast) var(--un-drop-shadow) var(--un-grayscale) var(--un-hue-rotate) var(--un-invert) var(--un-saturate) var(--un-sepia);}
.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;}
.transition-\\[background-color\\,color\\]{transition-property:background-color,color;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;}
.transition-\\[background-color\\,transform\\]{transition-property:background-color,transform;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;}
.transition-\\[border-color\\,background-color\\,color\\]{transition-property:border-color,background-color,color;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;}
.transition-\\[filter\\,transform\\,box-shadow\\]{transition-property:filter,transform,box-shadow;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;}
.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;}
.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;}
.duration-120{transition-duration:120ms;}
@container (max-width: 540px){
.search-panel-compact\\:block{display:block;}
}`;
}
});
// src/theme.css
var theme_default2, init_theme = __esm({
"src/theme.css"() {
theme_default2 = `:is(.ehpeek-ui-root, body.ehpeek-touch-gallery-page) {
--color-rating-submitted: #8595ff;
--color-site-favorite-0: #646464;
--color-site-favorite-1: #ff6868;
--color-site-favorite-2: #ffa561;
--color-site-favorite-3: #fff56b;
--color-site-favorite-4: #68ff8b;
--color-site-favorite-5: #cdff84;
--color-site-favorite-6: #8afeff;
--color-site-favorite-7: #7268ff;
--color-site-favorite-8: #ac57fe;
--color-site-favorite-9: #fe50c8;
}
html:has(#ehpeek-ui-state.ehpeek-site-e-hentai)
:is(.ehpeek-ui-root, body.ehpeek-touch-gallery-page) {
--color-site-page: #e3e0d1;
--color-site-surface: #edebdf;
--color-site-elevated: #f3f0e0;
--color-site-text: #5c0d11;
--color-site-accent: #8f4701;
--color-site-border: #5c0d12;
}
html:has(#ehpeek-ui-state.ehpeek-site-exhentai)
:is(.ehpeek-ui-root, body.ehpeek-touch-gallery-page) {
--color-site-page: #34353b;
--color-site-surface: #4f535b;
--color-site-elevated: #3f4249;
--color-site-text: #f1f1f1;
--color-site-accent: #f0b35a;
--color-site-border: #8d7454;
}
.ehpeek-ui-root {
-webkit-tap-highlight-color: transparent;
}
.ehpeek-ui-root [data-ehpeek-pressed="true"] {
opacity: 0.72;
}
html:has(#ehpeek-ui-state.ehpeek-pointer-mouse) .ehpeek-ui-root :is(
a[href],
button,
input[type="button"],
input[type="submit"],
[role="button"],
[role="tab"]
):not(:disabled, [aria-disabled="true"], .cursor-default):hover {
filter: brightness(1.08);
cursor: pointer;
}
html:has(#ehpeek-ui-state.ehpeek-pointer-mouse)
.ehpeek-ui-root
[data-ehpeek-pressable="true"]:hover {
background-image: linear-gradient(rgb(255 255 255 / 8%) 0 0);
cursor: pointer;
}
`;
}
});
// src/userscript.ts
function startUserscriptDownload(details) {
let failureReported = !1, reportFailure = (error) => {
failureReported || (failureReported = !0, details.onerror?.(error));
}, apiDetails = {
url: details.url,
...details.name ? { name: details.name } : {},
onerror: reportFailure
};
try {
if (GM.download)
return Promise.resolve(GM.download(apiDetails)).catch(reportFailure), !0;
if (typeof GM_download == "function")
return GM_download(apiDetails), !0;
} catch (error) {
return reportFailure(error), !1;
}
return reportFailure(new Error("Userscript download API is unavailable.")), !1;
}
var init_userscript = __esm({
"src/userscript.ts"() {
"use strict";
}
});
// src/App/ReadingProgressSession.ts
var SAVE_DELAY_MS, ReadingProgressSession, init_ReadingProgressSession = __esm({
"src/App/ReadingProgressSession.ts"() {
"use strict";
init_solid();
SAVE_DELAY_MS = 1e4, ReadingProgressSession = class {
constructor(target, initial) {
this.target = target;
this.pending = null;
this.lastSaved = null;
this.saving = null;
this.timer = null;
this.flush = () => (this.timer !== null && (window.clearTimeout(this.timer), this.timer = null), this.saving ? this.saving.then(() => this.flush()) : this.pending ? (this.saving = this.savePending(this.pending).finally(() => {
this.saving = null;
}), this.saving) : Promise.resolve());
this.onVisibilityChange = () => {
document.visibilityState === "hidden" && this.flush();
};
let [progress, setProgress] = createSignal(initial);
this.progress = progress, this.setProgress = setProgress, window.addEventListener("pagehide", this.flush), document.addEventListener("visibilitychange", this.onVisibilityChange);
}
update(pageNum, totalPages) {
if (!pageNum || pageNum <= 0 || (this.setProgress({
currentPage: pageNum,
hasHistory: this.target !== null,
totalPages: totalPages ?? this.progress().totalPages
}), !this.target))
return;
let nextRecord = {
...this.target.record,
pageNum,
totalPages,
updatedAt: Date.now()
};
if (!this.saving && this.sameProgress(nextRecord, this.lastSaved)) {
this.pending = null;
return;
}
this.pending = nextRecord, this.schedule();
}
dispose() {
this.flush(), window.removeEventListener("pagehide", this.flush), document.removeEventListener("visibilitychange", this.onVisibilityChange);
}
async savePending(record) {
try {
this.sameProgress(record, this.lastSaved) || (this.lastSaved = await this.target?.history.save(record) ?? null), this.pending === record && (this.pending = null);
} catch (error) {
console.error("[ehpeek] Failed to save reading progress", error);
}
}
schedule() {
this.timer === null && (this.timer = window.setTimeout(this.flush, SAVE_DELAY_MS));
}
sameProgress(left, right) {
return !!(left && right && left.galleryId === right.galleryId && left.token === right.token && left.pageNum === right.pageNum && left.totalPages === right.totalPages);
}
};
}
});
// src/App/Reader.tsx
async function openOriginalReader(pageNum, previewCache) {
let page2 = (await previewCache.getPages([pageNum]))[0];
if (!page2 || page2.pageNum !== pageNum)
throw new Error(activeTexts.errors.imageNotFound);
window.location.assign(page2.url);
}
var init_Reader = __esm({
"src/App/Reader.tsx"() {
"use strict";
init_i18n2();
}
});
// src/App/ReaderContentSource.ts
function createReaderContentSource(cache, galleryId, token) {
let initial = cache.current().data, fileName = (page2, url, alternative = "") => `${galleryId}-${token}-p${page2}.${imageExtension(url) || imageExtension(alternative) || "webp"}`;
return {
totalPages: initial.totalImages,
initialPageNum: initial.startImage,
aspectRatio: initial.dominantAspectRatio,
initialPreviewItems: initial.previewItems,
getPages: cache.getPages,
getPreviewItems: cache.getPreviewItems,
loadImage: async (page2, signal) => {
let image2 = await cache.loadImage(page2, signal);
return {
...image2,
fileName: fileName(page2.pageNum ?? 1, image2.imageUrl),
originalFileName: fileName(
page2.pageNum ?? 1,
image2.originalImageUrl ?? "",
image2.imageUrl
),
byteSize: imageByteSize(image2.imageUrl)
};
}
};
}
function imageExtension(url) {
try {
let extension = decodeURIComponent(
new URL(url).pathname.split("/").pop() ?? ""
).match(/\.([a-z0-9]{2,5})$/i)?.[1]?.toLowerCase();
return extension && ["avif", "bmp", "gif", "jpeg", "jpg", "png", "webp"].includes(extension) ? extension : "";
} catch {
return "";
}
}
function imageByteSize(url) {
try {
let key = new URL(url).pathname.split("/").find((part) => /^[a-f0-9]{40}-\d+-\d+-\d+-[a-z0-9]+$/i.test(part)), bytes = Number(key?.split("-")[1]);
return Number.isSafeInteger(bytes) && bytes > 0 ? bytes : null;
} catch {
return null;
}
}
var init_ReaderContentSource = __esm({
"src/App/ReaderContentSource.ts"() {
"use strict";
}
});
// src/App/ReaderSettings.ts
function readControls(store) {
return {
navigationMode: store.navigationMode.value,
scrollDirection: store.scrollDirection.value,
pagedDirection: store.pagedDirection.value,
pageLayout: store.pageLayout.value,
rightTapAction: store.rightTapAction.value
};
}
function saveControls(store, value) {
store.navigationMode.value !== value.navigationMode && store.navigationMode.set(value.navigationMode), store.scrollDirection.value !== value.scrollDirection && store.scrollDirection.set(value.scrollDirection), store.pagedDirection.value !== value.pagedDirection && store.pagedDirection.set(value.pagedDirection), store.pageLayout.value !== value.pageLayout && store.pageLayout.set(value.pageLayout), store.rightTapAction.value !== value.rightTapAction && store.rightTapAction.set(value.rightTapAction);
}
function readerSettings() {
return {
portraitControls: readControls(state.reader.portraitControls),
landscapeControls: readControls(state.reader.landscapeControls),
scrollTtbScale: state.reader.scrollTtbScale.value,
scrollHorizontalScale: state.reader.scrollHorizontalScale.value,
leftHandedControls: state.app.leftHandedControls.value,
previewDirection: state.gallery.scrollPreviewDirection.value
};
}
function readerSettingCallbacks(onEmbeddedDirectionChange) {
return {
portraitControls: (controls) => saveControls(state.reader.portraitControls, controls),
landscapeControls: (controls) => saveControls(state.reader.landscapeControls, controls),
scrollTtbScale: (scale) => state.reader.scrollTtbScale.set(scale),
scrollHorizontalScale: (scale) => state.reader.scrollHorizontalScale.set(scale),
previewDirection: (direction) => state.gallery.scrollPreviewDirection.set(direction),
embeddedPreviewDirection: onEmbeddedDirectionChange
};
}
var init_ReaderSettings = __esm({
"src/App/ReaderSettings.ts"() {
"use strict";
init_state();
}
});
// src/App/OverlayHistory.ts
function createOverlayHistory(onBeforeBack) {
let sessionId = crypto.randomUUID();
return {
push: (depth, surface) => {
let current = window.history.state;
window.history.pushState(
{
...current !== null && typeof current == "object" ? current : {},
ehpeekOverlay: { depth, sessionId, surface }
},
"",
window.location.href
);
},
back: (count) => {
onBeforeBack(count), window.history.go(-count);
},
subscribe: (listener) => {
let onPopState = (event) => {
let marker = event.state?.ehpeekOverlay, own = marker !== null && typeof marker == "object" && "sessionId" in marker && marker.sessionId === sessionId && "depth" in marker && typeof marker.depth == "number";
listener(own ? marker.depth : 0);
};
return window.addEventListener("popstate", onPopState), () => window.removeEventListener("popstate", onPopState);
}
};
}
var init_OverlayHistory = __esm({
"src/App/OverlayHistory.ts"() {
"use strict";
}
});
// src/App/GalleryCoordinator.ts
function createGalleryCoordinator(options) {
let previewCache = options.previewCache, preview = previewCache.current().data, gallery2 = galleryIdentityFromUrl(preview.currentUrl);
if (!gallery2) throw new Error("Cannot identify Gallery for Reader.");
let progress = createProgressSession(
gallery2.galleryId,
gallery2.token,
preview.totalImages,
options.readHistory,
options.includeUnreadHistoryEnabled
), readerInitialPreviewIndex = preview.currentIndex, readerLastPage = 1, coveredInfo = !1, thumbs = null, reader = null, mountedReader = () => {
if (!reader) throw new Error("Gallery reader is not mounted.");
return reader;
}, enhancedPreviewActive = () => options.enhanceThumbsGridsEnabled || options.replacePreviewWithScroll || reader?.activeView === "preview", replaceReaderLocation = (pageNumber) => {
if (pageNumber <= 0 || !options.includeReaderPageInUrl) return;
let url = new URL(window.location.href), hashParams = new URLSearchParams(url.hash.replace(/^#/, ""));
url = new URL(
previewUrlForIndex(
previewCache.previewIndexForPage(pageNumber),
url.href
)
), hashParams.set("peek_page", String(pageNumber)), url.hash = hashParams.toString(), url.href !== window.location.href && window.history.replaceState(window.history.state, "", url.href);
}, replacePreviewLocation = (previewIndex) => {
if (options.replacePreviewWithScroll) return;
let url = new URL(previewUrlForIndex(previewIndex));
url.href !== window.location.href && window.history.replaceState(window.history.state, "", url.href);
}, clearReaderLocation = () => {
if (!/(?:^#|&)peek_page(?:=|&|$)/.test(window.location.hash)) return;
let url = new URL(window.location.href), hashParams = new URLSearchParams(url.hash.replace(/^#/, ""));
hashParams.delete("peek_page"), url.hash = hashParams.toString(), window.history.replaceState(window.history.state, "", url.href);
};
return {
readerOptions: {
source: createReaderContentSource(
previewCache,
gallery2.galleryId,
gallery2.token
),
settings: readerSettings(),
onSettingChange: readerSettingCallbacks(options.onEmbeddedDirectionChange),
host: options.overlayHost,
history: createOverlayHistory((count) => {
(count > 1 || reader?.activeView === "reader") && clearReaderLocation();
}),
initialProgress: progress.progress().hasHistory ? progress.progress().currentPage : null,
fullscreenOnOpen: options.readerFullscreenEnabled,
exitOnFullscreenExit: options.exitReaderOnFullscreenExit,
beforeOpen: options.readerEnabled ? void 0 : async (pageNum) => (await openOriginalReader(pageNum, previewCache), !1),
placement: () => {
let column = options.twoColumnsReaderMode === "reader-preview" ? "info" : options.twoColumnsReaderMode === "on-preview" ? "preview" : null, container = column === null ? null : options.galleryColumn(column);
return coveredInfo = column === "info" && container !== null, container ? {
container,
coversPreview: column === "preview" && options.replacePreviewWithScroll
} : null;
},
onError: reportUiError,
onReaderOpen: (pageNum) => {
readerLastPage = pageNum, readerInitialPreviewIndex = previewCache.current().data.currentIndex;
},
onReaderMount: (mounted) => options.onReaderPreviewModeChange(mounted && coveredInfo),
onProgress: (page2) => {
page2.pageNum && (readerLastPage = page2.pageNum, enhancedPreviewActive() && thumbs?.gotoPreview(previewCache.previewIndexForPage(page2.pageNum)), replaceReaderLocation(page2.pageNum)), progress.update(page2.pageNum, preview.totalImages);
},
onEnd: () => progress.update(preview.totalImages, preview.totalImages),
onReaderClosed: async () => {
await progress.flush(), clearReaderLocation();
let exitIndex = previewCache.previewIndexForPage(readerLastPage);
enhancedPreviewActive() ? (thumbs?.gotoPreview(exitIndex), exitIndex !== previewCache.current().data.currentIndex && previewCache.select(exitIndex).catch(reportUiError), reader?.activeView === null && replacePreviewLocation(exitIndex)) : exitIndex !== readerInitialPreviewIndex ? window.location.replace(previewUrlForIndex(exitIndex)) : replacePreviewLocation(exitIndex);
},
onPreviewClosed: (pageNum) => {
let index = previewCache.previewIndexForPage(pageNum);
options.enhanceThumbsGridsEnabled || options.replacePreviewWithScroll ? (index !== previewCache.current().data.currentIndex && previewCache.select(index).catch(reportUiError), replacePreviewLocation(index)) : window.location.assign(
previewUrlForIndex(index, previewCache.current().data.currentUrl)
);
},
customization: {
download: (url, name) => startUserscriptDownload({
url,
name,
onerror: (error) => {
console.error("[ehpeek]", error), window.alert(activeTexts.errors.downloadFailed);
}
}),
downloadHelp: () => activeTexts.reader.downloadHelp,
onOpenOriginalPage: (url) => {
progress.flush().then(() => window.location.assign(url)).catch(reportUiError);
}
}
},
attachReader: (instance) => {
reader = instance, instance || progress.dispose();
},
attachThumbs: (actions) => {
thumbs = actions;
},
openFromReadButton: () => {
mountedReader().open(options.readHistory ? progress.progress().currentPage : 1, !0).catch(reportUiError);
},
openGalleryPage: (url, preferredPageNum) => {
let pageNum = preferredPageNum ?? peekPageFromHash() ?? galleryPageNumber(url);
pageNum ? mountedReader().open(pageNum, !0).catch(reportUiError) : reportUiError(new Error(activeTexts.errors.imageNotFound));
},
openReaderFromHash: async () => {
let pageNum = peekPageFromHash();
pageNum !== null && await mountedReader().open(pageNum).catch(reportUiError);
},
progress: progress.progress
};
}
function createProgressSession(galleryId, token, totalPages, history, includeUnread) {
if (!history)
return new ReadingProgressSession(null, {
currentPage: 1,
hasHistory: !1,
totalPages
});
let existing = history.value, galleryInfo = extractGalleryHistoryInfo();
return includeUnread ? history.recordVisit(totalPages, galleryInfo).catch((error) => {
console.error("[ehpeek] Failed to record gallery visit", error);
}) : existing && history.updateGalleryInfo(galleryInfo).catch((error) => {
console.error("[ehpeek] Failed to update gallery history info", error);
}), new ReadingProgressSession(
{
history,
record: {
gallery: galleryInfo,
galleryId,
token,
totalPages
}
},
{
currentPage: existing?.pageNum && existing.pageNum > 0 ? existing.pageNum : 1,
hasHistory: !!(existing && existing.pageNum > 0),
totalPages: existing?.totalPages ?? totalPages
}
);
}
var init_GalleryCoordinator = __esm({
"src/App/GalleryCoordinator.ts"() {
"use strict";
init_eh();
init_i18n2();
init_userscript();
init_ReadingProgressSession();
init_Reader();
init_ui2();
init_ReaderContentSource();
init_ReaderSettings();
init_OverlayHistory();
}
});
// src/App/GalleryPreviewCache.ts
function createGalleryPreviewCache(initialPreview) {
let [current, setCurrent] = createSignal(initialPreview), [loading, setLoading] = createSignal(!1), [previewDataVersion, setPreviewDataVersion] = createSignal(0), previews = /* @__PURE__ */ new Map(), pages = /* @__PURE__ */ new Map(), previewItems = /* @__PURE__ */ new Map(), pending = /* @__PURE__ */ new Map(), pageSize = initialPreview.data.pageSize, maxPreviewIndex = initialPreview.data.maxIndex, currentPreviewIndex = initialPreview.data.currentIndex, selectionId = 0, remember = (preview) => {
let index = preview.data.currentIndex, expectedItems = preview.data.endImage - preview.data.startImage + 1;
preview.data.previewItems.length >= expectedItems && (previews.delete(index), previews.set(index, preview));
for (let page2 of preview.data.pages)
page2.pageNum && page2.pageNum > 0 && pages.set(page2.pageNum, page2);
for (let item of preview.data.previewItems)
previewItems.set(item.pageNum, item);
for (setPreviewDataVersion((version) => version + 1); previews.size > PREVIEW_CACHE_LIMIT; ) {
let removable;
for (let candidate of previews.keys())
if (candidate !== currentPreviewIndex && candidate !== index) {
removable = candidate;
break;
}
if (removable === void 0)
break;
previews.delete(removable);
}
}, previewIndexForPage = (pageNum) => previewPageIndexForGalleryPage(
pageNum,
pageSize,
maxPreviewIndex
), load = (previewIndex) => {
if (previewIndex < 0 || previewIndex > maxPreviewIndex)
return Promise.reject(new RangeError(`Invalid Preview index: ${previewIndex}`));
let cached = previews.get(previewIndex);
if (cached)
return previews.delete(previewIndex), previews.set(previewIndex, cached), Promise.resolve(cached);
let existing = pending.get(previewIndex);
if (existing)
return existing;
setLoading(!0);
let request = loadGalleryPreviewPage(
previewIndex,
initialPreview.data.currentUrl
).then(
(preview) => (pending.delete(previewIndex), setLoading(pending.size > 0), remember(preview), preview),
(error) => {
throw pending.delete(previewIndex), setLoading(pending.size > 0), error;
}
);
return pending.set(previewIndex, request), request;
}, getPages = async (pageNums) => {
let requested = Array.from(new Set(pageNums.filter((pageNum) => pageNum > 0))), previewIndexes = Array.from(new Set(requested.filter((pageNum) => !pages.has(pageNum)).map(previewIndexForPage)));
return await Promise.all(previewIndexes.map(load)), requested.flatMap((pageNum) => pages.get(pageNum) ?? []);
}, getPreviewItems = async (pageNums) => {
let requested = Array.from(new Set(pageNums.filter((pageNum) => pageNum > 0))), previewIndexes = Array.from(new Set(requested.filter((pageNum) => !previewItems.has(pageNum)).map(previewIndexForPage)));
return await Promise.all(previewIndexes.map(load)), requested.flatMap((pageNum) => previewItems.get(pageNum) ?? []);
}, select2 = async (previewIndex) => {
if (previewIndex === current().data.currentIndex)
return current();
let activeSelection = ++selectionId, preview = await load(previewIndex);
return activeSelection === selectionId && (currentPreviewIndex = preview.data.currentIndex, setCurrent(preview)), preview;
};
return remember(initialPreview), {
current,
getPages,
getPreviewItems,
load,
loadImage: (page2, signal) => loadEhImagePage(page2, signal),
loading,
previewDataVersion,
previewIndexForPage,
previewItem: (pageNum) => (previewDataVersion(), previewItems.get(pageNum) ?? null),
select: select2
};
}
var PREVIEW_CACHE_LIMIT, init_GalleryPreviewCache = __esm({
"src/App/GalleryPreviewCache.ts"() {
"use strict";
init_solid();
init_eh();
PREVIEW_CACHE_LIMIT = 10;
}
});
// src/App/host.ts
function createAppMount(className2 = "", host = document.body) {
let mount = createManagedElement("div");
return className2 && mount.replaceClasses(className2), host.append(mount.Component()), mount;
}
var init_host = __esm({
"src/App/host.ts"() {
"use strict";
init_eh();
}
});
// src/App/Settings.ts
function settingsMenuState(defaults = !1) {
let read = (setting) => defaults ? setting.defaultValue : setting.value;
return {
twoColumnsReaderMode: read(state.reader.twoColumnsMode),
openGalleryInNewTab: read(state.app.openGalleryInNewTab),
locale: read(state.app.locale),
readerEnabled: read(state.reader.enabled),
exitReaderOnFullscreenExit: read(state.reader.exitOnFullscreenExit),
readerFullscreenEnabled: read(state.reader.fullscreen),
includeReaderPageInUrl: read(state.reader.includePageInUrl),
replacePreviewWithScroll: read(state.gallery.replacePreviewWithScroll),
enhanceThumbsGridsEnabled: read(state.gallery.enhanceThumbs),
enhanceSearchGridsEnabled: read(state.search.enhance),
myTagsEnabled: read(state.gallery.myTags),
readHistoryEnabled: read(state.gallery.readHistory),
includeUnreadHistoryEnabled: read(state.gallery.includeUnreadHistory),
searchHistoryEnabled: read(state.search.history),
touchUiEnabled: read(state.touch.enabled),
fitToViewport: read(state.touch.fitToViewport),
portraitUiScale: read(state.app.portraitUiScale),
landscapeUiScale: read(state.app.landscapeUiScale)
};
}
async function applySettingsMenuState(next) {
next.touchUiEnabled || await clearBackToTopPositions(), await Promise.all([
state.reader.twoColumnsMode.setAsync(next.twoColumnsReaderMode),
state.app.openGalleryInNewTab.setAsync(next.openGalleryInNewTab),
state.app.locale.setAsync(next.locale),
state.reader.enabled.setAsync(next.readerEnabled),
state.reader.exitOnFullscreenExit.setAsync(next.exitReaderOnFullscreenExit),
state.reader.fullscreen.setAsync(next.readerFullscreenEnabled),
state.reader.includePageInUrl.setAsync(next.includeReaderPageInUrl),
state.gallery.replacePreviewWithScroll.setAsync(next.replacePreviewWithScroll),
state.gallery.enhanceThumbs.setAsync(next.enhanceThumbsGridsEnabled),
state.search.enhance.setAsync(next.enhanceSearchGridsEnabled),
state.gallery.myTags.setAsync(next.myTagsEnabled),
state.gallery.readHistory.setAsync(next.readHistoryEnabled),
state.gallery.includeUnreadHistory.setAsync(next.includeUnreadHistoryEnabled),
state.search.history.setAsync(next.searchHistoryEnabled),
state.touch.enabled.setAsync(next.touchUiEnabled),
state.touch.fitToViewport.setAsync(next.fitToViewport),
state.app.portraitUiScale.setAsync(next.portraitUiScale),
state.app.landscapeUiScale.setAsync(next.landscapeUiScale)
]), window.location.reload();
}
var init_Settings = __esm({
"src/App/Settings.ts"() {
"use strict";
init_state();
}
});
// src/App/GalleryColumns.ts
function currentColumnsEnabled() {
return currentColumnsSetting().value;
}
function currentColumnsSetting() {
return window.matchMedia("(orientation: landscape)").matches ? state.touch.landscapeColumns : state.touch.portraitColumns;
}
function currentGalleryColumnsRatio() {
return currentGalleryColumnsRatioSetting().value;
}
function currentGalleryColumnsRatioSetting() {
return window.matchMedia("(orientation: landscape)").matches ? state.touch.landscapeGalleryColumnsRatio : state.touch.portraitGalleryColumnsRatio;
}
function currentReaderPreviewColumnsRatio() {
return currentReaderPreviewColumnsRatioSetting().value;
}
function currentReaderPreviewColumnsRatioSetting() {
return window.matchMedia("(orientation: landscape)").matches ? state.touch.landscapeReaderPreviewColumnsRatio : state.touch.portraitReaderPreviewColumnsRatio;
}
function createGalleryColumns(touchUiEnabled) {
let [columnsEnabled, setColumnsEnabled] = createSignal(currentColumnsEnabled()), [galleryColumnsRatio, setGalleryColumnsRatio] = createSignal(currentGalleryColumnsRatio()), [readerPreviewColumnsRatio, setReaderPreviewColumnsRatio] = createSignal(currentReaderPreviewColumnsRatio()), [readerPreviewModeActive, setReaderPreviewModeActive] = createSignal(!1), [galleryColumnsResizeHandleVisible, setGalleryColumnsResizeHandleVisible] = createSignal(!1);
function activeGalleryColumnsRatio() {
return readerPreviewModeActive() ? readerPreviewColumnsRatio() ?? galleryColumnsRatio() : galleryColumnsRatio();
}
function updateColumnsLayout() {
touchUiEnabled && (setColumnsEnabled(currentColumnsEnabled()), setGalleryColumnsRatio(currentGalleryColumnsRatio()), setReaderPreviewColumnsRatio(currentReaderPreviewColumnsRatio()));
}
function setCurrentColumnsEnabled(enabled) {
currentColumnsSetting().setAsync(enabled).then(() => window.location.reload()).catch(reportUiError);
}
function updateGalleryColumnsRatio(ratio) {
let normalized = Math.min(
GALLERY_COLUMNS_RATIO_MAX,
Math.max(GALLERY_COLUMNS_RATIO_MIN, ratio)
);
readerPreviewModeActive() ? setReaderPreviewColumnsRatio(normalized) : setGalleryColumnsRatio(normalized);
}
function persistGalleryColumnsRatio(ratio) {
readerPreviewModeActive() ? currentReaderPreviewColumnsRatioSetting().set(ratio) : currentGalleryColumnsRatioSetting().set(ratio);
}
function resetGalleryColumnsRatio() {
if (readerPreviewModeActive()) {
setReaderPreviewColumnsRatio(null), currentReaderPreviewColumnsRatioSetting().set(null);
return;
}
updateGalleryColumnsRatio(GALLERY_COLUMNS_RATIO_DEFAULT), persistGalleryColumnsRatio(GALLERY_COLUMNS_RATIO_DEFAULT);
}
return {
enabled: columnsEnabled,
ratio: activeGalleryColumnsRatio,
resizeHandleVisible: galleryColumnsResizeHandleVisible,
resetDisabled: () => readerPreviewModeActive() ? readerPreviewColumnsRatio() === null : galleryColumnsRatio() === GALLERY_COLUMNS_RATIO_DEFAULT,
setEnabled: setCurrentColumnsEnabled,
setReaderPreviewActive: setReaderPreviewModeActive,
showResizeHandle: setGalleryColumnsResizeHandleVisible,
updateRatio: updateGalleryColumnsRatio,
commitRatio: persistGalleryColumnsRatio,
resetRatio: resetGalleryColumnsRatio,
refreshOrientation: updateColumnsLayout
};
}
var init_GalleryColumns = __esm({
"src/App/GalleryColumns.ts"() {
"use strict";
init_solid();
init_state();
init_ui2();
}
});
// src/App/index.tsx
var App_exports = {};
function currentUiScale() {
return currentUiScaleSetting().value;
}
function currentUiScaleSetting() {
return window.matchMedia("(orientation: landscape)").matches ? state.app.landscapeUiScale : state.app.portraitUiScale;
}
function updateUiScale() {
let scale = currentUiScale();
gState.setUiScale(scale), applyUiScale2(scale), overlayHost?.setUiScale(scale);
}
function setCurrentUiScale(scale) {
currentUiScaleSetting().set(scale), gState.setUiScale(scale), applyUiScale2(scale), overlayHost?.setUiScale(scale);
}
function setLeftHandedControls(enabled) {
state.app.leftHandedControls.set(enabled), gState.setLeftHandedControls(enabled);
}
function allowFeatureFailure(name, run) {
try {
run();
} catch (error) {
console.error(`[ehpeek] ${name} failed`, error);
}
}
async function allowAsyncFeatureFailure(name, run) {
try {
await run();
} catch (error) {
console.error(`[ehpeek] ${name} failed`, error);
}
}
function requirePageDependency(name, dependency) {
if (dependency === null)
throw new Error(`Cannot initialize ${name}.`);
return dependency;
}
function readButtonLabel(progress) {
return progress.hasHistory ? activeTexts.reader.continueReading : activeTexts.reader.startReading;
}
function readButtonProgress(progress) {
return progress.totalPages ? `${progress.currentPage}/${progress.totalPages}` : String(progress.currentPage);
}
function GalleryReadButton(props) {
return (() => {
var _el$ = _tmpl$224();
return _el$.$$click = (event) => {
event.preventDefault(), event.stopPropagation(), props.onRead();
}, insert(_el$, () => readButtonLabel(props.progress()), null), insert(_el$, createComponent(Show, {
get when() {
return props.progress().hasHistory;
},
get children() {
var _el$2 = _tmpl$70();
return insert(_el$2, () => readButtonProgress(props.progress())), _el$2;
}
}), null), createRenderEffect((_p$) => {
var _v$ = readButtonLabel(props.progress()), _v$2 = readButtonLabel(props.progress());
return _v$ !== _p$.e && setAttribute(_el$, "aria-label", _p$.e = _v$), _v$2 !== _p$.t && setAttribute(_el$, "title", _p$.t = _v$2), _p$;
}, {
e: void 0,
t: void 0
}), _el$;
})();
}
function TouchGalleryReadButton(props) {
return (() => {
var _el$3 = _tmpl$414();
return _el$3.$$click = (event) => {
event.preventDefault(), event.stopPropagation(), props.onRead();
}, insert(_el$3, () => readButtonLabel(props.progress()), null), insert(_el$3, createComponent(Show, {
get when() {
return props.progress().hasHistory;
},
get children() {
var _el$4 = _tmpl$317();
return insert(_el$4, () => readButtonProgress(props.progress())), _el$4;
}
}), null), createRenderEffect((_p$) => {
var _v$3 = readButtonLabel(props.progress()), _v$4 = readButtonLabel(props.progress());
return _v$3 !== _p$.e && setAttribute(_el$3, "aria-label", _p$.e = _v$3), _v$4 !== _p$.t && setAttribute(_el$3, "title", _p$.t = _v$4), _p$;
}, {
e: void 0,
t: void 0
}), _el$3;
})();
}
function installSettingsMenu() {
GM.registerMenuCommand && GM.registerMenuCommand(activeTexts.settings.openSettings, () => {
gState.setSettingsMenuOpen(!0);
}), createAppMount("fixed inset-0 z-[2150] pointer-events-none", overlayHost.element).mount(() => createComponent(OverlayHostProvider, {
host: overlayHost,
get children() {
return createComponent(SettingsMenu, {
get historyHref() {
return readHistoryUrl();
},
get leftHandedControls() {
return gState.leftHandedControls;
},
get open() {
return gState.settingsMenuOpen();
},
get defaultState() {
return settingsMenuState(!0);
},
get initState() {
return {
...gState.settings,
...window.matchMedia("(orientation: landscape)").matches ? {
landscapeUiScale: gState.uiScale()
} : {
portraitUiScale: gState.uiScale()
}
};
},
onApply: (next) => {
allowAsyncFeatureFailure("Settings update", () => applySettingsMenuState(next));
},
get onOpenChange() {
return gState.setSettingsMenuOpen;
}
});
}
}));
}
function injectCommon(page2) {
if (gState.settings.searchHistoryEnabled && allowFeatureFailure("Search history", () => {
let host = null;
observeSearchBar((source) => {
host ?? (host = createAppMount()), host.mount(() => createComponent(SearchHistory, {
source
}));
});
}), !gState.settings.touchUiEnabled) {
allowFeatureFailure("Desktop settings entry", () => {
let settingsMount = manageSettingsMenuMount();
settingsMount && settingsMount.mount(() => (() => {
var _el$5 = _tmpl$511();
return _el$5.$$click = (event) => {
event.preventDefault(), event.stopPropagation(), gState.setSettingsMenuOpen(!0);
}, insert(_el$5, "EhPeek"), _el$5;
})());
});
return;
}
allowFeatureFailure("Touch top bar", () => {
let topBarDom = manageTopBar();
if (!topBarDom)
return;
let columnsAvailable = page2.type === "gallery" || page2.type === "readHistory" || (page2.type === "search" || page2.type === "favorites") && state.search.grid.value !== null;
topBarDom.elems.mount.mount(() => createComponent(TouchTopBar, {
get historyHref() {
return memo(() => !!gState.settings.readHistoryEnabled)() ? readHistoryUrl() : void 0;
},
get leftHandedControls() {
return {
enabled: gState.leftHandedControls,
onChange: setLeftHandedControls
};
},
get uiScale() {
return {
value: gState.uiScale,
onChange: setCurrentUiScale
};
},
get columns() {
return {
available: columnsAvailable,
enabled: columns.enabled,
onChange: columns.setEnabled,
...page2.type === "gallery" ? {
resizeHandle: {
visible: columns.resizeHandleVisible,
onChange: columns.showResizeHandle
}
} : {}
};
},
source: topBarDom,
onSettingsMenuOpen: () => {
gState.setSettingsMenuOpen(!0);
}
}));
}), (page2.type === "gallery" || page2.type === "search" || page2.type === "favorites" || page2.type === "readHistory") && allowFeatureFailure("Back to top", () => {
createAppMount().mount(() => createComponent(Show, {
get when() {
return page2.type !== "gallery" || !columns.enabled();
},
get children() {
return createComponent(BackToTop, {
get leftHanded() {
return gState.leftHandedControls;
}
});
}
}));
});
}
function injectGalleryDetails(previewCache, coordinator) {
let preview = previewCache.current(), galleryWideLayout = null;
return allowFeatureFailure("Touch GalleryInfo", () => {
mutateGalleryTouchLayout(gState.settings.fitToViewport);
let galleryInfoDom = requirePageDependency("Touch GalleryInfo", manageGalleryInfo(preview.data));
galleryInfoDom.handle.installGalleryInfoPanel(), galleryWideLayout = requirePageDependency("Touch Gallery layout", mutateGalleryWideLayout(galleryInfoDom, preview, columns.enabled(), columns.ratio(), gState.settings.replacePreviewWithScroll)), createEffect(() => galleryWideLayout?.updateEnabled(columns.enabled())), createEffect(() => galleryWideLayout?.updateInfoRatio(columns.ratio())), galleryWideLayout.resizeHandleMount.mount(() => createComponent(GalleryColumnsResizeHandle, {
onClose: () => columns.showResizeHandle(!1),
get onReset() {
return columns.resetRatio;
},
get ratio() {
return columns.ratio();
},
get resetDisabled() {
return columns.resetDisabled();
},
get visible() {
return columns.resizeHandleVisible();
},
get onInput() {
return columns.updateRatio;
},
get onCommit() {
return columns.commitRatio;
}
}));
let infoColumnScope = galleryWideLayout.columnScope("info");
galleryInfoDom.elems.mount.mount(() => createComponent(OverlayHostProvider, {
host: overlayHost,
get children() {
return createComponent(GalleryInfoPanel, {
get columnsEnabled() {
return columns.enabled;
},
columnScope: infoColumnScope,
get leftHandedControls() {
return gState.leftHandedControls;
},
source: galleryInfoDom,
get primaryAction() {
return createComponent(TouchGalleryReadButton, {
get onRead() {
return coordinator.openFromReadButton;
},
get progress() {
return coordinator.progress;
}
});
}
});
}
}));
}), allowFeatureFailure("Touch Gallery comments", () => {
manageGalleryCommentsTouch(reportUiError);
}), galleryWideLayout;
}
function injectGalleryPreview(previewCache, coordinator) {
let preview = previewCache.current(), previewMount = preview.elems.mount;
gState.settings.readerEnabled && allowFeatureFailure("Reader thumbnail links", () => {
preview.handle.interceptPreviewImageOpen((pageUrl) => {
coordinator.openGalleryPage(pageUrl);
});
}), gState.settings.touchUiEnabled || allowFeatureFailure("Desktop Read button", () => {
manageGalleryContinueReadingButtonMount().mount(() => createComponent(GalleryReadButton, {
get onRead() {
return coordinator.openFromReadButton;
},
get progress() {
return coordinator.progress;
}
}));
}), previewMount && allowFeatureFailure("Gallery Preview enhancements", () => {
gState.settings.replacePreviewWithScroll && preview.handle.installScrollPreviewMount(), previewMount.mount(() => createComponent(OverlayHostProvider, {
host: overlayHost,
get children() {
var _el$6 = _tmpl$610();
return insert(_el$6, createComponent(ReadingView, {
get options() {
return coordinator.readerOptions;
},
get instanceRef() {
return coordinator.attachReader;
},
get embeddedPreview() {
return gState.settings.replacePreviewWithScroll;
},
get embeddedDirection() {
return memo(() => !!columns.enabled())() ? state.gallery.embeddedScrollPreviewColumnsDirection.value : state.gallery.embeddedScrollPreviewSingleDirection.value;
},
get fillPreviewContainer() {
return columns.enabled;
},
get leftHandedControls() {
return gState.leftHandedControls();
}
}), null), insert(_el$6, (() => {
var _c$ = memo(() => !!(gState.settings.enhanceThumbsGridsEnabled && !gState.settings.replacePreviewWithScroll));
return () => _c$() ? createComponent(ThumbsGrids, {
get actionsRef() {
return coordinator.attachThumbs;
},
onLoadError: reportUiError,
previewCache
}) : null;
})(), null), createRenderEffect((_$p) => classList(_el$6, {
contents: !gState.settings.replacePreviewWithScroll,
"relative h-full w-full [--scroll-preview-height:100%]": gState.settings.replacePreviewWithScroll && gState.settings.touchUiEnabled && columns.enabled(),
"relative [--scroll-preview-height:100svh] w-[calc(100%-(var(--touch-gallery-gutter)*2))] mx-auto": gState.settings.replacePreviewWithScroll && gState.settings.touchUiEnabled && !columns.enabled(),
"relative [--scroll-preview-height:100svh] w-[calc(100%-32px)] mx-auto": gState.settings.replacePreviewWithScroll && !gState.settings.touchUiEnabled
}, _$p)), _el$6;
}
}));
});
}
function injectGalleryPage(page2, readHistory) {
let previewCache = createGalleryPreviewCache(manageGalleryPreview()), galleryWideLayout = null, coordinator = createGalleryCoordinator({
enhanceThumbsGridsEnabled: gState.settings.enhanceThumbsGridsEnabled,
exitReaderOnFullscreenExit: gState.settings.exitReaderOnFullscreenExit,
includeReaderPageInUrl: gState.settings.includeReaderPageInUrl,
includeUnreadHistoryEnabled: gState.settings.includeUnreadHistoryEnabled,
onReaderPreviewModeChange: columns.setReaderPreviewActive,
onEmbeddedDirectionChange: (direction) => {
(columns.enabled() ? state.gallery.embeddedScrollPreviewColumnsDirection : state.gallery.embeddedScrollPreviewSingleDirection).set(direction);
},
overlayHost,
previewCache,
readHistory,
readerEnabled: gState.settings.readerEnabled,
readerFullscreenEnabled: gState.settings.readerFullscreenEnabled,
twoColumnsReaderMode: gState.settings.twoColumnsReaderMode,
galleryColumn: (column) => {
let scope = galleryWideLayout?.columnScope(column);
return columns.enabled() && scope?.available() ? scope : null;
},
replacePreviewWithScroll: gState.settings.replacePreviewWithScroll
});
gState.settings.myTagsEnabled && allowFeatureFailure("Gallery My Tags appearance", () => {
let myTagAppearances = loadMyTagAppearances();
if (myTagAppearances) {
mutateGalleryMyTags(myTagAppearances);
return;
}
allowAsyncFeatureFailure("My Tags appearance", async () => {
let appearances = await refreshMyTags();
appearances && mutateGalleryMyTags(appearances);
});
}), gState.settings.touchUiEnabled && (galleryWideLayout = injectGalleryDetails(previewCache, coordinator)), injectGalleryPreview(previewCache, coordinator), state.reader.enabled.value && page2.peekPage !== null && allowAsyncFeatureFailure("Reader deep link", async () => {
await coordinator.openReaderFromHash();
});
}
function injectImagePage() {
if (!gState.settings.readerEnabled || !extractImageGalleryPage())
return;
let mount = manageImageReaderButtonMount();
if (!mount)
return;
let label = `EhPeek ${activeTexts.settings.readerLabel}`;
mount.mount(() => (() => {
var _el$7 = _tmpl$78();
return insert(_el$7, createComponent(LauncherButton, {
icon: "book-open",
label,
onClick: () => {
let page2 = extractPageType(), gallery2 = extractImageGalleryPage();
page2.type === "image" && gallery2 && window.location.replace(peekPageUrl(page2.pageNum, gallery2.url));
},
title: label
})), _el$7;
})());
}
function injectSearchControls(page2) {
let touchResultsDom = manageTouchResultsPage(page2, gState.settings.fitToViewport);
return allowFeatureFailure("Touch Search panel", () => {
let searchPanelDom = manageSearchPanel();
searchPanelDom && (markUiRoot2(searchPanelDom.elems.form.Component()), searchPanelDom.elems.mount.mount(() => createComponent(TouchSearchPanel, {
source: searchPanelDom,
get after() {
return memo(() => !!touchResultsDom.data.favoritesCategory)() ? createComponent(FavoritesCategorySelect, {
source: touchResultsDom
}) : void 0;
}
})), searchPanelDom.elems.categoryToggleMount?.mount(() => createComponent(TouchSearchCategoryToggle, {
source: searchPanelDom
})), searchPanelDom.elems.advancedToggleMount?.mount(() => createComponent(TouchSearchOptionToggle, {
option: "advancedOptions",
source: searchPanelDom
})), searchPanelDom.elems.fileSearchToggleMount?.mount(() => createComponent(TouchSearchOptionToggle, {
option: "fileSearch",
source: searchPanelDom
})), searchPanelDom.elems.searchActionMount.mount(() => createComponent(TouchSearchAction, {
action: "search",
source: searchPanelDom
})), searchPanelDom.elems.clearActionMount?.mount(() => createComponent(TouchSearchAction, {
action: "clear",
source: searchPanelDom
})));
}), touchResultsDom;
}
function injectSearchPage(page2) {
let initialResultsDom = requirePageDependency("Search results", manageSearchResults()), [resultsDom, setResultsDom] = createSignal(initialResultsDom);
markUiRoot2(initialResultsDom.elems.resultList.Component());
let updateSearchGridModeSelector = () => {
mutateSearchGridModeSelect(state.search.grid.value, (mode) => {
state.search.grid.set(mode);
let url = new URL(window.location.href);
url.searchParams.set("inline_set", "dm_e"), window.location.assign(url.href);
}, () => {
state.search.grid.set(null);
});
};
allowFeatureFailure("Search grid mode selector", updateSearchGridModeSelector);
let searchGridMode = state.search.grid.value;
searchGridMode && allowFeatureFailure("Search grid", () => manageSearchGrids(searchGridMode));
let readHistories = /* @__PURE__ */ new Map(), readProgressForGallery = (galleryId, token) => {
let reference = `${galleryId}:${token}`, history = readHistories.get(reference);
return readHistories.has(reference) || (readHistories.set(reference, null), allowAsyncFeatureFailure("Search Read History loading", async () => {
readHistories.set(reference, await galleryReadHistory(galleryId, token)), updateSearchReadHistoryAppearance();
})), history?.value ?? null;
}, updateSearchReadHistoryAppearance = () => {
gState.settings.readHistoryEnabled && mutateSearchReadHistoryAppearance(readProgressForGallery);
};
allowFeatureFailure("Search Read History appearance", updateSearchReadHistoryAppearance);
let stopObservingAppendedResults = () => {
}, observeAppendedResults = (source) => {
stopObservingAppendedResults(), stopObservingAppendedResults = source.handle.listenResultRowsAdded(() => {
allowFeatureFailure("Appended Search results", () => {
searchGridMode && manageSearchGrids(searchGridMode), updateSearchReadHistoryAppearance();
});
});
};
observeAppendedResults(initialResultsDom), gState.settings.openGalleryInNewTab && allowFeatureFailure("Gallery links in new tabs", () => {
initialResultsDom.handle.listenGalleryLinksOpenInNewTab();
}), allowFeatureFailure("Search scroll memory", () => {
installSearchScrollMemory();
});
let updateSearchPage = (source) => {
markUiRoot2(source.elems.resultList.Component()), setResultsDom(source), observeAppendedResults(source), updateSearchGridModeSelector(), searchGridMode && manageSearchGrids(searchGridMode), updateSearchReadHistoryAppearance();
}, mountSearchPagination = (onPageChange) => {
gState.settings.enhanceSearchGridsEnabled && allowFeatureFailure("Enhanced Search pagination", () => {
createAppMount().mount(() => createComponent(EnhanceSearchGrids, {
source: initialResultsDom,
onPageChange: (source) => allowFeatureFailure("Changed Search page", () => onPageChange(source))
}));
});
};
if (gState.settings.touchUiEnabled) {
let touchResultsDom = injectSearchControls(page2);
createEffect(() => {
resultsDom().handle.updateResultColumns(columns.enabled());
}), mountSearchPagination((source) => {
updateSearchPage(source), touchResultsDom.handle.updateTouchResultsLayout();
});
} else
mountSearchPagination(updateSearchPage);
}
function injectReadHistoryPage(page2, records) {
let pageCount = Math.max(1, Math.ceil(records.length / 25)), pageIndex = Math.min(page2.pageIndex, pageCount - 1), items = records.map((record) => ({
currentPage: record.pageNum,
galleryId: record.galleryId,
info: record.gallery,
token: record.token,
totalPages: record.totalPages,
updatedAt: record.updatedAt
})), historyDom = requirePageDependency("Read History page", manageReadHistoryPage(items.slice(pageIndex * 25, (pageIndex + 1) * 25), state.gallery.titlePreference.reload(), state.search.grid.value ?? "ehpeek-lite"));
markUiRoot2(historyDom.elems.resultList.Component()), markUiRoot2(historyDom.elems.navigationBottomMount.Component()), gState.settings.openGalleryInNewTab && historyDom.handle.listenGalleryLinksOpenInNewTab(), gState.settings.touchUiEnabled && (createEffect(() => {
historyDom.handle.updateResultColumns(columns.enabled());
}), allowFeatureFailure("Touch Read History layout", () => {
manageTouchResultsPage(page2, !0);
})), historyDom.elems.navigationTopMount.mount(() => createComponent(ReadHistoryPage, {
initialPageIndex: pageIndex,
items,
pageSize: 25,
source: historyDom
}));
}
function injectPage(page2, inject) {
createRoot(() => {
installSettingsMenu(), updateUiScale(), injectCommon(page2), inject?.();
}), dispatchReady();
}
async function startApp() {
document.readyState === "loading" && await new Promise((resolve) => {
document.addEventListener("DOMContentLoaded", () => resolve(), {
once: !0
});
}), overlayHost = createOverlayHost(document.body, currentUiScale(), activeTexts);
let page2 = extractPageType(), onViewportResize = () => {
updateUiScale(), columns.refreshOrientation();
};
window.addEventListener("resize", onViewportResize, {
passive: !0
});
let inject;
switch (page2.type) {
case "gallery": {
let history = gState.settings.readHistoryEnabled ? await galleryReadHistory(page2.galleryId, page2.token) : null;
inject = () => {
allowFeatureFailure("Gallery page", () => injectGalleryPage(page2, history));
};
break;
}
case "readHistory": {
let records = await loadDisplayReadHistoryRecords();
inject = () => {
allowFeatureFailure("Read History page", () => injectReadHistoryPage(page2, records));
};
break;
}
case "image":
inject = () => {
allowFeatureFailure("Image page", injectImagePage);
};
break;
case "favorites":
case "search":
inject = () => {
allowFeatureFailure("Search page", () => injectSearchPage(page2));
};
break;
case "myTags":
inject = () => {
gState.settings.myTagsEnabled && allowAsyncFeatureFailure("My Tags refresh", async () => {
await refreshMyTags(extractMyTagsPageData());
});
};
break;
case "settings":
inject = () => {
let titlePreference = extractGalleryTitlePreference();
titlePreference && state.gallery.titlePreference.set(titlePreference);
};
break;
case "other":
break;
}
injectPage(page2, inject);
}
var _tmpl$70, _tmpl$224, _tmpl$317, _tmpl$414, _tmpl$511, _tmpl$610, _tmpl$78, gState, columns, overlayHost, PRESS_MIN_VISIBLE_MS, PRESS_MOVE_TOLERANCE_PX, UI_INTERACTION_SELECTOR, UI_PRESSABLE_SELECTOR, isDisabledInteraction, pressedInteraction, pressedClearTimer, pendingPress, clearPressedInteraction, showPressedInteraction, releasePressedInteraction, historyRouteActive, init_App = __esm({
"src/App/index.tsx"() {
"use strict";
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_web();
init_solid();
init_EnhanceSearchGrids();
init_searchScroll();
init_ReadingView();
init_EnhanceThumbsGrids();
init_ReadHistory();
init_readHistory();
init_SearchHistory();
init_myTags();
init_SettingsMenu();
init_Widgets();
init_GalleryColumnsResizeHandle();
init_BackToTop();
init_TouchUI();
init_eh();
init_state();
init_events();
init_i18n2();
init_helpers();
init_styles();
init_ehpeek_uno();
init_theme();
init_ui2();
init_GalleryCoordinator();
init_GalleryPreviewCache();
init_host();
init_ui2();
init_Settings();
init_GalleryColumns();
_tmpl$70 = /* @__PURE__ */ template('<span class="inline-block ml-auto opacity-72 [font-size:0.9em] font-600 whitespace-nowrap">'), _tmpl$224 = /* @__PURE__ */ template('<button type=button class="flex box-border w-full max-w-full min-h-sm items-center gap-sm py-sm px-xs border-0 bg-transparent text-[var(--color-site-accent)] hover:bg-[var(--color-site-accent-hover)] shadow-none cursor-pointer text-left font-inherit [font-size:1.05em] font-700 leading-[1.2]">'), _tmpl$317 = /* @__PURE__ */ template('<span class="block ehp-color-site-accent [font-size:var(--ui-font-size-sm)] font-600 opacity-78 normal-case">'), _tmpl$414 = /* @__PURE__ */ template('<button type=button class="flex min-w-0 w-full h-full ui-hit-min-h-xl flex-col items-center justify-center ui-gap-xs ui-py-md ui-px-lg border-0 bg-transparent ehp-color-site-accent text-center uppercase [touch-action:manipulation] [font-size:var(--ui-font-size-lg)] font-700">'), _tmpl$511 = /* @__PURE__ */ template("<a href=#>"), _tmpl$610 = /* @__PURE__ */ template("<div>"), _tmpl$78 = /* @__PURE__ */ template('<div class="flex w-full justify-center ui-my-sm">'), gState = (() => {
let settings2 = settingsMenuState(), [leftHandedControls, setLeftHandedControls2] = createSignal(state.app.leftHandedControls.value), [settingsMenuOpen, setSettingsMenuOpen] = createSignal(!1), [uiScale, setUiScale] = createSignal(currentUiScale());
return {
leftHandedControls,
setLeftHandedControls: setLeftHandedControls2,
settings: settings2,
settingsMenuOpen,
setUiScale,
setSettingsMenuOpen,
uiScale
};
})(), columns = createGalleryColumns(gState.settings.touchUiEnabled);
configureUi({
pointer: window.matchMedia("(hover: hover) and (pointer: fine)").matches ? "mouse" : "touch",
site: ehSiteTheme()
});
PRESS_MIN_VISIBLE_MS = 100, PRESS_MOVE_TOLERANCE_PX = 8, UI_INTERACTION_SELECTOR = "a[href], button, input, select, textarea, label, [onclick], [role=button], [role=tab]", UI_PRESSABLE_SELECTOR = "[data-ehpeek-pressable=true]", isDisabledInteraction = (interaction) => interaction.matches(":disabled, [aria-disabled=true]"), clearPressedInteraction = () => {
pressedClearTimer !== void 0 && (window.clearTimeout(pressedClearTimer), pressedClearTimer = void 0), pendingPress = void 0, pressedInteraction?.removeAttribute("data-ehpeek-pressed"), pressedInteraction = void 0;
}, showPressedInteraction = (interaction) => {
isDisabledInteraction(interaction) || (pressedInteraction = interaction, interaction.setAttribute("data-ehpeek-pressed", "true"));
}, releasePressedInteraction = () => {
pressedClearTimer = window.setTimeout(clearPressedInteraction, PRESS_MIN_VISIBLE_MS);
};
document.addEventListener("pointerdown", (event) => {
event.pointerType !== "mouse" && setUiPointer("touch"), clearPressedInteraction();
let interaction = event.target instanceof Element ? event.target.closest(UI_INTERACTION_SELECTOR) : null;
!interaction?.closest(".ehpeek-ui-root") || isDisabledInteraction(interaction) || (pendingPress = {
interaction,
pointerId: event.pointerId,
startX: event.clientX,
startY: event.clientY
});
}, {
capture: !0,
passive: !0
});
document.addEventListener("pointerup", (event) => {
pendingPress?.pointerId === event.pointerId && (showPressedInteraction(pendingPress.interaction), pendingPress = void 0, releasePressedInteraction());
}, {
capture: !0,
passive: !0
});
document.addEventListener("click", (event) => {
let target = event.target instanceof Element ? event.target : null, interaction = target?.closest(UI_INTERACTION_SELECTOR), pressable = target?.closest(UI_PRESSABLE_SELECTOR);
interaction || !pressable?.closest(".ehpeek-ui-root") || (clearPressedInteraction(), showPressedInteraction(pressable), releasePressedInteraction());
});
document.addEventListener("pointercancel", clearPressedInteraction, {
capture: !0,
passive: !0
});
document.addEventListener("pointermove", (event) => {
event.pointerType === "mouse" && setUiPointer("mouse"), pendingPress?.pointerId === event.pointerId && Math.hypot(event.clientX - pendingPress.startX, event.clientY - pendingPress.startY) > PRESS_MOVE_TOLERANCE_PX && clearPressedInteraction();
}, {
capture: !0,
passive: !0
});
updateUiScale();
registerGlobalStyle("ehpeek-uno-style", ehpeek_uno_default);
registerGlobalStyle("ehpeek-theme-style", theme_default2);
registerGlobalStyle("ehpeek-dom-style", styles_default);
initializeExternalAutocompleteUi();
historyRouteActive = extractPageType().type === "readHistory";
window.addEventListener("hashchange", () => {
let nextHistoryRouteActive = extractPageType().type === "readHistory";
historyRouteActive !== nextHistoryRouteActive && window.location.reload(), historyRouteActive = nextHistoryRouteActive;
});
startApp().catch((error) => {
console.error("[ehpeek] App startup failed", error);
});
delegateEvents(["click"]);
}
});
// src/index.ts
init_i18n2();
init_state();
async function start() {
await loadPersistedState(), setAppLocale(state.app.locale.value), await Promise.resolve().then(() => (init_App(), App_exports));
}
start().catch((error) => {
console.error("[ehpeek] App startup failed", error);
});
})();
/*! Bundled license information:
lucide-solid/dist/esm/defaultAttributes.mjs:
lucide-solid/dist/esm/context.mjs:
lucide-solid/dist/esm/shared/src/utils/hasA11yProp.mjs:
lucide-solid/dist/esm/shared/src/utils/mergeClasses.mjs:
lucide-solid/dist/esm/shared/src/utils/toKebabCase.mjs:
lucide-solid/dist/esm/shared/src/utils/toCamelCase.mjs:
lucide-solid/dist/esm/shared/src/utils/toPascalCase.mjs:
lucide-solid/dist/esm/Icon.mjs:
lucide-solid/dist/esm/icons/arrow-down.mjs:
lucide-solid/dist/esm/icons/arrow-left.mjs:
lucide-solid/dist/esm/icons/arrow-right.mjs:
lucide-solid/dist/esm/icons/arrow-up.mjs:
lucide-solid/dist/esm/icons/book-open.mjs:
lucide-solid/dist/esm/icons/check.mjs:
lucide-solid/dist/esm/icons/chevron-left.mjs:
lucide-solid/dist/esm/icons/chevron-right.mjs:
lucide-solid/dist/esm/icons/columns-2.mjs:
lucide-solid/dist/esm/icons/copy.mjs:
lucide-solid/dist/esm/icons/download.mjs:
lucide-solid/dist/esm/icons/ellipsis-vertical.mjs:
lucide-solid/dist/esm/icons/external-link.mjs:
lucide-solid/dist/esm/icons/file.mjs:
lucide-solid/dist/esm/icons/grid-2x2.mjs:
lucide-solid/dist/esm/icons/heart.mjs:
lucide-solid/dist/esm/icons/history.mjs:
lucide-solid/dist/esm/icons/house.mjs:
lucide-solid/dist/esm/icons/hand.mjs:
lucide-solid/dist/esm/icons/info.mjs:
lucide-solid/dist/esm/icons/locate-fixed.mjs:
lucide-solid/dist/esm/icons/maximize.mjs:
lucide-solid/dist/esm/icons/minimize.mjs:
lucide-solid/dist/esm/icons/move-horizontal.mjs:
lucide-solid/dist/esm/icons/move-vertical.mjs:
lucide-solid/dist/esm/icons/palette.mjs:
lucide-solid/dist/esm/icons/pencil.mjs:
lucide-solid/dist/esm/icons/play.mjs:
lucide-solid/dist/esm/icons/refresh-cw.mjs:
lucide-solid/dist/esm/icons/rows-3.mjs:
lucide-solid/dist/esm/icons/scan-line.mjs:
lucide-solid/dist/esm/icons/search.mjs:
lucide-solid/dist/esm/icons/settings.mjs:
lucide-solid/dist/esm/icons/sparkles.mjs:
lucide-solid/dist/esm/icons/star.mjs:
lucide-solid/dist/esm/icons/x.mjs:
lucide-solid/dist/esm/icons/zoom-in.mjs:
lucide-solid/dist/esm/icons/zoom-out.mjs:
(**
* @license lucide-solid v1.26.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*)
*/