mirror of
https://github.com/zadam/trilium.git
synced 2025-10-20 15:19:01 +02:00
feat(docs): create docs.triliumnotes.org as additional place to serve user-facing docs (#6889)
This commit is contained in:
commit
1d82308c43
181
.github/workflows/deploy-docs.yml
vendored
Normal file
181
.github/workflows/deploy-docs.yml
vendored
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
# GitHub Actions workflow for deploying MkDocs documentation to Cloudflare Pages
|
||||||
|
# This workflow builds and deploys your MkDocs site when changes are pushed to main
|
||||||
|
name: Deploy MkDocs Documentation
|
||||||
|
|
||||||
|
on:
|
||||||
|
# Trigger on push to main branch
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- master # Also support master branch
|
||||||
|
# Only run when docs files change
|
||||||
|
paths:
|
||||||
|
- 'docs/**'
|
||||||
|
- 'mkdocs.yml'
|
||||||
|
- 'requirements-docs.txt'
|
||||||
|
- '.github/workflows/deploy-docs.yml'
|
||||||
|
- 'scripts/fix-mkdocs-structure.ts'
|
||||||
|
|
||||||
|
# Allow manual triggering from Actions tab
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
# Run on pull requests for preview deployments
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- master
|
||||||
|
paths:
|
||||||
|
- 'docs/**'
|
||||||
|
- 'mkdocs.yml'
|
||||||
|
- 'requirements-docs.txt'
|
||||||
|
- '.github/workflows/deploy-docs.yml'
|
||||||
|
- 'scripts/fix-mkdocs-structure.ts'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-deploy:
|
||||||
|
name: Build and Deploy MkDocs
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 10
|
||||||
|
|
||||||
|
# Required permissions for deployment
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
deployments: write
|
||||||
|
pull-requests: write # For PR preview comments
|
||||||
|
id-token: write # For OIDC authentication (if needed)
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout Repository
|
||||||
|
uses: actions/checkout@v5
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # Fetch all history for git info and mkdocs-git-revision-date plugin
|
||||||
|
|
||||||
|
- name: Setup Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.13'
|
||||||
|
cache: 'pip'
|
||||||
|
cache-dependency-path: 'requirements-docs.txt'
|
||||||
|
|
||||||
|
- name: Install MkDocs and Dependencies
|
||||||
|
run: |
|
||||||
|
pip install --upgrade pip
|
||||||
|
pip install -r requirements-docs.txt
|
||||||
|
env:
|
||||||
|
PIP_DISABLE_PIP_VERSION_CHECK: 1
|
||||||
|
|
||||||
|
# Setup pnpm before fixing docs structure
|
||||||
|
- name: Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
|
||||||
|
# Setup Node.js with pnpm
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
cache: 'pnpm'
|
||||||
|
|
||||||
|
# Install Node.js dependencies for the TypeScript script
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: |
|
||||||
|
pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Fix Documentation Structure
|
||||||
|
run: |
|
||||||
|
# Fix duplicate navigation entries by moving overview pages to index.md
|
||||||
|
pnpm run chore:fix-mkdocs-structure
|
||||||
|
|
||||||
|
- name: Build MkDocs Site
|
||||||
|
run: |
|
||||||
|
# Build with strict mode but allow expected warnings
|
||||||
|
mkdocs build --verbose || {
|
||||||
|
EXIT_CODE=$?
|
||||||
|
# Check if the only issue is expected warnings
|
||||||
|
if mkdocs build 2>&1 | grep -E "WARNING.*(README|not found)" && \
|
||||||
|
[ $(mkdocs build 2>&1 | grep -c "ERROR") -eq 0 ]; then
|
||||||
|
echo "✅ Build succeeded with expected warnings"
|
||||||
|
mkdocs build --verbose
|
||||||
|
else
|
||||||
|
echo "❌ Build failed with unexpected errors"
|
||||||
|
exit $EXIT_CODE
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
- name: Validate Built Site
|
||||||
|
run: |
|
||||||
|
# Basic validation that important files exist
|
||||||
|
test -f site/index.html || (echo "ERROR: site/index.html not found" && exit 1)
|
||||||
|
test -f site/sitemap.xml || (echo "ERROR: site/sitemap.xml not found" && exit 1)
|
||||||
|
test -d site/assets || (echo "ERROR: site/assets directory not found" && exit 1)
|
||||||
|
echo "✅ Site validation passed"
|
||||||
|
|
||||||
|
# Install wrangler globally to avoid workspace issues
|
||||||
|
- name: Install Wrangler
|
||||||
|
run: |
|
||||||
|
npm install -g wrangler
|
||||||
|
|
||||||
|
# Deploy using Wrangler (use pre-installed wrangler)
|
||||||
|
- name: Deploy to Cloudflare Pages
|
||||||
|
id: deploy
|
||||||
|
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
|
||||||
|
uses: cloudflare/wrangler-action@v3
|
||||||
|
with:
|
||||||
|
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
|
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
|
command: pages deploy site --project-name=trilium-docs --branch=${{ github.ref_name }}
|
||||||
|
wranglerVersion: '' # Use pre-installed version
|
||||||
|
|
||||||
|
# Deploy preview for PRs
|
||||||
|
- name: Deploy Preview to Cloudflare Pages
|
||||||
|
id: preview-deployment
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
uses: cloudflare/wrangler-action@v3
|
||||||
|
with:
|
||||||
|
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
|
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
|
command: pages deploy site --project-name=trilium-docs --branch=pr-${{ github.event.pull_request.number }}
|
||||||
|
wranglerVersion: '' # Use pre-installed version
|
||||||
|
|
||||||
|
# Post deployment URL as PR comment
|
||||||
|
- name: Comment PR with Preview URL
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
script: |
|
||||||
|
const prNumber = context.issue.number;
|
||||||
|
// Construct preview URL based on Cloudflare Pages pattern
|
||||||
|
const previewUrl = `https://pr-${prNumber}.trilium-docs.pages.dev`;
|
||||||
|
const mainUrl = 'https://docs.triliumnotes.org';
|
||||||
|
|
||||||
|
// Check if we already commented
|
||||||
|
const comments = await github.rest.issues.listComments({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: prNumber
|
||||||
|
});
|
||||||
|
|
||||||
|
const botComment = comments.data.find(comment =>
|
||||||
|
comment.user.type === 'Bot' &&
|
||||||
|
comment.body.includes('Documentation preview is ready')
|
||||||
|
);
|
||||||
|
|
||||||
|
const commentBody = `📚 Documentation preview is ready!\n\n🔗 Preview URL: ${previewUrl}\n📖 Production URL: ${mainUrl}\n\n✅ All checks passed\n\n_This preview will be updated automatically with new commits._`;
|
||||||
|
|
||||||
|
if (botComment) {
|
||||||
|
// Update existing comment
|
||||||
|
await github.rest.issues.updateComment({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
comment_id: botComment.id,
|
||||||
|
body: commentBody
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Create new comment
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
issue_number: prNumber,
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
body: commentBody
|
||||||
|
});
|
||||||
|
}
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -46,3 +46,6 @@ upload
|
|||||||
|
|
||||||
/result
|
/result
|
||||||
.svelte-kit
|
.svelte-kit
|
||||||
|
|
||||||
|
# docs
|
||||||
|
site/
|
||||||
|
8
docs/.pages
vendored
Normal file
8
docs/.pages
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# Control navigation order for top-level sections
|
||||||
|
nav:
|
||||||
|
- index.md
|
||||||
|
- User Guide
|
||||||
|
- Developer Guide
|
||||||
|
- Script API
|
||||||
|
- Release Notes
|
||||||
|
- ... # Include all other directories/files not explicitly listed
|
12
docs/README.md
vendored
Normal file
12
docs/README.md
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Trilium Notes
|
||||||
|
|
||||||
|
Please see the [main documentation](index.md) or visit one of our translated versions:
|
||||||
|
|
||||||
|
- [Español](README.es.md)
|
||||||
|
- [Italiano](README.it.md)
|
||||||
|
- [日本語](README.ja.md)
|
||||||
|
- [Русский](README.ru.md)
|
||||||
|
- [简体中文](README-ZH_CN.md)
|
||||||
|
- [繁體中文](README-ZH_TW.md)
|
||||||
|
|
||||||
|
For the full application README, please visit our [GitHub repository](https://github.com/triliumnext/trilium).
|
94
docs/index.md
vendored
Normal file
94
docs/index.md
vendored
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
# Trilium Notes Documentation
|
||||||
|
|
||||||
|
Welcome to the official documentation for **Trilium Notes** - a hierarchical note-taking application with a focus on building large personal knowledge bases.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## What is Trilium Notes?
|
||||||
|
|
||||||
|
Trilium Notes is a powerful, feature-rich note-taking application designed for building and managing extensive personal knowledge bases. It offers:
|
||||||
|
|
||||||
|
- **Hierarchical organization** with unlimited nesting of notes
|
||||||
|
- **Rich text editing** with markdown support
|
||||||
|
- **Powerful search** capabilities
|
||||||
|
- **Note relations** and attributes for semantic connections
|
||||||
|
- **Scripting support** for automation and customization
|
||||||
|
- **Synchronization** between devices
|
||||||
|
- **Encryption** for sensitive notes
|
||||||
|
- **Web clipper** for saving web content
|
||||||
|
|
||||||
|
## Quick Links
|
||||||
|
|
||||||
|
<div class="grid cards" markdown>
|
||||||
|
|
||||||
|
- :material-rocket-launch-outline: **[Quick Start Guide](User%20Guide/quick-start.md)**
|
||||||
|
|
||||||
|
Get up and running with Trilium in minutes
|
||||||
|
|
||||||
|
- :material-download: **[Installation](User%20Guide/installation.md)**
|
||||||
|
|
||||||
|
Download and install Trilium on your platform
|
||||||
|
|
||||||
|
- :material-docker: **[Docker Setup](User%20Guide/docker.md)**
|
||||||
|
|
||||||
|
Deploy Trilium using Docker containers
|
||||||
|
|
||||||
|
- :material-book-open-variant: **[User Guide](User%20Guide/index.md)**
|
||||||
|
|
||||||
|
Comprehensive guide to all features
|
||||||
|
|
||||||
|
- :material-code-braces: **[Script API](Script%20API/index.md)**
|
||||||
|
|
||||||
|
Automate and extend Trilium with scripting
|
||||||
|
|
||||||
|
- :material-wrench: **[Developer Guide](Developer%20Guide/index.md)**
|
||||||
|
|
||||||
|
Contributing and development documentation
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Features Overview
|
||||||
|
|
||||||
|
### Note Organization
|
||||||
|
- Create unlimited hierarchical note structures
|
||||||
|
- Clone notes to appear in multiple locations
|
||||||
|
- Use attributes and relations for metadata
|
||||||
|
- Template system for consistent note creation
|
||||||
|
|
||||||
|
### Content Types
|
||||||
|
- **Text notes** with rich formatting
|
||||||
|
- **Code notes** with syntax highlighting
|
||||||
|
- **Canvas notes** for drawing and diagrams
|
||||||
|
- **File attachments** of any type
|
||||||
|
- **Web view** for embedded content
|
||||||
|
- **Mermaid diagrams** support
|
||||||
|
|
||||||
|
### Advanced Features
|
||||||
|
- **Full-text search** with advanced operators
|
||||||
|
- **Note map** visualization
|
||||||
|
- **Day notes** for journaling
|
||||||
|
- **Book notes** for long-form content
|
||||||
|
- **Protected notes** with encryption
|
||||||
|
- **Note versioning** and history
|
||||||
|
|
||||||
|
### Automation & Integration
|
||||||
|
- JavaScript-based scripting
|
||||||
|
- Custom widgets and themes
|
||||||
|
- REST API for external integrations
|
||||||
|
- Web clipper browser extension
|
||||||
|
- Import/export in multiple formats
|
||||||
|
|
||||||
|
## Getting Help
|
||||||
|
|
||||||
|
- **[FAQ](support/faq.md)** - Frequently asked questions
|
||||||
|
- **[Troubleshooting](support/troubleshooting.md)** - Common issues and solutions
|
||||||
|
- **[Community Forum](https://github.com/triliumnext/trilium/discussions)** - Ask questions and share tips
|
||||||
|
- **[Issue Tracker](https://github.com/triliumnext/trilium/issues)** - Report bugs and request features
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Trilium is open-source and welcomes contributions! Check out our [Contributing Guide](Developer%20Guide/contributing.md) to get started.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Trilium Notes is licensed under [AGPL-3.0](https://github.com/triliumnext/trilium/blob/master/LICENSE).
|
111
docs/javascripts/extra.js
vendored
Normal file
111
docs/javascripts/extra.js
vendored
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
// Custom JavaScript for Trilium Notes documentation
|
||||||
|
|
||||||
|
// Add smooth scrolling for anchor links
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Smooth scroll for internal links
|
||||||
|
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
||||||
|
anchor.addEventListener('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const target = document.querySelector(this.getAttribute('href'));
|
||||||
|
if (target) {
|
||||||
|
target.scrollIntoView({
|
||||||
|
behavior: 'smooth',
|
||||||
|
block: 'start'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add copy button to code blocks if not already present
|
||||||
|
const codeBlocks = document.querySelectorAll('pre code');
|
||||||
|
codeBlocks.forEach(block => {
|
||||||
|
if (!block.parentElement.querySelector('.copy-button')) {
|
||||||
|
const button = document.createElement('button');
|
||||||
|
button.className = 'copy-button';
|
||||||
|
button.textContent = 'Copy';
|
||||||
|
button.addEventListener('click', () => {
|
||||||
|
navigator.clipboard.writeText(block.textContent);
|
||||||
|
button.textContent = 'Copied!';
|
||||||
|
setTimeout(() => {
|
||||||
|
button.textContent = 'Copy';
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
block.parentElement.appendChild(button);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add external link indicators
|
||||||
|
document.querySelectorAll('a[href^="http"]').forEach(link => {
|
||||||
|
if (!link.hostname.includes('trilium')) {
|
||||||
|
link.classList.add('external-link');
|
||||||
|
link.setAttribute('target', '_blank');
|
||||||
|
link.setAttribute('rel', 'noopener noreferrer');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Platform detection for download buttons
|
||||||
|
const platform = detectPlatform();
|
||||||
|
const downloadButtons = document.querySelectorAll('.download-button');
|
||||||
|
downloadButtons.forEach(button => {
|
||||||
|
if (button.dataset.platform === platform) {
|
||||||
|
button.classList.add('recommended');
|
||||||
|
button.innerHTML += ' <span class="badge">Recommended</span>';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Detect user's platform
|
||||||
|
function detectPlatform() {
|
||||||
|
const userAgent = navigator.userAgent.toLowerCase();
|
||||||
|
if (userAgent.includes('win')) return 'windows';
|
||||||
|
if (userAgent.includes('mac')) return 'macos';
|
||||||
|
if (userAgent.includes('linux')) return 'linux';
|
||||||
|
return 'unknown';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add search shortcuts
|
||||||
|
document.addEventListener('keydown', function(e) {
|
||||||
|
// Ctrl/Cmd + K to focus search
|
||||||
|
if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
|
||||||
|
e.preventDefault();
|
||||||
|
const searchInput = document.querySelector('.md-search__input');
|
||||||
|
if (searchInput) {
|
||||||
|
searchInput.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Version selector enhancement
|
||||||
|
const versionSelector = document.querySelector('.md-version__current');
|
||||||
|
if (versionSelector) {
|
||||||
|
// Add version comparison tooltip
|
||||||
|
versionSelector.addEventListener('mouseenter', function() {
|
||||||
|
const tooltip = document.createElement('div');
|
||||||
|
tooltip.className = 'version-tooltip';
|
||||||
|
tooltip.textContent = 'Click to view other versions';
|
||||||
|
this.appendChild(tooltip);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Analytics event tracking for documentation
|
||||||
|
if (typeof gtag !== 'undefined') {
|
||||||
|
// Track external link clicks
|
||||||
|
document.querySelectorAll('a[href^="http"]').forEach(link => {
|
||||||
|
link.addEventListener('click', () => {
|
||||||
|
gtag('event', 'click', {
|
||||||
|
'event_category': 'external_link',
|
||||||
|
'event_label': link.href
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Track code copy events
|
||||||
|
document.querySelectorAll('.copy-button').forEach(button => {
|
||||||
|
button.addEventListener('click', () => {
|
||||||
|
gtag('event', 'copy_code', {
|
||||||
|
'event_category': 'engagement',
|
||||||
|
'event_label': window.location.pathname
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
13
docs/javascripts/mathjax.js
vendored
Normal file
13
docs/javascripts/mathjax.js
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// MathJax configuration for mathematical notation support
|
||||||
|
window.MathJax = {
|
||||||
|
tex: {
|
||||||
|
inlineMath: [['$', '$'], ['\\(', '\\)']],
|
||||||
|
displayMath: [['$$', '$$'], ['\\[', '\\]']],
|
||||||
|
processEscapes: true,
|
||||||
|
processEnvironments: true
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
ignoreHtmlClass: 'no-mathjax',
|
||||||
|
processHtmlClass: 'mathjax'
|
||||||
|
}
|
||||||
|
};
|
121
docs/stylesheets/extra.css
vendored
Normal file
121
docs/stylesheets/extra.css
vendored
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
/* Custom styles for Trilium Notes documentation */
|
||||||
|
|
||||||
|
/* Grid cards for homepage */
|
||||||
|
.md-typeset .grid {
|
||||||
|
display: grid;
|
||||||
|
gap: 1rem;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-typeset .grid.cards > ul {
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-typeset .grid.cards > ul > li {
|
||||||
|
border: 1px solid var(--md-default-fg-color--lightest);
|
||||||
|
border-radius: .25rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 1rem;
|
||||||
|
transition: border-color .25s, box-shadow .25s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-typeset .grid.cards > ul > li:hover {
|
||||||
|
border-color: var(--md-accent-fg-color);
|
||||||
|
box-shadow: 0 0 0 .1rem var(--md-accent-fg-color--transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Improve code block appearance */
|
||||||
|
.md-typeset pre > code {
|
||||||
|
font-size: .85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Better admonition spacing */
|
||||||
|
.md-typeset .admonition {
|
||||||
|
margin: 1.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Trilium brand colors */
|
||||||
|
:root {
|
||||||
|
--trilium-primary: #4a5568;
|
||||||
|
--trilium-accent: #805ad5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom badge styles */
|
||||||
|
.badge {
|
||||||
|
background-color: var(--md-accent-fg-color);
|
||||||
|
border-radius: .125rem;
|
||||||
|
color: var(--md-accent-bg-color);
|
||||||
|
display: inline-block;
|
||||||
|
font-size: .75rem;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: .125rem .375rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Version badge */
|
||||||
|
.version-badge {
|
||||||
|
background-color: var(--md-primary-fg-color);
|
||||||
|
margin-left: .5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Platform badges */
|
||||||
|
.platform-badge {
|
||||||
|
margin: 0 .25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-badge.windows {
|
||||||
|
background-color: #0078d4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-badge.macos {
|
||||||
|
background-color: #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-badge.linux {
|
||||||
|
background-color: #fcc624;
|
||||||
|
color: #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Improve table readability */
|
||||||
|
.md-typeset table:not([class]) {
|
||||||
|
font-size: .85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-typeset table:not([class]) th {
|
||||||
|
background-color: var(--md-default-bg-color);
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* API reference styling */
|
||||||
|
.api-method {
|
||||||
|
background-color: var(--md-code-bg-color);
|
||||||
|
border-radius: .125rem;
|
||||||
|
font-family: var(--md-code-font-family);
|
||||||
|
font-weight: 600;
|
||||||
|
padding: .125rem .25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.api-method.get {
|
||||||
|
color: #10b981;
|
||||||
|
}
|
||||||
|
|
||||||
|
.api-method.post {
|
||||||
|
color: #3b82f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.api-method.put {
|
||||||
|
color: #f59e0b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.api-method.delete {
|
||||||
|
color: #ef4444;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive improvements */
|
||||||
|
@media screen and (max-width: 76.1875em) {
|
||||||
|
.md-typeset .grid {
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
|
||||||
|
}
|
||||||
|
}
|
191
mkdocs.yml
Normal file
191
mkdocs.yml
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
# MkDocs configuration for Trilium Notes documentation
|
||||||
|
site_name: Trilium Notes Documentation
|
||||||
|
site_url: https://docs.triliumnext.com
|
||||||
|
site_description: Trilium Notes is a hierarchical note taking application with focus on building large personal knowledge bases
|
||||||
|
site_author: Trilium Notes Team
|
||||||
|
|
||||||
|
# Repository information
|
||||||
|
repo_name: triliumnext/trilium
|
||||||
|
repo_url: https://github.com/triliumnext/trilium
|
||||||
|
edit_uri: edit/main/docs/
|
||||||
|
|
||||||
|
# Copyright
|
||||||
|
copyright: Copyright © 2025 Trilium Notes
|
||||||
|
|
||||||
|
# Use document-style URLs to fix image paths
|
||||||
|
use_directory_urls: false
|
||||||
|
|
||||||
|
# Theme configuration
|
||||||
|
theme:
|
||||||
|
name: material
|
||||||
|
|
||||||
|
# Color scheme
|
||||||
|
palette:
|
||||||
|
# Light mode
|
||||||
|
- media: "(prefers-color-scheme: light)"
|
||||||
|
scheme: default
|
||||||
|
primary: indigo
|
||||||
|
accent: deep-purple
|
||||||
|
toggle:
|
||||||
|
icon: material/brightness-7
|
||||||
|
name: Switch to dark mode
|
||||||
|
|
||||||
|
# Dark mode
|
||||||
|
- media: "(prefers-color-scheme: dark)"
|
||||||
|
scheme: slate
|
||||||
|
primary: blue-grey
|
||||||
|
accent: deep-purple
|
||||||
|
toggle:
|
||||||
|
icon: material/brightness-4
|
||||||
|
name: Switch to light mode
|
||||||
|
|
||||||
|
# Font configuration
|
||||||
|
font:
|
||||||
|
text: Inter
|
||||||
|
code: JetBrains Mono
|
||||||
|
|
||||||
|
# Features
|
||||||
|
features:
|
||||||
|
- announce.dismiss
|
||||||
|
- content.action.edit
|
||||||
|
- content.action.view
|
||||||
|
- content.code.annotate
|
||||||
|
- content.code.copy
|
||||||
|
- content.tooltips
|
||||||
|
- navigation.footer
|
||||||
|
- navigation.indexes
|
||||||
|
- navigation.instant
|
||||||
|
- navigation.instant.prefetch
|
||||||
|
- navigation.instant.progress
|
||||||
|
- navigation.path
|
||||||
|
- navigation.prune
|
||||||
|
- navigation.sections
|
||||||
|
- navigation.tabs
|
||||||
|
- navigation.tabs.sticky
|
||||||
|
- navigation.top
|
||||||
|
- navigation.tracking
|
||||||
|
- search.highlight
|
||||||
|
- search.share
|
||||||
|
- search.suggest
|
||||||
|
- toc.follow
|
||||||
|
- toc.integrate
|
||||||
|
|
||||||
|
# Icons
|
||||||
|
icon:
|
||||||
|
logo: material/note-multiple
|
||||||
|
repo: fontawesome/brands/github
|
||||||
|
|
||||||
|
# Plugins
|
||||||
|
plugins:
|
||||||
|
- search:
|
||||||
|
separator: '[\s\-,:!=\[\]()"`/]+|\.(?!\d)|&[lg]t;|(?!\b)(?=[A-Z][a-z])'
|
||||||
|
lang:
|
||||||
|
- en
|
||||||
|
- awesome-pages:
|
||||||
|
collapse_single_pages: false
|
||||||
|
strict: false
|
||||||
|
order: asc
|
||||||
|
sort_type: natural
|
||||||
|
order_by: title
|
||||||
|
- minify:
|
||||||
|
minify_html: true
|
||||||
|
minify_js: true
|
||||||
|
minify_css: true
|
||||||
|
htmlmin_opts:
|
||||||
|
remove_comments: true
|
||||||
|
- git-revision-date-localized:
|
||||||
|
enable_creation_date: true
|
||||||
|
type: iso_datetime
|
||||||
|
fallback_to_build_date: true
|
||||||
|
|
||||||
|
# Extensions
|
||||||
|
markdown_extensions:
|
||||||
|
# Python Markdown
|
||||||
|
- abbr
|
||||||
|
- admonition
|
||||||
|
- attr_list
|
||||||
|
- def_list
|
||||||
|
- footnotes
|
||||||
|
- md_in_html
|
||||||
|
- toc:
|
||||||
|
permalink: true
|
||||||
|
permalink_title: Anchor link to this section for reference
|
||||||
|
|
||||||
|
# Python Markdown Extensions
|
||||||
|
- pymdownx.arithmatex:
|
||||||
|
generic: true
|
||||||
|
- pymdownx.betterem:
|
||||||
|
smart_enable: all
|
||||||
|
- pymdownx.caret
|
||||||
|
- pymdownx.details
|
||||||
|
- pymdownx.emoji:
|
||||||
|
emoji_index: !!python/name:material.extensions.emoji.twemoji
|
||||||
|
emoji_generator: !!python/name:material.extensions.emoji.to_svg
|
||||||
|
- pymdownx.highlight:
|
||||||
|
anchor_linenums: true
|
||||||
|
line_spans: __span
|
||||||
|
pygments_lang_class: true
|
||||||
|
- pymdownx.inlinehilite
|
||||||
|
- pymdownx.keys
|
||||||
|
- pymdownx.mark
|
||||||
|
- pymdownx.smartsymbols
|
||||||
|
- pymdownx.snippets
|
||||||
|
- pymdownx.superfences:
|
||||||
|
custom_fences:
|
||||||
|
- name: mermaid
|
||||||
|
class: mermaid
|
||||||
|
format: !!python/name:pymdownx.superfences.fence_code_format
|
||||||
|
- pymdownx.tabbed:
|
||||||
|
alternate_style: true
|
||||||
|
combine_header_slug: true
|
||||||
|
- pymdownx.tasklist:
|
||||||
|
custom_checkbox: true
|
||||||
|
- pymdownx.tilde
|
||||||
|
|
||||||
|
# Extra CSS and JavaScript (if needed)
|
||||||
|
extra_css:
|
||||||
|
- stylesheets/extra.css
|
||||||
|
|
||||||
|
extra_javascript:
|
||||||
|
- javascripts/extra.js
|
||||||
|
# MathJax for mathematical notation
|
||||||
|
- javascripts/mathjax.js
|
||||||
|
- https://unpkg.com/mathjax@3/es5/tex-mml-chtml.js
|
||||||
|
|
||||||
|
# Extra configuration
|
||||||
|
extra:
|
||||||
|
# Social links
|
||||||
|
social:
|
||||||
|
- icon: fontawesome/brands/github
|
||||||
|
link: https://github.com/triliumnext/trilium
|
||||||
|
- icon: fontawesome/brands/docker
|
||||||
|
link: https://hub.docker.com/r/triliumnext/trilium
|
||||||
|
- icon: fontawesome/solid/globe
|
||||||
|
link: https://trilium.cc
|
||||||
|
|
||||||
|
# Analytics (optional - add your own if needed)
|
||||||
|
analytics:
|
||||||
|
provider: google
|
||||||
|
property: G-XXXXXXXXXX # Replace with your Google Analytics ID
|
||||||
|
feedback:
|
||||||
|
title: Was this page helpful?
|
||||||
|
ratings:
|
||||||
|
- icon: material/emoticon-happy-outline
|
||||||
|
name: This page was helpful
|
||||||
|
data: 1
|
||||||
|
note: >-
|
||||||
|
Thanks for your feedback!
|
||||||
|
- icon: material/emoticon-sad-outline
|
||||||
|
name: This page could be improved
|
||||||
|
data: 0
|
||||||
|
note: >-
|
||||||
|
Thanks for your feedback! Help us improve this page by
|
||||||
|
<a href="https://github.com/triliumnext/trilium/issues/new/?title=[Feedback]+{title}+-+{url}" target="_blank" rel="noopener">opening an issue</a>.
|
||||||
|
|
||||||
|
# Version
|
||||||
|
version:
|
||||||
|
provider: mike
|
||||||
|
default: stable
|
||||||
|
|
||||||
|
# Navigation is automatically generated from folder structure by awesome-pages plugin
|
||||||
|
# To customize order or titles, create .pages files in directories
|
@ -24,6 +24,7 @@
|
|||||||
"chore:generate-openapi": "tsx ./scripts/generate-openapi.ts",
|
"chore:generate-openapi": "tsx ./scripts/generate-openapi.ts",
|
||||||
"chore:update-build-info": "tsx ./scripts/update-build-info.ts",
|
"chore:update-build-info": "tsx ./scripts/update-build-info.ts",
|
||||||
"chore:update-version": "tsx ./scripts/update-version.ts",
|
"chore:update-version": "tsx ./scripts/update-version.ts",
|
||||||
|
"chore:fix-mkdocs-structure": "tsx ./scripts/fix-mkdocs-structure.ts",
|
||||||
"edit-docs:edit-docs": "pnpm run --filter edit-docs edit-docs",
|
"edit-docs:edit-docs": "pnpm run --filter edit-docs edit-docs",
|
||||||
"edit-docs:edit-demo": "pnpm run --filter edit-docs edit-demo",
|
"edit-docs:edit-demo": "pnpm run --filter edit-docs edit-demo",
|
||||||
"test:all": "pnpm test:parallel && pnpm test:sequential",
|
"test:all": "pnpm test:parallel && pnpm test:sequential",
|
||||||
|
21
requirements-docs.txt
Normal file
21
requirements-docs.txt
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# MkDocs and Material theme requirements for Trilium documentation
|
||||||
|
mkdocs>=1.6.0
|
||||||
|
mkdocs-material>=9.5.0
|
||||||
|
mkdocs-material-extensions>=1.3.0
|
||||||
|
|
||||||
|
# Essential plugins
|
||||||
|
mkdocs-awesome-pages-plugin>=2.9.0 # Auto-generate navigation from folder structure
|
||||||
|
mkdocs-minify-plugin>=0.8.0
|
||||||
|
mkdocs-git-revision-date-localized-plugin>=1.2.0
|
||||||
|
|
||||||
|
# Optional but recommended plugins
|
||||||
|
mkdocs-redirects>=1.2.0
|
||||||
|
mkdocs-rss-plugin>=1.12.0
|
||||||
|
mkdocs-glightbox>=0.3.0
|
||||||
|
|
||||||
|
# For advanced features
|
||||||
|
pillow>=10.0.0 # For social cards generation
|
||||||
|
cairosvg>=2.7.0 # For social cards with SVG support
|
||||||
|
|
||||||
|
# Search enhancements
|
||||||
|
mkdocs-material[imaging]>=9.5.0
|
308
scripts/fix-mkdocs-structure.ts
Normal file
308
scripts/fix-mkdocs-structure.ts
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
/**
|
||||||
|
* Fix MkDocs structure by moving overview pages to index.md inside their directories.
|
||||||
|
* This prevents duplicate navigation entries when a file and directory have the same name.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
interface FixResult {
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find markdown files that have a corresponding directory with the same name,
|
||||||
|
* and move them to index.md inside that directory.
|
||||||
|
*/
|
||||||
|
function fixDuplicateEntries(docsDir: string): FixResult[] {
|
||||||
|
const fixesMade: FixResult[] = [];
|
||||||
|
|
||||||
|
function walkDir(dir: string): void {
|
||||||
|
let files: string[];
|
||||||
|
try {
|
||||||
|
files = fs.readdirSync(dir);
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(`Warning: Unable to read directory ${dir}: ${err.message}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
const filePath = path.join(dir, file);
|
||||||
|
let stat: fs.Stats;
|
||||||
|
|
||||||
|
try {
|
||||||
|
stat = fs.statSync(filePath);
|
||||||
|
} catch (err) {
|
||||||
|
// File might have been moved already, skip it
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat.isDirectory()) {
|
||||||
|
walkDir(filePath);
|
||||||
|
} else if (file.endsWith('.md')) {
|
||||||
|
const basename = file.slice(0, -3); // Remove .md extension
|
||||||
|
const dirPath = path.join(dir, basename);
|
||||||
|
|
||||||
|
// Check if there's a directory with the same name
|
||||||
|
if (fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) {
|
||||||
|
const indexPath = path.join(dirPath, 'index.md');
|
||||||
|
|
||||||
|
// Check if index.md already exists in that directory
|
||||||
|
if (!fs.existsSync(indexPath)) {
|
||||||
|
// Move the file to index.md in the directory
|
||||||
|
fs.renameSync(filePath, indexPath);
|
||||||
|
fixesMade.push({
|
||||||
|
message: `Moved ${path.relative(docsDir, filePath)} -> ${path.relative(docsDir, indexPath)}`
|
||||||
|
});
|
||||||
|
|
||||||
|
// Move associated images with pattern basename_*
|
||||||
|
try {
|
||||||
|
const dirFiles = fs.readdirSync(dir);
|
||||||
|
for (const imgFile of dirFiles) {
|
||||||
|
if (imgFile.startsWith(`${basename}_`)) {
|
||||||
|
const imgSrc = path.join(dir, imgFile);
|
||||||
|
try {
|
||||||
|
if (!fs.statSync(imgSrc).isDirectory()) {
|
||||||
|
const imgDest = path.join(dirPath, imgFile);
|
||||||
|
fs.renameSync(imgSrc, imgDest);
|
||||||
|
fixesMade.push({
|
||||||
|
message: `Moved ${path.relative(docsDir, imgSrc)} -> ${path.relative(docsDir, imgDest)}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// File might have been moved already, skip it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// Directory might not exist anymore, skip it
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move exact match images
|
||||||
|
const imgExtensions = ['.png', '.jpg', '.jpeg', '.gif', '.svg'];
|
||||||
|
for (const ext of imgExtensions) {
|
||||||
|
const imgFile = path.join(dir, `${basename}${ext}`);
|
||||||
|
if (fs.existsSync(imgFile)) {
|
||||||
|
const imgDest = path.join(dirPath, `${basename}${ext}`);
|
||||||
|
fs.renameSync(imgFile, imgDest);
|
||||||
|
fixesMade.push({
|
||||||
|
message: `Moved ${path.relative(docsDir, imgFile)} -> ${path.relative(docsDir, imgDest)}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
walkDir(docsDir);
|
||||||
|
return fixesMade;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update references in markdown files to point to the new locations.
|
||||||
|
*/
|
||||||
|
function updateReferences(docsDir: string): FixResult[] {
|
||||||
|
const updatesMade: FixResult[] = [];
|
||||||
|
|
||||||
|
function fixLink(match: string, text: string, link: string, currentDir: string, isIndex: boolean): string {
|
||||||
|
// Skip external links
|
||||||
|
if (link.startsWith('http')) {
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode URL-encoded paths for processing
|
||||||
|
// Use decodeURIComponent which is equivalent to Python's unquote
|
||||||
|
let decodedLink: string;
|
||||||
|
try {
|
||||||
|
decodedLink = decodeURIComponent(link);
|
||||||
|
} catch (err) {
|
||||||
|
// If decoding fails, use the original link
|
||||||
|
decodedLink = link;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special case: if we're in index.md and the link starts with the parent directory name
|
||||||
|
if (isIndex && decodedLink.includes('/')) {
|
||||||
|
const pathParts = decodedLink.split('/');
|
||||||
|
const parentDirName = path.basename(currentDir);
|
||||||
|
|
||||||
|
// Check if first part matches the parent directory name
|
||||||
|
if (pathParts[0] === parentDirName) {
|
||||||
|
// This is a self-referential path, strip the first part
|
||||||
|
const fixedLink = pathParts.slice(1).join('/');
|
||||||
|
// Continue processing with the fixed link
|
||||||
|
const decodedFixedLink = fixedLink;
|
||||||
|
|
||||||
|
// Check if this fixed link points to a directory with index.md
|
||||||
|
if (!decodedFixedLink.startsWith('/')) {
|
||||||
|
const resolvedPath = path.resolve(currentDir, decodedFixedLink);
|
||||||
|
|
||||||
|
if (resolvedPath.endsWith('.md')) {
|
||||||
|
const potentialDir = resolvedPath.slice(0, -3);
|
||||||
|
const potentialIndex = path.join(potentialDir, 'index.md');
|
||||||
|
|
||||||
|
if (fs.existsSync(potentialIndex)) {
|
||||||
|
// Check if they share the same parent directory
|
||||||
|
if (path.dirname(potentialDir) === path.dirname(currentDir)) {
|
||||||
|
// It's a sibling - just use directory name
|
||||||
|
const dirName = path.basename(potentialDir).replace(/ /g, '%20');
|
||||||
|
return `[${text}](${dirName}/)`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate relative path from current file to the directory
|
||||||
|
const newPath = path.relative(currentDir, potentialDir).replace(/\\/g, '/').replace(/ /g, '%20');
|
||||||
|
return `[${text}](${newPath}/)`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no special handling needed for the fixed link, return it as-is
|
||||||
|
const fixedLinkEncoded = fixedLink.replace(/ /g, '%20');
|
||||||
|
return `[${text}](${fixedLinkEncoded})`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For any .md link, check if there's a directory with index.md
|
||||||
|
if (!decodedLink.startsWith('/')) {
|
||||||
|
const resolvedPath = path.resolve(currentDir, decodedLink);
|
||||||
|
|
||||||
|
// Check if this points to a file that should be a directory
|
||||||
|
if (resolvedPath.endsWith('.md')) {
|
||||||
|
const potentialDir = resolvedPath.slice(0, -3);
|
||||||
|
const potentialIndex = path.join(potentialDir, 'index.md');
|
||||||
|
|
||||||
|
// If a directory with index.md exists, update the link
|
||||||
|
if (fs.existsSync(potentialIndex)) {
|
||||||
|
if (isIndex) {
|
||||||
|
// Check if they share the same parent directory
|
||||||
|
if (path.dirname(potentialDir) === path.dirname(currentDir)) {
|
||||||
|
// It's a sibling - just use directory name
|
||||||
|
const dirName = path.basename(potentialDir).replace(/ /g, '%20');
|
||||||
|
return `[${text}](${dirName}/)`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate relative path from current file to the directory
|
||||||
|
const newPath = path.relative(currentDir, potentialDir).replace(/\\/g, '/').replace(/ /g, '%20');
|
||||||
|
return `[${text}](${newPath}/)`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also handle local references (same directory) - should be 'if', not 'elif'
|
||||||
|
// This is intentional to handle both absolute and relative paths
|
||||||
|
if (!decodedLink.includes('/')) {
|
||||||
|
const basename = decodedLink.slice(0, -3); // Remove .md
|
||||||
|
const possibleDir = path.join(currentDir, basename);
|
||||||
|
|
||||||
|
if (fs.existsSync(possibleDir) && fs.statSync(possibleDir).isDirectory()) {
|
||||||
|
const encodedBasename = basename.replace(/ /g, '%20');
|
||||||
|
return `[${text}](${encodedBasename}/)`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
|
function walkDir(dir: string): void {
|
||||||
|
let files: string[];
|
||||||
|
try {
|
||||||
|
files = fs.readdirSync(dir);
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(`Warning: Unable to read directory ${dir}: ${err.message}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
const filePath = path.join(dir, file);
|
||||||
|
let stat: fs.Stats;
|
||||||
|
|
||||||
|
try {
|
||||||
|
stat = fs.statSync(filePath);
|
||||||
|
} catch (err) {
|
||||||
|
// File might have been moved already, skip it
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat.isDirectory()) {
|
||||||
|
walkDir(filePath);
|
||||||
|
} else if (file.endsWith('.md')) {
|
||||||
|
let content = fs.readFileSync(filePath, 'utf-8');
|
||||||
|
const originalContent = content;
|
||||||
|
|
||||||
|
const isIndex = file === 'index.md';
|
||||||
|
const currentDir = path.dirname(filePath);
|
||||||
|
|
||||||
|
// Update markdown links: [text](path.md)
|
||||||
|
const pattern = /\[([^\]]*)\]\(([^)]+\.md)\)/g;
|
||||||
|
content = content.replace(pattern, (match, text, link) => {
|
||||||
|
return fixLink(match, text, link, currentDir, isIndex);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (content !== originalContent) {
|
||||||
|
fs.writeFileSync(filePath, content, 'utf-8');
|
||||||
|
updatesMade.push({
|
||||||
|
message: `Updated references in ${path.relative(docsDir, filePath)}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
walkDir(docsDir);
|
||||||
|
return updatesMade;
|
||||||
|
}
|
||||||
|
|
||||||
|
function main(): number {
|
||||||
|
// Get the docs directory
|
||||||
|
const scriptDir = path.dirname(new URL(import.meta.url).pathname);
|
||||||
|
const projectRoot = path.dirname(scriptDir);
|
||||||
|
const docsDir = path.join(projectRoot, 'docs');
|
||||||
|
|
||||||
|
// Handle Windows paths (remove leading slash if on Windows)
|
||||||
|
const normalizedDocsDir = process.platform === 'win32' && docsDir.startsWith('/')
|
||||||
|
? docsDir.substring(1)
|
||||||
|
: docsDir;
|
||||||
|
|
||||||
|
if (!fs.existsSync(normalizedDocsDir)) {
|
||||||
|
console.error(`Error: docs directory not found at ${normalizedDocsDir}`);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Fixing MkDocs structure in ${normalizedDocsDir}`);
|
||||||
|
console.log('-'.repeat(50));
|
||||||
|
|
||||||
|
// Fix duplicate entries
|
||||||
|
const fixes = fixDuplicateEntries(normalizedDocsDir);
|
||||||
|
if (fixes.length > 0) {
|
||||||
|
console.log('Files reorganized:');
|
||||||
|
for (const fix of fixes) {
|
||||||
|
console.log(` - ${fix.message}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('No duplicate entries found that need fixing');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log();
|
||||||
|
|
||||||
|
// Update references
|
||||||
|
const updates = updateReferences(normalizedDocsDir);
|
||||||
|
if (updates.length > 0) {
|
||||||
|
console.log('References updated:');
|
||||||
|
for (const update of updates) {
|
||||||
|
console.log(` - ${update.message}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('No references needed updating');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('-'.repeat(50));
|
||||||
|
console.log(`Structure fix complete: ${fixes.length} files moved, ${updates.length} files updated`);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the main function
|
||||||
|
process.exit(main());
|
Loading…
x
Reference in New Issue
Block a user