mirror of
https://github.com/ClovertaTheTrilobita/SanYeCao-blog.git
synced 2026-04-01 17:50:13 +00:00
added locale switch and adjusted css
This commit is contained in:
parent
4c623030ba
commit
80e2e1b156
32 changed files with 3641 additions and 171 deletions
95
build/fontmin.js
Normal file
95
build/fontmin.js
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
import fs from "fs";
|
||||||
|
import path from "path";
|
||||||
|
import Fontmin from "fontmin";
|
||||||
|
|
||||||
|
function getFiles(dir) {
|
||||||
|
const results = [];
|
||||||
|
const list = fs.readdirSync(dir);
|
||||||
|
|
||||||
|
for (const file of list) {
|
||||||
|
const filePath = path.join(dir, file);
|
||||||
|
const stat = fs.statSync(filePath);
|
||||||
|
|
||||||
|
if (stat.isDirectory()) {
|
||||||
|
results.push(...getFiles(filePath));
|
||||||
|
} else {
|
||||||
|
results.push(filePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
function scanDirectory(dir) {
|
||||||
|
let set = new Set();
|
||||||
|
const files = getFiles(dir);
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
const ignoredExtensions = [
|
||||||
|
".ttf",
|
||||||
|
".otf",
|
||||||
|
".woff",
|
||||||
|
".woff2",
|
||||||
|
".eot",
|
||||||
|
".png",
|
||||||
|
".jpg",
|
||||||
|
".jpeg",
|
||||||
|
".webp",
|
||||||
|
".gif",
|
||||||
|
".ico",
|
||||||
|
".pdf",
|
||||||
|
];
|
||||||
|
|
||||||
|
if (ignoredExtensions.some((ext) => file.endsWith(ext))) continue;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const content = fs.readFileSync(file, "utf8");
|
||||||
|
const currentSet = new Set(content);
|
||||||
|
set = new Set([...set, ...currentSet]);
|
||||||
|
} catch {
|
||||||
|
// 跳过二进制等不可读文件
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
function subsetFont(src, text) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const fontmin = new Fontmin()
|
||||||
|
.src(src)
|
||||||
|
.use(
|
||||||
|
Fontmin.glyph({
|
||||||
|
text,
|
||||||
|
hinting: false,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.use(Fontmin.ttf2woff2())
|
||||||
|
.dest("public/fonts/subset");
|
||||||
|
|
||||||
|
fontmin.run((err) => {
|
||||||
|
if (err) return reject(err);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const baseChars =
|
||||||
|
"首页文章标签关于作者评论发布于切换主题,。!?:“”‘’()《》【】、—…·-_/\\'\"()[]{}<>:;.!? ";
|
||||||
|
const scanned = Array.from(scanDirectory("src")).join("");
|
||||||
|
const chars = Array.from(new Set((scanned + baseChars).split(""))).join("");
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
subsetFont("public/fonts/MapleMono-CN-Regular.ttf", chars),
|
||||||
|
subsetFont("public/fonts/MapleMono-CN-Bold.ttf", chars),
|
||||||
|
subsetFont("public/fonts/MapleMono-CN-Italic.ttf", chars),
|
||||||
|
]);
|
||||||
|
|
||||||
|
console.log(`中文子集字体生成完成,共收集 ${chars.length} 个字符`);
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
2988
package-lock.json
generated
2988
package-lock.json
generated
File diff suppressed because it is too large
Load diff
10
package.json
10
package.json
|
|
@ -7,9 +7,10 @@
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "astro dev",
|
"dev": "astro dev",
|
||||||
"build": "astro build",
|
|
||||||
"preview": "astro preview",
|
"preview": "astro preview",
|
||||||
"astro": "astro"
|
"astro": "astro",
|
||||||
|
"subset-font": "node build/fontmin.js",
|
||||||
|
"build": "npm run subset-font && astro build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/rss": "^4.0.17",
|
"@astrojs/rss": "^4.0.17",
|
||||||
|
|
@ -17,6 +18,7 @@
|
||||||
"url": "^0.11.4"
|
"url": "^0.11.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^25.5.0"
|
"@types/node": "^25.5.0",
|
||||||
|
"fontmin": "^1.1.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BIN
public/fonts/MapleMono-CN-Bold.ttf
Normal file
BIN
public/fonts/MapleMono-CN-Bold.ttf
Normal file
Binary file not shown.
BIN
public/fonts/MapleMono-CN-Italic.ttf
Normal file
BIN
public/fonts/MapleMono-CN-Italic.ttf
Normal file
Binary file not shown.
BIN
public/fonts/MapleMono-CN-Regular.ttf
Normal file
BIN
public/fonts/MapleMono-CN-Regular.ttf
Normal file
Binary file not shown.
BIN
public/fonts/MapleMono-Italic.ttf.woff2
Normal file
BIN
public/fonts/MapleMono-Italic.ttf.woff2
Normal file
Binary file not shown.
BIN
public/fonts/subset/MapleMono-CN-Bold.ttf
Normal file
BIN
public/fonts/subset/MapleMono-CN-Bold.ttf
Normal file
Binary file not shown.
BIN
public/fonts/subset/MapleMono-CN-Bold.woff2
Normal file
BIN
public/fonts/subset/MapleMono-CN-Bold.woff2
Normal file
Binary file not shown.
BIN
public/fonts/subset/MapleMono-CN-Italic.ttf
Normal file
BIN
public/fonts/subset/MapleMono-CN-Italic.ttf
Normal file
Binary file not shown.
BIN
public/fonts/subset/MapleMono-CN-Italic.woff2
Normal file
BIN
public/fonts/subset/MapleMono-CN-Italic.woff2
Normal file
Binary file not shown.
BIN
public/fonts/subset/MapleMono-CN-Regular.ttf
Normal file
BIN
public/fonts/subset/MapleMono-CN-Regular.ttf
Normal file
Binary file not shown.
BIN
public/fonts/subset/MapleMono-CN-Regular.woff2
Normal file
BIN
public/fonts/subset/MapleMono-CN-Regular.woff2
Normal file
Binary file not shown.
|
|
@ -1,8 +1,57 @@
|
||||||
---
|
---
|
||||||
const platform = "github";
|
import { getLangFromUrl, getTranslations, type Lang } from "@/i18n";
|
||||||
const username = "ClovertaTheTrilobita";
|
|
||||||
|
const lang = getLangFromUrl(Astro.url);
|
||||||
|
const t = getTranslations(lang);
|
||||||
---
|
---
|
||||||
|
|
||||||
<footer>
|
<footer class="footer">
|
||||||
<p>Learn more about my projects on <a href={`https://www.${platform}.com/${username}`}>{platform}</a>!</p>
|
<p set:html={t.footer.githubIntro} />
|
||||||
</footer>
|
<p set:html={t.footer.repoIntro} />
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.footer {
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding: 1.5rem 0 0;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
opacity: 0.9;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer::before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 12px;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
background: repeating-linear-gradient(
|
||||||
|
-45deg,
|
||||||
|
#e96b6b 0 14px,
|
||||||
|
transparent 14px 28px,
|
||||||
|
#7da2ff 28px 42px,
|
||||||
|
transparent 42px 56px
|
||||||
|
);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer p {
|
||||||
|
margin: 0.4rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer a {
|
||||||
|
color: #7fb3ff;
|
||||||
|
font-weight: 700;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.dark) .footer::before {
|
||||||
|
background: repeating-linear-gradient(
|
||||||
|
-45deg,
|
||||||
|
#ff8a8a 0 14px,
|
||||||
|
transparent 14px 28px,
|
||||||
|
#9ecbff 28px 42px,
|
||||||
|
transparent 42px 56px
|
||||||
|
);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,43 @@
|
||||||
---
|
---
|
||||||
import Navigation from "./Navigation.astro";
|
import Navigation from "./Navigation.astro";
|
||||||
import ThemeIcon from "./ThemeIcon.astro";
|
import ThemeIcon from "./ThemeIcon.astro";
|
||||||
|
import { getLangFromUrl, getTranslations } from "@/i18n";
|
||||||
|
|
||||||
|
const lang = getLangFromUrl(Astro.url);
|
||||||
|
const t = getTranslations(lang);
|
||||||
---
|
---
|
||||||
|
|
||||||
<header>
|
<header class="site-header">
|
||||||
<nav>
|
<div class="theme-icon-wrap">
|
||||||
<h1>SanYeCao Blog</h1>
|
<ThemeIcon />
|
||||||
<div>
|
</div>
|
||||||
<ThemeIcon />
|
|
||||||
</div>
|
<nav class="header-nav">
|
||||||
|
<h1>{t.banner.title}</h1>
|
||||||
<Navigation />
|
<Navigation />
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
div {
|
.site-header {
|
||||||
|
position: relative;
|
||||||
|
padding-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-icon-wrap {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-nav {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-nav h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-style: italic;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,69 @@
|
||||||
---
|
---
|
||||||
import { getLangFromUrl, useTranslations } from "@/i18n";
|
import { getLangFromUrl, getTranslations } from "@/i18n";
|
||||||
|
|
||||||
const langParam = Astro.url.searchParams.get("lang");
|
const lang = getLangFromUrl(Astro.url);
|
||||||
const lang = langParam === "en" ? "en" : "zh";
|
const t = getTranslations(lang);
|
||||||
const t = useTranslations(lang);
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<nav>
|
<nav class="site-nav">
|
||||||
<a href={`/?lang=${lang}`}>{t("nav.home")}</a>
|
<a href={`/${lang}`}>{t.nav.home}</a>
|
||||||
<a href={`/about?lang=${lang}`}>{t("nav.about")}</a>
|
<a href={`/${lang}/about`}>{t.nav.about}</a>
|
||||||
<a href={`/tags?lang=${lang}`}>{t("nav.tags")}</a>
|
<a href={`/${lang}/tags`}>{t.nav.tags}</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.site-nav {
|
||||||
|
display: flex;
|
||||||
|
gap: 1.5rem;
|
||||||
|
align-items: center;
|
||||||
|
margin: 1rem 0;
|
||||||
|
padding-bottom: 3rem;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-nav::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
height: 12px;
|
||||||
|
background: repeating-linear-gradient(
|
||||||
|
-45deg,
|
||||||
|
#e96b6b 0 14px,
|
||||||
|
transparent 14px 28px,
|
||||||
|
#7da2ff 28px 42px,
|
||||||
|
transparent 42px 56px
|
||||||
|
);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.dark) .site-nav::after {
|
||||||
|
background: repeating-linear-gradient(
|
||||||
|
-45deg,
|
||||||
|
#ff8a8a 0 14px,
|
||||||
|
transparent 14px 28px,
|
||||||
|
#9ecbff 28px 42px,
|
||||||
|
transparent 42px 56px
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-nav a {
|
||||||
|
color: black;
|
||||||
|
text-decoration: underline;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-nav a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.dark) .site-nav a {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.dark) .site-nav a:hover {
|
||||||
|
color: #ddd;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,90 @@
|
||||||
---
|
---
|
||||||
|
const pathname = Astro.url.pathname;
|
||||||
|
const segments = pathname.split("/").filter(Boolean);
|
||||||
|
|
||||||
|
const currentLang = segments[0] === "en" ? "en" : "zh";
|
||||||
|
const nextLang = currentLang === "zh" ? "en" : "zh";
|
||||||
|
const switchLabel = currentLang === "zh" ? "EN" : "中文";
|
||||||
|
|
||||||
|
if (segments.length > 0) {
|
||||||
|
segments[0] = nextLang;
|
||||||
|
}
|
||||||
|
|
||||||
|
const switchHref = "/" + segments.join("/");
|
||||||
|
---
|
||||||
|
|
||||||
---
|
<div class="top-actions">
|
||||||
|
<button id="themeToggle" aria-label="Toggle theme">
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
width="30px"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
class="sun"
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M12 17.5a5.5 5.5 0 1 0 0-11 5.5 5.5 0 0 0 0 11zm0 1.5a7 7 0 1 0 0-14 7 7 0 0 0 0 14zm12-7a.8.8 0 0 1-.8.8h-2.4a.8.8 0 0 1 0-1.6h2.4a.8.8 0 0 1 .8.8zM4 12a.8.8 0 0 1-.8.8H.8a.8.8 0 0 1 0-1.6h2.5a.8.8 0 0 1 .8.8zm16.5-8.5a.8.8 0 0 1 0 1l-1.8 1.8a.8.8 0 0 1-1-1l1.7-1.8a.8.8 0 0 1 1 0zM6.3 17.7a.8.8 0 0 1 0 1l-1.7 1.8a.8.8 0 1 1-1-1l1.7-1.8a.8.8 0 0 1 1 0zM12 0a.8.8 0 0 1 .8.8v2.5a.8.8 0 0 1-1.6 0V.8A.8.8 0 0 1 12 0zm0 20a.8.8 0 0 1 .8.8v2.4a.8.8 0 0 1-1.6 0v-2.4a.8.8 0 0 1 .8-.8zM3.5 3.5a.8.8 0 0 1 1 0l1.8 1.8a.8.8 0 1 1-1 1L3.5 4.6a.8.8 0 0 1 0-1zm14.2 14.2a.8.8 0 0 1 1 0l1.8 1.7a.8.8 0 0 1-1 1l-1.8-1.7a.8.8 0 0 1 0-1z"
|
||||||
|
></path>
|
||||||
|
<path
|
||||||
|
class="moon"
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M16.5 6A10.5 10.5 0 0 1 4.7 16.4 8.5 8.5 0 1 0 16.4 4.7l.1 1.3zm-1.7-2a9 9 0 0 1 .2 2 9 9 0 0 1-11 8.8 9.4 9.4 0 0 1-.8-.3c-.4 0-.8.3-.7.7a10 10 0 0 0 .3.8 10 10 0 0 0 9.2 6 10 10 0 0 0 4-19.2 9.7 9.7 0 0 0-.9-.3c-.3-.1-.7.3-.6.7a9 9 0 0 1 .3.8z"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
<button id="themeToggle" aria-label="Toggle theme">
|
<a class="lang-switch" href={switchHref}>
|
||||||
<svg
|
{switchLabel}
|
||||||
aria-hidden="true"
|
</a>
|
||||||
width="30px"
|
</div>
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
class="sun"
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M12 17.5a5.5 5.5 0 1 0 0-11 5.5 5.5 0 0 0 0 11zm0 1.5a7 7 0 1 0 0-14 7 7 0 0 0 0 14zm12-7a.8.8 0 0 1-.8.8h-2.4a.8.8 0 0 1 0-1.6h2.4a.8.8 0 0 1 .8.8zM4 12a.8.8 0 0 1-.8.8H.8a.8.8 0 0 1 0-1.6h2.5a.8.8 0 0 1 .8.8zm16.5-8.5a.8.8 0 0 1 0 1l-1.8 1.8a.8.8 0 0 1-1-1l1.7-1.8a.8.8 0 0 1 1 0zM6.3 17.7a.8.8 0 0 1 0 1l-1.7 1.8a.8.8 0 1 1-1-1l1.7-1.8a.8.8 0 0 1 1 0zM12 0a.8.8 0 0 1 .8.8v2.5a.8.8 0 0 1-1.6 0V.8A.8.8 0 0 1 12 0zm0 20a.8.8 0 0 1 .8.8v2.4a.8.8 0 0 1-1.6 0v-2.4a.8.8 0 0 1 .8-.8zM3.5 3.5a.8.8 0 0 1 1 0l1.8 1.8a.8.8 0 1 1-1 1L3.5 4.6a.8.8 0 0 1 0-1zm14.2 14.2a.8.8 0 0 1 1 0l1.8 1.7a.8.8 0 0 1-1 1l-1.8-1.7a.8.8 0 0 1 0-1z"
|
|
||||||
></path>
|
|
||||||
<path
|
|
||||||
class="moon"
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M16.5 6A10.5 10.5 0 0 1 4.7 16.4 8.5 8.5 0 1 0 16.4 4.7l.1 1.3zm-1.7-2a9 9 0 0 1 .2 2 9 9 0 0 1-11 8.8 9.4 9.4 0 0 1-.8-.3c-.4 0-.8.3-.7.7a10 10 0 0 0 .3.8 10 10 0 0 0 9.2 6 10 10 0 0 0 4-19.2 9.7 9.7 0 0 0-.9-.3c-.3-.1-.7.3-.6.7a9 9 0 0 1 .3.8z"
|
|
||||||
></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.top-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.7rem;
|
||||||
|
}
|
||||||
|
|
||||||
#themeToggle {
|
#themeToggle {
|
||||||
border: 0;
|
border: 0;
|
||||||
background: none;
|
background: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
padding: 0.35rem;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 999px;
|
||||||
|
transition:
|
||||||
|
transform 0.2s ease,
|
||||||
|
opacity 0.2s ease;
|
||||||
|
transform-origin: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#themeToggle:hover {
|
||||||
|
transform: rotate(12deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
#themeToggle:active {
|
||||||
|
transform: rotate(18deg) scale(0.96);
|
||||||
|
}
|
||||||
|
|
||||||
|
.lang-switch {
|
||||||
|
color: black; !important
|
||||||
|
font-weight: 700; !important
|
||||||
|
font-size: 0.95rem; !important
|
||||||
|
text-decoration: none; !important
|
||||||
|
line-height: 1; !important
|
||||||
|
}
|
||||||
|
|
||||||
|
.lang-switch:hover {
|
||||||
|
text-decoration: underline; !important
|
||||||
|
}
|
||||||
|
|
||||||
.sun {
|
.sun {
|
||||||
fill: black;
|
fill: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
.moon {
|
.moon {
|
||||||
fill: transparent;
|
fill: transparent;
|
||||||
}
|
}
|
||||||
|
|
@ -38,9 +92,14 @@
|
||||||
:global(.dark) .sun {
|
:global(.dark) .sun {
|
||||||
fill: transparent;
|
fill: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.dark) .moon {
|
:global(.dark) .moon {
|
||||||
fill: white;
|
fill: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:global(.dark) .lang-switch {
|
||||||
|
color: #eaeaea;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script is:inline>
|
<script is:inline>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
export default {
|
export default {
|
||||||
|
banner: {
|
||||||
|
title: "Cloverta's Blog",
|
||||||
|
subtitle: ""
|
||||||
|
},
|
||||||
nav: {
|
nav: {
|
||||||
home: "Home",
|
home: "Home",
|
||||||
posts: "Posts",
|
posts: "Posts",
|
||||||
|
|
@ -13,4 +17,31 @@ export default {
|
||||||
theme: {
|
theme: {
|
||||||
toggle: "Toggle theme",
|
toggle: "Toggle theme",
|
||||||
},
|
},
|
||||||
|
langSwitcher: "中文",
|
||||||
|
home: {
|
||||||
|
content: ""
|
||||||
|
},
|
||||||
|
about: {
|
||||||
|
title: "About Me, and This Blog",
|
||||||
|
name: "Cloverta",
|
||||||
|
slogan: "Sata Andagi!!!",
|
||||||
|
profilePicture: "https://files.seeusercontent.com/2026/03/24/Ne8b/009BC44B87E00F74351AA6730F8B7353.jpg",
|
||||||
|
content: [
|
||||||
|
"Who am I? Who are you? What even am I?",
|
||||||
|
"Whatever brought you to this page, I'm glad our paths crossed here on the internet.",
|
||||||
|
'This blog is built with <a href="https://astro.build/">Astro</a> and is a fully static frontend website. Compared with third-party commercial blog platforms or WordPress, it is simpler, more efficient, faster, and, at least to my taste, more beautiful.',
|
||||||
|
"At first, I self-hosted WordPress on my server, but it was just too heavy — loading an article of only a few hundred words could still take several seconds. For any programmer anxiously searching online for a solution, that can be quite frustrating. So for a long time, I had wanted to build a static blog from scratch myself.",
|
||||||
|
"As you can see, the functionality of this website may still be incomplete for now. I will continue improving and maintaining it over time.",
|
||||||
|
"The design of this blog was inspired by:",
|
||||||
|
'· <a href="https://ex-tasty.com/">極限風味</a>',
|
||||||
|
'· <a href="https://blog.cloudti.de/">Parsifal\'s Blog</a>',
|
||||||
|
"· And some other websites whose names I have unfortunately forgotten",
|
||||||
|
"Thank you for your ideas and passion!",
|
||||||
|
"In addition, this blog is fully open source. You can find its source code through the link in the footer.",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
footer: {
|
||||||
|
githubIntro: 'See more on <a href="https://www.github.com/ClovertaTheTrilobita">GitHub</a>!',
|
||||||
|
repoIntro: 'This blog is fully open source at <a href="https://www.github.com/ClovertaTheTrilobita/SanYeCao-blog">ClovertaTheTrilobita/SanYeCao-blog</a>'
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import zh from "./zh.ts";
|
import zh from "./zh";
|
||||||
import en from "./en.ts";
|
import en from "./en";
|
||||||
|
|
||||||
export const languages = {
|
export const languages = {
|
||||||
zh,
|
zh,
|
||||||
|
|
@ -10,19 +10,9 @@ export type Lang = keyof typeof languages;
|
||||||
|
|
||||||
export function getLangFromUrl(url: URL): Lang {
|
export function getLangFromUrl(url: URL): Lang {
|
||||||
const lang = url.pathname.split("/")[1];
|
const lang = url.pathname.split("/")[1];
|
||||||
if (lang === "en") return "en";
|
return lang === "en" ? "en" : "zh";
|
||||||
return "zh";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useTranslations(lang: Lang) {
|
export function getTranslations(lang: Lang) {
|
||||||
return function t(path: string) {
|
return languages[lang];
|
||||||
const keys = path.split(".");
|
|
||||||
let current: any = languages[lang];
|
|
||||||
|
|
||||||
for (const key of keys) {
|
|
||||||
current = current?.[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
return current ?? path;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
export default {
|
export default {
|
||||||
|
banner: {
|
||||||
|
title: "Cloverta 的博客",
|
||||||
|
subtitle: ""
|
||||||
|
},
|
||||||
nav: {
|
nav: {
|
||||||
home: "首页",
|
home: "首页",
|
||||||
posts: "文章",
|
posts: "文章",
|
||||||
|
|
@ -13,4 +17,31 @@ export default {
|
||||||
theme: {
|
theme: {
|
||||||
toggle: "切换主题",
|
toggle: "切换主题",
|
||||||
},
|
},
|
||||||
|
langSwitcher: "EN",
|
||||||
|
home: {
|
||||||
|
content: ""
|
||||||
|
},
|
||||||
|
about: {
|
||||||
|
title: "关于我,和这个博客",
|
||||||
|
name: "三叶",
|
||||||
|
slogan: "Sata Andagi!!!",
|
||||||
|
profilePicture: "https://files.seeusercontent.com/2026/03/24/Ne8b/009BC44B87E00F74351AA6730F8B7353.jpg",
|
||||||
|
content: [
|
||||||
|
"我是?你是?我是??",
|
||||||
|
"无论你是因为什么点开了这个页面,都很高兴能在互联网中偶遇你。",
|
||||||
|
'这个博客使用 <a href="https://astro.build/">Astro</a> 构建,是一个完全静态的纯前端网页。相比第三方商业博客平台或 WordPress,它更简洁、更高效、更快速,并且(至少在我的审美里)也更美观。',
|
||||||
|
"最初,我曾在服务器上自建过 WordPress,但它实在太重了——加载短短几百字的文章竟然也要花上好几秒。这对于任何一个火急火燎地上网查解决方案的码农来说,都是相当折磨的事情。因此,我从很久以前就想着自己从头写一个静态博客。",
|
||||||
|
"如你所见,这个网站的功能现在可能还不算完善。我会在接下来的时间里慢慢把它维护好。",
|
||||||
|
"这个博客在设计理念上参考了:",
|
||||||
|
'· <a href="https://ex-tasty.com/">極限風味</a>',
|
||||||
|
'· <a href="https://blog.cloudti.de/">Parsifal\'s Blog</a>',
|
||||||
|
"· 还有一些已经忘记名字的网站",
|
||||||
|
"谢谢你们的想法和热情!",
|
||||||
|
"此外,这个博客完全开源,你可以从页脚的链接处获取它的源代码。",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
footer: {
|
||||||
|
githubIntro: '在 <a href="https://www.github.com/ClovertaTheTrilobita">GitHub</a> 查看更多!',
|
||||||
|
repoIntro: '这个博客完全开源于 <a href="https://www.github.com/ClovertaTheTrilobita/SanYeCao-blog">ClovertaTheTrilobita/SanYeCao-blog</a>'
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -1,11 +1,8 @@
|
||||||
---
|
---
|
||||||
import Footer from "../components/Footer.astro";
|
import Footer from "@/components/Footer.astro";
|
||||||
import Header from "@/components/Header.astro";
|
import Header from "@/components/Header.astro";
|
||||||
import { getLangFromUrl, useTranslations } from "@/i18n";
|
|
||||||
|
|
||||||
const { pageTitle } = Astro.props;
|
const { pageTitle } = Astro.props;
|
||||||
const lang = getLangFromUrl(Astro.url);
|
|
||||||
const t = useTranslations(lang);
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
|
|
|
||||||
96
src/pages/[lang]/about.astro
Normal file
96
src/pages/[lang]/about.astro
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
---
|
||||||
|
import BaseLayout from "@/layouts/BaseLayout.astro";
|
||||||
|
import { getLangFromUrl, getTranslations } from "@/i18n";
|
||||||
|
import "@/styles/global.css";
|
||||||
|
|
||||||
|
export function getStaticPaths() {
|
||||||
|
return [{ params: { lang: "zh" } }, { params: { lang: "en" } }];
|
||||||
|
}
|
||||||
|
|
||||||
|
const lang = getLangFromUrl(Astro.url);
|
||||||
|
const t = getTranslations(lang);
|
||||||
|
const pageTitle = t.about.title;
|
||||||
|
---
|
||||||
|
|
||||||
|
<BaseLayout pageTitle={pageTitle}>
|
||||||
|
<main class="about">
|
||||||
|
<h1>{t.about.title}</h1>
|
||||||
|
|
||||||
|
<div class="intro">
|
||||||
|
<div class="intro-text">
|
||||||
|
<h2 class="name">{t.about.name}</h2>
|
||||||
|
<p class="slogan">{t.about.slogan}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<img
|
||||||
|
src={t.about.profilePicture}
|
||||||
|
alt={t.about.name}
|
||||||
|
width="160"
|
||||||
|
class="avatar"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
{t.about.content.map((line: string) => <p set:html={line} />)}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</BaseLayout>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.about {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2rem 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about h1 {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
gap: 2rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro-text {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
margin: 0 0 0.4rem 0;
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slogan {
|
||||||
|
margin: 0;
|
||||||
|
color: gray;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
display: block;
|
||||||
|
border-radius: 50%;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content p {
|
||||||
|
line-height: 1.8;
|
||||||
|
margin: 1rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content a {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.intro {
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
17
src/pages/[lang]/index.astro
Normal file
17
src/pages/[lang]/index.astro
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
---
|
||||||
|
import BaseLayout from "@/layouts/BaseLayout.astro";
|
||||||
|
import PostList from "@/components/Posts/PostList.astro";
|
||||||
|
import "@/styles/global.css";
|
||||||
|
|
||||||
|
export function getStaticPaths() {
|
||||||
|
return [{ params: { lang: "zh" } }, { params: { lang: "en" } }];
|
||||||
|
}
|
||||||
|
|
||||||
|
const { lang } = Astro.params;
|
||||||
|
const pageTitle = "Homepage";
|
||||||
|
---
|
||||||
|
|
||||||
|
<BaseLayout pageTitle={pageTitle}>
|
||||||
|
<h1>My Astro Site</h1>
|
||||||
|
<PostList />
|
||||||
|
</BaseLayout>
|
||||||
29
src/pages/[lang]/posts/[...slug].astro
Normal file
29
src/pages/[lang]/posts/[...slug].astro
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
---
|
||||||
|
import { getCollection, render } from "astro:content";
|
||||||
|
import MarkdownPostLayout from "@/layouts/MarkdownPostLayout.astro";
|
||||||
|
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
const posts = await getCollection("blog");
|
||||||
|
const langs = ["zh", "en"];
|
||||||
|
|
||||||
|
return langs.flatMap((lang) =>
|
||||||
|
posts.map((post) => ({
|
||||||
|
params: {
|
||||||
|
lang,
|
||||||
|
slug: post.id,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
post,
|
||||||
|
lang,
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { post, lang } = Astro.props;
|
||||||
|
const { Content } = await render(post);
|
||||||
|
---
|
||||||
|
|
||||||
|
<MarkdownPostLayout frontmatter={post.data} lang={lang}>
|
||||||
|
<Content />
|
||||||
|
</MarkdownPostLayout>
|
||||||
40
src/pages/[lang]/tags/[tag].astro
Normal file
40
src/pages/[lang]/tags/[tag].astro
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
---
|
||||||
|
import { getCollection } from "astro:content";
|
||||||
|
import BaseLayout from "@/layouts/BaseLayout.astro";
|
||||||
|
import PostItem from "@/components/Posts/PostItem.astro";
|
||||||
|
import { getTranslations, type Lang } from "@/i18n";
|
||||||
|
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
const allPosts = await getCollection("blog");
|
||||||
|
const uniqueTags = [
|
||||||
|
...new Set(allPosts.map((post) => post.data.tags).flat()),
|
||||||
|
];
|
||||||
|
const langs: Lang[] = ["zh", "en"];
|
||||||
|
|
||||||
|
return langs.flatMap((lang) =>
|
||||||
|
uniqueTags.map((tag) => {
|
||||||
|
const filteredPosts = allPosts.filter((post) =>
|
||||||
|
post.data.tags.includes(tag),
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
params: { lang, tag },
|
||||||
|
props: { posts: filteredPosts, lang },
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { tag } = Astro.params;
|
||||||
|
const { posts, lang } = Astro.props;
|
||||||
|
const t = getTranslations(lang);
|
||||||
|
---
|
||||||
|
|
||||||
|
<BaseLayout pageTitle={String(tag)}>
|
||||||
|
<p>
|
||||||
|
{lang === "zh" ? `带有标签 ${tag} 的文章` : `Posts tagged with ${tag}`}
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
{posts.map((post) => <PostItem post={post} lang={lang} />)}
|
||||||
|
</ul>
|
||||||
|
</BaseLayout>
|
||||||
|
|
@ -1,10 +1,18 @@
|
||||||
---
|
---
|
||||||
import BaseLayout from "@/layouts/BaseLayout.astro";
|
import BaseLayout from "@/layouts/BaseLayout.astro";
|
||||||
import { getCollection } from "astro:content";
|
import { getCollection } from "astro:content";
|
||||||
|
import { getTranslations } from "@/i18n";
|
||||||
import "@/styles/global.css";
|
import "@/styles/global.css";
|
||||||
|
|
||||||
|
export function getStaticPaths() {
|
||||||
|
return [{ params: { lang: "zh" } }, { params: { lang: "en" } }];
|
||||||
|
}
|
||||||
|
|
||||||
|
const { lang } = Astro.params;
|
||||||
|
const t = getTranslations(lang);
|
||||||
const allPosts = await getCollection("blog");
|
const allPosts = await getCollection("blog");
|
||||||
const tags = [...new Set(allPosts.map((post: any) => post.data.tags).flat())];
|
const tags = [...new Set(allPosts.map((post: any) => post.data.tags).flat())];
|
||||||
const pageTitle = "Tag Index";
|
const pageTitle = lang === "zh" ? "标签索引" : "Tag Index";
|
||||||
---
|
---
|
||||||
|
|
||||||
<BaseLayout pageTitle={pageTitle}>
|
<BaseLayout pageTitle={pageTitle}>
|
||||||
|
|
@ -12,12 +20,13 @@ const pageTitle = "Tag Index";
|
||||||
{
|
{
|
||||||
tags.map((tag) => (
|
tags.map((tag) => (
|
||||||
<p class="tag">
|
<p class="tag">
|
||||||
<a href={`/tags/${tag}`}>{tag}</a>
|
<a href={`/${lang}/tags/${tag}`}>{tag}</a>
|
||||||
</p>
|
</p>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</BaseLayout>
|
</BaseLayout>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
a {
|
a {
|
||||||
color: #00539f;
|
color: #00539f;
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
---
|
|
||||||
import BaseLayout from "@/layouts/BaseLayout.astro";
|
|
||||||
import "@/styles/global.css";
|
|
||||||
|
|
||||||
const pageTitle = "About Me";
|
|
||||||
---
|
|
||||||
|
|
||||||
<BaseLayout pageTitle={pageTitle}>
|
|
||||||
<h1>{pageTitle}</h1>
|
|
||||||
<h2>... and my new Astro site!</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
I am working through Astro's introductory tutorial. This is the second page
|
|
||||||
on my website, and it's the first one I built myself!
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
This site will update as I complete more of the tutorial, so keep checking
|
|
||||||
back and see how my journey is going!
|
|
||||||
</p>
|
|
||||||
</BaseLayout>
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
---
|
|
||||||
import BaseLayout from "../layouts/BaseLayout.astro";
|
|
||||||
import PostList from "@/components/Posts/PostList.astro";
|
|
||||||
import "../styles/global.css";
|
|
||||||
|
|
||||||
const pageTitle = "Homepage";
|
|
||||||
|
|
||||||
// Welcome to Astro! Wondering what to do next? Check out the Astro documentation at https://docs.astro.build
|
|
||||||
// Don't want to use any of this? Delete everything in this file, the `assets`, `components`, and `layouts` directories, and start fresh.
|
|
||||||
---
|
|
||||||
|
|
||||||
<BaseLayout pageTitle={pageTitle}>
|
|
||||||
<h1>My Astro Site</h1>
|
|
||||||
<PostList />
|
|
||||||
</BaseLayout>
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
---
|
|
||||||
import { getCollection, render } from "astro:content";
|
|
||||||
import MarkdownPostLayout from "@/layouts/MarkdownPostLayout.astro";
|
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
|
||||||
const posts = await getCollection("blog");
|
|
||||||
return posts.map((post) => ({
|
|
||||||
params: { slug: post.id },
|
|
||||||
props: { post },
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
const { post } = Astro.props;
|
|
||||||
const { Content } = await render(post);
|
|
||||||
---
|
|
||||||
|
|
||||||
<MarkdownPostLayout frontmatter={post.data}>
|
|
||||||
<Content />
|
|
||||||
</MarkdownPostLayout>
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
---
|
|
||||||
import { getCollection } from "astro:content";
|
|
||||||
import BaseLayout from "../../layouts/BaseLayout.astro";
|
|
||||||
import PostItem from "@/components/Posts/PostItem.astro";
|
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
|
||||||
const allPosts = await getCollection("blog");
|
|
||||||
const uniqueTags = [
|
|
||||||
...new Set(allPosts.map((post) => post.data.tags).flat()),
|
|
||||||
];
|
|
||||||
|
|
||||||
return uniqueTags.map((tag) => {
|
|
||||||
const filteredPosts = allPosts.filter((post) =>
|
|
||||||
post.data.tags.includes(tag),
|
|
||||||
);
|
|
||||||
return {
|
|
||||||
params: { tag },
|
|
||||||
props: { posts: filteredPosts },
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const { tag } = Astro.params;
|
|
||||||
const { posts } = Astro.props;
|
|
||||||
---
|
|
||||||
|
|
||||||
<BaseLayout pageTitle={tag}>
|
|
||||||
<p>Posts tagged with {tag}</p>
|
|
||||||
<ul>
|
|
||||||
{
|
|
||||||
posts.map((post) => (
|
|
||||||
<PostItem url={`/posts/${post.id}/`} title={post.data.title} />
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</ul>
|
|
||||||
</BaseLayout>
|
|
||||||
0
src/scripts/main.ts
Normal file
0
src/scripts/main.ts
Normal file
|
|
@ -6,6 +6,14 @@
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Maple Mono";
|
||||||
|
src: url("/fonts/MapleMono-Italic.ttf.woff2") format("woff2");
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: italic;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Maple Mono";
|
font-family: "Maple Mono";
|
||||||
src: url("/fonts/MapleMono-Bold.ttf.woff2") format("woff2");
|
src: url("/fonts/MapleMono-Bold.ttf.woff2") format("woff2");
|
||||||
|
|
@ -14,9 +22,34 @@
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Maple Mono CN";
|
||||||
|
src: url("/fonts/subset/MapleMono-CN-Regular.woff2") format("woff2");
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Maple Mono CN";
|
||||||
|
src: url("/fonts/subset/MapleMono-CN-Italic.woff2") format("woff2");
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: italic;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Maple Mono CN";
|
||||||
|
src: url("/fonts/subset/MapleMono-CN-Bold.woff2") format("woff2");
|
||||||
|
font-weight: 700;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
/* background-color: #f1f5f9; */
|
font-family: "Maple Mono", "Maple Mono CN", monospace;
|
||||||
font-family: "Maple Mono", monospace;
|
background-color: #ffffff;
|
||||||
|
color: #1f2328;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
|
|
@ -24,7 +57,7 @@ body {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 80ch;
|
max-width: 80ch;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
line-height: 1.5;
|
line-height: 1.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
|
|
@ -34,27 +67,46 @@ body {
|
||||||
h1 {
|
h1 {
|
||||||
margin: 1rem 0;
|
margin: 1rem 0;
|
||||||
font-size: 2.5rem;
|
font-size: 2.5rem;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #7fb3ff;
|
||||||
|
font-weight: 700;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover,
|
||||||
|
a:focus {
|
||||||
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
html.dark {
|
html.dark {
|
||||||
background-color: #0d0950;
|
background-color: #1e1e1e;
|
||||||
color: #fff;
|
color: #e6e6e6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark .menu {
|
.dark .menu {
|
||||||
background-color: #fff;
|
background-color: #2a2a2a;
|
||||||
color: #000;
|
color: #e6e6e6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .nav-links a {
|
||||||
|
color: #9ecbff;
|
||||||
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark .nav-links a:hover,
|
.dark .nav-links a:hover,
|
||||||
.dark .nav-links a:focus {
|
.dark .nav-links a:focus {
|
||||||
color: #0d0950;
|
color: #c2deff;
|
||||||
}
|
|
||||||
|
|
||||||
.dark .nav-links a {
|
|
||||||
color: #fff;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark a {
|
.dark a {
|
||||||
color: #ff9776;
|
color: #9ecbff;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark a:hover,
|
||||||
|
.dark a:focus {
|
||||||
|
color: #c2deff;
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue