|
29 | 29 | </PopoverButton>
|
30 | 30 | </LayoutRow>
|
31 | 31 | <LayoutRow :class="'layer-tree scrollable-y'">
|
32 |
| - <LayoutCol :class="'list'" ref="layerTreeList" @click="() => deselectAllLayers()" @dragover="updateLine($event)" @dragend="drop()"> |
| 32 | + <LayoutCol :class="'list'" ref="layerTreeList" @click="() => deselectAllLayers()" @dragover="updateInsertLine($event)" @dragend="drop()"> |
33 | 33 | <div class="layer-row" v-for="(layer, index) in layers" :key="String(layer.path.slice(-1))">
|
34 |
| - <div class="layer-visibility"> |
| 34 | + <div class="visibility"> |
35 | 35 | <IconButton
|
36 | 36 | :action="(e) => (toggleLayerVisibility(layer.path), e && e.stopPropagation())"
|
37 | 37 | :icon="layer.visible ? 'EyeVisible' : 'EyeHidden'"
|
38 | 38 | :size="24"
|
39 | 39 | :title="layer.visible ? 'Visible' : 'Hidden'"
|
40 | 40 | />
|
41 | 41 | </div>
|
42 |
| - <button |
43 |
| - v-if="layer.layer_type === 'Folder'" |
44 |
| - class="node-connector" |
45 |
| - :class="{ expanded: layer.layer_metadata.expanded }" |
46 |
| - @click.stop="handleNodeConnectorClick(layer.path)" |
47 |
| - ></button> |
48 |
| - <div v-else class="node-connector-missing"></div> |
| 42 | + <div class="indent" :style="{ marginLeft: layerIndent(layer) }"></div> |
| 43 | + <button v-if="layer.layer_type === 'Folder'" class="expand-arrow" :class="{ expanded: layer.layer_metadata.expanded }" @click.stop="handleExpandArrowClick(layer.path)"></button> |
49 | 44 | <div
|
50 | 45 | class="layer"
|
51 | 46 | :class="{ selected: layer.layer_metadata.selected }"
|
52 |
| - :style="{ marginLeft: layerIndent(layer) }" |
53 | 47 | @click.shift.exact.stop="selectLayer(layer, false, true)"
|
54 | 48 | @click.shift.ctrl.exact.stop="selectLayer(layer, true, true)"
|
55 | 49 | @click.ctrl.exact.stop="selectLayer(layer, true, false)"
|
|
59 | 53 | @dragstart="dragStart($event, layer)"
|
60 | 54 | :title="layer.path"
|
61 | 55 | >
|
62 |
| - <div class="layer-thumbnail" v-html="layer.thumbnail"></div> |
63 | 56 | <div class="layer-type-icon">
|
64 | 57 | <IconLabel v-if="layer.layer_type === 'Folder'" :icon="'NodeTypeFolder'" title="Folder" />
|
65 | 58 | <IconLabel v-else :icon="'NodeTypePath'" title="Path" />
|
66 | 59 | </div>
|
67 | 60 | <div class="layer-name">
|
68 | 61 | <span>{{ layer.name }}</span>
|
69 | 62 | </div>
|
| 63 | + <div class="thumbnail" v-html="layer.thumbnail"></div> |
70 | 64 | </div>
|
71 |
| - <!-- <div class="glue" :style="{ marginLeft: layerIndent(layer) }"></div> --> |
72 | 65 | </div>
|
73 | 66 | </LayoutCol>
|
74 | 67 | </LayoutRow>
|
|
96 | 89 | }
|
97 | 90 |
|
98 | 91 | .layer-tree {
|
| 92 | + // Crop away the 1px border below the bottom layer entry when it uses the full space of this panel |
| 93 | + margin-bottom: -1px; |
| 94 | +
|
99 | 95 | .layer-row {
|
| 96 | + flex: 0 0 auto; |
100 | 97 | display: flex;
|
101 |
| - height: 36px; |
102 | 98 | align-items: center;
|
103 |
| - flex: 0 0 auto; |
104 | 99 | position: relative;
|
| 100 | + height: 36px; |
| 101 | + margin: 0 4px; |
| 102 | + border-bottom: 1px solid var(--color-4-dimgray); |
105 | 103 |
|
106 |
| - & + .layer-row, |
107 |
| - & + .insert-mark + .layer-row { |
108 |
| - margin-top: 2px; |
109 |
| - } |
110 |
| -
|
111 |
| - .layer-visibility { |
| 104 | + .visibility { |
| 105 | + height: 100%; |
112 | 106 | flex: 0 0 auto;
|
113 |
| - margin-left: 4px; |
| 107 | + display: flex; |
| 108 | + align-items: center; |
| 109 | +
|
| 110 | + .icon-button { |
| 111 | + height: 100%; |
| 112 | + width: calc(24px + 2 * 4px); |
| 113 | + } |
114 | 114 | }
|
115 | 115 |
|
116 |
| - .node-connector { |
117 |
| - flex: 0 0 auto; |
118 |
| - width: 12px; |
119 |
| - height: 12px; |
120 |
| - margin: 0 2px; |
121 |
| - border-radius: 50%; |
122 |
| - background: var(--color-data-raster); |
| 116 | + .expand-arrow { |
| 117 | + margin-left: -16px; |
| 118 | + width: 16px; |
| 119 | + height: 100%; |
| 120 | + padding: 0; |
123 | 121 | outline: none;
|
124 | 122 | border: none;
|
125 | 123 | position: relative;
|
| 124 | + background: none; |
| 125 | + flex: 0 0 auto; |
| 126 | + display: flex; |
| 127 | + align-items: center; |
| 128 | + justify-content: center; |
| 129 | + border-radius: 2px; |
| 130 | +
|
| 131 | + &:hover { |
| 132 | + background: var(--color-6-lowergray); |
| 133 | + } |
126 | 134 |
|
127 | 135 | &::after {
|
128 | 136 | content: "";
|
129 | 137 | position: absolute;
|
130 | 138 | width: 0;
|
131 | 139 | height: 0;
|
132 |
| - top: 3px; |
133 |
| - left: 4px; |
134 | 140 | border-style: solid;
|
135 | 141 | border-width: 3px 0 3px 6px;
|
136 |
| - border-color: transparent transparent transparent var(--color-2-mildblack); |
| 142 | + border-color: transparent transparent transparent var(--color-e-nearwhite); |
| 143 | +
|
| 144 | + &:hover { |
| 145 | + color: var(--color-f-white); |
| 146 | + } |
137 | 147 | }
|
138 | 148 |
|
139 | 149 | &.expanded::after {
|
140 |
| - top: 4px; |
141 |
| - left: 3px; |
142 | 150 | border-width: 6px 3px 0 3px;
|
143 |
| - border-color: var(--color-2-mildblack) transparent transparent transparent; |
144 |
| - } |
145 |
| - } |
| 151 | + border-color: var(--color-e-nearwhite) transparent transparent transparent; |
146 | 152 |
|
147 |
| - .node-connector-missing { |
148 |
| - width: 16px; |
149 |
| - flex: 0 0 auto; |
| 153 | + &:hover { |
| 154 | + color: var(--color-f-white); |
| 155 | + } |
| 156 | + } |
150 | 157 | }
|
151 | 158 |
|
152 | 159 | .layer {
|
153 | 160 | display: flex;
|
154 |
| - min-width: 0; |
155 | 161 | align-items: center;
|
156 |
| - border-radius: 2px; |
157 |
| - background: var(--color-5-dullgray); |
158 |
| - margin-right: 16px; |
| 162 | + z-index: 1; |
| 163 | + min-width: 0; |
159 | 164 | width: 100%;
|
160 | 165 | height: 100%;
|
161 |
| - z-index: 1; |
| 166 | + border-radius: 2px; |
| 167 | + padding: 0 4px; |
| 168 | + margin-right: 8px; |
162 | 169 |
|
163 | 170 | &.selected {
|
164 |
| - background: var(--color-7-middlegray); |
| 171 | + background: var(--color-5-dullgray); |
165 | 172 | color: var(--color-f-white);
|
166 | 173 | }
|
167 | 174 |
|
168 |
| - .layer-thumbnail { |
169 |
| - width: 64px; |
170 |
| - height: 100%; |
171 |
| - background: white; |
172 |
| - border-radius: 2px; |
173 |
| - flex: 0 0 auto; |
174 |
| -
|
175 |
| - svg { |
176 |
| - width: calc(100% - 4px); |
177 |
| - height: calc(100% - 4px); |
178 |
| - margin: 2px; |
179 |
| - } |
180 |
| - } |
181 |
| -
|
182 | 175 | .layer-type-icon {
|
183 |
| - margin-left: 8px; |
184 |
| - margin-right: 4px; |
185 | 176 | flex: 0 0 auto;
|
| 177 | + margin: 0 4px; |
186 | 178 | }
|
187 | 179 |
|
188 | 180 | .layer-name {
|
| 181 | + flex: 1 1 100%; |
189 | 182 | display: flex;
|
190 | 183 | min-width: 0;
|
191 |
| - flex: 1 1 100%; |
192 |
| - margin-right: 8px; |
| 184 | + margin: 0 4px; |
193 | 185 |
|
194 | 186 | span {
|
195 | 187 | text-overflow: ellipsis;
|
196 | 188 | white-space: nowrap;
|
197 | 189 | overflow: hidden;
|
198 | 190 | }
|
199 | 191 | }
|
200 |
| - } |
201 | 192 |
|
202 |
| - .glue { |
203 |
| - position: absolute; |
204 |
| - background: var(--color-data-raster); |
205 |
| - height: 6px; |
206 |
| - bottom: -4px; |
207 |
| - left: 44px; |
208 |
| - right: 16px; |
209 |
| - z-index: 0; |
| 193 | + .thumbnail { |
| 194 | + height: calc(100% - 4px); |
| 195 | + margin: 2px 0; |
| 196 | + margin-left: 4px; |
| 197 | + width: 64px; |
| 198 | + background: white; |
| 199 | + border-radius: 2px; |
| 200 | + flex: 0 0 auto; |
| 201 | +
|
| 202 | + svg { |
| 203 | + width: calc(100% - 4px); |
| 204 | + height: calc(100% - 4px); |
| 205 | + margin: 2px; |
| 206 | + } |
| 207 | + } |
210 | 208 | }
|
211 | 209 | }
|
212 | 210 |
|
|
221 | 219 | position: absolute;
|
222 | 220 | background: var(--color-accent-hover);
|
223 | 221 | width: 100%;
|
224 |
| - height: 6px; |
| 222 | + height: 5px; |
225 | 223 | }
|
226 | 224 |
|
227 | 225 | &:not(:first-child, :last-child) {
|
228 |
| - top: -2px; |
| 226 | + top: -3px; |
229 | 227 | }
|
230 | 228 |
|
231 | 229 | &:first-child::after {
|
232 | 230 | top: 0;
|
233 | 231 | }
|
234 | 232 |
|
235 | 233 | &:last-child::after {
|
236 |
| - bottom: 0; |
| 234 | + // Shifted up 1px to account for the shifting down of the entire `.layer-tree` panel |
| 235 | + bottom: 1px; |
237 | 236 | }
|
238 | 237 | }
|
239 | 238 | }
|
@@ -318,12 +317,12 @@ export default defineComponent({
|
318 | 317 | },
|
319 | 318 | methods: {
|
320 | 319 | layerIndent(layer: LayerPanelEntry) {
|
321 |
| - return `${(layer.path.length - 1) * 16}px`; |
| 320 | + return `${layer.path.length * 16}px`; |
322 | 321 | },
|
323 | 322 | async toggleLayerVisibility(path: BigUint64Array) {
|
324 | 323 | this.editor.instance.toggle_layer_visibility(path);
|
325 | 324 | },
|
326 |
| - async handleNodeConnectorClick(path: BigUint64Array) { |
| 325 | + async handleExpandArrowClick(path: BigUint64Array) { |
327 | 326 | this.editor.instance.toggle_layer_expansion(path);
|
328 | 327 | },
|
329 | 328 | async setLayerBlendMode(newSelectedIndex: number) {
|
@@ -416,15 +415,15 @@ export default defineComponent({
|
416 | 415 |
|
417 | 416 | const [nearestPath, above, nearestElement] = this.closest(tree, event.clientY);
|
418 | 417 |
|
419 |
| - // Set the initial state of the line |
| 418 | + // Set the initial state of the insert line |
420 | 419 | if (nearestElement.parentNode) {
|
421 |
| - insertLine.style.marginLeft = `${LAYER_LEFT_MARGIN_OFFSET + LAYER_LEFT_INDENT_OFFSET * nearestPath.length}px`; |
| 420 | + insertLine.style.marginLeft = `${LAYER_LEFT_MARGIN_OFFSET + LAYER_LEFT_INDENT_OFFSET * nearestPath.length}px`; // TODO: use layerIndent function to calculate this |
422 | 421 | tree.insertBefore(insertLine, nearestElement);
|
423 | 422 | }
|
424 | 423 |
|
425 | 424 | this.draggingData = { path: layer.path, above, nearestPath, insertLine };
|
426 | 425 | },
|
427 |
| - updateLine(event: DragEvent) { |
| 426 | + updateInsertLine(event: DragEvent) { |
428 | 427 | // Stop the drag from being shown as cancelled
|
429 | 428 | event.preventDefault();
|
430 | 429 |
|
|
0 commit comments