@@ -3,8 +3,8 @@ document.documentElement.classList.add("motion-ready");
33const RELEASE_URL = "https://github.com/monogram-android/monogram/releases" ;
44const RELEASES_API_URL = "https://api.github.com/repos/monogram-android/monogram/releases?per_page=10" ;
55const LANG_KEY = "monogram-site-language" ;
6- const LIGHT_THEME_COLOR = "#f6f3fb " ;
7- const DARK_THEME_COLOR = "#060708 " ;
6+ const LIGHT_THEME_COLOR = "#f3f4f8 " ;
7+ const DARK_THEME_COLOR = "#111417 " ;
88const translations = window . MONOGRAM_TRANSLATIONS || { } ;
99
1010const root = document . documentElement ;
@@ -14,7 +14,7 @@ const topBar = document.querySelector(".top-bar");
1414const revealNodes = document . querySelectorAll ( "[data-reveal]" ) ;
1515const latestReleaseNodes = document . querySelectorAll ( "[data-latest-release]" ) ;
1616const releasesBlock = document . querySelector ( "[data-releases]" ) ;
17- const langButtons = document . querySelectorAll ( "[data-lang]" ) ;
17+ const langChips = document . querySelectorAll ( "[data-lang]" ) ;
1818
1919let currentLang = "en" ;
2020let currentReleases = [ ] ;
@@ -50,7 +50,7 @@ function detectPreferredLanguage() {
5050}
5151
5252function getDictionary ( lang ) {
53- return translations [ lang ] || translations . en ;
53+ return translations [ lang ] || translations . en || { } ;
5454}
5555
5656function detectSystemTheme ( ) {
@@ -95,13 +95,13 @@ function updateTopBar() {
9595 return ;
9696 }
9797
98- topBar . dataset . elevated = window . scrollY > 10 ? "true" : "false" ;
98+ topBar . dataset . scrolled = window . scrollY > 10 ? "true" : "false" ;
9999}
100100
101101function setLatestReleaseTargets ( url ) {
102102 latestReleaseNodes . forEach ( ( node ) => {
103- if ( node instanceof HTMLAnchorElement ) {
104- node . href = url || RELEASE_URL ;
103+ if ( node instanceof HTMLElement ) {
104+ node . setAttribute ( " href" , url || RELEASE_URL ) ;
105105 }
106106 } ) ;
107107}
@@ -148,9 +148,13 @@ function applyTranslations(lang) {
148148 } ) ;
149149
150150 document . querySelectorAll ( "[data-i18n-attr]" ) . forEach ( ( node ) => {
151- const pairs = node . getAttribute ( "data-i18n-attr" ) . split ( ", ") ;
151+ const rawValue = node . getAttribute ( "data-i18n-attr" ) ;
152152
153- pairs . forEach ( ( pair ) => {
153+ if ( ! rawValue ) {
154+ return ;
155+ }
156+
157+ rawValue . split ( "," ) . forEach ( ( pair ) => {
154158 const [ attribute , key ] = pair . split ( ":" ) . map ( ( part ) => part . trim ( ) ) ;
155159
156160 if ( attribute && key && dictionary [ key ] ) {
@@ -160,17 +164,18 @@ function applyTranslations(lang) {
160164 } ) ;
161165
162166 root . lang = lang === "zh" ? "zh-CN" : lang ;
163- document . title = dictionary [ "meta.title" ] ;
167+ document . title = dictionary [ "meta.title" ] || "Monogram for Android" ;
164168}
165169
166- function renderReleaseCards ( ) {
170+ function renderReleaseRows ( ) {
167171 if ( ! releasesBlock ) {
168172 return ;
169173 }
170174
171175 const slots = [
172176 { key : "latest" , release : currentReleases [ 0 ] || null , labelKey : "release.latestCard" } ,
173- { key : "previous" , release : currentReleases [ 1 ] || null , labelKey : "release.previousCard" }
177+ { key : "previous" , release : currentReleases [ 1 ] || null , labelKey : null } ,
178+ { key : "earlier" , release : currentReleases [ 2 ] || null , labelKey : null }
174179 ] ;
175180
176181 slots . forEach ( ( { key, release, labelKey } ) => {
@@ -187,12 +192,12 @@ function renderReleaseCards() {
187192 return ;
188193 }
189194
190- if ( slotNodes . label ) {
191- slotNodes . label . textContent = getDictionary ( currentLang ) [ labelKey ] ;
195+ if ( slotNodes . label && labelKey ) {
196+ slotNodes . label . textContent = getDictionary ( currentLang ) [ labelKey ] || "" ;
192197 }
193198
194- if ( slotNodes . link instanceof HTMLAnchorElement ) {
195- slotNodes . link . href = release . url || RELEASE_URL ;
199+ if ( slotNodes . link instanceof HTMLElement ) {
200+ slotNodes . link . setAttribute ( " href" , release . url || RELEASE_URL ) ;
196201 }
197202
198203 if ( slotNodes . version ) {
@@ -204,6 +209,7 @@ function renderReleaseCards() {
204209 slotNodes . date . setAttribute ( "datetime" , release . publishedAt ) ;
205210 }
206211 } ) ;
212+
207213}
208214
209215function setReleaseVisibility ( isVisible ) {
@@ -225,26 +231,26 @@ function setReleaseVisibility(isVisible) {
225231 releasesBlock . hidden = true ;
226232}
227233
228- function updateLanguageButtons ( lang ) {
229- langButtons . forEach ( ( button ) => {
230- const isActive = button . dataset . lang === lang ;
231- button . classList . toggle ( "is-active ", isActive ) ;
232- button . setAttribute ( "aria-pressed" , isActive ? "true" : "false" ) ;
234+ function updateLanguageChips ( lang ) {
235+ langChips . forEach ( ( chip ) => {
236+ const isActive = chip . getAttribute ( "data- lang" ) === lang ;
237+ chip . toggleAttribute ( "selected ", isActive ) ;
238+ chip . setAttribute ( "aria-pressed" , isActive ? "true" : "false" ) ;
233239 } ) ;
234240}
235241
236242function applyLanguage ( lang ) {
237243 currentLang = translations [ lang ] ? lang : "en" ;
238244 applyTranslations ( currentLang ) ;
239- renderReleaseCards ( ) ;
240- updateLanguageButtons ( currentLang ) ;
245+ renderReleaseRows ( ) ;
246+ updateLanguageChips ( currentLang ) ;
241247 safeStorageSet ( LANG_KEY , currentLang ) ;
242248}
243249
244250function setupLanguageSwitcher ( ) {
245- langButtons . forEach ( ( button ) => {
246- button . addEventListener ( "click" , ( ) => {
247- applyLanguage ( button . dataset . lang || "en" ) ;
251+ langChips . forEach ( ( chip ) => {
252+ chip . addEventListener ( "click" , ( ) => {
253+ applyLanguage ( chip . getAttribute ( "data- lang" ) || "en" ) ;
248254 } ) ;
249255 } ) ;
250256}
@@ -297,7 +303,7 @@ async function loadLatestRelease() {
297303 const publishedReleases = releases
298304 . filter ( ( item ) => item && ! item . draft && item . published_at )
299305 . sort ( ( left , right ) => new Date ( right . published_at ) - new Date ( left . published_at ) )
300- . slice ( 0 , 2 )
306+ . slice ( 0 , 3 )
301307 . map ( ( release ) => ( {
302308 version : ( release . tag_name || release . name || "" ) . replace ( / ^ v / i, "" ) ,
303309 publishedAt : release . published_at ,
@@ -311,7 +317,7 @@ async function loadLatestRelease() {
311317
312318 currentReleases = publishedReleases ;
313319 setLatestReleaseTargets ( publishedReleases [ 0 ] . url || RELEASE_URL ) ;
314- renderReleaseCards ( ) ;
320+ renderReleaseRows ( ) ;
315321 setReleaseVisibility ( true ) ;
316322 } catch ( error ) {
317323 currentReleases = [ ] ;
0 commit comments