Enabling more natural styling and slash menu.
Browse files- index.html +1 -0
- package.json +2 -2
- src/app/app.css +20 -11
- src/app/enter-key.js +16 -2
- src/app/init-milkdown.js +33 -7
index.html
CHANGED
|
@@ -8,5 +8,6 @@
|
|
| 8 |
</head>
|
| 9 |
<body>
|
| 10 |
<script src="index.js"></script>
|
|
|
|
| 11 |
</body>
|
| 12 |
</html>
|
|
|
|
| 8 |
</head>
|
| 9 |
<body>
|
| 10 |
<script src="index.js"></script>
|
| 11 |
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css">
|
| 12 |
</body>
|
| 13 |
</html>
|
package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
| 1 |
{
|
| 2 |
"name": "localm",
|
| 3 |
-
"version": "1.1.
|
| 4 |
"description": "Chat application",
|
| 5 |
"scripts": {
|
| 6 |
-
"build": "esbuild src/index.js --target=es6 --bundle --sourcemap --outfile=./index.js --format=iife --external:fs --external:path --external:child_process --external:ws",
|
| 7 |
"start": "npm run build -- --watch --serve=0.0.0.0:8812 --servedir=. --serve-fallback=index.html",
|
| 8 |
"test": "echo \"Error: no test specified\" && exit 1"
|
| 9 |
},
|
|
|
|
| 1 |
{
|
| 2 |
"name": "localm",
|
| 3 |
+
"version": "1.1.14",
|
| 4 |
"description": "Chat application",
|
| 5 |
"scripts": {
|
| 6 |
+
"build": "esbuild src/index.js --target=es6 --bundle --sourcemap --outfile=./index.js --format=iife --external:fs --external:path --external:child_process --external:ws --external:katex/dist/katex.min.css",
|
| 7 |
"start": "npm run build -- --watch --serve=0.0.0.0:8812 --servedir=. --serve-fallback=index.html",
|
| 8 |
"test": "echo \"Error: no test specified\" && exit 1"
|
| 9 |
},
|
src/app/app.css
CHANGED
|
@@ -10,19 +10,28 @@ body {
|
|
| 10 |
display: grid;
|
| 11 |
grid-template: 1fr auto / 1fr;
|
| 12 |
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
| 13 |
-
}
|
| 14 |
|
| 15 |
-
.milkdown {
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
}
|
| 27 |
}
|
| 28 |
|
|
|
|
| 10 |
display: grid;
|
| 11 |
grid-template: 1fr auto / 1fr;
|
| 12 |
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
|
|
| 13 |
|
| 14 |
+
.milkdown {
|
| 15 |
+
display: grid;
|
| 16 |
+
grid-template: 1fr / 1fr;
|
| 17 |
+
padding: 0;
|
| 18 |
|
| 19 |
+
.ProseMirror {
|
| 20 |
+
padding: 0.6em 1em;
|
| 21 |
+
font-family: inherit;
|
| 22 |
+
white-space: pre-wrap;
|
| 23 |
+
outline: none;
|
| 24 |
+
margin: 0;
|
| 25 |
+
|
| 26 |
+
pre {
|
| 27 |
+
background: inherit;
|
| 28 |
+
color: inherit;
|
| 29 |
+
|
| 30 |
+
code {
|
| 31 |
+
color: inherit;
|
| 32 |
+
}
|
| 33 |
+
}
|
| 34 |
+
}
|
| 35 |
}
|
| 36 |
}
|
| 37 |
|
src/app/enter-key.js
CHANGED
|
@@ -36,9 +36,17 @@ export function makeEnterPlugins({ workerConnection }) {
|
|
| 36 |
shortcuts: 'Enter',
|
| 37 |
command: (ctx) => {
|
| 38 |
const commands = ctx.get(commandsCtx);
|
| 39 |
-
return () =>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
},
|
| 41 |
-
priority:
|
| 42 |
},
|
| 43 |
});
|
| 44 |
|
|
@@ -60,6 +68,12 @@ export function setupCrepeEnterKey(crepeInput, workerConnection) {
|
|
| 60 |
if (view.dom) {
|
| 61 |
view.dom.addEventListener('keydown', (e) => {
|
| 62 |
if (e.key === 'Enter' && !e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
e.preventDefault();
|
| 64 |
|
| 65 |
// Get markdown using the underlying editor's serializer
|
|
|
|
| 36 |
shortcuts: 'Enter',
|
| 37 |
command: (ctx) => {
|
| 38 |
const commands = ctx.get(commandsCtx);
|
| 39 |
+
return () => {
|
| 40 |
+
// Check if slash menu is open first
|
| 41 |
+
const slashMenu = document.querySelector('.milkdown-slash-menu[data-show="true"]');
|
| 42 |
+
if (slashMenu) {
|
| 43 |
+
// Let the slash menu handle Enter
|
| 44 |
+
return false;
|
| 45 |
+
}
|
| 46 |
+
return commands.call(myEnterCommand.key);
|
| 47 |
+
};
|
| 48 |
},
|
| 49 |
+
priority: 50, // Lower priority so slash menu can intercept first
|
| 50 |
},
|
| 51 |
});
|
| 52 |
|
|
|
|
| 68 |
if (view.dom) {
|
| 69 |
view.dom.addEventListener('keydown', (e) => {
|
| 70 |
if (e.key === 'Enter' && !e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey) {
|
| 71 |
+
// Check if slash menu is open - if so, let it handle Enter
|
| 72 |
+
const slashMenu = document.querySelector('.milkdown-slash-menu[data-show="true"]');
|
| 73 |
+
if (slashMenu) {
|
| 74 |
+
return false; // Don't prevent default, let slash menu handle it
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
e.preventDefault();
|
| 78 |
|
| 79 |
// Get markdown using the underlying editor's serializer
|
src/app/init-milkdown.js
CHANGED
|
@@ -7,9 +7,12 @@ import {
|
|
| 7 |
editorViewOptionsCtx,
|
| 8 |
rootCtx
|
| 9 |
} from '@milkdown/core';
|
|
|
|
| 10 |
import { commonmark } from '@milkdown/kit/preset/commonmark';
|
| 11 |
import { slashFactory } from "@milkdown/plugin-slash";
|
| 12 |
-
|
|
|
|
|
|
|
| 13 |
|
| 14 |
/**
|
| 15 |
* @typedef {{
|
|
@@ -49,22 +52,45 @@ export async function initMilkdown({
|
|
| 49 |
root: chatInput,
|
| 50 |
defaultValue: '',
|
| 51 |
features: {
|
| 52 |
-
[Crepe.Feature.BlockEdit]:
|
| 53 |
[Crepe.Feature.Placeholder]: true,
|
| 54 |
[Crepe.Feature.Cursor]: true,
|
| 55 |
[Crepe.Feature.ListItem]: true,
|
| 56 |
[Crepe.Feature.CodeMirror]: true,
|
| 57 |
// Disable features not needed for chat input
|
| 58 |
-
[Crepe.Feature.ImageBlock]:
|
| 59 |
-
[Crepe.Feature.Table]:
|
| 60 |
-
[Crepe.Feature.Latex]:
|
| 61 |
-
[Crepe.Feature.Toolbar]:
|
| 62 |
-
[Crepe.Feature.LinkTooltip]:
|
| 63 |
},
|
| 64 |
featureConfigs: {
|
| 65 |
[Crepe.Feature.Placeholder]: {
|
| 66 |
text: 'Start typing...',
|
| 67 |
mode: 'block'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
}
|
| 69 |
}
|
| 70 |
});
|
|
|
|
| 7 |
editorViewOptionsCtx,
|
| 8 |
rootCtx
|
| 9 |
} from '@milkdown/core';
|
| 10 |
+
import { Crepe } from '@milkdown/crepe';
|
| 11 |
import { commonmark } from '@milkdown/kit/preset/commonmark';
|
| 12 |
import { slashFactory } from "@milkdown/plugin-slash";
|
| 13 |
+
|
| 14 |
+
import "@milkdown/crepe/theme/common/style.css";
|
| 15 |
+
import "@milkdown/crepe/theme/frame.css";
|
| 16 |
|
| 17 |
/**
|
| 18 |
* @typedef {{
|
|
|
|
| 52 |
root: chatInput,
|
| 53 |
defaultValue: '',
|
| 54 |
features: {
|
| 55 |
+
[Crepe.Feature.BlockEdit]: true, // Enable slash menu
|
| 56 |
[Crepe.Feature.Placeholder]: true,
|
| 57 |
[Crepe.Feature.Cursor]: true,
|
| 58 |
[Crepe.Feature.ListItem]: true,
|
| 59 |
[Crepe.Feature.CodeMirror]: true,
|
| 60 |
// Disable features not needed for chat input
|
| 61 |
+
[Crepe.Feature.ImageBlock]: true,
|
| 62 |
+
[Crepe.Feature.Table]: true,
|
| 63 |
+
[Crepe.Feature.Latex]: true,
|
| 64 |
+
[Crepe.Feature.Toolbar]: true,
|
| 65 |
+
[Crepe.Feature.LinkTooltip]: true
|
| 66 |
},
|
| 67 |
featureConfigs: {
|
| 68 |
[Crepe.Feature.Placeholder]: {
|
| 69 |
text: 'Start typing...',
|
| 70 |
mode: 'block'
|
| 71 |
+
},
|
| 72 |
+
[Crepe.Feature.BlockEdit]: {
|
| 73 |
+
textGroup: {
|
| 74 |
+
label: 'Text',
|
| 75 |
+
text: null, // Hide /text option
|
| 76 |
+
h1: { label: 'Heading', icon: '#' },
|
| 77 |
+
h2: null, h3: null, h4: null, h5: null, h6: null, // Hide other headings
|
| 78 |
+
quote: { label: 'Quote', icon: '>' },
|
| 79 |
+
divider: null
|
| 80 |
+
},
|
| 81 |
+
listGroup: {
|
| 82 |
+
label: 'Lists',
|
| 83 |
+
bulletList: { label: 'List', icon: '•' },
|
| 84 |
+
orderedList: { label: 'Numbered', icon: '1.' },
|
| 85 |
+
taskList: null
|
| 86 |
+
},
|
| 87 |
+
advancedGroup: {
|
| 88 |
+
label: 'Code',
|
| 89 |
+
codeBlock: { label: 'Code', icon: '`' },
|
| 90 |
+
image: null,
|
| 91 |
+
table: null,
|
| 92 |
+
math: null
|
| 93 |
+
}
|
| 94 |
}
|
| 95 |
}
|
| 96 |
});
|