Unified AsciiDoc Publisher

Content Type: {contentType === 'article' ? 'Article' : contentType === 'scattered-notes' ? 'Notes' : 'None'}
{#if generatedEvents}
Events: {generatedEvents.contentEvents.length + (generatedEvents.indexEvent ? 1 : 0)}
{/if}
{#if publicationResult?.metadata?.eventStructure && generatedEvents} {/if}
{#if generatedEvents && contentType !== 'none'} {:else}
Add content to enable publishing
{/if}
{#if showPreview}

AsciiDoc Preview

{#if !content.trim()}
Start typing to see the preview...
{:else} {#if contentType === 'article' && publicationResult?.metadata.title}

{publicationResult.metadata.title}

{#if publicationResult.metadata.attributes.tags} {@const tagsList = publicationResult.metadata.attributes.tags.split(',').map((t: string) => t.trim())} {#if tagsList.length > 0}
{#each tagsList as tag} #{tag} {/each}
{/if} {/if}
{/if}
{#if contentType === 'article' && publicationResult?.metadata.title} {@const documentHeader = content.split(/\n==\s+/)[0]}
{@html asciidoctor.convert(documentHeader, { standalone: false, attributes: { showtitle: true, sectids: false, } })}
{#if publicationResult.metadata.attributes.tags} {@const tagsList = publicationResult.metadata.attributes.tags.split(',').map((t: string) => t.trim())} {#if tagsList.length > 0}
Document tags: {#each tagsList as tag}
# {tag}
{/each}
{/if} {/if}
{/if} {#each parsedSections as section, index}
{#if section.isIndex}
Index Event (30040)

{section.title}

{:else}
Content Event (30041)
{@html asciidoctor.convert(`${'='.repeat(section.level)} ${section.title}`, { standalone: false, attributes: { showtitle: false, sectids: false, } })}
{#if section.tags && section.tags.length > 0}
{#each section.tags as tag} #{tag[1]} {/each}
{/if} {#if section.content}
{@html asciidoctor.convert(section.content, { standalone: false, attributes: { showtitle: false, sectids: false, } })}
{/if}
{/if} {#if index < parsedSections.length - 1}
Event Boundary
{/if}
{/each}
Event Count: {#if generatedEvents} {@const indexEvents = generatedEvents.contentEvents.filter((e: any) => e.kind === 30040)} {@const contentOnlyEvents = generatedEvents.contentEvents.filter((e: any) => e.kind === 30041)} {@const totalIndexEvents = indexEvents.length + (generatedEvents.indexEvent ? 1 : 0)} {@const totalEvents = totalIndexEvents + contentOnlyEvents.length} {totalEvents} event{totalEvents !== 1 ? "s" : ""} ({totalIndexEvents} index{totalIndexEvents !== 1 ? " events" : ""} + {contentOnlyEvents.length} content{contentOnlyEvents.length !== 1 ? " events" : ""}) {:else} 0 events {/if}
{/if}
{/if} {#if showTutorial}

AsciiDoc Guide

Header Highlighting

Blue: Index Events (30040)
Green: Content Events (30041)
Amber: Potential Events (at parse level)
Gray: Subheaders (within content)

Publishing Levels

    {#each generateParseLevelOptions(MIN_PARSE_LEVEL, MAX_PARSE_LEVEL) as option}
  • Level {option.level}: {#if option.level === 2} Only {'='.repeat(option.level)} sections become events (containing {'='.repeat(option.level + 1)} and deeper) {:else} {'='.repeat(option.level - 1)} sections become indices, {'='.repeat(option.level)} sections become events {/if}
  • {/each}

Example Structure

{`= Understanding Knowledge
:image: https://i.nostr.build/example.jpg
:published: 2025-04-21
:tags: knowledge, philosophy, education
:type: text

== Preface
:tags: introduction, preface

This essay outlines the purpose...

== Introduction: Knowledge Ecosystem
:tags: introduction, ecosystem

Knowledge exists as dynamic representations...

=== Why Investigate Knowledge?
:difficulty: intermediate

Understanding the nature of knowledge...

==== The Four Perspectives
:complexity: high

1. Material Cause: The building blocks...`}

Attributes

Use :key: value format to add metadata that becomes event tags.

Content Types

  • Article: Starts with = title, creates index + content events
  • Notes: Just == sections, creates individual content events
{/if} {#if showStructurePreview}

Event Structure

{#if publicationResult?.metadata?.eventStructure && publicationResult.metadata.eventStructure.length > 0}
📁
Index Events
{publicationResult.metadata.eventStructure.filter((n: any) => n.eventKind === 30040).length + publicationResult.metadata.eventStructure.reduce((acc: number, n: any) => acc + (n.children?.filter?.((c: any) => c.eventKind === 30040)?.length || 0), 0)} × 30040
📄
Content Events
{generatedEvents.contentEvents.length} × 30041
{#snippet renderEventNode(node, depth = 0)}
{node.eventKind === 30040 ? '📁' : '📄'} [{node.eventKind}] {node.title || 'Untitled'}
{#if node.children && node.children.length > 0} {#each node.children as child} {@render renderEventNode(child, depth + 1)} {/each} {/if} {/snippet} {#each publicationResult.metadata.eventStructure as node} {@render renderEventNode(node, 0)} {/each}
Parse Level {parseLevel}
{#if parseLevel === 2} Each == section becomes a 30041 event with all nested content. {:else if parseLevel === 3} Level 2 sections with children → 30040 indices
Level 3 sections → 30041 content events {:else} Sections with children → 30040 indices
Level {parseLevel} sections → 30041 content events {/if}
📁 Index - references other events
📄 Content - contains article text
{:else}
Add content to see event structure
Debug: {JSON.stringify({ hasResult: !!publicationResult, hasMetadata: !!publicationResult?.metadata, hasStructure: !!publicationResult?.metadata?.eventStructure, structureLength: publicationResult?.metadata?.eventStructure?.length || 0, hasEvents: !!generatedEvents, contentLength: generatedEvents?.contentEvents?.length || 0 }, null, 2)}
{/if}
{/if}