From 395b27507dfdcf9379594b47fb0c1610d0d37e7d Mon Sep 17 00:00:00 2001
From: Ying Zhong <0x00eeee@gmail.com>
Date: Wed, 12 Aug 2026 16:41:33 +0800
Subject: [PATCH] Add support for release date
---
.github/workflows/publish.yml | 5 +-
README.md | 11 ++-
extensions/markedit-ai-writer.json | 1 +
extensions/markedit-authorship.json | 4 +-
.../markedit-bidirectional-preview-sync.json | 1 +
extensions/markedit-devtools.json | 4 +-
extensions/markedit-direct-preview.json | 4 +-
extensions/markedit-enhanced-paste.json | 6 +-
extensions/markedit-highlight.json | 4 +-
extensions/markedit-hitl-review.json | 4 +-
extensions/markedit-language-data.json | 5 +-
extensions/markedit-mindmap.json | 4 +-
extensions/markedit-mte.json | 4 +-
.../markedit-native-text-shortcuts.json | 1 +
extensions/markedit-outline-sidebar.json | 1 +
extensions/markedit-prettier.json | 5 +-
extensions/markedit-preview.json | 5 +-
extensions/markedit-proofreading.json | 4 +-
extensions/markedit-quick-emoji.json | 4 +-
.../markedit-reference-style-links.json | 4 +-
extensions/markedit-rendered-math.json | 4 +-
extensions/markedit-theme-zero.json | 5 +-
extensions/markedit-vim.json | 4 +-
extensions/markedit-wikilinks.json | 4 +-
index.json | 71 +++++++++++++++----
schemas/extension.schema.json | 6 ++
schemas/index.schema.json | 6 ++
schemas/theme.schema.json | 6 ++
scripts/assets/index.css | 5 ++
scripts/assets/index.js | 24 +++++--
scripts/build.mjs | 27 +++++--
scripts/lib/gallery.mjs | 22 +++++-
scripts/registry-date.mjs | 47 ++++++++++++
scripts/templates/card.html | 2 +-
test/gallery.test.mjs | 24 +++++++
test/registry-date.test.mjs | 56 +++++++++++++++
themes/markedit-theme-basic.json | 5 +-
themes/markedit-theme-catppuccin.json | 5 +-
themes/markedit-theme-duotone.json | 5 +-
themes/markedit-theme-gruvbox.json | 5 +-
themes/markedit-theme-noctis-lilac.json | 5 +-
themes/markedit-theme-nord.json | 5 +-
themes/markedit-theme-one-dark.json | 5 +-
themes/markedit-theme-quietlight.json | 5 +-
themes/markedit-theme-tokyo-night.json | 5 +-
themes/markedit-theme-vscode.json | 6 +-
46 files changed, 384 insertions(+), 61 deletions(-)
create mode 100644 scripts/registry-date.mjs
create mode 100644 test/gallery.test.mjs
create mode 100644 test/registry-date.test.mjs
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 04a8dae..d65e0e9 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -22,14 +22,13 @@ jobs:
timeout-minutes: 20
steps:
- uses: actions/checkout@v5
- with:
- fetch-depth: 0
- uses: actions/setup-node@v5
with:
node-version: 22
cache: yarn
- run: yarn install --frozen-lockfile
- - run: yarn build
+ - name: Build registry
+ run: STAMP_DATES=true yarn build
- name: Commit generated files
run: |
git config user.name "github-actions[bot]"
diff --git a/README.md b/README.md
index 7df7bf5..11e72bf 100644
--- a/README.md
+++ b/README.md
@@ -25,8 +25,10 @@ The folder an entry lives in determines its kind, so an entry's `category` (`ext
"versions": [
{
"version": "1.8.1",
+ "date": "2026-07-09T11:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-preview/v1.8.1/dist/markedit-preview.js",
- "sha256": "1532295f78826ed78e161ffdc0c7fdcf307bf0ac4664fbf7eb50dc4c741be0c8"
+ "sha256": "1532295f78826ed78e161ffdc0c7fdcf307bf0ac4664fbf7eb50dc4c741be0c8",
+ "notes": "Initial release."
}
]
}
@@ -34,10 +36,11 @@ The folder an entry lives in determines its kind, so an entry's `category` (`ext
- `id` is kebab-case and must equal the filename.
- `versions` lists builds newest-first; the newest becomes `latest` in `index.json`. Only the newest 5 are kept, every listed build is hash-checked.
+- `date` is the UTC hour when the version was checked into the registry, carried into `latest`. The publish workflow adds it after merge.
- `url` points at the `.js` file committed at a release tag (an immutable ref, served raw from GitHub).
- `sha256` pins the exact bytes at `url`.
- `minAppVersion` (optional) is the lowest MarkEdit version a build supports; it defaults to `1.0.0` and is carried into `latest`.
-- `notes` (optional) is a short release note for the build, carried into `latest`.
+- `notes` (optional) is a short release note carried into `latest`; it defaults to `Initial release.` for a first submission.
### Themes
@@ -62,8 +65,10 @@ A theme is an extension that only restyles the editor, via the [MarkEdit-theming
"versions": [
{
"version": "1.0.0",
+ "date": "2026-07-09T14:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-catppuccin/v1.0.0/dist/markedit-theme-catppuccin.js",
- "sha256": "ae27ae2f81e5865028e8c1d7d1a87254a18097e78e9dfcda113ed6f7882614d6"
+ "sha256": "ae27ae2f81e5865028e8c1d7d1a87254a18097e78e9dfcda113ed6f7882614d6",
+ "notes": "Initial release."
}
]
}
diff --git a/extensions/markedit-ai-writer.json b/extensions/markedit-ai-writer.json
index 558f529..df1e1ba 100644
--- a/extensions/markedit-ai-writer.json
+++ b/extensions/markedit-ai-writer.json
@@ -9,6 +9,7 @@
"versions": [
{
"version": "1.1.0",
+ "date": "2026-07-09T11:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-ai-writer/v1.1.0/dist/markedit-ai-writer.js",
"sha256": "94115461fdd053fceffd15033f26490a48ab214546dca43fc389d51367b87ec3",
"notes": "General bug fixes and performance improvements."
diff --git a/extensions/markedit-authorship.json b/extensions/markedit-authorship.json
index 042e710..1266493 100644
--- a/extensions/markedit-authorship.json
+++ b/extensions/markedit-authorship.json
@@ -8,8 +8,10 @@
"versions": [
{
"version": "1.0.0",
+ "date": "2026-07-09T11:00:00Z",
"url": "https://raw.githubusercontent.com/cinkoman/MarkEdit-authorship/v1.0/ai-rainbow.js",
- "sha256": "bb62bf5b8c69a5fbe7fe95d9b6e37d180781642d360821dfb28883a71c696633"
+ "sha256": "bb62bf5b8c69a5fbe7fe95d9b6e37d180781642d360821dfb28883a71c696633",
+ "notes": "Initial release."
}
]
}
diff --git a/extensions/markedit-bidirectional-preview-sync.json b/extensions/markedit-bidirectional-preview-sync.json
index c328a16..027ee53 100644
--- a/extensions/markedit-bidirectional-preview-sync.json
+++ b/extensions/markedit-bidirectional-preview-sync.json
@@ -8,6 +8,7 @@
"versions": [
{
"version": "1.1.3",
+ "date": "2026-08-08T01:00:00Z",
"url": "https://raw.githubusercontent.com/Nigelw/MarkEdit-bidirectional-preview-sync/v1.1.3/dist/markedit-bidirectional-preview-sync.js",
"sha256": "a5d6609af7f6a4f42596ca9849c6689749fe5f74eca57f3509b6d3e41f2984c7",
"notes": "Improved synchronization when an open document is updated externally."
diff --git a/extensions/markedit-devtools.json b/extensions/markedit-devtools.json
index 5aba92c..d0844c7 100644
--- a/extensions/markedit-devtools.json
+++ b/extensions/markedit-devtools.json
@@ -8,8 +8,10 @@
"versions": [
{
"version": "1.0.0",
+ "date": "2026-07-09T11:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-devtools/v1.0.0/dist/markedit-devtools.js",
- "sha256": "424251e05ae17e6fd63096592b38733c0ecb6869af45e14a51e2f07785d0b51c"
+ "sha256": "424251e05ae17e6fd63096592b38733c0ecb6869af45e14a51e2f07785d0b51c",
+ "notes": "Initial release."
}
]
}
diff --git a/extensions/markedit-direct-preview.json b/extensions/markedit-direct-preview.json
index 8d41278..be88f61 100644
--- a/extensions/markedit-direct-preview.json
+++ b/extensions/markedit-direct-preview.json
@@ -8,8 +8,10 @@
"versions": [
{
"version": "0.1.0",
+ "date": "2026-07-09T11:00:00Z",
"url": "https://github.com/Squarelight-ai/markedit-direct-preview/releases/download/v0.1.0/markedit-direct-preview.js",
- "sha256": "b6a3f48cc121232f184e896edeb6aa715d67f64bfbc10d5c9606a65ac5241960"
+ "sha256": "b6a3f48cc121232f184e896edeb6aa715d67f64bfbc10d5c9606a65ac5241960",
+ "notes": "Initial release."
}
]
}
diff --git a/extensions/markedit-enhanced-paste.json b/extensions/markedit-enhanced-paste.json
index efd05ea..c7b9aef 100644
--- a/extensions/markedit-enhanced-paste.json
+++ b/extensions/markedit-enhanced-paste.json
@@ -9,20 +9,24 @@
"versions": [
{
"version": "1.2.0",
+ "date": "2026-08-10T12:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-enhanced-paste/v1.2.0/dist/markedit-enhanced-paste.js",
"sha256": "157a9f149ed023d5be2e729ddb6e482a7e86dae40409ae760ffab264152a9df2",
"notes": "Add automatic link title fetch."
},
{
"version": "1.1.0",
+ "date": "2026-07-22T14:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-enhanced-paste/v1.1.0/dist/markedit-enhanced-paste.js",
"sha256": "495b1a9f6b23fec4e47c08c98079d27e3ed951386a7cc2b3ff9cae08637638a5",
"notes": "Wrap image paths in angle brackets."
},
{
"version": "1.0.0",
+ "date": "2026-07-09T11:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-enhanced-paste/v1.0.0/dist/markedit-enhanced-paste.js",
- "sha256": "ed7a0919815c5434e000b0bcf227aaa4555f9dc59bd5fe07d908e837e3789c19"
+ "sha256": "ed7a0919815c5434e000b0bcf227aaa4555f9dc59bd5fe07d908e837e3789c19",
+ "notes": "Initial release."
}
]
}
diff --git a/extensions/markedit-highlight.json b/extensions/markedit-highlight.json
index 867965e..e6295fb 100644
--- a/extensions/markedit-highlight.json
+++ b/extensions/markedit-highlight.json
@@ -8,8 +8,10 @@
"versions": [
{
"version": "1.0.0",
+ "date": "2026-07-09T11:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-highlight/v1.0.0/dist/markedit-highlight.js",
- "sha256": "3c8d443dda9bc8dffe3ec08e16cebb484d3c5c771274c981b6747fceac950aca"
+ "sha256": "3c8d443dda9bc8dffe3ec08e16cebb484d3c5c771274c981b6747fceac950aca",
+ "notes": "Initial release."
}
]
}
diff --git a/extensions/markedit-hitl-review.json b/extensions/markedit-hitl-review.json
index 8f18d1f..4022388 100644
--- a/extensions/markedit-hitl-review.json
+++ b/extensions/markedit-hitl-review.json
@@ -8,8 +8,10 @@
"versions": [
{
"version": "0.0.0",
+ "date": "2026-07-09T11:00:00Z",
"url": "https://raw.githubusercontent.com/beauzone/MarkEdit-hitl-review/f160e53e96de2ba3461ddebfffd2bf9618003244/hitl-review.js",
- "sha256": "f1b13bc17e8c61b157a3a8436dde6ba019fcd28dddb64c0688e3bdfef2a965c4"
+ "sha256": "f1b13bc17e8c61b157a3a8436dde6ba019fcd28dddb64c0688e3bdfef2a965c4",
+ "notes": "Initial release."
}
]
}
diff --git a/extensions/markedit-language-data.json b/extensions/markedit-language-data.json
index 8d68e5c..eb8c6cf 100644
--- a/extensions/markedit-language-data.json
+++ b/extensions/markedit-language-data.json
@@ -9,14 +9,17 @@
"versions": [
{
"version": "1.1.0",
+ "date": "2026-07-30T15:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-language-data/v1.1.0/dist/markedit-language-data.js",
"sha256": "c3a0448531dc2f039db745e03ec8caecad8d04aed9159222234b75e7f4855f43",
"notes": "Integrate full html language support."
},
{
"version": "1.0.0",
+ "date": "2026-07-27T06:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-language-data/v1.0.0/dist/markedit-language-data.js",
- "sha256": "16459c9c5b940b5f7baf0c61b7d06b9810fff64c2c478452020a668f2bacfe89"
+ "sha256": "16459c9c5b940b5f7baf0c61b7d06b9810fff64c2c478452020a668f2bacfe89",
+ "notes": "Initial release."
}
]
}
diff --git a/extensions/markedit-mindmap.json b/extensions/markedit-mindmap.json
index 5426fce..278c60f 100644
--- a/extensions/markedit-mindmap.json
+++ b/extensions/markedit-mindmap.json
@@ -8,8 +8,10 @@
"versions": [
{
"version": "1.0.0",
+ "date": "2026-08-11T13:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-mindmap/v1.0.0/dist/markedit-mindmap.js",
- "sha256": "48246f5a2e56f582078b02bd3a1a32b3fe6f6349a27b2e6c78d581f37c4e36cb"
+ "sha256": "48246f5a2e56f582078b02bd3a1a32b3fe6f6349a27b2e6c78d581f37c4e36cb",
+ "notes": "Initial release."
}
]
}
diff --git a/extensions/markedit-mte.json b/extensions/markedit-mte.json
index 5074f8c..f3e0bfb 100644
--- a/extensions/markedit-mte.json
+++ b/extensions/markedit-mte.json
@@ -8,8 +8,10 @@
"versions": [
{
"version": "1.0.0",
+ "date": "2026-07-09T11:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-mte/v1.0.0/dist/markedit-mte.js",
- "sha256": "1b08ad0dac94a423915416a57ad45b95bc5f3d70d29b77b00cdb02e34ce01700"
+ "sha256": "1b08ad0dac94a423915416a57ad45b95bc5f3d70d29b77b00cdb02e34ce01700",
+ "notes": "Initial release."
}
]
}
diff --git a/extensions/markedit-native-text-shortcuts.json b/extensions/markedit-native-text-shortcuts.json
index de7d04c..de9e361 100644
--- a/extensions/markedit-native-text-shortcuts.json
+++ b/extensions/markedit-native-text-shortcuts.json
@@ -8,6 +8,7 @@
"versions": [
{
"version": "1.1.2",
+ "date": "2026-08-08T01:00:00Z",
"url": "https://raw.githubusercontent.com/Nigelw/MarkEdit-native-text-shortcuts/v1.1.2/markedit-native-text-shortcuts.js",
"sha256": "835b3bc5a5d2326a24a2686b4026a8169b7694bbd09b1ec82df891edd60bcabd",
"notes": "Updates are managed centrally by MarkEdit's Extension Manager."
diff --git a/extensions/markedit-outline-sidebar.json b/extensions/markedit-outline-sidebar.json
index 590863f..d6e8736 100644
--- a/extensions/markedit-outline-sidebar.json
+++ b/extensions/markedit-outline-sidebar.json
@@ -8,6 +8,7 @@
"versions": [
{
"version": "1.3.2",
+ "date": "2026-08-08T01:00:00Z",
"url": "https://raw.githubusercontent.com/Nigelw/MarkEdit-outline-sidebar/v1.3.2/dist/markedit-outline.js",
"sha256": "87bc28d9b4efdba929235bdb2dd9b6be89a42c4e715b0db9f66bd29f74a8676b",
"notes": "The outline now refreshes when an open document is updated outside MarkEdit."
diff --git a/extensions/markedit-prettier.json b/extensions/markedit-prettier.json
index 02bcf71..2f934f4 100644
--- a/extensions/markedit-prettier.json
+++ b/extensions/markedit-prettier.json
@@ -8,6 +8,7 @@
"versions": [
{
"version": "1.1.0",
+ "date": "2026-08-12T02:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-prettier/v1.1.0/dist/markedit-prettier.js",
"sha256": "43a52c7e12e3dcc4c598a45181b7f6badc676fed6dd506b7513b6f6965655cd4",
"minAppVersion": "1.24.0",
@@ -15,8 +16,10 @@
},
{
"version": "1.0.0",
+ "date": "2026-07-09T11:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-prettier/v1.0.0/dist/markedit-prettier.js",
- "sha256": "cce9cf0b8df017114d942a1baee250c7f2fa5b2cbcdea4238f4f32a2be4a0940"
+ "sha256": "cce9cf0b8df017114d942a1baee250c7f2fa5b2cbcdea4238f4f32a2be4a0940",
+ "notes": "Initial release."
}
]
}
diff --git a/extensions/markedit-preview.json b/extensions/markedit-preview.json
index 2e93aaa..7bcba95 100644
--- a/extensions/markedit-preview.json
+++ b/extensions/markedit-preview.json
@@ -9,14 +9,17 @@
"versions": [
{
"version": "1.9.0",
+ "date": "2026-08-07T01:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-preview/v1.9.0/dist/markedit-preview.js",
"sha256": "2cca98ee432ea0f7f3a33fb65b329ab83d0e7f3e3573d1863bb780167becd530",
"notes": "Bug fixes and get ready for the new MarkEdit release."
},
{
"version": "1.8.1",
+ "date": "2026-07-09T11:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-preview/v1.8.1/dist/markedit-preview.js",
- "sha256": "1532295f78826ed78e161ffdc0c7fdcf307bf0ac4664fbf7eb50dc4c741be0c8"
+ "sha256": "1532295f78826ed78e161ffdc0c7fdcf307bf0ac4664fbf7eb50dc4c741be0c8",
+ "notes": "Initial release."
}
]
}
diff --git a/extensions/markedit-proofreading.json b/extensions/markedit-proofreading.json
index 78aecd2..461b873 100644
--- a/extensions/markedit-proofreading.json
+++ b/extensions/markedit-proofreading.json
@@ -8,8 +8,10 @@
"versions": [
{
"version": "1.0.0",
+ "date": "2026-07-09T11:00:00Z",
"url": "https://github.com/MarkEdit-app/MarkEdit-proofreading/releases/download/v1.0.0/markedit-proofreading.js",
- "sha256": "2a33c4c0be315c519c6c59748240fd17af843d67ebe0800beabedb19c25666f2"
+ "sha256": "2a33c4c0be315c519c6c59748240fd17af843d67ebe0800beabedb19c25666f2",
+ "notes": "Initial release."
}
]
}
diff --git a/extensions/markedit-quick-emoji.json b/extensions/markedit-quick-emoji.json
index 6a8f134..40a8f45 100644
--- a/extensions/markedit-quick-emoji.json
+++ b/extensions/markedit-quick-emoji.json
@@ -8,8 +8,10 @@
"versions": [
{
"version": "1.0.0",
+ "date": "2026-08-10T09:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-quick-emoji/v1.0.0/dist/markedit-quick-emoji.js",
- "sha256": "a7520d347ee8ffc5ced4767402a3d58205b13f06aa3cfd4e0fd2b5707119b146"
+ "sha256": "a7520d347ee8ffc5ced4767402a3d58205b13f06aa3cfd4e0fd2b5707119b146",
+ "notes": "Initial release."
}
]
}
diff --git a/extensions/markedit-reference-style-links.json b/extensions/markedit-reference-style-links.json
index 3ca7937..5e9063e 100644
--- a/extensions/markedit-reference-style-links.json
+++ b/extensions/markedit-reference-style-links.json
@@ -8,8 +8,10 @@
"versions": [
{
"version": "1.0.0",
+ "date": "2026-07-09T11:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-reference-style-links/v1.0.0/dist/markedit-reference-style-links.js",
- "sha256": "9231d97135d9157cbba16e1cd0b17d80a787c7aaf6a1b9e3861eda1baa766707"
+ "sha256": "9231d97135d9157cbba16e1cd0b17d80a787c7aaf6a1b9e3861eda1baa766707",
+ "notes": "Initial release."
}
]
}
diff --git a/extensions/markedit-rendered-math.json b/extensions/markedit-rendered-math.json
index b02103b..dc37ade 100644
--- a/extensions/markedit-rendered-math.json
+++ b/extensions/markedit-rendered-math.json
@@ -8,8 +8,10 @@
"versions": [
{
"version": "1.0.0",
+ "date": "2026-08-08T01:00:00Z",
"url": "https://raw.githubusercontent.com/lewallen/markedit-rendered-math/1.0.0/markedit-rendered-math.js",
- "sha256": "87eb4063a5f2f08b4e073118690199417034d6964b83bcb3dba4e21ce33a8c8a"
+ "sha256": "87eb4063a5f2f08b4e073118690199417034d6964b83bcb3dba4e21ce33a8c8a",
+ "notes": "Initial release."
}
]
}
diff --git a/extensions/markedit-theme-zero.json b/extensions/markedit-theme-zero.json
index f31269e..617acc6 100644
--- a/extensions/markedit-theme-zero.json
+++ b/extensions/markedit-theme-zero.json
@@ -8,14 +8,17 @@
"versions": [
{
"version": "1.1.0",
+ "date": "2026-08-07T11:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-zero/v1.1.0/dist/markedit-theme-zero.js",
"sha256": "70b6d8eda20c3a4bfa7527f8052d7fb3ebcdab8b45261065527861a5efafb4b3",
"notes": "Upgrade markedit-theming to latest."
},
{
"version": "1.0.0",
+ "date": "2026-07-09T14:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-zero/v1.0.0/dist/markedit-theme-zero.js",
- "sha256": "f97a85c385c87ca6d05333df53df80a2761ed44ff8a1848ef7bbe6e5efcec0d7"
+ "sha256": "f97a85c385c87ca6d05333df53df80a2761ed44ff8a1848ef7bbe6e5efcec0d7",
+ "notes": "Initial release."
}
]
}
diff --git a/extensions/markedit-vim.json b/extensions/markedit-vim.json
index 1df3f89..ddaefab 100644
--- a/extensions/markedit-vim.json
+++ b/extensions/markedit-vim.json
@@ -8,8 +8,10 @@
"versions": [
{
"version": "1.0.0",
+ "date": "2026-07-09T11:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-vim/v1.0.0/dist/markedit-vim.js",
- "sha256": "6b2bd014c98d307d502a7a8857514c3f74c2457dde9907ac300d97cae1facdac"
+ "sha256": "6b2bd014c98d307d502a7a8857514c3f74c2457dde9907ac300d97cae1facdac",
+ "notes": "Initial release."
}
]
}
diff --git a/extensions/markedit-wikilinks.json b/extensions/markedit-wikilinks.json
index c8e94bc..10c7fd0 100644
--- a/extensions/markedit-wikilinks.json
+++ b/extensions/markedit-wikilinks.json
@@ -8,8 +8,10 @@
"versions": [
{
"version": "0.1.3",
+ "date": "2026-07-09T11:00:00Z",
"url": "https://raw.githubusercontent.com/nuc/MarkEdit-wikilinks/v0.1.3/dist/markedit-wikilinks.js",
- "sha256": "1d82f4c55406bc8cb811e14dfcdd40db97405df1ef6d6f48458bdbcada64f7a7"
+ "sha256": "1d82f4c55406bc8cb811e14dfcdd40db97405df1ef6d6f48458bdbcada64f7a7",
+ "notes": "Initial release."
}
]
}
diff --git a/index.json b/index.json
index 6f3409c..a1ecd70 100644
--- a/index.json
+++ b/index.json
@@ -11,6 +11,7 @@
"category": "extension",
"latest": {
"version": "1.1.0",
+ "date": "2026-07-09T11:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-ai-writer/v1.1.0/dist/markedit-ai-writer.js",
"sha256": "94115461fdd053fceffd15033f26490a48ab214546dca43fc389d51367b87ec3",
"notes": "General bug fixes and performance improvements."
@@ -25,8 +26,10 @@
"category": "extension",
"latest": {
"version": "1.0.0",
+ "date": "2026-07-09T11:00:00Z",
"url": "https://raw.githubusercontent.com/cinkoman/MarkEdit-authorship/v1.0/ai-rainbow.js",
- "sha256": "bb62bf5b8c69a5fbe7fe95d9b6e37d180781642d360821dfb28883a71c696633"
+ "sha256": "bb62bf5b8c69a5fbe7fe95d9b6e37d180781642d360821dfb28883a71c696633",
+ "notes": "Initial release."
}
},
{
@@ -38,6 +41,7 @@
"category": "extension",
"latest": {
"version": "1.1.3",
+ "date": "2026-08-08T01:00:00Z",
"url": "https://raw.githubusercontent.com/Nigelw/MarkEdit-bidirectional-preview-sync/v1.1.3/dist/markedit-bidirectional-preview-sync.js",
"sha256": "a5d6609af7f6a4f42596ca9849c6689749fe5f74eca57f3509b6d3e41f2984c7",
"notes": "Improved synchronization when an open document is updated externally."
@@ -52,8 +56,10 @@
"category": "extension",
"latest": {
"version": "1.0.0",
+ "date": "2026-07-09T11:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-devtools/v1.0.0/dist/markedit-devtools.js",
- "sha256": "424251e05ae17e6fd63096592b38733c0ecb6869af45e14a51e2f07785d0b51c"
+ "sha256": "424251e05ae17e6fd63096592b38733c0ecb6869af45e14a51e2f07785d0b51c",
+ "notes": "Initial release."
}
},
{
@@ -65,8 +71,10 @@
"category": "extension",
"latest": {
"version": "0.1.0",
+ "date": "2026-07-09T11:00:00Z",
"url": "https://github.com/Squarelight-ai/markedit-direct-preview/releases/download/v0.1.0/markedit-direct-preview.js",
- "sha256": "b6a3f48cc121232f184e896edeb6aa715d67f64bfbc10d5c9606a65ac5241960"
+ "sha256": "b6a3f48cc121232f184e896edeb6aa715d67f64bfbc10d5c9606a65ac5241960",
+ "notes": "Initial release."
}
},
{
@@ -79,6 +87,7 @@
"category": "extension",
"latest": {
"version": "1.2.0",
+ "date": "2026-08-10T12:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-enhanced-paste/v1.2.0/dist/markedit-enhanced-paste.js",
"sha256": "157a9f149ed023d5be2e729ddb6e482a7e86dae40409ae760ffab264152a9df2",
"notes": "Add automatic link title fetch."
@@ -93,8 +102,10 @@
"category": "extension",
"latest": {
"version": "1.0.0",
+ "date": "2026-07-09T11:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-highlight/v1.0.0/dist/markedit-highlight.js",
- "sha256": "3c8d443dda9bc8dffe3ec08e16cebb484d3c5c771274c981b6747fceac950aca"
+ "sha256": "3c8d443dda9bc8dffe3ec08e16cebb484d3c5c771274c981b6747fceac950aca",
+ "notes": "Initial release."
}
},
{
@@ -106,8 +117,10 @@
"category": "extension",
"latest": {
"version": "0.0.0",
+ "date": "2026-07-09T11:00:00Z",
"url": "https://raw.githubusercontent.com/beauzone/MarkEdit-hitl-review/f160e53e96de2ba3461ddebfffd2bf9618003244/hitl-review.js",
- "sha256": "f1b13bc17e8c61b157a3a8436dde6ba019fcd28dddb64c0688e3bdfef2a965c4"
+ "sha256": "f1b13bc17e8c61b157a3a8436dde6ba019fcd28dddb64c0688e3bdfef2a965c4",
+ "notes": "Initial release."
}
},
{
@@ -120,6 +133,7 @@
"category": "extension",
"latest": {
"version": "1.1.0",
+ "date": "2026-07-30T15:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-language-data/v1.1.0/dist/markedit-language-data.js",
"sha256": "c3a0448531dc2f039db745e03ec8caecad8d04aed9159222234b75e7f4855f43",
"notes": "Integrate full html language support."
@@ -134,8 +148,10 @@
"category": "extension",
"latest": {
"version": "1.0.0",
+ "date": "2026-08-11T13:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-mindmap/v1.0.0/dist/markedit-mindmap.js",
- "sha256": "48246f5a2e56f582078b02bd3a1a32b3fe6f6349a27b2e6c78d581f37c4e36cb"
+ "sha256": "48246f5a2e56f582078b02bd3a1a32b3fe6f6349a27b2e6c78d581f37c4e36cb",
+ "notes": "Initial release."
}
},
{
@@ -147,8 +163,10 @@
"category": "extension",
"latest": {
"version": "1.0.0",
+ "date": "2026-07-09T11:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-mte/v1.0.0/dist/markedit-mte.js",
- "sha256": "1b08ad0dac94a423915416a57ad45b95bc5f3d70d29b77b00cdb02e34ce01700"
+ "sha256": "1b08ad0dac94a423915416a57ad45b95bc5f3d70d29b77b00cdb02e34ce01700",
+ "notes": "Initial release."
}
},
{
@@ -160,6 +178,7 @@
"category": "extension",
"latest": {
"version": "1.1.2",
+ "date": "2026-08-08T01:00:00Z",
"url": "https://raw.githubusercontent.com/Nigelw/MarkEdit-native-text-shortcuts/v1.1.2/markedit-native-text-shortcuts.js",
"sha256": "835b3bc5a5d2326a24a2686b4026a8169b7694bbd09b1ec82df891edd60bcabd",
"notes": "Updates are managed centrally by MarkEdit's Extension Manager."
@@ -174,6 +193,7 @@
"category": "extension",
"latest": {
"version": "1.3.2",
+ "date": "2026-08-08T01:00:00Z",
"url": "https://raw.githubusercontent.com/Nigelw/MarkEdit-outline-sidebar/v1.3.2/dist/markedit-outline.js",
"sha256": "87bc28d9b4efdba929235bdb2dd9b6be89a42c4e715b0db9f66bd29f74a8676b",
"notes": "The outline now refreshes when an open document is updated outside MarkEdit."
@@ -188,6 +208,7 @@
"category": "extension",
"latest": {
"version": "1.1.0",
+ "date": "2026-08-12T02:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-prettier/v1.1.0/dist/markedit-prettier.js",
"sha256": "43a52c7e12e3dcc4c598a45181b7f6badc676fed6dd506b7513b6f6965655cd4",
"minAppVersion": "1.24.0",
@@ -204,6 +225,7 @@
"category": "extension",
"latest": {
"version": "1.9.0",
+ "date": "2026-08-07T01:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-preview/v1.9.0/dist/markedit-preview.js",
"sha256": "2cca98ee432ea0f7f3a33fb65b329ab83d0e7f3e3573d1863bb780167becd530",
"notes": "Bug fixes and get ready for the new MarkEdit release."
@@ -218,8 +240,10 @@
"category": "extension",
"latest": {
"version": "1.0.0",
+ "date": "2026-07-09T11:00:00Z",
"url": "https://github.com/MarkEdit-app/MarkEdit-proofreading/releases/download/v1.0.0/markedit-proofreading.js",
- "sha256": "2a33c4c0be315c519c6c59748240fd17af843d67ebe0800beabedb19c25666f2"
+ "sha256": "2a33c4c0be315c519c6c59748240fd17af843d67ebe0800beabedb19c25666f2",
+ "notes": "Initial release."
}
},
{
@@ -231,8 +255,10 @@
"category": "extension",
"latest": {
"version": "1.0.0",
+ "date": "2026-08-10T09:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-quick-emoji/v1.0.0/dist/markedit-quick-emoji.js",
- "sha256": "a7520d347ee8ffc5ced4767402a3d58205b13f06aa3cfd4e0fd2b5707119b146"
+ "sha256": "a7520d347ee8ffc5ced4767402a3d58205b13f06aa3cfd4e0fd2b5707119b146",
+ "notes": "Initial release."
}
},
{
@@ -244,8 +270,10 @@
"category": "extension",
"latest": {
"version": "1.0.0",
+ "date": "2026-07-09T11:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-reference-style-links/v1.0.0/dist/markedit-reference-style-links.js",
- "sha256": "9231d97135d9157cbba16e1cd0b17d80a787c7aaf6a1b9e3861eda1baa766707"
+ "sha256": "9231d97135d9157cbba16e1cd0b17d80a787c7aaf6a1b9e3861eda1baa766707",
+ "notes": "Initial release."
}
},
{
@@ -257,8 +285,10 @@
"category": "extension",
"latest": {
"version": "1.0.0",
+ "date": "2026-08-08T01:00:00Z",
"url": "https://raw.githubusercontent.com/lewallen/markedit-rendered-math/1.0.0/markedit-rendered-math.js",
- "sha256": "87eb4063a5f2f08b4e073118690199417034d6964b83bcb3dba4e21ce33a8c8a"
+ "sha256": "87eb4063a5f2f08b4e073118690199417034d6964b83bcb3dba4e21ce33a8c8a",
+ "notes": "Initial release."
}
},
{
@@ -275,6 +305,7 @@
"category": "theme",
"latest": {
"version": "1.1.0",
+ "date": "2026-07-31T05:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-basic/v1.1.0/dist/markedit-theme-basic.js",
"sha256": "fcc16b6c5aab8cbb82934ea023fa064d409e7950fbd9d24c3086f14d21836c53",
"notes": "Upgrade markedit-theming to latest."
@@ -295,6 +326,7 @@
"category": "theme",
"latest": {
"version": "1.1.0",
+ "date": "2026-07-31T05:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-catppuccin/v1.1.0/dist/markedit-theme-catppuccin.js",
"sha256": "684d828ca10f74a500a1ad1b8b500331ae63d4a0e4a0d4059108bdb2655f5630",
"notes": "Upgrade markedit-theming to latest."
@@ -314,6 +346,7 @@
"category": "theme",
"latest": {
"version": "1.1.0",
+ "date": "2026-07-31T05:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-duotone/v1.1.0/dist/markedit-theme-duotone.js",
"sha256": "74c777e5873edfee6d2e526289d1ce0876078d8fb943e8420fc43357f134d9e3",
"notes": "Upgrade markedit-theming to latest."
@@ -334,6 +367,7 @@
"category": "theme",
"latest": {
"version": "1.1.0",
+ "date": "2026-07-31T05:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-gruvbox/v1.1.0/dist/markedit-theme-gruvbox.js",
"sha256": "a4ec67d8828caa049b9a9ea6016d8307a1c81ade0ad82eb3dbb16ccb15e2769a",
"notes": "Upgrade markedit-theming to latest."
@@ -352,6 +386,7 @@
"category": "theme",
"latest": {
"version": "1.1.0",
+ "date": "2026-07-31T05:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-noctis-lilac/v1.1.0/dist/markedit-theme-noctis-lilac.js",
"sha256": "684fe5830f715820f125dc06f851cde2ef7eacb58c1de3cd5e0bd5030a9d576f",
"notes": "Upgrade markedit-theming to latest."
@@ -370,6 +405,7 @@
"category": "theme",
"latest": {
"version": "1.1.0",
+ "date": "2026-07-31T05:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-nord/v1.1.0/dist/markedit-theme-nord.js",
"sha256": "6030e533a0bcce69b49c4862d38dfc93e3e58d5f10c52ebb92f0916997543f52",
"notes": "Upgrade markedit-theming to latest."
@@ -388,6 +424,7 @@
"category": "theme",
"latest": {
"version": "1.1.0",
+ "date": "2026-07-31T05:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-one-dark/v1.1.0/dist/markedit-theme-one-dark.js",
"sha256": "54dcad1c6a1594592efeaeb6c2a0e95eaf09a3333238de911a88972e0279e6bf",
"notes": "Upgrade markedit-theming to latest."
@@ -406,6 +443,7 @@
"category": "theme",
"latest": {
"version": "1.1.0",
+ "date": "2026-07-31T05:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-quietlight/v1.1.0/dist/markedit-theme-quietlight.js",
"sha256": "2ce3a603f31f268945e71493bbb1a65abe7783d59c3a0a3d994a538919b0633e",
"notes": "Upgrade markedit-theming to latest."
@@ -425,6 +463,7 @@
"category": "theme",
"latest": {
"version": "1.1.0",
+ "date": "2026-07-31T05:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-tokyo-night/v1.1.0/dist/markedit-theme-tokyo-night.js",
"sha256": "329ca79666cc6dddf5ef7c9def49919758d4f280c6bb968033dd105c3a5220bc",
"notes": "Upgrade markedit-theming to latest."
@@ -444,6 +483,7 @@
"category": "theme",
"latest": {
"version": "1.2.0",
+ "date": "2026-07-29T12:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-vscode/v1.2.0/dist/markedit-theme-vscode.js",
"sha256": "f563fa0dfcf010bc90253271fda5bf3040ccf28063ebe53d34d341a51ce78c69",
"notes": "Upgrade dependency and fix selection color."
@@ -458,6 +498,7 @@
"category": "extension",
"latest": {
"version": "1.1.0",
+ "date": "2026-08-07T11:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-zero/v1.1.0/dist/markedit-theme-zero.js",
"sha256": "70b6d8eda20c3a4bfa7527f8052d7fb3ebcdab8b45261065527861a5efafb4b3",
"notes": "Upgrade markedit-theming to latest."
@@ -472,8 +513,10 @@
"category": "extension",
"latest": {
"version": "1.0.0",
+ "date": "2026-07-09T11:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-vim/v1.0.0/dist/markedit-vim.js",
- "sha256": "6b2bd014c98d307d502a7a8857514c3f74c2457dde9907ac300d97cae1facdac"
+ "sha256": "6b2bd014c98d307d502a7a8857514c3f74c2457dde9907ac300d97cae1facdac",
+ "notes": "Initial release."
}
},
{
@@ -485,8 +528,10 @@
"category": "extension",
"latest": {
"version": "0.1.3",
+ "date": "2026-07-09T11:00:00Z",
"url": "https://raw.githubusercontent.com/nuc/MarkEdit-wikilinks/v0.1.3/dist/markedit-wikilinks.js",
- "sha256": "1d82f4c55406bc8cb811e14dfcdd40db97405df1ef6d6f48458bdbcada64f7a7"
+ "sha256": "1d82f4c55406bc8cb811e14dfcdd40db97405df1ef6d6f48458bdbcada64f7a7",
+ "notes": "Initial release."
}
}
]
diff --git a/schemas/extension.schema.json b/schemas/extension.schema.json
index 13dcc62..8863fb8 100644
--- a/schemas/extension.schema.json
+++ b/schemas/extension.schema.json
@@ -28,6 +28,12 @@
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+(?:-[0-9A-Za-z-.]+)?(?:\\+[0-9A-Za-z-.]+)?$",
"description": "Semantic version, e.g. \"1.2.0\"."
},
+ "date": {
+ "type": "string",
+ "format": "date-time",
+ "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:00:00Z$",
+ "description": "UTC hour when this version was checked into the registry."
+ },
"url": {
"type": "string",
"format": "uri",
diff --git a/schemas/index.schema.json b/schemas/index.schema.json
index 3f257db..a2e037d 100644
--- a/schemas/index.schema.json
+++ b/schemas/index.schema.json
@@ -93,6 +93,12 @@
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+(?:-[0-9A-Za-z-.]+)?(?:\\+[0-9A-Za-z-.]+)?$",
"description": "Resolved newest version, e.g. \"1.2.0\"."
},
+ "date": {
+ "type": "string",
+ "format": "date-time",
+ "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:00:00Z$",
+ "description": "UTC hour when this version was checked into the registry."
+ },
"url": {
"type": "string",
"format": "uri",
diff --git a/schemas/theme.schema.json b/schemas/theme.schema.json
index ab65a1f..6963ccc 100644
--- a/schemas/theme.schema.json
+++ b/schemas/theme.schema.json
@@ -30,6 +30,12 @@
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+(?:-[0-9A-Za-z-.]+)?(?:\\+[0-9A-Za-z-.]+)?$",
"description": "Semantic version, e.g. \"1.2.0\"."
},
+ "date": {
+ "type": "string",
+ "format": "date-time",
+ "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:00:00Z$",
+ "description": "UTC hour when this version was checked into the registry."
+ },
"url": {
"type": "string",
"format": "uri",
diff --git a/scripts/assets/index.css b/scripts/assets/index.css
index b2365ee..8412d0f 100644
--- a/scripts/assets/index.css
+++ b/scripts/assets/index.css
@@ -282,6 +282,11 @@ main {
font-size: 12px;
font-weight: 500;
color: var(--muted);
+ cursor: default;
+}
+
+.ver:hover {
+ color: var(--fg);
}
.featured {
diff --git a/scripts/assets/index.js b/scripts/assets/index.js
index f822873..364aea5 100644
--- a/scripts/assets/index.js
+++ b/scripts/assets/index.js
@@ -1,10 +1,26 @@
-// Re-render the timestamp in the viewer's own locale and timezone
+const formatLocalDate = (isoString, options) => {
+ const date = new Date(isoString);
+ return Number.isNaN(date.getTime())
+ ? undefined
+ : date.toLocaleString(undefined, options);
+};
+
+// Re-render timestamps in the viewer's own locale and timezone
(() => {
const element = document.getElementById('genDate');
- const date = element && new Date(element.dateTime);
- if (date && !Number.isNaN(date.getTime())) {
- element.textContent = date.toLocaleString(undefined, { dateStyle: 'long', timeStyle: 'short' });
+ const formattedDate = element && formatLocalDate(element.dateTime, { dateStyle: 'long', timeStyle: 'short' });
+ if (formattedDate) {
+ element.textContent = formattedDate;
}
+
+ document.querySelectorAll('.ver[data-date]').forEach((version) => {
+ const formattedVersionDate = formatLocalDate(version.dataset.date, { dateStyle: 'medium' });
+ if (formattedVersionDate) {
+ version.title = version.dataset.notes
+ ? `${formattedVersionDate}: ${version.dataset.notes}`
+ : formattedVersionDate;
+ }
+ });
})();
// Fast, smooth in-page navigation
diff --git a/scripts/build.mjs b/scripts/build.mjs
index f2f17a6..2d188d3 100644
--- a/scripts/build.mjs
+++ b/scripts/build.mjs
@@ -9,6 +9,7 @@ import { createHash } from 'node:crypto';
import { fileURLToPath } from 'node:url';
import { dirname, join, basename } from 'node:path';
import { renderGallery } from './lib/gallery.mjs';
+import { normalizeRegistryVersion, registryDate, stampRegistryMetadata } from './registry-date.mjs';
import { compare as compareSemver, valid as validSemver } from 'semver';
import Ajv from 'ajv';
@@ -18,6 +19,7 @@ const root = join(dirname(fileURLToPath(import.meta.url)), '..');
const schemasDir = join(root, 'schemas');
const assetsDir = join(root, 'scripts', 'assets');
const checkIntegrity = process.env.CHECK_INTEGRITY !== 'false';
+const checkInDate = process.env.STAMP_DATES === 'true' ? registryDate() : undefined;
const maxVersions = 5;
const requestTimeout = 30_000;
@@ -91,10 +93,20 @@ for (const { category, dir, validate } of sources) {
seenIds.add(data.id);
// Keep the history short, releases older than the newest few are dropped from the source file.
- const versions = [...data.versions].sort((a, b) => compareSemver(b.version, a.version));
+ let versions = [...data.versions].sort((a, b) => compareSemver(b.version, a.version));
+ let sourceChanged = checkInDate !== undefined && stampRegistryMetadata(versions, checkInDate);
if (versions.length > maxVersions) {
versions.length = maxVersions;
+ sourceChanged = true;
+ }
+
+ versions = versions.map(normalizeRegistryVersion);
+ if (JSON.stringify(data.versions) !== JSON.stringify(versions)) {
data.versions = versions;
+ sourceChanged = true;
+ }
+
+ if (sourceChanged) {
writeFileSync(join(dir, file), `${JSON.stringify(data, null, 2)}\n`);
}
@@ -105,11 +117,14 @@ for (const { category, dir, validate } of sources) {
}
const newest = versions[0];
- const latest = {
- version: newest.version,
- url: newest.url,
- sha256: newest.sha256,
- };
+ const latest = { version: newest.version };
+
+ if (newest.date !== undefined) {
+ latest.date = newest.date;
+ }
+
+ latest.url = newest.url;
+ latest.sha256 = newest.sha256;
if (newest.minAppVersion !== undefined) {
latest.minAppVersion = newest.minAppVersion;
diff --git a/scripts/lib/gallery.mjs b/scripts/lib/gallery.mjs
index 86ed0f9..c8e0497 100644
--- a/scripts/lib/gallery.mjs
+++ b/scripts/lib/gallery.mjs
@@ -38,10 +38,9 @@ function escapeHTML(value) {
return String(value).replace(/[&<>"]/g, (character) => HTML_ESCAPES[character]);
}
-function formatDate(isoString) {
+function formatDate(isoString, options = { dateStyle: 'long', timeStyle: 'short' }) {
const formatted = new Date(isoString).toLocaleString('en-US', {
- dateStyle: 'long',
- timeStyle: 'short',
+ ...options,
timeZone: 'UTC',
});
@@ -70,6 +69,22 @@ function renderScheme(extension) {
return label === undefined ? '' : `${escapeHTML(label)}`;
}
+function renderVersionTooltip(extension) {
+ const { date, notes } = extension.latest;
+ if (date === undefined && notes === undefined) {
+ return '';
+ }
+
+ if (date === undefined) {
+ return ` title="${escapeHTML(notes)}"`;
+ }
+
+ const formattedDate = formatDate(date, { dateStyle: 'medium' });
+ const title = notes === undefined ? formattedDate : `${formattedDate}: ${notes}`;
+ const notesAttribute = notes === undefined ? '' : ` data-notes="${escapeHTML(notes)}"`;
+ return ` title="${escapeHTML(title)}" data-date="${escapeHTML(date)}"${notesAttribute}`;
+}
+
function renderFeatured(extension) {
if (extension.featured !== true) {
return '';
@@ -173,6 +188,7 @@ function renderCard(extension) {
ICON: ``,
NAME: escapeHTML(extension.name),
VERSION: escapeHTML(extension.latest.version),
+ VERSION_TOOLTIP: renderVersionTooltip(extension),
FEATURED: renderFeatured(extension),
SCHEME: renderScheme(extension),
PREVIEW: renderPreview(extension),
diff --git a/scripts/registry-date.mjs b/scripts/registry-date.mjs
new file mode 100644
index 0000000..d433ca3
--- /dev/null
+++ b/scripts/registry-date.mjs
@@ -0,0 +1,47 @@
+export function registryDate(date = new Date()) {
+ date = new Date(date);
+ date.setUTCMinutes(0, 0, 0);
+ return date.toISOString().replace('.000Z', 'Z');
+}
+
+export function stampRegistryMetadata(versions, date) {
+ const isInitialSubmission = versions.every((version) => version.date === undefined);
+ let changed = false;
+
+ for (const version of versions) {
+ if (version.date === undefined) {
+ version.date = date;
+ changed = true;
+ }
+ }
+
+ if (isInitialSubmission && versions[0]?.notes == null) {
+ versions[0].notes = 'Initial release.';
+ changed = true;
+ }
+
+ return changed;
+}
+
+export function normalizeRegistryVersion(release) {
+ const normalized = {
+ version: release.version,
+ };
+
+ if (release.date !== undefined) {
+ normalized.date = release.date;
+ }
+
+ normalized.url = release.url;
+ normalized.sha256 = release.sha256;
+
+ if (release.minAppVersion !== undefined) {
+ normalized.minAppVersion = release.minAppVersion;
+ }
+
+ if (release.notes !== undefined) {
+ normalized.notes = release.notes;
+ }
+
+ return normalized;
+}
diff --git a/scripts/templates/card.html b/scripts/templates/card.html
index 14cab26..e3af8f3 100644
--- a/scripts/templates/card.html
+++ b/scripts/templates/card.html
@@ -1,5 +1,5 @@
- {{ICON}}{{NAME}} v{{VERSION}}{{FEATURED}}{{SCHEME}}
+ {{ICON}}{{NAME}} v{{VERSION}}{{FEATURED}}{{SCHEME}}
{{PREVIEW}}
{{DESCRIPTION}}
by {{AUTHOR}} · {{ID}}
diff --git a/test/gallery.test.mjs b/test/gallery.test.mjs
new file mode 100644
index 0000000..192bac1
--- /dev/null
+++ b/test/gallery.test.mjs
@@ -0,0 +1,24 @@
+import assert from 'node:assert/strict';
+import test from 'node:test';
+import { renderGallery } from '../scripts/lib/gallery.mjs';
+
+test('version label tooltip combines release date and notes', () => {
+ const html = renderGallery({
+ generatedAt: '2026-08-12T02:00:00Z',
+ extensions: [{
+ id: 'sample',
+ name: 'Sample',
+ description: 'Sample extension.',
+ author: 'Author',
+ homepage: 'https://example.com',
+ category: 'extension',
+ latest: {
+ version: '1.0.0',
+ date: '2026-08-12T02:00:00Z',
+ notes: 'Fix "quotes" & more.',
+ },
+ }],
+ });
+
+ assert.match(html, /v1\.0\.0<\/span>/);
+});
diff --git a/test/registry-date.test.mjs b/test/registry-date.test.mjs
new file mode 100644
index 0000000..c4e9ca9
--- /dev/null
+++ b/test/registry-date.test.mjs
@@ -0,0 +1,56 @@
+import assert from 'node:assert/strict';
+import test from 'node:test';
+import { normalizeRegistryVersion, registryDate, stampRegistryMetadata } from '../scripts/registry-date.mjs';
+
+test('registryDate truncates to the UTC hour', () => {
+ assert.equal(registryDate('2026-08-12T10:56:18+08:00'), '2026-08-12T02:00:00Z');
+});
+
+test('initial submissions receive a date and default notes', () => {
+ const versions = [{ version: '1.0.0' }];
+
+ assert.equal(stampRegistryMetadata(versions, '2026-08-12T02:00:00Z'), true);
+ assert.deepEqual(versions, [{
+ version: '1.0.0',
+ date: '2026-08-12T02:00:00Z',
+ notes: 'Initial release.',
+ }]);
+});
+
+test('initial submissions preserve provided notes', () => {
+ const versions = [{ version: '1.0.0', notes: 'A tailored introduction.' }];
+
+ stampRegistryMetadata(versions, '2026-08-12T02:00:00Z');
+ assert.equal(versions[0].notes, 'A tailored introduction.');
+});
+
+test('updates receive a date without default notes', () => {
+ const versions = [
+ { version: '1.1.0' },
+ { version: '1.0.0', date: '2026-08-01T00:00:00Z', notes: 'Initial release.' },
+ ];
+
+ assert.equal(stampRegistryMetadata(versions, '2026-08-12T02:00:00Z'), true);
+ assert.equal(versions[0].date, '2026-08-12T02:00:00Z');
+ assert.equal(versions[0].notes, undefined);
+});
+
+test('existing dates are preserved', () => {
+ const versions = [{ version: '1.0.0', date: '2000-01-01T00:00:00Z' }];
+
+ assert.equal(stampRegistryMetadata(versions, '2026-08-12T02:00:00Z'), false);
+ assert.equal(versions[0].date, '2000-01-01T00:00:00Z');
+ assert.equal(versions[0].notes, undefined);
+});
+
+test('release fields use canonical order', () => {
+ const release = normalizeRegistryVersion({
+ notes: 'Initial release.',
+ sha256: 'abc',
+ url: 'https://example.com/sample.js',
+ date: '2026-08-12T02:00:00Z',
+ version: '1.0.0',
+ });
+
+ assert.deepEqual(Object.keys(release), ['version', 'date', 'url', 'sha256', 'notes']);
+});
diff --git a/themes/markedit-theme-basic.json b/themes/markedit-theme-basic.json
index 1ee0264..14ec834 100644
--- a/themes/markedit-theme-basic.json
+++ b/themes/markedit-theme-basic.json
@@ -13,14 +13,17 @@
"versions": [
{
"version": "1.1.0",
+ "date": "2026-07-31T05:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-basic/v1.1.0/dist/markedit-theme-basic.js",
"sha256": "fcc16b6c5aab8cbb82934ea023fa064d409e7950fbd9d24c3086f14d21836c53",
"notes": "Upgrade markedit-theming to latest."
},
{
"version": "1.0.0",
+ "date": "2026-07-09T14:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-basic/v1.0.0/dist/markedit-theme-basic.js",
- "sha256": "36aa2857372dff13b5d6c2fd0f36f3fea9efb14b6742fa3e9d7a28cc966951ee"
+ "sha256": "36aa2857372dff13b5d6c2fd0f36f3fea9efb14b6742fa3e9d7a28cc966951ee",
+ "notes": "Initial release."
}
]
}
diff --git a/themes/markedit-theme-catppuccin.json b/themes/markedit-theme-catppuccin.json
index 009ac0f..d537607 100644
--- a/themes/markedit-theme-catppuccin.json
+++ b/themes/markedit-theme-catppuccin.json
@@ -14,14 +14,17 @@
"versions": [
{
"version": "1.1.0",
+ "date": "2026-07-31T05:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-catppuccin/v1.1.0/dist/markedit-theme-catppuccin.js",
"sha256": "684d828ca10f74a500a1ad1b8b500331ae63d4a0e4a0d4059108bdb2655f5630",
"notes": "Upgrade markedit-theming to latest."
},
{
"version": "1.0.0",
+ "date": "2026-07-09T14:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-catppuccin/v1.0.0/dist/markedit-theme-catppuccin.js",
- "sha256": "ae27ae2f81e5865028e8c1d7d1a87254a18097e78e9dfcda113ed6f7882614d6"
+ "sha256": "ae27ae2f81e5865028e8c1d7d1a87254a18097e78e9dfcda113ed6f7882614d6",
+ "notes": "Initial release."
}
]
}
diff --git a/themes/markedit-theme-duotone.json b/themes/markedit-theme-duotone.json
index 7e7dda8..e2c988b 100644
--- a/themes/markedit-theme-duotone.json
+++ b/themes/markedit-theme-duotone.json
@@ -13,14 +13,17 @@
"versions": [
{
"version": "1.1.0",
+ "date": "2026-07-31T05:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-duotone/v1.1.0/dist/markedit-theme-duotone.js",
"sha256": "74c777e5873edfee6d2e526289d1ce0876078d8fb943e8420fc43357f134d9e3",
"notes": "Upgrade markedit-theming to latest."
},
{
"version": "1.0.0",
+ "date": "2026-07-09T14:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-duotone/v1.0.0/dist/markedit-theme-duotone.js",
- "sha256": "f1b1e8773292a87efd13ae5b291efcbda4daef87fa752279f22a1251a876875e"
+ "sha256": "f1b1e8773292a87efd13ae5b291efcbda4daef87fa752279f22a1251a876875e",
+ "notes": "Initial release."
}
]
}
diff --git a/themes/markedit-theme-gruvbox.json b/themes/markedit-theme-gruvbox.json
index 891cd11..79d8d80 100644
--- a/themes/markedit-theme-gruvbox.json
+++ b/themes/markedit-theme-gruvbox.json
@@ -14,14 +14,17 @@
"versions": [
{
"version": "1.1.0",
+ "date": "2026-07-31T05:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-gruvbox/v1.1.0/dist/markedit-theme-gruvbox.js",
"sha256": "a4ec67d8828caa049b9a9ea6016d8307a1c81ade0ad82eb3dbb16ccb15e2769a",
"notes": "Upgrade markedit-theming to latest."
},
{
"version": "1.0.0",
+ "date": "2026-07-09T14:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-gruvbox/v1.0.0/dist/markedit-theme-gruvbox.js",
- "sha256": "d2abe83583370c16d47d4cc27f61ec96fc65fce7c093b5913f72b2a1bcc8cdd4"
+ "sha256": "d2abe83583370c16d47d4cc27f61ec96fc65fce7c093b5913f72b2a1bcc8cdd4",
+ "notes": "Initial release."
}
]
}
diff --git a/themes/markedit-theme-noctis-lilac.json b/themes/markedit-theme-noctis-lilac.json
index acbdb54..8317093 100644
--- a/themes/markedit-theme-noctis-lilac.json
+++ b/themes/markedit-theme-noctis-lilac.json
@@ -12,14 +12,17 @@
"versions": [
{
"version": "1.1.0",
+ "date": "2026-07-31T05:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-noctis-lilac/v1.1.0/dist/markedit-theme-noctis-lilac.js",
"sha256": "684fe5830f715820f125dc06f851cde2ef7eacb58c1de3cd5e0bd5030a9d576f",
"notes": "Upgrade markedit-theming to latest."
},
{
"version": "1.0.0",
+ "date": "2026-07-09T14:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-noctis-lilac/v1.0.0/dist/markedit-theme-noctis-lilac.js",
- "sha256": "2813adad175d5e1fa4eeefdea65fc458ab8605204c5598bc1f90f149d8be7e22"
+ "sha256": "2813adad175d5e1fa4eeefdea65fc458ab8605204c5598bc1f90f149d8be7e22",
+ "notes": "Initial release."
}
]
}
diff --git a/themes/markedit-theme-nord.json b/themes/markedit-theme-nord.json
index 746303b..601f0c3 100644
--- a/themes/markedit-theme-nord.json
+++ b/themes/markedit-theme-nord.json
@@ -12,14 +12,17 @@
"versions": [
{
"version": "1.1.0",
+ "date": "2026-07-31T05:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-nord/v1.1.0/dist/markedit-theme-nord.js",
"sha256": "6030e533a0bcce69b49c4862d38dfc93e3e58d5f10c52ebb92f0916997543f52",
"notes": "Upgrade markedit-theming to latest."
},
{
"version": "1.0.0",
+ "date": "2026-07-09T14:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-nord/v1.0.0/dist/markedit-theme-nord.js",
- "sha256": "ab6ba9fb2bd78685db1e01d89186e8e721a59401fe0544b929b0fcec750590fa"
+ "sha256": "ab6ba9fb2bd78685db1e01d89186e8e721a59401fe0544b929b0fcec750590fa",
+ "notes": "Initial release."
}
]
}
diff --git a/themes/markedit-theme-one-dark.json b/themes/markedit-theme-one-dark.json
index 6ced040..4e91e3b 100644
--- a/themes/markedit-theme-one-dark.json
+++ b/themes/markedit-theme-one-dark.json
@@ -12,14 +12,17 @@
"versions": [
{
"version": "1.1.0",
+ "date": "2026-07-31T05:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-one-dark/v1.1.0/dist/markedit-theme-one-dark.js",
"sha256": "54dcad1c6a1594592efeaeb6c2a0e95eaf09a3333238de911a88972e0279e6bf",
"notes": "Upgrade markedit-theming to latest."
},
{
"version": "1.0.0",
+ "date": "2026-07-09T14:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-one-dark/v1.0.0/dist/markedit-theme-one-dark.js",
- "sha256": "0cd771f25cf73773332d38e6b5b9368bb24c2b77895c32ebecd0356e04511f02"
+ "sha256": "0cd771f25cf73773332d38e6b5b9368bb24c2b77895c32ebecd0356e04511f02",
+ "notes": "Initial release."
}
]
}
diff --git a/themes/markedit-theme-quietlight.json b/themes/markedit-theme-quietlight.json
index f878cf5..b392d7e 100644
--- a/themes/markedit-theme-quietlight.json
+++ b/themes/markedit-theme-quietlight.json
@@ -12,14 +12,17 @@
"versions": [
{
"version": "1.1.0",
+ "date": "2026-07-31T05:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-quietlight/v1.1.0/dist/markedit-theme-quietlight.js",
"sha256": "2ce3a603f31f268945e71493bbb1a65abe7783d59c3a0a3d994a538919b0633e",
"notes": "Upgrade markedit-theming to latest."
},
{
"version": "1.0.0",
+ "date": "2026-07-09T14:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-quietlight/v1.0.0/dist/markedit-theme-quietlight.js",
- "sha256": "f121285a5de1b5ffa281a9077aab287715bf88ec1cdc70bedf8f80a64a701f4f"
+ "sha256": "f121285a5de1b5ffa281a9077aab287715bf88ec1cdc70bedf8f80a64a701f4f",
+ "notes": "Initial release."
}
]
}
diff --git a/themes/markedit-theme-tokyo-night.json b/themes/markedit-theme-tokyo-night.json
index 757d3cd..3b18c00 100644
--- a/themes/markedit-theme-tokyo-night.json
+++ b/themes/markedit-theme-tokyo-night.json
@@ -13,14 +13,17 @@
"versions": [
{
"version": "1.1.0",
+ "date": "2026-07-31T05:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-tokyo-night/v1.1.0/dist/markedit-theme-tokyo-night.js",
"sha256": "329ca79666cc6dddf5ef7c9def49919758d4f280c6bb968033dd105c3a5220bc",
"notes": "Upgrade markedit-theming to latest."
},
{
"version": "1.0.0",
+ "date": "2026-07-09T14:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-tokyo-night/v1.0.0/dist/markedit-theme-tokyo-night.js",
- "sha256": "82f4b0724c654d9aa5270f444a5e39cf887da3f7c1d18d45db69bd31c5496de6"
+ "sha256": "82f4b0724c654d9aa5270f444a5e39cf887da3f7c1d18d45db69bd31c5496de6",
+ "notes": "Initial release."
}
]
}
diff --git a/themes/markedit-theme-vscode.json b/themes/markedit-theme-vscode.json
index 9faa300..f7e9a67 100644
--- a/themes/markedit-theme-vscode.json
+++ b/themes/markedit-theme-vscode.json
@@ -13,20 +13,24 @@
"versions": [
{
"version": "1.2.0",
+ "date": "2026-07-29T12:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-vscode/v1.2.0/dist/markedit-theme-vscode.js",
"sha256": "f563fa0dfcf010bc90253271fda5bf3040ccf28063ebe53d34d341a51ce78c69",
"notes": "Upgrade dependency and fix selection color."
},
{
"version": "1.1.0",
+ "date": "2026-07-21T12:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-vscode/v1.1.0/dist/markedit-theme-vscode.js",
"sha256": "f0cb00e63902c93f0d516932a77a8e1bb731498525e1f4748ce56ea0279c04ef",
"notes": "Use better textColor in dark mode."
},
{
"version": "1.0.0",
+ "date": "2026-07-09T14:00:00Z",
"url": "https://raw.githubusercontent.com/MarkEdit-app/MarkEdit-theme-vscode/v1.0.0/dist/markedit-theme-vscode.js",
- "sha256": "35fa546038d8c41544c7260ca7e99cb21450df4b540bfbdc96712d34c987f2bc"
+ "sha256": "35fa546038d8c41544c7260ca7e99cb21450df4b540bfbdc96712d34c987f2bc",
+ "notes": "Initial release."
}
]
}