From 8bfdfae22444225591b0fa31a188dc6c7b4b2e93 Mon Sep 17 00:00:00 2001 From: Christopher Serr Date: Fri, 31 May 2024 21:19:13 +0200 Subject: [PATCH] Add a changelog and improve contributors section This improves the contributors section in the About page. It now uses flexbox to dynamically place the contributors. Additionally their avatar is now being shown. Also the ten most recent changes are now being shown in the About page. The information is extracted from the git history. The idea is to mark commit messages with a special changelog section at the end that's specifically meant to be shown as a user facing change. It can be arbitrary markdown and looks like this (which is also the first one): Changelog: The About page now shows the most recent changes. The contributors section has also been improved. It now shows the avatar of each contributor. --- src/css/About.scss | 49 ++++++++++++++++------- src/type-definitions/webpack-globals.d.ts | 14 ++++++- src/ui/About.tsx | 45 +++++++++++++++++---- src/util/Markdown.tsx | 9 +++-- webpack.config.js | 37 ++++++++++++++++- 5 files changed, 126 insertions(+), 28 deletions(-) diff --git a/src/css/About.scss b/src/css/About.scss index 16e90d9c5..368c14c20 100644 --- a/src/css/About.scss +++ b/src/css/About.scss @@ -1,7 +1,6 @@ @import 'mobile'; @import 'variables'; -$text-width: 400px; $icon-size: 40px; $title-font-size: 40px; $build-version-font-size: 12px; @@ -37,28 +36,42 @@ $link-color: #56b0ff; font-size: $build-version-font-size; } - .contributors-header { - margin-bottom: 0; + h2 { + margin-bottom: $ui-large-margin; } - .contributor { - margin-block-start: 0.5em; - margin-block-end: 0.5em; + a { + color: $link-color; + } + + .changelog { + margin-left: $ui-large-margin; - &:last-child { - margin-block-end: 0; + >div { + margin: $ui-large-margin 0 $ui-large-margin $ui-large-margin; } } - a { - color: $link-color; - } + .contributors { + margin: 0 auto; + display: flex; + flex-wrap: wrap; + gap: 14px; + justify-content: space-evenly; + align-items: end; + font-size: 14px; - p { - max-width: $text-width; + a { + display: flex; + align-items: center; + flex-direction: column; + gap: 4px; - @include mobile { - max-width: 100%; + img { + width: 42px; + height: 42px; + border-radius: 50%; + } } } @@ -66,4 +79,10 @@ $link-color: #56b0ff; box-sizing: border-box; } } + + max-width: 700px; + + @include mobile { + max-width: 100%; + } } diff --git a/src/type-definitions/webpack-globals.d.ts b/src/type-definitions/webpack-globals.d.ts index 433aca49d..f49f5d7b4 100644 --- a/src/type-definitions/webpack-globals.d.ts +++ b/src/type-definitions/webpack-globals.d.ts @@ -1,3 +1,15 @@ declare const BUILD_DATE: string; declare const COMMIT_HASH: string; -declare const CONTRIBUTORS_LIST: string[]; +declare const CONTRIBUTORS_LIST: Contributor[]; +declare const CHANGELOG: ChangelogEntry[]; + +declare interface Contributor { + id: string, + name: string, +} + +declare interface ChangelogEntry { + id: string, + message: string, + date: string, +} diff --git a/src/ui/About.tsx b/src/ui/About.tsx index 4df57eb69..f42bfd123 100644 --- a/src/ui/About.tsx +++ b/src/ui/About.tsx @@ -1,6 +1,7 @@ import * as React from "react"; import LiveSplitIcon from "../assets/icon.svg"; +import { renderMarkdown } from "../util/Markdown"; import "../css/About.scss"; @@ -13,6 +14,11 @@ interface Callbacks { openTimerView(): void, } +const changelogRenderSettings = { + softBreak: false, + escapeHtml: false, +}; + export class About extends React.Component { public render() { const renderedView = this.renderView(); @@ -21,6 +27,8 @@ export class About extends React.Component { } private renderView() { + const idealAvatarResolution = Math.round(devicePixelRatio * 42); + return (
@@ -42,14 +50,35 @@ export class About extends React.Component { View Source Code on GitHub

-

Contributors

- { - CONTRIBUTORS_LIST.map((contributor) => ( -

- {contributor} -

- )) - } +

Recent Changes

+
+ { + CHANGELOG.map((change) => ( + <> + + {change.date} + +
+ {renderMarkdown(change.message, changelogRenderSettings)} +
+ + )) + } +
+

Contributors

+
+ { + CONTRIBUTORS_LIST.map((contributor) => ( + + (e.target as any).remove()} + /> + {contributor.name} + + )) + } +
); diff --git a/src/util/Markdown.tsx b/src/util/Markdown.tsx index 51ada0790..be84e0d1c 100644 --- a/src/util/Markdown.tsx +++ b/src/util/Markdown.tsx @@ -22,13 +22,16 @@ export function replaceFlag(countryCode: string): JSX.Element { return {countryCode}; } -export function renderMarkdown(markdown: string): JSX.Element { +export function renderMarkdown(markdown: string, options: { + softBreak?: boolean, + escapeHtml?: boolean, +} = {}): JSX.Element { const markdownWithEmotes = replaceTwitchEmotes(markdown); const parsed = new CommonMarkParser().parse(markdownWithEmotes); const renderedMarkdown = new CommonMarkRenderer({ - escapeHtml: true, + escapeHtml: options.escapeHtml ?? true, linkTarget: "_blank", - softBreak: "br", + softBreak: options.softBreak === false ? undefined : "br", }).render(parsed); return ( diff --git a/webpack.config.js b/webpack.config.js index 2d17fc049..19e922c30 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -13,6 +13,36 @@ import fetch from "node-fetch"; import { fileURLToPath } from 'url'; import * as sass from "sass"; +function parseChangelog() { + return execSync("git log --grep \"^Changelog: \" -10") + .toString() + .split(/^commit /) + .slice(1) + .map((commit) => { + const changelogIndex = commit.indexOf(" Changelog: "); + if (changelogIndex === -1) { + return {}; + } + const dateIndex = commit.indexOf("Date: "); + if (dateIndex === -1) { + return {}; + } + const afterDate = commit.substring(dateIndex + 8); + const date = moment(new Date(afterDate.substring(0, afterDate.indexOf("\n")))).utc().format("YYYY-MM-DD"); + const id = commit.substring(0, commit.indexOf("\n")); + const message = commit + .substring(changelogIndex + 15) + .replaceAll("\n ", "\n") + .trim(); + return { + id, + message, + date, + }; + }) + .filter((changelog) => changelog.message); +} + export default async (env, argv) => { const getContributorsForRepo = async (repoName) => { const contributorsData = await fetch(`https://api.github.com/repos/LiveSplit/${repoName}/contributors`); @@ -40,10 +70,14 @@ export default async (env, argv) => { const contributorsList = Object.values(coreContributorsMap) .sort((user1, user2) => user2.contributions - user1.contributions) - .map((user) => user.login); + .map((user) => { + return { id: user.id, name: user.login }; + }); const commitHash = execSync("git rev-parse --short HEAD").toString(); const date = moment.utc().format("YYYY-MM-DD kk:mm:ss z"); + const changelog = parseChangelog(); + const basePath = path.dirname(fileURLToPath(import.meta.url)); const isProduction = argv.mode === "production"; @@ -97,6 +131,7 @@ export default async (env, argv) => { BUILD_DATE: JSON.stringify(date), COMMIT_HASH: JSON.stringify(commitHash), CONTRIBUTORS_LIST: JSON.stringify(contributorsList), + CHANGELOG: JSON.stringify(changelog), }), ...(isProduction ? [ new HtmlInlineScriptPlugin({