feat: update tag and timeline share panel copy for clarity and conciseness
Some checks failed
docker-images / resolve-build-targets (push) Successful in 7s
ui-regression / playwright-regression (push) Failing after 13m4s
docker-images / build-and-push (admin) (push) Successful in 1m17s
docker-images / build-and-push (backend) (push) Successful in 28m13s
docker-images / build-and-push (frontend) (push) Successful in 47s
docker-images / submit-indexnow (push) Successful in 13s
Some checks failed
docker-images / resolve-build-targets (push) Successful in 7s
ui-regression / playwright-regression (push) Failing after 13m4s
docker-images / build-and-push (admin) (push) Successful in 1m17s
docker-images / build-and-push (backend) (push) Successful in 28m13s
docker-images / build-and-push (frontend) (push) Successful in 47s
docker-images / submit-indexnow (push) Successful in 13s
style: enhance global CSS for better responsiveness of terminal chips and navigation pills test: remove inline subscription test and add maintenance mode access code test feat: implement media library picker dialog for selecting images from the media library feat: add media URL controls for uploading and managing media assets feat: add migration for music_enabled and maintenance_mode settings in site settings feat: implement maintenance mode functionality with access control feat: create maintenance page with access code input and error handling chore: add TypeScript declaration for QR code module
This commit is contained in:
@@ -16,7 +16,8 @@ const {
|
||||
|
||||
const { locale, t, buildLocaleUrl } = getI18n(Astro);
|
||||
const aiEnabled = Boolean(Astro.props.siteSettings?.ai?.enabled);
|
||||
const musicPlaylist = (Astro.props.siteSettings?.musicPlaylist || []).filter(
|
||||
const musicEnabled = Astro.props.siteSettings?.musicEnabled ?? true;
|
||||
const musicPlaylist = (musicEnabled ? Astro.props.siteSettings?.musicPlaylist : []).filter(
|
||||
(item) => item?.title?.trim() && item?.url?.trim()
|
||||
);
|
||||
const musicPlaylistPayload = JSON.stringify(musicPlaylist);
|
||||
@@ -60,11 +61,11 @@ const currentNavLabel =
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<div class="relative hidden lg:block flex-1 min-w-0 max-w-[16rem] xl:max-w-[18rem]">
|
||||
<div class="terminal-toolbar-module gap-2 px-2.5 py-1.5">
|
||||
<div class="terminal-toolbar-label" id="search-label">{t('header.searchPromptKeyword')}</div>
|
||||
<div class="relative hidden min-w-[20rem] grow basis-[24rem] lg:block xl:min-w-[24rem] xl:basis-[30rem]">
|
||||
<div class="terminal-toolbar-module min-w-0 gap-2 px-2.5 py-1.5">
|
||||
<div class="terminal-toolbar-label shrink-0 whitespace-nowrap" id="search-label">{t('header.searchPromptKeyword')}</div>
|
||||
{aiEnabled && (
|
||||
<div id="search-mode-panel" class="hidden 2xl:flex items-center gap-1 rounded-xl border border-[var(--border-color)] bg-[var(--header-bg)]/80 p-1">
|
||||
<div id="search-mode-panel" class="hidden shrink-0 2xl:flex items-center gap-1 rounded-xl border border-[var(--border-color)] bg-[var(--header-bg)]/80 p-1">
|
||||
<button
|
||||
type="button"
|
||||
class="search-mode-btn rounded-lg px-2.5 py-1.5 text-xs font-medium text-[var(--text-secondary)] transition hover:bg-[var(--header-bg)]"
|
||||
@@ -91,7 +92,7 @@ const currentNavLabel =
|
||||
placeholder={t('header.searchPlaceholderKeyword')}
|
||||
class="terminal-console-input"
|
||||
/>
|
||||
<button id="search-btn" class="terminal-toolbar-iconbtn h-8 w-8" aria-label="Search">
|
||||
<button id="search-btn" class="terminal-toolbar-iconbtn h-8 w-8 shrink-0" aria-label="Search">
|
||||
<i id="search-btn-icon" class="fas fa-search text-sm"></i>
|
||||
</button>
|
||||
</div>
|
||||
@@ -104,73 +105,89 @@ const currentNavLabel =
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<div class="hidden 2xl:flex terminal-toolbar-module min-w-0 max-w-[13rem] gap-2 px-2.5 py-1.5">
|
||||
<div class="flex h-9 w-9 shrink-0 items-center justify-center overflow-hidden rounded-xl border border-[var(--border-color)] bg-[var(--primary)]/8">
|
||||
<img
|
||||
id="desktop-music-cover"
|
||||
src={currentMusicTrack?.coverImageUrl || ''}
|
||||
alt={currentMusicTrack?.title || 'Music cover'}
|
||||
class:list={[
|
||||
'h-full w-full object-cover',
|
||||
!currentMusicTrack?.coverImageUrl && 'hidden'
|
||||
]}
|
||||
/>
|
||||
<i
|
||||
id="desktop-music-cover-fallback"
|
||||
class:list={[
|
||||
'fas fa-compact-disc text-sm text-[var(--primary)]',
|
||||
currentMusicTrack?.coverImageUrl && 'hidden'
|
||||
]}
|
||||
></i>
|
||||
</div>
|
||||
<div class="min-w-0 flex-1">
|
||||
<p class="truncate text-[13px] font-semibold text-[var(--title-color)]" id="desktop-music-title">
|
||||
{currentMusicTrack?.title || '未配置曲目'}
|
||||
</p>
|
||||
<div class="mt-1 flex items-center gap-1">
|
||||
<button id="desktop-music-prev" class="terminal-toolbar-iconbtn h-7 w-7" aria-label="Previous track" disabled={!hasMusicPlaylist}>
|
||||
<i class="fas fa-step-backward text-[11px]"></i>
|
||||
</button>
|
||||
<button id="desktop-music-play" class="terminal-toolbar-iconbtn h-7 w-7 bg-[var(--primary)]/12 text-[var(--primary)]" style="border-color: color-mix(in oklab, var(--primary) 28%, var(--border-color));" aria-label="Play or pause" disabled={!hasMusicPlaylist}>
|
||||
<i class="fas fa-play text-[11px]" id="desktop-music-play-icon"></i>
|
||||
</button>
|
||||
<button id="desktop-music-next" class="terminal-toolbar-iconbtn h-7 w-7" aria-label="Next track" disabled={!hasMusicPlaylist}>
|
||||
<i class="fas fa-step-forward text-[11px]"></i>
|
||||
</button>
|
||||
<div class="ml-auto hidden shrink-0 items-center gap-2 lg:flex">
|
||||
{musicEnabled && (
|
||||
<div class="hidden 2xl:flex terminal-toolbar-module min-w-0 max-w-[13rem] gap-2 px-2.5 py-1.5">
|
||||
<div class="flex h-9 w-9 shrink-0 items-center justify-center overflow-hidden rounded-xl border border-[var(--border-color)] bg-[var(--primary)]/8">
|
||||
<img
|
||||
id="desktop-music-cover"
|
||||
src={currentMusicTrack?.coverImageUrl || ''}
|
||||
alt={currentMusicTrack?.title || 'Music cover'}
|
||||
class:list={[
|
||||
'h-full w-full object-cover',
|
||||
!currentMusicTrack?.coverImageUrl && 'hidden'
|
||||
]}
|
||||
/>
|
||||
<i
|
||||
id="desktop-music-cover-fallback"
|
||||
class:list={[
|
||||
'fas fa-compact-disc text-sm text-[var(--primary)]',
|
||||
currentMusicTrack?.coverImageUrl && 'hidden'
|
||||
]}
|
||||
></i>
|
||||
</div>
|
||||
<div class="min-w-0 flex-1">
|
||||
<p class="truncate text-[13px] font-semibold text-[var(--title-color)]" id="desktop-music-title">
|
||||
{currentMusicTrack?.title || '未配置曲目'}
|
||||
</p>
|
||||
<div class="mt-1 flex items-center gap-1">
|
||||
<button id="desktop-music-prev" class="terminal-toolbar-iconbtn h-7 w-7" aria-label="Previous track" disabled={!hasMusicPlaylist}>
|
||||
<i class="fas fa-step-backward text-[11px]"></i>
|
||||
</button>
|
||||
<button id="desktop-music-play" class="terminal-toolbar-iconbtn h-7 w-7 bg-[var(--primary)]/12 text-[var(--primary)]" style="border-color: color-mix(in oklab, var(--primary) 28%, var(--border-color));" aria-label="Play or pause" disabled={!hasMusicPlaylist}>
|
||||
<i class="fas fa-play text-[11px]" id="desktop-music-play-icon"></i>
|
||||
</button>
|
||||
<button id="desktop-music-next" class="terminal-toolbar-iconbtn h-7 w-7" aria-label="Next track" disabled={!hasMusicPlaylist}>
|
||||
<i class="fas fa-step-forward text-[11px]"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{aiEnabled && (
|
||||
<a
|
||||
href="/ask"
|
||||
class="inline-flex shrink-0 items-center gap-2 rounded-xl border border-[var(--primary)]/18 bg-[var(--primary)]/8 px-2.5 py-1.5 text-sm font-medium text-[var(--primary)] transition hover:border-[var(--primary)]/32 hover:text-[var(--title-color)]"
|
||||
>
|
||||
<i class="fas fa-robot text-sm"></i>
|
||||
<span class="hidden xl:inline">{t('nav.ask')}</span>
|
||||
</a>
|
||||
)}
|
||||
|
||||
<div class="flex shrink-0 items-center gap-1 rounded-xl border border-[var(--border-color)] bg-[var(--header-bg)]/80 p-0.5">
|
||||
{localeLinks.map((item) => (
|
||||
<a
|
||||
href={item.href}
|
||||
data-locale-switch={item.locale}
|
||||
class:list={[
|
||||
'rounded-lg px-2.5 py-1.5 text-xs font-semibold transition',
|
||||
item.locale === locale
|
||||
? 'bg-[var(--primary)] text-white shadow-sm'
|
||||
: 'text-[var(--text-secondary)] hover:bg-[var(--header-bg)]'
|
||||
]}
|
||||
aria-current={item.locale === locale ? 'true' : undefined}
|
||||
title={item.label}
|
||||
>
|
||||
{item.shortLabel}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div class="relative shrink-0">
|
||||
<ThemeToggle
|
||||
client:load
|
||||
labels={{
|
||||
toggle: t('header.themeToggle'),
|
||||
system: t('header.themeSystem'),
|
||||
light: t('header.themeLight'),
|
||||
dark: t('header.themeDark'),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{aiEnabled && (
|
||||
<a
|
||||
href="/ask"
|
||||
class="hidden lg:inline-flex items-center gap-2 rounded-xl border border-[var(--primary)]/18 bg-[var(--primary)]/8 px-2.5 py-1.5 text-sm font-medium text-[var(--primary)] transition hover:border-[var(--primary)]/32 hover:text-[var(--title-color)]"
|
||||
>
|
||||
<i class="fas fa-robot text-sm"></i>
|
||||
<span class="hidden xl:inline">{t('nav.ask')}</span>
|
||||
</a>
|
||||
)}
|
||||
|
||||
<div class="hidden lg:flex items-center gap-1 rounded-xl border border-[var(--border-color)] bg-[var(--header-bg)]/80 p-0.5">
|
||||
{localeLinks.map((item) => (
|
||||
<a
|
||||
href={item.href}
|
||||
data-locale-switch={item.locale}
|
||||
class:list={[
|
||||
'rounded-lg px-2.5 py-1.5 text-xs font-semibold transition',
|
||||
item.locale === locale
|
||||
? 'bg-[var(--primary)] text-white shadow-sm'
|
||||
: 'text-[var(--text-secondary)] hover:bg-[var(--header-bg)]'
|
||||
]}
|
||||
aria-current={item.locale === locale ? 'true' : undefined}
|
||||
title={item.label}
|
||||
>
|
||||
{item.shortLabel}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div class="relative shrink-0">
|
||||
<div class="relative shrink-0 lg:hidden">
|
||||
<ThemeToggle
|
||||
client:load
|
||||
labels={{
|
||||
@@ -262,51 +279,53 @@ const currentNavLabel =
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="terminal-toolbar-module items-center gap-3">
|
||||
<div class="flex h-12 w-12 shrink-0 items-center justify-center overflow-hidden rounded-2xl border border-[var(--border-color)] bg-[var(--primary)]/8">
|
||||
<img
|
||||
id="music-cover"
|
||||
src={currentMusicTrack?.coverImageUrl || ''}
|
||||
alt={currentMusicTrack?.title || 'Music cover'}
|
||||
class:list={[
|
||||
'h-full w-full object-cover',
|
||||
!currentMusicTrack?.coverImageUrl && 'hidden'
|
||||
]}
|
||||
/>
|
||||
<i
|
||||
id="music-cover-fallback"
|
||||
class:list={[
|
||||
'fas fa-compact-disc text-base text-[var(--primary)]',
|
||||
currentMusicTrack?.coverImageUrl && 'hidden'
|
||||
]}
|
||||
></i>
|
||||
</div>
|
||||
<div class="min-w-0 flex-1">
|
||||
<div class="terminal-toolbar-label">{t('header.musicPanel')}</div>
|
||||
<div class="mt-1 flex items-center gap-2">
|
||||
<button id="music-prev" class="terminal-toolbar-iconbtn" aria-label="Previous track" disabled={!hasMusicPlaylist}>
|
||||
<i class="fas fa-step-backward text-xs"></i>
|
||||
</button>
|
||||
<button id="music-play" class="terminal-toolbar-iconbtn bg-[var(--primary)]/12 text-[var(--primary)]" style="border-color: color-mix(in oklab, var(--primary) 28%, var(--border-color));" aria-label="Play or pause" disabled={!hasMusicPlaylist}>
|
||||
<i class="fas fa-play text-xs" id="music-play-icon"></i>
|
||||
</button>
|
||||
<button id="music-next" class="terminal-toolbar-iconbtn" aria-label="Next track" disabled={!hasMusicPlaylist}>
|
||||
<i class="fas fa-step-forward text-xs"></i>
|
||||
</button>
|
||||
<button id="music-volume" class="terminal-toolbar-iconbtn" aria-label="Mute or unmute" disabled={!hasMusicPlaylist}>
|
||||
<i class="fas fa-volume-up text-xs"></i>
|
||||
</button>
|
||||
{musicEnabled && (
|
||||
<div class="terminal-toolbar-module items-center gap-3">
|
||||
<div class="flex h-12 w-12 shrink-0 items-center justify-center overflow-hidden rounded-2xl border border-[var(--border-color)] bg-[var(--primary)]/8">
|
||||
<img
|
||||
id="music-cover"
|
||||
src={currentMusicTrack?.coverImageUrl || ''}
|
||||
alt={currentMusicTrack?.title || 'Music cover'}
|
||||
class:list={[
|
||||
'h-full w-full object-cover',
|
||||
!currentMusicTrack?.coverImageUrl && 'hidden'
|
||||
]}
|
||||
/>
|
||||
<i
|
||||
id="music-cover-fallback"
|
||||
class:list={[
|
||||
'fas fa-compact-disc text-base text-[var(--primary)]',
|
||||
currentMusicTrack?.coverImageUrl && 'hidden'
|
||||
]}
|
||||
></i>
|
||||
</div>
|
||||
<div class="mt-2 min-w-0">
|
||||
<p class="truncate text-sm font-semibold text-[var(--title-color)]" id="music-title">
|
||||
{currentMusicTrack?.title || '未配置曲目'}
|
||||
</p>
|
||||
<p class="truncate text-[11px] text-[var(--text-tertiary)]" id="music-artist">
|
||||
{currentMusicTrack?.artist || currentMusicTrack?.album || '等待播放'}
|
||||
</p>
|
||||
<div class="min-w-0 flex-1">
|
||||
<div class="terminal-toolbar-label">{t('header.musicPanel')}</div>
|
||||
<div class="mt-1 flex items-center gap-2">
|
||||
<button id="music-prev" class="terminal-toolbar-iconbtn" aria-label="Previous track" disabled={!hasMusicPlaylist}>
|
||||
<i class="fas fa-step-backward text-xs"></i>
|
||||
</button>
|
||||
<button id="music-play" class="terminal-toolbar-iconbtn bg-[var(--primary)]/12 text-[var(--primary)]" style="border-color: color-mix(in oklab, var(--primary) 28%, var(--border-color));" aria-label="Play or pause" disabled={!hasMusicPlaylist}>
|
||||
<i class="fas fa-play text-xs" id="music-play-icon"></i>
|
||||
</button>
|
||||
<button id="music-next" class="terminal-toolbar-iconbtn" aria-label="Next track" disabled={!hasMusicPlaylist}>
|
||||
<i class="fas fa-step-forward text-xs"></i>
|
||||
</button>
|
||||
<button id="music-volume" class="terminal-toolbar-iconbtn" aria-label="Mute or unmute" disabled={!hasMusicPlaylist}>
|
||||
<i class="fas fa-volume-up text-xs"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="mt-2 min-w-0">
|
||||
<p class="truncate text-sm font-semibold text-[var(--title-color)]" id="music-title">
|
||||
{currentMusicTrack?.title || '未配置曲目'}
|
||||
</p>
|
||||
<p class="truncate text-[11px] text-[var(--text-tertiary)]" id="music-artist">
|
||||
{currentMusicTrack?.artist || currentMusicTrack?.album || '等待播放'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div class="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
|
||||
@@ -320,13 +339,13 @@ const currentNavLabel =
|
||||
: ''
|
||||
]}
|
||||
>
|
||||
<span class="flex items-center gap-3">
|
||||
<span class="flex min-w-0 flex-1 items-center gap-3">
|
||||
<span class="flex h-10 w-10 items-center justify-center rounded-xl border border-[var(--border-color)] bg-[var(--header-bg)]/82 text-[var(--primary)]">
|
||||
<i class={`fas ${item.icon} text-sm`}></i>
|
||||
</span>
|
||||
<span class="min-w-0">
|
||||
<span class="terminal-toolbar-label block">{t('header.navigation')}</span>
|
||||
<span class="mt-1 block text-sm font-semibold text-[var(--title-color)]">{item.text}</span>
|
||||
<span class="mt-1 block truncate text-sm font-semibold text-[var(--title-color)]">{item.text}</span>
|
||||
</span>
|
||||
</span>
|
||||
<i class="fas fa-arrow-right text-[11px] text-[var(--text-tertiary)]"></i>
|
||||
|
||||
Reference in New Issue
Block a user