Skip to content

Commit 2ed390c

Browse files
childrentimeclaude
andcommitted
feat: add promotional banner for Chinese locale pages
- Blue-purple gradient banner linking to frontend interview course - Only visible on zh-Hans/zh-Hant pages, hidden on English - Dismissible per session via sessionStorage - WCAG AA compliant contrast, keyboard accessible - Responsive layout adjustments for mobile Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 93587d8 commit 2ed390c

3 files changed

Lines changed: 143 additions & 6 deletions

File tree

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
---
2+
import { type Locale } from '../i18n/translations'
3+
4+
interface Props {
5+
locale?: Locale
6+
}
7+
8+
const { locale = 'en' } = Astro.props
9+
10+
const showBanner = locale === 'zh-Hans' || locale === 'zh-Hant'
11+
12+
const text = locale === 'zh-Hant'
13+
? '前端面試秘籍 — 系統化面試準備課程'
14+
: '前端面试秘籍 — 系统化面试准备课程'
15+
16+
const cta = '立即查看'
17+
---
18+
19+
{showBanner && (
20+
<div class="top-banner" id="top-banner">
21+
<a href="https://jingtongit.com/courses/%E5%89%8D%E7%AB%AF%E9%9D%A2%E8%AF%95%E7%A7%98%E7%B1%8D" target="_blank" rel="noopener">
22+
<span class="top-banner-text">{text}</span>
23+
<span class="top-banner-cta">{cta} &rarr;</span>
24+
</a>
25+
<button class="top-banner-close" id="top-banner-close" aria-label="关闭">&times;</button>
26+
</div>
27+
)}
28+
29+
<style>
30+
.top-banner {
31+
position: fixed;
32+
top: 0;
33+
left: 0;
34+
right: 0;
35+
height: var(--banner-h);
36+
display: flex;
37+
align-items: center;
38+
justify-content: center;
39+
background: linear-gradient(90deg, #1d4ed8, #4338ca, #6d28d9);
40+
color: #fff;
41+
font-size: 0.82rem;
42+
z-index: 101;
43+
}
44+
.top-banner a {
45+
color: #fff;
46+
text-decoration: none;
47+
display: flex;
48+
align-items: center;
49+
gap: 8px;
50+
}
51+
.top-banner a:hover .top-banner-cta {
52+
background: rgba(255,255,255,0.3);
53+
}
54+
.top-banner a:focus-visible {
55+
outline: 2px solid #fff;
56+
outline-offset: 2px;
57+
border-radius: 4px;
58+
}
59+
.top-banner-text {
60+
font-weight: 500;
61+
}
62+
.top-banner-cta {
63+
font-weight: 700;
64+
background: rgba(255,255,255,0.15);
65+
padding: 2px 10px;
66+
border-radius: 4px;
67+
font-size: 0.78rem;
68+
transition: background 0.15s;
69+
}
70+
.top-banner-close {
71+
position: absolute;
72+
right: 8px;
73+
top: 50%;
74+
transform: translateY(-50%);
75+
background: none;
76+
border: none;
77+
color: rgba(255,255,255,0.7);
78+
font-size: 1.1rem;
79+
cursor: pointer;
80+
min-width: 36px;
81+
min-height: 36px;
82+
display: flex;
83+
align-items: center;
84+
justify-content: center;
85+
border-radius: 4px;
86+
}
87+
.top-banner-close:hover {
88+
color: #fff;
89+
background: rgba(255,255,255,0.1);
90+
}
91+
.top-banner-close:focus-visible {
92+
outline: 2px solid #fff;
93+
outline-offset: -2px;
94+
}
95+
.top-banner.hidden {
96+
display: none;
97+
}
98+
99+
@media (max-width: 480px) {
100+
.top-banner {
101+
font-size: 0.74rem;
102+
padding: 0 40px 0 8px;
103+
}
104+
.top-banner-cta {
105+
font-size: 0.7rem;
106+
padding: 2px 6px;
107+
}
108+
}
109+
</style>
110+
111+
<script is:inline>
112+
(function() {
113+
if (sessionStorage.getItem('banner-closed')) {
114+
var banner = document.getElementById('top-banner');
115+
if (banner) {
116+
banner.classList.add('hidden');
117+
document.documentElement.style.setProperty('--banner-h', '0px');
118+
}
119+
}
120+
document.getElementById('top-banner-close')?.addEventListener('click', function() {
121+
var banner = document.getElementById('top-banner');
122+
if (banner) {
123+
banner.classList.add('hidden');
124+
document.documentElement.style.setProperty('--banner-h', '0px');
125+
sessionStorage.setItem('banner-closed', '1');
126+
}
127+
});
128+
})();
129+
</script>

packages/website-astro/src/layouts/BaseLayout.astro

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
import '../styles/global.css'
3+
import Banner from '../components/Banner.astro'
34
45
import type { Locale } from '../i18n/translations'
56
@@ -174,6 +175,11 @@ const structuredData = {
174175
(function(){
175176
const t = localStorage.getItem('theme') || (matchMedia('(prefers-color-scheme:dark)').matches ? 'dark' : 'light');
176177
document.documentElement.setAttribute('data-theme', t);
178+
var p = window.location.pathname;
179+
var isCN = p.startsWith('/zh-Hans') || p.startsWith('/zh-Hant');
180+
if (!isCN || sessionStorage.getItem('banner-closed')) {
181+
document.documentElement.style.setProperty('--banner-h', '0px');
182+
}
177183
})();
178184
</script>
179185
<link rel="preconnect" href="https://fonts.googleapis.com" />
@@ -185,6 +191,7 @@ const structuredData = {
185191
<noscript><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@docsearch/css@3" /></noscript>
186192
</head>
187193
<body>
194+
<Banner locale={locale} />
188195
<slot />
189196
<script is:inline src="https://cdn.jsdelivr.net/npm/@docsearch/js@3"></script>
190197
<script is:inline>

packages/website-astro/src/styles/global.css

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
/* Sidebar */
3232
--sidebar-w: 260px;
3333
--navbar-h: 56px;
34+
--banner-h: 36px;
3435

3536
/* Spacing (4pt grid) */
3637
--sp-1: 4px;
@@ -79,7 +80,7 @@ html {
7980
-webkit-font-smoothing: antialiased;
8081
text-rendering: optimizeLegibility;
8182
scroll-behavior: smooth;
82-
scroll-padding-top: calc(var(--navbar-h) + 24px);
83+
scroll-padding-top: calc(var(--navbar-h) + var(--banner-h) + 24px);
8384
}
8485

8586
body {
@@ -98,7 +99,7 @@ a:hover {
9899
/* --- Navbar --- */
99100
.navbar {
100101
position: fixed;
101-
top: 0;
102+
top: var(--banner-h);
102103
left: 0;
103104
right: 0;
104105
height: var(--navbar-h);
@@ -140,15 +141,15 @@ a:hover {
140141

141142
/* --- Layout --- */
142143
.page-shell {
143-
padding-top: var(--navbar-h);
144+
padding-top: calc(var(--navbar-h) + var(--banner-h));
144145
display: flex;
145146
min-height: 100dvh;
146147
}
147148

148149
/* --- Sidebar --- */
149150
.sidebar {
150151
position: fixed;
151-
top: var(--navbar-h);
152+
top: calc(var(--navbar-h) + var(--banner-h));
152153
left: 0;
153154
bottom: 0;
154155
width: var(--sidebar-w);
@@ -229,10 +230,10 @@ a:hover {
229230
/* --- Table of Contents (right sidebar) --- */
230231
.toc {
231232
position: sticky;
232-
top: var(--navbar-h);
233+
top: calc(var(--navbar-h) + var(--banner-h));
233234
flex-shrink: 0;
234235
width: 220px;
235-
height: calc(100dvh - var(--navbar-h));
236+
height: calc(100dvh - var(--navbar-h) - var(--banner-h));
236237
overflow-y: auto;
237238
padding: var(--sp-8) var(--sp-5) var(--sp-8) var(--sp-4);
238239
font-size: 0.8rem;

0 commit comments

Comments
 (0)