Skip to content

Upgrade remaining components to Svelte 5 syntax#962

Merged
FyreByrd merged 8 commits into
mainfrom
upgrade/svelte-5
May 26, 2026
Merged

Upgrade remaining components to Svelte 5 syntax#962
FyreByrd merged 8 commits into
mainfrom
upgrade/svelte-5

Conversation

@FyreByrd

@FyreByrd FyreByrd commented May 22, 2026

Copy link
Copy Markdown
Collaborator

Closes #819, #890

Summary by CodeRabbit

  • Refactor

    • Modernized component patterns and navigation calls for more consistent routing
    • Updated asset handling so images, audio, and video resolve reliably across deployments
    • Migrated many UI controls and icons to updated prop handling for more predictable sizing/behavior
  • Chores

    • Adjusted linting configuration (commented guidance for hash-based navigation)

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 22, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@FyreByrd, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 44 minutes and 35 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bc686aee-2bb3-4466-b862-89961fd188e6

📥 Commits

Reviewing files that changed from the base of the PR and between 867f5a2 and fbe804d.

📒 Files selected for processing (1)
  • src/routes/plans/[id]/settings/+page.svelte
📝 Walkthrough

Walkthrough

Migration to Svelte 5 runes across the codebase: replace legacy props/reactivity/event directives with $props(), $bindable(), $derived, $effect, convert asset URL usage from base to asset() and navigation to goto(resolve(...)), and adjust ESLint rules and a few supporting deletions.

Changes

Svelte 5 Migration: Runes, Props API, and Asset/Navigation Helpers

Layer / File(s) Summary
All changed files (icons, components, routes, navigation, assets, config)
src/lib/icons/*, src/lib/components/*, src/lib/navigate/index.ts, src/lib/video/index.ts, src/routes/**, eslint.config.js, src/lib/data/plansData.ts
Entire PR migrates components and routes to Svelte 5 runes: replaces export let with $props() (many icon components), converts reactive $: statements to $derived/$effect (core components like Slider/StackView/HistoryCard), swaps on:click handlers for raw onclick in templates, switches static asset construction from base to asset() and route navigation to goto(resolve(...)), and updates ESLint navigation rule usage.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • chrisvire
  • eomerdws

"🐰 A hop, a patch, a tiny tweak—
Props now runes, and imports sleek.
Images found with asset()’s glow,
Routes resolve where hashes go.
The rabbit cheers: the migration’s neat!"

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR includes out-of-scope changes that go beyond Svelte 5 syntax migration: replacement of the gotoRoute helper with goto+resolve represents architectural navigation changes not mandated by the Svelte 5 migration guide. Separate the navigation architecture changes (replacing gotoRoute with goto+resolve) into a distinct PR from the Svelte 5 syntax migration to maintain clear separation of concerns.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Upgrade remaining components to Svelte 5 syntax' is concise, specific, and clearly summarizes the main objective of migrating components to Svelte 5 runes-based syntax.
Linked Issues check ✅ Passed The PR successfully implements Svelte 5 syntax migration across all component files, including runes adoption ($props, $derived, $effect), event handler modernization, asset path resolution updates, and navigation helper replacements.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch upgrade/svelte-5

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/components/FontSelector.svelte`:
- Around line 13-15: The modal opens with a stale selectedFont value; update
selectedFont from the currentFont store/value before showing the dialog. In the
export function showModal() (and the equivalent open/submit path around the same
modal usage), read the latest currentFont (or $currentFont) and assign it to
selectedFont immediately prior to calling modal.showModal(), ensuring the
selection reflects the currentFont when the modal opens.

In `@src/lib/components/HistoryCard.svelte`:
- Line 55: The inline style on the clickable div using "text-decorationnone;" is
invalid and being ignored; update the div with the correct CSS declaration
(e.g., "text-decoration: none;") or remove the style attribute entirely if not
needed, by editing the element that contains onclick={onHistoryClick} to use a
valid style string or class name so the intended no-text-decoration behavior is
applied.

In `@src/lib/components/StackView.svelte`:
- Around line 118-121: In StackView.svelte change the onclick handler so
insideClick receives the actual clicked element instead of the outer container:
keep e.stopPropagation(), then compute const clicked = (e.target as
HTMLElement).closest('a') ?? e.target and call insideClick(clicked); this
ensures insideClick (used to check data-start-ref or class ref-link) sees the
generated <a> even when wrapped by tooltips or other wrappers.

In `@src/routes/plans/`[id]/settings/+page.svelte:
- Around line 21-24: Compute a single guarded planId from data.planConfig (e.g.
const planId = data.planConfig?.id) and use that in backNavigation and the start
action instead of accessing data.planConfig directly; if planId is missing do an
early return (or show a fallback) to avoid routing to `/plans/undefined` or
throwing on click—update the backNavigation function (which calls
gotoRoute(`/plans/${id}`)) and the other handler around lines 52-54 to use this
guarded planId and return immediately when it’s falsy.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 27d0830f-4f46-4c56-9852-9c0442931502

📥 Commits

Reviewing files that changed from the base of the PR and between 24bd165 and 4b5a0e9.

📒 Files selected for processing (93)
  • eslint.config.js
  • src/lib/components/AudioPlaybackSpeed.svelte
  • src/lib/components/ContentCarousel.svelte
  • src/lib/components/ContentGrid.svelte
  • src/lib/components/ContentHeading.svelte
  • src/lib/components/ContentSingle.svelte
  • src/lib/components/FontList.svelte
  • src/lib/components/FontSelector.svelte
  • src/lib/components/HistoryCard.svelte
  • src/lib/components/HtmlBookView.svelte
  • src/lib/components/IconCard.svelte
  • src/lib/components/PlayButton.svelte
  • src/lib/components/ScrolledContent.svelte
  • src/lib/components/Sidebar.svelte
  • src/lib/components/Slider.svelte
  • src/lib/components/StackView.svelte
  • src/lib/components/TextAppearanceSelector.svelte
  • src/lib/data/plansData.ts
  • src/lib/icons/AboutIcon.svelte
  • src/lib/icons/AccountIcon.svelte
  • src/lib/icons/ArrowBackIcon.svelte
  • src/lib/icons/ArrowForwardIcon.svelte
  • src/lib/icons/BibleIcon.svelte
  • src/lib/icons/BookmarkIcon.svelte
  • src/lib/icons/BookmarkOutlineIcon.svelte
  • src/lib/icons/CalendarMonthIcon.svelte
  • src/lib/icons/CheckIcon.svelte
  • src/lib/icons/CheckboxIcon.svelte
  • src/lib/icons/CheckboxOutlineIcon.svelte
  • src/lib/icons/ChevronIcon.svelte
  • src/lib/icons/CopyContentIcon.svelte
  • src/lib/icons/DeleteIcon.svelte
  • src/lib/icons/DeleteSweepIcon.svelte
  • src/lib/icons/DropdownIcon.svelte
  • src/lib/icons/EditIcon.svelte
  • src/lib/icons/HamburgerIcon.svelte
  • src/lib/icons/HighlightIcon.svelte
  • src/lib/icons/HistoryIcon.svelte
  • src/lib/icons/HomeIcon.svelte
  • src/lib/icons/InfoIcon.svelte
  • src/lib/icons/LaunchIcon.svelte
  • src/lib/icons/LineSpacingIcon.svelte
  • src/lib/icons/MoreVertIcon.svelte
  • src/lib/icons/NoteIcon.svelte
  • src/lib/icons/SearchIcon.svelte
  • src/lib/icons/SettingsIcon.svelte
  • src/lib/icons/ShareIcon.svelte
  • src/lib/icons/SideBySideIcon.svelte
  • src/lib/icons/SinglePaneIcon.svelte
  • src/lib/icons/SortIcon.svelte
  • src/lib/icons/TextAppearanceIcon.svelte
  • src/lib/icons/TriangleLeftIcon.svelte
  • src/lib/icons/TriangleRightIcon.svelte
  • src/lib/icons/VerseByVerseIcon.svelte
  • src/lib/icons/audio/PauseIcon.svelte
  • src/lib/icons/audio/PauseOutlineCircleIcon.svelte
  • src/lib/icons/audio/PlayFillCircleIcon.svelte
  • src/lib/icons/audio/PlayIcon.svelte
  • src/lib/icons/audio/PlayOutlineCircleIcon.svelte
  • src/lib/icons/audio/PlayRepeatIcon.svelte
  • src/lib/icons/audio/RepeatIcon.svelte
  • src/lib/icons/image/BlurIcon.svelte
  • src/lib/icons/image/BrightnessIcon.svelte
  • src/lib/icons/image/ContrastIcon.svelte
  • src/lib/icons/image/FontChoiceIcon.svelte
  • src/lib/icons/image/FormatAlignCenterIcon.svelte
  • src/lib/icons/image/FormatAlignLeftIcon.svelte
  • src/lib/icons/image/FormatAlignRightIcon.svelte
  • src/lib/icons/image/FormatBoldIcon.svelte
  • src/lib/icons/image/FormatColorFillIcon.svelte
  • src/lib/icons/image/FormatItalicIcon.svelte
  • src/lib/icons/image/FormatLineSpacingIcon.svelte
  • src/lib/icons/image/ImageSingleIcon.svelte
  • src/lib/icons/image/ImagesIcon.svelte
  • src/lib/icons/image/LetterSpacingIcon.svelte
  • src/lib/icons/image/OpacityIcon.svelte
  • src/lib/icons/image/ReferenceIcon.svelte
  • src/lib/icons/image/ResizeArrowsIcon.svelte
  • src/lib/icons/image/SaturationIcon.svelte
  • src/lib/icons/image/TextGlowIcon.svelte
  • src/lib/icons/image/TextShadowIcon.svelte
  • src/lib/icons/image/TextShadowNoneIcon.svelte
  • src/lib/icons/image/TextWidthIcon.svelte
  • src/lib/navigate/index.ts
  • src/lib/video/index.ts
  • src/routes/+page.svelte
  • src/routes/bookmarks/+page.svelte
  • src/routes/contents/[id]/+page.svelte
  • src/routes/dev/icons/+page.svelte
  • src/routes/lexicon/+page.svelte
  • src/routes/notes/+page.svelte
  • src/routes/plans/[id]/settings/+page.svelte
  • src/routes/text/+page.svelte
💤 Files with no reviewable changes (3)
  • src/lib/data/plansData.ts
  • src/lib/components/ScrolledContent.svelte
  • src/routes/lexicon/+page.svelte

Comment thread src/lib/components/FontSelector.svelte
Comment thread src/lib/components/HistoryCard.svelte Outdated
Comment thread src/lib/components/StackView.svelte
Comment thread src/routes/plans/[id]/settings/+page.svelte

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (2)
src/lib/components/HistoryCard.svelte (1)

55-55: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use a style declaration (or real CSS class), not a CSS rule string in class.

Line 55 uses class="text-decoration:none;", which won’t apply the intended styling.

Suggested fix
-    <div class="text-decoration:none;" onclick={onHistoryClick}>
+    <div style="text-decoration:none;" onclick={onHistoryClick}>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/components/HistoryCard.svelte` at line 55, The element uses
class="text-decoration:none;" which is incorrect; replace that with a proper
style or CSS class: either change the attribute to style="text-decoration:
none;" on the div that uses onclick={onHistoryClick}, or create a CSS class
(e.g. .no-underline) in HistoryCard.svelte's <style> block and set
class="no-underline" on the div so the decoration is applied correctly.
src/routes/plans/[id]/settings/+page.svelte (1)

22-25: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard planConfig?.id before navigation and start action.

Line 24 can route to /plans/undefined when data.planConfig?.id is missing, and Line 54 can throw due to data.planConfig!.id. Reuse one guarded planId and early-return/fallback.

Proposed fix
 let { data }: Props = $props();
+const planId = $derived(data.planConfig?.id);

 async function startPlan(id: string) {
     await addPlanState({
         id: id,
         state: 'started'
     });
     goto(resolve(`/plans/${id}`));
 }
 function backNavigation() {
-    const id = data.planConfig?.id;
-    goto(resolve(`/plans/${id}`));
+    if (!planId) {
+        goto(resolve('/plans'));
+        return;
+    }
+    goto(resolve(`/plans/${planId}`));
 }
@@
             <div
                 class="plan-button"
                 id="plan-continue"
                 onclick={async function () {
-                    await startPlan(data.planConfig!.id);
+                    if (!planId) return;
+                    await startPlan(planId);
                 }}
             >

Also applies to: 53-55

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/routes/plans/`[id]/settings/+page.svelte around lines 22 - 25, Compute
and reuse a guarded planId once (e.g., const planId = data.planConfig?.id) and
early-return or show a fallback when it's undefined before performing navigation
or actions; update backNavigation() to use planId and avoid calling
goto(`/plans/${id}`) when planId is falsy, and replace all occurrences of
data.planConfig!.id (e.g., the start action at the other site) with the guarded
planId so no code attempts to navigate or start with an undefined id.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@src/lib/components/HistoryCard.svelte`:
- Line 55: The element uses class="text-decoration:none;" which is incorrect;
replace that with a proper style or CSS class: either change the attribute to
style="text-decoration: none;" on the div that uses onclick={onHistoryClick}, or
create a CSS class (e.g. .no-underline) in HistoryCard.svelte's <style> block
and set class="no-underline" on the div so the decoration is applied correctly.

In `@src/routes/plans/`[id]/settings/+page.svelte:
- Around line 22-25: Compute and reuse a guarded planId once (e.g., const planId
= data.planConfig?.id) and early-return or show a fallback when it's undefined
before performing navigation or actions; update backNavigation() to use planId
and avoid calling goto(`/plans/${id}`) when planId is falsy, and replace all
occurrences of data.planConfig!.id (e.g., the start action at the other site)
with the guarded planId so no code attempts to navigate or start with an
undefined id.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 32912d66-6913-4f41-a3bf-b67ce26065a6

📥 Commits

Reviewing files that changed from the base of the PR and between 4b5a0e9 and 867f5a2.

📒 Files selected for processing (24)
  • src/lib/components/BookSelector.svelte
  • src/lib/components/BottomNavigationBar.svelte
  • src/lib/components/ChapterSelector.svelte
  • src/lib/components/FontSelector.svelte
  • src/lib/components/HistoryCard.svelte
  • src/lib/components/Navbar.svelte
  • src/lib/components/NoteDialog.svelte
  • src/lib/components/PlanStopDialog.svelte
  • src/lib/components/ScriptureViewSofria.svelte
  • src/lib/components/Sidebar.svelte
  • src/lib/components/TextSelectionToolbar.svelte
  • src/lib/navigate/index.ts
  • src/routes/+page.svelte
  • src/routes/bookmarks/+page.svelte
  • src/routes/contents/[id]/+page.svelte
  • src/routes/highlights/+page.svelte
  • src/routes/lexicon/+layout.svelte
  • src/routes/lexicon/+page.svelte
  • src/routes/notes/+page.svelte
  • src/routes/plans/+page.svelte
  • src/routes/plans/[id]/+page.svelte
  • src/routes/plans/[id]/settings/+page.svelte
  • src/routes/search/[collection]/[[savedResults]]/+page.svelte
  • src/routes/text/+page.svelte

@FyreByrd FyreByrd requested a review from eomerdws May 26, 2026 15:20

@eomerdws eomerdws left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome job.. It honestly took me a bit to realize that both goto and resolve where a svelte way of doing code. I don't think my questions are show stoppers so if you don't mind answering them for history sake otherwise I think this is an easy approve.

Comment thread src/lib/components/HistoryCard.svelte
Comment thread src/lib/components/ScrolledContent.svelte
@FyreByrd FyreByrd merged commit 3793743 into main May 26, 2026
4 checks passed
@FyreByrd FyreByrd deleted the upgrade/svelte-5 branch May 26, 2026 18:51
@FyreByrd FyreByrd mentioned this pull request May 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Svelte 5 Migration

2 participants