Skip to content

Commit e7a1a42

Browse files
feat: refactor trust navbar responsiveness (#106)
1 parent 076b553 commit e7a1a42

File tree

9 files changed

+407
-870
lines changed

9 files changed

+407
-870
lines changed

src/components/TrustTopbar.astro

Lines changed: 338 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,338 @@
1+
---
2+
type PageKey = 'trust' | 'threatmodel';
3+
type Locale = 'en' | 'zh-cn' | 'ko' | 'ja';
4+
5+
interface LanguageLink {
6+
label: string;
7+
trust: string;
8+
threatmodel: string;
9+
}
10+
11+
interface Props {
12+
activePage: PageKey;
13+
locale: Locale;
14+
wide?: boolean;
15+
labels: {
16+
trust: string;
17+
threatModel: string;
18+
};
19+
langLinks: Record<Locale, LanguageLink>;
20+
}
21+
22+
const { activePage, locale, wide = false, labels, langLinks } = Astro.props;
23+
24+
const languageOrder: Locale[] = ['en', 'zh-cn', 'ko', 'ja'];
25+
const currentLinks = langLinks[locale];
26+
const currentLanguageLabel = langLinks[locale].label;
27+
const languageEntries = languageOrder.map((language) => ({
28+
code: language,
29+
href: langLinks[language][activePage],
30+
label: langLinks[language].label,
31+
isActive: language === locale,
32+
}));
33+
---
34+
35+
<nav class="trust-topbar" aria-label="Trust site">
36+
<div class:list={['trust-topbar-inner', { wide }]}>
37+
<a href="https://openclaw.ai" class="trust-topbar-brand">
38+
<img src="/openclaw-logo-text-dark.png" alt="OpenClaw" />
39+
</a>
40+
41+
<div class="trust-topbar-nav">
42+
<div class="trust-topbar-tabs">
43+
<a
44+
href={currentLinks.trust}
45+
class:list={['trust-topbar-link', { active: activePage === 'trust' }]}
46+
aria-current={activePage === 'trust' ? 'page' : undefined}
47+
>
48+
{labels.trust}
49+
</a>
50+
<a
51+
href={currentLinks.threatmodel}
52+
class:list={['trust-topbar-link', { active: activePage === 'threatmodel' }]}
53+
aria-current={activePage === 'threatmodel' ? 'page' : undefined}
54+
>
55+
{labels.threatModel}
56+
</a>
57+
</div>
58+
59+
<div class="trust-lang-switcher" aria-label="Languages">
60+
{languageEntries.map((language) => (
61+
<a
62+
href={language.href}
63+
class:list={['trust-lang-link', { active: language.isActive }]}
64+
aria-current={language.isActive ? 'page' : undefined}
65+
>
66+
{language.label}
67+
</a>
68+
))}
69+
</div>
70+
71+
<label class="trust-lang-select-wrap">
72+
<span class="sr-only">Language</span>
73+
<select
74+
class="trust-lang-select"
75+
aria-label="Language"
76+
onchange="if (this.value) window.location.href = this.value"
77+
>
78+
{languageEntries.map((language) => (
79+
<option
80+
value={language.href}
81+
selected={language.isActive}
82+
>
83+
{language.label}
84+
</option>
85+
))}
86+
</select>
87+
<span class="trust-lang-select-label">{currentLanguageLabel}</span>
88+
<span class="trust-lang-select-icon" aria-hidden="true">▾</span>
89+
</label>
90+
</div>
91+
</div>
92+
</nav>
93+
94+
<style>
95+
.sr-only {
96+
position: absolute;
97+
width: 1px;
98+
height: 1px;
99+
padding: 0;
100+
margin: -1px;
101+
overflow: hidden;
102+
clip: rect(0, 0, 0, 0);
103+
white-space: nowrap;
104+
border: 0;
105+
}
106+
107+
.trust-topbar {
108+
position: sticky;
109+
top: 0;
110+
z-index: 100;
111+
background: var(--bg);
112+
border-bottom: 1px solid var(--gray-200);
113+
}
114+
115+
.trust-topbar-inner {
116+
max-width: 720px;
117+
margin: 0 auto;
118+
padding: 0 24px;
119+
min-height: 52px;
120+
display: flex;
121+
align-items: center;
122+
justify-content: space-between;
123+
gap: 16px;
124+
}
125+
126+
.trust-topbar-inner.wide {
127+
max-width: 1800px;
128+
}
129+
130+
.trust-topbar-brand {
131+
display: flex;
132+
align-items: center;
133+
text-decoration: none;
134+
color: var(--gray-900);
135+
flex-shrink: 0;
136+
}
137+
138+
.trust-topbar-brand:hover {
139+
color: var(--gray-900);
140+
}
141+
142+
.trust-topbar-brand img {
143+
height: 28px;
144+
width: auto;
145+
display: block;
146+
}
147+
148+
.trust-topbar-nav {
149+
display: flex;
150+
align-items: center;
151+
flex-wrap: nowrap;
152+
gap: 12px;
153+
min-width: 0;
154+
}
155+
156+
.trust-topbar-tabs {
157+
display: flex;
158+
align-items: center;
159+
flex-wrap: nowrap;
160+
gap: 4px;
161+
min-width: 0;
162+
flex: 0 1 auto;
163+
}
164+
165+
.trust-topbar-link {
166+
display: inline-flex;
167+
align-items: center;
168+
justify-content: center;
169+
min-width: 0;
170+
padding: 6px 14px;
171+
border-radius: 8px;
172+
font-family: var(--heading);
173+
font-size: 14px;
174+
font-weight: 500;
175+
color: var(--gray-500);
176+
transition: color 0.15s, background 0.15s;
177+
text-align: center;
178+
}
179+
180+
.trust-topbar-link:hover {
181+
color: var(--gray-900);
182+
background: var(--gray-50);
183+
}
184+
185+
.trust-topbar-link.active {
186+
color: var(--primary);
187+
font-weight: 600;
188+
}
189+
190+
.trust-lang-switcher {
191+
display: flex;
192+
align-items: center;
193+
flex-wrap: wrap;
194+
gap: 2px;
195+
margin-left: 8px;
196+
padding-left: 10px;
197+
border-left: 1px solid var(--gray-200);
198+
}
199+
200+
.trust-lang-link {
201+
padding: 4px 8px;
202+
border-radius: 6px;
203+
font-family: var(--heading);
204+
font-size: 12px;
205+
font-weight: 500;
206+
color: var(--gray-400);
207+
transition: color 0.15s, background 0.15s;
208+
}
209+
210+
.trust-lang-link:hover {
211+
color: var(--gray-900);
212+
background: var(--gray-50);
213+
}
214+
215+
.trust-lang-link.active {
216+
color: var(--primary);
217+
font-weight: 600;
218+
}
219+
220+
.trust-lang-select-wrap {
221+
display: none;
222+
position: relative;
223+
flex: 0 0 86px;
224+
min-width: 86px;
225+
}
226+
227+
.trust-lang-select {
228+
position: absolute;
229+
inset: 0;
230+
width: 100%;
231+
height: 100%;
232+
opacity: 0;
233+
cursor: pointer;
234+
}
235+
236+
.trust-lang-select-label {
237+
display: inline-flex;
238+
align-items: center;
239+
width: 100%;
240+
min-height: 34px;
241+
padding: 7px 28px 7px 10px;
242+
border: 1px solid var(--gray-200);
243+
border-radius: 8px;
244+
font-family: var(--heading);
245+
font-size: 12px;
246+
font-weight: 600;
247+
color: var(--primary);
248+
background: var(--bg);
249+
}
250+
251+
.trust-lang-select-icon {
252+
position: absolute;
253+
right: 10px;
254+
top: 50%;
255+
transform: translateY(-50%);
256+
color: var(--gray-400);
257+
pointer-events: none;
258+
font-size: 10px;
259+
}
260+
261+
@media (max-width: 820px) {
262+
.trust-topbar-inner {
263+
padding: 10px 16px;
264+
min-height: 52px;
265+
gap: 8px;
266+
}
267+
268+
.trust-topbar-brand img {
269+
height: 24px;
270+
}
271+
272+
.trust-topbar-nav {
273+
flex: 1 1 auto;
274+
justify-content: flex-end;
275+
gap: 6px;
276+
}
277+
278+
.trust-topbar-tabs {
279+
flex: 0 1 auto;
280+
gap: 2px;
281+
}
282+
283+
.trust-topbar-link {
284+
flex: 0 1 auto;
285+
min-width: 0;
286+
padding: 8px 4px;
287+
font-size: 12px;
288+
white-space: nowrap;
289+
overflow: hidden;
290+
text-overflow: ellipsis;
291+
}
292+
293+
.trust-lang-switcher {
294+
display: none;
295+
}
296+
297+
.trust-lang-select-wrap {
298+
display: block;
299+
flex: 0 0 80px;
300+
min-width: 80px;
301+
}
302+
}
303+
304+
@media (max-width: 380px) {
305+
.trust-topbar-inner {
306+
padding: 10px 12px;
307+
gap: 6px;
308+
}
309+
310+
.trust-topbar-brand img {
311+
height: 20px;
312+
}
313+
314+
.trust-topbar-nav {
315+
gap: 4px;
316+
}
317+
318+
.trust-topbar-link {
319+
font-size: 11px;
320+
padding: 8px 2px;
321+
}
322+
323+
.trust-lang-select-wrap {
324+
flex-basis: 72px;
325+
min-width: 72px;
326+
}
327+
328+
.trust-lang-select-label {
329+
min-height: 32px;
330+
padding: 6px 24px 6px 8px;
331+
font-size: 11px;
332+
}
333+
334+
.trust-lang-select-icon {
335+
right: 8px;
336+
}
337+
}
338+
</style>

0 commit comments

Comments
 (0)