diff --git a/src/components/settings/AboutSection.tsx b/src/components/settings/AboutSection.tsx index 3bf499d9..ca06d3c9 100644 --- a/src/components/settings/AboutSection.tsx +++ b/src/components/settings/AboutSection.tsx @@ -1,5 +1,5 @@ // Responsibility: About group — asymmetric layout (one large version block + a column of narrow link rows), breaking the default three-equal-card look. -import { ChevronRight, Code, FileText } from "lucide-solid"; +import { ChevronRight, Code, FileText, ScrollText } from "lucide-solid"; import { createResource, type JSXElement } from "solid-js"; import { Item, @@ -16,6 +16,8 @@ import { SettingsGroup } from "./SettingsGroup"; import { UpdateCheck } from "./UpdateCheck"; const SOURCE_URL = "https://github.com/dwall-rs/dwall"; +/** The release list, not one tag: nightly builds are published under their own release. */ +const CHANGELOG_URL = `${SOURCE_URL}/releases`; export function AboutSection() { const [info] = createResource(getAppInfo); @@ -29,7 +31,7 @@ export function AboutSection() { delay={200} >
-
+
{t("settings.about.logoAlt")}
+ } + 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. */} + + + + {t("settings.about.whatsNew")} + + + + + {t("settings.about.whatsNewFor", { + version: updateStore.version ?? "", + })} + + +
+ +
+
+
+