diff --git a/client/components/codeEditor/codeEditor.jsx b/client/components/codeEditor/codeEditor.jsx index c5cf669bd..25bf4f88e 100644 --- a/client/components/codeEditor/codeEditor.jsx +++ b/client/components/codeEditor/codeEditor.jsx @@ -308,7 +308,7 @@ const CodeEditor = forwardRef( view.dispatch({ effects : themeCompartment.reconfigure(themeExtension), }); - }, [editorTheme]); + }, [editorTheme, tab]); useEffect(()=>{ //rebuild syntax highlight when changing tab or renderer diff --git a/client/components/codeEditor/extensions/customKeyMaps.js b/client/components/codeEditor/extensions/customKeyMaps.js index db3edf47f..581268222 100644 --- a/client/components/codeEditor/extensions/customKeyMaps.js +++ b/client/components/codeEditor/extensions/customKeyMaps.js @@ -1,33 +1,44 @@ /* eslint max-lines: ["error", { "max": 300 }] */ import { keymap } from '@codemirror/view'; -import { undo, redo, indentMore, deleteLine } from '@codemirror/commands'; +import { undo, redo, indentMore, indentLess, deleteLine } from '@codemirror/commands'; +import { EditorSelection } from '@codemirror/state'; import { Prec } from '@codemirror/state'; const insertTab = (view)=>{ - const { from, to } = view.state.selection.main; + // If any selection spans multiple lines, delegates to CodeMirror's indentMore + // Otherwise inserts two spaces at each cursor/selection + const shouldIndent = view.state.selection.ranges.some((range)=>view.state.doc.lineAt(range.from).number !== + view.state.doc.lineAt(range.to).number + ); + + if(shouldIndent) return indentMore(view); + + const changes = []; + + for (const range of view.state.selection.ranges) { + changes.push({ + from : range.from, + to : range.to, + insert : ' ' // Insert two spaces, not a tab char! + }); + } + // Create a transaction so we can map old positions to + // their new positions after the edits are applied + const mappedChanges = view.state.update({ changes }); view.dispatch({ - changes : { from, to, insert: ' ' }, - selection : { anchor: from + 2 } + changes, + selection : EditorSelection.create( + view.state.selection.ranges.map((range)=>EditorSelection.cursor( + mappedChanges.changes.mapPos(range.from, 1) + 2 + ) + ) + ) }); return true; }; -const indentLess = (view)=>{ - const { from, to } = view.state.selection.main; - const lines = []; - for (let l = view.state.doc.lineAt(from).number; l <= view.state.doc.lineAt(to).number; l++) { - const line = view.state.doc.line(l); - const match = line.text.match(/^ {1,2}/); // match up to 2 spaces - if(match) { - lines.push({ from: line.from, to: line.from + match[0].length, insert: '' }); - } - } - if(lines.length > 0) view.dispatch({ changes: lines }); - return true; -}; - const wrapSelection = (prefix, suffix)=>(view)=>{ const changes = []; @@ -169,16 +180,16 @@ const newPage = (view)=>{ }; export const generalKeymap = Prec.high(keymap.of([ - { key: 'Tab', run: insertTab }, - { key: 'Mod-z', run: undo }, //i think it may be unnecessary + { key: 'Tab', run: insertTab }, //runs indentMore if multiple lines selected in a single selection + { key: 'Shift-Tab', run: indentLess }, + { key: 'Mod-z', run: undo }, //it may be unnecessary { key: 'Mod-Shift-z', run: redo }, - { key: 'Mod-y', run: redo }, - { key: 'Mod-d', run: deleteLine }, + { key: 'Mod-y', run: redo }, //user asked, so double keybind + { key: 'Mod-d', run: deleteLine }, //annoyingly overrides "selectNextOccurrence" because users asked ])); export const markdownKeymap = Prec.highest(keymap.of([ - //{ key: 'Shift-Tab', run: indentMore }, - { key: 'Shift-Tab', run: indentLess }, + { key: 'Mod-b', run: wrapSelection('**', '**') }, // makeBold { key: 'Mod-i', run: wrapSelection('*', '*') }, // makeItalic { key: 'Mod-u', run: wrapSelection('', '') }, // makeUnderline diff --git a/client/components/dropdown/dropdown.jsx b/client/components/dropdown/dropdown.jsx index 0848f3fdd..b6ea37d13 100644 --- a/client/components/dropdown/dropdown.jsx +++ b/client/components/dropdown/dropdown.jsx @@ -92,12 +92,13 @@ const Dropdown = ({ groupName, className = null, icon, children, color = null, c }; return ( -
+
  • + ); }; diff --git a/client/components/dropdown/dropdown.less b/client/components/dropdown/dropdown.less index 28a26954c..8148a7c85 100644 --- a/client/components/dropdown/dropdown.less +++ b/client/components/dropdown/dropdown.less @@ -1,24 +1,33 @@ -.menu-wrapper { - position: relative; - &:is(.menu-bar > .menu-section > .menu-wrapper){ - display: inline-block; - } +@property --menuColor { + syntax: ''; + inherits: true; + initial-value: #DDD; } +@property --activeTriggerColor { + syntax: ''; + inherits: true; + initial-value: #DDD; +} + +:root{ + --activeTriggerColor : var(--activeTriggerColor); +} .menu-list { + contain : content; position : fixed; - z-index : 1000; top : anchor(bottom); left : anchor(left); position-try: flip-inline flip-block; color: inherit; // [popover] gets a `canvastext` color value from useragent. - > .menu-wrapper { - position:relative; - > .menu-list { + background: var(--menuColor); + li > .menu-list { margin: 0 0px; top : anchor(top); left : anchor(right); position-try: flip-inline; } - } +} +.menu-wrapper:has(:popover-open) > button { // if menu is open... + background-color: var(--activeTriggerColor, hsl(from var(--menuColor) h s calc(l * .85))); // tint menu triggers based on menu color } \ No newline at end of file diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index 976f8c9c1..05ca73bea 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -29,6 +29,7 @@ const TOOLBAR_STATE_KEY = 'HB_renderer_toolbarState'; const INITIAL_CONTENT = dedent` + Rendered Brew Content @@ -210,7 +211,7 @@ const BrewRenderer = (props)=>{ classes = [classes, injectedTags.classes].join(' ').trim(); attributes = injectedTags.attributes; if(global.enablev4) { - if (attributes && Object.hasOwn(attributes, 'hbtemplate')) { + if(attributes && Object.hasOwn(attributes, 'hbtemplate')) { pageTemplates[index] = attributes['hbtemplate']; } } @@ -220,7 +221,7 @@ const BrewRenderer = (props)=>{ if(!pageTemplates[index]) { for (let i=index;i>=0; i--) { // If one is found, add the template attribute - if (pageTemplates[i]) attributes['hbtemplate'] = pageTemplates[i]; + if(pageTemplates[i]) attributes['hbtemplate'] = pageTemplates[i]; } } } @@ -348,10 +349,11 @@ const BrewRenderer = (props)=>{ 0 ? state.visiblePages : [state.centerPage]} totalPages={rawPages.length} headerState={headerState} setHeaderState={setHeaderState}/> {/*render in iFrame so broken code doesn't crash the site.*/} - {emitClick();}} + sandbox="allow-same-origin allow-modals allow-top-navigation" >
    { if(blacklistAttrs.some((test)=>{return test(attribute);})) { - element.removeAttribute(attribute.localName); - break; + element.removeAttribute(attribute.name); + return; }; - }; + }); }); return div.innerHTML; diff --git a/client/homebrew/brewRenderer/toolBar/toolBar.jsx b/client/homebrew/brewRenderer/toolBar/toolBar.jsx index 16c89ea59..0f158e0e6 100644 --- a/client/homebrew/brewRenderer/toolBar/toolBar.jsx +++ b/client/homebrew/brewRenderer/toolBar/toolBar.jsx @@ -99,11 +99,16 @@ const ToolBar = ({ displayOptions, onDisplayOptionsChange, visiblePages, totalPa return (