mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-20 21:36:09 +08:00
Polish up the Layers panel design
This commit is contained in:
@@ -69,6 +69,7 @@
|
||||
:root {
|
||||
// Replace usage of `-rgb` variants with CSS color() function to calculate alpha when browsers support it
|
||||
// See https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color() and https://caniuse.com/css-color-function
|
||||
// Specifically, support for the relative syntax is needed: `color(from var(--color-0-black) srgb r g b / 0.5)` to convert black to 50% alpha
|
||||
--color-0-black: #000;
|
||||
--color-0-black-rgb: 0, 0, 0;
|
||||
--color-1-nearblack: #111;
|
||||
@@ -138,6 +139,16 @@
|
||||
--color-transparent-checkered-background-size: 16px 16px;
|
||||
--color-transparent-checkered-background-position: 0 0, 8px 8px;
|
||||
|
||||
--background-inactive-stripes: repeating-linear-gradient(
|
||||
-45deg,
|
||||
transparent 0px,
|
||||
transparent calc((3px * sqrt(2) / 2) - 0.5px),
|
||||
var(--color-5-dullgray) calc((3px * sqrt(2) / 2) - 0.5px),
|
||||
var(--color-5-dullgray) calc((3px * sqrt(2) / 2) + 0.5px),
|
||||
transparent calc((3px * sqrt(2) / 2) + 0.5px),
|
||||
transparent calc(6px * sqrt(2) / 2)
|
||||
);
|
||||
|
||||
// Arrow triangle (#eee fill)
|
||||
--icon-expand-collapse-arrow: url('data:image/svg+xml;utf8,\
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8 8"><polygon fill="%23eee" points="3,0 1,0 5,4 1,8 3,8 7,4" /></svg>\
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
export { styleName as style };
|
||||
export let styles: Record<string, string | number | undefined> = {};
|
||||
export let tooltip: string | undefined = undefined;
|
||||
// TODO: Add middle-click drag scrolling
|
||||
export let scrollableX = false;
|
||||
export let scrollableY = false;
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
export { styleName as style };
|
||||
export let styles: Record<string, string | number | undefined> = {};
|
||||
export let tooltip: string | undefined = undefined;
|
||||
// TODO: Add middle-click drag scrolling
|
||||
export let scrollableX = false;
|
||||
export let scrollableY = false;
|
||||
|
||||
|
||||
@@ -377,6 +377,7 @@
|
||||
classes={{
|
||||
selected: fakeHighlight !== undefined ? fakeHighlight === listing.entry.id : $nodeGraph.selected.includes(listing.entry.id),
|
||||
"insert-folder": (draggingData?.highlightFolder || false) && draggingData?.insertParentId === listing.entry.id,
|
||||
"nesting-layer": isNestingLayer(listing.entry.layerClassification),
|
||||
}}
|
||||
styles={{ "--layer-indent-levels": `${listing.entry.depth - 1}` }}
|
||||
data-layer
|
||||
@@ -387,7 +388,13 @@
|
||||
on:click={(e) => selectLayerWithModifiers(e, listing)}
|
||||
>
|
||||
{#if isNestingLayer(listing.entry.layerClassification)}
|
||||
<button class="expand-arrow" class:expanded={listing.entry.expanded} on:click|stopPropagation={() => handleExpandArrowClick(listing.entry.id)} tabindex="0" />
|
||||
<button
|
||||
class="expand-arrow"
|
||||
class:expanded={listing.entry.expanded}
|
||||
disabled={!listing.entry.hasChildren}
|
||||
on:click|stopPropagation={() => handleExpandArrowClick(listing.entry.id)}
|
||||
tabindex="0"
|
||||
/>
|
||||
{#if listing.entry.layerClassification === "Artboard"}
|
||||
<IconLabel icon="Artboard" class={"layer-type-icon"} />
|
||||
{:else if listing.entry.layerClassification === "Folder"}
|
||||
@@ -413,12 +420,25 @@
|
||||
on:change={(e) => onEditLayerNameChange(listing, e)}
|
||||
/>
|
||||
</LayoutRow>
|
||||
{#if !listing.entry.unlocked || !listing.entry.parentsUnlocked}
|
||||
<IconButton
|
||||
class={"status-toggle"}
|
||||
classes={{ inactive: !listing.entry.parentsUnlocked }}
|
||||
action={(e) => (toggleLayerVisibility(listing.entry.id), e?.stopPropagation())}
|
||||
size={24}
|
||||
icon={listing.entry.parentsUnlocked ? "PadlockLocked" : "PadlockUnlocked"}
|
||||
hoverIcon={listing.entry.parentsUnlocked ? "PadlockUnlocked" : "PadlockLocked"}
|
||||
tooltip={listing.entry.parentsUnlocked ? "Unlock" : "Lock"}
|
||||
/>
|
||||
{/if}
|
||||
<IconButton
|
||||
class={"visibility"}
|
||||
class={"status-toggle"}
|
||||
classes={{ inactive: !listing.entry.parentsVisible }}
|
||||
action={(e) => (toggleLayerVisibility(listing.entry.id), e?.stopPropagation())}
|
||||
size={24}
|
||||
icon={listing.entry.visible ? "EyeVisible" : "EyeHidden"}
|
||||
tooltip={listing.entry.visible ? "Visible" : "Hidden"}
|
||||
hoverIcon={listing.entry.visible ? "EyeHide" : "EyeShow"}
|
||||
tooltip={listing.entry.visible ? "Hide" : "Show"}
|
||||
/>
|
||||
</LayoutRow>
|
||||
{/each}
|
||||
@@ -443,16 +463,27 @@
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
// Blend mode selector
|
||||
.dropdown-input {
|
||||
max-width: 120px;
|
||||
}
|
||||
|
||||
// Blend mode selector and opacity slider
|
||||
.dropdown-input,
|
||||
.number-input {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
// Blend mode selector
|
||||
.dropdown-input {
|
||||
max-width: 120px;
|
||||
flex-basis: 120px;
|
||||
}
|
||||
|
||||
// Opacity slider
|
||||
.number-input {
|
||||
max-width: 180px;
|
||||
flex-basis: 180px;
|
||||
|
||||
+ .separator ~ .separator {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Layer hierarchy
|
||||
@@ -464,11 +495,15 @@
|
||||
flex: 0 0 auto;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
border-bottom: 1px solid var(--color-2-mildblack);
|
||||
border-radius: 2px;
|
||||
height: 32px;
|
||||
margin: 0 4px;
|
||||
padding-left: calc(4px + var(--layer-indent-levels) * 16px);
|
||||
border-bottom: 1px solid var(--color-2-mildblack);
|
||||
border-radius: 2px;
|
||||
|
||||
&.nesting-layer {
|
||||
padding-left: calc(var(--layer-indent-levels) * 16px);
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background: var(--color-4-dimgray);
|
||||
@@ -493,23 +528,28 @@
|
||||
justify-content: center;
|
||||
border-radius: 2px;
|
||||
|
||||
&:hover {
|
||||
background: var(--color-5-dullgray);
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
border-width: 3px 0 3px 6px;
|
||||
border-color: transparent transparent transparent var(--color-e-nearwhite);
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background: var(--icon-expand-collapse-arrow);
|
||||
}
|
||||
|
||||
&[disabled]::after {
|
||||
background: var(--icon-expand-collapse-arrow-disabled);
|
||||
}
|
||||
|
||||
&:hover:not([disabled]) {
|
||||
background: var(--color-5-dullgray);
|
||||
|
||||
&::after {
|
||||
background: var(--icon-expand-collapse-arrow-hover);
|
||||
}
|
||||
}
|
||||
|
||||
&.expanded::after {
|
||||
border-width: 6px 3px 0 3px;
|
||||
border-color: var(--color-e-nearwhite) transparent transparent transparent;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -573,11 +613,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
.visibility {
|
||||
.status-toggle {
|
||||
flex: 0 0 auto;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
|
||||
&.inactive {
|
||||
background-image: var(--background-inactive-stripes);
|
||||
}
|
||||
|
||||
.icon-button {
|
||||
height: 100%;
|
||||
width: calc(24px + 2 * 4px);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import IconLabel from "@graphite/components/widgets/labels/IconLabel.svelte";
|
||||
|
||||
export let icon: IconName;
|
||||
export let hoverIcon: IconName | undefined = undefined;
|
||||
export let size: IconSize;
|
||||
export let disabled = false;
|
||||
export let active = false;
|
||||
@@ -20,8 +21,21 @@
|
||||
.join(" ");
|
||||
</script>
|
||||
|
||||
<button class={`icon-button size-${size} ${className} ${extraClasses}`.trim()} class:disabled class:active on:click={action} {disabled} title={tooltip} tabindex={active ? -1 : 0} {...$$restProps}>
|
||||
<button
|
||||
class={`icon-button size-${size} ${className} ${extraClasses}`.trim()}
|
||||
class:hover-icon={hoverIcon && !disabled}
|
||||
class:disabled
|
||||
class:active
|
||||
on:click={action}
|
||||
{disabled}
|
||||
title={tooltip}
|
||||
tabindex={active ? -1 : 0}
|
||||
{...$$restProps}
|
||||
>
|
||||
<IconLabel {icon} />
|
||||
{#if hoverIcon && !disabled}
|
||||
<IconLabel icon={hoverIcon} />
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
<style lang="scss" global>
|
||||
@@ -49,6 +63,16 @@
|
||||
background: var(--color-5-dullgray);
|
||||
}
|
||||
|
||||
&.hover-icon {
|
||||
&:not(:hover) .icon-label:nth-of-type(2) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover .icon-label:nth-of-type(1) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
background: none;
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
// However, if multiple TextButton widgets are used in a group with only some having no label, this component is able to accommodate that.
|
||||
export let label: string;
|
||||
export let icon: IconName | undefined = undefined;
|
||||
export let hoverIcon: IconName | undefined = undefined;
|
||||
export let emphasized = false;
|
||||
export let flush = false;
|
||||
export let minWidth = 0;
|
||||
@@ -54,6 +55,7 @@
|
||||
<button
|
||||
class="text-button"
|
||||
class:open={self?.open}
|
||||
class:hover-icon={hoverIcon && !disabled}
|
||||
class:emphasized
|
||||
class:disabled
|
||||
class:flush
|
||||
@@ -68,6 +70,9 @@
|
||||
>
|
||||
{#if icon}
|
||||
<IconLabel {icon} />
|
||||
{#if hoverIcon && !disabled}
|
||||
<IconLabel icon={hoverIcon} />
|
||||
{/if}
|
||||
{/if}
|
||||
{#if icon && label}
|
||||
<Separator type={flush ? "Unrelated" : "Related"} />
|
||||
@@ -118,6 +123,16 @@
|
||||
--button-text-color: var(--color-f-white);
|
||||
}
|
||||
|
||||
&.hover-icon {
|
||||
&:not(:hover) .icon-label:nth-of-type(2) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover .icon-label:nth-of-type(1) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
--button-background-color: var(--color-4-dimgray);
|
||||
--button-text-color: var(--color-8-uppergray);
|
||||
|
||||
Reference in New Issue
Block a user