mirror of
https://github.com/Nanaloveyuki/BitLogger.git
synced 2026-07-30 06:26:38 +00:00
Add VitePress docs site with MoonBit highlighting
This commit is contained in:
@@ -0,0 +1,218 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, shallowRef } from 'vue'
|
||||
|
||||
import { docsData } from '../../generated/docs-data.mjs'
|
||||
|
||||
const selectedGroup = shallowRef('all')
|
||||
const query = shallowRef('')
|
||||
|
||||
const groups = computed(() => docsData.api.groups)
|
||||
|
||||
const filteredGroups = computed(() => {
|
||||
const keyword = query.value.trim().toLowerCase()
|
||||
return groups.value
|
||||
.filter(group => selectedGroup.value === 'all' || group.id === selectedGroup.value)
|
||||
.map(group => ({
|
||||
...group,
|
||||
categories: group.categories
|
||||
.map(category => ({
|
||||
...category,
|
||||
entries: category.entries.filter(entry => {
|
||||
if (!keyword) return true
|
||||
const haystack = [entry.title, entry.description, entry.name, ...entry.keywords]
|
||||
.join(' ')
|
||||
.toLowerCase()
|
||||
return haystack.includes(keyword)
|
||||
}),
|
||||
}))
|
||||
.filter(category => category.entries.length > 0),
|
||||
}))
|
||||
.filter(group => group.categories.length > 0)
|
||||
})
|
||||
|
||||
const resultCount = computed(() =>
|
||||
filteredGroups.value.reduce(
|
||||
(total, group) => total + group.categories.reduce((sum, category) => sum + category.entries.length, 0),
|
||||
0,
|
||||
),
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="api-shell">
|
||||
<div class="api-toolbar">
|
||||
<label class="api-search">
|
||||
<span>Find API</span>
|
||||
<input v-model="query" type="search" placeholder="Search logger, sink, config, async...">
|
||||
</label>
|
||||
|
||||
<label class="api-filter">
|
||||
<span>Doc Group</span>
|
||||
<select v-model="selectedGroup">
|
||||
<option value="all">All groups</option>
|
||||
<option v-for="group in groups" :key="group.id" :value="group.id">
|
||||
{{ group.label }}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="api-summary">
|
||||
<strong>{{ resultCount }}</strong>
|
||||
<span>matching API pages across {{ filteredGroups.length }} group views</span>
|
||||
</div>
|
||||
|
||||
<div class="api-groups">
|
||||
<article v-for="group in filteredGroups" :key="group.id" class="api-group-card">
|
||||
<header class="api-group-header">
|
||||
<div>
|
||||
<p class="api-group-kicker">{{ group.label }}</p>
|
||||
<h3>{{ group.entryCount }} APIs in this group</h3>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="api-category-grid">
|
||||
<section v-for="category in group.categories" :key="category.id" class="api-category-card">
|
||||
<h4>{{ category.label }}</h4>
|
||||
<p>{{ category.entries.length }} entries</p>
|
||||
<ul>
|
||||
<li v-for="entry in category.entries.slice(0, 8)" :key="entry.slug">
|
||||
<a :href="entry.link">{{ entry.title }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
<a v-if="category.entries.length > 8" class="api-more" href="/api/">
|
||||
Browse {{ category.entries.length - 8 }} more in sidebar
|
||||
</a>
|
||||
</section>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.api-shell {
|
||||
margin: 1.5rem 0 2rem;
|
||||
}
|
||||
|
||||
.api-toolbar {
|
||||
display: grid;
|
||||
gap: 0.9rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.api-search,
|
||||
.api-filter {
|
||||
display: grid;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.api-search span,
|
||||
.api-filter span {
|
||||
font-size: 0.78rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
color: #9b4d28;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.api-search input,
|
||||
.api-filter select {
|
||||
width: 100%;
|
||||
border-radius: 14px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
padding: 0.85rem 0.95rem;
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
.api-summary {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 0.65rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.api-summary strong {
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
.api-summary span {
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.api-groups {
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.api-group-card {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 28px;
|
||||
padding: 1rem;
|
||||
background: linear-gradient(180deg, rgba(255, 251, 247, 0.96), rgba(246, 242, 236, 0.96));
|
||||
}
|
||||
|
||||
.api-group-header h3,
|
||||
.api-category-card h4,
|
||||
.api-category-card p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.api-group-kicker {
|
||||
margin: 0 0 0.25rem;
|
||||
color: #9b4d28;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.api-category-grid {
|
||||
display: grid;
|
||||
gap: 0.85rem;
|
||||
margin-top: 0.9rem;
|
||||
}
|
||||
|
||||
.api-category-card {
|
||||
border-radius: 20px;
|
||||
background: rgba(255, 255, 255, 0.88);
|
||||
border: 1px solid rgba(155, 77, 40, 0.12);
|
||||
padding: 0.95rem;
|
||||
}
|
||||
|
||||
.api-category-card p {
|
||||
margin-top: 0.25rem;
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.api-category-card ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0.85rem 0 0;
|
||||
display: grid;
|
||||
gap: 0.45rem;
|
||||
}
|
||||
|
||||
.api-category-card a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.api-more {
|
||||
display: inline-block;
|
||||
margin-top: 0.8rem;
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
@media (min-width: 820px) {
|
||||
.api-toolbar {
|
||||
grid-template-columns: minmax(0, 2fr) minmax(220px, 0.8fr);
|
||||
}
|
||||
|
||||
.api-category-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,175 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
|
||||
import { docsData } from '../../generated/docs-data.mjs'
|
||||
|
||||
const topCategories = computed(() => docsData.api.categories.slice(0, 6))
|
||||
const recentChanges = computed(() => docsData.changes.slice(0, 4))
|
||||
const apiCount = computed(() => docsData.api.entries.filter(entry => entry.slug !== 'index').length)
|
||||
const groupCount = computed(() => docsData.api.groups.length)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="hub-grid">
|
||||
<article class="hub-panel hub-panel-accent">
|
||||
<p class="hub-eyebrow">Docs Hub</p>
|
||||
<h2 class="hub-title">Start from use case, not from filenames.</h2>
|
||||
<p class="hub-copy">
|
||||
Browse builders, runtime helpers, presets, sync logging, and async logging from one place.
|
||||
</p>
|
||||
<div class="hub-stats">
|
||||
<div>
|
||||
<strong>{{ apiCount }}</strong>
|
||||
<span>API pages</span>
|
||||
</div>
|
||||
<div>
|
||||
<strong>{{ groupCount }}</strong>
|
||||
<span>doc groups</span>
|
||||
</div>
|
||||
<div>
|
||||
<strong>{{ docsData.changes.length }}</strong>
|
||||
<span>release notes</span>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="hub-panel">
|
||||
<p class="hub-eyebrow">Popular Areas</p>
|
||||
<ul class="hub-chip-list">
|
||||
<li v-for="category in topCategories" :key="category.id">
|
||||
<a class="hub-chip" href="/api/">
|
||||
<span>{{ category.label }}</span>
|
||||
<small>{{ category.entryCount }}</small>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</article>
|
||||
|
||||
<article class="hub-panel">
|
||||
<p class="hub-eyebrow">Release Trail</p>
|
||||
<ul class="hub-link-list">
|
||||
<li v-for="item in recentChanges" :key="item.version">
|
||||
<a :href="item.link">Version {{ item.version }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</article>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.hub-grid {
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
margin: 1.5rem 0 2rem;
|
||||
}
|
||||
|
||||
.hub-panel {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 24px;
|
||||
padding: 1.25rem;
|
||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0.95), rgba(247, 245, 239, 0.95));
|
||||
box-shadow: 0 16px 40px rgba(62, 46, 31, 0.08);
|
||||
}
|
||||
|
||||
.hub-panel-accent {
|
||||
background:
|
||||
radial-gradient(circle at top right, rgba(191, 68, 32, 0.16), transparent 34%),
|
||||
linear-gradient(180deg, rgba(255, 250, 244, 0.98), rgba(247, 241, 232, 0.98));
|
||||
}
|
||||
|
||||
.hub-eyebrow {
|
||||
margin: 0 0 0.5rem;
|
||||
color: #9b4d28;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.12em;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.hub-title {
|
||||
margin: 0;
|
||||
font-size: 1.55rem;
|
||||
line-height: 1.15;
|
||||
}
|
||||
|
||||
.hub-copy {
|
||||
margin: 0.85rem 0 0;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.hub-stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 0.75rem;
|
||||
margin-top: 1.15rem;
|
||||
}
|
||||
|
||||
.hub-stats strong,
|
||||
.hub-stats span {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.hub-stats strong {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
.hub-stats span {
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.hub-chip-list,
|
||||
.hub-link-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.hub-chip-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.7rem;
|
||||
}
|
||||
|
||||
.hub-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.65rem;
|
||||
padding: 0.7rem 0.9rem;
|
||||
border-radius: 999px;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
border: 1px solid rgba(155, 77, 40, 0.14);
|
||||
}
|
||||
|
||||
.hub-chip small {
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.hub-link-list {
|
||||
display: grid;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.hub-link-list a {
|
||||
color: var(--vp-c-brand-1);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media (min-width: 860px) {
|
||||
.hub-grid {
|
||||
grid-template-columns: 1.35fr 1fr;
|
||||
}
|
||||
|
||||
.hub-panel-accent {
|
||||
grid-row: span 2;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.hub-stats {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user