feat(reader): wire double-page spread setting into web reader
The double_page_spread checkbox in the reader settings panel was inert: it had no Alpine binding, no apply logic, and no persistence. Default was also inconsistent (false in settings-manager, absent from server defaults). - Add doublePageSpread state to the reader Alpine component, loaded from saved settings (default true) - Add applyDoublePageSpread() which sets the renderer's 'spread' attribute to auto/none and persists the setting via saveSettings - Apply the spread attribute during fixed-layout renderer init - Bind the settings checkbox with x-model and @change - Add double_page_spread: true to ReaderService server defaults so new users get the same starting value the client expects - Also improve the PDF pan/select toolbar button: distinct smart- select vs pan icons, highlighted state while pan mode is active, and dynamic tooltips/aria-labels explaining each mode
This commit is contained in:
@@ -403,6 +403,7 @@ func (s *ReaderService) getDefaultSettings() map[string]interface{} {
|
||||
"tap_zone_size": 30,
|
||||
"auto_scroll": false,
|
||||
"panel_zoom_enabled": true,
|
||||
"double_page_spread": true,
|
||||
|
||||
// Dockable panel defaults
|
||||
"panel_layout": map[string]interface{}{
|
||||
|
||||
@@ -153,8 +153,13 @@ templ ReaderChrome(user User, metadata ReaderMetadata, progress ReadingProgress)
|
||||
</svg>
|
||||
</button>
|
||||
<!-- Pan/Select mode (PDF only) -->
|
||||
<button x-show="isPDF" @click="toggleInteractionMode()" class="p-1.5 sm:p-2 rounded-lg hover:bg-gray-700" title="Pan/Select Mode" aria-label="Toggle pan/select mode">
|
||||
<svg class="reader-icon" width="20" height="20" aria-hidden="true">
|
||||
<button x-show="isPDF" @click="toggleInteractionMode()" class="p-1.5 sm:p-2 rounded-lg hover:bg-gray-700" :class="interactionMode === 'pan' ? 'bg-blue-600 hover:bg-blue-700' : ''" :title="interactionMode === 'pan' ? 'Pan mode: drag anywhere to move. Click for Smart select.' : 'Smart select: drag text to select, drag blank to pan (Shift = force pan). Click for Pan mode.'" :aria-label="interactionMode === 'pan' ? 'Pan mode' : 'Smart select mode'">
|
||||
<!-- Smart select (default): text cursor -->
|
||||
<svg x-show="interactionMode !== 'pan'" class="reader-icon" width="20" height="20" aria-hidden="true">
|
||||
<path d="M 10 3 L 10 17 M 7 5 L 10 4 L 13 5 M 7 15 L 10 16 L 13 15"></path>
|
||||
</svg>
|
||||
<!-- Force pan: move arrow -->
|
||||
<svg x-show="interactionMode === 'pan'" class="reader-icon" width="20" height="20" aria-hidden="true">
|
||||
<path d="M 5 3 v 12 M 5 15 l -2 2 M 5 15 l 2 2 M 5 3 l 3 3"></path>
|
||||
</svg>
|
||||
</button>
|
||||
@@ -306,7 +311,7 @@ templ ReaderSettingsPanel() {
|
||||
<div class="mb-6" x-show="isFixedLayout">
|
||||
<h3 class="font-semibold mb-2">Navigation</h3>
|
||||
<label class="flex items-center mb-2">
|
||||
<input type="checkbox" name="double_page_spread" class="mr-2"/>
|
||||
<input type="checkbox" name="double_page_spread" x-model="doublePageSpread" @change="applyDoublePageSpread()" class="mr-2"/>
|
||||
Double Page Spread
|
||||
</label>
|
||||
</div>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -371,6 +371,7 @@ document.addEventListener("alpine:init", () => {
|
||||
isPDF: false,
|
||||
interactionMode: "select" as string,
|
||||
magnifierEnabled: false,
|
||||
doublePageSpread: true as boolean,
|
||||
progressText: "",
|
||||
progressLabel: "",
|
||||
progressMain: "",
|
||||
@@ -454,6 +455,7 @@ document.addEventListener("alpine:init", () => {
|
||||
this.readingFont = this.settings.reading_font || "literata";
|
||||
this.fontSize = this.settings.font_size || 18;
|
||||
this.lineHeight = this.settings.line_height || 1.6;
|
||||
this.doublePageSpread = this.settings.double_page_spread ?? true;
|
||||
if (this.settings.reading_mode) {
|
||||
this.readingMode = this.settings.reading_mode;
|
||||
} else {
|
||||
@@ -492,6 +494,7 @@ document.addEventListener("alpine:init", () => {
|
||||
this.zoomPercent = this.renderer.zoomPercent;
|
||||
});
|
||||
this.computeFixedLayoutChapterBoundaries();
|
||||
this.applyDoublePageSpread();
|
||||
} else {
|
||||
this.renderer.setStyles?.(this.buildCSS());
|
||||
}
|
||||
@@ -692,6 +695,14 @@ document.addEventListener("alpine:init", () => {
|
||||
this.renderer.setAttribute("interaction-mode", next);
|
||||
this.interactionMode = next;
|
||||
},
|
||||
applyDoublePageSpread() {
|
||||
if (!this.isFixedLayout || !this.renderer) return;
|
||||
this.renderer.setAttribute(
|
||||
"spread",
|
||||
this.doublePageSpread ? "auto" : "none",
|
||||
);
|
||||
saveSettings({ double_page_spread: this.doublePageSpread });
|
||||
},
|
||||
goLeft() {
|
||||
this.view?.goLeft?.();
|
||||
},
|
||||
|
||||
@@ -78,7 +78,7 @@ export function getDefaultSettings(): ReaderSettings {
|
||||
font_size: 18,
|
||||
line_height: 1.6,
|
||||
margin_width: 20,
|
||||
double_page_spread: false,
|
||||
double_page_spread: true,
|
||||
reading_direction: "ltr",
|
||||
hardware_acceleration: true,
|
||||
panel_layout: {
|
||||
|
||||
Reference in New Issue
Block a user