@motion-proto/live-tokens 0.72.1 → 0.74.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/live-tokens-build-page/SKILL.md +37 -2
- package/.claude/skills/live-tokens-build-page/references/layout-sources.md +48 -0
- package/.claude/skills/live-tokens-check-compliance/SKILL.md +2 -2
- package/.claude/skills/live-tokens-create-component/SKILL.md +4 -4
- package/.claude/skills/live-tokens-create-theme/SKILL.md +80 -0
- package/.claude/skills/live-tokens-create-theme/references/design-directions.md +94 -0
- package/.claude/skills/live-tokens-pick-component/SKILL.md +1 -1
- package/.claude/skills/live-tokens-set-colors/SKILL.md +140 -0
- package/.claude/skills/live-tokens-set-colors/references/color-anchors.md +80 -0
- package/.claude/skills/{live-tokens-adjust-geometry → live-tokens-set-geometry}/SKILL.md +12 -7
- package/.claude/skills/live-tokens-set-geometry/references/geometry-anchors.md +61 -0
- package/.claude/skills/{live-tokens-pair-fonts → live-tokens-set-type}/SKILL.md +18 -15
- package/.claude/skills/live-tokens-set-type/references/type-anchors.md +60 -0
- package/CHANGELOG.md +141 -0
- package/README.md +24 -15
- package/bin/check-page.mjs +3 -3
- package/bin/cli.mjs +92 -55
- package/bin/lib/liveState.mjs +110 -0
- package/bin/save-theme.mjs +177 -0
- package/bin/set-colors.mjs +191 -0
- package/bin/{adjust.mjs → set-geometry.mjs} +18 -50
- package/bin/{set-fonts.mjs → set-type.mjs} +21 -55
- package/dist-plugin/{chunk-RIXO2E55.js → chunk-7VRTBGJT.js} +1 -1
- package/dist-plugin/{chunk-YLCOIGQC.js → chunk-V3YF6CGT.js} +56 -2
- package/dist-plugin/index.cjs +58 -3
- package/dist-plugin/index.js +11 -11
- package/dist-plugin/migrateData/index.cjs +56 -1
- package/dist-plugin/migrateData/index.js +2 -2
- package/dist-plugin/{generateColorsAndType → setColors}/index.cjs +1109 -1071
- package/dist-plugin/{generateColorsAndType → setColors}/index.d.cts +33 -24
- package/dist-plugin/{generateColorsAndType → setColors}/index.d.ts +33 -24
- package/dist-plugin/{generateColorsAndType → setColors}/index.js +45 -63
- package/dist-plugin/{adjust → setGeometry}/index.cjs +60 -5
- package/dist-plugin/{adjust → setGeometry}/index.d.cts +1 -1
- package/dist-plugin/{adjust → setGeometry}/index.d.ts +1 -1
- package/dist-plugin/{adjust → setGeometry}/index.js +1 -1
- package/dist-plugin/{fontPairing → setType}/index.cjs +4 -4
- package/dist-plugin/{fontPairing → setType}/index.d.cts +1 -1
- package/dist-plugin/{fontPairing → setType}/index.d.ts +1 -1
- package/dist-plugin/{themeTypes-DSV3Zisf.d.cts → themeTypes-BxRtuN5V.d.cts} +1 -1
- package/dist-plugin/{themeTypes-DSV3Zisf.d.ts → themeTypes-BxRtuN5V.d.ts} +1 -1
- package/package.json +10 -2
- package/src/editor/core/themes/{generateColorsAndType.ts → buildColors.ts} +82 -96
- package/src/editor/core/themes/migrations/2026-09-03-drop-legacy-component-keys.ts +62 -0
- package/src/editor/core/themes/migrations/index.ts +2 -0
- package/src/editor/docs/content/creating-components.md +13 -0
- package/src/editor/docs/content/themes-workflow.md +2 -2
- package/src/editor/docs/content.generated.ts +2 -2
- package/src/editor/overlay/LiveEditorOverlay.svelte +519 -28
- package/src/editor/skill-atlas/SkillAtlas.svelte +836 -0
- package/src/editor/skill-atlas/SkillAtlas.svelte.d.ts +4 -0
- package/src/editor/skill-atlas/SourcePane.svelte +364 -0
- package/src/editor/skill-atlas/TreeNodeCard.svelte +206 -0
- package/src/editor/skill-atlas/skillSources.generated.ts +45 -0
- package/src/editor/skill-atlas/skillSources.ts +1 -0
- package/src/editor/skill-atlas/skillTrees.ts +3844 -0
- package/src/editor/skill-atlas/types.ts +65 -0
- package/src/live-tokens/data/colors-and-type/autumn.json +1 -37
- package/src/live-tokens/data/colors-and-type/default.json +1 -37
- package/src/live-tokens/data/colors-and-type/halloween.json +1 -37
- package/src/live-tokens/data/colors-and-type/midnight-study.json +1 -37
- package/src/live-tokens/data/colors-and-type/ocean.json +1 -37
- package/src/live-tokens/data/colors-and-type/royal-velvet.json +1 -37
- package/src/live-tokens/data/colors-and-type/sketchy.json +1 -37
- package/src/live-tokens/data/colors-and-type/spring-meadow.json +1 -37
- package/src/live-tokens/data/colors-and-type/sunset.json +1 -37
- package/src/live-tokens/data/themes/autumn.json +1 -37
- package/src/live-tokens/data/themes/halloween.json +1 -37
- package/src/live-tokens/data/themes/midnight-study.json +1 -37
- package/src/live-tokens/data/themes/ocean.json +1 -37
- package/src/live-tokens/data/themes/royal-velvet.json +1 -37
- package/src/live-tokens/data/themes/sketchy.json +1 -37
- package/src/live-tokens/data/themes/spring-meadow.json +1 -37
- package/src/live-tokens/data/themes/sunset.json +1 -37
- package/src/live-tokens/data/tokens.generated.css +0 -36
- package/.claude/skills/live-tokens-generate-theme/SKILL.md +0 -156
- package/.claude/skills/live-tokens-generate-theme/references/mood-vocabulary.md +0 -43
- package/.claude/skills/live-tokens-generate-theme/references/named-themes.md +0 -18
- package/.claude/skills/live-tokens-generate-theme/references/style-vocabulary.md +0 -35
- package/bin/generate-theme.mjs +0 -260
- /package/dist-plugin/{fontPairing → setType}/index.js +0 -0
|
@@ -105,10 +105,28 @@
|
|
|
105
105
|
});
|
|
106
106
|
|
|
107
107
|
type Mode = 'docked' | 'floating';
|
|
108
|
+
type Side = 'left' | 'right';
|
|
108
109
|
|
|
109
110
|
const STORAGE_KEY = storageKey('overlay-state');
|
|
110
111
|
const MIN_WIDTH = 360;
|
|
111
112
|
const MIN_HEIGHT = 480;
|
|
113
|
+
|
|
114
|
+
// Collapsed-pill size; slight overshoot is fine (overflow:hidden).
|
|
115
|
+
const COLLAPSED_WIDTH = 252;
|
|
116
|
+
const COLLAPSED_HEIGHT = 44;
|
|
117
|
+
const COLLAPSED_DEFAULT = { right: 12, top: 12 };
|
|
118
|
+
|
|
119
|
+
// Drop the pill this close to an edge and it docks there.
|
|
120
|
+
const DOCK_EDGES = ['left', 'right', 'top', 'bottom'] as const;
|
|
121
|
+
const DOCK_SNAP = 20;
|
|
122
|
+
// Leaving a dock is resisted across twice that distance, so the edge holds
|
|
123
|
+
// unless the drag is deliberate.
|
|
124
|
+
const DOCK_PULL = DOCK_SNAP * 2;
|
|
125
|
+
// A press that travels this far is a drag, and must not also fire a click.
|
|
126
|
+
const DRAG_SLOP = 16;
|
|
127
|
+
// Mirror the pill motion timings in CSS below.
|
|
128
|
+
const SNAP_DUR = 200;
|
|
129
|
+
const SETTLE_DUR = 300;
|
|
112
130
|
const DEFAULT_DOCKED_WIDTH = Math.min(960, Math.floor(window.innerWidth * 0.55));
|
|
113
131
|
const DEFAULT_FLOATING = {
|
|
114
132
|
x: Math.max(16, window.innerWidth - 960 - 32),
|
|
@@ -117,10 +135,44 @@
|
|
|
117
135
|
height: Math.min(880, window.innerHeight - 96),
|
|
118
136
|
};
|
|
119
137
|
|
|
138
|
+
// The collapsed pill is placed from the right and top edges whichever side it
|
|
139
|
+
// docks to, so that every dock is a value change on one of those two axes and
|
|
140
|
+
// stays animatable. A left dock is right: <the far end>, not left: 0.
|
|
141
|
+
type DockEdge = 'none' | (typeof DOCK_EDGES)[number];
|
|
142
|
+
|
|
143
|
+
interface CollapsedState {
|
|
144
|
+
right: number;
|
|
145
|
+
top: number;
|
|
146
|
+
edge: DockEdge;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function parseEdge(value: unknown): DockEdge {
|
|
150
|
+
return DOCK_EDGES.find((e) => e === value) ?? 'none';
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// A fixed element's offsets resolve against the viewport without its
|
|
154
|
+
// scrollbars, which is what documentElement.clientWidth/Height report.
|
|
155
|
+
// window.innerWidth counts the scrollbar, and pinning a dock with it hangs
|
|
156
|
+
// the pill off the edge by the scrollbar's width.
|
|
157
|
+
let viewport = $state({
|
|
158
|
+
width: document.documentElement.clientWidth,
|
|
159
|
+
height: document.documentElement.clientHeight,
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
function maxRight() {
|
|
163
|
+
return Math.max(0, viewport.width - COLLAPSED_WIDTH);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function maxTop() {
|
|
167
|
+
return Math.max(0, viewport.height - COLLAPSED_HEIGHT);
|
|
168
|
+
}
|
|
169
|
+
|
|
120
170
|
interface OverlayState {
|
|
121
171
|
mode: Mode;
|
|
172
|
+
dockSide: Side;
|
|
122
173
|
dockedWidth: number;
|
|
123
174
|
floating: { x: number; y: number; width: number; height: number };
|
|
175
|
+
collapsed: CollapsedState;
|
|
124
176
|
}
|
|
125
177
|
|
|
126
178
|
function loadState(): OverlayState {
|
|
@@ -128,6 +180,7 @@
|
|
|
128
180
|
if (parsed && typeof parsed === 'object') {
|
|
129
181
|
return {
|
|
130
182
|
mode: parsed.mode === 'floating' ? 'floating' : 'docked',
|
|
183
|
+
dockSide: parsed.dockSide === 'left' ? 'left' : 'right',
|
|
131
184
|
dockedWidth: typeof parsed.dockedWidth === 'number' ? parsed.dockedWidth : DEFAULT_DOCKED_WIDTH,
|
|
132
185
|
floating: {
|
|
133
186
|
x: parsed.floating?.x ?? DEFAULT_FLOATING.x,
|
|
@@ -135,27 +188,41 @@
|
|
|
135
188
|
width: parsed.floating?.width ?? DEFAULT_FLOATING.width,
|
|
136
189
|
height: parsed.floating?.height ?? DEFAULT_FLOATING.height,
|
|
137
190
|
},
|
|
191
|
+
collapsed: {
|
|
192
|
+
right: parsed.collapsed?.right ?? COLLAPSED_DEFAULT.right,
|
|
193
|
+
top: parsed.collapsed?.top ?? COLLAPSED_DEFAULT.top,
|
|
194
|
+
edge: parseEdge(parsed.collapsed?.edge),
|
|
195
|
+
},
|
|
138
196
|
};
|
|
139
197
|
}
|
|
140
198
|
return {
|
|
141
199
|
mode: 'docked',
|
|
200
|
+
dockSide: 'right',
|
|
142
201
|
dockedWidth: DEFAULT_DOCKED_WIDTH,
|
|
143
202
|
floating: { ...DEFAULT_FLOATING },
|
|
203
|
+
collapsed: { ...COLLAPSED_DEFAULT, edge: 'none' },
|
|
144
204
|
};
|
|
145
205
|
}
|
|
146
206
|
|
|
147
207
|
function persist() {
|
|
148
|
-
quietSet(STORAGE_KEY, JSON.stringify({ mode, dockedWidth, floating }));
|
|
208
|
+
quietSet(STORAGE_KEY, JSON.stringify({ mode, dockSide, dockedWidth, floating, collapsed }));
|
|
149
209
|
}
|
|
150
210
|
|
|
151
211
|
const initial = loadState();
|
|
152
212
|
let mode: Mode = $state(initial.mode);
|
|
213
|
+
let dockSide: Side = $state(initial.dockSide);
|
|
153
214
|
let dockedWidth: number = $state(Math.max(MIN_WIDTH, initial.dockedWidth));
|
|
154
215
|
let floating = $state({ ...initial.floating });
|
|
216
|
+
let collapsed: CollapsedState = $state({ ...initial.collapsed });
|
|
155
217
|
|
|
156
|
-
//
|
|
157
|
-
|
|
158
|
-
|
|
218
|
+
// A docked pill tucks off the edge; its tab pulls it back out.
|
|
219
|
+
let dockExpanded = $state(false);
|
|
220
|
+
// Set once a press passes DRAG_SLOP, and consumed by the click it precedes.
|
|
221
|
+
let dragged = false;
|
|
222
|
+
let snapping = $state(false);
|
|
223
|
+
let settling = $state(false);
|
|
224
|
+
let snapTimer: ReturnType<typeof setTimeout> | undefined;
|
|
225
|
+
let settleTimer: ReturnType<typeof setTimeout> | undefined;
|
|
159
226
|
|
|
160
227
|
// Fade for open-only buttons (bar timing lives in CSS vars below).
|
|
161
228
|
const BTN_FADE = { duration: 130, easing: cubicInOut };
|
|
@@ -184,6 +251,8 @@
|
|
|
184
251
|
if (open) {
|
|
185
252
|
closing = false;
|
|
186
253
|
opening = true;
|
|
254
|
+
dockExpanded = false;
|
|
255
|
+
if (collapsed.edge === 'left' || collapsed.edge === 'right') dockSide = collapsed.edge;
|
|
187
256
|
if (gesturing || suppressTransition) {
|
|
188
257
|
// .no-transition path: no transitionend will fire, so reveal next frame.
|
|
189
258
|
requestAnimationFrame(() => { opening = false; });
|
|
@@ -210,7 +279,7 @@
|
|
|
210
279
|
}
|
|
211
280
|
|
|
212
281
|
// Scrim catches pointer events during gestures so they hit the panel, not the iframe.
|
|
213
|
-
let gesturing: 'drag' | 'resize-
|
|
282
|
+
let gesturing: 'drag' | 'resize-dock' | 'resize-se' | 'collapsed-drag' | null = $state(null);
|
|
214
283
|
|
|
215
284
|
function startDrag(e: PointerEvent) {
|
|
216
285
|
if (!open || mode !== 'floating') return;
|
|
@@ -238,15 +307,140 @@
|
|
|
238
307
|
window.addEventListener('pointerup', up);
|
|
239
308
|
}
|
|
240
309
|
|
|
310
|
+
// The whole collapsed pill is the drag surface, so a press anywhere on it can
|
|
311
|
+
// become a drag; the buttons under it stay clickable via dragSafe().
|
|
312
|
+
function startCollapsedDrag(e: PointerEvent) {
|
|
313
|
+
const surface = e.currentTarget as HTMLElement;
|
|
314
|
+
const pointerId = e.pointerId;
|
|
315
|
+
const orig = { ...collapsed };
|
|
316
|
+
// The pointer only moves the pill once it has travelled DRAG_SLOP, and it
|
|
317
|
+
// moves from that point rather than from the press, so a click on a button
|
|
318
|
+
// in the pill neither nudges it nor gets retargeted by pointer capture.
|
|
319
|
+
let anchorX = e.clientX;
|
|
320
|
+
let anchorY = e.clientY;
|
|
321
|
+
|
|
322
|
+
function move(ev: PointerEvent) {
|
|
323
|
+
if (!dragged) {
|
|
324
|
+
if (Math.hypot(ev.clientX - anchorX, ev.clientY - anchorY) <= DRAG_SLOP) return;
|
|
325
|
+
dragged = true;
|
|
326
|
+
gesturing = 'collapsed-drag';
|
|
327
|
+
anchorX = ev.clientX;
|
|
328
|
+
anchorY = ev.clientY;
|
|
329
|
+
surface.setPointerCapture(pointerId);
|
|
330
|
+
}
|
|
331
|
+
const dx = ev.clientX - anchorX;
|
|
332
|
+
const dy = ev.clientY - anchorY;
|
|
333
|
+
|
|
334
|
+
let right = clamp(orig.right - dx, 0, maxRight());
|
|
335
|
+
let top = clamp(orig.top + dy, 0, maxTop());
|
|
336
|
+
|
|
337
|
+
// Sticky edge: while docked, blend the pill back toward the edge it is on,
|
|
338
|
+
// so pulling off takes a deliberate move rather than a twitch.
|
|
339
|
+
if (collapsed.edge === 'right') right = resist(right, 0);
|
|
340
|
+
else if (collapsed.edge === 'left') right = resist(right, maxRight());
|
|
341
|
+
else if (collapsed.edge === 'top') top = resist(top, 0);
|
|
342
|
+
else if (collapsed.edge === 'bottom') top = resist(top, maxTop());
|
|
343
|
+
|
|
344
|
+
const edge = nearestEdge(right, top);
|
|
345
|
+
if (edge === 'right') right = 0;
|
|
346
|
+
else if (edge === 'left') right = maxRight();
|
|
347
|
+
else if (edge === 'top') top = 0;
|
|
348
|
+
else if (edge === 'bottom') top = maxTop();
|
|
349
|
+
|
|
350
|
+
if (edge !== 'none' && edge !== collapsed.edge) {
|
|
351
|
+
// Animate the last pixels to the edge instead of jumping them.
|
|
352
|
+
dockExpanded = false;
|
|
353
|
+
snapping = true;
|
|
354
|
+
clearTimeout(snapTimer);
|
|
355
|
+
snapTimer = setTimeout(() => { snapping = false; }, SNAP_DUR);
|
|
356
|
+
}
|
|
357
|
+
collapsed = { right, top, edge };
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function up() {
|
|
361
|
+
window.removeEventListener('pointermove', move);
|
|
362
|
+
window.removeEventListener('pointerup', up);
|
|
363
|
+
if (!dragged) return;
|
|
364
|
+
gesturing = null;
|
|
365
|
+
snapping = false;
|
|
366
|
+
clearTimeout(snapTimer);
|
|
367
|
+
settling = true;
|
|
368
|
+
clearTimeout(settleTimer);
|
|
369
|
+
settleTimer = setTimeout(() => { settling = false; }, SETTLE_DUR + 40);
|
|
370
|
+
persist();
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
window.addEventListener('pointermove', move);
|
|
374
|
+
window.addEventListener('pointerup', up);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function onHeaderPointerDown(e: PointerEvent) {
|
|
378
|
+
dragged = false;
|
|
379
|
+
if (open) startDrag(e);
|
|
380
|
+
else startCollapsedDrag(e);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Mirrors applySnapResistance in the source toolbar: the closer the pill is to
|
|
384
|
+
// the edge it is docked on, the harder it pulls back to it.
|
|
385
|
+
function resist(value: number, anchor: number) {
|
|
386
|
+
const delta = Math.abs(value - anchor);
|
|
387
|
+
if (delta >= DOCK_PULL) return value;
|
|
388
|
+
const factor = 1 - delta / DOCK_PULL;
|
|
389
|
+
return value * (1 - factor) + anchor * factor;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function nearestEdge(right: number, top: number): DockEdge {
|
|
393
|
+
const distances = [
|
|
394
|
+
{ edge: 'right' as const, distance: right },
|
|
395
|
+
{ edge: 'left' as const, distance: maxRight() - right },
|
|
396
|
+
{ edge: 'top' as const, distance: top },
|
|
397
|
+
{ edge: 'bottom' as const, distance: maxTop() - top },
|
|
398
|
+
];
|
|
399
|
+
const nearest = distances.reduce((a, b) => (b.distance < a.distance ? b : a));
|
|
400
|
+
return nearest.distance < DOCK_SNAP ? nearest.edge : 'none';
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// A press that turned into a drag must not also fire the button it landed on.
|
|
404
|
+
function dragSafe(fn: () => void) {
|
|
405
|
+
return () => {
|
|
406
|
+
if (dragged) return;
|
|
407
|
+
fn();
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function toggleDock() {
|
|
412
|
+
if (collapsed.edge === 'none') return;
|
|
413
|
+
dockExpanded = !dockExpanded;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function onViewportResize() {
|
|
417
|
+
viewport = {
|
|
418
|
+
width: document.documentElement.clientWidth,
|
|
419
|
+
height: document.documentElement.clientHeight,
|
|
420
|
+
};
|
|
421
|
+
clampCollapsed();
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
function clampCollapsed() {
|
|
425
|
+
const { edge } = collapsed;
|
|
426
|
+
collapsed = {
|
|
427
|
+
edge,
|
|
428
|
+
right: edge === 'left' ? maxRight() : edge === 'right' ? 0 : clamp(collapsed.right, 0, maxRight()),
|
|
429
|
+
top: edge === 'bottom' ? maxTop() : edge === 'top' ? 0 : clamp(collapsed.top, 0, maxTop()),
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
|
|
241
433
|
function startDockedResize(e: PointerEvent) {
|
|
242
434
|
if (!open || mode !== 'docked') return;
|
|
243
|
-
gesturing = 'resize-
|
|
435
|
+
gesturing = 'resize-dock';
|
|
244
436
|
(e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);
|
|
245
437
|
const startX = e.clientX;
|
|
246
438
|
const origWidth = dockedWidth;
|
|
247
439
|
function move(ev: PointerEvent) {
|
|
248
|
-
//
|
|
249
|
-
|
|
440
|
+
// The panel is pinned to its docked side, so dragging away from that side
|
|
441
|
+
// is what grows it.
|
|
442
|
+
const grow = dockSide === 'left' ? ev.clientX - startX : startX - ev.clientX;
|
|
443
|
+
dockedWidth = clamp(origWidth + grow, MIN_WIDTH, viewport.width - 120);
|
|
250
444
|
}
|
|
251
445
|
function up() {
|
|
252
446
|
gesturing = null;
|
|
@@ -307,9 +501,16 @@
|
|
|
307
501
|
open = !open;
|
|
308
502
|
}
|
|
309
503
|
|
|
504
|
+
function flipDockSide() {
|
|
505
|
+
dockSide = dockSide === 'right' ? 'left' : 'right';
|
|
506
|
+
persist();
|
|
507
|
+
}
|
|
508
|
+
|
|
310
509
|
function handleHeaderDblClick(e: MouseEvent) {
|
|
311
|
-
// Skip dblclick on buttons so their handlers don't double-fire
|
|
510
|
+
// Skip dblclick on buttons so their handlers don't double-fire, and on the
|
|
511
|
+
// grip so a quick reposition doesn't open the editor.
|
|
312
512
|
if ((e.target as HTMLElement).closest('button')) return;
|
|
513
|
+
if (dragged) return;
|
|
313
514
|
toggleOpen();
|
|
314
515
|
}
|
|
315
516
|
|
|
@@ -319,52 +520,100 @@
|
|
|
319
520
|
|
|
320
521
|
onMount(() => {
|
|
321
522
|
window.addEventListener('lt-overlay-toggle', handleToggleRequest);
|
|
523
|
+
window.addEventListener('resize', onViewportResize);
|
|
524
|
+
onViewportResize();
|
|
322
525
|
});
|
|
323
526
|
onDestroy(() => {
|
|
324
527
|
window.removeEventListener('lt-overlay-toggle', handleToggleRequest);
|
|
528
|
+
window.removeEventListener('resize', onViewportResize);
|
|
325
529
|
clearTimeout(maskTimer);
|
|
530
|
+
clearTimeout(snapTimer);
|
|
531
|
+
clearTimeout(settleTimer);
|
|
326
532
|
});
|
|
327
533
|
|
|
534
|
+
// A docked pill tucks off its edge the moment it snaps, mid-drag included, so
|
|
535
|
+
// that reaching an edge gets it out of the way instead of parking it against
|
|
536
|
+
// the side. It waits out the collapse animation, so the shrink and the tuck
|
|
537
|
+
// read as one move.
|
|
538
|
+
let tucked = $derived(!open && !closing && !dockExpanded && collapsed.edge !== 'none');
|
|
539
|
+
let dockClass = $derived(!open && collapsed.edge !== 'none' ? `dock-${collapsed.edge}` : '');
|
|
540
|
+
let tabIsHorizontal = $derived(collapsed.edge === 'top' || collapsed.edge === 'bottom');
|
|
541
|
+
|
|
328
542
|
let panelStyle = $derived(!open
|
|
329
|
-
? `position: fixed; top:
|
|
543
|
+
? `position: fixed; top: ${collapsed.top}px; right: ${collapsed.right}px; width: ${COLLAPSED_WIDTH}px; height: ${COLLAPSED_HEIGHT}px;`
|
|
330
544
|
: mode === 'docked'
|
|
331
|
-
|
|
545
|
+
// Both sides are pinned with `right`, so flipping side and collapsing to
|
|
546
|
+
// the pill are value changes on one axis, and animate.
|
|
547
|
+
? `position: fixed; top: 0; right: ${dockSide === 'left' ? Math.max(0, viewport.width - dockedWidth) : 0}px; width: ${dockedWidth}px; height: 100vh;`
|
|
332
548
|
: `position: fixed; top: ${floating.y}px; left: ${floating.x}px; width: ${floating.width}px; height: ${floating.height}px;`);
|
|
333
549
|
</script>
|
|
334
550
|
|
|
335
551
|
{#if enabled && !onEditorPath}
|
|
336
552
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
337
553
|
<div
|
|
338
|
-
class="lt-overlay"
|
|
554
|
+
class="lt-overlay {dockClass}"
|
|
339
555
|
style={panelStyle}
|
|
340
556
|
class:shown={open}
|
|
341
557
|
class:hidden={!open}
|
|
342
558
|
class:docked={open && mode === 'docked'}
|
|
559
|
+
class:side-left={open && mode === 'docked' && dockSide === 'left'}
|
|
343
560
|
class:floating={open && mode === 'floating'}
|
|
561
|
+
class:tucked
|
|
562
|
+
class:dragging={gesturing === 'collapsed-drag'}
|
|
563
|
+
class:snapping
|
|
564
|
+
class:settling
|
|
565
|
+
class:at-edge={gesturing === 'collapsed-drag' && collapsed.edge !== 'none'}
|
|
344
566
|
class:opening={open && opening}
|
|
345
567
|
class:closing={!open && closing}
|
|
346
|
-
class:no-transition={!!gesturing || suppressTransition}
|
|
568
|
+
class:no-transition={(!!gesturing && gesturing !== 'collapsed-drag') || suppressTransition}
|
|
347
569
|
ontransitionend={onPanelTransitionEnd}
|
|
348
570
|
>
|
|
349
571
|
<div
|
|
350
572
|
class="header"
|
|
351
|
-
onpointerdown={
|
|
573
|
+
onpointerdown={onHeaderPointerDown}
|
|
352
574
|
ondblclick={handleHeaderDblClick}
|
|
353
|
-
title={open ? 'Double-click to
|
|
575
|
+
title={open ? 'Double-click to collapse' : 'Double-click to expand'}
|
|
354
576
|
>
|
|
577
|
+
{#if !open && collapsed.edge !== 'none'}
|
|
578
|
+
<button
|
|
579
|
+
class="tab"
|
|
580
|
+
inert={!tucked}
|
|
581
|
+
onclick={dragSafe(toggleDock)}
|
|
582
|
+
title="Show the editor bar. Drag to undock."
|
|
583
|
+
>
|
|
584
|
+
<i class="fas {tabIsHorizontal ? 'fa-grip' : 'fa-grip-vertical'}"></i>
|
|
585
|
+
</button>
|
|
586
|
+
{/if}
|
|
587
|
+
|
|
588
|
+
{#if !open}
|
|
589
|
+
<button
|
|
590
|
+
class="grip"
|
|
591
|
+
inert={tucked}
|
|
592
|
+
onclick={dragSafe(toggleDock)}
|
|
593
|
+
title={collapsed.edge === 'none'
|
|
594
|
+
? 'Drag to move. Drop at an edge to dock.'
|
|
595
|
+
: 'Tuck to the edge'}
|
|
596
|
+
transition:fade={BTN_FADE}
|
|
597
|
+
>
|
|
598
|
+
<i class="fas fa-grip-vertical"></i>
|
|
599
|
+
</button>
|
|
600
|
+
{/if}
|
|
601
|
+
|
|
355
602
|
<button
|
|
356
603
|
class="hdr-btn text title"
|
|
357
|
-
|
|
358
|
-
|
|
604
|
+
inert={tucked}
|
|
605
|
+
onclick={dragSafe(toggleOpen)}
|
|
606
|
+
title={open ? 'Collapse Editor' : 'Expand Editor'}
|
|
359
607
|
>
|
|
360
|
-
<i class="fas {open ? 'fa-
|
|
608
|
+
<i class="fas {open ? 'fa-compress' : 'fa-expand'}"></i>
|
|
361
609
|
<span>Editor</span>
|
|
362
610
|
</button>
|
|
363
611
|
|
|
364
612
|
<button
|
|
365
613
|
class="hdr-btn icon"
|
|
366
614
|
class:active={$columnsVisible}
|
|
367
|
-
|
|
615
|
+
inert={tucked}
|
|
616
|
+
onclick={dragSafe(toggleColumns)}
|
|
368
617
|
title="{$columnsVisible ? 'Hide' : 'Show'} columns"
|
|
369
618
|
>
|
|
370
619
|
<i class="fas fa-grip-lines-vertical"></i>
|
|
@@ -373,7 +622,7 @@
|
|
|
373
622
|
{#if open}
|
|
374
623
|
<button
|
|
375
624
|
class="hdr-btn icon"
|
|
376
|
-
title={mode === 'docked' ? 'Float' :
|
|
625
|
+
title={mode === 'docked' ? 'Float' : `Dock to the ${dockSide}`}
|
|
377
626
|
onclick={toggleMode}
|
|
378
627
|
transition:fade={BTN_FADE}
|
|
379
628
|
>
|
|
@@ -381,6 +630,17 @@
|
|
|
381
630
|
</button>
|
|
382
631
|
{/if}
|
|
383
632
|
|
|
633
|
+
{#if open && mode === 'docked'}
|
|
634
|
+
<button
|
|
635
|
+
class="hdr-btn icon"
|
|
636
|
+
title="Dock to the {dockSide === 'right' ? 'left' : 'right'}"
|
|
637
|
+
onclick={flipDockSide}
|
|
638
|
+
transition:fade={BTN_FADE}
|
|
639
|
+
>
|
|
640
|
+
<i class="fas {dockSide === 'right' ? 'fa-angles-left' : 'fa-angles-right'}"></i>
|
|
641
|
+
</button>
|
|
642
|
+
{/if}
|
|
643
|
+
|
|
384
644
|
{#if APP_VERSION}
|
|
385
645
|
<span class="version" title="live-tokens version">v{APP_VERSION}</span>
|
|
386
646
|
{/if}
|
|
@@ -437,7 +697,10 @@
|
|
|
437
697
|
</div>
|
|
438
698
|
|
|
439
699
|
{#if mode === 'docked'}
|
|
440
|
-
<div
|
|
700
|
+
<div
|
|
701
|
+
class="resize-edge {dockSide === 'left' ? 'at-right' : 'at-left'}"
|
|
702
|
+
onpointerdown={startDockedResize}
|
|
703
|
+
></div>
|
|
441
704
|
{:else}
|
|
442
705
|
<div class="resize-se" onpointerdown={startFloatingResize}></div>
|
|
443
706
|
{/if}
|
|
@@ -454,6 +717,17 @@
|
|
|
454
717
|
--bar-close-dur: 240ms;
|
|
455
718
|
--bar-close-ease: cubic-bezier(0, 0, 0.2, 1); /* ease-out */
|
|
456
719
|
--bar-close-delay: 120ms; /* let the iframe fade out before the panel shrinks */
|
|
720
|
+
/* Collapsed-pill motion: snap = the last pixels to the edge, settle = the
|
|
721
|
+
drop, tuck = sliding off the edge and back. Mirrored by SNAP_DUR and
|
|
722
|
+
SETTLE_DUR in the script. */
|
|
723
|
+
--snap-dur: 200ms;
|
|
724
|
+
--snap-ease: cubic-bezier(0.755, 0.05, 0.855, 0.06);
|
|
725
|
+
--settle-dur: 300ms;
|
|
726
|
+
--settle-ease: cubic-bezier(0.22, 1, 0.36, 1);
|
|
727
|
+
--tuck-dur: 220ms;
|
|
728
|
+
--tuck-ease: cubic-bezier(0.22, 1, 0.36, 1);
|
|
729
|
+
--tab-width: 20px; /* the sliver of pill that stays on screen when docked */
|
|
730
|
+
--tab-length: 56px; /* the handle's reach along a horizontal edge */
|
|
457
731
|
|
|
458
732
|
display: flex;
|
|
459
733
|
flex-direction: column;
|
|
@@ -469,7 +743,8 @@
|
|
|
469
743
|
height var(--bar-open-dur) var(--bar-open-ease) var(--bar-open-delay),
|
|
470
744
|
top var(--bar-open-dur) var(--bar-open-ease) var(--bar-open-delay),
|
|
471
745
|
right var(--bar-open-dur) var(--bar-open-ease) var(--bar-open-delay),
|
|
472
|
-
border-radius var(--bar-open-dur) var(--bar-open-ease) var(--bar-open-delay)
|
|
746
|
+
border-radius var(--bar-open-dur) var(--bar-open-ease) var(--bar-open-delay),
|
|
747
|
+
transform var(--tuck-dur) var(--tuck-ease);
|
|
473
748
|
}
|
|
474
749
|
|
|
475
750
|
/* Sketch mode scopes itself to the host document root, and this bar lives
|
|
@@ -492,11 +767,17 @@
|
|
|
492
767
|
border-radius: 0;
|
|
493
768
|
}
|
|
494
769
|
|
|
770
|
+
.lt-overlay.docked.side-left {
|
|
771
|
+
border-right: 1px solid rgba(255, 255, 255, 0.12);
|
|
772
|
+
border-left: none;
|
|
773
|
+
}
|
|
774
|
+
|
|
495
775
|
.lt-overlay.floating {
|
|
496
776
|
border-radius: var(--ui-radius-xl, 8px);
|
|
497
777
|
}
|
|
498
778
|
|
|
499
|
-
/* Collapsed state:
|
|
779
|
+
/* Collapsed state: draggable pill, placed from the right edge; iframe stays
|
|
780
|
+
mounted, clipped by overflow:hidden. */
|
|
500
781
|
.lt-overlay.hidden {
|
|
501
782
|
border-radius: var(--ui-radius-lg, 6px);
|
|
502
783
|
border-color: rgba(255, 255, 255, 0.32);
|
|
@@ -505,10 +786,99 @@
|
|
|
505
786
|
height var(--bar-close-dur) var(--bar-close-ease) var(--bar-close-delay),
|
|
506
787
|
top var(--bar-close-dur) var(--bar-close-ease) var(--bar-close-delay),
|
|
507
788
|
right var(--bar-close-dur) var(--bar-close-ease) var(--bar-close-delay),
|
|
508
|
-
border-radius var(--bar-close-dur) var(--bar-close-ease) var(--bar-close-delay)
|
|
789
|
+
border-radius var(--bar-close-dur) var(--bar-close-ease) var(--bar-close-delay),
|
|
790
|
+
transform var(--tuck-dur) var(--tuck-ease),
|
|
791
|
+
background-color var(--tuck-dur) var(--tuck-ease),
|
|
792
|
+
border-color var(--tuck-dur) var(--tuck-ease),
|
|
793
|
+
box-shadow var(--tuck-dur) ease;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
/* Docked: slide all but a tab's width off the edge, whichever edge it is. */
|
|
797
|
+
.lt-overlay.tucked.dock-right {
|
|
798
|
+
transform: translateX(calc(100% - var(--tab-width)));
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
.lt-overlay.tucked.dock-left {
|
|
802
|
+
transform: translateX(calc(-100% + var(--tab-width)));
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
.lt-overlay.tucked.dock-top {
|
|
806
|
+
transform: translateY(calc(-100% + var(--tab-width)));
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
.lt-overlay.tucked.dock-bottom {
|
|
810
|
+
transform: translateY(calc(100% - var(--tab-width)));
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
/* Flatten the corners the pill is resting against. */
|
|
814
|
+
.lt-overlay.hidden.dock-right {
|
|
815
|
+
border-top-right-radius: 0;
|
|
816
|
+
border-bottom-right-radius: 0;
|
|
509
817
|
}
|
|
510
818
|
|
|
511
|
-
.lt-overlay.hidden
|
|
819
|
+
.lt-overlay.hidden.dock-left {
|
|
820
|
+
border-top-left-radius: 0;
|
|
821
|
+
border-bottom-left-radius: 0;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
.lt-overlay.hidden.dock-top {
|
|
825
|
+
border-top-left-radius: 0;
|
|
826
|
+
border-top-right-radius: 0;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
.lt-overlay.hidden.dock-bottom {
|
|
830
|
+
border-bottom-left-radius: 0;
|
|
831
|
+
border-bottom-right-radius: 0;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
/* Following the pointer, so position does not animate. The tuck still does,
|
|
835
|
+
so pulling a docked pill off the edge unfurls it. */
|
|
836
|
+
.lt-overlay.dragging {
|
|
837
|
+
transition: transform var(--tuck-dur) var(--tuck-ease);
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
/* The last pixels to the edge are a jump, and worth animating. */
|
|
841
|
+
.lt-overlay.dragging.snapping {
|
|
842
|
+
transition:
|
|
843
|
+
right var(--snap-dur) var(--snap-ease),
|
|
844
|
+
top var(--snap-dur) var(--snap-ease),
|
|
845
|
+
transform var(--tuck-dur) var(--tuck-ease);
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
/* Released: ease into the resting spot rather than stopping dead. */
|
|
849
|
+
.lt-overlay.settling {
|
|
850
|
+
transition:
|
|
851
|
+
top var(--settle-dur) var(--settle-ease),
|
|
852
|
+
right var(--settle-dur) var(--settle-ease),
|
|
853
|
+
transform var(--tuck-dur) var(--tuck-ease),
|
|
854
|
+
box-shadow var(--tuck-dur) ease;
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
/* Docked to a horizontal edge, the pill hides its depth rather than its
|
|
858
|
+
length, which would leave its whole width parked on the page. Its chrome
|
|
859
|
+
gives way to the tab, so what stays on screen is a handle either way. */
|
|
860
|
+
.lt-overlay.tucked.dock-top,
|
|
861
|
+
.lt-overlay.tucked.dock-bottom,
|
|
862
|
+
.lt-overlay.tucked.dock-top .header,
|
|
863
|
+
.lt-overlay.tucked.dock-bottom .header {
|
|
864
|
+
background: transparent;
|
|
865
|
+
border-color: transparent;
|
|
866
|
+
box-shadow: none;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
.lt-overlay.tucked.dock-top .frame-wrap,
|
|
870
|
+
.lt-overlay.tucked.dock-bottom .frame-wrap {
|
|
871
|
+
opacity: 0;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
/* The edge has the pill: say so while it is still under the pointer. */
|
|
875
|
+
.lt-overlay.at-edge {
|
|
876
|
+
box-shadow:
|
|
877
|
+
0 0 0 2px rgba(255, 255, 255, 0.45),
|
|
878
|
+
0 18px 60px rgba(0, 0, 0, 0.6);
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
.lt-overlay.hidden .resize-edge,
|
|
512
882
|
.lt-overlay.hidden .resize-se {
|
|
513
883
|
display: none;
|
|
514
884
|
}
|
|
@@ -519,6 +889,7 @@
|
|
|
519
889
|
}
|
|
520
890
|
|
|
521
891
|
.header {
|
|
892
|
+
position: relative;
|
|
522
893
|
display: flex;
|
|
523
894
|
align-items: center;
|
|
524
895
|
gap: var(--ui-space-6, 6px);
|
|
@@ -530,15 +901,127 @@
|
|
|
530
901
|
user-select: none;
|
|
531
902
|
}
|
|
532
903
|
|
|
904
|
+
/* The whole collapsed pill is the drag surface. */
|
|
533
905
|
.lt-overlay.hidden .header {
|
|
534
906
|
border-bottom: none;
|
|
535
907
|
padding: 5px var(--ui-space-8, 8px);
|
|
908
|
+
cursor: grab;
|
|
909
|
+
transition: background-color var(--tuck-dur) var(--tuck-ease);
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
.grip {
|
|
913
|
+
display: inline-flex;
|
|
914
|
+
align-self: stretch;
|
|
915
|
+
align-items: center;
|
|
916
|
+
justify-content: center;
|
|
917
|
+
width: var(--tab-width);
|
|
918
|
+
/* Cancel the header's left padding so the grip is the pill's left edge,
|
|
919
|
+
which is what stays on screen when docked. */
|
|
920
|
+
margin-left: calc(-1 * var(--ui-space-8, 8px));
|
|
921
|
+
padding: 0;
|
|
922
|
+
background: transparent;
|
|
923
|
+
border: 0;
|
|
924
|
+
color: rgba(255, 255, 255, 0.45);
|
|
925
|
+
font-size: var(--ui-font-size-sm, 12px);
|
|
926
|
+
cursor: grab;
|
|
927
|
+
touch-action: none;
|
|
928
|
+
transition: background var(--ui-transition-fast, 120ms ease), color var(--ui-transition-fast, 120ms ease);
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
.grip:hover {
|
|
932
|
+
background: rgba(255, 255, 255, 0.1);
|
|
933
|
+
color: rgba(255, 255, 255, 0.9);
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
/* The tab hugs the edge of the pill that stays on screen, so it is the whole
|
|
937
|
+
of what a tucked pill shows. It sits over the bar, which fades out under it. */
|
|
938
|
+
.tab {
|
|
939
|
+
position: absolute;
|
|
940
|
+
display: flex;
|
|
941
|
+
align-items: center;
|
|
942
|
+
justify-content: center;
|
|
943
|
+
padding: 0;
|
|
944
|
+
background: rgba(255, 255, 255, 0.08);
|
|
945
|
+
border: 0;
|
|
946
|
+
color: rgba(255, 255, 255, 0.75);
|
|
947
|
+
font-size: var(--ui-font-size-sm, 12px);
|
|
948
|
+
cursor: grab;
|
|
949
|
+
opacity: 0;
|
|
950
|
+
touch-action: none;
|
|
951
|
+
transition: opacity var(--tuck-dur) var(--tuck-ease), background var(--ui-transition-fast, 120ms ease);
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
.tab:hover {
|
|
955
|
+
background: rgba(255, 255, 255, 0.14);
|
|
956
|
+
color: var(--ui-text-primary, #fff);
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
.dock-right .tab {
|
|
960
|
+
top: 0;
|
|
961
|
+
bottom: 0;
|
|
962
|
+
left: 0;
|
|
963
|
+
width: var(--tab-width);
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
.dock-left .tab {
|
|
967
|
+
top: 0;
|
|
968
|
+
bottom: 0;
|
|
969
|
+
right: 0;
|
|
970
|
+
width: var(--tab-width);
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
/* On a horizontal edge the tab is the whole of the visible chrome, so it
|
|
974
|
+
carries the pill's surface and border and reaches only --tab-length. */
|
|
975
|
+
.dock-top .tab,
|
|
976
|
+
.dock-bottom .tab {
|
|
977
|
+
left: 50%;
|
|
978
|
+
width: var(--tab-length);
|
|
979
|
+
height: var(--tab-width);
|
|
980
|
+
margin-left: calc(var(--tab-length) / -2);
|
|
981
|
+
background: var(--ui-surface-low, #111);
|
|
982
|
+
border: 1px solid rgba(255, 255, 255, 0.32);
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
.dock-top .tab {
|
|
986
|
+
bottom: 0;
|
|
987
|
+
border-top: 0;
|
|
988
|
+
border-radius: 0 0 var(--ui-radius-lg, 6px) var(--ui-radius-lg, 6px);
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
.dock-bottom .tab {
|
|
992
|
+
top: 0;
|
|
993
|
+
border-bottom: 0;
|
|
994
|
+
border-radius: var(--ui-radius-lg, 6px) var(--ui-radius-lg, 6px) 0 0;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
.dock-top .tab:hover,
|
|
998
|
+
.dock-bottom .tab:hover {
|
|
999
|
+
background: var(--ui-surface-lower, #0a0a0a);
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
.lt-overlay.tucked .tab {
|
|
1003
|
+
opacity: 1;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
/* Tucked, the bar itself is off-screen; fade it so nothing of it shows
|
|
1007
|
+
through the tab on the way out. */
|
|
1008
|
+
.lt-overlay.tucked .hdr-btn,
|
|
1009
|
+
.lt-overlay.tucked .grip,
|
|
1010
|
+
.lt-overlay.tucked .version {
|
|
1011
|
+
opacity: 0;
|
|
1012
|
+
transition: opacity var(--tuck-dur) var(--tuck-ease);
|
|
536
1013
|
}
|
|
537
1014
|
|
|
538
1015
|
.lt-overlay.floating .header {
|
|
539
1016
|
cursor: move;
|
|
540
1017
|
}
|
|
541
1018
|
|
|
1019
|
+
.lt-overlay.dragging .header,
|
|
1020
|
+
.lt-overlay.dragging .grip,
|
|
1021
|
+
.lt-overlay.dragging .tab {
|
|
1022
|
+
cursor: grabbing;
|
|
1023
|
+
}
|
|
1024
|
+
|
|
542
1025
|
.hdr-btn.title {
|
|
543
1026
|
gap: 7px;
|
|
544
1027
|
font-size: var(--ui-font-size-md, 16px);
|
|
@@ -716,17 +1199,25 @@
|
|
|
716
1199
|
cursor: inherit;
|
|
717
1200
|
}
|
|
718
1201
|
|
|
719
|
-
.
|
|
1202
|
+
/* Sits on the panel's inner edge, whichever side it is docked to. */
|
|
1203
|
+
.resize-edge {
|
|
720
1204
|
position: absolute;
|
|
721
1205
|
top: 0;
|
|
722
|
-
left: 0;
|
|
723
1206
|
bottom: 0;
|
|
724
1207
|
width: 6px;
|
|
725
1208
|
cursor: ew-resize;
|
|
726
1209
|
background: transparent;
|
|
727
1210
|
}
|
|
728
1211
|
|
|
729
|
-
.resize-left
|
|
1212
|
+
.resize-edge.at-left {
|
|
1213
|
+
left: 0;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
.resize-edge.at-right {
|
|
1217
|
+
right: 0;
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
.resize-edge:hover {
|
|
730
1221
|
background: rgba(255, 255, 255, 0.08);
|
|
731
1222
|
}
|
|
732
1223
|
|