7 documentation system features: - Blog authoring: frontmatter panel, new post wizard, authors management - Access policies: per-file/directory edit restrictions with role/user granularity - Public sharing: share links with collaborative editing via dual JWT auth - Version history: Gitea auto-commit on save, diff viewer, restore - Document templates: 8 built-in templates (blog, guide, API ref, ADR, FAQ, etc.) - Metadata dashboard: overview of all docs with warnings (no-tags, stale, etc.) - Content search: in-file text search with line-level matches Gitea auto-setup: one-click configuration of API token, repos, labels, OAuth app - Backend service + startup hook (auto-configures if GITEA_ADMIN_PASSWORD set) - Admin GUI wizard at /app/services/gitea/setup - config.sh now prompts for Gitea admin password Backend: 10 new files, 5 modified (3 models, 1 enum, 2 migrations, 30+ API endpoints) Frontend: 13 new files, 3 modified (hooks, components, pages) Bunker Admin
405 lines
6.8 KiB
TypeScript
405 lines
6.8 KiB
TypeScript
export interface DocTemplate {
|
|
id: string;
|
|
name: string;
|
|
description: string;
|
|
category: 'blog' | 'guide' | 'reference' | 'planning' | 'general';
|
|
icon: string; // Material icon name
|
|
filenamePattern: string; // e.g. "{{slug}}.md" or "blog/posts/{{date}}-{{slug}}.md"
|
|
content: string;
|
|
}
|
|
|
|
const today = () => new Date().toISOString().split('T')[0];
|
|
|
|
const BUILT_IN_TEMPLATES: DocTemplate[] = [
|
|
{
|
|
id: 'blog-post',
|
|
name: 'Blog Post',
|
|
description: 'A blog post with MkDocs Material frontmatter',
|
|
category: 'blog',
|
|
icon: 'article',
|
|
filenamePattern: 'blog/posts/{{date}}-{{slug}}.md',
|
|
content: `---
|
|
date: {{date}}
|
|
authors:
|
|
- admin
|
|
categories:
|
|
- General
|
|
draft: true
|
|
---
|
|
|
|
# {{title}}
|
|
|
|
Write your intro paragraph here. This appears on the blog index page.
|
|
|
|
<!-- more -->
|
|
|
|
## Main Content
|
|
|
|
Continue writing below the fold...
|
|
`,
|
|
},
|
|
{
|
|
id: 'how-to-guide',
|
|
name: 'How-To Guide',
|
|
description: 'Step-by-step guide for a specific task',
|
|
category: 'guide',
|
|
icon: 'menu_book',
|
|
filenamePattern: 'docs/{{slug}}.md',
|
|
content: `---
|
|
tags:
|
|
- guide
|
|
---
|
|
|
|
# How to {{title}}
|
|
|
|
Brief description of what this guide covers and who it's for.
|
|
|
|
## Prerequisites
|
|
|
|
- Prerequisite 1
|
|
- Prerequisite 2
|
|
|
|
## Steps
|
|
|
|
### Step 1: Getting Started
|
|
|
|
Description of the first step.
|
|
|
|
### Step 2: Configuration
|
|
|
|
Description of the second step.
|
|
|
|
### Step 3: Verification
|
|
|
|
How to verify everything is working.
|
|
|
|
## Troubleshooting
|
|
|
|
Common issues and their solutions.
|
|
|
|
## Next Steps
|
|
|
|
What to do after completing this guide.
|
|
`,
|
|
},
|
|
{
|
|
id: 'api-reference',
|
|
name: 'API Reference',
|
|
description: 'API endpoint documentation',
|
|
category: 'reference',
|
|
icon: 'api',
|
|
filenamePattern: 'docs/api/{{slug}}.md',
|
|
content: `---
|
|
tags:
|
|
- api
|
|
- reference
|
|
---
|
|
|
|
# {{title}} API
|
|
|
|
## Overview
|
|
|
|
Brief description of this API group.
|
|
|
|
## Endpoints
|
|
|
|
### GET /api/endpoint
|
|
|
|
Description of what this endpoint does.
|
|
|
|
**Parameters:**
|
|
|
|
| Parameter | Type | Required | Description |
|
|
|-----------|------|----------|-------------|
|
|
| id | string | Yes | Resource ID |
|
|
|
|
**Response:**
|
|
|
|
\`\`\`json
|
|
{
|
|
"id": "abc123",
|
|
"name": "Example"
|
|
}
|
|
\`\`\`
|
|
|
|
### POST /api/endpoint
|
|
|
|
Description of what this endpoint does.
|
|
|
|
**Request Body:**
|
|
|
|
\`\`\`json
|
|
{
|
|
"name": "Example"
|
|
}
|
|
\`\`\`
|
|
|
|
## Error Codes
|
|
|
|
| Code | Description |
|
|
|------|-------------|
|
|
| 400 | Bad Request |
|
|
| 401 | Unauthorized |
|
|
| 404 | Not Found |
|
|
`,
|
|
},
|
|
{
|
|
id: 'adr',
|
|
name: 'Architecture Decision Record',
|
|
description: 'Document an architecture decision',
|
|
category: 'planning',
|
|
icon: 'architecture',
|
|
filenamePattern: 'docs/architecture/adr-{{slug}}.md',
|
|
content: `---
|
|
tags:
|
|
- architecture
|
|
- decision
|
|
---
|
|
|
|
# ADR: {{title}}
|
|
|
|
**Date:** {{date}}
|
|
**Status:** Proposed
|
|
|
|
## Context
|
|
|
|
What is the issue that we're seeing that is motivating this decision or change?
|
|
|
|
## Decision
|
|
|
|
What is the change that we're proposing and/or doing?
|
|
|
|
## Consequences
|
|
|
|
What becomes easier or more difficult to do because of this change?
|
|
|
|
### Positive
|
|
|
|
- Benefit 1
|
|
- Benefit 2
|
|
|
|
### Negative
|
|
|
|
- Drawback 1
|
|
- Drawback 2
|
|
|
|
### Neutral
|
|
|
|
- Side effect 1
|
|
`,
|
|
},
|
|
{
|
|
id: 'faq',
|
|
name: 'FAQ Page',
|
|
description: 'Frequently asked questions with collapsible answers',
|
|
category: 'general',
|
|
icon: 'quiz',
|
|
filenamePattern: 'docs/{{slug}}.md',
|
|
content: `---
|
|
tags:
|
|
- faq
|
|
---
|
|
|
|
# {{title}}
|
|
|
|
Frequently asked questions about this topic.
|
|
|
|
??? question "Question 1?"
|
|
|
|
Answer to question 1. You can include **formatting**, links, and code blocks.
|
|
|
|
??? question "Question 2?"
|
|
|
|
Answer to question 2.
|
|
|
|
\`\`\`bash
|
|
# Example command
|
|
echo "hello world"
|
|
\`\`\`
|
|
|
|
??? question "Question 3?"
|
|
|
|
Answer to question 3.
|
|
`,
|
|
},
|
|
{
|
|
id: 'release-notes',
|
|
name: 'Release Notes',
|
|
description: 'Release notes for a version',
|
|
category: 'planning',
|
|
icon: 'new_releases',
|
|
filenamePattern: 'docs/{{slug}}.md',
|
|
content: `---
|
|
tags:
|
|
- release
|
|
---
|
|
|
|
# Release Notes — {{title}}
|
|
|
|
**Release Date:** {{date}}
|
|
|
|
## Highlights
|
|
|
|
Brief summary of the most important changes.
|
|
|
|
## New Features
|
|
|
|
- **Feature Name** — Description of the new feature
|
|
|
|
## Improvements
|
|
|
|
- **Improvement** — Description of the improvement
|
|
|
|
## Bug Fixes
|
|
|
|
- **Fix** — Description of what was fixed
|
|
|
|
## Breaking Changes
|
|
|
|
!!! warning "Breaking Changes"
|
|
List any breaking changes that require user action.
|
|
|
|
## Upgrade Instructions
|
|
|
|
Steps needed to upgrade from the previous version.
|
|
`,
|
|
},
|
|
{
|
|
id: 'tutorial',
|
|
name: 'Tutorial',
|
|
description: 'In-depth tutorial with learning objectives',
|
|
category: 'guide',
|
|
icon: 'school',
|
|
filenamePattern: 'docs/{{slug}}.md',
|
|
content: `---
|
|
tags:
|
|
- tutorial
|
|
---
|
|
|
|
# {{title}}
|
|
|
|
## What You'll Learn
|
|
|
|
By the end of this tutorial, you will be able to:
|
|
|
|
- Learning objective 1
|
|
- Learning objective 2
|
|
- Learning objective 3
|
|
|
|
## Prerequisites
|
|
|
|
!!! info "Before you begin"
|
|
- Prerequisite 1
|
|
- Prerequisite 2
|
|
|
|
## Part 1: Setup
|
|
|
|
Content for part 1...
|
|
|
|
## Part 2: Implementation
|
|
|
|
Content for part 2...
|
|
|
|
## Part 3: Testing
|
|
|
|
Content for part 3...
|
|
|
|
## Summary
|
|
|
|
Recap of what was covered and next steps.
|
|
|
|
## Further Reading
|
|
|
|
- [Related Guide 1](link)
|
|
- [Related Guide 2](link)
|
|
`,
|
|
},
|
|
{
|
|
id: 'meeting-notes',
|
|
name: 'Meeting Notes',
|
|
description: 'Meeting notes template with agenda and action items',
|
|
category: 'general',
|
|
icon: 'groups',
|
|
filenamePattern: 'docs/{{slug}}.md',
|
|
content: `---
|
|
tags:
|
|
- meeting
|
|
---
|
|
|
|
# {{title}}
|
|
|
|
**Date:** {{date}}
|
|
**Attendees:**
|
|
|
|
## Agenda
|
|
|
|
1. Item 1
|
|
2. Item 2
|
|
3. Item 3
|
|
|
|
## Discussion Notes
|
|
|
|
### Topic 1
|
|
|
|
Notes...
|
|
|
|
### Topic 2
|
|
|
|
Notes...
|
|
|
|
## Action Items
|
|
|
|
- [ ] Action item 1 — @assignee — due date
|
|
- [ ] Action item 2 — @assignee — due date
|
|
|
|
## Next Meeting
|
|
|
|
Date and topics for next meeting.
|
|
`,
|
|
},
|
|
];
|
|
|
|
function getTemplates(): DocTemplate[] {
|
|
return BUILT_IN_TEMPLATES;
|
|
}
|
|
|
|
function applyTemplate(
|
|
templateId: string,
|
|
variables: { title: string; date?: string; slug?: string; author?: string },
|
|
): { content: string; suggestedPath: string } | null {
|
|
const template = BUILT_IN_TEMPLATES.find(t => t.id === templateId);
|
|
if (!template) return null;
|
|
|
|
const date = variables.date || today();
|
|
const slug = variables.slug || slugify(variables.title);
|
|
const author = variables.author || 'admin';
|
|
|
|
let content = template.content
|
|
.replace(/\{\{title\}\}/g, variables.title)
|
|
.replace(/\{\{date\}\}/g, date)
|
|
.replace(/\{\{slug\}\}/g, slug)
|
|
.replace(/\{\{author\}\}/g, author);
|
|
|
|
let suggestedPath = template.filenamePattern
|
|
.replace(/\{\{title\}\}/g, variables.title)
|
|
.replace(/\{\{date\}\}/g, date)
|
|
.replace(/\{\{slug\}\}/g, slug);
|
|
|
|
return { content, suggestedPath };
|
|
}
|
|
|
|
function slugify(text: string): string {
|
|
return text
|
|
.toLowerCase()
|
|
.replace(/[^a-z0-9\s-]/g, '')
|
|
.replace(/\s+/g, '-')
|
|
.replace(/-+/g, '-')
|
|
.replace(/^-|-$/g, '')
|
|
.substring(0, 80);
|
|
}
|
|
|
|
export const docsTemplatesService = {
|
|
getTemplates,
|
|
applyTemplate,
|
|
};
|