mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 21:10:38 +03:00
Add tooltips
This commit is contained in:
parent
54b10e4bf6
commit
cc882ad53a
|
@ -1,19 +1,20 @@
|
||||||
import { bracketMatching, MatchResult } from '@codemirror/language';
|
import { bracketMatching, MatchResult } from '@codemirror/language';
|
||||||
import { Decoration, EditorView } from '@codemirror/view';
|
import { Decoration, EditorView } from '@codemirror/view';
|
||||||
|
|
||||||
const matchingMark = Decoration.mark({class: "cc-matchingBracket"}),
|
const matchingMark = Decoration.mark({class: "cc-matchingBracket"});
|
||||||
nonmatchingMark = Decoration.mark({class: "cc-nonmatchingBracket"})
|
const nonmatchingMark = Decoration.mark({class: "cc-nonmatchingBracket"});
|
||||||
|
|
||||||
function bracketRender(match: MatchResult) {
|
function bracketRender(match: MatchResult) {
|
||||||
const decorations = []
|
const decorations = [];
|
||||||
const mark = match.matched ? matchingMark : nonmatchingMark
|
const mark = match.matched ? matchingMark : nonmatchingMark;
|
||||||
decorations.push(mark.range(match.start.from, match.start.to))
|
decorations.push(mark.range(match.start.from, match.start.to));
|
||||||
if (match.end) decorations.push(mark.range(match.end.from, match.end.to))
|
if (match.end) {
|
||||||
return decorations
|
decorations.push(mark.range(match.end.from, match.end.to));
|
||||||
|
}
|
||||||
|
return decorations;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ccBracketMatching(darkMode: boolean) {
|
const darkTheme = EditorView.baseTheme({
|
||||||
const bracketTheme = EditorView.baseTheme({
|
|
||||||
'.cc-matchingBracket': {
|
'.cc-matchingBracket': {
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
},
|
},
|
||||||
|
@ -22,9 +23,23 @@ export function ccBracketMatching(darkMode: boolean) {
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
},
|
},
|
||||||
'&.cm-focused .cc-matchingBracket': {
|
'&.cm-focused .cc-matchingBracket': {
|
||||||
backgroundColor: darkMode ? '#734f00' : '#dae6f2',
|
backgroundColor: '#734f00',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return [bracketMatching({ renderMatch: bracketRender }), bracketTheme];
|
const lightTheme = EditorView.baseTheme({
|
||||||
|
'.cc-matchingBracket': {
|
||||||
|
fontWeight: 600,
|
||||||
|
},
|
||||||
|
'.cc-nonmatchingBracket': {
|
||||||
|
color: '#ef4444',
|
||||||
|
fontWeight: 700,
|
||||||
|
},
|
||||||
|
'&.cm-focused .cc-matchingBracket': {
|
||||||
|
backgroundColor: '#dae6f2',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export function ccBracketMatching(darkMode: boolean) {
|
||||||
|
return [bracketMatching({ renderMatch: bracketRender }), darkMode ? darkTheme : lightTheme];
|
||||||
}
|
}
|
|
@ -6,10 +6,11 @@ import CodeMirror, { BasicSetupOptions, ReactCodeMirrorProps, ReactCodeMirrorRef
|
||||||
import { EditorView } from 'codemirror';
|
import { EditorView } from 'codemirror';
|
||||||
import { Ref, useMemo } from 'react';
|
import { Ref, useMemo } from 'react';
|
||||||
|
|
||||||
|
import { useRSForm } from '../../context/RSFormContext';
|
||||||
import { useConceptTheme } from '../../context/ThemeContext';
|
import { useConceptTheme } from '../../context/ThemeContext';
|
||||||
import { ccBracketMatching } from './bracketMatching';
|
import { ccBracketMatching } from './bracketMatching';
|
||||||
import { RSLanguage } from './rslang';
|
import { RSLanguage } from './rslang';
|
||||||
//import { cursorTooltip } from './tooltip';
|
import { rshoverTooltip } from './tooltip';
|
||||||
|
|
||||||
const editorSetup: BasicSetupOptions = {
|
const editorSetup: BasicSetupOptions = {
|
||||||
highlightSpecialChars: false,
|
highlightSpecialChars: false,
|
||||||
|
@ -51,6 +52,7 @@ function RSInput({
|
||||||
...props
|
...props
|
||||||
}: RSInputProps) {
|
}: RSInputProps) {
|
||||||
const { darkMode } = useConceptTheme();
|
const { darkMode } = useConceptTheme();
|
||||||
|
const { schema } = useRSForm();
|
||||||
|
|
||||||
const cursor = useMemo(() => editable ? 'cursor-text': 'cursor-default', [editable]);
|
const cursor = useMemo(() => editable ? 'cursor-text': 'cursor-default', [editable]);
|
||||||
const lightTheme: Extension = useMemo(
|
const lightTheme: Extension = useMemo(
|
||||||
|
@ -64,7 +66,7 @@ function RSInput({
|
||||||
caret: '#5d00ff',
|
caret: '#5d00ff',
|
||||||
},
|
},
|
||||||
styles: [
|
styles: [
|
||||||
{ tag: t.name, class: 'text-[#b266ff]' }, // GlobalID
|
{ tag: t.name, class: 'text-[#b266ff] cursor-default' }, // GlobalID
|
||||||
{ tag: t.variableName, class: 'text-[#24821a]' }, // LocalID
|
{ tag: t.variableName, class: 'text-[#24821a]' }, // LocalID
|
||||||
{ tag: t.propertyName, class: '' }, // Radical
|
{ tag: t.propertyName, class: '' }, // Radical
|
||||||
{ tag: t.keyword, class: 'text-[#001aff]' }, // keywords
|
{ tag: t.keyword, class: 'text-[#001aff]' }, // keywords
|
||||||
|
@ -85,7 +87,7 @@ function RSInput({
|
||||||
caret: '#ffaa00'
|
caret: '#ffaa00'
|
||||||
},
|
},
|
||||||
styles: [
|
styles: [
|
||||||
{ tag: t.name, class: 'text-[#dfbfff]' }, // GlobalID
|
{ tag: t.name, class: 'text-[#dfbfff] cursor-default' }, // GlobalID
|
||||||
{ tag: t.variableName, class: 'text-[#69bf60]' }, // LocalID
|
{ tag: t.variableName, class: 'text-[#69bf60]' }, // LocalID
|
||||||
{ tag: t.propertyName, class: '' }, // Radical
|
{ tag: t.propertyName, class: '' }, // Radical
|
||||||
{ tag: t.keyword, class: 'text-[#808dff]' }, // keywords
|
{ tag: t.keyword, class: 'text-[#808dff]' }, // keywords
|
||||||
|
@ -100,8 +102,8 @@ function RSInput({
|
||||||
EditorView.lineWrapping,
|
EditorView.lineWrapping,
|
||||||
RSLanguage,
|
RSLanguage,
|
||||||
ccBracketMatching(darkMode),
|
ccBracketMatching(darkMode),
|
||||||
//cursorTooltip(),
|
rshoverTooltip(schema?.items || []),
|
||||||
], [darkMode]);
|
], [darkMode, schema?.items]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`w-full ${cursor} text-lg`}>
|
<div className={`w-full ${cursor} text-lg`}>
|
||||||
|
|
|
@ -1,53 +1,64 @@
|
||||||
import { EditorState, Extension, StateField } from "@codemirror/state";
|
import { Extension } from "@codemirror/state";
|
||||||
import { EditorView, showTooltip } from "@codemirror/view";
|
import { hoverTooltip } from "@codemirror/view";
|
||||||
|
|
||||||
function getCursorTooltips(state: EditorState) {
|
import { IConstituenta } from '../../utils/models';
|
||||||
return state.selection.ranges
|
import { getCstTypificationLabel } from '../../utils/staticUI';
|
||||||
.filter(range => !range.empty)
|
|
||||||
.map(range => {
|
function createTooltipFor(cst: IConstituenta) {
|
||||||
const line = state.doc.lineAt(range.head);
|
const dom = document.createElement('div');
|
||||||
const text = `${line.number}:${range.head - line.from}`;
|
dom.className = 'overflow-y-auto border shadow-md max-h-[25rem] max-w-[25rem] min-w-[10rem] w-fit z-20 text-sm';
|
||||||
|
const alias = document.createElement('h1');
|
||||||
|
alias.className = 'text-sm text-left';
|
||||||
|
alias.textContent = `${cst.alias}: ${getCstTypificationLabel(cst)}`;
|
||||||
|
dom.appendChild(alias);
|
||||||
|
if (cst.term.resolved) {
|
||||||
|
const term = document.createElement('p');
|
||||||
|
term.innerHTML = `<b>Термин:</b> ${cst.term.resolved}`;
|
||||||
|
dom.appendChild(term);
|
||||||
|
}
|
||||||
|
if (cst.definition.formal) {
|
||||||
|
const expression = document.createElement('p');
|
||||||
|
expression.innerHTML = `<b>Выражение:</b> ${cst.definition.formal}`;
|
||||||
|
dom.appendChild(expression);
|
||||||
|
}
|
||||||
|
if (cst.definition.text.resolved) {
|
||||||
|
const definition = document.createElement('p');
|
||||||
|
definition.innerHTML = `<b>Определение:</b> ${cst.definition.text.resolved}`;
|
||||||
|
dom.appendChild(definition);
|
||||||
|
}
|
||||||
|
if (cst.convention) {
|
||||||
|
const convention = document.createElement('p');
|
||||||
|
convention.innerHTML = `<b>Конвенция:</b> ${cst.convention}`;
|
||||||
|
dom.appendChild(convention);
|
||||||
|
}
|
||||||
|
return { dom: dom }
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getHoverTooltip = (items: IConstituenta[]) => {
|
||||||
|
return hoverTooltip((view, pos, side) => {
|
||||||
|
const {from, to, text} = view.state.doc.lineAt(pos);
|
||||||
|
let start = pos, end = pos;
|
||||||
|
while (start > from && /\w/.test(text[start - from - 1]))
|
||||||
|
start--;
|
||||||
|
while (end < to && /\w/.test(text[end - from]))
|
||||||
|
end++;
|
||||||
|
if (start == pos && side < 0 || end == pos && side > 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const alias = text.slice(start - from, end - from);
|
||||||
|
const cst = items.find(cst => cst.alias === alias);
|
||||||
|
if (!cst) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
pos: (range.to + range.from)/2,
|
pos: start,
|
||||||
|
end: end,
|
||||||
above: false,
|
above: false,
|
||||||
strictSide: true,
|
create: () => createTooltipFor(cst)
|
||||||
create: () => {
|
|
||||||
const dom = document.createElement("div");
|
|
||||||
dom.className = "cm-tooltip-cursor";
|
|
||||||
dom.textContent = text;
|
|
||||||
return { dom };
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const cursorTooltipField = StateField.define({
|
export function rshoverTooltip(items: IConstituenta[]): Extension {
|
||||||
create: getCursorTooltips,
|
return [getHoverTooltip(items)];
|
||||||
update(tooltips, transaction) {
|
|
||||||
if (!transaction.docChanged && !transaction.selection) {
|
|
||||||
return tooltips;
|
|
||||||
}
|
|
||||||
return getCursorTooltips(transaction.state);
|
|
||||||
},
|
|
||||||
provide: field => showTooltip.computeN([field], state => state.field(field))
|
|
||||||
});
|
|
||||||
|
|
||||||
const cursorTooltipBaseTheme = EditorView.baseTheme({
|
|
||||||
".cm-tooltip.cm-tooltip-cursor": {
|
|
||||||
backgroundColor: "#66b",
|
|
||||||
color: "white",
|
|
||||||
border: "none",
|
|
||||||
padding: "2px 7px",
|
|
||||||
borderRadius: "4px",
|
|
||||||
"&.cm-tooltip-arrow:before": {
|
|
||||||
borderTopColor: "#66b"
|
|
||||||
},
|
|
||||||
"&.cm-tooltip-arrow:after": {
|
|
||||||
borderTopColor: "transparent"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export function cursorTooltip(): Extension {
|
|
||||||
return [cursorTooltipField, cursorTooltipBaseTheme];
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user