Skip to content

Commit 4009c58

Browse files
yijun-leeminsubb13
andauthored
Feat/lang button (#88)
* Docs: Added Commutative Ring.md, Division Ring.md and Field.md In Basic Algebra, to describe field, added commutative ring and division ring * fix typo * Modify Basic Algebra.md * feat: reposition language selection button for better accessibility --------- Co-authored-by: MinseopChoi <minsubb13@gmail.com>
1 parent cc5eef1 commit 4009c58

6 files changed

Lines changed: 100 additions & 129 deletions

File tree

content/Basic Algebra/Basic Algebra.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
- [[Subgroup]]
88
- [[Cyclic Subgroup]]
99
- [[Ring]]
10+
- [[Division Ring]]
11+
- [[Commutative Ring]]
1012
- [[Binary Relation]]
1113
- [[Equivalence Relation]]
1214
- [[Quotient Ring]]

package-lock.json

Lines changed: 21 additions & 31 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

quartz.layout.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ export const defaultContentPageLayout: PageLayout = {
2727
Component.MobileOnly(Component.Spacer()),
2828
Component.Search(),
2929
Component.Darkmode(),
30+
Component.Language(),
3031
Component.DesktopOnly(Component.Explorer()),
3132
],
3233
right: [
33-
Component.Language(),
3434
Component.Graph(),
3535
Component.DesktopOnly(Component.TableOfContents()),
3636
Component.Backlinks(),
@@ -45,6 +45,7 @@ export const defaultListPageLayout: PageLayout = {
4545
Component.MobileOnly(Component.Spacer()),
4646
Component.Search(),
4747
Component.Darkmode(),
48+
Component.Language(),
4849
Component.DesktopOnly(Component.Explorer()),
4950
],
5051
right: [],

quartz/components/Language.tsx

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,31 @@
44
import languageScript from "./scripts/language.inline"
55
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
66
import languageStyle from "./styles/language.scss"
7-
8-
const languages = [
9-
{ code: 'en', name: 'English' },
10-
{ code: 'ko', name: 'Korean' },
11-
{ code: 'ja', name: 'Japanese' },
12-
{ code: 'zh', name: 'Chinese' },
13-
{ code: 'es', name: 'Spanish' },
14-
{ code: 'fr', name: 'French' }
15-
];
7+
import { classNames } from "../util/lang"
168

179
const Language: QuartzComponent = ({ displayClass, cfg }: QuartzComponentProps) => {
10+
const currentLang = typeof window !== 'undefined' ? localStorage.getItem('lang') || 'en' : 'en'
11+
1812
return (
19-
<div class="language-selector">
20-
<label for="language-select">Language: </label>
21-
<select id="language-select">
22-
{languages.map(language => (
23-
<option value={language.code} key={language.code}>
24-
{language.name}
25-
</option>
26-
))}
27-
</select>
13+
<div class={classNames(displayClass, "language-selector")}>
14+
<button
15+
class={`lang-button ${currentLang === 'en' ? 'active' : ''}`}
16+
data-lang="en"
17+
aria-label="Switch to English"
18+
>
19+
En
20+
</button>
21+
<button
22+
class={`lang-button ${currentLang === 'ko' ? 'active' : ''}`}
23+
data-lang="ko"
24+
aria-label="한국어로 전환"
25+
>
26+
Ko
27+
</button>
2828
</div>
2929
)
3030
}
3131

32-
Language.beforeDOMLoaded = languageScript;
33-
Language.css = languageStyle;
32+
Language.beforeDOMLoaded = languageScript
33+
Language.css = languageStyle
3434
export default (() => Language) satisfies QuartzComponentConstructor

quartz/components/scripts/language.inline.ts

Lines changed: 42 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,59 @@
1-
const userLang = navigator.language.startsWith("ko")
2-
? "ko"
3-
: navigator.language.startsWith("ja")
4-
? "ja"
5-
: navigator.language.startsWith("zh")
6-
? "zh"
7-
: navigator.language.startsWith("es")
8-
? "es"
9-
: navigator.language.startsWith("fr")
10-
? "fr"
11-
: "en"
1+
const userLang = navigator.language.split('-')[0]
2+
const currentLang = localStorage.getItem('lang') || userLang
123

13-
const currentLang = localStorage.getItem("lang") ?? userLang
14-
document.documentElement.setAttribute("lang", currentLang)
15-
16-
const emitLangChangeEvent = (lang: string) => {
17-
const event = new CustomEvent("langchange", {
18-
detail: { lang },
19-
})
20-
document.dispatchEvent(event)
4+
function getCurrentPathWithoutLang() {
5+
const path = window.location.pathname
6+
const parts = path.split('/')
7+
if (parts[1] === 'i18n') {
8+
parts.splice(1, 2)
9+
}
10+
return parts.join('/').replace(/^\/+/, '')
2111
}
2212

23-
const getCurrentPathWithoutLang = () => {
24-
const path = window.location.pathname
25-
const pathParts = path.split("/").filter((part) => part)
26-
27-
if (pathParts[0] === "i18n") {
28-
pathParts.splice(0, 2)
29-
}
30-
return pathParts.join("/")
13+
function navigateToUrl(url: string) {
14+
window.location.href = url
3115
}
3216

33-
const navigateToUrl = async (url) => {
34-
try {
35-
const response = await fetch(url, { method: "HEAD" })
36-
if (response.status === 404) {
37-
window.location.href = "/translate"
38-
} else {
39-
window.location.href = url
40-
}
41-
} catch (error) {
42-
console.error("Failed to check URL status:", error)
43-
window.location.href = "/translate"
44-
}
17+
function emitLangChangeEvent(lang: string) {
18+
const event = new CustomEvent('langchange', { detail: { lang } })
19+
document.dispatchEvent(event)
4520
}
4621

4722
document.addEventListener("nav", () => {
48-
const switchLang = async (e: Event) => {
49-
const newLang = (e.target as HTMLSelectElement)?.value
50-
document.documentElement.setAttribute("lang", newLang)
51-
localStorage.setItem("lang", newLang)
52-
emitLangChangeEvent(newLang)
23+
const switchLang = async (e: Event) => {
24+
const button = e.target as HTMLButtonElement
25+
const newLang = button.dataset.lang
26+
if (!newLang) return
5327

54-
const currentPath = getCurrentPathWithoutLang()
55-
const newUrl = newLang === "en" ? `/${currentPath}` : `/i18n/${newLang}/${currentPath}`
28+
document.documentElement.setAttribute("lang", newLang)
29+
localStorage.setItem("lang", newLang)
30+
emitLangChangeEvent(newLang)
5631

57-
await navigateToUrl(newUrl)
58-
}
32+
const currentPath = getCurrentPathWithoutLang()
33+
const newUrl = newLang === "en" ? `/${currentPath}` : `/i18n/${newLang}/${currentPath}`
5934

60-
const langSelect = document.querySelector("#language-select") as HTMLSelectElement
61-
langSelect.addEventListener("change", switchLang)
62-
window.addCleanup(() => langSelect.removeEventListener("change", switchLang))
63-
if (currentLang) {
64-
langSelect.value = currentLang
65-
}
35+
await navigateToUrl(newUrl)
36+
}
37+
38+
const langButtons = document.querySelectorAll(".lang-button")
39+
langButtons.forEach(button => {
40+
button.addEventListener("click", switchLang)
41+
window.addCleanup(() => button.removeEventListener("click", switchLang))
42+
})
6643
})
6744

6845
document.addEventListener("DOMContentLoaded", () => {
69-
const lang = localStorage.getItem("lang") ?? userLang
70-
document.documentElement.setAttribute("lang", lang)
71-
emitLangChangeEvent(lang)
46+
const lang = localStorage.getItem("lang") ?? userLang
47+
document.documentElement.setAttribute("lang", lang)
48+
emitLangChangeEvent(lang)
49+
50+
// Update active button state
51+
const langButtons = document.querySelectorAll(".lang-button")
52+
langButtons.forEach(button => {
53+
if (button instanceof HTMLButtonElement) {
54+
button.classList.toggle('active', button.dataset.lang === lang)
55+
}
56+
})
7257
})
7358

7459
document.addEventListener("langchange", (event) => {
Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,29 @@
11
@use "../../styles/variables.scss" as *;
22

33
.language-selector {
4-
margin: 10px 0;
54
display: flex;
65
align-items: center;
6+
gap: 0.5rem;
7+
margin: 0;
78

8-
& label {
9-
margin-right: 10px;
10-
font-family: var(--headerFont);
11-
font-size: 1rem;
9+
.lang-button {
10+
padding: 0.3rem 0.6rem;
11+
font-size: 0.9rem;
1212
color: var(--dark);
13-
font-weight: $semiBoldWeight;
14-
}
15-
16-
& select {
17-
padding: 8px 12px;
18-
font-size: 1rem;
19-
color: var(--dark);
20-
background-color: var(--background);
21-
border: 1px solid var(--secondary);
13+
background-color: var(--light);
14+
border: 1px solid var(--lightgray);
2215
border-radius: 4px;
2316
cursor: pointer;
24-
transition: border-color 0.3s ease, box-shadow 0.3s ease;
17+
transition: all 0.2s ease;
2518

2619
&:hover {
27-
border-color: var(--tertiary);
20+
background-color: var(--lightgray);
2821
}
2922

30-
&:focus {
31-
outline: none;
32-
border-color: var(--tertiary);
33-
box-shadow: 0 0 0 3px rgba(var(--tertiary-rgb), 0.2);
23+
&.active {
24+
background-color: var(--secondary);
25+
color: var(--light);
26+
border-color: var(--secondary);
3427
}
3528
}
3629
}

0 commit comments

Comments
 (0)