Skip to content

Commit 939ee9a

Browse files
authored
feat: language selector (#34)
* feat: language selector * refactor: improve comments * refactor: add language selector in topbar
1 parent 4b135a2 commit 939ee9a

File tree

8 files changed

+137
-67
lines changed

8 files changed

+137
-67
lines changed

src/components/ByLogto.astro

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
---
22
import { Icon } from "astro-icon/components";
3-
import SolidA from "./SolidA.astro";
43
---
54

6-
<SolidA
5+
<a
6+
class="solid-button"
77
href="https://logto.io/?ref=auth-wiki"
88
target="_blank"
99
rel="noopener"
@@ -12,10 +12,10 @@ import SolidA from "./SolidA.astro";
1212
<span class="designed-by">Designed by</span>
1313
<Icon name="logto-logo" />
1414
<span>Logto</span>
15-
</SolidA>
15+
</a>
1616

1717
<style>
18-
@media (max-width: 500px) {
18+
@media (max-width: 660px) {
1919
.designed-by {
2020
display: none;
2121
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
---
2+
import { getLocale, getLocaleUrl } from "astro-i18n-aut";
3+
import { localeDisplay } from "../phrases";
4+
5+
type Props = {
6+
class?: string;
7+
};
8+
9+
const locale = getLocale(Astro.url);
10+
const alternateLinks = Object.fromEntries(
11+
Object.keys(localeDisplay).map((locale) => [
12+
locale,
13+
getLocaleUrl(Astro.url.pathname, locale),
14+
]),
15+
);
16+
const { class: className, ...rest } = Astro.props;
17+
---
18+
19+
<astro-language-selector data-links={JSON.stringify(alternateLinks)}>
20+
<select class={className} {...rest}>
21+
{
22+
Object.entries(localeDisplay).map(([value, display]) => (
23+
<option value={value} selected={value === locale}>
24+
{display}
25+
</option>
26+
))
27+
}
28+
</select>
29+
</astro-language-selector>
30+
31+
<script>
32+
// Astro doesn't provide syntax sugar for passing frontmatter variables to scripts, so a custom
33+
// element with data attributes is used to pass data from the frontmatter to the script.
34+
// https://docs.astro.build/en/guides/client-side-scripts/#pass-frontmatter-variables-to-scripts
35+
class AstroLanguageSelector extends HTMLElement {
36+
connectedCallback() {
37+
const select = this.querySelector("select");
38+
const links = JSON.parse(this.dataset.links ?? "{}");
39+
40+
if (select) {
41+
select.addEventListener("change", () => {
42+
const locale = select.value;
43+
const url = links[locale];
44+
window.location.href = url;
45+
});
46+
}
47+
}
48+
}
49+
50+
customElements.define("astro-language-selector", AstroLanguageSelector);
51+
</script>

src/components/ShareButton.astro

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ const { type, title } = Astro.props;
4343
</style>
4444

4545
<script>
46-
// Astro doesn't provide syntax sugar for passing frontmatter variables to scripts.
46+
// Astro doesn't provide syntax sugar for passing frontmatter variables to scripts, so a custom
47+
// element with data attributes is used to pass data from the frontmatter to the script.
4748
// https://docs.astro.build/en/guides/client-side-scripts/#pass-frontmatter-variables-to-scripts
4849
import { buildShareUrlMap } from "../utils/share";
4950

src/components/SolidA.astro

Lines changed: 0 additions & 46 deletions
This file was deleted.

src/components/Topbar.astro

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
import { Icon } from "astro-icon/components";
33
import Logo from "./Logo.astro";
44
import ByLogto from "./ByLogto.astro";
5-
import SolidA from "./SolidA.astro";
65
import { defaultLocale, getLocale } from "astro-i18n-aut";
6+
import LanguageSelector from "./LanguageSelector.astro";
77
88
const locale = getLocale(Astro.url);
99
---
@@ -17,14 +17,16 @@ const locale = getLocale(Astro.url);
1717
<Logo />
1818
</a>
1919
<div class="actions">
20-
<SolidA
20+
<a
21+
class="solid-button"
2122
href="https://github.com/logto-io/auth-wiki"
2223
target="_blank"
2324
rel="noopener"
2425
>
2526
<Icon name="github" />
2627
<span class="github">GitHub</span>
27-
</SolidA>
28+
</a>
29+
<LanguageSelector class="select solid-button" />
2830
<ByLogto />
2931
</div>
3032
</div>
@@ -50,7 +52,18 @@ const locale = getLocale(Astro.url);
5052
display: flex;
5153
gap: 12px;
5254
}
53-
@media (max-width: 500px) {
55+
.select {
56+
border: none;
57+
border-right: 12px solid transparent;
58+
height: 100%;
59+
}
60+
@media (max-width: 810px) {
61+
.topbar a.home :global(svg) {
62+
width: auto;
63+
height: 24px;
64+
}
65+
}
66+
@media (max-width: 600px) {
5467
.topbar .actions {
5568
gap: 8px;
5669
}

src/layouts/Layout.astro

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,4 +159,43 @@ const canonical = new URL(
159159
background-color: var(--shiki-dark-bg) !important;
160160
}
161161
}
162+
163+
/* Reusable styles */
164+
.solid-button {
165+
display: inline-flex;
166+
align-items: center;
167+
gap: 8px;
168+
text-decoration: none;
169+
padding: 8px 12px;
170+
border-radius: 6px;
171+
color: #fff;
172+
background-color: rgba(255, 255, 255, 0.1);
173+
font-size: 14px;
174+
font-weight: 600;
175+
line-height: 20px;
176+
transition: background-color 0.2s ease-in-out;
177+
}
178+
179+
.solid-button:hover {
180+
cursor: pointer;
181+
background-color: rgba(255, 255, 255, 0.18);
182+
}
183+
184+
.solid-button svg {
185+
height: 20px;
186+
width: auto;
187+
margin-inline-end: -2px;
188+
}
189+
@media (max-width: 810px) {
190+
.solid-button {
191+
font-size: 12px;
192+
line-height: 16px;
193+
padding: 6px 10px;
194+
}
195+
196+
.solid-button svg {
197+
width: 16px;
198+
height: 16px;
199+
}
200+
}
162201
</style>

src/pages/[slug].astro

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,10 @@ const phrases = getPhrases(locale);
6767
<div class="background"></div>
6868
<div class="metadata">
6969
<BackgroundCells class="background-cells" />
70-
<Tags data={tags} />
71-
<h1>{title}</h1>
72-
<p class="description">
73-
{description}
74-
</p>
7570
<div class="actions">
76-
<Share title={title} shareText={phrases.general.share} />
71+
<Tags data={tags} />
7772
<a
78-
class="edit"
73+
class="button"
7974
href={`https://github.com/logto-io/auth-wiki/edit/master/src/content/${entry.collection}/${entry.slug}.mdx`}
8075
target="_blank"
8176
rel="noopener"
@@ -84,6 +79,11 @@ const phrases = getPhrases(locale);
8479
<span>{phrases.content.edit_on_github}</span>
8580
</a>
8681
</div>
82+
<h1>{title}</h1>
83+
<p class="description">
84+
{description}
85+
</p>
86+
<Share title={title} shareText={phrases.general.share} />
8787
</div>
8888
</header>
8989
<div class="content">
@@ -175,11 +175,16 @@ const phrases = getPhrases(locale);
175175
justify-content: space-between;
176176
flex-wrap: wrap;
177177
column-gap: 32px;
178+
row-gap: 16px;
179+
}
180+
div.actions select.button {
181+
border: none;
182+
border-right: 12px solid transparent;
178183
}
179-
div.actions a.edit {
184+
div.actions .button {
180185
display: inline-flex;
181186
align-items: center;
182-
gap: 6px;
187+
gap: 8px;
183188
text-decoration: none;
184189
border-radius: 8px;
185190
padding: 6px 10px;
@@ -191,10 +196,11 @@ const phrases = getPhrases(locale);
191196
transition: background-color 0.2s ease-in-out;
192197
text-wrap: nowrap;
193198
}
194-
div.actions a.edit:hover {
199+
div.actions .button:hover {
200+
cursor: pointer;
195201
background-color: rgba(255, 255, 255, 0.2);
196202
}
197-
div.actions a.edit :global(svg) {
203+
div.actions .button :global(svg) {
198204
width: 16px;
199205
height: auto;
200206
}
@@ -385,7 +391,7 @@ const phrases = getPhrases(locale);
385391
div.metadata p.description {
386392
color: rgba(255, 255, 255, 0.7);
387393
}
388-
div.actions a.edit {
394+
div.actions .button {
389395
color: rgba(255, 255, 255, 0.6);
390396
}
391397
div.content {

src/phrases/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ export * from './zh';
44
import { en } from './en';
55
import { zh } from './zh';
66

7+
/** Display names for each locale. */
8+
export const localeDisplay: Readonly<Record<string, string>> = Object.freeze({
9+
en: 'English',
10+
zh: '简体中文',
11+
});
12+
713
export const getPhrases = (locale: string) => {
814
switch (locale) {
915
case 'zh':

0 commit comments

Comments
 (0)