|
6090 | 6090 | return html; |
6091 | 6091 | } |
6092 | 6092 |
|
6093 | | - async function openChangelog(version) { |
| 6093 | + /** Compare two semver strings. Returns -1, 0, or 1. */ |
| 6094 | + function compareSemver(a, b) { |
| 6095 | + const pa = a.split('.').map(Number); |
| 6096 | + const pb = b.split('.').map(Number); |
| 6097 | + for (let i = 0; i < 3; i++) { |
| 6098 | + const va = pa[i] || 0, vb = pb[i] || 0; |
| 6099 | + if (va < vb) return -1; |
| 6100 | + if (va > vb) return 1; |
| 6101 | + } |
| 6102 | + return 0; |
| 6103 | + } |
| 6104 | + |
| 6105 | + /** |
| 6106 | + * Open the changelog modal. |
| 6107 | + * @param {string} version - The current/target version |
| 6108 | + * @param {string} [sinceVersion] - If provided, show all releases after this version up to `version` |
| 6109 | + */ |
| 6110 | + async function openChangelog(version, sinceVersion) { |
6094 | 6111 | const modal = $('#changelog-modal'); |
6095 | 6112 | const body = $('#changelog-body'); |
6096 | 6113 | const meta = $('#changelog-meta'); |
|
6101 | 6118 | title.textContent = "What's New"; |
6102 | 6119 | modal.classList.remove('hidden'); |
6103 | 6120 |
|
6104 | | - const data = await window.snowify.getChangelog(version); |
| 6121 | + // Multi-version mode: fetch releases between sinceVersion and version |
| 6122 | + if (sinceVersion && compareSemver(sinceVersion, version) < 0) { |
| 6123 | + const releases = await window.snowify.getRecentReleases(); |
| 6124 | + // Filter to versions > sinceVersion and <= version, sort descending (newest first) |
| 6125 | + const missed = releases |
| 6126 | + .filter(r => r.version && compareSemver(r.version, sinceVersion) > 0 && compareSemver(r.version, version) <= 0) |
| 6127 | + .sort((a, b) => compareSemver(b.version, a.version)); |
| 6128 | + |
| 6129 | + if (missed.length === 0) { |
| 6130 | + // Fallback to single version |
| 6131 | + return openChangelog(version); |
| 6132 | + } |
6105 | 6133 |
|
6106 | | - if (!data || !data.body) { |
6107 | | - body.innerHTML = '<div class="changelog-empty"><p>No changelog available for this version.</p></div>'; |
6108 | | - meta.textContent = `v${version}`; |
6109 | | - return; |
6110 | | - } |
| 6134 | + title.textContent = missed.length === 1 |
| 6135 | + ? (missed[0].name || `What's New in v${version}`) |
| 6136 | + : "What's New"; |
| 6137 | + meta.textContent = missed.length > 1 |
| 6138 | + ? `${missed.length} updates since v${sinceVersion}` |
| 6139 | + : ''; |
| 6140 | + |
| 6141 | + let html = ''; |
| 6142 | + missed.forEach((rel, i) => { |
| 6143 | + if (missed.length > 1) { |
| 6144 | + const dateStr = rel.date |
| 6145 | + ? new Date(rel.date).toLocaleDateString(undefined, { year: 'numeric', month: 'long', day: 'numeric' }) |
| 6146 | + : ''; |
| 6147 | + html += `<div class="changelog-version-section${i > 0 ? ' changelog-version-divider' : ''}">`; |
| 6148 | + html += `<h2 class="changelog-version-heading">${escapeHtml(rel.name || `v${rel.version}`)}</h2>`; |
| 6149 | + if (dateStr) html += `<p class="changelog-version-date">${dateStr}</p>`; |
| 6150 | + } |
| 6151 | + html += renderMarkdown(rel.body || ''); |
| 6152 | + if (missed.length > 1) html += '</div>'; |
| 6153 | + }); |
| 6154 | + |
| 6155 | + body.innerHTML = html; |
6111 | 6156 |
|
6112 | | - title.textContent = data.name || `What's New in v${data.version}`; |
6113 | | - if (data.date) { |
6114 | | - const d = new Date(data.date); |
6115 | | - meta.textContent = `Released ${d.toLocaleDateString(undefined, { year: 'numeric', month: 'long', day: 'numeric' })}`; |
| 6157 | + // Single version — set proper title/meta |
| 6158 | + if (missed.length === 1) { |
| 6159 | + const rel = missed[0]; |
| 6160 | + title.textContent = rel.name || `What's New in v${rel.version}`; |
| 6161 | + if (rel.date) { |
| 6162 | + const d = new Date(rel.date); |
| 6163 | + meta.textContent = `Released ${d.toLocaleDateString(undefined, { year: 'numeric', month: 'long', day: 'numeric' })}`; |
| 6164 | + } |
| 6165 | + } |
| 6166 | + } else { |
| 6167 | + // Single version mode (direct open from button) |
| 6168 | + const data = await window.snowify.getChangelog(version); |
| 6169 | + |
| 6170 | + if (!data || !data.body) { |
| 6171 | + body.innerHTML = '<div class="changelog-empty"><p>No changelog available for this version.</p></div>'; |
| 6172 | + meta.textContent = `v${version}`; |
| 6173 | + return; |
| 6174 | + } |
| 6175 | + |
| 6176 | + title.textContent = data.name || `What's New in v${data.version}`; |
| 6177 | + if (data.date) { |
| 6178 | + const d = new Date(data.date); |
| 6179 | + meta.textContent = `Released ${d.toLocaleDateString(undefined, { year: 'numeric', month: 'long', day: 'numeric' })}`; |
| 6180 | + } |
| 6181 | + body.innerHTML = renderMarkdown(data.body); |
6116 | 6182 | } |
6117 | | - body.innerHTML = renderMarkdown(data.body); |
6118 | 6183 |
|
6119 | 6184 | // Make links open externally |
6120 | 6185 | body.querySelectorAll('a[href]').forEach(a => { |
|
6149 | 6214 | const version = await window.snowify.getVersion(); |
6150 | 6215 | const lastSeenVersion = localStorage.getItem('snowify_last_changelog_version'); |
6151 | 6216 | if (lastSeenVersion && lastSeenVersion !== version) { |
6152 | | - // Version changed — show changelog after a short delay |
6153 | | - setTimeout(() => openChangelog(version), 1500); |
| 6217 | + // Version changed — show stacked changelog for all missed versions |
| 6218 | + setTimeout(() => openChangelog(version, lastSeenVersion), 1500); |
6154 | 6219 | } |
6155 | 6220 | localStorage.setItem('snowify_last_changelog_version', version); |
6156 | 6221 | })(); |
|
0 commit comments