diff --git a/src/pages/changelog/changelog.js b/src/pages/changelog/changelog.js
index fb5a21b85..e016df1bd 100644
--- a/src/pages/changelog/changelog.js
+++ b/src/pages/changelog/changelog.js
@@ -1,36 +1,186 @@
+import fsOperation from "fileSystem";
import "./style.scss";
+import Contextmenu from "components/contextmenu";
import Page from "components/page";
+import Ref from "html-tag-js/ref";
import actionStack from "lib/actionStack";
import markdownIt from "markdown-it";
import markdownItTaskLists from "markdown-it-task-lists";
import helpers from "utils/helpers";
export default async function Changelog() {
- const CHANGELOG_URL =
- "https://raw.githubusercontent.com/deadlyjack/Acode/main/CHANGELOG.md";
- const $page = Page(strings["changelog"]);
- const $content =
;
+ const GITHUB_API_URL =
+ "https://api.github.com/repos/Acode-Foundation/Acode/releases";
+ const CHANGELOG_FILE_URL =
+ "https://raw.githubusercontent.com/Acode-Foundation/Acode/main/CHANGELOG.md";
+ const currentVersion = BuildInfo.version;
- $content.innerHTML = 'Loading changelog...
';
+ let selectedVersion = currentVersion;
+ let selectedStatus = "current";
+ const versionIndicatorRef = new Ref();
+ const versionTextRef = new Ref();
+
+ const versionSelector = (
+
+
+ {selectedVersion}
+
+ );
+ const $page = Page(strings["changelog"], {
+ tail: versionSelector,
+ });
+
+ const versionSelectorMenu = Contextmenu({
+ top: "36px",
+ right: "5px",
+ toggler: versionSelector,
+ transformOrigin: "top right",
+ innerHTML: () => {
+ return `
+
+ Current Version (${currentVersion})
+
+
+ Latest Release
+
+
+ Beta Version
+
+
+ Full Changelog
+
+ `;
+ },
+ });
+
+ const $content = ;
+ $content.innerHTML = 'Loading changelog...
';
$page.content = $content;
app.append($page);
- try {
- const changeLog = await fetch(CHANGELOG_URL);
- const changeLogText = await changeLog.text();
+ async function loadLatestRelease() {
+ try {
+ const releases = await fsOperation(`${GITHUB_API_URL}/latest`).readFile(
+ "json",
+ );
+ selectedVersion = releases.tag_name.replace("v", "");
+ selectedStatus = "latest";
+ updateVersionSelector();
+ return renderChangelog(releases.body);
+ } catch (error) {
+ $content.innerHTML =
+ 'Failed to load latest release notes
';
+ }
+ }
- const cleanedText = changeLogText.replace(/^#\s*Change\s*Log\s*\n*/i, "");
+ async function loadBetaRelease() {
+ try {
+ const releases = await fsOperation(GITHUB_API_URL).readFile("json");
+ const betaRelease = releases.find((r) => r.prerelease);
+ if (!betaRelease) {
+ $content.innerHTML = 'No beta release found
';
+ return;
+ }
+ selectedVersion = betaRelease.tag_name.replace("v", "");
+ selectedStatus = "prerelease";
+ updateVersionSelector();
+ return renderChangelog(betaRelease.body);
+ } catch (error) {
+ $content.innerHTML =
+ 'Failed to load beta release notes
';
+ }
+ }
- const htmlContent = markdownIt({ html: true })
- .use(markdownItTaskLists)
- .render(cleanedText);
+ async function loadFullChangelog() {
+ try {
+ const changeLogText =
+ await fsOperation(CHANGELOG_FILE_URL).readFile("utf8");
+ const cleanedText = changeLogText.replace(/^#\s*Change\s*Log\s*\n*/i, "");
+ selectedVersion = "Changelogs.md";
+ selectedStatus = "current";
+ updateVersionSelector();
+ return renderChangelog(cleanedText);
+ } catch (error) {
+ $content.innerHTML =
+ 'Failed to load full changelog
';
+ }
+ }
+
+ async function loadVersionChangelog() {
+ try {
+ const releases = await fsOperation(GITHUB_API_URL).readFile("json");
+ const currentRelease = releases.find(
+ (r) => r.tag_name.replace("v", "") === currentVersion,
+ );
+ selectedVersion = currentVersion;
+ selectedStatus = "current";
+ updateVersionSelector();
+ if (currentRelease) {
+ return renderChangelog(currentRelease.body);
+ } else {
+ return loadLatestRelease();
+ }
+ } catch (error) {
+ $content.innerHTML =
+ 'Failed to load version changelog
';
+ }
+ }
+ function renderChangelog(text) {
+ const md = markdownIt({ html: true, linkify: true });
+ const REPO_URL = "https://github.com/Acode-Foundation/Acode";
+ let processedText = text
+ // Convert full PR URLs to #number format with links preserved in markdown
+ .replace(
+ /https:\/\/github\.com\/Acode-Foundation\/Acode\/pull\/(\d+)/g,
+ "[#$1](https://github.com/Acode-Foundation/Acode/pull/$1)",
+ )
+ // Convert existing #number references to links if they aren't already
+ .replace(
+ /(?Failed to load changelog';
}
+ function updateVersionSelector() {
+ versionTextRef.textContent = selectedVersion;
+ versionIndicatorRef.className = "status-indicator status-" + selectedStatus;
+ }
+
+ versionSelectorMenu.onclick = async function (e) {
+ const action = e.target.closest("li")?.getAttribute("action");
+ if (!action) return;
+ versionSelectorMenu.hide();
+
+ switch (action) {
+ case "current":
+ await loadVersionChangelog();
+ break;
+ case "latest":
+ await loadLatestRelease();
+ break;
+ case "beta":
+ await loadBetaRelease();
+ break;
+ case "full":
+ await loadFullChangelog();
+ break;
+ }
+ };
+
+ // Load current version changelog by default
+ loadVersionChangelog();
+
$page.onhide = function () {
actionStack.remove("changelog");
};
diff --git a/src/pages/changelog/style.scss b/src/pages/changelog/style.scss
index ed74854b6..e5bc0ddf8 100644
--- a/src/pages/changelog/style.scss
+++ b/src/pages/changelog/style.scss
@@ -5,6 +5,40 @@
padding: 0 1rem;
}
+.changelog-version-selector {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ background-color: var(--popup-background-color);
+ border: none;
+ border-radius: 8px;
+ padding: 8px 16px;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ margin-right: 6px;
+
+ &:hover {
+ background-color: var(--secondary-color);
+ }
+}
+
+.status-indicator {
+ display: inline-block;
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+}
+.status-latest {
+ background-color: #10b981;
+}
+.status-prerelease {
+ background-color: var(--danger-color);
+}
+.status-current {
+ background-color: var(--active-icon-color);
+}
+
.loading {
display: flex;
justify-content: center;