Skip to content

Commit 67c4477

Browse files
committed
feat: add toolbar items for plugin
1 parent 50bb3d3 commit 67c4477

File tree

6 files changed

+69
-16
lines changed

6 files changed

+69
-16
lines changed

packages/bytemd/src/Editor.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
</style>
6868

6969
<div class="bytemd" style={containerStyle}>
70-
<Toolbar {cm} {fileHandler} />
70+
<Toolbar {cm} {fileHandler} {plugins} />
7171
<div class="bytemd-body">
7272
<textarea bind:this={textarea} />
7373
<div class="bytemd-viewer" bind:this={viewer}>

packages/bytemd/src/Toolbar.svelte

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { handleDec, handleBlockquote, handleLink, handleImage, handleTable } from './utils.js'
33
export let cm;
44
export let fileHandler;
5+
export let plugins;
56
let fileInput;
67
</script>
78

@@ -16,16 +17,17 @@
1617
border: 1px solid transparent;
1718
margin-left: 6px;
1819
}
19-
span path {
20-
fill: #777;
21-
}
2220
span:hover {
2321
border: 1px solid #aaa;
2422
}
25-
svg {
23+
span :global(svg) {
2624
display: block;
2725
width: 24px;
2826
height: 24px;
27+
fill: #777;
28+
}
29+
span :global(path) {
30+
fill: #777;
2931
}
3032
input {
3133
display: none;
@@ -41,4 +43,11 @@
4143
<span on:click={() => fileInput.click()}><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/></svg></span>
4244
<input bind:this={fileInput} type="file" accept="image/png, image/jpeg" on:change={(e) => handleImage(cm, e, fileHandler)} />
4345
<span on:click={() => handleTable(cm)}><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 3v18h18V3H3zm8 16H5v-6h6v6zm0-8H5V5h6v6zm8 8h-6v-6h6v6zm0-8h-6V5h6v6z"/></svg></span>
46+
{#each plugins as plugin}
47+
{#if plugin.toolbarItems}
48+
{#each plugin.toolbarItems as item}
49+
<span on:click={() => item.onClick(cm)}><svelte:component this={item.component} {...item.props} /></span>
50+
{/each}
51+
{/if}
52+
{/each}
4453
</div>

packages/bytemd/src/index.d.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
11
import { SvelteComponent } from 'svelte';
22
import { HastNode } from '../helpers';
3+
import * as cm from 'codemirror';
34

4-
export interface Plugin {
5+
type Props = Record<string, unknown>;
6+
7+
export interface Plugin<P extends Props = Props> {
58
/**
69
* Transformers for unified to be applied
710
*/
811
transformer?: any; // TODO:
912
/**
1013
* Specify how to render this node
14+
*
15+
* If `undefined` returned then go to the next plugin
1116
*/
1217
render(
1318
node: HastNode,
14-
):
15-
| {
16-
component: typeof SvelteComponent;
17-
props?: Record<string, unknown>;
18-
}
19-
| undefined;
19+
): { component: typeof SvelteComponent; props?: P } | undefined;
20+
/**
21+
* Components which should be added to toolbar
22+
*/
23+
toolbarItems?: {
24+
component: typeof SvelteComponent;
25+
onClick(cm: cm.Editor): void;
26+
}[];
2027
}
2128

2229
// TODO: https://github.com/sveltejs/svelte/pull/4577
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 3v9.28c-.47-.17-.97-.28-1.5-.28C8.01 12 6 14.01 6 16.5S8.01 21 10.5 21c2.31 0 4.2-1.75 4.45-4H15V6h4V3h-7z"/></svg>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M21 3H3c-1.11 0-2 .89-2 2v12c0 1.1.89 2 2 2h5v2h8v-2h5c1.1 0 1.99-.9 1.99-2L23 5c0-1.11-.9-2-2-2zm0 14H3V5h18v12zm-5-6l-7 4V7z"/></svg>

packages/plugin-media/src/index.ts

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,40 @@
11
import { Plugin } from 'bytemd';
22
import Audio from './Audio.svelte';
33
import Video from './Video.svelte';
4+
import AudioIcon from './AudioIcon.svelte';
5+
import VideoIcon from './VideoIcon.svelte';
6+
7+
type ClickHandler = Exclude<Plugin['toolbarItems'], undefined>[0]['onClick'];
48

59
export interface PluginOptions {
6-
videoAttrs?: Partial<HTMLVideoElement>;
7-
audioAttrs?: Partial<HTMLAudioElement>;
10+
video?: {
11+
defaultAttrs?: Partial<HTMLVideoElement>;
12+
onClickIcon?: ClickHandler;
13+
};
14+
audio?: {
15+
defaultAttrs?: Partial<HTMLAudioElement>;
16+
onClickIcon?: ClickHandler;
17+
};
18+
}
19+
20+
function getClickHandler(type: string): ClickHandler {
21+
return cm => {
22+
const pos = cm.getCursor('from');
23+
cm.replaceRange(`<${type} src=""></${type}>`, pos);
24+
cm.setCursor({ line: pos.line, ch: pos.ch + 12 });
25+
cm.focus();
26+
};
827
}
928

1029
export default function media({
11-
videoAttrs = { controls: true },
12-
audioAttrs = { controls: true },
30+
video: {
31+
defaultAttrs: videoAttrs = { controls: true },
32+
onClickIcon: onClickVideo = getClickHandler('video'),
33+
} = {},
34+
audio: {
35+
defaultAttrs: audioAttrs = { controls: true },
36+
onClickIcon: onClickAudio = getClickHandler('audio'),
37+
} = {},
1338
}: PluginOptions = {}): Plugin {
1439
return {
1540
render(node) {
@@ -33,5 +58,15 @@ export default function media({
3358
}
3459
}
3560
},
61+
toolbarItems: [
62+
{
63+
component: AudioIcon,
64+
onClick: onClickAudio,
65+
},
66+
{
67+
component: VideoIcon,
68+
onClick: onClickVideo,
69+
},
70+
],
3671
};
3772
}

0 commit comments

Comments
 (0)