Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "royalrefresh",
"version": "1.5.0",
"version": "1.6.0",
"description": "A web extension for royalroad.com. For people who juggle multiple stories",
"main": "background.js",
"directories": {
Expand Down
12 changes: 12 additions & 0 deletions src/assets/patches/v1.6.0.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"version": "1.6.0",
"releasedOn": "2026-01-20",
"summary": "Enhanced scrolling options and accessibility improvements.",
"new": [
"You can now choose between 'Auto' and 'Instant' scrolling speeds when jumping to recaps"
],
"fixes": [
"Clearer explanations when your device's Reduced Motion settings affect animations",
"Improved reliability when jumping to the recap section"
]
}
25 changes: 7 additions & 18 deletions src/components/settings/BasicSettings.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,6 @@
onValidationChange(wordCountValidation.isValid)
}
})

// Compute effective scroll behavior - respects OS reduced motion preference
const effectiveScrollBehavior = $derived(
userPrefersReducedMotion ? "instant" : settings.scrollBehavior,
)
</script>

<h2>Recap Settings</h2>
Expand All @@ -77,26 +72,20 @@
{#if settings.enableJump}
<label>
<span>Scroll behavior</span>
<select
class="form-control"
value={effectiveScrollBehavior}
onchange={(e) =>
(settings.scrollBehavior = e.currentTarget
.value as ScrollBehavior)}
disabled={userPrefersReducedMotion}>
<option value="smooth">Animated scroll</option>
<select class="form-control" bind:value={settings.scrollBehavior}>
<option value="smooth">Auto (Recommended)</option>
<option value="instant">Instant</option>
</select>
</label>
{#if userPrefersReducedMotion}
{#if userPrefersReducedMotion && settings.scrollBehavior === "smooth"}
<div class="message info-message">
<p>
Scroll animations are disabled because <em
>prefers-reduced-motion</em> is enabled in your system settings.
<strong>System Reduced Motion Detected</strong>
</p>
<p>
To enable smooth scrolling, change your system's accessibility
settings to allow motion.
Your system has reduced motion enabled, so "Auto" will use
instant scrolling. If you prefer not to jump at all, disable
"Enable jump to recap" above.
</p>
</div>
{/if}
Expand Down
6 changes: 2 additions & 4 deletions src/entrypoints/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ import { restoreSelectors, setSettings } from "~/lib/utils/storage-utils"
export default defineBackground(() => {
browser.runtime.onInstalled.addListener(async (details) => {
if (details.reason === "install") {
// Use conservative defaults - first-time detection happens on UI side
// Use defaults
await setSettings({
...DEFAULTS,
hasDetectedReducedMotion: false, // Flag to trigger first-time detection
})
}

Expand All @@ -27,10 +26,9 @@ export default defineBackground(() => {
if (typeof message !== "object" || message === null) return

if ("request" in message && message.request === "getDefaultSettings") {
// Return basic defaults - first-time detection happens on UI side
// Return basic defaults
return Promise.resolve({
...DEFAULTS,
hasDetectedReducedMotion: false, // Flag to trigger first-time detection
})
}

Expand Down
4 changes: 2 additions & 2 deletions src/entrypoints/options/Options.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
BackButton,
GitHubButton,
PatchNotesButton,
} from "@/components/buttons"
import PatchNotes from "@/entrypoints/popup/PatchNotes.svelte"
} from "~/components/buttons"
import PatchNotes from "~/entrypoints/popup/PatchNotes.svelte"
import { PageHeader } from "~/components/layout"
import { AdvancedSettings, BasicSettings } from "~/components/settings"
import { getDefaults } from "~/lib/config/defaults"
Expand Down
14 changes: 7 additions & 7 deletions src/entrypoints/popup/Popup.svelte
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
<script lang="ts">
import { untrack } from "svelte"
import {
ActionButtons,
BackButton,
GitHubButton,
PatchNotesButton,
SettingsButton,
} from "@/components/buttons"
import PatchNotes from "@/entrypoints/popup/PatchNotes.svelte"
import AdvancedSettingsView from "@/entrypoints/popup/AdvancedSettingsView.svelte"
} from "~/components/buttons"
import AdvancedSettingsView from "~/entrypoints/popup/AdvancedSettingsView.svelte"
import PatchNotes from "~/entrypoints/popup/PatchNotes.svelte"
import { untrack } from "svelte"
import { PageHeader } from "~/components/layout"
import { AdvancedSettings, BasicSettings } from "~/components/settings"
import DEFAULTS from "~/lib/config/defaults"
import { BasicSettings } from "~/components/settings"
import { getDefaults } from "~/lib/config/defaults"
import { BrowserType, currentBrowser } from "~/lib/utils/platform"
import { getSettings, watchSettings } from "~/lib/utils/storage-utils"
import type { ExtensionSettings } from "~/types/types"
Expand All @@ -29,7 +29,7 @@
localSettings = await getSettings()
} catch (error) {
console.error("Failed to load settings:", error)
localSettings = DEFAULTS
localSettings = getDefaults()
}
}

Expand Down
23 changes: 3 additions & 20 deletions src/lib/config/defaults.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { ExtensionSelectors, ExtensionSettings } from "~/types/types"
import { devLog } from "../utils/logger"
import { prefersReducedMotion } from "../utils/platform"

export const DEFAULT_SELECTORS: ExtensionSelectors = {
Expand All @@ -17,14 +16,14 @@ export const DEFAULT_SELECTORS: ExtensionSelectors = {

const DEFAULTS: ExtensionSettings = {
wordCount: 250,
enableJump: false,
enableJump: true,
scrollBehavior: "smooth" as ScrollBehavior,
autoExpand: false,
...DEFAULT_SELECTORS,
}

/**
* Get defaults with prefers-reduced-motion detection for fresh installs only
* Get defaults
* For existing users, their settings are preserved completely
*/
export function getDefaults(existingSettings?: Partial<ExtensionSettings>) {
Expand All @@ -36,23 +35,7 @@ export function getDefaults(existingSettings?: Partial<ExtensionSettings>) {
}
}

// Fresh install: detect reduced motion preference
const reducedMotion = prefersReducedMotion()
devLog.log("Fresh install: prefersReducedMotion", reducedMotion)

if (!reducedMotion) {
// No reduced motion preference - safe to enable jump functionality
return {
...DEFAULTS,
enableJump: true,
scrollBehavior: "smooth" as ScrollBehavior,
}
}

// Default case (reduced motion or detection failed) - disable animations
return {
...DEFAULTS,
}
return { ...DEFAULTS }
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/lib/utils/logger.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const devLog = {
log: (...args: any[]) => {
if (import.meta.env.DEV) {
if (import.meta.env?.DEV) {
console.log(...args)
}
},
Expand Down
24 changes: 24 additions & 0 deletions src/lib/utils/migrations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { ExtensionSettings } from "~/types/types"
import { devLog } from "./logger"

export function migrateV1toV2(oldSettings: any): ExtensionSettings {
// Migration from v1 to v2: smoothScroll -> enableJump & scrollBehavior
if ("smoothScroll" in oldSettings) {
const { smoothScroll, ...rest } = oldSettings
const migrated: ExtensionSettings = {
...rest,
enableJump: smoothScroll === true, // Preserve user's choice
scrollBehavior: (smoothScroll
? "smooth"
: "instant") as ScrollBehavior,
}

devLog.log("WXT Migration v1→v2: smoothScroll ->", {
enableJump: migrated.enableJump,
scrollBehavior: migrated.scrollBehavior,
})

return migrated
}
return oldSettings as ExtensionSettings
}
78 changes: 4 additions & 74 deletions src/lib/utils/storage-utils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { storage } from "wxt/utils/storage"
import { DEFAULT_SELECTORS, getDefaults } from "~/lib/config/defaults"
import type { ExtensionSettings } from "~/types/types"
import { devLog } from "./logger"
import { prefersReducedMotion } from "./platform"
import { migrateV1toV2 } from "./migrations"

/**
* WXT storage utilities for extension settings with migration support
Expand All @@ -14,92 +13,23 @@ export const settingsStore = storage.defineItem<ExtensionSettings>(
{
fallback: {
wordCount: 250,
enableJump: true, // Will be adjusted in getSettings() based on reduced motion
enableJump: true, // Jump is a core feature, always enabled by default
scrollBehavior: "smooth" as ScrollBehavior,
autoExpand: false,
// hasDetectedReducedMotion is undefined for fresh installs - this triggers detection
...DEFAULT_SELECTORS,
},
version: 2,
migrations: {
2: (oldSettings: any) => {
// Migration from v1 to v2: smoothScroll -> enableJump & scrollBehavior
if ("smoothScroll" in oldSettings) {
const migrated = {
...oldSettings,
enableJump: oldSettings.smoothScroll === true,
scrollBehavior: (oldSettings.smoothScroll
? "smooth"
: "instant") as ScrollBehavior,
// Migration: mark as having been detected so we don't override user's choice
hasDetectedReducedMotion: true,
} as ExtensionSettings

// Remove the old property
delete (migrated as any).smoothScroll

devLog.log("WXT Migration v1→v2: smoothScroll ->", {
enableJump: migrated.enableJump,
scrollBehavior: migrated.scrollBehavior,
})

return migrated
}
return oldSettings as ExtensionSettings
},
2: migrateV1toV2,
},
},
)

/**
* Get current settings from storage
* Automatically performs first-time reduced motion detection if needed
*/
export async function getSettings(): Promise<ExtensionSettings> {
const settings = await settingsStore.getValue()

// Skip if we've already done detection
if (settings?.hasDetectedReducedMotion) {
return settings
}

try {
const reducedMotion = prefersReducedMotion()

let updatedSettings = {
...settings,
hasDetectedReducedMotion: true,
}

// For users without reduced motion preference, enable jump and animations by default if not already set
if (!reducedMotion) {
updatedSettings = {
...updatedSettings,
enableJump: settings?.enableJump ?? true,
scrollBehavior:
settings?.scrollBehavior ?? ("smooth" as ScrollBehavior),
}
} else {
// Respect reduced motion by ensuring instant scrolling and disabling animations
updatedSettings = {
...updatedSettings,
scrollBehavior: "instant" as ScrollBehavior,
}
}

await settingsStore.setValue(updatedSettings)
return updatedSettings
} catch (error) {
devLog.log("Could not detect reduced motion preference:", error)
}

// Fallback: just mark as detected
const fallbackSettings = {
...settings,
hasDetectedReducedMotion: true,
}
await settingsStore.setValue(fallbackSettings)
return fallbackSettings
return await settingsStore.getValue()
}

/**
Expand Down
Loading