docs: add setup guides, architecture docs, and config examples

This commit is contained in:
2026-02-22 21:43:43 -08:00
parent ae95601698
commit 64020a9069
48 changed files with 5095 additions and 0 deletions

98
docs/.vitepress/config.ts Normal file
View File

@@ -0,0 +1,98 @@
const repositoryName = process.env.GITHUB_REPOSITORY?.split('/')[1];
const base = process.env.GITHUB_ACTIONS && repositoryName ? `/${repositoryName}/` : '/';
export default {
title: 'SubMiner Docs',
description:
'SubMiner: an MPV immersion-mining overlay with Yomitan and AnkiConnect integration.',
base,
head: [
['link', { rel: 'icon', href: '/favicon.ico', sizes: 'any' }],
[
'link',
{
rel: 'icon',
type: 'image/png',
href: '/favicon-32x32.png',
sizes: '32x32',
},
],
[
'link',
{
rel: 'icon',
type: 'image/png',
href: '/favicon-16x16.png',
sizes: '16x16',
},
],
[
'link',
{
rel: 'apple-touch-icon',
href: '/apple-touch-icon.png',
sizes: '180x180',
},
],
],
appearance: 'dark',
cleanUrls: true,
lastUpdated: true,
srcExclude: ['subagents/**'],
markdown: {
theme: {
light: 'catppuccin-latte',
dark: 'catppuccin-macchiato',
},
},
themeConfig: {
logo: {
light: '/assets/SubMiner.png',
dark: '/assets/SubMiner.png',
},
siteTitle: 'SubMiner Docs',
nav: [
{ text: 'Home', link: '/' },
{ text: 'Get Started', link: '/installation' },
{ text: 'Mining', link: '/mining-workflow' },
{ text: 'Configuration', link: '/configuration' },
{ text: 'Troubleshooting', link: '/troubleshooting' },
],
sidebar: [
{
text: 'Getting Started',
items: [
{ text: 'Overview', link: '/' },
{ text: 'Installation', link: '/installation' },
{ text: 'Launcher Script', link: '/launcher-script' },
{ text: 'Usage', link: '/usage' },
{ text: 'Mining Workflow', link: '/mining-workflow' },
],
},
{
text: 'Reference',
items: [
{ text: 'Configuration', link: '/configuration' },
{ text: 'Keyboard Shortcuts', link: '/shortcuts' },
{ text: 'Anki Integration', link: '/anki-integration' },
{ text: 'Jellyfin Integration', link: '/jellyfin-integration' },
{ text: 'Immersion Tracking', link: '/immersion-tracking' },
{ text: 'JLPT Vocabulary', link: '/jlpt-vocab-bundle' },
{ text: 'MPV Plugin', link: '/mpv-plugin' },
{ text: 'Troubleshooting', link: '/troubleshooting' },
],
},
{
text: 'Development',
items: [
{ text: 'Building & Testing', link: '/development' },
{ text: 'Architecture', link: '/architecture' },
],
},
],
search: {
provider: 'local',
},
socialLinks: [{ icon: 'github', link: 'https://github.com/ksyasuda/SubMiner' }],
},
};

View File

@@ -0,0 +1,194 @@
import DefaultTheme from 'vitepress/theme';
import { useRoute } from 'vitepress';
import { nextTick, onMounted, watch } from 'vue';
import '@catppuccin/vitepress/theme/macchiato/mauve.css';
import './mermaid-modal.css';
let mermaidLoader: Promise<any> | null = null;
const MERMAID_MODAL_ID = 'mermaid-diagram-modal';
function closeMermaidModal() {
if (typeof document === 'undefined') {
return;
}
const modal = document.getElementById(MERMAID_MODAL_ID);
if (!modal) {
return;
}
modal.classList.remove('is-open');
document.body.classList.remove('mermaid-modal-open');
}
function ensureMermaidModal(): HTMLDivElement {
const existing = document.getElementById(MERMAID_MODAL_ID);
if (existing) {
return existing as HTMLDivElement;
}
const modal = document.createElement('div');
modal.id = MERMAID_MODAL_ID;
modal.className = 'mermaid-modal';
modal.innerHTML = `
<div class="mermaid-modal__backdrop" data-mermaid-close="true"></div>
<div class="mermaid-modal__dialog" role="dialog" aria-modal="true" aria-label="Expanded Mermaid diagram">
<button class="mermaid-modal__close" type="button" aria-label="Close Mermaid diagram">Close</button>
<div class="mermaid-modal__content"></div>
</div>
`;
modal.addEventListener('click', (event) => {
const target = event.target as HTMLElement | null;
if (!target) {
return;
}
if (target.closest('[data-mermaid-close="true"]') || target.closest('.mermaid-modal__close')) {
closeMermaidModal();
}
});
document.addEventListener('keydown', (event) => {
if (event.key === 'Escape' && modal.classList.contains('is-open')) {
closeMermaidModal();
}
});
document.body.appendChild(modal);
return modal;
}
function openMermaidModal(sourceNode: HTMLElement) {
if (typeof document === 'undefined') {
return;
}
const modal = ensureMermaidModal();
const content = modal.querySelector<HTMLDivElement>('.mermaid-modal__content');
if (!content) {
return;
}
content.replaceChildren(sourceNode.cloneNode(true));
modal.classList.add('is-open');
document.body.classList.add('mermaid-modal-open');
}
function attachMermaidInteractions(nodes: HTMLElement[]) {
for (const node of nodes) {
if (node.dataset.mermaidInteractive === 'true') {
continue;
}
const svg = node.querySelector<HTMLElement>('svg');
if (!svg) {
continue;
}
node.classList.add('mermaid-interactive');
node.setAttribute('role', 'button');
node.setAttribute('tabindex', '0');
node.setAttribute('aria-label', 'Open Mermaid diagram in full view');
const open = () => openMermaidModal(svg);
node.addEventListener('click', open);
node.addEventListener('keydown', (event) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
open();
}
});
node.dataset.mermaidInteractive = 'true';
}
}
async function getMermaid() {
if (!mermaidLoader) {
mermaidLoader = import('mermaid').then((module) => {
const mermaid = module.default;
mermaid.initialize({
startOnLoad: false,
securityLevel: 'loose',
theme: 'base',
themeVariables: {
background: '#24273a',
primaryColor: '#363a4f',
primaryTextColor: '#cad3f5',
primaryBorderColor: '#c6a0f6',
secondaryColor: '#494d64',
secondaryTextColor: '#cad3f5',
secondaryBorderColor: '#b7bdf8',
tertiaryColor: '#5b6078',
tertiaryTextColor: '#cad3f5',
tertiaryBorderColor: '#8aadf4',
lineColor: '#939ab7',
textColor: '#cad3f5',
mainBkg: '#363a4f',
nodeBorder: '#c6a0f6',
clusterBkg: '#1e2030',
clusterBorder: '#494d64',
edgeLabelBackground: '#24273a',
labelTextColor: '#cad3f5',
},
});
return mermaid;
});
}
return mermaidLoader;
}
async function renderMermaidBlocks() {
if (typeof document === 'undefined') {
return;
}
const blocks = Array.from(document.querySelectorAll<HTMLElement>('div.language-mermaid'));
if (blocks.length === 0) {
return;
}
const mermaid = await getMermaid();
const nodes: HTMLElement[] = [];
for (const block of blocks) {
if (block.dataset.mermaidRendered === 'true') {
continue;
}
const code = block.querySelector('pre code');
const source = code?.textContent?.trim();
if (!source) {
continue;
}
const mount = document.createElement('div');
mount.className = 'mermaid';
mount.textContent = source;
block.replaceChildren(mount);
block.dataset.mermaidRendered = 'true';
nodes.push(mount);
}
if (nodes.length > 0) {
await mermaid.run({ nodes });
attachMermaidInteractions(nodes);
}
}
export default {
...DefaultTheme,
setup() {
const route = useRoute();
const render = () => {
nextTick(() => {
renderMermaidBlocks().catch((error) => {
console.error('Failed to render Mermaid diagram:', error);
});
});
};
onMounted(render);
watch(() => route.path, render);
},
};

View File

@@ -0,0 +1,69 @@
.mermaid-interactive {
cursor: zoom-in;
}
.mermaid-interactive:focus-visible {
outline: 2px solid var(--vp-c-brand-1);
outline-offset: 4px;
border-radius: 6px;
}
.mermaid-modal {
position: fixed;
inset: 0;
z-index: 200;
display: none;
}
.mermaid-modal.is-open {
display: block;
}
.mermaid-modal__backdrop {
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.72);
}
.mermaid-modal__dialog {
position: relative;
z-index: 1;
margin: 4vh auto;
width: min(96vw, 1800px);
max-height: 92vh;
border: 1px solid var(--vp-c-border);
border-radius: 12px;
background: var(--vp-c-bg);
box-shadow: var(--vp-shadow-4);
overflow: hidden;
}
.mermaid-modal__close {
display: block;
margin-left: auto;
margin-right: 16px;
margin-top: 12px;
border: 1px solid var(--vp-c-border);
border-radius: 6px;
padding: 4px 10px;
background: var(--vp-c-bg-soft);
color: var(--vp-c-text-1);
font-size: 14px;
}
.mermaid-modal__content {
overflow: auto;
max-height: calc(92vh - 56px);
padding: 8px 16px 16px;
}
.mermaid-modal__content svg {
max-width: none;
width: max-content;
height: auto;
min-width: 100%;
}
body.mermaid-modal-open {
overflow: hidden;
}