diff --git a/editor/src/messages/tool/utility_types.rs b/editor/src/messages/tool/utility_types.rs index f02bd819..98cbd766 100644 --- a/editor/src/messages/tool/utility_types.rs +++ b/editor/src/messages/tool/utility_types.rs @@ -281,7 +281,7 @@ impl LayoutHolder for ToolData { .collect(); Layout::WidgetLayout(WidgetLayout { - layout: vec![LayoutGroup::Column { widgets: tool_groups_layout }], + layout: vec![LayoutGroup::Row { widgets: tool_groups_layout }], }) } } diff --git a/frontend/src/components/Editor.svelte b/frontend/src/components/Editor.svelte index 08d7853e..895fd99c 100644 --- a/frontend/src/components/Editor.svelte +++ b/frontend/src/components/Editor.svelte @@ -198,25 +198,18 @@ .layout-col { .scrollable-x, .scrollable-y { + overflow: hidden; + // Firefox (standardized in CSS, but less capable) scrollbar-width: thin; scrollbar-color: var(--color-5-dullgray) transparent; - &:not(:hover) { - scrollbar-width: none; - } - // WebKit (only in Chromium/Safari but more capable) &::-webkit-scrollbar { width: calc(2px + 6px + 2px); height: calc(2px + 6px + 2px); } - &:not(:hover)::-webkit-scrollbar { - width: 0; - height: 0; - } - &::-webkit-scrollbar-track { box-shadow: inset 0 0 0 1px var(--color-5-dullgray); border: 2px solid transparent; diff --git a/frontend/src/components/layout/FloatingMenu.svelte b/frontend/src/components/layout/FloatingMenu.svelte index 35db85ef..a66f2330 100644 --- a/frontend/src/components/layout/FloatingMenu.svelte +++ b/frontend/src/components/layout/FloatingMenu.svelte @@ -55,7 +55,7 @@ $: displayTail = open && type === "Popover"; $: displayContainer = open || measuringOngoing; $: extraClasses = Object.entries(classes) - .flatMap((classAndState) => (classAndState[1] ? [classAndState[0]] : [])) + .flatMap(([className, stateName]) => (stateName ? [className] : [])) .join(" "); $: extraStyles = Object.entries(styles) .flatMap((styleAndValue) => (styleAndValue[1] !== undefined ? [`${styleAndValue[0]}: ${styleAndValue[1]};`] : [])) diff --git a/frontend/src/components/layout/LayoutCol.svelte b/frontend/src/components/layout/LayoutCol.svelte index 3775987a..5d0a7cf8 100644 --- a/frontend/src/components/layout/LayoutCol.svelte +++ b/frontend/src/components/layout/LayoutCol.svelte @@ -12,7 +12,7 @@ let self: HTMLDivElement | undefined; $: extraClasses = Object.entries(classes) - .flatMap((classAndState) => (classAndState[1] ? [classAndState[0]] : [])) + .flatMap(([className, stateName]) => (stateName ? [className] : [])) .join(" "); $: extraStyles = Object.entries(styles) .flatMap((styleAndValue) => (styleAndValue[1] !== undefined ? [`${styleAndValue[0]}: ${styleAndValue[1]};`] : [])) diff --git a/frontend/src/components/layout/LayoutRow.svelte b/frontend/src/components/layout/LayoutRow.svelte index 388214c6..8eb96216 100644 --- a/frontend/src/components/layout/LayoutRow.svelte +++ b/frontend/src/components/layout/LayoutRow.svelte @@ -12,7 +12,7 @@ let self: HTMLDivElement | undefined; $: extraClasses = Object.entries(classes) - .flatMap((classAndState) => (classAndState[1] ? [classAndState[0]] : [])) + .flatMap(([className, stateName]) => (stateName ? [className] : [])) .join(" "); $: extraStyles = Object.entries(styles) .flatMap((styleAndValue) => (styleAndValue[1] !== undefined ? [`${styleAndValue[0]}: ${styleAndValue[1]};`] : [])) diff --git a/frontend/src/components/panels/Document.svelte b/frontend/src/components/panels/Document.svelte index 254dbfeb..b1ec18bc 100644 --- a/frontend/src/components/panels/Document.svelte +++ b/frontend/src/components/panels/Document.svelte @@ -21,6 +21,7 @@ UpdateEyedropperSamplingState, UpdateMouseCursor, UpdateDocumentNodeRender, + isWidgetSpanRow, } from "@graphite/wasm-communication/messages"; import EyedropperPreview, { ZOOM_WINDOW_DIMENSIONS } from "@graphite/components/floating-menus/EyedropperPreview.svelte"; @@ -80,6 +81,39 @@ $: canvasWidthCSS = canvasDimensionCSS(canvasSvgWidth); $: canvasHeightCSS = canvasDimensionCSS(canvasSvgHeight); + $: toolShelfTotalToolsAndSeparators = ((layoutGroup) => { + if (!isWidgetSpanRow(layoutGroup)) return undefined; + + let totalSeparators = 0; + let totalToolRowsFor1Columns = 0; + let totalToolRowsFor2Columns = 0; + let totalToolRowsFor3Columns = 0; + + const tally = () => { + totalToolRowsFor1Columns += toolsInCurrentGroup; + totalToolRowsFor2Columns += Math.ceil(toolsInCurrentGroup / 2); + totalToolRowsFor3Columns += Math.ceil(toolsInCurrentGroup / 3); + toolsInCurrentGroup = 0; + }; + + let toolsInCurrentGroup = 0; + layoutGroup.rowWidgets.forEach((widget) => { + if (widget.props.kind === "Separator") { + totalSeparators += 1; + tally(); + } else { + toolsInCurrentGroup += 1; + } + }); + tally(); + + return { + totalSeparators, + totalToolRowsFor1Columns, + totalToolRowsFor2Columns, + totalToolRowsFor3Columns, + }; + })($document.toolShelfLayout.layout[0]); function pasteFile(e: DragEvent) { const { dataTransfer } = e; @@ -428,17 +462,26 @@ {/if} - + {#if !$document.graphViewOverlayOpen} + {:else} + {/if} - - - + + @@ -523,71 +566,102 @@ min-width: 40px; } - &.for-graph .widget-layout { - flex-direction: row; - flex-grow: 1; + &.for-graph { justify-content: space-between; } } .shelf-and-table { + // Enables usage of the `100cqh` unit to reference the height of this container element. + container-type: size; + // Be sure to recalculate this if the items below the tools (working colors and graph overlay buttons) change height in the future. + --height-of-elements-below-tools: 104px; + // Target height for the tools within the container above the lower elements. + --available-height: calc(100cqh - var(--height-of-elements-below-tools)); + // The least height required to fit all the tools in 1 column and 2 columns, which the available space must exceed in order for the fewest number of columns to be used. + --1-col-required-height: calc(var(--total-tool-rows-for-1-columns) * 32px + var(--total-separators) * (1px + 8px * 2)); + --2-col-required-height: calc(var(--total-tool-rows-for-2-columns) * 32px + var(--total-separators) * (1px + 8px * 2)); + // Evaluates to 0px (if false) or 1px (if true). We multiply by 1000000 to force the result to be an integer 0 or 1 and not interpolate values in-between. + --needs-at-least-2-columns: calc(1px - clamp(0px, calc((var(--available-height) - Min(var(--available-height), var(--1-col-required-height))) * 1000000), 1px)); + --needs-at-least-3-columns: calc(1px - clamp(0px, calc((var(--available-height) - Min(var(--available-height), var(--2-col-required-height))) * 1000000), 1px)); + --columns: calc(1px + var(--needs-at-least-2-columns) + var(--needs-at-least-3-columns)); + .shelf { - width: 32px; flex: 0 0 auto; + justify-content: space-between; .tools { flex: 0 1 auto; - .icon-button[title^="Coming Soon"] { - opacity: 0.25; - transition: opacity 0.25s; - - &:hover { - opacity: 1; - } + // Firefox-specific workaround for this bug causing the scrollbar to cover up the toolbar instead of widening to accommodate the scrollbar: + // + // + // Remove this when the Firefox bug is fixed. + @-moz-document url-prefix() { + --available-height-plus-1: calc(var(--available-height) + 1px); + --3-col-required-height: calc(var(--total-tool-rows-for-3-columns) * 32px + var(--total-separators) * (1px + 8px * 2)); + --overflows-with-3-columns: calc(1px - clamp(0px, calc((var(--available-height-plus-1) - Min(var(--available-height-plus-1), var(--3-col-required-height))) * 1000000), 1px)); + --firefox-scrollbar-width-space-occupied: 8; // Might change someday, or on different platforms, but this is the value in FF 120 on Windows + padding-right: calc(var(--firefox-scrollbar-width-space-occupied) * var(--overflows-with-3-columns)); } - .icon-button:not(.active) { - .color-general { - fill: var(--color-data-general); + .widget-span { + flex-wrap: wrap; + width: calc(var(--columns) * 32); + + .icon-button { + margin: 0; + + &[title^="Coming Soon"] { + opacity: 0.25; + transition: opacity 0.25s; + + &:hover { + opacity: 1; + } + } + + &:not(.active) { + .color-general { + fill: var(--color-data-general); + } + + .color-vector { + fill: var(--color-data-vector); + } + + .color-raster { + fill: var(--color-data-raster); + } + } } - .color-vector { - fill: var(--color-data-vector); - } - - .color-raster { - fill: var(--color-data-raster); + .separator { + min-height: 0; } } } - .spacer { - flex: 1 0 auto; - min-height: 20px; - } - .shelf-bottom-widgets { flex: 0 0 auto; + align-items: center; - .widget-layout:first-of-type { + .graph-overlay-button-area { height: auto; align-items: center; } - .widget-layout:last-of-type { + .working-colors-button-area { height: auto; + margin: 0; + min-height: 0; - .widget-span.row { - min-height: 0; + .working-colors-button { + margin: 0; + } - .working-colors-button { - margin: 0; - } - - .icon-button { - --widget-height: 0; - } + .icon-button { + --widget-height: 0; } } } diff --git a/frontend/src/components/panels/Layers.svelte b/frontend/src/components/panels/Layers.svelte index dab698c8..ace3abed 100644 --- a/frontend/src/components/panels/Layers.svelte +++ b/frontend/src/components/panels/Layers.svelte @@ -363,7 +363,6 @@ height: 32px; flex: 0 0 auto; margin: 0 4px; - align-items: center; .widget-span { width: 100%; diff --git a/frontend/src/components/panels/Properties.svelte b/frontend/src/components/panels/Properties.svelte index ecf6c31f..85a1b4d4 100644 --- a/frontend/src/components/panels/Properties.svelte +++ b/frontend/src/components/panels/Properties.svelte @@ -30,23 +30,23 @@ - + - + + diff --git a/frontend/src/components/widgets/WidgetSection.svelte b/frontend/src/components/widgets/WidgetSection.svelte index 671fe838..92df997c 100644 --- a/frontend/src/components/widgets/WidgetSection.svelte +++ b/frontend/src/components/widgets/WidgetSection.svelte @@ -9,11 +9,15 @@ // eslint-disable-next-line @typescript-eslint/no-explicit-any export let layoutTarget: any; // TODO: Give type + let className = ""; + export { className as class }; + export let classes: Record = {}; + let expanded = true; - +