Enhance README and UI for documentation viewer; improve navigation, styling, and folder organization, added folder pages

This commit is contained in:
2025-02-09 01:50:26 +11:00
parent 50064853bc
commit 95005d05f6
4 changed files with 119 additions and 77 deletions

123
README.md
View File

@@ -1,100 +1,79 @@
# Documentation Viewer # Documentation Viewer
A lightweight, static documentation viewer that renders Markdown files with syntax highlighting. Built as a single-page application with no backend requirements. A robust, modern documentation viewer built for rendering Markdown files with advanced syntax highlighting capabilities. This zero-dependency static application enables seamless documentation hosting without backend requirements.
## Features ## Features
- 📝 Renders Markdown documents with syntax highlighting - 🚀 **High-Performance Rendering** - Lightning-fast Markdown processing with optimized syntax highlighting
- 📑 Document outline/table of contents - 📑 **Dynamic Navigation** - Auto-generated document outline with interactive table of contents
- 📱 Responsive design with mobile support - 📱 **Responsive Design** - Optimized viewing experience across all device sizes
- 🚀 Zero backend requirements - deploy anywhere - 🔒 **Zero Backend** - Fully static implementation for maximum security and deployability
- ⚡ Fast client-side rendering - 🎨 **Modern UI/UX** - Clean, intuitive interface with customizable theming
## Getting Started ## Quick Start
### Prerequisites ### Development Setup
- Node.js and npm (only needed for development)
### Installation
1. Clone the repository:
```sh ```sh
git clone <repository-url> git clone https://github.com/litruv/Docs-Viewer
cd <repository-directory> cd Docs-Viewer
```
2. Install dependencies (only needed for development):
```sh
npm install
``` ```
### Deployment ### Deployment
This is a static website that can be hosted on any web server or static hosting service. Simply upload all files to your hosting provider. Deploy anywhere that serves static files. For local development:
For local testing, you can use any static file server. For example:
```sh ```sh
npx live-server npx live-server
``` ```
### Usage ## Project Structure
- The file index is displayed on the left sidebar.
- Click on a file to load its content.
- The document outline is displayed on the right sidebar.
- Use the menu button to toggle the sidebar on mobile devices.
### Directory Structure
``` ```
docs/ # Your markdown documents go here .
├── images/ # Images referenced in documents ├── docs/ # Documentation source files
├── doc1.md │ ├── images/ # Document assets
└── doc2.md │ └── *.md # Markdown documents
index.html # Main entry point ├── index.html # Application entry point
config.json # Document index configuration ├── config.json # Document configuration
styles.css # Custom styling └── styles.css # Theme customization
``` ```
### Adding New Documents ## Configuration
1. Add your Markdown file to the `docs` directory. ### Document Index
2. Update to include the new document:
Configure your documentation structure in `index.json`:
```json ```json
{ {
"documents": [ "documents": [
{ {
"title": "Blueprint Depth Trace", "title": "Getting Started",
"path": "docs/Blueprint Penetration Trace.md" "path": "docs/getting-started.md"
},
{
"title": "New Document Title",
"path": "docs/NewDocument.md"
} }
] ]
} }
``` ```
## Configuring Folders ### Folder Organization
You can control whether a folder is expanded by default using `defaultOpen`. You can also specify a Font Awesome `icon`.
Both properties (`defaultOpen` and `icon`) are optional — if you omit them, the folder will use default behavior. Create hierarchical documentation structures with nested folders:
Example in index.json:
```json ```json
{ {
"folders": [ "documents": [
{ {
"title": "Folder 1", "title": "Core Concepts",
"type": "folder",
"defaultOpen": true, "defaultOpen": true,
"icon": "fa-solid fa-folder", "icon": "fa-solid fa-book",
"documents": [ "path": "docs/core-concepts/index.md",
"slug": "core-concepts",
"items": [
{ {
"title": "Document 1", "title": "Architecture",
"path": "docs/Document1.md" "path": "docs/core-concepts/architecture.md"
} }
] ]
} }
@@ -102,12 +81,30 @@ Example in index.json:
} }
``` ```
## Acknowledgements #### Folder Configuration Options
- [marked](https://github.com/markedjs/marked) for Markdown parsing. | Option | Type | Description |
- [highlight.js](https://highlightjs.org/) for syntax highlighting. |--------|------|-------------|
- [Font Awesome](https://fontawesome.com/) for icons | `type` | string | Set to `"folder"` for directory nodes |
| `title` | string | Display name |
| `path` | string? | Optional content file path |
| `slug` | string | URL-friendly identifier (required with `path`) |
| `items` | array | Nested documents or folders |
| `defaultOpen` | boolean? | Auto-expand folder |
| `icon` | string? | Custom Font Awesome class |
## Technology Stack
Built with modern web technologies and carefully selected dependencies:
- [marked](https://github.com/markedjs/marked) - Markdown processing
- [highlight.js](https://highlightjs.org/) - Syntax highlighting
- [Font Awesome](https://fontawesome.com/) - UI iconography
## License ## License
This project is licensed under the MIT License. Released under the MIT License. See [LICENSE](LICENSE) for details.
## Contributing
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details.

View File

@@ -55,12 +55,23 @@ function createFileIndexItem(doc, container, level = 0) {
const folderHeader = document.createElement('div'); const folderHeader = document.createElement('div');
folderHeader.className = 'folder-header'; folderHeader.className = 'folder-header';
// Use custom icon if provided, otherwise use default folder icon
const iconClass = doc.icon || `fas fa-folder${doc.defaultOpen !== false ? '-open' : ''}`; const iconClass = doc.icon || `fas fa-folder${doc.defaultOpen !== false ? '-open' : ''}`;
folderHeader.innerHTML = `
// Put file icon before folder icon
const headerContent = doc.path ?
`<div class="folder-icons">
<a href="?${doc.slug}" class="folder-link" title="View folder page">
<i class="fas fa-file-alt"></i>
</a>
<i class="${iconClass} folder-icon"></i> <i class="${iconClass} folder-icon"></i>
<span>${doc.title}</span> </div>
`; <span>${doc.title}</span>` :
`<div class="folder-icons">
<i class="${iconClass} folder-icon"></i>
</div>
<span>${doc.title}</span>`;
folderHeader.innerHTML = headerContent;
folderDiv.appendChild(folderHeader); folderDiv.appendChild(folderHeader);
const folderContent = document.createElement('div'); const folderContent = document.createElement('div');
@@ -68,9 +79,21 @@ function createFileIndexItem(doc, container, level = 0) {
doc.items.forEach(item => createFileIndexItem(item, folderContent, level + 1)); doc.items.forEach(item => createFileIndexItem(item, folderContent, level + 1));
folderDiv.appendChild(folderContent); folderDiv.appendChild(folderContent);
folderHeader.addEventListener('click', () => { // Make entire header toggle folder
folderHeader.addEventListener('click', (e) => {
// Don't toggle if clicking the folder link
if (e.target.closest('.folder-link')) {
e.preventDefault();
loadDocument(doc.path);
history.pushState(null, '', `?${doc.slug}`);
if (window.innerWidth <= 1000) {
document.querySelector('.left-sidebar').classList.remove('show');
}
return;
}
folderDiv.classList.toggle('open'); folderDiv.classList.toggle('open');
if (!doc.icon) { // Only toggle folder icon if using default if (!doc.icon) {
folderHeader.querySelector('.folder-icon').classList.toggle('fa-folder-closed'); folderHeader.querySelector('.folder-icon').classList.toggle('fa-folder-closed');
folderHeader.querySelector('.folder-icon').classList.toggle('fa-folder-open'); folderHeader.querySelector('.folder-icon').classList.toggle('fa-folder-open');
} }

View File

@@ -8,6 +8,8 @@
{ {
"title": "Unreal Engine", "title": "Unreal Engine",
"type": "folder", "type": "folder",
"path": "docs/unreal-engine.md",
"slug": "unreal-engine",
"items": [ "items": [
{ {
"title": "DeepImpact", "title": "DeepImpact",

View File

@@ -188,19 +188,39 @@ body {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.5rem; gap: 0.5rem;
padding: 0.4rem 1.2rem; padding: 0.4rem 0rem;
cursor: pointer; cursor: pointer;
user-select: none; user-select: none;
font-size: 0.875rem; font-size: 0.875rem;
} }
.folder-header:hover { .folder-link {
background-color: rgba(0, 0, 0, 0.05); display: flex;
align-items: center;
color: var(--ifm-color-content-secondary);
opacity: 0.6;
font-size: 0.8em;
padding: 2px;
border-radius: 3px;
margin-left: 0.25rem; /* Add spacing between file and folder icons */
} }
.folder-icon { .folder-header:hover .folder-link {
width: 1.2em; opacity: 0.8;
}
.folder-link:hover {
opacity: 1 !important;
color: var(--ifm-color-primary);
background-color: rgba(255, 255, 255, 0.05);
}
.folder-icons {
display: flex;
align-items: center;
gap: 0.25rem;
color: var(--ifm-color-content-secondary); color: var(--ifm-color-content-secondary);
min-width: 2.5em; /* Ensure consistent spacing */
} }
.folder-content { .folder-content {