Features and Localization Updates for 1.5.2
Enhances user experience with increased contrast option for titlebar buttons. Adds localization option for the PDF preview page, improving accessibility for international users. Includes localization option and upgrade message for the InnoSetup installer, ensuring a smoother and more informative installation process.
This commit is contained in:
@@ -17,6 +17,7 @@ const defaults: EMLy_GUI_Settings = {
|
||||
musicInspirationEnabled: false,
|
||||
reduceMotion: false,
|
||||
theme: "dark",
|
||||
increaseWindowButtonsContrast: false,
|
||||
};
|
||||
|
||||
class SettingsStore {
|
||||
|
||||
1
frontend/src/lib/types.d.ts
vendored
1
frontend/src/lib/types.d.ts
vendored
@@ -13,6 +13,7 @@ interface EMLy_GUI_Settings {
|
||||
musicInspirationEnabled?: boolean;
|
||||
reduceMotion?: boolean;
|
||||
theme?: "light" | "dark";
|
||||
increaseWindowButtonsContrast?: boolean;
|
||||
}
|
||||
|
||||
type SupportedLanguages = "en" | "it";
|
||||
|
||||
@@ -304,7 +304,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="controls">
|
||||
<div class="controls" class:high-contrast={settingsStore.settings.increaseWindowButtonsContrast}>
|
||||
<button class="btn" onclick={minimize}>─</button>
|
||||
|
||||
<button class="btn" onclick={toggleMaximize}>
|
||||
@@ -694,6 +694,10 @@
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.controls.high-contrast {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 46px;
|
||||
height: 100%;
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
enableUpdateChecker: false,
|
||||
reduceMotion: false,
|
||||
theme: "dark",
|
||||
increaseWindowButtonsContrast: false,
|
||||
};
|
||||
|
||||
async function setLanguage(
|
||||
@@ -80,6 +81,7 @@
|
||||
: (s.enableUpdateChecker ?? defaults.enableUpdateChecker ?? true),
|
||||
reduceMotion: s.reduceMotion ?? defaults.reduceMotion ?? false,
|
||||
theme: s.theme || defaults.theme || "light",
|
||||
increaseWindowButtonsContrast: s.increaseWindowButtonsContrast ?? defaults.increaseWindowButtonsContrast ?? false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -93,6 +95,7 @@
|
||||
!!a.enableUpdateChecker === !!b.enableUpdateChecker &&
|
||||
!!a.reduceMotion === !!b.reduceMotion &&
|
||||
(a.theme ?? "light") === (b.theme ?? "light") &&
|
||||
!!a.increaseWindowButtonsContrast === !!b.increaseWindowButtonsContrast &&
|
||||
JSON.stringify(a.previewFileSupportedTypes?.sort()) ===
|
||||
JSON.stringify(b.previewFileSupportedTypes?.sort())
|
||||
);
|
||||
@@ -467,6 +470,45 @@
|
||||
<p class="text-xs text-muted-foreground mt-2">
|
||||
{m.settings_reduce_motion_info()}
|
||||
</p>
|
||||
|
||||
<Separator />
|
||||
|
||||
<div
|
||||
class="flex items-center justify-between gap-4 rounded-lg border bg-card p-4"
|
||||
>
|
||||
<div>
|
||||
<div class="font-medium">
|
||||
{m.settings_window_buttons_contrast_label()}
|
||||
</div>
|
||||
<div class="text-sm text-muted-foreground">
|
||||
{m.settings_window_buttons_contrast_hint()}
|
||||
</div>
|
||||
</div>
|
||||
<Switch
|
||||
bind:checked={form.increaseWindowButtonsContrast}
|
||||
class="cursor-pointer hover:cursor-pointer"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex items-center justify-between gap-4 rounded-lg border bg-card p-4"
|
||||
>
|
||||
<div>
|
||||
<div class="font-medium">
|
||||
{m.settings_email_dark_viewer_label()}
|
||||
</div>
|
||||
<div class="text-sm text-muted-foreground">
|
||||
{m.settings_email_dark_viewer_hint()}
|
||||
</div>
|
||||
</div>
|
||||
<Switch
|
||||
bind:checked={form.useDarkEmailViewer}
|
||||
class="cursor-pointer hover:cursor-pointer"
|
||||
/>
|
||||
</div>
|
||||
<p class="text-xs text-muted-foreground mt-2">
|
||||
{m.settings_email_dark_viewer_info()}
|
||||
</p>
|
||||
</div>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
@@ -495,7 +537,7 @@
|
||||
{m.settings_export_button()}
|
||||
</Button>
|
||||
</div>
|
||||
<Separator />
|
||||
|
||||
<div
|
||||
class="flex items-center justify-between gap-4 rounded-lg border bg-card p-4"
|
||||
>
|
||||
@@ -640,29 +682,6 @@
|
||||
{m.settings_preview_pdf_builtin_info()}
|
||||
</p>
|
||||
</div>
|
||||
<Separator />
|
||||
|
||||
<div class="space-y-3">
|
||||
<div
|
||||
class="flex items-center justify-between gap-4 rounded-lg border bg-card p-4"
|
||||
>
|
||||
<div>
|
||||
<div class="font-medium">
|
||||
{m.settings_email_dark_viewer_label()}
|
||||
</div>
|
||||
<div class="text-sm text-muted-foreground">
|
||||
{m.settings_email_dark_viewer_hint()}
|
||||
</div>
|
||||
</div>
|
||||
<Switch
|
||||
bind:checked={form.useDarkEmailViewer}
|
||||
class="cursor-pointer hover:cursor-pointer"
|
||||
/>
|
||||
</div>
|
||||
<p class="text-xs text-muted-foreground mt-2">
|
||||
{m.settings_email_dark_viewer_info()}
|
||||
</p>
|
||||
</div>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
Quit,
|
||||
} from "$lib/wailsjs/runtime/runtime";
|
||||
import type { LayoutProps } from "./$types";
|
||||
import { settingsStore } from "$lib/stores/settings.svelte.js";
|
||||
|
||||
let { data, children }: LayoutProps = $props();
|
||||
|
||||
@@ -57,7 +58,7 @@
|
||||
>
|
||||
<div class="title">EMLy PDF Viewer</div>
|
||||
|
||||
<div class="controls">
|
||||
<div class="controls" class:high-contrast={settingsStore.settings.increaseWindowButtonsContrast}>
|
||||
<button class="btn" onclick={minimize}>─</button>
|
||||
<button class="btn" onclick={toggleMaximize}>
|
||||
{#if isMaximized}
|
||||
@@ -120,6 +121,10 @@
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.controls.high-contrast {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 46px;
|
||||
height: 100%;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
} from "@lucide/svelte";
|
||||
import { sidebarOpen } from "$lib/stores/app";
|
||||
import { toast } from "svelte-sonner";
|
||||
import * as m from "$lib/paraglide/messages.js";
|
||||
import * as pdfjsLib from "pdfjs-dist";
|
||||
import pdfWorker from "pdfjs-dist/build/pdf.worker.min.mjs?url";
|
||||
|
||||
@@ -63,9 +64,8 @@
|
||||
|
||||
await loadPDF();
|
||||
} else {
|
||||
toast.error("No PDF data provided");
|
||||
error =
|
||||
"No PDF data provided. Please open this window from the main EMLy application.";
|
||||
toast.error(m.pdf_error_no_data());
|
||||
error = m.pdf_error_no_data_desc();
|
||||
loading = false;
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -81,8 +81,7 @@
|
||||
const timeout = setTimeout(() => {
|
||||
if (loading) {
|
||||
loading = false;
|
||||
error =
|
||||
"Timeout loading PDF. The worker might have failed to initialize.";
|
||||
error = m.pdf_error_timeout();
|
||||
toast.error(error);
|
||||
}
|
||||
}, 10000);
|
||||
@@ -96,7 +95,7 @@
|
||||
loading = false;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
error = "Error parsing PDF: " + e;
|
||||
error = m.pdf_error_parsing() + e;
|
||||
loading = false;
|
||||
} finally {
|
||||
clearTimeout(timeout);
|
||||
@@ -135,7 +134,7 @@
|
||||
} catch (e: any) {
|
||||
if (e.name !== "RenderingCancelledException") {
|
||||
console.error(e);
|
||||
toast.error("Error rendering page: " + e.message);
|
||||
toast.error(m.pdf_error_rendering() + e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -189,7 +188,7 @@
|
||||
{#if loading}
|
||||
<div class="loading-overlay">
|
||||
<div class="spinner"></div>
|
||||
<div>Loading PDF...</div>
|
||||
<div>{m.pdf_loading()}</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -200,24 +199,24 @@
|
||||
{/if}
|
||||
|
||||
<div class="toolbar">
|
||||
<h1 class="title" title={filename}>{filename || "Image Viewer"}</h1>
|
||||
<h1 class="title" title={filename}>{filename || m.pdf_viewer_title()}</h1>
|
||||
|
||||
<div class="controls">
|
||||
<button class="btn" onclick={() => zoom(0.1)} title="Zoom In">
|
||||
<button class="btn" onclick={() => zoom(0.1)} title={m.pdf_zoom_in()}>
|
||||
<ZoomIn size="16" />
|
||||
</button>
|
||||
<button class="btn" onclick={() => zoom(-0.1)} title="Zoom Out">
|
||||
<button class="btn" onclick={() => zoom(-0.1)} title={m.pdf_zoom_out()}>
|
||||
<ZoomOut size="16" />
|
||||
</button>
|
||||
<div class="separator"></div>
|
||||
<button class="btn" onclick={() => rotate(-90)} title="Rotate Left">
|
||||
<button class="btn" onclick={() => rotate(-90)} title={m.pdf_rotate_left()}>
|
||||
<RotateCcw size="16" />
|
||||
</button>
|
||||
<button class="btn" onclick={() => rotate(90)} title="Rotate Right">
|
||||
<button class="btn" onclick={() => rotate(90)} title={m.pdf_rotate_right()}>
|
||||
<RotateCw size="16" />
|
||||
</button>
|
||||
<div class="separator"></div>
|
||||
<button class="btn" onclick={fitToWidth} title="Reset">
|
||||
<button class="btn" onclick={fitToWidth} title={m.pdf_fit_width()}>
|
||||
<AlignHorizontalSpaceAround size="16" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user