98 lines
2.9 KiB
Markdown
98 lines
2.9 KiB
Markdown
# ribbit
|
|
|
|
Zero-dependency WYSIWYG markdown editor for the browser.
|
|
|
|
## Source Layout
|
|
|
|
- `src/ts/` — TypeScript source files
|
|
- `types.ts` — shared interfaces (Tag, SourceToken, Converter, etc.)
|
|
- `tags.ts` — tag definitions and `inlineTag()` factory
|
|
- `hopdown.ts` — configurable markdown↔HTML converter (HopDown class)
|
|
- `macros.ts` — macro parsing and Tag generation
|
|
- `ribbit.ts` — Ribbit viewer, RibbitPlugin, utilities
|
|
- `ribbit-editor.ts` — RibbitEditor with WYSIWYG support, public API exports
|
|
- `default-theme.ts` — built-in theme definition
|
|
- `theme-manager.ts` — theme registration and switching
|
|
- `events.ts` — typed event emitter
|
|
- `src/static/` — CSS and static assets
|
|
- `ribbit-core.css` — functional editor styles (always load)
|
|
- `themes/ribbit-default/theme.css` — default theme
|
|
|
|
## Build Output
|
|
|
|
```
|
|
dist/ribbit/
|
|
├── ribbit.js # readable IIFE bundle + source map
|
|
├── ribbit.min.js # minified bundle
|
|
├── ribbit-core.css # functional styles
|
|
└── themes/
|
|
└── ribbit-default/
|
|
└── theme.css # default theme (imports ribbit-core.css)
|
|
```
|
|
|
|
## Usage
|
|
|
|
```html
|
|
<link rel="stylesheet" href="ribbit/themes/ribbit-default/theme.css">
|
|
<article id="ribbit">your markdown here</article>
|
|
|
|
<script src="ribbit/ribbit.js"></script>
|
|
<script>
|
|
const editor = new ribbit.Editor({
|
|
on: {
|
|
save: ({ markdown }) => {
|
|
fetch('/api/save', { method: 'POST', body: markdown });
|
|
},
|
|
},
|
|
macros: [
|
|
{
|
|
name: 'npc',
|
|
toHTML: ({ keywords }) => {
|
|
const name = keywords.join(' ');
|
|
return `<a href="/NPC/${name}">${name}</a>`;
|
|
},
|
|
},
|
|
],
|
|
});
|
|
editor.run();
|
|
editor.wysiwyg();
|
|
</script>
|
|
```
|
|
|
|
## Custom Block Tags
|
|
|
|
```javascript
|
|
const spoiler = {
|
|
name: 'spoiler',
|
|
match: (context) => {
|
|
if (!/^\|{3,}/.test(context.lines[context.index])) return null;
|
|
const content = [];
|
|
let i = context.index + 1;
|
|
while (i < context.lines.length && !/^\|{3,}/.test(context.lines[i]))
|
|
content.push(context.lines[i++]);
|
|
return { content: content.join('\n'), raw: '', consumed: i + 1 - context.index };
|
|
},
|
|
toHTML: (token, convert) =>
|
|
'<details><summary>Spoiler</summary>' + convert.block(token.content) + '</details>',
|
|
selector: 'DETAILS',
|
|
toMarkdown: (element, convert) =>
|
|
'\n\n|||\n' + convert.children(element).trim() + '\n|||\n\n',
|
|
};
|
|
|
|
const converter = new ribbit.HopDown({
|
|
tags: { ...ribbit.defaultTags, 'DETAILS': spoiler },
|
|
});
|
|
```
|
|
|
|
## Tests
|
|
|
|
```
|
|
npm test
|
|
```
|
|
|
|
## Supported Markdown
|
|
|
|
Bold, italic, inline code, links, headings (h1-h6), unordered/ordered/nested lists,
|
|
blockquotes, fenced code blocks with language, horizontal rules, GFM tables with
|
|
column alignment, paragraphs, and macros (@name syntax).
|