Various QOL changes
This commit is contained in:
@@ -10,7 +10,7 @@ type CropperModal = {
|
|||||||
|
|
||||||
export const cropperStore = writable<CropperModal | undefined>(undefined);
|
export const cropperStore = writable<CropperModal | undefined>(undefined);
|
||||||
|
|
||||||
export function showCropper(image: string, sentence: string) {
|
export function showCropper(image: string, sentence?: string) {
|
||||||
cropperStore.set({
|
cropperStore.set({
|
||||||
open: true,
|
open: true,
|
||||||
image,
|
image,
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ export async function imageToWebp(source: File) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function updateLastCard(imageData: string | null | undefined, sentence: string) {
|
export async function updateLastCard(imageData: string | null | undefined, sentence?: string) {
|
||||||
const {
|
const {
|
||||||
overwriteImage,
|
overwriteImage,
|
||||||
enabled,
|
enabled,
|
||||||
@@ -88,7 +88,7 @@ export async function updateLastCard(imageData: string | null | undefined, sente
|
|||||||
|
|
||||||
const fields: Record<string, any> = {};
|
const fields: Record<string, any> = {};
|
||||||
|
|
||||||
if (grabSentence) {
|
if (grabSentence && sentence) {
|
||||||
fields[sentenceField] = sentence;
|
fields[sentenceField] = sentence;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { afterNavigate } from '$app/navigation';
|
import { afterNavigate } from '$app/navigation';
|
||||||
import { cropperStore, getCroppedImg, updateLastCard, type Pixels } from '$lib/anki-connect';
|
import { cropperStore, getCroppedImg, updateLastCard, type Pixels } from '$lib/anki-connect';
|
||||||
|
import { settings } from '$lib/settings';
|
||||||
import { Button, Modal, Spinner } from 'flowbite-svelte';
|
import { Button, Modal, Spinner } from 'flowbite-svelte';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import Cropper from 'svelte-easy-crop';
|
import Cropper from 'svelte-easy-crop';
|
||||||
@@ -43,7 +44,7 @@
|
|||||||
<Modal title="Crop image" bind:open on:{close}>
|
<Modal title="Crop image" bind:open on:{close}>
|
||||||
{#if $cropperStore?.image && !loading}
|
{#if $cropperStore?.image && !loading}
|
||||||
<div class=" flex flex-col gap-2">
|
<div class=" flex flex-col gap-2">
|
||||||
<div class="relative w-full h-[55svh] sm:h-[70svh]">
|
<div class="relative w-full h-[55svh] sm:h-[65svh]">
|
||||||
<Cropper
|
<Cropper
|
||||||
zoomSpeed={0.5}
|
zoomSpeed={0.5}
|
||||||
maxZoom={10}
|
maxZoom={10}
|
||||||
@@ -51,6 +52,12 @@
|
|||||||
on:cropcomplete={onCropComplete}
|
on:cropcomplete={onCropComplete}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{#if $settings.ankiConnectSettings.grabSentence && $cropperStore?.sentence}
|
||||||
|
<p>
|
||||||
|
<b>Sentence:</b>
|
||||||
|
{$cropperStore?.sentence}
|
||||||
|
</p>
|
||||||
|
{/if}
|
||||||
<Button on:click={onCrop}>Crop</Button>
|
<Button on:click={onCrop}>Crop</Button>
|
||||||
<Button on:click={close} outline color="light">Close</Button>
|
<Button on:click={close} outline color="light">Close</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
74
src/lib/components/Reader/QuickActions.svelte
Normal file
74
src/lib/components/Reader/QuickActions.svelte
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { zoomFitToScreen } from '$lib/panzoom';
|
||||||
|
import { SpeedDial, SpeedDialButton } from 'flowbite-svelte';
|
||||||
|
import { settings } from '$lib/settings';
|
||||||
|
import {
|
||||||
|
ArrowLeftOutline,
|
||||||
|
ArrowRightOutline,
|
||||||
|
ImageOutline,
|
||||||
|
ZoomOutOutline
|
||||||
|
} from 'flowbite-svelte-icons';
|
||||||
|
import { imageToWebp, showCropper, updateLastCard } from '$lib/anki-connect';
|
||||||
|
import { promptConfirmation } from '$lib/util';
|
||||||
|
|
||||||
|
export let left: (_e: any, ingoreTimeOut?: boolean) => void;
|
||||||
|
export let right: (_e: any, ingoreTimeOut?: boolean) => void;
|
||||||
|
export let src: File;
|
||||||
|
|
||||||
|
let open = false;
|
||||||
|
|
||||||
|
function handleZoom() {
|
||||||
|
zoomFitToScreen();
|
||||||
|
open = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleLeft(_e: Event) {
|
||||||
|
left(_e, true);
|
||||||
|
open = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleRight(_e: Event) {
|
||||||
|
right(_e, true);
|
||||||
|
open = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onUpdateCard() {
|
||||||
|
if ($settings.ankiConnectSettings.enabled) {
|
||||||
|
if ($settings.ankiConnectSettings.cropImage) {
|
||||||
|
showCropper(URL.createObjectURL(src));
|
||||||
|
} else {
|
||||||
|
promptConfirmation('Add image to last created anki card?', async () => {
|
||||||
|
const imageData = await imageToWebp(src);
|
||||||
|
updateLastCard(imageData);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
open = false;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if $settings.quickActions}
|
||||||
|
<SpeedDial
|
||||||
|
tooltip="none"
|
||||||
|
trigger="click"
|
||||||
|
defaultClass="absolute end-3 bottom-3 z-50"
|
||||||
|
outline
|
||||||
|
color="dark"
|
||||||
|
bind:open
|
||||||
|
>
|
||||||
|
{#if $settings.ankiConnectSettings.enabled}
|
||||||
|
<SpeedDialButton on:click={onUpdateCard}>
|
||||||
|
<ImageOutline />
|
||||||
|
</SpeedDialButton>
|
||||||
|
{/if}
|
||||||
|
<SpeedDialButton on:click={handleZoom}>
|
||||||
|
<ZoomOutOutline />
|
||||||
|
</SpeedDialButton>
|
||||||
|
<SpeedDialButton on:click={handleRight}>
|
||||||
|
<ArrowRightOutline />
|
||||||
|
</SpeedDialButton>
|
||||||
|
<SpeedDialButton on:click={handleLeft}>
|
||||||
|
<ArrowLeftOutline />
|
||||||
|
</SpeedDialButton>
|
||||||
|
</SpeedDial>
|
||||||
|
{/if}
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
import { page as pageStore } from '$app/stores';
|
import { page as pageStore } from '$app/stores';
|
||||||
import SettingsButton from './SettingsButton.svelte';
|
import SettingsButton from './SettingsButton.svelte';
|
||||||
import { getCharCount } from '$lib/util/count-chars';
|
import { getCharCount } from '$lib/util/count-chars';
|
||||||
import { afterUpdate } from 'svelte';
|
import QuickActions from './QuickActions.svelte';
|
||||||
|
|
||||||
// TODO: Refactor this whole mess
|
// TODO: Refactor this whole mess
|
||||||
export let volumeSettings: VolumeSettings;
|
export let volumeSettings: VolumeSettings;
|
||||||
@@ -196,7 +196,7 @@
|
|||||||
const { scale } = $panzoomStore.getTransform();
|
const { scale } = $panzoomStore.getTransform();
|
||||||
|
|
||||||
if (scale < 0.6) {
|
if (scale < 0.6) {
|
||||||
$panzoomStore.zoomTo(clientX, clientY, 1.5);
|
$panzoomStore.zoomTo(clientX, clientY, 1.4);
|
||||||
} else {
|
} else {
|
||||||
zoomFitToScreen();
|
zoomFitToScreen();
|
||||||
}
|
}
|
||||||
@@ -213,8 +213,9 @@
|
|||||||
<svelte:head>
|
<svelte:head>
|
||||||
<title>{volume?.mokuroData.volume || 'Volume'}</title>
|
<title>{volume?.mokuroData.volume || 'Volume'}</title>
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
<SettingsButton />
|
|
||||||
{#if volume && pages}
|
{#if volume && pages}
|
||||||
|
<QuickActions {left} {right} src={Object.values(volume?.files)[index]} />
|
||||||
|
<SettingsButton />
|
||||||
<Cropper />
|
<Cropper />
|
||||||
<Popover placement="bottom" trigger="click" triggeredBy="#page-num" class="z-20 w-full max-w-xs">
|
<Popover placement="bottom" trigger="click" triggeredBy="#page-num" class="z-20 w-full max-w-xs">
|
||||||
<div class="flex flex-col gap-3">
|
<div class="flex flex-col gap-3">
|
||||||
@@ -266,11 +267,13 @@
|
|||||||
<Panzoom>
|
<Panzoom>
|
||||||
<button
|
<button
|
||||||
class="h-full fixed -left-full z-10 w-full hover:bg-slate-400 opacity-[0.01]"
|
class="h-full fixed -left-full z-10 w-full hover:bg-slate-400 opacity-[0.01]"
|
||||||
|
style:margin-left={`${$settings.edgeButtonWidth}px`}
|
||||||
on:mousedown={mouseDown}
|
on:mousedown={mouseDown}
|
||||||
on:mouseup={left}
|
on:mouseup={left}
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
class="h-full fixed -right-full z-10 w-full hover:bg-slate-400 opacity-[0.01]"
|
class="h-full fixed -right-full z-10 w-full hover:bg-slate-400 opacity-[0.01]"
|
||||||
|
style:margin-right={`${$settings.edgeButtonWidth}px`}
|
||||||
on:mousedown={mouseDown}
|
on:mousedown={mouseDown}
|
||||||
on:mouseup={right}
|
on:mouseup={right}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { goto } from '$app/navigation';
|
|
||||||
import { page } from '$app/stores';
|
|
||||||
import { toggleFullScreen } from '$lib/panzoom';
|
import { toggleFullScreen } from '$lib/panzoom';
|
||||||
import { isReader } from '$lib/util';
|
import { isReader } from '$lib/util';
|
||||||
|
|
||||||
@@ -10,7 +8,6 @@
|
|||||||
{#if isReader()}
|
{#if isReader()}
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<Button color="alternative" on:click={toggleFullScreen}>Toggle fullscreen</Button>
|
<Button color="alternative" on:click={toggleFullScreen}>Toggle fullscreen</Button>
|
||||||
<Button color="alternative" on:click={() => goto(`/${$page.params.manga}`)}>Close reader</Button
|
<Button color="alternative" on:click={() => history.back()}>Close reader</Button>
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -4,9 +4,14 @@
|
|||||||
import ReaderToggles from './ReaderToggles.svelte';
|
import ReaderToggles from './ReaderToggles.svelte';
|
||||||
import { settings, updateSetting } from '$lib/settings';
|
import { settings, updateSetting } from '$lib/settings';
|
||||||
|
|
||||||
let value = $settings.swipeThreshold;
|
let swipeThresholdValue = $settings.swipeThreshold;
|
||||||
function onChange() {
|
let edgeButtonWidthValue = $settings.edgeButtonWidth;
|
||||||
updateSetting('swipeThreshold', value);
|
function onSwipeChange() {
|
||||||
|
updateSetting('swipeThreshold', swipeThresholdValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onWidthChange() {
|
||||||
|
updateSetting('edgeButtonWidth', edgeButtonWidthValue);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -18,7 +23,17 @@
|
|||||||
<ReaderToggles />
|
<ReaderToggles />
|
||||||
<div>
|
<div>
|
||||||
<Label>Swipe threshold</Label>
|
<Label>Swipe threshold</Label>
|
||||||
<Range on:change={onChange} min={20} max={90} disabled={!$settings.mobile} bind:value />
|
<Range
|
||||||
|
on:change={onSwipeChange}
|
||||||
|
min={20}
|
||||||
|
max={90}
|
||||||
|
disabled={!$settings.mobile}
|
||||||
|
bind:value={swipeThresholdValue}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Label>Edge button width</Label>
|
||||||
|
<Range on:change={onWidthChange} min={1} max={100} bind:value={edgeButtonWidthValue} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</AccordionItem>
|
</AccordionItem>
|
||||||
|
|||||||
@@ -10,7 +10,8 @@
|
|||||||
{ key: 'pageNum', text: 'Show page number', value: $settings.pageNum },
|
{ key: 'pageNum', text: 'Show page number', value: $settings.pageNum },
|
||||||
{ key: 'charCount', text: 'Show character count', value: $settings.charCount },
|
{ key: 'charCount', text: 'Show character count', value: $settings.charCount },
|
||||||
{ key: 'mobile', text: 'Mobile', value: $settings.mobile },
|
{ key: 'mobile', text: 'Mobile', value: $settings.mobile },
|
||||||
{ key: 'showTimer', text: 'Show timer', value: $settings.showTimer }
|
{ key: 'showTimer', text: 'Show timer', value: $settings.showTimer },
|
||||||
|
{ key: 'quickActions', text: 'Show quick actions', value: $settings.quickActions }
|
||||||
] as { key: SettingsKey; text: string; value: any }[];
|
] as { key: SettingsKey; text: string; value: any }[];
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
import VolumeSettings from './Volume/VolumeSettings.svelte';
|
import VolumeSettings from './Volume/VolumeSettings.svelte';
|
||||||
import About from './About.svelte';
|
import About from './About.svelte';
|
||||||
import QuickAccess from './QuickAccess.svelte';
|
import QuickAccess from './QuickAccess.svelte';
|
||||||
|
import { beforeNavigate } from '$app/navigation';
|
||||||
|
|
||||||
let transitionParams = {
|
let transitionParams = {
|
||||||
x: 320,
|
x: 320,
|
||||||
@@ -30,6 +31,13 @@
|
|||||||
function onClose() {
|
function onClose() {
|
||||||
hidden = true;
|
hidden = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
beforeNavigate((nav) => {
|
||||||
|
if (!hidden) {
|
||||||
|
nav.cancel();
|
||||||
|
hidden = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Drawer
|
<Drawer
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
import { AccordionItem, Helper, Toggle } from 'flowbite-svelte';
|
import { AccordionItem, Helper, Toggle } from 'flowbite-svelte';
|
||||||
|
|
||||||
$: toggles = [
|
$: toggles = [
|
||||||
{ key: 'rightToLeft', text: 'Right to left', value: $settings.volumeDefaults.rightToLeft },
|
{ key: 'rightToLeft', text: 'Right to left', value: $settings.volumeDefaults?.rightToLeft },
|
||||||
{
|
{
|
||||||
key: 'singlePageView',
|
key: 'singlePageView',
|
||||||
text: 'Single page view',
|
text: 'Single page view',
|
||||||
value: $settings.volumeDefaults.singlePageView
|
value: $settings.volumeDefaults?.singlePageView
|
||||||
},
|
},
|
||||||
{ key: 'hasCover', text: 'First page is cover', value: $settings.volumeDefaults.hasCover }
|
{ key: 'hasCover', text: 'First page is cover', value: $settings.volumeDefaults?.hasCover }
|
||||||
] as { key: VolumeDefaultsKey; text: string; value: any }[];
|
] as { key: VolumeDefaultsKey; text: string; value: any }[];
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,9 @@ export type Settings = {
|
|||||||
mobile: boolean;
|
mobile: boolean;
|
||||||
backgroundColor: string;
|
backgroundColor: string;
|
||||||
swipeThreshold: number;
|
swipeThreshold: number;
|
||||||
|
edgeButtonWidth: number;
|
||||||
showTimer: boolean;
|
showTimer: boolean;
|
||||||
|
quickActions: boolean;
|
||||||
fontSize: FontSize;
|
fontSize: FontSize;
|
||||||
zoomDefault: ZoomModes;
|
zoomDefault: ZoomModes;
|
||||||
volumeDefaults: VolumeDefaults;
|
volumeDefaults: VolumeDefaults;
|
||||||
@@ -72,7 +74,9 @@ const defaultSettings: Settings = {
|
|||||||
mobile: false,
|
mobile: false,
|
||||||
backgroundColor: '#030712',
|
backgroundColor: '#030712',
|
||||||
swipeThreshold: 50,
|
swipeThreshold: 50,
|
||||||
|
edgeButtonWidth: 10,
|
||||||
showTimer: false,
|
showTimer: false,
|
||||||
|
quickActions: true,
|
||||||
fontSize: 'auto',
|
fontSize: 'auto',
|
||||||
zoomDefault: 'zoomFitToScreen',
|
zoomDefault: 'zoomFitToScreen',
|
||||||
volumeDefaults: {
|
volumeDefaults: {
|
||||||
|
|||||||
Reference in New Issue
Block a user