Cleanup settings
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
import { UserSettingsSolid, UploadSolid } from 'flowbite-svelte-icons';
|
||||
import { afterNavigate } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
import Settings from './Settings.svelte';
|
||||
import Settings from './Settings/Settings.svelte';
|
||||
import UploadModal from './UploadModal.svelte';
|
||||
import { settings } from '$lib/settings';
|
||||
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { Drawer, CloseButton, Toggle, Select, Input, Label, Button } from 'flowbite-svelte';
|
||||
import { UserSettingsSolid } from 'flowbite-svelte-icons';
|
||||
import { sineIn } from 'svelte/easing';
|
||||
import { resetSettings, settings, updateSetting } from '$lib/settings';
|
||||
import type { SettingsKey } from '$lib/settings';
|
||||
import { promptConfirmation } from '$lib/util';
|
||||
import { zoomDefault } from '$lib/panzoom';
|
||||
|
||||
let transitionParams = {
|
||||
x: 320,
|
||||
duration: 200,
|
||||
easing: sineIn
|
||||
};
|
||||
|
||||
export let hidden = true;
|
||||
|
||||
$: zoomModeValue = $settings.zoomDefault;
|
||||
$: fontSizeValue = $settings.fontSize;
|
||||
|
||||
let zoomModes = [
|
||||
{ value: 'zoomFitToScreen', name: 'Fit to screen' },
|
||||
{ value: 'zoomFitToWidth', name: 'Fit to width' },
|
||||
{ value: 'zoomOriginal', name: 'Original size' },
|
||||
{ value: 'keepZoom', name: 'Keep zoom' },
|
||||
{ value: 'keepZoomStart', name: 'Keep zoom, pan to top' }
|
||||
];
|
||||
|
||||
let fontSizes = [
|
||||
{ value: 'auto', name: 'auto' },
|
||||
{ value: '9', name: '9' },
|
||||
{ value: '10', name: '10' },
|
||||
{ value: '11', name: '11' },
|
||||
{ value: '12', name: '12' },
|
||||
{ value: '14', name: '14' },
|
||||
{ value: '16', name: '16' },
|
||||
{ value: '18', name: '18' },
|
||||
{ value: '20', name: '20' },
|
||||
{ value: '24', name: '24' },
|
||||
{ value: '32', name: '32' },
|
||||
{ value: '40', name: '40' },
|
||||
{ value: '48', name: '48' },
|
||||
{ value: '60', name: '60' }
|
||||
];
|
||||
|
||||
$: toggles = [
|
||||
{ key: 'rightToLeft', text: 'Right to left', value: $settings.rightToLeft },
|
||||
{ key: 'singlePageView', text: 'Single page view', value: $settings.singlePageView },
|
||||
{ key: 'hasCover', text: 'First page is cover', value: $settings.hasCover },
|
||||
{ key: 'textEditable', text: 'Editable text', value: $settings.textEditable },
|
||||
{ key: 'textBoxBorders', text: 'Text box borders', value: $settings.textBoxBorders },
|
||||
{ key: 'displayOCR', text: 'OCR enabled', value: $settings.displayOCR },
|
||||
{ key: 'boldFont', text: 'Bold font', value: $settings.boldFont },
|
||||
{ key: 'pageNum', text: 'Show page number', value: $settings.pageNum }
|
||||
] as { key: SettingsKey; text: string; value: any }[];
|
||||
|
||||
function onBackgroundColor(event: Event) {
|
||||
updateSetting('backgroundColor', (event.target as HTMLInputElement).value);
|
||||
}
|
||||
|
||||
function onSelectChange(event: Event, setting: SettingsKey) {
|
||||
updateSetting(setting, (event.target as HTMLInputElement).value);
|
||||
}
|
||||
|
||||
function onReset() {
|
||||
hidden = true;
|
||||
promptConfirmation('Restore default settings?', resetSettings);
|
||||
}
|
||||
</script>
|
||||
|
||||
<Drawer
|
||||
placement="right"
|
||||
transitionType="fly"
|
||||
width="lg:w-1/4 md:w-1/2 w-full"
|
||||
{transitionParams}
|
||||
bind:hidden
|
||||
id="settings"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<h5 id="drawer-label" class="inline-flex items-center mb-4 text-base font-semibold">
|
||||
<UserSettingsSolid class="w-4 h-4 mr-2.5" />Settings
|
||||
</h5>
|
||||
<CloseButton on:click={() => (hidden = true)} class="mb-4 dark:text-white" />
|
||||
</div>
|
||||
<div class="flex flex-col gap-5">
|
||||
<div>
|
||||
<Label>On page zoom:</Label>
|
||||
<Select
|
||||
items={zoomModes}
|
||||
value={zoomModeValue}
|
||||
on:change={(e) => onSelectChange(e, 'zoomDefault')}
|
||||
/>
|
||||
</div>
|
||||
{#each toggles as { key, text, value }}
|
||||
<Toggle size="small" checked={value} on:change={() => updateSetting(key, !value)}
|
||||
>{text}</Toggle
|
||||
>
|
||||
{/each}
|
||||
<div>
|
||||
<Label>Fontsize:</Label>
|
||||
<Select
|
||||
items={fontSizes}
|
||||
value={fontSizeValue}
|
||||
on:change={(e) => onSelectChange(e, 'fontSize')}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label>Background color:</Label>
|
||||
<Input type="color" on:change={onBackgroundColor} value={$settings.backgroundColor} />
|
||||
</div>
|
||||
<Button outline on:click={onReset}>Reset</Button>
|
||||
</div>
|
||||
</Drawer>
|
||||
65
src/lib/components/Settings/AnkiConnectSettings.svelte
Normal file
65
src/lib/components/Settings/AnkiConnectSettings.svelte
Normal file
@@ -0,0 +1,65 @@
|
||||
<script lang="ts">
|
||||
import { settings, updateAnkiSetting } from '$lib/settings';
|
||||
import { AccordionItem, Label, Toggle, Input } from 'flowbite-svelte';
|
||||
|
||||
$: disabled = !$settings.ankiConnectSettings.enabled;
|
||||
|
||||
let enabled = $settings.ankiConnectSettings.enabled;
|
||||
let cropImage = $settings.ankiConnectSettings.cropImage;
|
||||
let grabSentence = $settings.ankiConnectSettings.grabSentence;
|
||||
let overwriteImage = $settings.ankiConnectSettings.overwriteImage;
|
||||
|
||||
let pictureField = $settings.ankiConnectSettings.pictureField;
|
||||
let sentenceField = $settings.ankiConnectSettings.sentenceField;
|
||||
</script>
|
||||
|
||||
<AccordionItem>
|
||||
<span slot="header">Anki Connect</span>
|
||||
<div class="flex flex-col gap-5">
|
||||
<div>
|
||||
<Toggle bind:checked={enabled} on:change={() => updateAnkiSetting('enabled', enabled)}
|
||||
>AnkiConnect Integration Enabled</Toggle
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<Label>Picture field:</Label>
|
||||
<Input
|
||||
{disabled}
|
||||
type="text"
|
||||
bind:value={pictureField}
|
||||
on:change={() => updateAnkiSetting('pictureField', pictureField)}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label>Sentence field:</Label>
|
||||
<Input
|
||||
{disabled}
|
||||
type="text"
|
||||
bind:value={sentenceField}
|
||||
on:change={() => updateAnkiSetting('sentenceField', sentenceField)}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Toggle
|
||||
{disabled}
|
||||
bind:checked={cropImage}
|
||||
on:change={() => updateAnkiSetting('cropImage', cropImage)}>Crop image</Toggle
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<Toggle
|
||||
{disabled}
|
||||
bind:checked={overwriteImage}
|
||||
on:change={() => updateAnkiSetting('overwriteImage', overwriteImage)}
|
||||
>Overwrite image</Toggle
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<Toggle
|
||||
{disabled}
|
||||
bind:checked={grabSentence}
|
||||
on:change={() => updateAnkiSetting('grabSentence', grabSentence)}>Grab sentence</Toggle
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</AccordionItem>
|
||||
62
src/lib/components/Settings/ReaderSelects.svelte
Normal file
62
src/lib/components/Settings/ReaderSelects.svelte
Normal file
@@ -0,0 +1,62 @@
|
||||
<script lang="ts">
|
||||
import { Select, Input, Label } from 'flowbite-svelte';
|
||||
import { settings, updateSetting } from '$lib/settings';
|
||||
import type { SettingsKey } from '$lib/settings';
|
||||
|
||||
$: zoomModeValue = $settings.zoomDefault;
|
||||
$: fontSizeValue = $settings.fontSize;
|
||||
|
||||
let zoomModes = [
|
||||
{ value: 'zoomFitToScreen', name: 'Fit to screen' },
|
||||
{ value: 'zoomFitToWidth', name: 'Fit to width' },
|
||||
{ value: 'zoomOriginal', name: 'Original size' },
|
||||
{ value: 'keepZoom', name: 'Keep zoom' },
|
||||
{ value: 'keepZoomStart', name: 'Keep zoom, pan to top' }
|
||||
];
|
||||
|
||||
let fontSizes = [
|
||||
{ value: 'auto', name: 'auto' },
|
||||
{ value: '9', name: '9' },
|
||||
{ value: '10', name: '10' },
|
||||
{ value: '11', name: '11' },
|
||||
{ value: '12', name: '12' },
|
||||
{ value: '14', name: '14' },
|
||||
{ value: '16', name: '16' },
|
||||
{ value: '18', name: '18' },
|
||||
{ value: '20', name: '20' },
|
||||
{ value: '24', name: '24' },
|
||||
{ value: '32', name: '32' },
|
||||
{ value: '40', name: '40' },
|
||||
{ value: '48', name: '48' },
|
||||
{ value: '60', name: '60' }
|
||||
];
|
||||
|
||||
function onBackgroundColor(event: Event) {
|
||||
updateSetting('backgroundColor', (event.target as HTMLInputElement).value);
|
||||
}
|
||||
|
||||
function onSelectChange(event: Event, setting: SettingsKey) {
|
||||
updateSetting(setting, (event.target as HTMLInputElement).value);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<Label>On page zoom:</Label>
|
||||
<Select
|
||||
items={zoomModes}
|
||||
value={zoomModeValue}
|
||||
on:change={(e) => onSelectChange(e, 'zoomDefault')}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label>Fontsize:</Label>
|
||||
<Select
|
||||
items={fontSizes}
|
||||
value={fontSizeValue}
|
||||
on:change={(e) => onSelectChange(e, 'fontSize')}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label>Background color:</Label>
|
||||
<Input type="color" on:change={onBackgroundColor} value={$settings.backgroundColor} />
|
||||
</div>
|
||||
15
src/lib/components/Settings/ReaderSettings.svelte
Normal file
15
src/lib/components/Settings/ReaderSettings.svelte
Normal file
@@ -0,0 +1,15 @@
|
||||
<script lang="ts">
|
||||
import { Accordion, AccordionItem, Label, Toggle, Input } from 'flowbite-svelte';
|
||||
import ReaderSelects from './ReaderSelects.svelte';
|
||||
import ReaderToggles from './ReaderToggles.svelte';
|
||||
import { page } from '$app/stores';
|
||||
</script>
|
||||
|
||||
<AccordionItem open={$page.route.id === '/[manga]/[volume]'}>
|
||||
<span slot="header">Reader</span>
|
||||
<div class="flex flex-col gap-5">
|
||||
<ReaderSelects />
|
||||
<hr class="border-gray-100 opacity-10" />
|
||||
<ReaderToggles />
|
||||
</div>
|
||||
</AccordionItem>
|
||||
19
src/lib/components/Settings/ReaderToggles.svelte
Normal file
19
src/lib/components/Settings/ReaderToggles.svelte
Normal file
@@ -0,0 +1,19 @@
|
||||
<script lang="ts">
|
||||
import { settings, updateSetting, type SettingsKey } from '$lib/settings';
|
||||
import { Toggle } from 'flowbite-svelte';
|
||||
|
||||
$: toggles = [
|
||||
{ key: 'rightToLeft', text: 'Right to left', value: $settings.rightToLeft },
|
||||
{ key: 'singlePageView', text: 'Single page view', value: $settings.singlePageView },
|
||||
{ key: 'hasCover', text: 'First page is cover', value: $settings.hasCover },
|
||||
{ key: 'textEditable', text: 'Editable text', value: $settings.textEditable },
|
||||
{ key: 'textBoxBorders', text: 'Text box borders', value: $settings.textBoxBorders },
|
||||
{ key: 'displayOCR', text: 'OCR enabled', value: $settings.displayOCR },
|
||||
{ key: 'boldFont', text: 'Bold font', value: $settings.boldFont },
|
||||
{ key: 'pageNum', text: 'Show page number', value: $settings.pageNum }
|
||||
] as { key: SettingsKey; text: string; value: any }[];
|
||||
</script>
|
||||
|
||||
{#each toggles as { key, text, value }}
|
||||
<Toggle size="small" checked={value} on:change={() => updateSetting(key, !value)}>{text}</Toggle>
|
||||
{/each}
|
||||
52
src/lib/components/Settings/Settings.svelte
Normal file
52
src/lib/components/Settings/Settings.svelte
Normal file
@@ -0,0 +1,52 @@
|
||||
<script lang="ts">
|
||||
import { Drawer, CloseButton, Button, Accordion } from 'flowbite-svelte';
|
||||
import { UserSettingsSolid } from 'flowbite-svelte-icons';
|
||||
import { sineIn } from 'svelte/easing';
|
||||
import { resetSettings } from '$lib/settings';
|
||||
import { promptConfirmation } from '$lib/util';
|
||||
import AnkiConnectSettings from './AnkiConnectSettings.svelte';
|
||||
import ReaderSettings from './ReaderSettings.svelte';
|
||||
|
||||
let transitionParams = {
|
||||
x: 320,
|
||||
duration: 200,
|
||||
easing: sineIn
|
||||
};
|
||||
|
||||
export let hidden = true;
|
||||
|
||||
function onReset() {
|
||||
hidden = true;
|
||||
promptConfirmation('Restore default settings?', resetSettings);
|
||||
}
|
||||
|
||||
function onClose() {
|
||||
hidden = true;
|
||||
}
|
||||
</script>
|
||||
|
||||
<Drawer
|
||||
placement="right"
|
||||
transitionType="fly"
|
||||
width="lg:w-1/4 md:w-1/2 w-full"
|
||||
{transitionParams}
|
||||
bind:hidden
|
||||
id="settings"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<h5 id="drawer-label" class="inline-flex items-center mb-4 text-base font-semibold">
|
||||
<UserSettingsSolid class="w-4 h-4 mr-2.5" />Settings
|
||||
</h5>
|
||||
<CloseButton on:click={onClose} class="mb-4 dark:text-white" />
|
||||
</div>
|
||||
<div class="flex flex-col gap-5">
|
||||
<Accordion flush>
|
||||
<ReaderSettings />
|
||||
<AnkiConnectSettings />
|
||||
</Accordion>
|
||||
<div class="flex flex-col gap-2">
|
||||
<Button outline on:click={onReset}>Reset</Button>
|
||||
<Button outline on:click={onClose} color="light">Close</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Drawer>
|
||||
@@ -37,13 +37,26 @@ export type Settings = {
|
||||
backgroundColor: string;
|
||||
fontSize: FontSize;
|
||||
zoomDefault: ZoomModes;
|
||||
ankiConnectSettings: AnkiConnectSettings;
|
||||
};
|
||||
|
||||
export type SettingsKey = keyof Settings;
|
||||
|
||||
export type AnkiConnectSettings = {
|
||||
enabled: boolean;
|
||||
pictureField: string;
|
||||
sentenceField: string;
|
||||
cropImage: boolean;
|
||||
overwriteImage: boolean;
|
||||
grabSentence: boolean;
|
||||
}
|
||||
|
||||
export type AnkiSettingsKey = keyof AnkiConnectSettings;
|
||||
|
||||
|
||||
const defaultSettings: Settings = {
|
||||
rightToLeft: true,
|
||||
singlePageView: true,
|
||||
singlePageView: false,
|
||||
hasCover: false,
|
||||
displayOCR: true,
|
||||
textEditable: false,
|
||||
@@ -52,7 +65,15 @@ const defaultSettings: Settings = {
|
||||
pageNum: true,
|
||||
backgroundColor: '#0d0d0f',
|
||||
fontSize: 'auto',
|
||||
zoomDefault: 'zoomFitToScreen'
|
||||
zoomDefault: 'zoomFitToScreen',
|
||||
ankiConnectSettings: {
|
||||
enabled: false,
|
||||
cropImage: false,
|
||||
grabSentence: false,
|
||||
overwriteImage: true,
|
||||
pictureField: 'Picture',
|
||||
sentenceField: 'Sentence'
|
||||
}
|
||||
};
|
||||
|
||||
const stored = browser ? window.localStorage.getItem('settings') : undefined;
|
||||
@@ -72,6 +93,18 @@ export function updateSetting(key: SettingsKey, value: any) {
|
||||
zoomDefault();
|
||||
}
|
||||
|
||||
export function updateAnkiSetting(key: AnkiSettingsKey, value: any) {
|
||||
settings.update((settings) => {
|
||||
return {
|
||||
...settings,
|
||||
ankiConnectSettings: {
|
||||
...settings.ankiConnectSettings,
|
||||
[key]: value
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export function resetSettings() {
|
||||
settings.set(defaultSettings);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user