diff --git a/main/themes.js b/main/themes.js index af6978ce..7fa482f5 100644 --- a/main/themes.js +++ b/main/themes.js @@ -263,6 +263,7 @@ function setIconImage(htmlCollectionIcons, imageURL) { for (const icon of htmlCollectionIcons) { for (const image of icon.getElementsByTagName('image')) { image.setAttribute('xlink:href', imageURL); + image.setAttribute('href', imageURL); } } } @@ -278,7 +279,7 @@ function setBinAndZoomIcons(themeName) { const zoomIcons = document.getElementsByClassName('blocklyZoom'); if (themeName === 'contrast') { - const iconsURL = './images/blocklywhitesprites.svg'; + const iconsURL = './images/blocklywhitesprites.png'; setIconImage(binIcon, iconsURL); setIconImage(zoomIcons, iconsURL); } else { diff --git a/style.css b/style.css index 61e581aa..5acb732b 100644 --- a/style.css +++ b/style.css @@ -1482,6 +1482,10 @@ button { background-color: var(--color-button-bg-hover); } +[data-theme='contrast'] .example-tab { + color: var(--color-bg); +} + .example-tab[aria-selected='true'] { background-color: var(--color-primary); border-color: var(--color-primary); @@ -1889,10 +1893,6 @@ body.color-picker-open #renderCanvas { height: 10px; } -[data-theme='contrast'] .menu-item[aria-haspopup='true']:hover .menu-arrow { - color: black; -} - #examples { min-width: 100px; flex-grow: 1; @@ -1917,18 +1917,6 @@ body.color-picker-open #renderCanvas { background-color: var(--color-menu-hover); } -[data-theme='contrast'] .menu-item:hover .menu-label { - color: black; -} - -[data-theme='contrast'] #main-menu a:hover { - color: black; -} - -[data-theme='contrast'] .menu-item:hover .menu-icon svg { - fill: black; -} - .menu-icon { width: 2em; min-width: 2em; @@ -2680,6 +2668,26 @@ svg.blocklyTrashcanFlyout { z-index: 1; } +/* Flipped below the block (see positionBlockToolbar): the toolbar renders + under the block instead of above it, so the caret triangles point up. */ +.fc-block-toolbar.below { + transform: translate(-50%, 7px); +} + +.fc-block-toolbar.below::after { + top: -7px; + bottom: auto; + border-top: 0; + border-bottom: 7px solid var(--color-border, #ddd); +} + +.fc-block-toolbar.below::before { + top: -5px; + bottom: auto; + border-top: 0; + border-bottom: 5px solid var(--color-menu, #f9f9f9); +} + .fc-block-toolbar.visible { opacity: 1; pointer-events: auto; diff --git a/ui/contextmenu.js b/ui/contextmenu.js index 6c6682ad..c232a3b3 100644 --- a/ui/contextmenu.js +++ b/ui/contextmenu.js @@ -882,6 +882,8 @@ export function initContextMenus(workspace) { return { left: topLeft.x, top: topLeft.y, + right: bottomRight.x, + bottom: bottomRight.y, width: bottomRight.x - topLeft.x, height: bottomRight.y - topLeft.y, }; @@ -903,6 +905,26 @@ export function initContextMenus(workspace) { return right === -Infinity ? null : right; } + function getWorkspaceTopEdge() { + const div = workspace.getInjectionDiv?.(); + if (!div) return null; + const r = div.getBoundingClientRect(); + return r.height > 0 ? r.top : null; + } + + // Get the position of the jaw start for a hat block to display the context menu + function getHatJawTopScreenY(block) { + if (block.previousConnection) return null; + const jawInput = block.inputList?.find((input) => input.type === Blockly.NEXT_STATEMENT); + const connection = jawInput?.connection; + if (!connection) return null; + const screen = Blockly.utils.svgMath.wsToScreenCoordinates( + workspace, + new Blockly.utils.Coordinate(connection.x, connection.y) + ); + return screen.y; + } + function positionBlockToolbar() { if (!toolbarBlock) return; const svgRoot = toolbarBlock.getSvgRoot?.(); @@ -914,13 +936,24 @@ export function initContextMenus(workspace) { const rect = getOwnBlockScreenRect(toolbarBlock) ?? svgRoot.getBoundingClientRect(); const blockCenterX = Math.round(rect.left + rect.width / 2); blockToolbar.style.left = `${blockCenterX}px`; - blockToolbar.style.top = `${Math.round(rect.top)}px`; blockToolbar.style.removeProperty('--caret-shift'); + const margin = 8; + const workspaceTop = getWorkspaceTopEdge(); + const minTop = workspaceTop != null ? workspaceTop + margin : margin; + + // Push the context bar below the block if it would be outside the top of the workspace + blockToolbar.style.top = `${Math.round(rect.top)}px`; + blockToolbar.classList.remove('below'); + if (blockToolbar.getBoundingClientRect().top < minTop) { + blockToolbar.classList.add('below'); + const jawTop = getHatJawTopScreenY(toolbarBlock); + blockToolbar.style.top = `${Math.round(jawTop ?? rect.bottom)}px`; + } + // Clamp to viewport, and to the right of the toolbox/flyout so the // toolbar is never tucked behind it. Shift the caret opposite so it // still points at the block. - const margin = 8; const toolboxRight = getToolboxRightEdge(); const minLeft = toolboxRight != null ? Math.max(margin, toolboxRight + margin) : margin; const tbRect = blockToolbar.getBoundingClientRect();