Skip to content

Commit cff321a

Browse files
committed
✨ Improve changelog dialog
1 parent b15ccce commit cff321a

File tree

1 file changed

+106
-40
lines changed

1 file changed

+106
-40
lines changed

src/components/changelogDialog.svelte

Lines changed: 106 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
55
const ISSUES_URL = 'https://api.github.com/repos/animated-java/animated-java/issues/'
66
7-
const FORMATTED_CHANGELOG_CACHE = new Map<string, string>()
8-
97
const formatDateFull = (date: string) => {
108
// @ts-expect-error No types for getDateDisplay
119
return getDateDisplay(date).full
@@ -15,44 +13,37 @@
1513
return getDateDisplay(date).short
1614
}
1715
18-
const formatMarkdown = async (text: string) => {
19-
const issues: Record<number, { title: string; url: string }> = {}
20-
text = text.replace('[BREAKING]', '<span class="breaking">BREAKING</span>')
21-
text = text.replace(/\[([^\]]+?)\]\(([^)]+?)\)/gm, (match, title, url) => {
22-
const issueMatch = url.match(/issues\/(\d+)/)
23-
if (issueMatch) {
24-
const issueNumber = parseInt(issueMatch[1])
25-
issues[issueNumber] = { title, url }
26-
return `$$$ISSUE${issueNumber}$$$`
27-
}
28-
return `<a href="${url}" target="_blank">${title}</a>`
29-
})
30-
for (const [issueNumber, { url }] of Object.entries(issues)) {
31-
const data = await fetch(ISSUES_URL + issueNumber)
32-
.then(response => response.json())
33-
.catch(() => undefined)
34-
text = text.replace(
35-
`$$$ISSUE${issueNumber}$$$`,
36-
`<a href="${url}" target="_blank">#${issueNumber}${data ? ' - ' + data.title : ''}</a>`
37-
)
38-
}
39-
// inline code blocks
40-
text = text.replace(/`([^`]+?)`/g, '<code>$1</code>')
41-
return text
16+
interface GithubIssue {
17+
number: number
18+
title: string
19+
html_url: string
4220
}
4321
44-
const getChangelog = async (item: string) => {
45-
if (FORMATTED_CHANGELOG_CACHE.has(item)) {
46-
return FORMATTED_CHANGELOG_CACHE.get(item)
47-
}
48-
const formatted = await formatMarkdown(item)
49-
FORMATTED_CHANGELOG_CACHE.set(item, formatted)
50-
return formatted
22+
const ISSUES = new Map<string, GithubIssue>()
23+
24+
const fetchIssue = async (issueId: string): Promise<GithubIssue | undefined> => {
25+
if (ISSUES.has(issueId)) return ISSUES.get(issueId)
26+
27+
const issue = await fetch(ISSUES_URL + issueId)
28+
.then(async response => {
29+
const json = await response.json()
30+
if (!response.ok)
31+
throw new Error(
32+
`Failed to fetch issue ${issueId}: ` + (json.message ?? response.statusText)
33+
)
34+
return json
35+
})
36+
.catch(e => {
37+
console.error(`Failed to fetch issue ${issueId}`, e)
38+
return undefined
39+
})
40+
if (issue) ISSUES.set(issueId, issue)
41+
return issue
5142
}
5243
</script>
5344

5445
<div class="content plugin_browser_tabbed_page" id="plugin_browser_changelog">
55-
{#each Object.values(changelog).reverse() as versions}
46+
{#each Object.values(changelog).reverse().slice(0, 4) as versions}
5647
<div class="title-container">
5748
<img src={AnimatedJavaIcon} alt="" />
5849
<h3>
@@ -70,21 +61,72 @@
7061
<ul>
7162
{#each versions.categories as category}
7263
<li>
73-
<h4>{category.title}</h4>
64+
<h4>
65+
{category.title}
66+
</h4>
7467
<ul class="plugin_changelog_features">
7568
{#each category.list as item}
76-
<li>
77-
{#await getChangelog(item) then data}
78-
{@html data}
69+
{@const issueMatch = /^Fixed \[#(\d+)\]\(.+?\)$/.exec(item)}
70+
{#if issueMatch}
71+
{#await fetchIssue(issueMatch[1])}
72+
<li>
73+
<p>
74+
<i class="material-icons icon spinner"
75+
>progress_activity</i
76+
>
77+
<!-- svelte-ignore missing-declaration -->
78+
{@html pureMarked(item)}
79+
</p>
80+
</li>
81+
{:then issue}
82+
<li>
83+
<p>
84+
{'Fixed '}
85+
{#if issue}
86+
<a href={issue.html_url} target="_blank">
87+
{'#' + issue.number}
88+
</a>
89+
{' - '}
90+
<!-- svelte-ignore missing-declaration -->
91+
{@html pureMarked(issue.title)}
92+
{:else}
93+
<a
94+
href="${ISSUES_URL + issueMatch[1]}"
95+
target="_blank"
96+
>
97+
{'#' + issueMatch[1]}
98+
</a>
99+
{/if}
100+
</p>
101+
</li>
102+
{:catch}
103+
<li>
104+
<!-- svelte-ignore missing-declaration -->
105+
{@html pureMarked(item)}
106+
</li>
79107
{/await}
80-
</li>
108+
{:else if item.startsWith('[BREAKING]')}
109+
<li>
110+
<p>
111+
<span class="breaking">BREAKING</span>
112+
<!-- svelte-ignore missing-declaration -->
113+
{@html pureMarked(item.replace('[BREAKING]', '').trim())}
114+
</p>
115+
</li>
116+
{:else}
117+
<li>
118+
<!-- svelte-ignore missing-declaration -->
119+
{@html pureMarked(item)}
120+
</li>
121+
{/if}
81122
{/each}
82123
</ul>
83124
</li>
84125
{/each}
85126
</ul>
86127
<hr />
87128
{/each}
129+
<p class="disclaimer">To see the full changelog, open Animated Java in the plugin list.</p>
88130
</div>
89131

90132
<style>
@@ -105,7 +147,7 @@
105147
border-radius: 3px;
106148
font-size: 0.9em;
107149
font-weight: bold;
108-
margin-right: 0.25rem;
150+
height: min-content;
109151
}
110152
img {
111153
border-radius: 4px;
@@ -128,4 +170,28 @@
128170
hr {
129171
margin: 2rem 0;
130172
}
173+
.disclaimer {
174+
font-size: 0.9em;
175+
color: var(--color-text-secondary);
176+
font-style: italic;
177+
text-align: center;
178+
margin-top: 1rem;
179+
}
180+
li > p {
181+
display: flex;
182+
flex-direction: row;
183+
gap: 0.5rem;
184+
align-items: flex-start;
185+
}
186+
@keyframes spin {
187+
from {
188+
transform: rotate(0deg);
189+
}
190+
to {
191+
transform: rotate(360deg);
192+
}
193+
}
194+
.spinner {
195+
animation: spin 1s linear infinite;
196+
}
131197
</style>

0 commit comments

Comments
 (0)