2023-03-24 09:59:13 -04:00
|
|
|
import { StateEffect, StateField } from '@codemirror/state'
|
|
|
|
import { Decoration, EditorView, hoverTooltip, Tooltip } from '@codemirror/view'
|
2023-03-30 05:16:26 -04:00
|
|
|
import { Highlight } from '../services/types/doc'
|
2023-03-24 09:59:13 -04:00
|
|
|
|
|
|
|
export const setHighlightsEffect = StateEffect.define<Highlight[]>()
|
|
|
|
|
|
|
|
function highlightToMarker(highlight: Highlight) {
|
|
|
|
const className =
|
|
|
|
highlight.type === 'addition' ? 'ol-addition-marker' : 'ol-deletion-marker'
|
|
|
|
const { from, to } = highlight.range
|
|
|
|
|
|
|
|
return Decoration.mark({
|
|
|
|
class: className,
|
|
|
|
attributes: {
|
|
|
|
style: `--hue: ${highlight.hue}`,
|
|
|
|
},
|
|
|
|
}).range(from, to)
|
|
|
|
}
|
|
|
|
|
|
|
|
const theme = EditorView.baseTheme({
|
|
|
|
'.ol-addition-marker': {
|
|
|
|
backgroundColor: 'hsl(var(--hue), 70%, 85%)',
|
|
|
|
},
|
|
|
|
'.ol-deletion-marker': {
|
|
|
|
textDecoration: 'line-through',
|
|
|
|
},
|
|
|
|
'&.overall-theme-dark .ol-deletion-marker': {
|
|
|
|
color: 'hsl(var(--hue), 100%, 60%)',
|
|
|
|
},
|
|
|
|
'&.overall-theme-light .ol-deletion-marker': {
|
|
|
|
color: 'hsl(var(--hue), 70%, 40%)',
|
|
|
|
},
|
|
|
|
'.cm-tooltip-hover': {
|
|
|
|
backgroundColor: 'transparent',
|
|
|
|
borderWidth: 0,
|
|
|
|
},
|
|
|
|
'.ol-cm-highlight-tooltip': {
|
|
|
|
backgroundColor: 'hsl(var(--hue), 70%, 50%)',
|
|
|
|
borderRadius: '4px',
|
|
|
|
padding: '4px',
|
|
|
|
color: '#fff',
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
const tooltip = (view: EditorView, pos: number, side: any): Tooltip | null => {
|
|
|
|
const highlights = view.state.field(highlightsField)
|
|
|
|
const highlight = highlights.find(highlight => {
|
|
|
|
const { from, to } = highlight.range
|
|
|
|
return !(
|
|
|
|
pos < from ||
|
|
|
|
pos > to ||
|
|
|
|
(pos === from && side < 0) ||
|
|
|
|
(pos === to && side > 0)
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
if (!highlight) {
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
pos: highlight.range.from,
|
|
|
|
end: highlight.range.to,
|
|
|
|
above: true,
|
|
|
|
create: () => {
|
|
|
|
const dom = document.createElement('div')
|
|
|
|
dom.classList.add('ol-cm-highlight-tooltip')
|
|
|
|
dom.style.setProperty('--hue', highlight.hue.toString())
|
|
|
|
dom.textContent = highlight.label
|
|
|
|
|
|
|
|
return { dom }
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-14 06:57:15 -04:00
|
|
|
export const highlightsField = StateField.define<Highlight[]>({
|
2023-03-24 09:59:13 -04:00
|
|
|
create() {
|
|
|
|
return []
|
|
|
|
},
|
|
|
|
update(highlightMarkers, tr) {
|
|
|
|
for (const effect of tr.effects) {
|
|
|
|
if (effect.is(setHighlightsEffect)) {
|
|
|
|
return effect.value
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return highlightMarkers
|
|
|
|
},
|
|
|
|
provide: field => [
|
|
|
|
EditorView.decorations.from(field, highlights =>
|
|
|
|
Decoration.set(highlights.map(highlight => highlightToMarker(highlight)))
|
|
|
|
),
|
|
|
|
theme,
|
|
|
|
hoverTooltip(tooltip, { hoverTime: 0 }),
|
|
|
|
],
|
|
|
|
})
|
|
|
|
|
|
|
|
export function highlights() {
|
|
|
|
return highlightsField
|
|
|
|
}
|