Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,19 @@ jobs:
exit 0
fi

size_of() { find frontend/dist/assets "$@" -printf '%s\n' | awk '{s+=$1} END {printf "%.2f MB", s/1048576}'; }
WASM_SIZE=$(size_of -name '*.wasm')
JS_SIZE=$(size_of -name '*.js')
CSS_SIZE=$(size_of -name '*.css')
FONT_SIZE=$(size_of \( -name '*.woff2' -o -name '*.woff' -o -name '*.ttf' -o -name '*.otf' \))
IMAGE_SIZE=$(size_of \( -name '*.png' -o -name '*.jpg' -o -name '*.svg' \))
ALL_SIZE=$(size_of -type f)

COMMENT_BODY="| 📦 **Web Build Complete for** $(git rev-parse HEAD) |
|-|
| $CF_URL |"
| $CF_URL |

Wasm: **$WASM_SIZE** — JS: **$JS_SIZE** — CSS: **$CSS_SIZE** — Fonts: **$FONT_SIZE** — Images: **$IMAGE_SIZE** — All Assets: **$ALL_SIZE**"

if [ "${{ github.ref }}" = "refs/tags/latest-stable" ]; then
# Push tag: skip commenting (commit was already commented on master merge)
Expand Down
57 changes: 34 additions & 23 deletions frontend/src/components/layout/FloatingMenu.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@
let measuringOngoingGuard = false;
let minWidthParentWidth = 0;
let pointerStillDown = false;
let floatingMenuBounds = new DOMRect();
let floatingMenuContentBounds = new DOMRect();

$: watchOpenChange(open);

Expand Down Expand Up @@ -189,9 +187,9 @@
if (!self || !floatingMenuContainer || !floatingMenuContent || !floatingMenuContentDiv) return;

const windowBounds = document.documentElement.getBoundingClientRect();
floatingMenuBounds = self.getBoundingClientRect();
const floatingMenuBounds = self.getBoundingClientRect();
const floatingMenuContainerBounds = floatingMenuContainer.getBoundingClientRect();
floatingMenuContentBounds = floatingMenuContentDiv.getBoundingClientRect();
const floatingMenuContentBounds = floatingMenuContentDiv.getBoundingClientRect();

const overflowingLeft = floatingMenuContentBounds.left - windowEdgeMargin <= windowBounds.left;
const overflowingRight = floatingMenuContentBounds.right + windowEdgeMargin >= windowBounds.right;
Expand All @@ -210,22 +208,30 @@
else if (direction === "Right" && overflowingRight) direction = "Left";
}

// These are set imperatively, not through reactive Svelte style bindings, because that would cause `afterUpdate()` to call this function recursively forever.
// CSS custom properties on the container are used instead of direct `.style` on the content because Svelte's `set_style` can replace the content's entire
// inline style when its managed `style` attribute updates, which would wipe out any manually-set properties like `top` and `left`.
floatingMenuContainer.style.removeProperty("--content-top");
floatingMenuContainer.style.removeProperty("--content-bottom");
floatingMenuContainer.style.removeProperty("--content-left");
floatingMenuContainer.style.removeProperty("--content-right");
floatingMenuContainer.style.removeProperty("--content-border-top-left-radius");
floatingMenuContainer.style.removeProperty("--content-border-top-right-radius");
floatingMenuContainer.style.removeProperty("--content-border-bottom-left-radius");
floatingMenuContainer.style.removeProperty("--content-border-bottom-right-radius");

const inParentFloatingMenu = Boolean(floatingMenuContainer.closest("[data-floating-menu-content]"));
const noPosition = Boolean(floatingMenuContainer.closest("[data-floating-menu-no-position]"));
if (!inParentFloatingMenu && !noPosition) {
// Required to correctly position content when scrolled (it has a `position: fixed` to prevent clipping)
// We use `.style` on a div (instead of a style DOM attribute binding) because the binding causes the `afterUpdate()` hook to call the function we're in recursively forever
let tailOffset = 0;
if (type === "Popover") tailOffset = 10;
if (type === "Tooltip") tailOffset = direction === "Bottom" ? 20 : 10;

if (direction === "Bottom") floatingMenuContentDiv.style.top = `${tailOffset + floatingMenuBounds.y}px`;
if (direction === "Top") floatingMenuContentDiv.style.bottom = `${tailOffset + (windowBounds.height - floatingMenuBounds.y)}px`;
if (direction === "Right") floatingMenuContentDiv.style.left = `${tailOffset + floatingMenuBounds.x}px`;
if (direction === "Left") floatingMenuContentDiv.style.right = `${tailOffset + (windowBounds.width - floatingMenuBounds.x)}px`;
if (direction === "Bottom") floatingMenuContainer.style.setProperty("--content-top", `${tailOffset + floatingMenuBounds.y}px`);
if (direction === "Top") floatingMenuContainer.style.setProperty("--content-bottom", `${tailOffset + (windowBounds.height - floatingMenuBounds.y)}px`);
if (direction === "Right") floatingMenuContainer.style.setProperty("--content-left", `${tailOffset + floatingMenuBounds.x}px`);
if (direction === "Left") floatingMenuContainer.style.setProperty("--content-right", `${tailOffset + (windowBounds.width - floatingMenuBounds.x)}px`);

// Required to correctly position tail when scrolled (it has a `position: fixed` to prevent clipping)
// We use `.style` on a div (instead of a style DOM attribute binding) because the binding causes the `afterUpdate()` hook to call the function we're in recursively forever
if (tail && direction === "Bottom") tail.style.top = `${floatingMenuBounds.y}px`;
if (tail && direction === "Top") tail.style.bottom = `${windowBounds.height - floatingMenuBounds.y}px`;
if (tail && direction === "Right") tail.style.left = `${floatingMenuBounds.x}px`;
Expand All @@ -239,45 +245,42 @@
if (direction === "Top" || direction === "Bottom") {
zeroedBorderVertical = direction === "Top" ? "Bottom" : "Top";

// We use `.style` on a div (instead of a style DOM attribute binding) because the binding causes the `afterUpdate()` hook to call the function we're in recursively forever
if (overflowingLeft) {
floatingMenuContentDiv.style.left = `${windowEdgeMargin}px`;
floatingMenuContainer.style.setProperty("--content-left", `${windowEdgeMargin}px`);
if (windowBounds.left + floatingMenuContainerBounds.left === 12) zeroedBorderHorizontal = "Left";
}
if (overflowingRight) {
floatingMenuContentDiv.style.right = `${windowEdgeMargin}px`;
floatingMenuContainer.style.setProperty("--content-right", `${windowEdgeMargin}px`);
if (windowBounds.right - floatingMenuContainerBounds.right === 12) zeroedBorderHorizontal = "Right";
}
}
if (direction === "Left" || direction === "Right") {
zeroedBorderHorizontal = direction === "Left" ? "Right" : "Left";

// We use `.style` on a div (instead of a style DOM attribute binding) because the binding causes the `afterUpdate()` hook to call the function we're in recursively forever
if (overflowingTop) {
floatingMenuContentDiv.style.top = `${windowEdgeMargin}px`;
floatingMenuContainer.style.setProperty("--content-top", `${windowEdgeMargin}px`);
if (windowBounds.top + floatingMenuContainerBounds.top === 12) zeroedBorderVertical = "Top";
}
if (overflowingBottom) {
floatingMenuContentDiv.style.bottom = `${windowEdgeMargin}px`;
floatingMenuContainer.style.setProperty("--content-bottom", `${windowEdgeMargin}px`);
if (windowBounds.bottom - floatingMenuContainerBounds.bottom === 12) zeroedBorderVertical = "Bottom";
}
}

// Remove the rounded corner from the content where the tail perfectly meets the corner
if (displayTail && windowEdgeMargin === 6 && zeroedBorderVertical && zeroedBorderHorizontal) {
// We use `.style` on a div (instead of a style DOM attribute binding) because the binding causes the `afterUpdate()` hook to call the function we're in recursively forever
switch (`${zeroedBorderVertical}${zeroedBorderHorizontal}`) {
case "TopLeft":
floatingMenuContentDiv.style.borderTopLeftRadius = "0";
floatingMenuContainer.style.setProperty("--content-border-top-left-radius", "0");
break;
case "TopRight":
floatingMenuContentDiv.style.borderTopRightRadius = "0";
floatingMenuContainer.style.setProperty("--content-border-top-right-radius", "0");
break;
case "BottomLeft":
floatingMenuContentDiv.style.borderBottomLeftRadius = "0";
floatingMenuContainer.style.setProperty("--content-border-bottom-left-radius", "0");
break;
case "BottomRight":
floatingMenuContentDiv.style.borderBottomRightRadius = "0";
floatingMenuContainer.style.setProperty("--content-border-bottom-right-radius", "0");
break;
default:
break;
Expand Down Expand Up @@ -537,12 +540,20 @@
box-shadow: rgba(var(--color-0-black-rgb), 0.5) 0 2px 4px;
border: 1px solid var(--color-3-darkgray);
border-radius: 4px;
border-top-left-radius: var(--content-border-top-left-radius, 4px);
border-top-right-radius: var(--content-border-top-right-radius, 4px);
border-bottom-left-radius: var(--content-border-bottom-left-radius, 4px);
border-bottom-right-radius: var(--content-border-bottom-right-radius, 4px);
color: var(--color-e-nearwhite);
font-size: inherit;
padding: 8px;
z-index: 0;
// Draw over the application without being clipped by the containing panel's `overflow: hidden`
position: fixed;
top: var(--content-top, auto);
bottom: var(--content-bottom, auto);
left: var(--content-left, auto);
right: var(--content-right, auto);
// Counteract the rightward shift caused by the border
margin-left: -1px;
}
Expand Down
14 changes: 7 additions & 7 deletions node-graph/nodes/text/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -682,25 +682,25 @@ fn string_length(_: impl Ctx, string: String) -> f64 {
string.graphemes(true).count() as f64
}

/// Splits a string into a list of substrings based on the specified delimeter. This is the inverse of the **String Join** node.
/// Splits a string into a list of substrings based on the specified delimiter. This is the inverse of the **String Join** node.
///
/// For example, splitting "a, b, c" with delimeter ", " produces `["a", "b", "c"]`.
/// For example, splitting "a, b, c" with delimiter ", " produces `["a", "b", "c"]`.
#[node_macro::node(category("Text"))]
fn string_split(
_: impl Ctx,
/// The string to split into substrings.
string: String,
/// The character(s) that separate the substrings. These are not included in the outputs.
#[default("\\n")]
delimeter: String,
/// Whether to convert escape sequences found in the delimeter into their corresponding characters:
delimiter: String,
/// Whether to convert escape sequences found in the delimiter into their corresponding characters:
/// "\n" (newline), "\r" (carriage return), "\t" (tab), "\0" (null), and "\\" (backslash).
#[default(true)]
delimeter_escaping: bool,
delimiter_escaping: bool,
) -> Vec<String> {
let delimeter = if delimeter_escaping { unescape_string(delimeter) } else { delimeter };
let delimiter = if delimiter_escaping { unescape_string(delimiter) } else { delimiter };

string.split(&delimeter).map(str::to_string).collect()
string.split(&delimiter).map(str::to_string).collect()
}

/// Joins a list of strings together with a separator between each pair. This is the inverse of the **String Split** node.
Expand Down
Loading