@@ -9,14 +9,11 @@ const root = document.documentElement;
99const topBar = document . querySelector ( ".top-bar" ) ;
1010const revealNodes = document . querySelectorAll ( "[data-reveal]" ) ;
1111const latestReleaseNodes = document . querySelectorAll ( "[data-latest-release]" ) ;
12- const releaseMeta = document . querySelector ( ".release-meta" ) ;
13- const releaseVersionNodes = document . querySelectorAll ( "[data-release-version]" ) ;
14- const releaseDateNodes = document . querySelectorAll ( "[data-release-date]" ) ;
15- const releaseChannelNodes = document . querySelectorAll ( "[data-release-channel]" ) ;
12+ const releasesBlock = document . querySelector ( "[data-releases]" ) ;
1613const langButtons = document . querySelectorAll ( "[data-lang]" ) ;
1714
1815let currentLang = "en" ;
19- let currentRelease = null ;
16+ let currentReleases = [ ] ;
2017let hasAnimatedRelease = false ;
2118
2219function safeStorageGet ( key ) {
@@ -69,6 +66,16 @@ function setLatestReleaseTargets(url) {
6966 } ) ;
7067}
7168
69+ function getReleaseSlotNodes ( slot ) {
70+ return {
71+ container : document . querySelector ( `[data-release-slot="${ slot } "]` ) ,
72+ label : document . querySelector ( `[data-release-slot-label="${ slot } "]` ) ,
73+ link : document . querySelector ( `[data-release-slot-link="${ slot } "]` ) ,
74+ version : document . querySelector ( `[data-release-slot-version="${ slot } "]` ) ,
75+ date : document . querySelector ( `[data-release-slot-date="${ slot } "]` )
76+ } ;
77+ }
78+
7279function formatReleaseDate ( value , lang ) {
7380 const date = new Date ( value ) ;
7481
@@ -116,43 +123,63 @@ function applyTranslations(lang) {
116123 document . title = dictionary [ "meta.title" ] ;
117124}
118125
119- function renderRelease ( ) {
120- if ( ! releaseMeta || ! currentRelease ) {
126+ function renderReleaseCards ( ) {
127+ if ( ! releasesBlock ) {
121128 return ;
122129 }
123130
124- const dictionary = getDictionary ( currentLang ) ;
125- const formattedDate = formatReleaseDate ( currentRelease . publishedAt , currentLang ) ;
126- const stateKey = currentRelease . prerelease ? "release.preview" : "release.latest" ;
131+ const slots = [
132+ { key : "latest" , release : currentReleases [ 0 ] || null , labelKey : "release.latestCard" } ,
133+ { key : "previous" , release : currentReleases [ 1 ] || null , labelKey : "release.previousCard" }
134+ ] ;
127135
128- releaseVersionNodes . forEach ( ( node ) => {
129- node . textContent = currentRelease . version ;
130- } ) ;
136+ slots . forEach ( ( { key, release, labelKey } ) => {
137+ const slotNodes = getReleaseSlotNodes ( key ) ;
131138
132- releaseDateNodes . forEach ( ( node ) => {
133- node . textContent = formattedDate ;
134- node . setAttribute ( "datetime" , currentRelease . publishedAt ) ;
135- } ) ;
139+ if ( ! slotNodes . container ) {
140+ return ;
141+ }
142+
143+ const isVisible = Boolean ( release ) ;
144+ slotNodes . container . hidden = ! isVisible ;
145+
146+ if ( ! isVisible ) {
147+ return ;
148+ }
136149
137- releaseChannelNodes . forEach ( ( node ) => {
138- node . textContent = dictionary [ stateKey ] ;
150+ if ( slotNodes . label ) {
151+ slotNodes . label . textContent = getDictionary ( currentLang ) [ labelKey ] ;
152+ }
153+
154+ if ( slotNodes . link instanceof HTMLAnchorElement ) {
155+ slotNodes . link . href = release . url || RELEASE_URL ;
156+ }
157+
158+ if ( slotNodes . version ) {
159+ slotNodes . version . textContent = release . version ;
160+ }
161+
162+ if ( slotNodes . date ) {
163+ slotNodes . date . textContent = formatReleaseDate ( release . publishedAt , currentLang ) ;
164+ slotNodes . date . setAttribute ( "datetime" , release . publishedAt ) ;
165+ }
139166 } ) ;
140167}
141168
142169function setReleaseVisibility ( isVisible ) {
143- if ( ! releaseMeta ) {
170+ if ( ! releasesBlock ) {
144171 return ;
145172 }
146173
147- releaseMeta . hidden = ! isVisible ;
174+ releasesBlock . hidden = ! isVisible ;
148175
149176 if ( isVisible ) {
150- releaseMeta . classList . add ( "is-visible" ) ;
177+ releasesBlock . classList . add ( "is-visible" ) ;
151178
152179 if ( ! hasAnimatedRelease ) {
153- releaseMeta . classList . remove ( "is-appearing" ) ;
154- void releaseMeta . offsetWidth ;
155- releaseMeta . classList . add ( "is-appearing" ) ;
180+ releasesBlock . classList . remove ( "is-appearing" ) ;
181+ void releasesBlock . offsetWidth ;
182+ releasesBlock . classList . add ( "is-appearing" ) ;
156183 hasAnimatedRelease = true ;
157184 }
158185 }
@@ -169,7 +196,7 @@ function updateLanguageButtons(lang) {
169196function applyLanguage ( lang ) {
170197 currentLang = translations [ lang ] ? lang : "en" ;
171198 applyTranslations ( currentLang ) ;
172- renderRelease ( ) ;
199+ renderReleaseCards ( ) ;
173200 updateLanguageButtons ( currentLang ) ;
174201 safeStorageSet ( LANG_KEY , currentLang ) ;
175202}
@@ -227,25 +254,27 @@ async function loadLatestRelease() {
227254 throw new Error ( "GitHub API returned an unexpected payload." ) ;
228255 }
229256
230- const release = releases
257+ const publishedReleases = releases
231258 . filter ( ( item ) => item && ! item . draft && item . published_at )
232- . sort ( ( left , right ) => new Date ( right . published_at ) - new Date ( left . published_at ) ) [ 0 ] ;
233-
234- if ( ! release ) {
259+ . sort ( ( left , right ) => new Date ( right . published_at ) - new Date ( left . published_at ) )
260+ . slice ( 0 , 2 )
261+ . map ( ( release ) => ( {
262+ version : ( release . tag_name || release . name || "" ) . replace ( / ^ v / i, "" ) ,
263+ publishedAt : release . published_at ,
264+ prerelease : Boolean ( release . prerelease ) ,
265+ url : release . html_url || RELEASE_URL
266+ } ) ) ;
267+
268+ if ( publishedReleases . length === 0 ) {
235269 throw new Error ( "No published releases were found." ) ;
236270 }
237271
238- currentRelease = {
239- version : ( release . tag_name || release . name || "" ) . replace ( / ^ v / i, "" ) ,
240- publishedAt : release . published_at ,
241- prerelease : Boolean ( release . prerelease )
242- } ;
243-
244- setLatestReleaseTargets ( release . html_url || RELEASE_URL ) ;
272+ currentReleases = publishedReleases ;
273+ setLatestReleaseTargets ( publishedReleases [ 0 ] . url || RELEASE_URL ) ;
245274 setReleaseVisibility ( true ) ;
246- renderRelease ( ) ;
275+ renderReleaseCards ( ) ;
247276 } catch ( error ) {
248- currentRelease = null ;
277+ currentReleases = [ ] ;
249278 setLatestReleaseTargets ( RELEASE_URL ) ;
250279 setReleaseVisibility ( false ) ;
251280 console . warn ( "Unable to load latest release metadata." , error ) ;
0 commit comments