docmk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/pdf/SKILL.md +89 -0
- package/.claude/skills/web-scraping/SKILL.md +78 -0
- package/CLAUDE.md +90 -0
- package/bin/docmk.js +3 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +636 -0
- package/dist/index.js.map +1 -0
- package/final-site/assets/main-B4orIFxK.css +1 -0
- package/final-site/assets/main-CSoKXua6.js +25 -0
- package/final-site/favicon.svg +4 -0
- package/final-site/index.html +26 -0
- package/final-site/robots.txt +4 -0
- package/final-site/sitemap.xml +14 -0
- package/my-docs/api/README.md +152 -0
- package/my-docs/api/advanced.md +260 -0
- package/my-docs/getting-started/README.md +24 -0
- package/my-docs/tutorials/README.md +272 -0
- package/my-docs/tutorials/customization.md +492 -0
- package/package.json +59 -0
- package/postcss.config.js +6 -0
- package/site/assets/main-BZUsYUCF.css +1 -0
- package/site/assets/main-q6laQtCD.js +114 -0
- package/site/favicon.svg +4 -0
- package/site/index.html +23 -0
- package/site/robots.txt +4 -0
- package/site/sitemap.xml +34 -0
- package/site-output/assets/main-B4orIFxK.css +1 -0
- package/site-output/assets/main-CSoKXua6.js +25 -0
- package/site-output/favicon.svg +4 -0
- package/site-output/index.html +26 -0
- package/site-output/robots.txt +4 -0
- package/site-output/sitemap.xml +14 -0
- package/src/builder/index.ts +189 -0
- package/src/builder/vite-dev.ts +117 -0
- package/src/cli/commands/build.ts +48 -0
- package/src/cli/commands/dev.ts +53 -0
- package/src/cli/commands/preview.ts +57 -0
- package/src/cli/index.ts +42 -0
- package/src/client/App.vue +15 -0
- package/src/client/components/SearchBox.vue +204 -0
- package/src/client/components/Sidebar.vue +18 -0
- package/src/client/components/SidebarItem.vue +108 -0
- package/src/client/index.html +21 -0
- package/src/client/layouts/AppLayout.vue +99 -0
- package/src/client/lib/utils.ts +6 -0
- package/src/client/main.ts +42 -0
- package/src/client/pages/Home.vue +279 -0
- package/src/client/pages/SkillPage.vue +565 -0
- package/src/client/router.ts +16 -0
- package/src/client/styles/global.css +92 -0
- package/src/client/utils/routes.ts +69 -0
- package/src/parser/index.ts +253 -0
- package/src/scanner/index.ts +127 -0
- package/src/types/index.ts +45 -0
- package/tailwind.config.js +65 -0
- package/test-build/assets/main-C2ARPC0e.css +1 -0
- package/test-build/assets/main-CHIQpV3B.js +25 -0
- package/test-build/favicon.svg +4 -0
- package/test-build/index.html +47 -0
- package/test-build/robots.txt +4 -0
- package/test-build/sitemap.xml +19 -0
- package/test-dist/assets/main-B4orIFxK.css +1 -0
- package/test-dist/assets/main-CSoKXua6.js +25 -0
- package/test-dist/favicon.svg +4 -0
- package/test-dist/index.html +26 -0
- package/test-dist/robots.txt +4 -0
- package/test-dist/sitemap.xml +14 -0
- package/tsconfig.json +30 -0
- package/tsup.config.ts +13 -0
- package/vite.config.ts +21 -0
|
@@ -0,0 +1,565 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="skill-page xl:grid xl:grid-cols-[minmax(0,1fr)_240px] gap-12">
|
|
3
|
+
<div v-if="currentFile" class="skill-content max-w-4xl">
|
|
4
|
+
<!-- Breadcrumb -->
|
|
5
|
+
<nav class="flex items-center gap-2 text-sm text-muted-foreground mb-6 overflow-hidden">
|
|
6
|
+
<router-link to="/" class="hover:text-foreground transition-colors truncate">
|
|
7
|
+
Docs
|
|
8
|
+
</router-link>
|
|
9
|
+
<ChevronRight class="h-4 w-4 shrink-0" />
|
|
10
|
+
<span v-if="currentFile.category" class="flex items-center gap-2 truncate">
|
|
11
|
+
<span class="hover:text-foreground transition-colors truncate">
|
|
12
|
+
{{ currentFile.category }}
|
|
13
|
+
</span>
|
|
14
|
+
<ChevronRight class="h-4 w-4 shrink-0" />
|
|
15
|
+
</span>
|
|
16
|
+
<span class="text-foreground font-medium truncate">{{ currentFile.title }}</span>
|
|
17
|
+
</nav>
|
|
18
|
+
|
|
19
|
+
<!-- Header -->
|
|
20
|
+
<header class="mb-10 space-y-4">
|
|
21
|
+
<div class="flex items-start justify-between gap-4">
|
|
22
|
+
<h1 class="scroll-m-20 text-4xl font-bold tracking-tight text-foreground">{{ currentFile.title }}</h1>
|
|
23
|
+
<button
|
|
24
|
+
@click="copyPage"
|
|
25
|
+
class="shrink-0 flex items-center gap-1.5 px-3 py-1.5 text-sm text-muted-foreground hover:text-foreground border border-border rounded-md hover:bg-accent transition-colors"
|
|
26
|
+
>
|
|
27
|
+
<Check v-if="copied" class="h-4 w-4 text-green-500" />
|
|
28
|
+
<Copy v-else class="h-4 w-4" />
|
|
29
|
+
{{ copied ? 'Copied!' : 'Copy page' }}
|
|
30
|
+
</button>
|
|
31
|
+
</div>
|
|
32
|
+
<p v-if="currentFile.description" class="text-lg text-muted-foreground leading-relaxed">
|
|
33
|
+
{{ currentFile.description }}
|
|
34
|
+
</p>
|
|
35
|
+
</header>
|
|
36
|
+
|
|
37
|
+
<!-- Content -->
|
|
38
|
+
<article class="doc-content">
|
|
39
|
+
<div v-html="renderedContent" ref="contentRef"></div>
|
|
40
|
+
</article>
|
|
41
|
+
|
|
42
|
+
<!-- Footer Navigation -->
|
|
43
|
+
<div class="flex items-center justify-between pt-8 mt-12 border-t border-border">
|
|
44
|
+
<div class="flex-1 min-w-0">
|
|
45
|
+
<router-link
|
|
46
|
+
v-if="navigation.prev"
|
|
47
|
+
:to="navigation.prev.route"
|
|
48
|
+
class="group flex flex-col gap-1 pr-4"
|
|
49
|
+
>
|
|
50
|
+
<span class="text-xs font-medium text-muted-foreground group-hover:text-foreground transition-colors">
|
|
51
|
+
Previous
|
|
52
|
+
</span>
|
|
53
|
+
<span class="text-base font-medium text-foreground group-hover:text-primary transition-colors flex items-center gap-1 truncate">
|
|
54
|
+
<ChevronLeft class="h-4 w-4 transition-transform group-hover:-translate-x-1" />
|
|
55
|
+
{{ navigation.prev.title }}
|
|
56
|
+
</span>
|
|
57
|
+
</router-link>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<div class="flex-1 min-w-0 text-right">
|
|
61
|
+
<router-link
|
|
62
|
+
v-if="navigation.next"
|
|
63
|
+
:to="navigation.next.route"
|
|
64
|
+
class="group flex flex-col gap-1 pl-4 items-end"
|
|
65
|
+
>
|
|
66
|
+
<span class="text-xs font-medium text-muted-foreground group-hover:text-foreground transition-colors">
|
|
67
|
+
Next
|
|
68
|
+
</span>
|
|
69
|
+
<span class="text-base font-medium text-foreground group-hover:text-primary transition-colors flex items-center gap-1 truncate">
|
|
70
|
+
{{ navigation.next.title }}
|
|
71
|
+
<ChevronRight class="h-4 w-4 transition-transform group-hover:translate-x-1" />
|
|
72
|
+
</span>
|
|
73
|
+
</router-link>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<div v-else class="not-found py-20 text-center">
|
|
79
|
+
<h1 class="text-2xl font-bold text-foreground mb-4">Page Not Found</h1>
|
|
80
|
+
<p class="text-muted-foreground mb-8">The requested documentation page could not be found.</p>
|
|
81
|
+
<router-link to="/" class="inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground shadow hover:bg-primary/90 h-9 px-4 py-2">
|
|
82
|
+
Return to Home
|
|
83
|
+
</router-link>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<!-- Right Sidebar (Table of Contents) -->
|
|
87
|
+
<aside v-if="currentFile && headings.length > 0" class="hidden xl:block">
|
|
88
|
+
<div class="sticky top-20">
|
|
89
|
+
<p class="text-sm font-medium text-foreground mb-3">On this page</p>
|
|
90
|
+
<nav class="flex flex-col space-y-2 text-sm">
|
|
91
|
+
<a
|
|
92
|
+
v-for="heading in headings"
|
|
93
|
+
:key="heading.anchor"
|
|
94
|
+
:href="`#${heading.anchor}`"
|
|
95
|
+
class="text-muted-foreground hover:text-foreground transition-colors"
|
|
96
|
+
:class="{ 'pl-3': heading.level === 3, 'pl-6': heading.level === 4 }"
|
|
97
|
+
@click.prevent="scrollToHeading(heading.anchor)"
|
|
98
|
+
>
|
|
99
|
+
{{ heading.text }}
|
|
100
|
+
</a>
|
|
101
|
+
</nav>
|
|
102
|
+
</div>
|
|
103
|
+
</aside>
|
|
104
|
+
</div>
|
|
105
|
+
</template>
|
|
106
|
+
|
|
107
|
+
<script setup lang="ts">
|
|
108
|
+
import { computed, onMounted, nextTick, ref, watch } from 'vue'
|
|
109
|
+
import { useRoute } from 'vue-router'
|
|
110
|
+
import { DocGenConfig, SkillFile } from '../../types/index.js'
|
|
111
|
+
import { getFileRoute } from '../utils/routes.js'
|
|
112
|
+
import { ChevronRight, ChevronLeft, Github, Check, Copy } from 'lucide-vue-next'
|
|
113
|
+
|
|
114
|
+
const props = defineProps<{
|
|
115
|
+
config: DocGenConfig
|
|
116
|
+
}>()
|
|
117
|
+
|
|
118
|
+
const route = useRoute()
|
|
119
|
+
const contentRef = ref<HTMLElement | null>(null)
|
|
120
|
+
const copied = ref(false)
|
|
121
|
+
|
|
122
|
+
const currentFile = computed(() => {
|
|
123
|
+
const path = route.path
|
|
124
|
+
|
|
125
|
+
// Find matching file based on route
|
|
126
|
+
for (const file of props.config.files) {
|
|
127
|
+
const fileRoute = getFileRoute(file)
|
|
128
|
+
if (fileRoute === path) {
|
|
129
|
+
return file
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return null
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
const renderedContent = computed(() => {
|
|
137
|
+
if (!currentFile.value) return ''
|
|
138
|
+
|
|
139
|
+
// Use pre-rendered HTML if available
|
|
140
|
+
if (currentFile.value.frontmatter.html) {
|
|
141
|
+
// Post-process HTML to add copy buttons to code blocks if needed
|
|
142
|
+
// But since we are using v-html, we'll handle interactivity in onMounted/watch
|
|
143
|
+
return currentFile.value.frontmatter.html
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Fallback: basic markdown rendering
|
|
147
|
+
return currentFile.value.content
|
|
148
|
+
.replace(/^### (.*$)/gim, '<h3 id="$1">$1</h3>')
|
|
149
|
+
.replace(/^## (.*$)/gim, '<h2 id="$1">$1</h2>')
|
|
150
|
+
.replace(/^# (.*$)/gim, '<h1 id="$1">$1</h1>')
|
|
151
|
+
.replace(/\*\*(.*?)\*\*/gim, '<strong>$1</strong>')
|
|
152
|
+
.replace(/\*(.*?)\*/gim, '<em>$1</em>')
|
|
153
|
+
.replace(/```([\s\S]*?)```/gim, '<pre><code>$1</code></pre>')
|
|
154
|
+
.replace(/`(.*?)`/gim, '<code>$1</code>')
|
|
155
|
+
.replace(/\n/g, '<br>')
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
const headings = computed(() => {
|
|
159
|
+
return currentFile.value?.frontmatter.headings || []
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
const navigation = computed(() => {
|
|
163
|
+
if (!currentFile.value) return { prev: null, next: null }
|
|
164
|
+
|
|
165
|
+
const allFiles = props.config.files
|
|
166
|
+
const currentIndex = allFiles.findIndex(f => f.path === currentFile.value!.path)
|
|
167
|
+
|
|
168
|
+
const prev = currentIndex > 0 ? allFiles[currentIndex - 1] : null
|
|
169
|
+
const next = currentIndex < allFiles.length - 1 ? allFiles[currentIndex + 1] : null
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
prev: prev ? {
|
|
173
|
+
title: prev.title,
|
|
174
|
+
route: getFileRoute(prev)
|
|
175
|
+
} : null,
|
|
176
|
+
next: next ? {
|
|
177
|
+
title: next.title,
|
|
178
|
+
route: getFileRoute(next)
|
|
179
|
+
} : null
|
|
180
|
+
}
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
function formatDate(timestamp: number): string {
|
|
184
|
+
return new Date(timestamp).toLocaleDateString('en-US', {
|
|
185
|
+
year: 'numeric',
|
|
186
|
+
month: 'long',
|
|
187
|
+
day: 'numeric'
|
|
188
|
+
})
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function scrollToHeading(id: string) {
|
|
192
|
+
const element = document.getElementById(id)
|
|
193
|
+
if (element) {
|
|
194
|
+
const offset = 80 // Header height + padding
|
|
195
|
+
const bodyRect = document.body.getBoundingClientRect().top
|
|
196
|
+
const elementRect = element.getBoundingClientRect().top
|
|
197
|
+
const elementPosition = elementRect - bodyRect
|
|
198
|
+
const offsetPosition = elementPosition - offset
|
|
199
|
+
|
|
200
|
+
window.scrollTo({
|
|
201
|
+
top: offsetPosition,
|
|
202
|
+
behavior: 'smooth'
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
// Update URL hash without jumping
|
|
206
|
+
history.pushState(null, '', `#${id}`)
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Copy entire page content (markdown source)
|
|
211
|
+
function copyPage() {
|
|
212
|
+
if (!currentFile.value) return
|
|
213
|
+
|
|
214
|
+
const content = currentFile.value.content
|
|
215
|
+
navigator.clipboard.writeText(content).then(() => {
|
|
216
|
+
copied.value = true
|
|
217
|
+
setTimeout(() => {
|
|
218
|
+
copied.value = false
|
|
219
|
+
}, 2000)
|
|
220
|
+
})
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Add copy functionality to code blocks (GitHub style)
|
|
224
|
+
function setupCodeBlocks() {
|
|
225
|
+
if (!contentRef.value) return
|
|
226
|
+
|
|
227
|
+
const preElements = contentRef.value.querySelectorAll('pre.shiki')
|
|
228
|
+
preElements.forEach((pre) => {
|
|
229
|
+
// Skip if already processed
|
|
230
|
+
if (pre.parentElement?.classList.contains('code-block-wrapper')) return
|
|
231
|
+
|
|
232
|
+
// Create wrapper
|
|
233
|
+
const wrapper = document.createElement('div')
|
|
234
|
+
wrapper.className = 'code-block-wrapper group relative my-4'
|
|
235
|
+
|
|
236
|
+
// Copy button (appears on hover)
|
|
237
|
+
const button = document.createElement('button')
|
|
238
|
+
button.className = 'copy-btn absolute top-2 right-2 p-2 rounded-md bg-zinc-700/80 text-zinc-400 hover:text-white opacity-0 group-hover:opacity-100 transition-opacity z-10'
|
|
239
|
+
button.innerHTML = `<svg class="w-4 h-4" viewBox="0 0 16 16" fill="currentColor"><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg>`
|
|
240
|
+
|
|
241
|
+
button.onclick = () => {
|
|
242
|
+
const code = pre.textContent || ''
|
|
243
|
+
navigator.clipboard.writeText(code).then(() => {
|
|
244
|
+
button.innerHTML = `<svg class="w-4 h-4 text-green-400" viewBox="0 0 16 16" fill="currentColor"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.75.75 0 0 1 1.06-1.06L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path></svg>`
|
|
245
|
+
setTimeout(() => {
|
|
246
|
+
button.innerHTML = `<svg class="w-4 h-4" viewBox="0 0 16 16" fill="currentColor"><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg>`
|
|
247
|
+
}, 2000)
|
|
248
|
+
})
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Wrap pre element in place (don't clone to preserve shiki styles)
|
|
252
|
+
pre.parentNode?.insertBefore(wrapper, pre)
|
|
253
|
+
wrapper.appendChild(pre)
|
|
254
|
+
wrapper.appendChild(button)
|
|
255
|
+
|
|
256
|
+
// Style pre element
|
|
257
|
+
pre.style.margin = '0'
|
|
258
|
+
pre.style.padding = '16px'
|
|
259
|
+
pre.style.borderRadius = '6px'
|
|
260
|
+
pre.style.fontSize = '14px'
|
|
261
|
+
pre.style.lineHeight = '1.45'
|
|
262
|
+
pre.style.overflow = 'auto'
|
|
263
|
+
})
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Watch for content changes to re-setup code blocks
|
|
267
|
+
watch(renderedContent, () => {
|
|
268
|
+
nextTick(() => {
|
|
269
|
+
setupCodeBlocks()
|
|
270
|
+
})
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
onMounted(() => {
|
|
274
|
+
// Smooth scroll to anchor if present
|
|
275
|
+
nextTick(() => {
|
|
276
|
+
if (route.hash) {
|
|
277
|
+
scrollToHeading(route.hash.slice(1))
|
|
278
|
+
}
|
|
279
|
+
setupCodeBlocks()
|
|
280
|
+
})
|
|
281
|
+
})
|
|
282
|
+
</script>
|
|
283
|
+
|
|
284
|
+
<style scoped>
|
|
285
|
+
.skill-page {
|
|
286
|
+
width: 100%;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/* Document content styles */
|
|
290
|
+
:deep(.doc-content) {
|
|
291
|
+
line-height: 1.75;
|
|
292
|
+
color: var(--color-foreground);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
:deep(.doc-content h2) {
|
|
296
|
+
font-size: 1.5rem;
|
|
297
|
+
font-weight: 600;
|
|
298
|
+
margin-top: 2.5rem;
|
|
299
|
+
margin-bottom: 1rem;
|
|
300
|
+
padding-bottom: 0.5rem;
|
|
301
|
+
border-bottom: 1px solid var(--color-border);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
:deep(.doc-content h3) {
|
|
305
|
+
font-size: 1.25rem;
|
|
306
|
+
font-weight: 600;
|
|
307
|
+
margin-top: 2rem;
|
|
308
|
+
margin-bottom: 0.75rem;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
:deep(.doc-content p) {
|
|
312
|
+
margin-bottom: 1.25rem;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
:deep(.doc-content ul, .doc-content ol) {
|
|
316
|
+
margin: 1rem 0;
|
|
317
|
+
padding-left: 1.5rem;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
:deep(.doc-content li) {
|
|
321
|
+
margin: 0.5rem 0;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
:deep(.doc-content a) {
|
|
325
|
+
color: var(--color-primary);
|
|
326
|
+
text-decoration: underline;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/* Inline code */
|
|
330
|
+
:deep(.doc-content code:not(pre code)) {
|
|
331
|
+
background: var(--color-muted);
|
|
332
|
+
padding: 0.2em 0.4em;
|
|
333
|
+
border-radius: 4px;
|
|
334
|
+
font-size: 0.875em;
|
|
335
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/* Code blocks - shiki handles colors via inline styles */
|
|
339
|
+
:deep(.doc-content pre.shiki) {
|
|
340
|
+
margin: 1.5rem 0;
|
|
341
|
+
padding: 1rem;
|
|
342
|
+
border-radius: 8px;
|
|
343
|
+
overflow-x: auto;
|
|
344
|
+
font-size: 14px;
|
|
345
|
+
line-height: 1.6;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
:deep(.doc-content pre.shiki code) {
|
|
349
|
+
background: transparent;
|
|
350
|
+
padding: 0;
|
|
351
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.skill-header {
|
|
355
|
+
margin-bottom: 3rem;
|
|
356
|
+
padding-bottom: 2rem;
|
|
357
|
+
border-bottom: 1px solid var(--color-border);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.skill-title {
|
|
361
|
+
font-size: 2.25rem;
|
|
362
|
+
font-weight: 700;
|
|
363
|
+
color: var(--color-foreground);
|
|
364
|
+
margin-bottom: 1rem;
|
|
365
|
+
line-height: 1.2;
|
|
366
|
+
letter-spacing: -0.02em;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
.skill-description {
|
|
370
|
+
font-size: 1.125rem;
|
|
371
|
+
color: var(--color-muted-foreground);
|
|
372
|
+
margin-bottom: 1.5rem;
|
|
373
|
+
line-height: 1.6;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
.skill-meta {
|
|
377
|
+
color: var(--color-muted-foreground);
|
|
378
|
+
font-size: 0.875rem;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/* TOC - Simplified */
|
|
382
|
+
.toc {
|
|
383
|
+
background: var(--color-muted);
|
|
384
|
+
border-radius: var(--radius-lg);
|
|
385
|
+
padding: 1.5rem;
|
|
386
|
+
margin-bottom: 3rem;
|
|
387
|
+
border: 1px solid var(--color-border);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.toc h3 {
|
|
391
|
+
margin: 0 0 1rem;
|
|
392
|
+
color: var(--color-foreground);
|
|
393
|
+
font-size: 0.875rem;
|
|
394
|
+
text-transform: uppercase;
|
|
395
|
+
letter-spacing: 0.05em;
|
|
396
|
+
font-weight: 600;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
.toc-list {
|
|
400
|
+
list-style: none;
|
|
401
|
+
padding: 0;
|
|
402
|
+
margin: 0;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
.toc-list li {
|
|
406
|
+
margin-bottom: 0.5rem;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
.toc-level-1 { padding-left: 0; }
|
|
410
|
+
.toc-level-2 { padding-left: 0; }
|
|
411
|
+
.toc-level-3 { padding-left: 1rem; }
|
|
412
|
+
.toc-level-4 { padding-left: 2rem; }
|
|
413
|
+
|
|
414
|
+
.toc-link {
|
|
415
|
+
color: var(--color-muted-foreground);
|
|
416
|
+
text-decoration: none;
|
|
417
|
+
font-size: 0.875rem;
|
|
418
|
+
transition: color 0.2s ease;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
.toc-link:hover {
|
|
422
|
+
color: var(--color-primary);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/* Content Typography */
|
|
426
|
+
:deep(.markdown-content) {
|
|
427
|
+
line-height: 1.7;
|
|
428
|
+
color: var(--color-foreground);
|
|
429
|
+
border-radius: var(--radius-sm);
|
|
430
|
+
font-family: var(--font-mono);
|
|
431
|
+
font-size: 0.875em;
|
|
432
|
+
color: var(--color-foreground);
|
|
433
|
+
border: 1px solid var(--color-code-border);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
:deep(.markdown-content pre) {
|
|
437
|
+
background: var(--color-code-bg);
|
|
438
|
+
border: 1px solid var(--color-code-border);
|
|
439
|
+
border-radius: var(--radius-lg);
|
|
440
|
+
padding: 1.25rem;
|
|
441
|
+
overflow-x: auto;
|
|
442
|
+
margin: 1.5rem 0;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
:deep(.markdown-content pre code) {
|
|
446
|
+
background: none;
|
|
447
|
+
padding: 0;
|
|
448
|
+
border: none;
|
|
449
|
+
border-radius: 0;
|
|
450
|
+
color: inherit;
|
|
451
|
+
font-size: 0.875rem;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
:deep(.markdown-content blockquote) {
|
|
455
|
+
border-left: 4px solid var(--color-primary);
|
|
456
|
+
background: var(--color-muted);
|
|
457
|
+
padding: 1rem 1.5rem;
|
|
458
|
+
margin: 1.5rem 0;
|
|
459
|
+
border-radius: 0 var(--radius-md) var(--radius-md) 0;
|
|
460
|
+
color: var(--color-muted-foreground);
|
|
461
|
+
font-style: italic;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
:deep(.markdown-content table) {
|
|
465
|
+
width: 100%;
|
|
466
|
+
border-collapse: collapse;
|
|
467
|
+
margin: 2rem 0;
|
|
468
|
+
font-size: 0.875rem;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
:deep(.markdown-content th),
|
|
472
|
+
:deep(.markdown-content td) {
|
|
473
|
+
border-bottom: 1px solid var(--color-border);
|
|
474
|
+
padding: 0.75rem 1rem;
|
|
475
|
+
text-align: left;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
:deep(.markdown-content th) {
|
|
479
|
+
color: var(--color-foreground);
|
|
480
|
+
font-weight: 600;
|
|
481
|
+
background: var(--color-muted);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/* Page Navigation */
|
|
485
|
+
.page-navigation {
|
|
486
|
+
display: flex;
|
|
487
|
+
justify-content: space-between;
|
|
488
|
+
margin-top: 4rem;
|
|
489
|
+
padding-top: 2rem;
|
|
490
|
+
border-top: 1px solid var(--color-border);
|
|
491
|
+
gap: 1.5rem;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
.nav-link {
|
|
495
|
+
flex: 1;
|
|
496
|
+
text-decoration: none;
|
|
497
|
+
color: inherit;
|
|
498
|
+
padding: 1.5rem;
|
|
499
|
+
border: 1px solid var(--color-border);
|
|
500
|
+
border-radius: var(--radius-lg);
|
|
501
|
+
transition: all 0.2s ease;
|
|
502
|
+
background: var(--color-card);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
.nav-link:hover {
|
|
506
|
+
border-color: var(--color-primary);
|
|
507
|
+
box-shadow: var(--shadow-md);
|
|
508
|
+
transform: translateY(-2px);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
.nav-prev { text-align: left; }
|
|
512
|
+
.nav-next { text-align: right; }
|
|
513
|
+
|
|
514
|
+
.nav-direction {
|
|
515
|
+
color: var(--color-muted-foreground);
|
|
516
|
+
font-size: 0.875rem;
|
|
517
|
+
font-weight: 500;
|
|
518
|
+
margin-bottom: 0.5rem;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
.nav-title {
|
|
522
|
+
color: var(--color-foreground);
|
|
523
|
+
font-weight: 600;
|
|
524
|
+
font-size: 1rem;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/* Not Found */
|
|
528
|
+
.not-found {
|
|
529
|
+
text-align: center;
|
|
530
|
+
padding: 4rem 0;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
.not-found h1 {
|
|
534
|
+
font-size: 2.5rem;
|
|
535
|
+
color: var(--color-foreground);
|
|
536
|
+
margin-bottom: 1rem;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
.not-found p {
|
|
540
|
+
color: var(--color-muted-foreground);
|
|
541
|
+
margin-bottom: 2rem;
|
|
542
|
+
font-size: 1.125rem;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
.back-home {
|
|
546
|
+
display: inline-block;
|
|
547
|
+
padding: 0.75rem 1.5rem;
|
|
548
|
+
background: var(--color-primary);
|
|
549
|
+
color: var(--color-primary-foreground);
|
|
550
|
+
border-radius: var(--radius-md);
|
|
551
|
+
font-weight: 500;
|
|
552
|
+
transition: opacity 0.2s ease;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
.back-home:hover {
|
|
556
|
+
opacity: 0.9;
|
|
557
|
+
text-decoration: none;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
@media (max-width: 768px) {
|
|
561
|
+
.skill-title { font-size: 1.875rem; }
|
|
562
|
+
.page-navigation { flex-direction: column; }
|
|
563
|
+
.nav-next { text-align: left; }
|
|
564
|
+
}
|
|
565
|
+
</style>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { RouteRecordRaw } from 'vue-router'
|
|
2
|
+
import Home from './pages/Home.vue'
|
|
3
|
+
import SkillPage from './pages/SkillPage.vue'
|
|
4
|
+
|
|
5
|
+
export const routes: RouteRecordRaw[] = [
|
|
6
|
+
{
|
|
7
|
+
path: '/',
|
|
8
|
+
name: 'Home',
|
|
9
|
+
component: Home
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
path: '/:pathMatch(.*)*',
|
|
13
|
+
name: 'Skill',
|
|
14
|
+
component: SkillPage
|
|
15
|
+
}
|
|
16
|
+
]
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
@tailwind base;
|
|
2
|
+
@tailwind components;
|
|
3
|
+
@tailwind utilities;
|
|
4
|
+
|
|
5
|
+
@layer base {
|
|
6
|
+
:root {
|
|
7
|
+
--background: 0 0% 100%;
|
|
8
|
+
--foreground: 222.2 84% 4.9%;
|
|
9
|
+
|
|
10
|
+
--card: 0 0% 100%;
|
|
11
|
+
--card-foreground: 222.2 84% 4.9%;
|
|
12
|
+
|
|
13
|
+
--popover: 0 0% 100%;
|
|
14
|
+
--popover-foreground: 222.2 84% 4.9%;
|
|
15
|
+
|
|
16
|
+
--primary: 222.2 47.4% 11.2%;
|
|
17
|
+
--primary-foreground: 210 40% 98%;
|
|
18
|
+
|
|
19
|
+
--secondary: 210 40% 96.1%;
|
|
20
|
+
--secondary-foreground: 222.2 47.4% 11.2%;
|
|
21
|
+
|
|
22
|
+
--muted: 210 40% 96.1%;
|
|
23
|
+
--muted-foreground: 215.4 16.3% 46.9%;
|
|
24
|
+
|
|
25
|
+
--accent: 210 40% 96.1%;
|
|
26
|
+
--accent-foreground: 222.2 47.4% 11.2%;
|
|
27
|
+
|
|
28
|
+
--destructive: 0 84.2% 60.2%;
|
|
29
|
+
--destructive-foreground: 210 40% 98%;
|
|
30
|
+
|
|
31
|
+
--border: 214.3 31.8% 91.4%;
|
|
32
|
+
--input: 214.3 31.8% 91.4%;
|
|
33
|
+
--ring: 222.2 84% 4.9%;
|
|
34
|
+
|
|
35
|
+
--radius: 0.5rem;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.dark {
|
|
39
|
+
--background: 222.2 84% 4.9%;
|
|
40
|
+
--foreground: 210 40% 98%;
|
|
41
|
+
|
|
42
|
+
--card: 222.2 84% 4.9%;
|
|
43
|
+
--card-foreground: 210 40% 98%;
|
|
44
|
+
|
|
45
|
+
--popover: 222.2 84% 4.9%;
|
|
46
|
+
--popover-foreground: 210 40% 98%;
|
|
47
|
+
|
|
48
|
+
--primary: 210 40% 98%;
|
|
49
|
+
--primary-foreground: 222.2 47.4% 11.2%;
|
|
50
|
+
|
|
51
|
+
--secondary: 217.2 32.6% 17.5%;
|
|
52
|
+
--secondary-foreground: 210 40% 98%;
|
|
53
|
+
|
|
54
|
+
--muted: 217.2 32.6% 17.5%;
|
|
55
|
+
--muted-foreground: 215 20.2% 65.1%;
|
|
56
|
+
|
|
57
|
+
--accent: 217.2 32.6% 17.5%;
|
|
58
|
+
--accent-foreground: 210 40% 98%;
|
|
59
|
+
|
|
60
|
+
--destructive: 0 62.8% 30.6%;
|
|
61
|
+
--destructive-foreground: 210 40% 98%;
|
|
62
|
+
|
|
63
|
+
--border: 217.2 32.6% 17.5%;
|
|
64
|
+
--input: 217.2 32.6% 17.5%;
|
|
65
|
+
--ring: 212.7 26.8% 83.9%;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@layer base {
|
|
70
|
+
* {
|
|
71
|
+
@apply border-border;
|
|
72
|
+
}
|
|
73
|
+
body {
|
|
74
|
+
@apply bg-background text-foreground;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/* Shiki code block styles - GitHub style */
|
|
79
|
+
pre.shiki {
|
|
80
|
+
margin: 1.5rem 0;
|
|
81
|
+
padding: 1rem;
|
|
82
|
+
border-radius: 6px;
|
|
83
|
+
overflow-x: auto;
|
|
84
|
+
font-size: 14px;
|
|
85
|
+
line-height: 1.45;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
pre.shiki code {
|
|
89
|
+
background: transparent;
|
|
90
|
+
padding: 0;
|
|
91
|
+
font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
|
|
92
|
+
}
|