svelte-markdown-pages
Version:
Build and render markdown-based content with distributed navigation for Svelte projects
287 lines (284 loc) • 7.97 kB
JavaScript
import { marked } from 'marked';
// src/renderer/navigation.ts
var NavigationTree = class {
constructor(data) {
this._flatItems = [];
this._pathMap = /* @__PURE__ */ new Map();
this._items = data.items;
this._buildIndexes();
}
get items() {
return this._items;
}
get flatItems() {
return this._flatItems;
}
findItemByPath(path) {
return this._pathMap.get(path);
}
findItemByName(name) {
return this._findItemByNameRecursive(this._items, name);
}
getBreadcrumbs(path) {
const item = this.findItemByPath(path);
if (!item) {
return [];
}
const breadcrumbs = [];
let current = item;
while (current) {
breadcrumbs.unshift(current);
current = current.parent;
}
return breadcrumbs;
}
getSiblings(path) {
const item = this.findItemByPath(path);
if (!item || !item.parent) {
return this._items;
}
return item.parent.items || [];
}
getNextSibling(path) {
const siblings = this.getSiblings(path);
const currentIndex = siblings.findIndex((item) => item.path === path);
if (currentIndex === -1 || currentIndex === siblings.length - 1) {
return void 0;
}
return siblings[currentIndex + 1];
}
getPreviousSibling(path) {
const siblings = this.getSiblings(path);
const currentIndex = siblings.findIndex((item) => item.path === path);
if (currentIndex <= 0) {
return void 0;
}
return siblings[currentIndex - 1];
}
getChildren(path) {
let item = this.findItemByName(path);
if (!item) {
item = this.findItemByPath(path);
}
if (!item && path.includes("/")) {
const pathParts = path.split("/");
const sectionName = pathParts[pathParts.length - 1];
if (sectionName) {
item = this.findItemByName(sectionName);
}
}
return item?.items || [];
}
isExpanded(path) {
const item = this.findItemByName(path) || this.findItemByPath(path);
return item ? !item.collapsed : false;
}
toggleExpanded(path) {
const item = this.findItemByName(path) || this.findItemByPath(path);
if (item) {
item.collapsed = !item.collapsed;
}
}
_buildIndexes() {
this._flatItems = [];
this._pathMap.clear();
this._buildIndexesRecursive(this._items, void 0);
}
_buildIndexesRecursive(items, parent) {
for (const item of items) {
item.parent = parent || void 0;
this._flatItems.push(item);
if (item.path) {
this._pathMap.set(item.path, item);
}
if (item.items) {
this._buildIndexesRecursive(item.items, item);
}
}
}
_findItemByNameRecursive(items, name) {
for (const item of items) {
if (item.name === name) {
return item;
}
if (item.items) {
const found = this._findItemByNameRecursive(item.items, name);
if (found) {
return found;
}
}
}
return void 0;
}
};
function createNavigationTree(data) {
return new NavigationTree(data);
}
var ContentLoader = class {
constructor(content, processor) {
this.content = content;
this.processor = processor;
}
loadContent(path) {
return this.content[path];
}
loadAndProcess(path) {
const content = this.loadContent(path);
if (!content) {
return void 0;
}
return this.processContent(content);
}
processContent(content) {
if (this.processor) {
content = this.processor.process(content);
}
return marked(content);
}
hasContent(path) {
return path in this.content;
}
getAvailablePaths() {
return Object.keys(this.content);
}
getContentSize(path) {
const content = this.loadContent(path);
return content ? content.length : 0;
}
getTotalContentSize() {
return Object.values(this.content).reduce((total, content) => total + content.length, 0);
}
};
async function loadContent(path, contentBundle, processor) {
const loader = new ContentLoader(contentBundle, processor);
return loader.loadAndProcess(path);
}
function createContentLoader(contentBundle, processor) {
return new ContentLoader(contentBundle, processor);
}
function extractHeadings(content) {
const headings = [];
const lines = content.split("\n");
for (const line of lines) {
const match = line.match(/^(#{1,6})\s+(.+)$/);
if (match && match[1] && match[2]) {
const level = match[1].length;
const text = match[2].trim();
const id = text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
headings.push({ level, text, id });
}
}
return headings;
}
function extractTableOfContents(content) {
const headings = extractHeadings(content);
if (headings.length === 0) {
return "";
}
const toc = ["## Table of Contents", ""];
for (const heading of headings) {
const indent = " ".repeat(heading.level - 1);
toc.push(`${indent}- [${heading.text}](#${heading.id})`);
}
return toc.join("\n");
}
function addTableOfContents(content) {
const toc = extractTableOfContents(content);
if (!toc) {
return content;
}
const lines = content.split("\n");
const firstHeadingIndex = lines.findIndex((line) => line.match(/^#{1,6}\s+/));
if (firstHeadingIndex === -1) {
return content;
}
lines.splice(firstHeadingIndex + 1, 0, toc, "");
return lines.join("\n");
}
// src/renderer/components.ts
var DocsSidebarClass = class {
constructor(props) {
this.props = props;
}
render() {
return `
<nav class="docs-sidebar ${this.props.collapsed ? "collapsed" : ""}">
${this.renderNavigationItems(this.props.navigation.items)}
</nav>
`;
}
renderNavigationItems(items) {
return items.map((item) => {
if (item.type === "section") {
return `
<div class="nav-section">
<div class="nav-section-header">${item.label}</div>
${item.items ? this.renderNavigationItems(item.items) : ""}
</div>
`;
} else {
const isActive = this.props.currentPage === item.path;
return `
<a href="#"
class="nav-link ${isActive ? "active" : ""}"
data-path="${item.path}"
onclick="this.dispatchEvent(new CustomEvent('pageSelect', {detail: '${item.path}'}))">
${item.label}
</a>
`;
}
}).join("");
}
};
var DocsContentClass = class {
constructor(props) {
this.props = props;
}
render() {
if (this.props.loading) {
return '<div class="docs-content loading">Loading...</div>';
}
if (this.props.error) {
return `<div class="docs-content error">Error: ${this.props.error}</div>`;
}
if (!this.props.content) {
return '<div class="docs-content empty">No content selected</div>';
}
return `
<div class="docs-content">
${this.props.title ? `<h1>${this.props.title}</h1>` : ""}
<div class="content-body">
${this.props.content}
</div>
</div>
`;
}
};
function createDocsSidebar(props) {
return new DocsSidebarClass(props);
}
function createDocsContent(props) {
return new DocsContentClass(props);
}
function createDocsLayout(props) {
const sidebar = new DocsSidebarClass({
navigation: props.navigation,
currentPage: props.currentPage,
onPageSelect: props.onPageSelect,
collapsed: props.sidebarCollapsed
});
const content = new DocsContentClass({
content: props.content,
loading: false,
error: null
});
return `
<div class="docs-layout">
${sidebar.render()}
${content.render()}
</div>
`;
}
export { ContentLoader, DocsContentClass as DocsContent, DocsSidebarClass as DocsSidebar, NavigationTree, addTableOfContents, createContentLoader, createDocsContent, createDocsLayout, createDocsSidebar, createNavigationTree, extractHeadings, extractTableOfContents, loadContent };
//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map