diff --git a/src/LiveDevelopment/BrowserScripts/RemoteFunctions.js b/src/LiveDevelopment/BrowserScripts/RemoteFunctions.js index d14a09c913..7d049eb79f 100644 --- a/src/LiveDevelopment/BrowserScripts/RemoteFunctions.js +++ b/src/LiveDevelopment/BrowserScripts/RemoteFunctions.js @@ -49,8 +49,8 @@ function RemoteFunctions(config = {}) { let _sourcelessClass = null; const SOURCELESS_RECOVER_DELAY_MS = 60; let _selectedFromEditor = false; - // the selected element the `phcode-no-lp-edit` opt-out is lifted for, see _isEditOptedOut - let _editOptOutOverride = null; + // the element selected by name (layers panel row), not by pointer + let _namedSelection = null; // Expose the currently selected element globally for external access window.__current_ph_lp_selected = null; @@ -140,7 +140,7 @@ function RemoteFunctions(config = {}) { } if(element && // element should exist - element.tagName.toLowerCase() !== "body" && // shouldn't be the body tag + (!isBodyElement(element) || _isNamedSelection(element)) && // body only when selected by name element.tagName.toLowerCase() !== "html" && // shouldn't be the HTML tag // this attribute is used by phoenix internal elements !element.closest(`[${GLOBALS.PHCODE_INTERNAL_ATTR}]`) && @@ -151,19 +151,23 @@ function RemoteFunctions(config = {}) { return false; } + // The body is never selected by pointer (blank clicks deselect, hover stays quiet), + // only by name from the layers panel or the caret, and then without the structural tools. + function isBodyElement(element) { + return !!(element && element.tagName && element.tagName.toLowerCase() === "body"); + } + + // a named selection lifts the `phcode-no-lp-edit` opt-out and the body block, both pointer-only guards + function _isNamedSelection(element) { + return !!element && element === _namedSelection; + } + /** * `phcode-no-lp-edit` cascades to descendants, `phcode-no-lp-edit-this` covers * the one element. - * - * The opt-out exists so that a pointer landing on the page is read as the page's - * own business rather than as an edit, and a click still is: handleElementClick - * tests for it before anything else. But an element the editor named outright - - * a row picked in the layers panel - is being edited on purpose and there is - * nothing ambiguous to protect, so while such an element holds the selection - * every tool treats it like any other. */ function _isEditOptedOut(element) { - if (element === _editOptOutOverride) { + if (_isNamedSelection(element)) { return false; } return !!(element.closest('.phcode-no-lp-edit') || @@ -246,6 +250,7 @@ function RemoteFunctions(config = {}) { getAllToolHandlers: getAllToolHandlers, isElementEditable: isElementEditable, isElementInspectable: isElementInspectable, + isBodyElement: isBodyElement, isSourceless: isSourceless, getElementRef: getElementRef, getElementByRef: getElementByRef, @@ -677,7 +682,8 @@ function RemoteFunctions(config = {}) { if (element === _lastHoverTarget) { return; } - if(!LivePreviewView.isElementInspectable(element) || element.nodeType !== Node.ELEMENT_NODE) { + if(isBodyElement(element) || !LivePreviewView.isElementInspectable(element) || + element.nodeType !== Node.ELEMENT_NODE) { return; } _lastHoverTarget = element; @@ -737,11 +743,10 @@ function RemoteFunctions(config = {}) { * @param {boolean} [fromEditor] - If true, this is an editor-cursor-driven selection; * only lightweight highlights (outline, margin/padding overlay) are shown, not interactive * UI like control box, spacing handles, or measurements. - * @param {boolean} [ignoreEditOptOut] - Edit this element even though it opted - * out of live preview editing. For selections asked for by name from the - * editor side; holds only while the element stays selected. + * @param {boolean} [byName] - Selected by name (a layers panel row), so the edit + * opt-out and the body block don't apply while it stays selected. */ - function selectElement(element, fromEditor, ignoreEditOptOut) { + function selectElement(element, fromEditor, byName) { // When a cursor-based highlight re-selects the already-selected element, // just refresh the highlight overlay without dismissing existing UI panels // (control box, editor box, element-info). This prevents cursor activity @@ -758,7 +763,7 @@ function RemoteFunctions(config = {}) { dismissUIAndCleanupState(); // set after the dismissal, which clears the previous selection's exemption - _editOptOutOverride = ignoreEditOptOut ? element : null; + _namedSelection = byName ? element : null; // this should also be there when users are in highlight mode scrollElementToViewPort(element); @@ -939,7 +944,8 @@ function RemoteFunctions(config = {}) { if(element && (element.closest('.phcode-no-lp-edit') || element.classList.contains('phcode-no-lp-edit-this'))) { return; } - if (!LivePreviewView.isElementInspectable(element)) { + // a blank-space click lands on the body and deselects, even a body selected by name + if (isBodyElement(element) || !LivePreviewView.isElementInspectable(element)) { dismissUIAndCleanupState(); return; } @@ -1093,7 +1099,7 @@ function RemoteFunctions(config = {}) { hideHighlight(); // Filter out the universal selector (*) from the rule - highlighting everything - // is not useful, similar to how we skip html/body in isElementInspectable. + // is not useful, similar to how we skip the html tag in isElementInspectable. // The rule can be a comma-separated list of selectors (from multi-cursor), // so we filter out any standalone * segments and keep valid ones. rule = rule.split(",").map(s => s.trim()).filter(s => s !== "*").join(","); @@ -1661,7 +1667,7 @@ function RemoteFunctions(config = {}) { window.__current_ph_lp_selected = null; } _unwatchSourcelessSelection(); - _editOptOutOverride = null; + _namedSelection = null; // Reset hover tracking so the same-element skip doesn't suppress // re-highlighting after a full state cleanup (e.g. Escape, dismiss). @@ -1761,7 +1767,7 @@ function RemoteFunctions(config = {}) { /** * This function dismisses all UI elements and cleans up application state - * Called when user presses Esc key, clicks on HTML/Body tags, or other dismissal events + * Called when user presses Esc key, clicks on blank page space (the body), or other dismissal events */ function dismissUIAndCleanupState() { getAllToolHandlers().forEach(handler => (handler.dismiss && handler.dismiss())); // to dismiss all UI boxes diff --git a/src/nls/root/strings.js b/src/nls/root/strings.js index 8e3db4d9ab..b904cc2a4d 100644 --- a/src/nls/root/strings.js +++ b/src/nls/root/strings.js @@ -833,11 +833,16 @@ define({ "LIVE_PREVIEW_LAYERS_SCROLL_ON_HOVER": "Scroll to Element on Hover", "LIVE_PREVIEW_LAYERS_MOVE_UP": "Move Up", "LIVE_PREVIEW_LAYERS_MOVE_DOWN": "Move Down", + "LIVE_PREVIEW_LAYERS_COPIED_HINT": "Copied. Right-click a row to paste below it.", + "LIVE_PREVIEW_LAYERS_CUT_HINT": "Cut. Right-click a row to paste below it.", "LIVE_PREVIEW_LAYERS_ADD_ATTRIBUTE": "Add Attribute", "LIVE_PREVIEW_LAYERS_REMOVE_ATTRIBUTE": "Remove Attribute", "LIVE_PREVIEW_LAYERS_PROPERTIES": "Properties", "LIVE_PREVIEW_LAYERS_STYLES": "Styles", - "LIVE_PREVIEW_LAYERS_NO_SELECTION": "Select an element to see its details", + "LIVE_PREVIEW_LAYERS_MAXIMIZE_SECTION": "Expand Section", + "LIVE_PREVIEW_LAYERS_RESTORE_SECTIONS": "Restore Sections", + "LIVE_PREVIEW_LAYERS_NO_SELECTION_PROPERTIES": "Select an element to see its properties", + "LIVE_PREVIEW_LAYERS_NO_SELECTION_STYLES": "Select an element to see its styles", "LIVE_PREVIEW_LAYERS_NOT_IN_SOURCE": "This element is not in the source file", "LIVE_PREVIEW_LAYERS_NO_STYLES": "No styles applied", "LIVE_PREVIEW_LAYERS_OPEN_SOURCE": "Open in editor", @@ -849,6 +854,16 @@ define({ "LIVE_PREVIEW_LAYERS_SHOW_SCRIPT_NODES": "Show Script-Generated Elements", "LIVE_PREVIEW_LAYERS_SCRIPT_GENERATED": "Generated by script, not in the source file", "LIVE_PREVIEW_LAYERS_TAG_TOOLTIP": "Show Tag Name Tooltip", + "LIVE_PREVIEW_LAYERS_INSERT_ELEMENT": "Insert Element", + "LIVE_PREVIEW_LAYERS_INSERT_INTO_PAGE": "Add to the page", + "LIVE_PREVIEW_LAYERS_INSERT_LOADING": "Loading elements…", + "LIVE_PREVIEW_LAYERS_INSERT_UNAVAILABLE": "The live preview did not answer. Try again in a moment.", + "LIVE_PREVIEW_LAYERS_EMPTY_PAGE": "This page has no elements yet.", + "LIVE_PREVIEW_LAYERS_ADD_ELEMENT": "Add an element", + "LIVE_PREVIEW_LAYERS_EMPTY_PAGE_PROPERTIES": "The page is empty. Add an element to see its properties.", + "LIVE_PREVIEW_LAYERS_EMPTY_PAGE_STYLES": "The page is empty. Add an element to see its styles.", + "LIVE_PREVIEW_LAYERS_SHOW_SELECTED": "Show the selected element", + "LIVE_PREVIEW_LAYERS_SCRUB_HINT": "Drag to adjust, double-click to edit", "LIVE_DEV_DETACHED_REPLACED_WITH_DEVTOOLS": "Live Preview was canceled because the browser's developer tools were opened", "LIVE_DEV_DETACHED_TARGET_CLOSED": "Live Preview was canceled because the page was closed in the browser", diff --git a/src/styles/Extn-LayersPanel.less b/src/styles/Extn-LayersPanel.less index ef16cc5497..ceee5f07c5 100644 --- a/src/styles/Extn-LayersPanel.less +++ b/src/styles/Extn-LayersPanel.less @@ -29,7 +29,7 @@ @layers-input-bg-focus: rgba(255, 255, 255, 0.06); @layers-row-height: 26px; @layers-label-min-width: 72px; -@layers-tools-width: 74px; +@layers-tools-width: 96px; @layers-indent: 14px; @layers-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace; @layers-prop-name: #9cdcfe; @@ -37,6 +37,7 @@ @layers-row-bg: @bc-ai-sidebar-bg; @layers-row-hover-bg: mix(#ffffff, @bc-ai-sidebar-bg, 6%); @layers-row-select-bg: mix(@layers-accent, @bc-ai-sidebar-bg, 16%); +@layers-row-holder-bg: mix(#ffffff, @bc-ai-sidebar-bg, 4%); .layers-icon-button() { display: flex; @@ -293,13 +294,16 @@ gap: 4px; margin-left: auto; flex-shrink: 0; - opacity: 0; } - .layers-section-header:hover .layers-section-actions, - .layers-section-actions:focus-within, - .layers-menu-open .layers-section-actions { - opacity: 1; + .layers-section-actions .layers-hdr-btn:not(.layers-active) { + display: none; + } + + .layers-section-header:hover .layers-section-actions .layers-hdr-btn, + .layers-section-actions:focus-within .layers-hdr-btn, + .layers-menu-open .layers-section-actions .layers-hdr-btn { + display: flex; } .layers-hdr-btn { @@ -315,6 +319,21 @@ } } + .layers-maximize { + opacity: 0; + + svg { + width: 11px; + height: 11px; + } + } + + .layers-section-header:hover .layers-maximize, + .layers-maximize:focus-visible, + .layers-maximize.layers-active { + opacity: 1; + } + .layers-section-content { position: relative; flex: 1; @@ -323,7 +342,8 @@ } .layers-section.layers-collapsed .layers-section-content, - .layers-section.layers-collapsed .layers-search { + .layers-section.layers-collapsed .layers-search, + .layers-section.layers-collapsed .layers-notice { display: none; } @@ -451,7 +471,7 @@ font-size: @sidebar-content-font-size; } - .layers-tree.layers-kbd-nav .layers-node:hover:not(.layers-selected):not(.layers-cursor) { + .layers-tree.layers-kbd-nav .layers-node:hover:not(.layers-selected) { background: transparent; } @@ -474,7 +494,8 @@ cursor: default; user-select: none; - &:hover { + &:hover, + &.layers-actions-open { background: @layers-hover-bg; } @@ -483,13 +504,12 @@ box-shadow: inset 2px 0 0 @layers-accent; } - &.layers-cursor { - background: @layers-hover-bg; - box-shadow: inset 2px 0 0 fade(@layers-accent, 70%); + &.layers-match { + box-shadow: inset 2px 0 0 fade(@layers-accent, 40%); } - &.layers-cursor-ancestor { - box-shadow: inset 2px 0 0 fade(@layers-accent, 35%); + &.layers-holds-selected { + background: @layers-row-holder-bg; } &.layers-text-active { @@ -505,6 +525,59 @@ &.layers-spring { animation: layers-spring-row 600ms ease-in-out; } + + &.layers-removing { + overflow: hidden; + pointer-events: none; + animation: layers-remove-row 200ms ease-in forwards; + } + + &.layers-clone-in { + overflow: hidden; + pointer-events: none; + animation: layers-clone-row 240ms cubic-bezier(0.2, 0, 0, 1) forwards; + } + } + + .layers-notice { + display: flex; + align-items: center; + gap: 7px; + flex-shrink: 0; + box-sizing: border-box; + margin: 0 8px 8px; + padding: 5px 8px 5px 5px; + border: 1px solid @layers-border; + border-radius: 6px; + background: @layers-input-bg; + color: @project-panel-text-1; + font-size: @sidebar-xs-font-size; + line-height: 1.4; + white-space: normal; + animation: layers-notice-in 180ms ease-out; + + .layers-notice-icon { + display: flex; + align-items: center; + justify-content: center; + flex: none; + width: 20px; + height: 20px; + border-radius: 4px; + background: @layers-accent-soft; + color: @layers-accent; + + svg { + width: 12px; + height: 12px; + display: block; + } + } + + .layers-notice-text { + flex: 1; + min-width: 0; + } } .layers-twisty { @@ -646,7 +719,7 @@ } .layers-node:hover .layers-node-tools, - .layers-node.layers-cursor .layers-node-tools { + .layers-node.layers-actions-open .layers-node-tools { background: @layers-row-hover-bg; } @@ -654,8 +727,39 @@ background: @layers-row-select-bg; } + .layers-node.layers-holds-selected:not(:hover) .layers-node-tools { + background: @layers-row-holder-bg; + } + + .layers-holder-chip { + position: absolute; + left: 0; + top: 50%; + width: 6px; + height: 18px; + margin-top: -9px; + padding: 0; + border: none; + border-radius: 0 3px 3px 0; + background: fade(@layers-accent, 65%); + cursor: pointer; + outline: none; + z-index: 1; + transition: width 100ms ease, background-color 100ms ease; + + &:hover { + width: 9px; + background: @layers-accent; + } + } + .layers-node-action { .layers-icon-button(); + + &.layers-active { + background: @layers-accent-soft; + color: @layers-accent; + } } .layers-drop-line { @@ -679,6 +783,58 @@ color: @project-panel-text-2; } + .layers-tree.layers-tree-empty { + display: flex; + min-height: 100%; + min-width: 0; + padding: 0; + box-sizing: border-box; + } + + .layers-empty-page { + display: flex; + flex: 1; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 4px; + padding: 20px 16px; + text-align: center; + white-space: normal; + } + + .layers-empty-page-text { + max-width: 220px; + color: @project-panel-text-2; + line-height: 1.5; + } + + .layers-empty-page .layers-message-btn { + display: inline-flex; + align-items: center; + gap: 6px; + margin-top: 8px; + padding: 5px 14px 5px 10px; + + svg { + width: 12px; + height: 12px; + flex: none; + } + } + + .layers-decl:not(.layers-editing) .layers-decl-value.layers-decl-numeric { + cursor: ew-resize; + } + + .layers-decl.layers-scrubbing { + background: @layers-hover-bg; + + .layers-decl-value { + color: @layers-accent; + } + } + .layers-label { font-size: 10px; font-weight: 700; @@ -1016,29 +1172,399 @@ body.layers-resizing { user-select: none; } +body.layers-scrubbing { + cursor: ew-resize; + user-select: none; +} + +.layers-insert-popup { + position: fixed; + z-index: 1000; + display: flex; + flex-direction: column; + box-sizing: border-box; + padding: 8px; + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 8px; + background: #2a2a2a; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(0, 0, 0, 0.3); + color: @project-panel-text-1; + font-size: @sidebar-small-font-size; + letter-spacing: normal; + text-shadow: none; + animation: layers-notice-in 90ms ease-out; + + .layers-insert-head { + display: flex; + align-items: center; + gap: 8px; + min-height: 24px; + padding: 0 0 8px; + white-space: nowrap; + } + + .layers-insert-where { + flex: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + font-weight: 600; + color: @project-panel-text-1; + } + + .layers-node-icon { + display: flex; + align-items: center; + justify-content: center; + width: 15px; + height: 15px; + flex: none; + color: @project-panel-text-2; + + svg { + width: 15px; + height: 15px; + display: block; + } + } + + .layers-insert-target { + display: flex; + flex: 0 1 auto; + align-items: center; + gap: 4px; + min-width: 40px; + max-width: 38%; + height: 24px; + padding: 0 7px 0 5px; + box-sizing: border-box; + border-radius: 6px; + background: @layers-accent-soft; + color: @project-panel-text-1; + + .layers-node-icon { + width: 14px; + height: 14px; + color: @layers-accent; + + svg { + width: 14px; + height: 14px; + } + } + } + + .layers-insert-target-name { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + font-family: @layers-mono; + font-size: @sidebar-xs-font-size; + font-weight: 500; + } + + .layers-insert-positions { + display: flex; + flex: 1 1 auto; + min-width: 0; + gap: 2px; + padding: 2px; + border-radius: 6px; + background: rgba(255, 255, 255, 0.06); + } + + .layers-insert-pos { + display: flex; + flex: 1 1 0; + align-items: center; + justify-content: center; + gap: 3px; + min-width: 0; + height: 20px; + padding: 0 4px; + margin: 0; + border: none; + border-radius: 4px; + background: transparent; + color: @project-panel-text-1; + font-family: inherit; + font-size: 10px; + font-weight: 500; + opacity: 0.8; + cursor: pointer; + outline: none; + + svg { + width: 12px; + height: 12px; + flex: none; + } + + span { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + &:hover { + background: rgba(255, 255, 255, 0.1); + opacity: 1; + } + + &.layers-active { + background: @layers-accent; + color: #ffffff; + opacity: 1; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); + } + + &:disabled { + opacity: 0.3; + cursor: default; + + &:hover { + background: transparent; + } + } + } + + .layers-insert-search { + display: flex; + align-items: center; + gap: 6px; + height: 26px; + padding: 0 6px 0 8px; + box-sizing: border-box; + border: 1px solid @layers-border; + border-radius: 6px; + background: @layers-input-bg; + + &:focus-within { + border-color: @layers-accent; + background: @layers-input-bg-focus; + } + + > svg { + width: 13px; + height: 13px; + flex: none; + color: @project-panel-text-2; + } + + input[type="text"] { + flex: 1; + min-width: 0; + height: 100%; + padding: 0; + margin: 0; + border: none; + outline: none; + box-shadow: none; + background: transparent; + color: @project-panel-text-1; + font-family: inherit; + font-size: @sidebar-small-font-size; + + &::placeholder { + color: @project-panel-text-2; + opacity: 0.75; + } + } + } + + .layers-insert-list { + margin: 8px -6px 0 0; + padding: 0; + overflow-y: auto; + overflow-x: hidden; + scrollbar-gutter: stable; + + &::-webkit-scrollbar { + width: 6px !important; + background-color: transparent !important; + } + + &::-webkit-scrollbar-thumb { + border-radius: 3px !important; + border: none !important; + background-color: rgba(255, 255, 255, 0.18) !important; + } + } + + .layers-insert-grid { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 4px; + } + + .layers-insert-item { + border-radius: 5px; + cursor: pointer; + + &.layers-insert-selected { + background: @layers-accent-strong; + + .layers-node-icon, + .layers-insert-item-tag { + color: @project-panel-text-1; + } + } + } + + .layers-insert-tile { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 3px; + min-width: 0; + height: 42px; + padding: 0 3px; + box-sizing: border-box; + border: 1px solid @layers-border; + background: rgba(255, 255, 255, 0.03); + + .layers-node-icon { + width: 15px; + height: 15px; + color: @project-panel-text-1; + + svg { + width: 15px; + height: 15px; + } + } + + .layers-insert-item-name { + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-size: 10px; + line-height: 1.2; + } + + &.layers-insert-selected { + border-color: @layers-accent; + + .layers-node-icon { + color: @layers-accent; + } + } + } + + .layers-insert-more { + display: flex; + align-items: center; + justify-content: center; + gap: 4px; + width: 100%; + height: 24px; + margin: 6px 0 0; + padding: 0; + border: none; + border-radius: 4px; + background: transparent; + color: @project-panel-text-2; + font-family: inherit; + font-size: @sidebar-xs-font-size; + cursor: pointer; + outline: none; + + svg { + width: 11px; + height: 11px; + flex: none; + transition: transform 120ms ease; + } + + &.layers-insert-open svg { + transform: rotate(180deg); + } + + &:hover { + background: @layers-hover-bg; + color: @project-panel-text-1; + } + } + + .layers-insert-create { + display: flex; + align-items: center; + gap: 7px; + height: 24px; + margin-top: 4px; + padding: 0 6px; + white-space: nowrap; + + .layers-node-icon { + color: @layers-accent; + } + + .layers-insert-item-name { + flex: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + } + } + + .layers-insert-empty { + padding: 8px 6px; + color: @project-panel-text-2; + white-space: normal; + } +} + .layers-hints { position: fixed; z-index: 1000; box-sizing: border-box; - max-height: 220px; - padding: 3px; + max-height: 180px; + padding: 4px; overflow-y: auto; - border: 1px solid rgba(255, 255, 255, 0.12); + overflow-x: hidden; + border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 6px; - background: #2f2f2f; - box-shadow: 0 6px 18px rgba(0, 0, 0, 0.4); + background: #2a2a2a; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(0, 0, 0, 0.3); font-family: @layers-mono; font-size: @sidebar-xs-font-size; - line-height: 18px; + line-height: 20px; + animation: layers-notice-in 90ms ease-out; + + &::-webkit-scrollbar { + width: 6px !important; + height: 6px !important; + background-color: transparent !important; + } + + &::-webkit-scrollbar-track { + margin: 0 !important; + background-color: transparent !important; + } + + &::-webkit-scrollbar-thumb { + border-radius: 3px !important; + border: none !important; + background-color: rgba(255, 255, 255, 0.18) !important; + background-clip: padding-box !important; + } + + &::-webkit-scrollbar-thumb:hover { + background-color: rgba(255, 255, 255, 0.3) !important; + } } .layers-hint { display: flex; align-items: center; - gap: 6px; - padding: 1px 6px; - border-radius: 3px; - color: #e0e0e0; + gap: 8px; + height: 22px; + padding: 0 8px; + border-radius: 4px; + color: #d8d8d8; white-space: nowrap; cursor: pointer; @@ -1047,26 +1573,33 @@ body.layers-resizing { } &.layers-hint-selected { - background: @layers-accent-soft; + background: @layers-accent-strong; + color: #ffffff; } strong { font-weight: 600; color: @layers-accent; } + + &.layers-hint-selected strong { + color: lighten(@layers-accent, 12%); + } } .layers-hint-label { + min-width: 0; overflow: hidden; text-overflow: ellipsis; } .layers-hint-swatch { flex: none; - width: 10px; - height: 10px; - border: 1px solid rgba(255, 255, 255, 0.25); - border-radius: 2px; + width: 12px; + height: 12px; + box-sizing: border-box; + border: 1px solid rgba(255, 255, 255, 0.28); + border-radius: 3px; } .dropdownbutton-popup.layers-menu-popup { @@ -1147,6 +1680,53 @@ body.layers-dnd-invalid { } } +@keyframes layers-remove-row { + 0% { + height: @layers-row-height; + opacity: 1; + transform: none; + } + + 60% { + opacity: 0; + transform: translateX(-10px); + } + + 100% { + height: 0; + opacity: 0; + transform: translateX(-10px); + } +} + +@keyframes layers-clone-row { + 0% { + height: 0; + opacity: 0; + transform: translateY(-4px); + background-color: fade(@layers-accent, 45%); + } + + 100% { + height: @layers-row-height; + opacity: 1; + transform: none; + background-color: fade(@layers-accent, 45%); + } +} + +@keyframes layers-notice-in { + 0% { + opacity: 0; + transform: translateY(6px); + } + + 100% { + opacity: 1; + transform: none; + } +} + @keyframes layers-spring-row { 0%, 100% { background-color: @layers-accent-soft; @@ -1177,4 +1757,10 @@ body.layers-dnd-invalid { .layers-tab-container .layers-node.layers-spring { animation: none; } + + .layers-tab-container .layers-node.layers-removing, + .layers-tab-container .layers-node.layers-clone-in, + .layers-tab-container .layers-notice { + animation-duration: 1ms; + } } diff --git a/tracking-repos.json b/tracking-repos.json index 9ebcc59de1..a2ca12e38a 100644 --- a/tracking-repos.json +++ b/tracking-repos.json @@ -1,5 +1,5 @@ { "phoenixPro": { - "commitID": "fdbb193c654554398abb77e5082a7348fc728f15" + "commitID": "d71aaac1a8ac3e4f0af5c5c2bbe5ff7c787a9945" } }