diff --git a/main/blocklyinit.js b/main/blocklyinit.js index 8aeee5e7..58ece38f 100644 --- a/main/blocklyinit.js +++ b/main/blocklyinit.js @@ -2422,6 +2422,7 @@ export function createBlocklyWorkspace() { (function registerClipboardContextMenuItems() { const registry = Blockly.ContextMenuRegistry.registry; const BLOCK = Blockly.ContextMenuRegistry.ScopeType.BLOCK; + const WORKSPACE = Blockly.ContextMenuRegistry.ScopeType.WORKSPACE; const notInFlyout = (scope) => (scope.block?.isInFlyout ? 'hidden' : 'enabled'); const hasCopiedData = () => !!Blockly.clipboard?.getLastCopiedData?.(); @@ -2473,6 +2474,30 @@ export function createBlocklyWorkspace() { }, scopeType: BLOCK, }); + + registry.register({ + id: 'workspacePaste', + weight: 3, + displayText: () => Blockly.Msg['PASTE_SHORTCUT'] || 'Paste', + preconditionFn: () => (hasCopiedData() ? 'enabled' : 'disabled'), + callback: (scope) => { + const data = Blockly.clipboard?.getLastCopiedData?.(); + if (!data) return; + const ws = scope?.workspace ?? mainWs; + if (!ws) return; + pasteAsChildOrHere(null, ws, data); + }, + scopeType: WORKSPACE, + }); + + if (!registry.getItem?.('flock_ws_sep_after_paste')) { + registry.register({ + id: 'flock_ws_sep_after_paste', + weight: 3.5, + separator: true, + scopeType: WORKSPACE, + }); + } })(); // Add separators to the block context menu to group related items. @@ -2857,7 +2882,8 @@ export function createBlocklyWorkspace() { const tbRect = blockToolbar.getBoundingClientRect(); let adj = 0; if (tbRect.left < margin) adj = margin - tbRect.left; - else if (tbRect.right > window.innerWidth - margin) adj = window.innerWidth - margin - tbRect.right; + else if (tbRect.right > window.innerWidth - margin) + adj = window.innerWidth - margin - tbRect.right; if (adj !== 0) { blockToolbar.style.left = `${blockCenterX + adj}px`; blockToolbar.style.setProperty('--caret-shift', `${-adj}px`); @@ -2876,7 +2902,7 @@ export function createBlocklyWorkspace() { } catch { /* scene not ready */ } - viewBtn.style.display = (!mesh || mesh.name === 'ground') ? 'none' : ''; + viewBtn.style.display = !mesh || mesh.name === 'ground' ? 'none' : ''; positionBlockToolbar(); blockToolbar.classList.add('visible'); } @@ -2888,8 +2914,7 @@ export function createBlocklyWorkspace() { blockToolbar.classList.remove('visible'); } - const isToolbarBlock = (block) => - block && !block.isInFlyout && !block.isShadow(); + const isToolbarBlock = (block) => block && !block.isInFlyout && !block.isShadow(); workspace.addChangeListener((e) => { if (e.type === Blockly.Events.SELECTED) { diff --git a/main/themes.js b/main/themes.js index ad31e265..b675e4bc 100644 --- a/main/themes.js +++ b/main/themes.js @@ -570,8 +570,8 @@ function getThemeBaseStyles(themeName) { flyoutForegroundColour: "#000000", flyoutOpacity: 1, scrollbarColour: "#000000", - insertionMarkerColour: "#FF0000", - insertionMarkerOpacity: 1, + insertionMarkerColour: "#FFFFFF", + insertionMarkerOpacity: 0.3, markerColour: "#FF0000", cursorColour: "#FF0000", }, @@ -601,8 +601,8 @@ function getThemeBaseStyles(themeName) { flyoutForegroundColour: "#000000", flyoutOpacity: 1, scrollbarColour: "#000000", - insertionMarkerColour: "#FF0000", - insertionMarkerOpacity: 1, + insertionMarkerColour: "#FFFFFF", + insertionMarkerOpacity: 0.3, markerColour: "#FF0000", cursorColour: "#FF0000", }, @@ -691,8 +691,8 @@ function getThemeBaseStyles(themeName) { flyoutForegroundColour: "#CFCFCF", flyoutOpacity: 1, scrollbarColour: "#E0E0E0", - insertionMarkerColour: "#E0E0E0", - insertionMarkerOpacity: 1, + insertionMarkerColour: "#000000", + insertionMarkerOpacity: 0.3, markerColour: "#E0E0E0", cursorColour: "#E0E0E0", fieldColour: "#1E1E1E", diff --git a/style/blockly.css b/style/blockly.css index 68946fc8..161bfbf7 100644 --- a/style/blockly.css +++ b/style/blockly.css @@ -56,18 +56,6 @@ --color-toolbox-focus: #fc3; } -[data-theme='dark-contrast'] .blocklyInsertionMarker path { - fill: grey !important; -} - -[data-theme='low-vision'] .blocklyInsertionMarker path { - fill: #e0e0e0 !important; -} - -[data-theme='contrast'] .blocklyInsertionMarker path { - fill: grey !important; -} - /* Only target text inputs with cursor: text */ .blocklyEditableText[style*='cursor: text'] > rect { fill: var(--color-bg) !important; @@ -496,6 +484,16 @@ body[data-theme='low-vision'] { color: var(--color-menu-item-text) !important; } +/* Disabled menu items (e.g. Paste with an empty clipboard). Blockly's default + greying targets .blocklyMenuItemDisabled, but the !important colour rule above + keeps the content at full strength — so grey the content explicitly here. */ +.blocklyDropDownDiv .blocklyMenuItemDisabled .goog-menuitem-content, +.blocklyWidgetDiv .blocklyMenuItemDisabled .goog-menuitem-content, +.blocklyDropDownDiv .blocklyMenuItemDisabled .blocklyMenuItemContent, +.blocklyWidgetDiv .blocklyMenuItemDisabled .blocklyMenuItemContent { + opacity: 0.45 !important; +} + /* Make blocklyFieldGridContainer the offsetParent for grid items so the keyboard-scroll logic in GridItem.focus() targets the right element. */ .blocklyFieldGridContainer {