-
Notifications
You must be signed in to change notification settings - Fork 42
/
forest.less
339 lines (291 loc) · 9 KB
/
forest.less
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
// A forest is a group of trees, visually something like this:
//
// <ul class="forest">
//
// <li> <!-- this is a group -->
// <??? class="forest-item">...</>
// <ul class="forest-children">
// <li><??? class="forest-item">...</></li>
// <li>
// <??? class="forest-item">...</>
// <ul class="forest-children"> ... </ul>
// </li>
// </ul>
// </li>
//
// ...
//
// </ul>
//
// Importantly, groups, trees and subtrees all share the same DOM, but are
// styled differently. So a group looks just like an item with child items.
//
// A forest item looks like this; each sub-element is optional except the title:
//
// <??? class="forest-item">
// <??? class="forest-collapse" />
// <??? class="forest-icon" />
// <??? class="forest-title" />
// <??? class="forest-badge" />
// <??? class="forest-toolbar" />
// </>
//
// There are a few special classes that can be applied to .forest-item and
// .forest-children to change their appearance/behavior:
//
// For .forest-item:
// .selectable - Means the item can be selected by clicking its icon
// .selected - The item is currently selected
//
// For .forest-children:
// .collapsed - The children should not be visible
.forest,
.forest-children {
display: flex;
flex-direction: column;
margin: 0;
padding: 0;
& > li {
display: flex;
flex-direction: column;
list-style: none;
// Hide empty list items in the forest (as a workaround so that indexes in
// <dnd-list> stay accurate)
&:empty:not(.dnd-list-ghost) {
display: none;
}
// Hide the toolbar unless the item is being hovered over
&:not(:hover):not(:focus-within) > .forest-item > .forest-toolbar {
display: none;
}
// Hide the collapse button unless the item is collapsed or being hovered
// over
&:not(:hover):not(:focus-within)
> .forest-item:not(.collapsed)
> .forest-collapse {
display: none;
}
}
}
.forest-children {
.forest-children {
margin-left: var(--item-indent-w);
// Show an indent guide
border-left: var(--indent-guide-w) solid var(--indent-guide-border-clr);
// Give ourselves a little space at the bottom of each child list, with a
// nice curl to the indent guide--this makes drag-and-drop easier when
// appending inside a child vs. inserting below the child
&:last-child {
border-bottom-left-radius: calc(var(--item-h) / 4);
padding-bottom: calc(var(--item-h) / 4);
}
}
// Nested children should be hidden if the child is collapsed
&.collapsed {
display: none;
}
// Lower-level children which are folders should have bold titles. This is
// different from top-level folders, which use a bigger font size and
// therefore can use a lighter weight.
.forest-item.folder > .forest-title {
font-weight: bold;
}
}
.forest-item {
display: grid;
// The column layout. This is tweaked in the top-level .forest-item overrides
// above, so keep that in mind.
//
// 1:.forest-collapse, 2:.forest-icon, 3:.forest-title, 4:.forest-badge, 5:.forest-toolbar
grid-template-columns: var(--collapse-btn-size) var(--icon-btn-size) 1fr 0fr 0fr;
// No column-gap because we assign margins to individual items
align-items: center;
// We pad to --collapse-btn-size so that the left and right margins appear
// symmetric, and because --collapse-btn-size is wide enough that the
// auto-hiding scrollbars on macOS don't intrude on the right-side toolbar
// buttons. (Funny how macOS messed with their scrollbars and now we all just
// have to work around it...)
padding: 0 var(--page-pw) 0 0;
height: var(--item-h);
& > .forest-collapse {
grid-row: 1;
grid-column: 1;
width: var(--collapse-btn-size);
}
& > .forest-icon {
grid-row: 1;
grid-column: 2;
}
& > .forest-title {
grid-row: 1;
grid-column: 3;
}
& > .forest-badge {
grid-row: 1;
grid-column: 4;
}
& > .forest-toolbar {
grid-row: 1;
grid-column: 5;
}
&.selectable {
// If a selection is active and this is a candidate for selection, show
// a background on the select button indicating the item can be selected.
.selection-active & .action.select {
background-color: var(--button-bg);
}
&.selected .action.select {
background-color: var(--userlink-fg);
// When an item is selected, always show an icon indicating this instead
// of the actual item icon.
.icon-select-selected-inverse();
& > img,
& > span {
display: none;
}
&:hover {
background-color: var(--userlink-hover-fg);
}
&:active,
&:focus-within {
background-color: var(--userlink-active-fg);
}
}
&:hover,
&:focus-within {
background-color: var(--item-hover-bg);
&.selected {
background-color: var(--selected-hover-bg);
}
.action.select {
box-shadow: var(--ephemeral-hover-shadow-metrics) var(--ctrl-border-clr);
}
// Special highlighting behavior for using the icon to select the tab.
&:not(.selected) .action.select {
background-color: var(--button-bg);
// On hover/activation, show the "select me" icon instead of whatever
// actual icon is present.
.icon-select();
& > img,
& > span {
display: none;
}
&:focus-within,
&:hover {
background-color: var(--button-hover-bg);
}
&:active {
background-color: var(--button-active-bg);
}
}
}
}
& > .forest-title {
padding: 0 calc(var(--item-gap-w) / 2);
margin: 0 calc(var(--item-gap-w) / 2);
height: var(--item-h);
/* to vertically center text while text-overflow: ellipsis; */
line-height: var(--item-h);
.text-overflow-ellipsis();
}
// Don't double-highlight titles that are also links
& > a.forest-title {
&:hover,
&:focus-within,
&:active {
background-color: transparent;
}
}
}
.forest-badge {
height: var(--item-h);
line-height: var(--item-h);
&.icon {
.icon-wrapper();
}
}
// Like .forest-icon and .forest-badge but without the horizontal padding. It
// gets the item-height though, and is aligned for putting inline with text.
.forest-inline-icon {
// Similar to .action's sizing
box-sizing: border-box;
width: var(--icon-size);
height: var(--item-h);
padding: var(--icon-p) 0;
vertical-align: top;
}
.text-overflow-ellipsis() {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
//
// Mods for top-level forest items (which should look like groups)
//
// The top level of the forest, which is shown as a set of different
// sections/groups.
.forest {
& > li {
border-radius: var(--group-border-radius);
// Make sure the sidebar/panel views have a visible gap between groups.
// This should be overridden in the tab view.
margin-top: var(--group-ph);
& > .forest-item {
border-top: var(--group-border);
// Must match the enclosing <li> or the background-color that is set on
// hover/selection will mess things up.
border-top-left-radius: var(--group-border-radius);
border-top-right-radius: var(--group-border-radius);
// Since there's no icon for the top-level group, don't leave space for it
// (unlike what we do inside the group). This should match the same
// layout as the regular .forest-item grid above, or the other columns
// won't line up properly.
grid-template-columns: var(--collapse-btn-size) 0fr 1fr 0fr 0fr;
margin: 0;
padding-top: var(--group-ph);
padding-bottom: var(--group-ph);
height: auto;
& > .forest-title {
font-weight: var(--group-header-font-weight);
font-size: var(--group-header-font-size);
margin-left: 0; // To align with the icons in child items
}
// Don't change the background color as if the group were a regular item
&:not(.selected) {
&:hover,
&:focus-within {
background-color: inherit;
}
}
}
& > .forest-children:last-child {
// This is here, instead of the enclosing <li>, so the bottom margin
// naturally disappears when the group is collapsed. It should also be
// overridden in the tab view.
//
// We use padding instead of margin here to give a bigger drop target for
// drag-and-drop operations.
padding-bottom: calc(var(--group-ph) + var(--page-ph));
flex: auto; // Fill all leftover space so we're a bigger drop target
}
}
// Mods to how drag-and-drop looks, since the top-level grouping has a ghost
// which displaces items in the list.
&.dnd-list {
& > .dragging {
display: none;
}
& > .dnd-list-ghost {
display: none;
&.dropping-here {
display: block;
box-sizing: border-box;
border: var(--ghost-border-width) dashed var(--disabled-fg);
background: transparent;
min-height: var(--item-h);
min-width: var(--icon-btn-size);
margin: 0;
}
}
}
}