refactor(reader): remove old callback-based feature files

- Delete gestures.ts: replaced by features/gestures.ts
- Delete keyboard-shortcuts.ts: replaced by features/keyboard-shortcuts.ts
- Delete progress-indicator.ts: replaced by features/progress-indicator.ts
- Old files used callback pattern, new files use init(context) pattern
This commit is contained in:
2026-04-04 13:38:28 -04:00
parent 7fd8ccb129
commit c3cf4717db
3 changed files with 0 additions and 327 deletions
-115
View File
@@ -1,115 +0,0 @@
// Touch gesture controls for mobile/tablet
// Procedural implementation (no OOP)
interface GestureHandlers {
onSwipeLeft: () => void;
onSwipeRight: () => void;
onSwipeUp: () => void;
onSwipeDown: () => void;
onPinch: (scale: number) => void;
onTap: () => void;
onDoubleTap: () => void;
}
interface GestureState {
touchStartX: number;
touchStartY: number;
touchStartTime: number;
lastTapTime: number;
initialPinchDistance: number;
scale: number;
}
function setupGestureControls(
container: HTMLElement,
handlers: GestureHandlers,
): void {
let state: GestureState = {
touchStartX: 0,
touchStartY: 0,
touchStartTime: 0,
lastTapTime: 0,
initialPinchDistance: 0,
scale: 1,
};
container.addEventListener(
"touchstart",
(e) => {
if (e.touches.length === 1) {
state.touchStartX = e.touches[0].clientX;
state.touchStartY = e.touches[0].clientY;
state.touchStartTime = Date.now();
} else if (e.touches.length === 2) {
state.initialPinchDistance = getPinchDistance(e.touches);
}
},
{ passive: true },
);
container.addEventListener(
"touchend",
(e) => {
const deltaX = e.changedTouches[0].clientX - state.touchStartX;
const deltaY = e.changedTouches[0].clientY - state.touchStartY;
const deltaTime = Date.now() - state.touchStartTime;
if (Math.abs(deltaX) < 30 && Math.abs(deltaY) < 30 && deltaTime < 300) {
const now = Date.now();
if (now - state.lastTapTime < 300) {
handlers.onDoubleTap();
state.lastTapTime = 0;
} else {
state.lastTapTime = now;
setTimeout(() => {
if (state.lastTapTime !== 0) {
handlers.onTap();
}
}, 300);
}
return;
}
const minSwipeDistance = 50;
const maxSwipeTime = 500;
if (deltaTime > maxSwipeTime) return;
if (Math.abs(deltaX) > Math.abs(deltaY)) {
if (deltaX > minSwipeDistance) {
handlers.onSwipeRight();
} else if (deltaX < -minSwipeDistance) {
handlers.onSwipeLeft();
}
} else {
if (deltaY > minSwipeDistance) {
handlers.onSwipeDown();
} else if (deltaY < -minSwipeDistance) {
handlers.onSwipeUp();
}
}
},
{ passive: true },
);
container.addEventListener(
"touchmove",
(e) => {
if (e.touches.length === 2) {
const currentDistance = getPinchDistance(e.touches);
if (state.initialPinchDistance > 0) {
const scale = currentDistance / state.initialPinchDistance;
state.scale = scale;
handlers.onPinch(scale);
}
}
},
{ passive: true },
);
}
function getPinchDistance(touches: TouchList): number {
const dx = touches[0].clientX - touches[1].clientX;
const dy = touches[0].clientY - touches[1].clientY;
return Math.sqrt(dx * dx + dy * dy);
}
-146
View File
@@ -1,146 +0,0 @@
// Extended keyboard shortcuts for all readers
// Procedural implementation (no OOP)
interface KeyboardShortcutHandler {
onNextPage: () => void;
onPreviousPage: () => void;
onNextChapter: () => void;
onPreviousChapter: () => void;
onGoToPage: (page: number) => void;
onToggleBookmark: () => void;
onZoomIn: () => void;
onZoomOut: () => void;
onToggleFullscreen: () => void;
onClose: () => void;
}
function setupKeyboardShortcuts(
container: HTMLElement,
handlers: KeyboardShortcutHandler,
maxPage: number,
): void {
container.addEventListener("keydown", (e) => {
if (
e.target instanceof HTMLInputElement ||
e.target instanceof HTMLTextAreaElement
) {
return;
}
switch (e.key) {
case "ArrowRight":
case "PageDown":
case "l":
e.preventDefault();
handlers.onNextPage();
break;
case "ArrowLeft":
case "PageUp":
case "h":
e.preventDefault();
handlers.onPreviousPage();
break;
case "ArrowUp":
case "k":
e.preventDefault();
handlers.onPreviousPage();
break;
case "ArrowDown":
case "j":
e.preventDefault();
handlers.onNextPage();
break;
case " ":
e.preventDefault();
handlers.onNextPage();
break;
case "Home":
e.preventDefault();
handlers.onGoToPage(1);
break;
case "End":
e.preventDefault();
handlers.onGoToPage(maxPage);
break;
case "b":
if (!e.ctrlKey && !e.metaKey) {
e.preventDefault();
handlers.onToggleBookmark();
}
break;
case "+":
case "=":
e.preventDefault();
handlers.onZoomIn();
break;
case "-":
case "_":
e.preventDefault();
handlers.onZoomOut();
break;
case "0":
e.preventDefault();
handlers.onZoomIn();
handlers.onZoomIn();
handlers.onZoomIn();
break;
case "f":
if (!e.ctrlKey && !e.metaKey) {
e.preventDefault();
handlers.onToggleFullscreen();
}
break;
case "Escape":
e.preventDefault();
handlers.onClose();
break;
default:
if (e.key >= "1" && e.key <= "9") {
const targetPage = Math.floor((parseInt(e.key) / 10) * maxPage);
e.preventDefault();
handlers.onGoToPage(targetPage);
}
}
});
}
function showShortcutHelp(): void {
const help = document.createElement("div");
help.className =
"keyboard-shortcut-help fixed inset-0 bg-black bg-opacity-80 flex items-center justify-center z-50";
help.innerHTML = `
<div class="bg-gray-800 rounded-lg p-6 max-w-md">
<h2 class="text-xl font-bold mb-4">Keyboard Shortcuts</h2>
<div class="grid grid-cols-2 gap-4 text-sm">
<div><kbd class="bg-gray-700 px-2 py-1 rounded">→</kbd> / <kbd class="bg-gray-700 px-2 py-1 rounded">Space</kbd> Next page</div>
<div><kbd class="bg-gray-700 px-2 py-1 rounded">←</kbd> Previous page</div>
<div><kbd class="bg-gray-700 px-2 py-1 rounded">Home</kbd> First page</div>
<div><kbd class="bg-gray-700 px-2 py-1 rounded">End</kbd> Last page</div>
<div><kbd class="bg-gray-700 px-2 py-1 rounded">+</kbd> / <kbd class="bg-gray-700 px-2 py-1 rounded">-</kbd> Zoom</div>
<div><kbd class="bg-gray-700 px-2 py-1 rounded">B</kbd> Toggle bookmark</div>
<div><kbd class="bg-gray-700 px-2 py-1 rounded">F</kbd> Fullscreen</div>
<div><kbd class="bg-gray-700 px-2 py-1 rounded">1-9</kbd> Jump to %</div>
</div>
<button class="mt-4 px-4 py-2 bg-blue-600 rounded" onclick="this.closest('.keyboard-shortcut-help').remove()">
Close
</button>
</div>
`;
document.body.appendChild(help);
help.addEventListener("click", (e) => {
if (e.target === help) help.remove();
});
}
-66
View File
@@ -1,66 +0,0 @@
// KOReader-style switchable progress indicator
import { Alpine } from "../alpine";
import { getReadingSpeed } from "./api";
interface ProgressDisplay {
mode: "pages" | "chapter" | "percentage" | "time-left";
text: string;
}
function calculateProgress(
currentPage: number,
totalPages: number,
currentChapterPage: number,
chapterPages: number,
readingSpeed?: ReadingSpeed,
): ProgressDisplay {
const mode = getCurrentProgressMode(); // From settings
switch (mode) {
case "pages":
return {
mode: "pages",
text: `${currentPage}/${totalPages}`,
};
case "chapter":
return {
mode: "chapter",
text: `${currentChapterPage}/${chapterPages}`,
};
case "percentage":
const percentage = Math.round((currentPage / totalPages) * 100);
return {
mode: "percentage",
text: `${percentage}%`,
};
case "time-left":
if (!readingSpeed) {
return { mode: "time-left", text: "--:--" };
}
const pagesLeft = totalPages - currentPage;
const minutesLeft = pagesLeft / readingSpeed.pages_per_minute;
const hours = Math.floor(minutesLeft / 60);
const mins = Math.round(minutesLeft % 60);
return {
mode: "time-left",
text: `${hours}h ${mins}m`,
};
}
}
function cycleProgressMode(): void {
const modes: Array<"pages" | "chapter" | "percentage" | "time-left"> = [
"pages",
"chapter",
"percentage",
"time-left",
];
const currentMode = getCurrentProgressMode();
const currentIndex = modes.indexOf(currentMode);
const nextMode = modes[(currentIndex + 1) % modes.length];
setProgressMode(nextMode);
}