{"id":50249276,"url":"https://github.com/slpstream/traven","last_synced_at":"2026-05-31T02:02:16.053Z","repository":{"id":359784593,"uuid":"1247216056","full_name":"slpstream/traven","owner":"slpstream","description":"Standalone MIT-licensed WYSIWYM Markdown Editor with customization features (skins, toolbars) and image uploads: Markdown input, Markdown output, single line deploy.","archived":false,"fork":false,"pushed_at":"2026-05-27T00:19:22.000Z","size":1686,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-27T01:20:38.471Z","etag":null,"topics":["live-preview","markdown","markdown-editor","markdowneditor","rich-text-editor","wysiwyg","wysiwyg-editor","wysiwyg-js-editor","wysiwyg-markdown","wysiwym-markdown"],"latest_commit_sha":null,"homepage":"https://traven.dev","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/slpstream.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-23T03:16:20.000Z","updated_at":"2026-05-27T00:19:25.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/slpstream/traven","commit_stats":null,"previous_names":["slpstream/traven"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/slpstream/traven","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slpstream%2Ftraven","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slpstream%2Ftraven/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slpstream%2Ftraven/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slpstream%2Ftraven/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/slpstream","download_url":"https://codeload.github.com/slpstream/traven/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slpstream%2Ftraven/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33716339,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-31T02:00:06.040Z","response_time":95,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["live-preview","markdown","markdown-editor","markdowneditor","rich-text-editor","wysiwyg","wysiwyg-editor","wysiwyg-js-editor","wysiwyg-markdown","wysiwym-markdown"],"created_at":"2026-05-27T01:00:55.459Z","updated_at":"2026-05-31T02:02:16.046Z","avatar_url":"https://github.com/slpstream.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/images/traven.png\" alt=\"Traven Editor\" width=\"400\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003eA standalone, lightweight, framework-agnostic WYSIWYM Markdown Editor\u003c/strong\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  Add Traven editor to any website:\n  LaTeX, table editor, image modal, shortcode system, custom Lezer extensions, \n  four skins, five demos, six toolbars, full documentation\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-MIT-blue.svg\" alt=\"MIT License\"\u003e\u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/badge/version-0.1.8-orange.svg\" alt=\"Version 0.1.8\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/engine-CodeMirror_6-6aa00.svg\" alt=\"CodeMirror 6 Engine\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/peer_dependencies-none-blue.svg\" alt=\"Zero Peer Dependencies\"\u003e\n\u003c/p\u003e\n\n---\n\n## The Typora-like Markdown editor you can embed anywhere\n\n**Traven Editor** is a non-brittle WYSIWYM (What You See Is What You Mean) Markdown editor for embedding directly into custom CMS systems, administrative dashboards, web forms and apps. Built on the **CodeMirror 6** editing engine, Traven delivers a high-fidelity editing experience while outputting clean, raw Markdown.\n\nTraven is highly modular and straightforward to customize or extend. If you need a powerful, flexible and mostly unopinionated Markdown editor that adapts to the layout, theme, and behavior of an existing project, its theming and configuration options and decoupled styling make integration fast and easy.\n\n### Naming \u0026 Philosophy\n\n**\"B. Traven\"** was the self-chosen nym of the privacy-first author behind *The Treasure of the Sierra Madre*, who spent his career proving that the work outlasts its author, communicating with publishers pseudonymously and letting his writing speak for itself. For a framework-agnostic, open-source editor meant to be embedded, customized, and stay quietly out of the limelight, the name fits.\n\n---\n\n## Live Demos\n\nGo to **[Traven.dev](https://traven.dev)** to try the Traven framework-agnostic WYSIWYM editor with live previews in different demo sandboxes. \n\nMix and match different combinations of toolbar buttons, skins, and editor layouts to see the flexibility of how Traven can be themed and configured to fit any setting where JavaScript works.\n\n---\n\n## Key Features\n\n*   **WYSIWYM Collapsing**: Formatting syntax markers (like `**` for bold and `*` for italic) display dynamically only when the cursor is inside the formatted text. When the cursor leaves, they transition smoothly into clean, styled blocks.\n*   **Optimistic Media Uploads**: Drag and drop or paste image files directly into the editor. The view immediately embeds an optimistic spinner loader and replaces it with the final URL once your upload handler resolves.\n*   **Decoupled Styling (Skins)**: Theme aesthetics (colors, padding, borders) are decoupled from the JavaScript logic. Swap between the neutral **Default Skin** and optional skins such as a **Dark Skin** and a contemporary **Colorful Skin** by changing a single `\u003clink\u003e` stylesheet, with no rebuilding required.\n*   **Bidirectional Raw Sync**: Easily bind a secondary raw Markdown viewer/editor in split-screen layouts. Changes flow incrementally between editors, maintaining cursor positions and separate histories without circular synchronization loops.\n*   **Smart Keyboard Utilities**: Includes keyboard helpers that prevent cursors from getting trapped inside collapsed markdown delimiters during arrow navigation.\n*   **Vim Emulation Mode**: Toggleable Vim normal/visual/insert mode keybindings dynamically at runtime.\n*   **Real-Time Statistics**: Out-of-the-box support for tracking words, characters, and estimated reading times with statistics update event listeners.\n*   **Dynamic HTML Preview Rendering**: Features a compilation hook for registering custom Markdown renderers to generate structural, skin-synced HTML previews.\n*   **LaTeX Math Rendering**: Native support for inline (`$ ... $`) and display (`$$ ... $$`) LaTeX equations. Math is dynamically parsed via custom Lezer syntax extensions and rendered asynchronously using KaTeX (supporting pre-loaded global instances, locally-hosted files, or optional CDN assets). Delimiters collapse gracefully, and equations automatically update in both the WYSIWYM editing canvas and the fallback HTML preview.\n*   **Zero Peer Dependencies**: Bundles CodeMirror and Vim emulation modules internally using `esbuild`. Simply drop in the compiled script and a stylesheet to start editing.\n\n---\n\n## Installation \u0026 Setup\n\n### 1. Direct Include (Recommended for CMSs)\n\nCopy `dist/traven.js` and your preferred skin stylesheet (from `assets/skins/`) into your host project directory, and include them:\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en\"\u003e\n\u003chead\u003e\n  \u003cmeta charset=\"UTF-8\"\u003e\n  \u003ctitle\u003eTraven Integration\u003c/title\u003e\n  \n  \u003c!-- Load the stylesheet skin --\u003e\n  \u003clink rel=\"stylesheet\" href=\"assets/skins/skin-default.css\"\u003e\n  \u003clink rel=\"stylesheet\" href=\"assets/toolbars/toolbar-default.css\"\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n\n  \u003c!-- Parent containers for mounting --\u003e\n  \u003cdiv class=\"editor-container\"\u003e\n    \u003cdiv id=\"editor-mount\"\u003e\u003c/div\u003e\n  \u003c/div\u003e\n\n  \u003cscript type=\"module\"\u003e\n    import { TravenEditor } from \"./dist/traven.js\";\n\n    // Defer initialization until fonts are ready for CodeMirror coordinate caching\n    document.fonts.ready.then(() =\u003e {\n      const editor = new TravenEditor({\n        element: document.getElementById(\"editor-mount\"),\n        initialValue: \"# Hello Traven\\n\\nEdit **this bold text** to see delimiters appear!\",\n        lineNumbers: true\n      });\n    });\n  \u003c/script\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n---\n\n## API Reference\n\n### `new TravenEditor(options)`\n\nInitializes a new editor instance.\n\n#### Options\n\n| Option | Type | Default | Description |\n| :--- | :--- | :--- | :--- |\n| `element` | `HTMLElement` | *(Required)* | The DOM element inside which the WYSIWYM editor will mount. |\n| `sourceElement` | `HTMLElement` | `null` | Optional DOM element to mount the secondary raw editor for live sync. |\n| `initialValue` | `string` | `\"\"` | The starting Markdown document string. |\n| `lineNumbers` | `boolean` | `false` | Show line numbers and folding gutters in the primary editor. |\n| `sourceLineNumbers`| `boolean` | `false` | Show line numbers and gutters in the raw sync editor. |\n| `lineWrapping` | `boolean` | `true` | Enable soft line wrapping in the primary editor. |\n| `sourceLineWrapping`| `boolean` | `true` | Enable soft line wrapping in the raw sync editor. |\n| `onChange` | `function` | `null` | Callback fired on change: `(value: string) =\u003e void`. |\n| `onSave` | `function` | `null` | Callback fired on Save command (Cmd+S / Ctrl+S): `(value: string) =\u003e void`. |\n| `onUploadImage` | `function` | `null` | Callback returning a promise of the uploaded image's URL: `(file: File) =\u003e Promise\u003cstring\u003e`. |\n| `onStatsUpdate` | `function` | `null` | Callback fired when document stats change: `(stats: { words: number, characters: number, readTime: number }) =\u003e void`. |\n| `theme` | `\"light\" \\| \"dark\"`| `\"light\"` | Configures baseline cursor theme variables and dark mode class triggers. |\n| `caretColor` | `string` | `\"\"` | Custom hex color for the editor caret overrides. |\n| `toolbar` | `Array\u003cstring\u003e \\| boolean`| `false` | A list of tool key strings defining the toolbar buttons layout, or `false` to disable the toolbar. |\n| `vimMode` | `boolean` | `false` | Enables Vim keybindings and normal mode emulation in both editing panes. |\n| `readOnly` | `boolean` | `false` | Enables read-only mode for both primary and secondary editor panes. |\n| `keybindings` | `object` | `{}` | Key-value pairs overriding default tool keybindings (e.g. `{ bold: \"Ctrl-Shift-b\" }`). |\n| `katex` | `boolean \\| string \\| object` | `false` | Configures KaTeX loading. If `false` (default), only uses local preloaded `window.katex`. If `true`, loads from JSDelivr CDN. If a string or object, defines custom self-hosted paths (e.g. `{ js: \"path/to/katex.js\", css: \"path/to/katex.css\" }`). |\n\n---\n\n### Public Methods\n\n#### `getValue()`\nReturns the complete document content as a Markdown string.\n*   **Returns:** `string`\n\n#### `setValue(value)`\nReplaces the entire document content with a new Markdown string.\n*   **Parameters:** `value` (`string`)\n\n#### `focus()`\nProgrammatically focuses the primary editor view.\n\n#### `setReadOnly(readOnly)`\nSets the editor to read-only or read-write mode dynamically.\n*   **Parameters:** `readOnly` (`boolean`): Whether the editor should be read-only.\n\n#### `isReadOnly()`\nReturns whether the editor is currently in read-only mode.\n*   **Returns:** `boolean`\n\n#### `getSelection()`\nReturns the currently selected text in the primary editor.\n*   **Returns:** `string`\n\n#### `setSelection(anchor, head)`\nSets the selection range in the editor and focuses it.\n*   **Parameters:**\n    *   `anchor` (`number`): The starting character index of the selection.\n    *   `head` (`number`, optional): The ending character index of the selection. Defaults to `anchor`.\n\n\n#### `insertSnippet(before, after, placeholder)`\nWraps the current text selection with markdown characters. If no text is selected, inserts a formatted placeholder string.\n*   **Parameters:**\n    *   `before` (`string`): Prefix tags (e.g. `**`).\n    *   `after` (`string`): Suffix tags (e.g. `**`).\n    *   `placeholder` (`string`): Text displayed inside tags if selection is empty.\n\n#### `undo()`\nTriggers history undo on the currently focused editor (WYSIWYM or raw).\n\n#### `redo()`\nTriggers history redo on the currently focused editor (WYSIWYM or raw).\n\n#### `setTheme(theme)`\nDynamically toggles light or dark mode styling across the editors.\n*   **Parameters:** `theme` (`\"light\" | \"dark\"`)\n\n#### `setVimMode(enabled)`\nDynamically toggles Vim mode emulation at runtime.\n*   **Parameters:** `enabled` (`boolean`)\n\n#### `getCharacterCount()`\nReturns the total character length of the active document.\n*   **Returns:** `number`\n\n#### `getWordCount()`\nReturns the total word count of the active document.\n*   **Returns:** `number`\n\n#### `getReadTime()`\nReturns the estimated reading time of the active document in minutes.\n*   **Returns:** `number`\n\n#### `registerRenderer(renderFn)`\nRegisters a custom Markdown compilation function to render custom HTML previews.\n*   **Parameters:** `renderFn` (`(markdown: string) =\u003e string`)\n\n#### `getContentHtml()`\nReturns the compiled HTML representation of the document, using the registered custom renderer or the built-in fallback parser.\n*   **Returns:** `string`\n\n#### `getView()`\nExposes the primary CodeMirror `EditorView` instance.\n*   **Returns:** `EditorView`\n\n#### `triggerSave()`\nProgrammatically invokes the registered save callback with current values.\n\n#### `on(event, callback)`\nRegisters an event listener callback.\n*   **Parameters:**\n    *   `event` (`\"change\" | \"save\" | \"statsUpdate\"`): The event name.\n    *   `callback` (`function`): The callback function:\n        *   For `\"change\"` / `\"save\"`: receives `(value: string)` (the updated Markdown document).\n        *   For `\"statsUpdate\"`: receives a stats object: `{ words: number, characters: number, readTime: number }`.\n\n**Example:**\n```javascript\neditor.on(\"statsUpdate\", (stats) =\u003e {\n  console.log(`Words: ${stats.words}, Characters: ${stats.characters}, Read Time: ${stats.readTime} min`);\n});\n```\n\n#### `destroy()`\nCleans up event listeners and destroys CodeMirror instances.\n\n---\n\n### Editing \u0026 Formatting Helpers\n\nTraven exposes several built-in commands to manipulate text selections programmatically:\n\n#### `clear()`\nWipes the entire document content and focuses the primary editor.\n\n#### `toUpperCase()`\nConverts the active selection to uppercase, preserving the selected text boundary.\n\n#### `toLowerCase()`\nConverts the active selection to lowercase, preserving the selected text boundary.\n\n#### `capitalizeWords()`\nCapitalizes the first letter of every word in the active selection.\n\n#### `removeFormatting()`\nStrips all inline styles (bold, italic, code backticks, strikethrough, highlights) and block formatting (lists, taskboxes, headings, blockquotes, horizontal rules) from the selection.\n\n#### `toggleFullscreen()`\nToggles fullscreen class `.is-fullscreen` on the editor's parent container and recalculates layout coordinates.\n\n#### `openSearch()`\nOpens the built-in CodeMirror find-and-replace search panel.\n\n#### `goToLine(lineNumber)`\nNavigates the cursor to the specified 1-indexed line number and scrolls it into view.\n*   **Parameters:** `lineNumber` (`number`)\n\n#### `insertCodeBlock()`\nWraps the selection in a fenced code block (`` ``` ``) with appropriate line spacing.\n\n#### `insertHR()`\nInserts a standalone markdown horizontal rule line (`---`) at the cursor.\n\n#### `insertTable()`\nInserts a pre-formatted 3x3 Markdown table template at the cursor, and selects the first header text.\n\n#### `setHeading(level)`\nToggles or applies a heading level (`1` to `6`) prefix to the active line. Pass `0` to strip headings.\n*   **Parameters:** `level` (`number`)\n\n#### `insertBlockquote()`\nConverts the active selection or line into a markdown blockquote block (`\u003e `).\n\n#### `insertList(type)`\nConverts the active selection or line into a list of the specified type.\n*   **Parameters:** `type` (`\"ul\" | \"ol\" | \"task\"`)\n\n---\n\n## Integration Patterns\n\nTraven supports two main options for handling YAML Frontmatter metadata (e.g. `title`, `tags`):\n\n### Approach A: Freeform Editing (Inline)\nUseful for markdown-first environments (like Obsidian or wikis) where authors prefer typing raw YAML manually.\n*   **Usage**: Pass the raw file directly into `TravenEditor`. The editor automatically highlights the frontmatter boundaries `---`, styles the keys, and collapses them when focus is lost.\n\n### Approach B: Structured Forms (Split-Before / Join-After) — *Recommended for CMSs*\nRecommended for databases and dashboard layouts. Metadata (Title, Author, Status, Date) is typed into standard, validated HTML form fields, while Traven is initialized **only** with the Markdown body content. This prevents users from breaking frontmatter syntax formatting.\n\n#### Split/Join Helper Recipe (JavaScript)\n\nAdd these utilities to your integration pipeline to split content before loading, and join it on save:\n\n```javascript\n/**\n * Splits a raw Markdown file into its YAML block and body Markdown content.\n * Supports Windows (\\r\\n) line endings.\n */\nexport function splitFrontmatter(raw) {\n  const match = raw.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/);\n  if (!match) {\n    return { yaml: \"\", markdown: raw };\n  }\n  return { yaml: match[1], markdown: match[2] };\n}\n\n/**\n * Recombines a YAML metadata block and body Markdown back into a single file string.\n */\nexport function joinFrontmatter(yaml, markdown) {\n  const trimmedYaml = yaml.trim();\n  return trimmedYaml ? `---\\n${trimmedYaml}\\n---\\n${markdown}` : markdown;\n}\n```\n\n---\n\n## Customization \u0026 Styling\n\nSkins are configured as plain CSS files, letting developers override colors and layout elements without running build systems.\n\n### SWAPPING THEMES\nSimply swap the styling link in your HTML document:\n```html\n\u003c!-- For a slate, clean typography-focused feel: --\u003e\n\u003clink rel=\"stylesheet\" href=\"assets/skins/skin-default.css\"\u003e\n\n\u003c!-- For a warm, rust-tinted brand feel: --\u003e\n\u003clink rel=\"stylesheet\" href=\"assets/skins/skin-colorful.css\"\u003e\n\n\u003c!-- For a premium slate dark theme feel: --\u003e\n\u003clink rel=\"stylesheet\" href=\"assets/skins/skin-dark.css\"\u003e\n```\n\n### CUSTOMIZING THE TOOLBAR\n\nYou can customize the toolbar layout by passing an array of tool keys to the constructor's `toolbar` option, or hide buttons using CSS overrides.\n\n#### Available Toolbar Stylesheets\n\nAlternative pre-configured toolbar presentation sheets are available in `assets/toolbars/` and can be loaded dynamically or statically to swap editor layouts:\n*   `toolbar-default.css`: The default clean toolbar skin, containing the full set of all available buttons.\n*   `toolbar-compact.css` / `toolbar-compact-dark.css`: Slim layouts with reduced padding.\n*   `toolbar-reduced.css` / `toolbar-reduced-dark.css`: Ultra-minimalist layouts for simplified interfaces.\n*   `toolbar-expandable.css` / `toolbar-expandable-dark.css`: A dynamic \"2-in-1\" toolbar that toggles between core buttons and the full set when expanded.\n\n#### Toolbar Buttons \u0026 Selectors Reference\n\nEach button generated in the toolbar is assigned a generic `.toolbar-btn` class, along with a button-specific class matching its key name (e.g. `.btn-bold`):\n\n| Tool Key | CSS Selector | Action Description | Default Keyboard Shortcut |\n| :--- | :--- | :--- | :--- |\n| `undo` | `.btn-undo` | Undo last operation | `Ctrl+Z` (`Cmd+Z` on Mac) |\n| `redo` | `.btn-redo` | Redo last undone operation | `Ctrl+Y` (`Cmd+Y` on Mac) |\n| `bold` | `.btn-bold` | Bold text (`**bold text**`) | `Ctrl+B` (`Cmd+B` on Mac) |\n| `italic` | `.btn-italic` | Italic text (`*italic text*`) | `Ctrl+I` (`Cmd+I` on Mac) |\n| `strikethrough` | `.btn-strikethrough` | Strikethrough text (`~~strikethrough~~`) | `Ctrl+Shift+S` (`Cmd+Shift+S` on Mac) |\n| `code` | `.btn-code` | Inline code backticks (`` `code` ``) | - |\n| `codeblock` | `.btn-codeblock` | Wrap selection in fenced code block (`` ``` ``) | - |\n| `heading` | `.btn-heading` | Dropdown selector for Heading 1 to Heading 6 | - |\n| `bulletlist` | `.btn-bulletlist` | Format line or selection as unordered list (`- `) | - |\n| `numberedlist` | `.btn-numberedlist` | Format line or selection as ordered list (`1. `) | - |\n| `tasklist` | `.btn-tasklist` | Format line or selection as checklist (`- [ ] `) | `Ctrl+Shift+C` (`Cmd+Shift+C` on Mac) |\n| `blockquote` | `.btn-blockquote` | Format line or selection as blockquote (`\u003e `) | - |\n| `hr` | `.btn-hr` | Insert horizontal rule line (`---`) | - |\n| `table` | `.btn-table` | Insert standard 3x3 table template | - |\n| `datetime` | `.btn-datetime` | Insert current Date \u0026 Time (YYYY-MM-DD HH:MM) | - |\n| `search` | `.btn-search` | Open CodeMirror search panel | `Ctrl+F` (`Cmd+F` on Mac) |\n| `fullscreen` | `.btn-fullscreen` | Toggle editor container fullscreen mode | - |\n| `clear` | `.btn-clear` | Clear all document content | - |\n| `uppercase` | `.btn-uppercase` | Convert selection to UPPERCASE | - |\n| `lowercase` | `.btn-lowercase` | Convert selection to lowercase | - |\n| `capitalize` | `.btn-capitalize` | Capitalize selection words | - |\n| `removeformatting` | `.btn-removeformatting` | Remove Markdown styling from selection | - |\n| `gotoline` | `.btn-gotoline` | Prompt for line number and navigate | `Ctrl+G` (`Cmd+G` on Mac) |\n| `link` | `.btn-link` | Insert link using link modal dialog | `Ctrl+K` (`Cmd+K` on Mac) |\n| `help` | `.btn-help` | Open keyboard shortcuts help modal | `Ctrl+/` (`Cmd+/` on Mac) |\n\n#### Hiding Buttons via CSS\nTo hide buttons or re-style them, override classes in your local stylesheets:\n```css\n/* Hide the Heading and Redo buttons from the toolbar */\n.toolbar-btn.btn-heading,\n.toolbar-btn.btn-redo {\n  display: none;\n}\n```\n\n---\n\n## Custom Shortcodes Architecture\n\nTraven supports custom shortcodes to extend the standard Markdown syntax. By default, it features native support for a custom `[image]` shortcode and a block-level `[component]` shortcode with quote/pullquote aliases:\n\n### Custom `[image]` Shortcode\nTraven includes an advanced, optional `[image]` shortcode (e.g. `[image src=\"...\" alt=\"...\" align=\"center\" size=\"medium\" class=\"my-custom-class\"]`) designed for modular, responsive layouts:\n* **Fully Backwards-Compatible**: The custom shortcode is completely optional. Traven remains fully backwards-compatible and non-breaking for standard legacy Markdown syntax (`![alt](src)`). Existing standard images continue to render and compile flawlessly.\n* **Toolbar Toggle**: The \"Insert Image\" toolbar modal contains a sliders-icon toggle to switch between Advanced mode (generating the custom `[image]` shortcode with support for captions, custom CSS classes, sizing, and alignment settings) and Legacy mode (producing standard `![alt](src)` Markdown).\n* **Decoupled Presentation Styling**: The fallback renderer compiles the shortcode to clean semantic HTML (an `\u003cimg\u003e` tag with class attributes and no inline `style=\"\"` declarations). Layout formatting (width, display, float, margin) is delegated entirely to the skin stylesheets (e.g. `assets/skins/skin-default.css`) via `.align-[alignment]` and `.size-[size]` selector classes.\n\n### Custom `[component]` \u0026 Blockquote Aliases Shortcode\nTraven includes native support for a pair-tag `[component]...[/component]` shortcode system, designed to handle structural block-level content:\n* **Flexible Syntax**: Supported formats:\n  - Canonical: `[component name=\"blockquote\" author=\"James Baldwin\" source=\"The Fire Next Time\"]Not everything that is faced can be changed...[/component]`\n  - Short Attribute Fallback: `[component=\"blockquote\" author=\"...\" source=\"...\"]...[/component]`\n* **Shorthand Aliases**: For writing convenience, Traven translates shorthand tags under the hood:\n  - Blockquote Alias: `[quote author=\"...\" source=\"...\"]...[/quote]` or `[blockquote author=\"...\" source=\"...\"]...[/blockquote]`\n  - Pullquote Alias: `[pullquote]...[/pullquote]`\n* **WYSIWYM Widget Folding**: In the editor, when the cursor is outside the tag range, the tag delimiters collapse, rendering a styled preview block of the component with an edit/modal trigger icon. Clicking the widget or edit icon launches the interactive Custom Component editor modal.\n* **Clean Fallback HTML Output**: The fallback compiler renders these shortcodes into standard HTML structure with **zero inline styles**:\n  - **Blockquotes**: `\u003cblockquote class=\"traven-component-blockquote\"\u003e...\u003cfooter\u003e\u003ccite\u003e— Author, Source\u003c/cite\u003e\u003c/footer\u003e\u003c/blockquote\u003e`\n  - **Pullquotes**: `\u003cblockquote class=\"traven-component-pullquote\"\u003e...\u003c/blockquote\u003e`\n  - **Generic/Unknown Blocks (e.g. `[component=\"info\"]` / `[component=\"warning\"]`)**: Compiles to a standard wrapper `\u003cdiv class=\"traven-component traven-component-[name]\"\u003e...\u003c/div\u003e`, allowing theme authors to style them independently.\n\nDevelopers can also extend Traven to support other custom shortcodes using its decoupled architecture:\n\n1.  **Grammar \u0026 Parser (`src/component-parser.js`)**: Extends the Lezer Markdown parser to detect tag pairs, attributes, and values.\n2.  **Replacement Widget (`src/wysiwym.js`)**: Injects a custom CodeMirror `WidgetType` returning custom interactive preview elements when the cursor is outside the shortcode range.\n3.  **Themes (`assets/skins/*.css`)**: Defines visual tokens (e.g. background colors, border styles, hand-drawn styles) for classes like `.cm-wysiwym-component-shortcode`.\n\n---\n\n## Development\n\nInstall development packages to test and build modifications:\n\n```bash\n# Install bundler dependencies\nnpm install\n\n# Run bundling build (produces dist/traven.js and dist/traven.css)\nnpm run build\n\n# Optional tests\nnpm run test\n\n# Start esbuild watch mode for live development\nnpm run watch\n```\n\nTo view the included integration demos, serve the project files on a local PHP-capable server (e.g. `php -S localhost:8000`).\n\n---\n\n## License\n\nTraven is open-source software licensed under the [MIT License](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslpstream%2Ftraven","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fslpstream%2Ftraven","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslpstream%2Ftraven/lists"}