mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-03-22 08:58:11 +00:00
basic css changes
This commit is contained in:
@@ -6,138 +6,153 @@ import { foldGutter, foldKeymap } from "@codemirror/language";
|
|||||||
import { EditorView, keymap, lineNumbers, highlightActiveLineGutter, highlightActiveLine } from "@codemirror/view";
|
import { EditorView, keymap, lineNumbers, highlightActiveLineGutter, highlightActiveLine } from "@codemirror/view";
|
||||||
import { markdown } from "@codemirror/lang-markdown";
|
import { markdown } from "@codemirror/lang-markdown";
|
||||||
import { css } from "@codemirror/lang-css";
|
import { css } from "@codemirror/lang-css";
|
||||||
|
import { oneDark } from "@codemirror/theme-one-dark";
|
||||||
|
|
||||||
const CodeEditor = forwardRef(({ value = "", onChange = () => {} }, ref) => {
|
const CodeEditor = forwardRef(
|
||||||
const editorRef = useRef(null);
|
({ value = "", onChange = () => {}, language, editorTheme, tab, view, style, ...props }, ref) => {
|
||||||
const viewRef = useRef(null);
|
const editorRef = useRef(null);
|
||||||
|
const viewRef = useRef(null);
|
||||||
|
|
||||||
// --- init editor ---
|
console.log(props);
|
||||||
useEffect(() => {
|
|
||||||
if (!editorRef.current) return;
|
|
||||||
|
|
||||||
const updateListener = EditorView.updateListener.of((update) => {
|
// --- init editor ---
|
||||||
if (update.docChanged) {
|
useEffect(() => {
|
||||||
onChange(update.state.doc.toString());
|
if (!editorRef.current) return;
|
||||||
|
|
||||||
|
const updateListener = EditorView.updateListener.of((update) => {
|
||||||
|
if (update.docChanged) {
|
||||||
|
onChange(update.state.doc.toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const boldCommand = (view) => {
|
||||||
|
const { from, to } = view.state.selection.main;
|
||||||
|
const selected = view.state.doc.sliceString(from, to);
|
||||||
|
const text = `**${selected}**`;
|
||||||
|
|
||||||
|
view.dispatch({
|
||||||
|
changes: { from, to, insert: text },
|
||||||
|
selection: { anchor: from + text.length },
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const italicCommand = (view) => {
|
||||||
|
const { from, to } = view.state.selection.main;
|
||||||
|
const selected = view.state.doc.sliceString(from, to);
|
||||||
|
const text = `*${selected}*`;
|
||||||
|
|
||||||
|
view.dispatch({
|
||||||
|
changes: { from, to, insert: text },
|
||||||
|
selection: { anchor: from + text.length },
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const customKeymap = keymap.of([
|
||||||
|
{ key: "Mod-b", run: boldCommand },
|
||||||
|
{ key: "Mod-i", run: italicCommand },
|
||||||
|
]);
|
||||||
|
|
||||||
|
const languageExtension = () => {
|
||||||
|
switch (language) {
|
||||||
|
case "gfm":
|
||||||
|
return markdown({ codeLanguages: [] }); // GitHub-flavored Markdown
|
||||||
|
case "css":
|
||||||
|
return css();
|
||||||
|
default:
|
||||||
|
return markdown();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = EditorState.create({
|
||||||
|
doc: value,
|
||||||
|
extensions: [
|
||||||
|
history(),
|
||||||
|
keymap.of(defaultKeymap),
|
||||||
|
customKeymap,
|
||||||
|
updateListener,
|
||||||
|
languageExtension(),
|
||||||
|
highlightActiveLine(),
|
||||||
|
highlightActiveLineGutter(),
|
||||||
|
keymap.of(foldKeymap),
|
||||||
|
foldGutter(),
|
||||||
|
lineNumbers(),
|
||||||
|
oneDark,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
viewRef.current = new EditorView({
|
||||||
|
state,
|
||||||
|
parent: editorRef.current,
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => viewRef.current?.destroy();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// --- sync external value ---
|
||||||
|
useEffect(() => {
|
||||||
|
const view = viewRef.current;
|
||||||
|
if (!view) return;
|
||||||
|
|
||||||
|
const current = view.state.doc.toString();
|
||||||
|
if (value !== current) {
|
||||||
|
view.dispatch({
|
||||||
|
changes: { from: 0, to: current.length, insert: value },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
}, [value]);
|
||||||
|
|
||||||
const boldCommand = (view) => {
|
// --- exposed API ---
|
||||||
const { from, to } = view.state.selection.main;
|
useImperativeHandle(ref, () => ({
|
||||||
const selected = view.state.doc.sliceString(from, to);
|
getValue: () => viewRef.current.state.doc.toString(),
|
||||||
const text = `**${selected}**`;
|
|
||||||
|
|
||||||
view.dispatch({
|
setValue: (text) => {
|
||||||
changes: { from, to, insert: text },
|
const view = viewRef.current;
|
||||||
selection: { anchor: from + text.length },
|
view.dispatch({
|
||||||
});
|
changes: { from: 0, to: view.state.doc.length, insert: text },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
return true;
|
injectText: (text) => {
|
||||||
};
|
const view = viewRef.current;
|
||||||
|
const { from, to } = view.state.selection.main;
|
||||||
|
|
||||||
const italicCommand = (view) => {
|
view.dispatch({
|
||||||
const { from, to } = view.state.selection.main;
|
changes: { from, to, insert: text },
|
||||||
const selected = view.state.doc.sliceString(from, to);
|
selection: { anchor: from + text.length },
|
||||||
const text = `*${selected}*`;
|
});
|
||||||
|
|
||||||
view.dispatch({
|
view.focus();
|
||||||
changes: { from, to, insert: text },
|
},
|
||||||
selection: { anchor: from + text.length },
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
getCursorPosition: () => viewRef.current.state.selection.main.head,
|
||||||
};
|
|
||||||
|
|
||||||
const customKeymap = keymap.of([
|
setCursorPosition: (pos) => {
|
||||||
{ key: "Mod-b", run: boldCommand },
|
viewRef.current.dispatch({ selection: { anchor: pos } });
|
||||||
{ key: "Mod-i", run: italicCommand },
|
viewRef.current.focus();
|
||||||
]);
|
},
|
||||||
|
|
||||||
const state = EditorState.create({
|
undo: () => undo(viewRef.current),
|
||||||
doc: value,
|
redo: () => redo(viewRef.current),
|
||||||
extensions: [
|
|
||||||
history(),
|
|
||||||
keymap.of(defaultKeymap),
|
|
||||||
customKeymap,
|
|
||||||
updateListener,
|
|
||||||
markdown(),
|
|
||||||
css(),
|
|
||||||
highlightActiveLine(),
|
|
||||||
highlightActiveLineGutter(),
|
|
||||||
keymap.of(foldKeymap),
|
|
||||||
foldGutter(),
|
|
||||||
lineNumbers(),
|
|
||||||
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
viewRef.current = new EditorView({
|
historySize: () => {
|
||||||
state,
|
const view = viewRef.current;
|
||||||
parent: editorRef.current,
|
if (!view) return { done: 0, undone: 0 };
|
||||||
});
|
|
||||||
|
|
||||||
return () => viewRef.current?.destroy();
|
const h = view.state.field(historyField, false);
|
||||||
}, []);
|
if (!h) return { done: 0, undone: 0 };
|
||||||
|
|
||||||
// --- sync external value ---
|
return { done: h.done.length, undone: h.undone.length };
|
||||||
useEffect(() => {
|
},
|
||||||
const view = viewRef.current;
|
|
||||||
if (!view) return;
|
|
||||||
|
|
||||||
const current = view.state.doc.toString();
|
focus: () => viewRef.current.focus(),
|
||||||
if (value !== current) {
|
}));
|
||||||
view.dispatch({
|
|
||||||
changes: { from: 0, to: current.length, insert: value },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [value]);
|
|
||||||
|
|
||||||
// --- exposed API ---
|
return <div className="codeEditor" ref={editorRef} style={style} />;
|
||||||
useImperativeHandle(ref, () => ({
|
},
|
||||||
getValue: () => viewRef.current.state.doc.toString(),
|
);
|
||||||
|
|
||||||
setValue: (text) => {
|
export default CodeEditor;
|
||||||
const view = viewRef.current;
|
|
||||||
view.dispatch({
|
|
||||||
changes: { from: 0, to: view.state.doc.length, insert: text },
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
injectText: (text) => {
|
|
||||||
const view = viewRef.current;
|
|
||||||
const { from, to } = view.state.selection.main;
|
|
||||||
|
|
||||||
view.dispatch({
|
|
||||||
changes: { from, to, insert: text },
|
|
||||||
selection: { anchor: from + text.length },
|
|
||||||
});
|
|
||||||
|
|
||||||
view.focus();
|
|
||||||
},
|
|
||||||
|
|
||||||
getCursorPosition: () => viewRef.current.state.selection.main.head,
|
|
||||||
|
|
||||||
setCursorPosition: (pos) => {
|
|
||||||
viewRef.current.dispatch({ selection: { anchor: pos } });
|
|
||||||
viewRef.current.focus();
|
|
||||||
},
|
|
||||||
|
|
||||||
undo: () => undo(viewRef.current),
|
|
||||||
redo: () => redo(viewRef.current),
|
|
||||||
|
|
||||||
historySize: () => {
|
|
||||||
const view = viewRef.current;
|
|
||||||
if (!view) return { done: 0, undone: 0 };
|
|
||||||
|
|
||||||
const h = view.state.field(historyField, false);
|
|
||||||
if (!h) return { done: 0, undone: 0 };
|
|
||||||
|
|
||||||
return { done: h.done.length, undone: h.undone.length };
|
|
||||||
},
|
|
||||||
|
|
||||||
focus: () => viewRef.current.focus(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
return <div ref={editorRef} style={{ height: "100%" }} />;
|
|
||||||
});
|
|
||||||
|
|
||||||
export default CodeEditor;
|
|
||||||
|
|||||||
@@ -1,60 +1,81 @@
|
|||||||
@import (less) 'codemirror/lib/codemirror.css';
|
// Icon fonts for emoji/autocomplete
|
||||||
@import (less) 'codemirror/addon/fold/foldgutter.css';
|
@import (less) "@themes/fonts/iconFonts/diceFont.less";
|
||||||
@import (less) 'codemirror/addon/search/matchesonscrollbar.css';
|
@import (less) "@themes/fonts/iconFonts/elderberryInn.less";
|
||||||
@import (less) 'codemirror/addon/dialog/dialog.css';
|
@import (less) "@themes/fonts/iconFonts/gameIcons.less";
|
||||||
@import (less) 'codemirror/addon/hint/show-hint.css';
|
@import (less) "@themes/fonts/iconFonts/fontAwesome.less";
|
||||||
|
|
||||||
//Icon fonts included so they can appear in emoji autosuggest dropdown
|
|
||||||
@import (less) '@themes/fonts/iconFonts/diceFont.less';
|
|
||||||
@import (less) '@themes/fonts/iconFonts/elderberryInn.less';
|
|
||||||
@import (less) '@themes/fonts/iconFonts/gameIcons.less';
|
|
||||||
@import (less) '@themes/fonts/iconFonts/fontAwesome.less';
|
|
||||||
|
|
||||||
@keyframes sourceMoveAnimation {
|
@keyframes sourceMoveAnimation {
|
||||||
50% { color : white;background-color : red;}
|
50% {
|
||||||
100% { color : unset;background-color : unset;}
|
color: white;
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
color: unset;
|
||||||
|
background-color: unset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.codeEditor {
|
.codeEditor {
|
||||||
@media screen and (pointer : coarse) {
|
font-family: monospace;
|
||||||
font-size : 16px;
|
height: 100%;
|
||||||
}
|
|
||||||
.CodeMirror-foldmarker {
|
@media screen and (pointer: coarse) {
|
||||||
font-family : inherit;
|
font-size: 16px;
|
||||||
font-weight : 600;
|
|
||||||
color : grey;
|
|
||||||
text-shadow : none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.CodeMirror-foldgutter {
|
/* Line numbers and gutters */
|
||||||
cursor : pointer;
|
.cm-gutters {
|
||||||
border-left : 1px solid #EEEEEE;
|
background-color: #f0f0f0;
|
||||||
transition : background 0.1s;
|
color: #555;
|
||||||
&:hover { background : #DDDDDD; }
|
border-right: 1px solid #ddd;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sourceMoveFlash .CodeMirror-line {
|
/* Folding gutter */
|
||||||
animation-name : sourceMoveAnimation;
|
.cm-foldGutter {
|
||||||
animation-duration : 0.4s;
|
cursor: pointer;
|
||||||
|
color: grey;
|
||||||
|
font-weight: 600;
|
||||||
|
transition: background 0.1s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #dddddd;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.CodeMirror-search-field {
|
/* Active line */
|
||||||
width:25em !important;
|
.cm-activeLine {
|
||||||
outline:1px inset #00000055 !important;
|
background-color: #f5f5f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cm-activeLineGutter {
|
||||||
|
background-color: #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flash animation for source moves */
|
||||||
|
.sourceMoveFlash .cm-line {
|
||||||
|
animation-name: sourceMoveAnimation;
|
||||||
|
animation-duration: 0.4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search input */
|
||||||
|
.cm-searchField {
|
||||||
|
width: 25em !important;
|
||||||
|
outline: 1px inset #00000055 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tab character visualization (optional) */
|
||||||
//.cm-tab {
|
//.cm-tab {
|
||||||
// background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAQAAACOs/baAAAARUlEQVR4nGJgIAG8JkXxUAcCtDWemcGR1lY4MvgzCEKY7jSBjgxBDAG09UEQzAe0AMwMHrSOAwEGRtpaMIwAAAAA//8DAG4ID9EKs6YqAAAAAElFTkSuQmCC) no-repeat right;
|
// background: url(...) no-repeat right;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
//.cm-trailingspace {
|
/* Trailing space visualization (optional) */
|
||||||
// .cm-space {
|
//.cm-trailingSpace .cm-space {
|
||||||
// background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQAgMAAABW5NbuAAAACVBMVEVHcEwAAAAAAAAWawmTAAAAA3RSTlMAPBJ6PMxpAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAFUlEQVQI12NgwACcCQysASAEZGAAACMuAX06aCQUAAAAAElFTkSuQmCC) no-repeat right;
|
// background: url(...) no-repeat right;
|
||||||
// }
|
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Emoji preview styling */
|
||||||
.emojiPreview {
|
.emojiPreview {
|
||||||
font-size : 1.5em;
|
font-size: 1.5em;
|
||||||
line-height : 1.2em;
|
line-height: 1.2em;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
background:white;
|
background:white;
|
||||||
.codeEditor {
|
.codeEditor {
|
||||||
height : calc(100% - 25px);
|
height : calc(100% - 25px);
|
||||||
.CodeMirror { height : 100%; }
|
.cm-editor { height : 100%; }
|
||||||
.pageLine, .snippetLine {
|
.pageLine, .snippetLine {
|
||||||
background : #33333328;
|
background : #33333328;
|
||||||
border-top : #333399 solid 1px;
|
border-top : #333399 solid 1px;
|
||||||
|
|||||||
13
package-lock.json
generated
13
package-lock.json
generated
@@ -21,6 +21,7 @@
|
|||||||
"@codemirror/lang-markdown": "^6.5.0",
|
"@codemirror/lang-markdown": "^6.5.0",
|
||||||
"@codemirror/language": "^6.12.2",
|
"@codemirror/language": "^6.12.2",
|
||||||
"@codemirror/state": "^6.6.0",
|
"@codemirror/state": "^6.6.0",
|
||||||
|
"@codemirror/theme-one-dark": "^6.1.3",
|
||||||
"@codemirror/view": "^6.40.0",
|
"@codemirror/view": "^6.40.0",
|
||||||
"@dmsnell/diff-match-patch": "^1.1.0",
|
"@dmsnell/diff-match-patch": "^1.1.0",
|
||||||
"@googleapis/drive": "^20.1.0",
|
"@googleapis/drive": "^20.1.0",
|
||||||
@@ -2173,6 +2174,18 @@
|
|||||||
"@marijn/find-cluster-break": "^1.0.0"
|
"@marijn/find-cluster-break": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@codemirror/theme-one-dark": {
|
||||||
|
"version": "6.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.3.tgz",
|
||||||
|
"integrity": "sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/language": "^6.0.0",
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@codemirror/view": "^6.0.0",
|
||||||
|
"@lezer/highlight": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@codemirror/view": {
|
"node_modules/@codemirror/view": {
|
||||||
"version": "6.40.0",
|
"version": "6.40.0",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.40.0.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.40.0.tgz",
|
||||||
|
|||||||
@@ -97,6 +97,7 @@
|
|||||||
"@codemirror/lang-markdown": "^6.5.0",
|
"@codemirror/lang-markdown": "^6.5.0",
|
||||||
"@codemirror/language": "^6.12.2",
|
"@codemirror/language": "^6.12.2",
|
||||||
"@codemirror/state": "^6.6.0",
|
"@codemirror/state": "^6.6.0",
|
||||||
|
"@codemirror/theme-one-dark": "^6.1.3",
|
||||||
"@codemirror/view": "^6.40.0",
|
"@codemirror/view": "^6.40.0",
|
||||||
"@dmsnell/diff-match-patch": "^1.1.0",
|
"@dmsnell/diff-match-patch": "^1.1.0",
|
||||||
"@googleapis/drive": "^20.1.0",
|
"@googleapis/drive": "^20.1.0",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
.editor .codeEditor .CodeMirror {
|
.editor .codeEditor .cm-editor {
|
||||||
// Themes with dark backgrounds
|
// Themes with dark backgrounds
|
||||||
&.cm-s-3024-night,
|
&.cm-s-3024-night,
|
||||||
&.cm-s-abbott,
|
&.cm-s-abbott,
|
||||||
|
|||||||
@@ -15,11 +15,11 @@
|
|||||||
--highlight: #bcbcbc;
|
--highlight: #bcbcbc;
|
||||||
color: #91A6AA;
|
color: #91A6AA;
|
||||||
background: var(--bg);
|
background: var(--bg);
|
||||||
.CodeMirror-scroll {
|
.cm-scroller {
|
||||||
.CodeMirror-gutters {
|
.cm-gutters {
|
||||||
border-right: 1px solid #555;
|
border-right: 1px solid #555;
|
||||||
background: var(--bg);
|
background: var(--bg);
|
||||||
.CodeMirror-gutter {
|
.cm-gutter {
|
||||||
background-color: var(--bg);
|
background-color: var(--bg);
|
||||||
&.CodeMirror-foldgutter {
|
&.CodeMirror-foldgutter {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -31,9 +31,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.CodeMirror-lines {
|
.cm-content {
|
||||||
/* Line numbers*/
|
/* Line numbers*/
|
||||||
.CodeMirror-linenumber.CodeMirror-gutter-elt {
|
.CodeMirror-linenumber.cm-gutter-elt {
|
||||||
background-color: var(--bg);
|
background-color: var(--bg);
|
||||||
color: #81969A;
|
color: #81969A;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,13 +18,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Line number stuff */
|
/* Line number stuff */
|
||||||
.CodeMirror-gutter-elt {
|
.cm-gutter-elt {
|
||||||
color: #81969A;
|
color: #81969A;
|
||||||
}
|
}
|
||||||
.CodeMirror-linenumber {
|
.CodeMirror-linenumber {
|
||||||
background-color: #0C0C0C;
|
background-color: #0C0C0C;
|
||||||
}
|
}
|
||||||
.CodeMirror-gutter {
|
.cm-gutter {
|
||||||
background-color: #0C0C0C;
|
background-color: #0C0C0C;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user