+
+
}
+ title={t("settings.about.changelog")}
+ sub={t("settings.about.changelogSub")}
+ onClick={() => void openUrl(CHANGELOG_URL)}
+ />
}
title={t("settings.about.sourceCode")}
diff --git a/src/components/settings/ReleaseNotes.tsx b/src/components/settings/ReleaseNotes.tsx
new file mode 100644
index 00000000..dd33743e
--- /dev/null
+++ b/src/components/settings/ReleaseNotes.tsx
@@ -0,0 +1,73 @@
+// Responsibility: renders the parsed release notes as elements — headings, lists, paragraphs and
+// inline code — with no HTML sink anywhere.
+import { For, Match, Switch, type JSX } from "solid-js";
+import {
+ parseReleaseNoteSpans,
+ parseReleaseNotes,
+ type ReleaseNoteBlock,
+} from "@/lib/release-notes";
+
+const asHeading = (block: ReleaseNoteBlock) =>
+ block.kind === "heading" ? block : undefined;
+
+const asList = (block: ReleaseNoteBlock) =>
+ block.kind === "list" ? block : undefined;
+
+const asParagraph = (block: ReleaseNoteBlock) =>
+ block.kind === "paragraph" ? block : undefined;
+
+function Spans(props: { text: string }): JSX.Element {
+ return (
+
+ {(span) =>
+ span.code ? (
+
+ {span.text}
+
+ ) : (
+ span.text
+ )
+ }
+
+ );
+}
+
+export function ReleaseNotes(props: { markdown: string }) {
+ return (
+
+
+ {(block) => (
+
+
+ {(heading) => (
+
+ {heading().text}
+
+ )}
+
+
+ {(list) => (
+
+
+ {(item) => (
+ -
+
+
+ )}
+
+
+ )}
+
+
+ {(paragraph) => (
+
+
+
+ )}
+
+
+ )}
+
+
+ );
+}
diff --git a/src/components/settings/UpdateCheck.tsx b/src/components/settings/UpdateCheck.tsx
index f299f442..80408667 100644
--- a/src/components/settings/UpdateCheck.tsx
+++ b/src/components/settings/UpdateCheck.tsx
@@ -1,8 +1,15 @@
-// Responsibility: Update check widget — idle / checking / up to date / update available / downloading / awaiting restart / failed.
-import { Match, Switch } from "solid-js";
+// Responsibility: Update check widget — idle / checking / up to date / update available (with its notes in a dialog) / downloading / awaiting restart / failed.
+import { Match, Show, Switch } from "solid-js";
import { t } from "@/i18n";
import { check, install, restart, updateStore } from "@/store/update.store";
import { Button } from "@/components/ui/button";
+import {
+ Dialog,
+ DialogContent,
+ DialogHeader,
+ DialogTitle,
+ DialogTrigger,
+} from "@/components/ui/dialog";
import {
Check,
Download,
@@ -10,6 +17,7 @@ import {
RefreshCw,
TriangleAlert,
} from "lucide-solid";
+import { ReleaseNotes } from "./ReleaseNotes";
export function UpdateCheck() {
const percent = () =>
@@ -29,6 +37,32 @@ export function UpdateCheck() {
version: updateStore.version ?? "",
})}
+ {/* The notes are the release body the updater already fetched. They open in a
+ dialog rather than inside this card: a changelog is longer than the card and
+ would push the install button off the screen. */}
+
+
+