feat: enhance post listing and reading time display

- Implement dynamic post listing grouped by year with improved date formatting
- Add reading time display for each post
- Update index pages for both default and localized routes
- Modify content utility functions to support reading time metadata
- Refactor global styles and type definitions to support new features
This commit is contained in:
radishzzz 2025-01-26 02:59:39 +00:00
parent e9e318e02d
commit ae39d7b08c
18 changed files with 558 additions and 117 deletions

View file

@ -2,9 +2,9 @@
import themeConfig from '@/config'
const { title, subtitle } = themeConfig.site
const { titleSpace = 2 } = themeConfig.global
const { titleSpace } = themeConfig.global
const marginClass = {
const marginBottom = {
1: 'mb-1',
2: 'mb-2',
3: 'mb-3',
@ -13,18 +13,13 @@ const marginClass = {
---
<header>
<h1
class={`${marginClass} mt--5.2 text-12 c-primary font-bold font-title`}
aria-label="Title Tag"
>
<h1 class={`${marginBottom} mt--5.2 text-12 c-primary font-bold font-title`}>
<a href="/">
{title}
</a>
</h1>
<h2
class="text-5.6 c-secondary font-navbar"
aria-label="Meta Description"
>
<h2 class="text-5.6 c-secondary font-navbar">
{subtitle}
</h2>
</header>

View file

@ -6,26 +6,30 @@ const langs = ['', ...themeConfig.global.moreLocale]
const currentLocale = themeConfig.global.locale
function getLanguageDisplayName(code: string) {
if (!code)
return 'Default'
if (!code) {
return 'Default'
}
return new Intl.DisplayNames(['en'], { type: 'language' }).of(code) || code
}
---
<button
type="button"
id="language-switcher"
class="absolute right-25.6 top-20 z-99 aspect-square w-6.6 c-secondary active:scale-92"
aria-label="Switch Language"
title={`Current Language: ${getLanguageDisplayName(currentLocale)}`}
class="absolute right-25.6 top-20 z-9 aspect-square w-6.6 c-secondary active:scale-90"
aria-label={`Current Language: ${getLanguageDisplayName(currentLocale)}. Click to switch to next language.`}
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="h-full w-full">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
class="h-full w-full"
aria-hidden="true"
>
<path d="M19 21 12.3 2h-1L4.7 21l-2.5.2v.8h6.3v-.8L5.7 21l2-5.9h7.5l2 5.9-3.3.2v.8h7.9v-.8zM8 14.3l3.4-10.1 3.5 10.1z" fill="currentColor" />
</svg>
<span class="sr-only">Switch Language</span>
</button>
<script is:inline define:vars={{ langs }}>
// Move event binding into astro:page-load event
document.addEventListener('astro:page-load', () => {
const langSwitch = document.getElementById('language-switcher')
@ -33,24 +37,32 @@ document.addEventListener('astro:page-load', () => {
const { pathname, search, hash } = window.location
const segments = pathname.split('/').filter(Boolean)
const firstSegment = segments[0] || ''
// Check if first segment is a valid language code
const currentLang = langs.includes(firstSegment) ? firstSegment : ''
// Get next language in rotation (empty string means default locale)
// Get current language or empty string if invalid
const currentLang = langs.includes(firstSegment)
? firstSegment
: ''
const currentIndex = langs.indexOf(currentLang)
const nextLang = langs[(currentIndex + 1) % langs.length]
const newPath = buildNewPath(currentLang, nextLang, segments, pathname) || '/'
window.location.href = `${newPath}${search}${hash}`
})
})
// Handle path construction for both cases:
// 1. Current path has language prefix
// 2. Current path has no language prefix
function buildNewPath(currentLang, nextLang, segments, pathname) {
if (currentLang) {
segments[0] = nextLang || segments[0]
return nextLang ? `/${segments.join('/')}` : `/${segments.slice(1).join('/')}`
// Handle path with or without language code
return nextLang
? `/${segments.join('/')}`
: `/${segments.slice(1).join('/')}`
}
return nextLang ? `/${nextLang}${pathname}` : pathname
return nextLang
? `/${nextLang}${pathname}`
: pathname
}
</script>

View file

@ -51,13 +51,13 @@ const isTagActive = isTagPage(currentPath)
const isAboutActive = isAboutPage(currentPath)
---
<nav class="mb-20 mt-13 text-5.6 text-secondary font-semibold leading-13 font-navbar">
<nav class="mb-16 mt-13 text-5.6 font-semibold leading-13 font-navbar">
<ul>
<li>
<a
href={getLocalizedPath('/')}
class:list={[
isPostActive ? 'font-bold text-primary' : 'text-secondary',
isPostActive && 'font-bold text-primary'
]}
>
{currentUI.posts}
@ -67,7 +67,7 @@ const isAboutActive = isAboutPage(currentPath)
<a
href={getLocalizedPath('/tags')}
class:list={[
isTagActive ? 'font-bold text-primary' : 'text-secondary',
isTagActive && 'font-bold text-primary'
]}
>
{currentUI.tags}
@ -77,7 +77,7 @@ const isAboutActive = isAboutPage(currentPath)
<a
href={getLocalizedPath('/about')}
class:list={[
isAboutActive ? 'font-bold text-primary' : 'text-secondary',
isAboutActive && 'font-bold text-primary'
]}
>
{currentUI.about}

View file

@ -25,7 +25,7 @@ function toggleTheme() {
// Execute transition
const transition = document.startViewTransition(() => {
switchTheme()
}) as any
})
// Clean up after transition
transition.finished.then(() => {
@ -63,9 +63,13 @@ window.addEventListener('pageshow', (event) => {
<button
aria-pressed="false"
aria-label="Theme Toggle Button"
class="absolute right-9.6 top-19.8 z-99 aspect-square w-7 c-secondary active:scale-92"
class="absolute right-9.6 top-19.8 z-9 aspect-square w-7 c-secondary active:scale-92"
>
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="currentColor">
<svg
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
>
<path d="m12 1c-6.1 0-11 4.9-11 11s4.9 11 11 11 11-4.9 11-11-4.9-11-11-11m0 20c-5.8 0-10.5-4-10.5-9s4.7-9 10.5-9 10.5 4 10.5 9-4.7 9-10.5 9" />
</svg>
</button>