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;
-
+