Skip to content

Commit 4944ae4

Browse files
committed
多语言支持
1 parent 079e0ca commit 4944ae4

54 files changed

Lines changed: 581 additions & 23 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/.vitepress/config.mts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { defineConfig } from 'vitepress'
22

33
// https://vitepress.dev/reference/site-config
44
export default defineConfig({
5+
// 默认语言(中文)
6+
lang: 'zh-CN',
57
title: 'Goldfish Scheme',
68
description: '让 Scheme 和 Python 一样易用且实用',
79

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
<script setup lang="ts">
2+
import { useData } from 'vitepress'
3+
4+
const { page, theme } = useData()
5+
6+
// 获取当前路径
7+
const currentPath = page.value.relativePath
8+
9+
// 检查链接是否激活
10+
function isActive(link: string): boolean {
11+
if (!link) return false
12+
const cleanLink = link.replace(/\.md$/, '').replace(/\/$/, '')
13+
const cleanPath = currentPath.replace(/\.md$/, '').replace(/\/$/, '')
14+
return cleanPath === cleanLink || cleanPath.startsWith(cleanLink + '/')
15+
}
16+
17+
// 侧边栏配置类型
18+
interface SidebarItem {
19+
text: string
20+
link?: string
21+
items?: SidebarItem[]
22+
collapsed?: boolean
23+
}
24+
25+
// 获取当前页面的侧边栏配置
26+
function getSidebarConfig(): SidebarItem[] {
27+
const sidebar = theme.value.sidebar
28+
if (!sidebar) return []
29+
30+
// 找到匹配的侧边栏配置
31+
for (const [path, config] of Object.entries(sidebar)) {
32+
const cleanPath = path.replace(/\/$/, '')
33+
if (currentPath.startsWith(cleanPath)) {
34+
return Array.isArray(config) ? config : []
35+
}
36+
}
37+
38+
return []
39+
}
40+
41+
const sidebarItems = getSidebarConfig()
42+
</script>
43+
44+
<template>
45+
<aside class="sidebar">
46+
<nav class="sidebar-nav">
47+
<div v-for="(section, index) in sidebarItems" :key="index" class="sidebar-section">
48+
<!-- 节标题 -->
49+
<h3 v-if="section.text" class="section-title">
50+
{{ section.text }}
51+
</h3>
52+
53+
<!-- 节内链接 -->
54+
<ul v-if="section.items" class="section-items">
55+
<li v-for="item in section.items" :key="item.text" class="section-item">
56+
<a :href="item.link" class="item-link" :class="{ active: isActive(item.link || '') }">
57+
{{ item.text }}
58+
</a>
59+
</li>
60+
</ul>
61+
62+
<!-- 直接链接(无子项) -->
63+
<a
64+
v-else-if="section.link"
65+
:href="section.link"
66+
class="item-link section-link"
67+
:class="{ active: isActive(section.link) }"
68+
>
69+
{{ section.text }}
70+
</a>
71+
</div>
72+
</nav>
73+
</aside>
74+
</template>
75+
76+
<style scoped>
77+
.sidebar {
78+
width: 260px;
79+
flex-shrink: 0;
80+
padding: 1.5rem 0;
81+
border-right: 1px solid #e5e7eb;
82+
background: #fafafa;
83+
overflow-y: auto;
84+
}
85+
86+
.sidebar-nav {
87+
padding: 0 1rem;
88+
}
89+
90+
.sidebar-section {
91+
margin-bottom: 1.5rem;
92+
}
93+
94+
.section-title {
95+
font-size: 0.75rem;
96+
font-weight: 600;
97+
color: #9ca3af;
98+
text-transform: uppercase;
99+
letter-spacing: 0.05em;
100+
margin: 0 0 0.75rem 0;
101+
padding: 0 0.75rem;
102+
}
103+
104+
.section-items {
105+
list-style: none;
106+
margin: 0;
107+
padding: 0;
108+
}
109+
110+
.section-item {
111+
margin: 0.25rem 0;
112+
}
113+
114+
.item-link {
115+
display: block;
116+
padding: 0.5rem 0.75rem;
117+
border-radius: 0.375rem;
118+
color: #4b5563;
119+
text-decoration: none;
120+
font-size: 0.875rem;
121+
line-height: 1.5;
122+
transition: all 0.2s;
123+
}
124+
125+
.item-link:hover {
126+
background: #f3f4f6;
127+
color: #3b82f6;
128+
}
129+
130+
.item-link.active {
131+
background: #eff6ff;
132+
color: #3b82f6;
133+
font-weight: 500;
134+
}
135+
136+
.section-link {
137+
margin: 0 0.75rem;
138+
}
139+
140+
/* 移动端隐藏 */
141+
@media (max-width: 1024px) {
142+
.sidebar {
143+
display: none;
144+
}
145+
}
146+
</style>
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
<script setup lang="ts">
2+
import { ref, onMounted, onUnmounted } from 'vue'
3+
4+
// 目录项类型
5+
interface TocItem {
6+
level: number
7+
text: string
8+
link: string
9+
children?: TocItem[]
10+
}
11+
12+
const headers = ref<TocItem[]>([])
13+
const activeId = ref('')
14+
15+
// 从页面中提取标题
16+
function extractHeaders(): TocItem[] {
17+
if (typeof document === 'undefined') return []
18+
19+
const article = document.querySelector('.vp-doc') || document.querySelector('.page')
20+
if (!article) return []
21+
22+
const elements = article.querySelectorAll('h2, h3, h4')
23+
const result: TocItem[] = []
24+
25+
elements.forEach((el) => {
26+
const id = el.id
27+
const level = parseInt(el.tagName[1])
28+
const text = el.textContent?.replace(/#$/, '').trim() || ''
29+
30+
if (id && text) {
31+
result.push({ level, text, link: `#${id}` })
32+
}
33+
})
34+
35+
return result
36+
}
37+
38+
// 更新活动标题
39+
function updateActiveHeader() {
40+
if (typeof document === 'undefined') return
41+
42+
const article = document.querySelector('.vp-doc') || document.querySelector('.page')
43+
if (!article) return
44+
45+
const elements = article.querySelectorAll('h2, h3, h4')
46+
let current = ''
47+
48+
elements.forEach((el) => {
49+
const rect = el.getBoundingClientRect()
50+
if (rect.top <= 100) {
51+
current = el.id
52+
}
53+
})
54+
55+
if (current) {
56+
activeId.value = current
57+
}
58+
}
59+
60+
let observer: IntersectionObserver | null = null
61+
62+
onMounted(() => {
63+
headers.value = extractHeaders()
64+
65+
// 使用 IntersectionObserver 监听标题
66+
if (typeof document !== 'undefined') {
67+
observer = new IntersectionObserver(
68+
(entries) => {
69+
entries.forEach((entry) => {
70+
if (entry.isIntersecting) {
71+
activeId.value = entry.target.id
72+
}
73+
})
74+
},
75+
{
76+
rootMargin: '-80px 0px -60% 0px',
77+
threshold: 0
78+
}
79+
)
80+
81+
const article = document.querySelector('.vp-doc') || document.querySelector('.page')
82+
if (article) {
83+
article.querySelectorAll('h2, h3, h4').forEach((el) => {
84+
observer?.observe(el)
85+
})
86+
}
87+
}
88+
89+
window.addEventListener('scroll', updateActiveHeader)
90+
})
91+
92+
onUnmounted(() => {
93+
observer?.disconnect()
94+
window.removeEventListener('scroll', updateActiveHeader)
95+
})
96+
</script>
97+
98+
<template>
99+
<aside v-if="headers.length > 0" class="toc">
100+
<nav class="toc-nav">
101+
<h2 class="toc-title">本页导航</h2>
102+
<ul class="toc-list">
103+
<li
104+
v-for="header in headers"
105+
:key="header.link"
106+
class="toc-item"
107+
:class="[`level-${header.level}`, { active: activeId === header.link.slice(1) }]"
108+
>
109+
<a :href="header.link" class="toc-link">
110+
{{ header.text }}
111+
</a>
112+
</li>
113+
</ul>
114+
</nav>
115+
</aside>
116+
</template>
117+
118+
<style scoped>
119+
.toc {
120+
width: 240px;
121+
flex-shrink: 0;
122+
padding: 1.5rem 0;
123+
position: sticky;
124+
top: 4rem;
125+
height: calc(100vh - 4rem);
126+
overflow-y: auto;
127+
}
128+
129+
.toc-nav {
130+
padding: 0 1rem;
131+
}
132+
133+
.toc-title {
134+
font-size: 0.75rem;
135+
font-weight: 600;
136+
color: #9ca3af;
137+
text-transform: uppercase;
138+
letter-spacing: 0.05em;
139+
margin: 0 0 0.75rem 0;
140+
}
141+
142+
.toc-list {
143+
list-style: none;
144+
margin: 0;
145+
padding: 0;
146+
border-left: 1px solid #e5e7eb;
147+
}
148+
149+
.toc-item {
150+
margin: 0;
151+
}
152+
153+
.toc-item.level-2 {
154+
padding-left: 0.75rem;
155+
}
156+
157+
.toc-item.level-3 {
158+
padding-left: 1.5rem;
159+
}
160+
161+
.toc-item.level-4 {
162+
padding-left: 2.25rem;
163+
}
164+
165+
.toc-link {
166+
display: block;
167+
padding: 0.375rem 0;
168+
color: #6b7280;
169+
text-decoration: none;
170+
font-size: 0.8125rem;
171+
line-height: 1.5;
172+
transition: color 0.2s;
173+
border-left: 2px solid transparent;
174+
margin-left: -1px;
175+
}
176+
177+
.toc-link:hover {
178+
color: #3b82f6;
179+
}
180+
181+
.toc-item.active .toc-link {
182+
color: #3b82f6;
183+
font-weight: 500;
184+
border-left-color: #3b82f6;
185+
}
186+
187+
/* 移动端和平板隐藏 */
188+
@media (max-width: 1280px) {
189+
.toc {
190+
display: none;
191+
}
192+
}
193+
</style>

docs/en/index.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
layout: home
3+
4+
hero:
5+
name: Goldfish Scheme
6+
text: Make Scheme as easy as Python
7+
tagline: R7RS-small compatible Scheme interpreter with Python-like versatile standard library
8+
image:
9+
src: /GoldfishScheme-logo.png
10+
alt: Goldfish Scheme Logo
11+
actions:
12+
- theme: brand
13+
text: Get Started
14+
link: /en/guide/getting-started
15+
- theme: alt
16+
text: GitHub
17+
link: https://github.com/MoganLab/goldfish
18+
- theme: alt
19+
text: API Docs
20+
link: /en/api/liii/
21+
22+
features:
23+
- icon: 🎯
24+
title: Simple & Efficient
25+
details: R7RS-small compatible, depends only on S7 Scheme and tbox, small and fast.
26+
- icon: 🐍
27+
title: Python-like
28+
details: Rich standard library similar to Python, including HTTP, JSON, OS, path operations, etc.
29+
- icon: 🤖
30+
title: AI Friendly
31+
details: Clear code structure, AI coding friendly, easy to learn and use.
32+
- icon: 📦
33+
title: Rich Library Support
34+
details: Built-in extensive SRFI implementations and liii extension libraries.
35+
---
36+
37+
<style>
38+
:root {
39+
--vp-home-hero-name-color: transparent;
40+
--vp-home-hero-name-background: -webkit-linear-gradient(120deg, #bd34fe 30%, #41d1ff);
41+
--vp-home-hero-image-background-image: linear-gradient(-45deg, #bd34fe 50%, #47caff 50%);
42+
--vp-home-hero-image-filter: blur(44px);
43+
}
44+
45+
.vp-doc a {
46+
text-decoration: none;
47+
}
48+
</style>

0 commit comments

Comments
 (0)