@skygraph/styles 0.0.0-placeholder.0 → 0.1.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/LICENSE +21 -0
- package/README.md +92 -6
- package/components/autocomplete.css +33 -0
- package/components/avatar.css +37 -0
- package/components/badge.css +102 -0
- package/components/breadcrumb.css +29 -0
- package/components/button.css +181 -0
- package/components/calendar.css +408 -0
- package/components/carousel.css +102 -0
- package/components/cascader.css +354 -0
- package/components/charts.css +408 -0
- package/components/checkbox.css +29 -0
- package/components/collapse.css +166 -0
- package/components/colorpicker.css +252 -0
- package/components/context-menu.css +95 -0
- package/components/dashboard.css +299 -0
- package/components/datagrid.css +86 -0
- package/components/datepicker.css +601 -0
- package/components/descriptions.css +82 -0
- package/components/diagram.css +422 -0
- package/components/drawer.css +103 -0
- package/components/dropdown.css +93 -0
- package/components/empty.css +25 -0
- package/components/event-timeline.css +100 -0
- package/components/field.css +35 -0
- package/components/form.css +115 -0
- package/components/gantt.css +161 -0
- package/components/inline-edit.css +113 -0
- package/components/input-group.css +79 -0
- package/components/input-number.css +76 -0
- package/components/input-password.css +104 -0
- package/components/input.css +110 -0
- package/components/list.css +357 -0
- package/components/mentions.css +54 -0
- package/components/menu.css +309 -0
- package/components/modal.css +77 -0
- package/components/notification.css +128 -0
- package/components/pagination.css +162 -0
- package/components/pin-input.css +71 -0
- package/components/popconfirm.css +95 -0
- package/components/progress.css +116 -0
- package/components/radio.css +38 -0
- package/components/rate.css +34 -0
- package/components/resource-calendar.css +219 -0
- package/components/result.css +45 -0
- package/components/schema-form-editor.css +425 -0
- package/components/search-input.css +112 -0
- package/components/segmented.css +76 -0
- package/components/select.css +172 -0
- package/components/skeleton.css +68 -0
- package/components/slider.css +51 -0
- package/components/spin.css +86 -0
- package/components/steps.css +185 -0
- package/components/switch.css +69 -0
- package/components/table.css +984 -0
- package/components/tabs.css +117 -0
- package/components/tag-input.css +94 -0
- package/components/tag.css +61 -0
- package/components/textarea.css +22 -0
- package/components/timeline.css +169 -0
- package/components/timepicker.css +213 -0
- package/components/tooltip.css +91 -0
- package/components/transfer.css +140 -0
- package/components/tree.css +574 -0
- package/components/treeselect.css +219 -0
- package/components/upload.css +124 -0
- package/index.css +69 -3
- package/index.d.ts +9 -0
- package/package.json +102 -18
- package/print.css +88 -0
- package/reset.css +17 -0
- package/themes/dark.css +17 -0
- package/themes/default.css +14 -0
- package/tokens.css +312 -0
- package/transitions.css +158 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/* === ColorPicker === */
|
|
2
|
+
|
|
3
|
+
.sg-colorpicker-wrapper {
|
|
4
|
+
position: relative;
|
|
5
|
+
display: inline-block;
|
|
6
|
+
font-size: var(--sg-font-size);
|
|
7
|
+
color: var(--sg-color-text);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.sg-colorpicker-disabled {
|
|
11
|
+
opacity: 0.5;
|
|
12
|
+
pointer-events: none;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* --- Sizes --- */
|
|
16
|
+
|
|
17
|
+
.sg-colorpicker-small .sg-colorpicker-trigger {
|
|
18
|
+
height: var(--sg-height-sm);
|
|
19
|
+
padding: 2px var(--sg-padding-xs);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.sg-colorpicker-small .sg-colorpicker-swatch {
|
|
23
|
+
width: 16px;
|
|
24
|
+
height: 16px;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.sg-colorpicker-middle .sg-colorpicker-trigger {
|
|
28
|
+
height: var(--sg-height-md);
|
|
29
|
+
padding: var(--sg-padding-xs) var(--sg-padding-sm);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.sg-colorpicker-middle .sg-colorpicker-swatch {
|
|
33
|
+
width: 20px;
|
|
34
|
+
height: 20px;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.sg-colorpicker-large .sg-colorpicker-trigger {
|
|
38
|
+
height: var(--sg-height-lg);
|
|
39
|
+
padding: var(--sg-padding-xs) var(--sg-padding-md);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.sg-colorpicker-large .sg-colorpicker-swatch {
|
|
43
|
+
width: 24px;
|
|
44
|
+
height: 24px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* --- Trigger --- */
|
|
48
|
+
|
|
49
|
+
.sg-colorpicker-trigger {
|
|
50
|
+
display: inline-flex;
|
|
51
|
+
align-items: center;
|
|
52
|
+
gap: var(--sg-padding-sm);
|
|
53
|
+
border: 1px solid var(--sg-color-border);
|
|
54
|
+
border-radius: var(--sg-border-radius);
|
|
55
|
+
background: var(--sg-color-bg-container);
|
|
56
|
+
color: inherit;
|
|
57
|
+
font: inherit;
|
|
58
|
+
cursor: pointer;
|
|
59
|
+
transition:
|
|
60
|
+
border-color var(--sg-transition-duration) var(--sg-transition-timing),
|
|
61
|
+
box-shadow var(--sg-transition-duration) var(--sg-transition-timing);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.sg-colorpicker-trigger:disabled {
|
|
65
|
+
cursor: not-allowed;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.sg-colorpicker-trigger:hover {
|
|
69
|
+
border-color: var(--sg-color-primary-hover);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.sg-colorpicker-trigger:focus-visible {
|
|
73
|
+
outline: none;
|
|
74
|
+
border-color: var(--sg-color-primary);
|
|
75
|
+
box-shadow: 0 0 0 2px var(--sg-color-primary-bg);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/* --- Swatch --- */
|
|
79
|
+
|
|
80
|
+
.sg-colorpicker-swatch {
|
|
81
|
+
display: inline-block;
|
|
82
|
+
border-radius: var(--sg-border-radius-sm);
|
|
83
|
+
border: 1px solid var(--sg-color-border-secondary);
|
|
84
|
+
flex-shrink: 0;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.sg-colorpicker-text {
|
|
88
|
+
font-size: var(--sg-font-size-sm);
|
|
89
|
+
color: var(--sg-color-text-secondary);
|
|
90
|
+
font-family: monospace;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/* --- Dropdown --- */
|
|
94
|
+
|
|
95
|
+
.sg-colorpicker-dropdown {
|
|
96
|
+
position: absolute;
|
|
97
|
+
z-index: var(--sg-z-dropdown);
|
|
98
|
+
top: calc(100% + 4px);
|
|
99
|
+
left: 0;
|
|
100
|
+
width: 240px;
|
|
101
|
+
padding: var(--sg-padding-md);
|
|
102
|
+
background: var(--sg-color-bg-elevated);
|
|
103
|
+
border-radius: var(--sg-border-radius-lg);
|
|
104
|
+
box-shadow: var(--sg-shadow-lg);
|
|
105
|
+
border: 1px solid var(--sg-color-border-secondary);
|
|
106
|
+
display: flex;
|
|
107
|
+
flex-direction: column;
|
|
108
|
+
gap: var(--sg-padding-sm);
|
|
109
|
+
animation: sg-colorpicker-in var(--sg-transition-duration) var(--sg-transition-timing);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
@keyframes sg-colorpicker-in {
|
|
113
|
+
from {
|
|
114
|
+
opacity: 0;
|
|
115
|
+
transform: scaleY(0.9);
|
|
116
|
+
}
|
|
117
|
+
to {
|
|
118
|
+
opacity: 1;
|
|
119
|
+
transform: scaleY(1);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* --- Saturation panel --- */
|
|
124
|
+
|
|
125
|
+
.sg-colorpicker-saturation {
|
|
126
|
+
position: relative;
|
|
127
|
+
width: 100%;
|
|
128
|
+
height: 150px;
|
|
129
|
+
border-radius: var(--sg-border-radius-sm);
|
|
130
|
+
cursor: crosshair;
|
|
131
|
+
touch-action: none;
|
|
132
|
+
user-select: none;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.sg-colorpicker-cursor {
|
|
136
|
+
position: absolute;
|
|
137
|
+
width: 12px;
|
|
138
|
+
height: 12px;
|
|
139
|
+
border: 2px solid #fff;
|
|
140
|
+
border-radius: 50%;
|
|
141
|
+
box-shadow: 0 0 2px rgba(0, 0, 0, 0.4);
|
|
142
|
+
transform: translate(-50%, -50%);
|
|
143
|
+
pointer-events: none;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/* --- Hue bar --- */
|
|
147
|
+
|
|
148
|
+
.sg-colorpicker-hue {
|
|
149
|
+
position: relative;
|
|
150
|
+
width: 100%;
|
|
151
|
+
height: 12px;
|
|
152
|
+
border-radius: 6px;
|
|
153
|
+
background: linear-gradient(
|
|
154
|
+
to right,
|
|
155
|
+
#f00 0%,
|
|
156
|
+
#ff0 17%,
|
|
157
|
+
#0f0 33%,
|
|
158
|
+
#0ff 50%,
|
|
159
|
+
#00f 67%,
|
|
160
|
+
#f0f 83%,
|
|
161
|
+
#f00 100%
|
|
162
|
+
);
|
|
163
|
+
cursor: pointer;
|
|
164
|
+
touch-action: none;
|
|
165
|
+
user-select: none;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.sg-colorpicker-hue-cursor {
|
|
169
|
+
position: absolute;
|
|
170
|
+
top: 50%;
|
|
171
|
+
width: 14px;
|
|
172
|
+
height: 14px;
|
|
173
|
+
border: 2px solid #fff;
|
|
174
|
+
border-radius: 50%;
|
|
175
|
+
box-shadow: 0 0 2px rgba(0, 0, 0, 0.4);
|
|
176
|
+
background: transparent;
|
|
177
|
+
transform: translate(-50%, -50%);
|
|
178
|
+
pointer-events: none;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/* --- Input row --- */
|
|
182
|
+
|
|
183
|
+
.sg-colorpicker-input-row {
|
|
184
|
+
display: flex;
|
|
185
|
+
align-items: center;
|
|
186
|
+
gap: var(--sg-padding-sm);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.sg-colorpicker-preview {
|
|
190
|
+
display: inline-block;
|
|
191
|
+
width: 24px;
|
|
192
|
+
height: 24px;
|
|
193
|
+
border-radius: var(--sg-border-radius-sm);
|
|
194
|
+
border: 1px solid var(--sg-color-border-secondary);
|
|
195
|
+
flex-shrink: 0;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.sg-colorpicker-input {
|
|
199
|
+
flex: 1;
|
|
200
|
+
min-width: 0;
|
|
201
|
+
height: var(--sg-height-sm);
|
|
202
|
+
padding: 0 var(--sg-padding-sm);
|
|
203
|
+
font-size: var(--sg-font-size-sm);
|
|
204
|
+
font-family: monospace;
|
|
205
|
+
color: var(--sg-color-text);
|
|
206
|
+
background: var(--sg-color-bg-container);
|
|
207
|
+
border: 1px solid var(--sg-color-border);
|
|
208
|
+
border-radius: var(--sg-border-radius-sm);
|
|
209
|
+
outline: none;
|
|
210
|
+
transition: border-color var(--sg-transition-duration) var(--sg-transition-timing);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.sg-colorpicker-input:focus {
|
|
214
|
+
border-color: var(--sg-color-primary);
|
|
215
|
+
box-shadow: 0 0 0 2px var(--sg-color-primary-bg);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/* --- Presets --- */
|
|
219
|
+
|
|
220
|
+
.sg-colorpicker-preset-group {
|
|
221
|
+
display: flex;
|
|
222
|
+
flex-direction: column;
|
|
223
|
+
gap: var(--sg-padding-xs);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.sg-colorpicker-preset-label {
|
|
227
|
+
font-size: var(--sg-font-size-sm);
|
|
228
|
+
color: var(--sg-color-text-tertiary);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.sg-colorpicker-preset-grid {
|
|
232
|
+
display: flex;
|
|
233
|
+
flex-wrap: wrap;
|
|
234
|
+
gap: var(--sg-padding-xs);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.sg-colorpicker-preset-color {
|
|
238
|
+
width: 20px;
|
|
239
|
+
height: 20px;
|
|
240
|
+
border-radius: var(--sg-border-radius-sm);
|
|
241
|
+
border: 1px solid var(--sg-color-border-secondary);
|
|
242
|
+
cursor: pointer;
|
|
243
|
+
padding: 0;
|
|
244
|
+
transition:
|
|
245
|
+
transform var(--sg-transition-duration) var(--sg-transition-timing),
|
|
246
|
+
box-shadow var(--sg-transition-duration) var(--sg-transition-timing);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.sg-colorpicker-preset-color:hover {
|
|
250
|
+
transform: scale(1.2);
|
|
251
|
+
box-shadow: 0 0 0 2px var(--sg-color-primary-bg);
|
|
252
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/* SkyGraph -- Context Menu
|
|
2
|
+
*
|
|
3
|
+
* Floating menu used by Table cell/header right-click and DataGrid
|
|
4
|
+
* context-menu. Both share visual structure (background, border, shadow,
|
|
5
|
+
* padding, hover state) but live in separate class namespaces:
|
|
6
|
+
*
|
|
7
|
+
* - `.sg-context-menu*` — Table ContextMenu (packages/react/src/
|
|
8
|
+
* components/complex/Table/ContextMenu.tsx)
|
|
9
|
+
* - `.sg-datagrid-context-menu*` — DataGrid ContextMenuPopup (DataGrid.tsx)
|
|
10
|
+
*
|
|
11
|
+
* Position (top/left) and submenu offset (`top:0; left:100%`) stay inline in
|
|
12
|
+
* TSX because they are computed at runtime from the click coordinates. Every
|
|
13
|
+
* other visual property (background, colour, border, shadow, paddings,
|
|
14
|
+
* font-size, hover state, danger state, disabled state) lives here and is
|
|
15
|
+
* driven by tokens — no hard-coded hex / px values.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/* ── Base shape, shared between Table and DataGrid via :is() group ── */
|
|
19
|
+
.sg-context-menu,
|
|
20
|
+
.sg-datagrid-context-menu {
|
|
21
|
+
z-index: var(--sg-z-dropdown);
|
|
22
|
+
min-width: 160px;
|
|
23
|
+
padding: var(--sg-padding-xs) 0;
|
|
24
|
+
background: var(--sg-color-bg-elevated);
|
|
25
|
+
border: 1px solid var(--sg-color-border-secondary);
|
|
26
|
+
border-radius: var(--sg-border-radius);
|
|
27
|
+
box-shadow: var(--sg-shadow-lg);
|
|
28
|
+
font-size: var(--sg-font-size);
|
|
29
|
+
color: var(--sg-color-text);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* ── Items ── */
|
|
33
|
+
.sg-context-menu-item,
|
|
34
|
+
.sg-datagrid-context-menu-item {
|
|
35
|
+
display: flex;
|
|
36
|
+
align-items: center;
|
|
37
|
+
gap: var(--sg-padding-sm);
|
|
38
|
+
padding: var(--sg-padding-xs) var(--sg-padding-md);
|
|
39
|
+
cursor: pointer;
|
|
40
|
+
line-height: var(--sg-line-height);
|
|
41
|
+
transition: background var(--sg-transition-duration) var(--sg-transition-timing);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.sg-context-menu-item:hover,
|
|
45
|
+
.sg-datagrid-context-menu-item:hover {
|
|
46
|
+
background: var(--sg-color-bg-hover);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* ── Modifiers ── */
|
|
50
|
+
.sg-context-menu-item--danger,
|
|
51
|
+
.sg-datagrid-context-menu-item--danger {
|
|
52
|
+
color: var(--sg-color-error);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.sg-context-menu-item--disabled,
|
|
56
|
+
.sg-datagrid-context-menu-item--disabled {
|
|
57
|
+
color: var(--sg-color-text-disabled);
|
|
58
|
+
cursor: not-allowed;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.sg-context-menu-item--disabled:hover,
|
|
62
|
+
.sg-datagrid-context-menu-item--disabled:hover {
|
|
63
|
+
background: transparent;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* ── Label (Table only — DataGrid uses plain text inside item div) ── */
|
|
67
|
+
.sg-context-menu-label {
|
|
68
|
+
flex: 1;
|
|
69
|
+
min-width: 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* ── Submenu indicator (Table only) ── */
|
|
73
|
+
.sg-context-menu-submenu-arrow {
|
|
74
|
+
margin-left: var(--sg-padding-sm);
|
|
75
|
+
color: var(--sg-color-text-tertiary);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/* ── Icon slot ── */
|
|
79
|
+
.sg-context-menu-icon {
|
|
80
|
+
display: inline-flex;
|
|
81
|
+
align-items: center;
|
|
82
|
+
justify-content: center;
|
|
83
|
+
flex-shrink: 0;
|
|
84
|
+
width: 16px;
|
|
85
|
+
height: 16px;
|
|
86
|
+
color: var(--sg-color-text-secondary);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* ── Divider ── */
|
|
90
|
+
.sg-context-menu-divider,
|
|
91
|
+
.sg-datagrid-context-menu-divider {
|
|
92
|
+
height: 1px;
|
|
93
|
+
margin: var(--sg-padding-xs) 0;
|
|
94
|
+
background: var(--sg-color-border-secondary);
|
|
95
|
+
}
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
/* Dashboard — minimal static-layout grid for widgets.
|
|
2
|
+
*
|
|
3
|
+
* Editor-mode treatment lives in the same file so the visual difference
|
|
4
|
+
* between view and edit reads as a single, designed state rather than a
|
|
5
|
+
* collection of bolted-on tweaks. All colors / shadows route through
|
|
6
|
+
* `--sg-dashboard-*` semantic tokens so dark theme picks them up
|
|
7
|
+
* without per-rule duplication.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
.sg-dashboard {
|
|
11
|
+
width: 100%;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.sg-dashboard-widget {
|
|
15
|
+
background: var(--sg-color-bg-elevated);
|
|
16
|
+
border: 1px solid var(--sg-color-border);
|
|
17
|
+
border-radius: var(--sg-border-radius);
|
|
18
|
+
display: flex;
|
|
19
|
+
flex-direction: column;
|
|
20
|
+
overflow: hidden;
|
|
21
|
+
box-shadow: var(--sg-dashboard-widget-shadow);
|
|
22
|
+
/* `transform` participates so the hover lift below stays in lock-step
|
|
23
|
+
* with the elevation change. Border-color animates on hover to give
|
|
24
|
+
* the widget a faint frame highlight. */
|
|
25
|
+
transition:
|
|
26
|
+
box-shadow var(--sg-transition-medium),
|
|
27
|
+
transform var(--sg-transition-medium),
|
|
28
|
+
border-color var(--sg-transition-medium);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.sg-dashboard-widget:hover {
|
|
32
|
+
box-shadow: var(--sg-dashboard-widget-shadow-hover);
|
|
33
|
+
border-color: var(--sg-color-border);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.sg-dashboard-widget[data-sg-maximized='true'] {
|
|
37
|
+
box-shadow: var(--sg-shadow-lg);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.sg-dashboard-widget-header {
|
|
41
|
+
position: relative;
|
|
42
|
+
display: flex;
|
|
43
|
+
align-items: center;
|
|
44
|
+
gap: var(--sg-padding-sm);
|
|
45
|
+
padding: var(--sg-padding-sm) var(--sg-padding-md);
|
|
46
|
+
font-weight: 600;
|
|
47
|
+
font-size: var(--sg-font-size);
|
|
48
|
+
color: var(--sg-color-text);
|
|
49
|
+
border-bottom: 1px solid var(--sg-color-border-secondary);
|
|
50
|
+
background: var(--sg-color-bg-container);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.sg-dashboard-widget-title {
|
|
54
|
+
flex: 1;
|
|
55
|
+
min-width: 0;
|
|
56
|
+
overflow: hidden;
|
|
57
|
+
text-overflow: ellipsis;
|
|
58
|
+
white-space: nowrap;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.sg-dashboard-widget-body {
|
|
62
|
+
flex: 1;
|
|
63
|
+
padding: var(--sg-padding-md);
|
|
64
|
+
font-size: var(--sg-font-size);
|
|
65
|
+
color: var(--sg-color-text-secondary);
|
|
66
|
+
overflow: auto;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* Actions — `⋯` button + dropdown anchored to the widget header. */
|
|
70
|
+
.sg-dashboard-widget-actions {
|
|
71
|
+
position: relative;
|
|
72
|
+
display: inline-flex;
|
|
73
|
+
flex-shrink: 0;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.sg-dashboard-widget-more {
|
|
77
|
+
display: inline-flex;
|
|
78
|
+
align-items: center;
|
|
79
|
+
justify-content: center;
|
|
80
|
+
width: 24px;
|
|
81
|
+
height: 24px;
|
|
82
|
+
padding: 0;
|
|
83
|
+
border: none;
|
|
84
|
+
border-radius: var(--sg-border-radius-sm);
|
|
85
|
+
background: transparent;
|
|
86
|
+
color: var(--sg-color-text-secondary);
|
|
87
|
+
cursor: pointer;
|
|
88
|
+
opacity: 0;
|
|
89
|
+
transition:
|
|
90
|
+
opacity var(--sg-transition-fast),
|
|
91
|
+
background-color var(--sg-transition-fast),
|
|
92
|
+
color var(--sg-transition-fast);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.sg-dashboard-widget[data-sg-actions='visible'] .sg-dashboard-widget-more,
|
|
96
|
+
.sg-dashboard-widget:hover .sg-dashboard-widget-more,
|
|
97
|
+
.sg-dashboard-widget-more:focus-visible,
|
|
98
|
+
.sg-dashboard-widget-more[aria-expanded='true'] {
|
|
99
|
+
opacity: 1;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.sg-dashboard-widget-more:hover,
|
|
103
|
+
.sg-dashboard-widget-more[aria-expanded='true'] {
|
|
104
|
+
background: var(--sg-color-bg-hover);
|
|
105
|
+
color: var(--sg-color-text);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.sg-dashboard-widget-actions-menu {
|
|
109
|
+
position: absolute;
|
|
110
|
+
top: calc(100% + 4px);
|
|
111
|
+
right: 0;
|
|
112
|
+
z-index: 20;
|
|
113
|
+
min-width: 160px;
|
|
114
|
+
padding: 4px;
|
|
115
|
+
background: var(--sg-color-bg-elevated);
|
|
116
|
+
border: 1px solid var(--sg-color-border);
|
|
117
|
+
border-radius: var(--sg-border-radius);
|
|
118
|
+
box-shadow: var(--sg-shadow-lg);
|
|
119
|
+
display: flex;
|
|
120
|
+
flex-direction: column;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.sg-dashboard-widget-actions-item {
|
|
124
|
+
display: flex;
|
|
125
|
+
align-items: center;
|
|
126
|
+
gap: var(--sg-padding-sm);
|
|
127
|
+
padding: 6px 10px;
|
|
128
|
+
border: none;
|
|
129
|
+
border-radius: var(--sg-border-radius-sm);
|
|
130
|
+
background: transparent;
|
|
131
|
+
color: var(--sg-color-text);
|
|
132
|
+
font-size: var(--sg-font-size);
|
|
133
|
+
font-weight: 400;
|
|
134
|
+
text-align: left;
|
|
135
|
+
cursor: pointer;
|
|
136
|
+
white-space: nowrap;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.sg-dashboard-widget-actions-item:hover,
|
|
140
|
+
.sg-dashboard-widget-actions-item:focus-visible {
|
|
141
|
+
background: var(--sg-color-bg-hover);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.sg-dashboard-widget-actions-item-danger {
|
|
145
|
+
color: var(--sg-color-error);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.sg-dashboard-widget-actions-item-danger:hover,
|
|
149
|
+
.sg-dashboard-widget-actions-item-danger:focus-visible {
|
|
150
|
+
background: var(--sg-color-error-bg);
|
|
151
|
+
color: var(--sg-color-error);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.sg-dashboard-widget-actions-icon {
|
|
155
|
+
display: inline-flex;
|
|
156
|
+
align-items: center;
|
|
157
|
+
justify-content: center;
|
|
158
|
+
width: 16px;
|
|
159
|
+
height: 16px;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* ─── Editor mode ────────────────────────────────────────────────────────
|
|
163
|
+
*
|
|
164
|
+
* `data-edit-mode='true'` on `.sg-dashboard-editor` flips the dashboard
|
|
165
|
+
* into edit mode. Key visual signals:
|
|
166
|
+
* 1. Subtle grid pattern on the editor background — communicates that
|
|
167
|
+
* widgets snap to a layout grid.
|
|
168
|
+
* 2. Dashed accent border on every widget — reads as "drag me".
|
|
169
|
+
* 3. Resize handle gets full opacity + a halo when hovered.
|
|
170
|
+
* Reused base widget chrome above.
|
|
171
|
+
*/
|
|
172
|
+
|
|
173
|
+
.sg-dashboard-editor[data-edit-mode='true'] {
|
|
174
|
+
/* Fine 8px grid that hints at the underlying layout snap step. The
|
|
175
|
+
* `--sg-dashboard-editor-grid-color` token is primary-tinted in both
|
|
176
|
+
* themes so the pattern reads as "active editing surface". */
|
|
177
|
+
background-image:
|
|
178
|
+
linear-gradient(to right, var(--sg-dashboard-editor-grid-color) 1px, transparent 1px),
|
|
179
|
+
linear-gradient(to bottom, var(--sg-dashboard-editor-grid-color) 1px, transparent 1px);
|
|
180
|
+
background-size: 16px 16px;
|
|
181
|
+
border-radius: var(--sg-border-radius);
|
|
182
|
+
/* A faint inset frame visually fences off the editor area — a useful
|
|
183
|
+
* affordance when the surrounding page also has its own layout. */
|
|
184
|
+
box-shadow: inset 0 0 0 1px var(--sg-color-border-secondary);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.sg-dashboard-editor[data-edit-mode='true'] .sg-dashboard-widget {
|
|
188
|
+
position: relative;
|
|
189
|
+
/* Dashed accent border replaces the solid one only in edit mode so
|
|
190
|
+
* widgets read as "live, draggable" without being noisy in view-mode.
|
|
191
|
+
* We override the *border* property entirely (style + color) so the
|
|
192
|
+
* change is unambiguous. */
|
|
193
|
+
border: 1px dashed var(--sg-dashboard-editor-widget-border);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.sg-dashboard-editor[data-edit-mode='true'] .sg-dashboard-widget:hover {
|
|
197
|
+
/* In edit-mode hover also tints the entire widget border so the
|
|
198
|
+
* dashed line goes from "inert outline" to "actively highlighted". */
|
|
199
|
+
border-color: var(--sg-color-primary);
|
|
200
|
+
box-shadow:
|
|
201
|
+
var(--sg-dashboard-widget-shadow-hover),
|
|
202
|
+
0 0 0 2px var(--sg-color-primary-bg);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.sg-dashboard-editor[data-edit-mode='true'] .sg-dashboard-widget-header {
|
|
206
|
+
cursor: grab;
|
|
207
|
+
user-select: none;
|
|
208
|
+
touch-action: none;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.sg-dashboard-editor[data-edit-mode='true'] .sg-dashboard-widget-header::before {
|
|
212
|
+
content: '';
|
|
213
|
+
display: inline-block;
|
|
214
|
+
width: 10px;
|
|
215
|
+
height: 14px;
|
|
216
|
+
margin-right: 4px;
|
|
217
|
+
flex-shrink: 0;
|
|
218
|
+
background-image:
|
|
219
|
+
radial-gradient(circle, var(--sg-color-text-tertiary) 1px, transparent 1.4px),
|
|
220
|
+
radial-gradient(circle, var(--sg-color-text-tertiary) 1px, transparent 1.4px);
|
|
221
|
+
background-size: 4px 4px;
|
|
222
|
+
background-position: 0 2px, 4px 2px;
|
|
223
|
+
background-repeat: repeat-y;
|
|
224
|
+
opacity: 0.6;
|
|
225
|
+
transition: opacity var(--sg-transition-fast);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.sg-dashboard-editor[data-edit-mode='true'] .sg-dashboard-widget:hover .sg-dashboard-widget-header::before {
|
|
229
|
+
opacity: 1;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.sg-dashboard-editor[data-edit-mode='true'] .sg-dashboard-widget-header:active {
|
|
233
|
+
cursor: grabbing;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/* Drop-zone affordance: while the editor is not actively being hovered
|
|
237
|
+
* by a particular widget but a drag is happening, an empty grid cell
|
|
238
|
+
* becomes a candidate target. We use `:focus-within` as a proxy for
|
|
239
|
+
* "interaction in progress" — when a widget is being dragged via
|
|
240
|
+
* keyboard, it lands focus on the editor. The pattern matches the
|
|
241
|
+
* snap grid above so the user's eye doesn't need to refocus. */
|
|
242
|
+
.sg-dashboard-editor[data-edit-mode='true']:focus-within {
|
|
243
|
+
background-image:
|
|
244
|
+
linear-gradient(to right, var(--sg-dashboard-editor-drop-zone-border) 1px, transparent 1px),
|
|
245
|
+
linear-gradient(to bottom, var(--sg-dashboard-editor-drop-zone-border) 1px, transparent 1px);
|
|
246
|
+
background-color: var(--sg-dashboard-editor-drop-zone-bg);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.sg-dashboard-editor-resize-handle {
|
|
250
|
+
position: absolute;
|
|
251
|
+
right: 0;
|
|
252
|
+
bottom: 0;
|
|
253
|
+
width: 16px;
|
|
254
|
+
height: 16px;
|
|
255
|
+
cursor: nwse-resize;
|
|
256
|
+
opacity: 0.5;
|
|
257
|
+
touch-action: none;
|
|
258
|
+
display: flex;
|
|
259
|
+
align-items: flex-end;
|
|
260
|
+
justify-content: flex-end;
|
|
261
|
+
padding: 2px;
|
|
262
|
+
border-radius: var(--sg-border-radius-sm) 0 var(--sg-border-radius) 0;
|
|
263
|
+
transition:
|
|
264
|
+
opacity var(--sg-transition-fast),
|
|
265
|
+
background-color var(--sg-transition-fast);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.sg-dashboard-editor-resize-handle-grip {
|
|
269
|
+
display: block;
|
|
270
|
+
width: 10px;
|
|
271
|
+
height: 10px;
|
|
272
|
+
background-image:
|
|
273
|
+
linear-gradient(135deg, transparent 0 60%, var(--sg-color-border-secondary) 60% 70%, transparent 70% 80%, var(--sg-color-border-secondary) 80% 90%, transparent 90%);
|
|
274
|
+
pointer-events: none;
|
|
275
|
+
transition: background-image var(--sg-transition-fast);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.sg-dashboard-editor-resize-handle:hover,
|
|
279
|
+
.sg-dashboard-editor-resize-handle:focus-visible,
|
|
280
|
+
.sg-dashboard-widget:hover .sg-dashboard-editor-resize-handle {
|
|
281
|
+
opacity: 1;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.sg-dashboard-editor-resize-handle:hover {
|
|
285
|
+
background: var(--sg-color-primary-bg);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.sg-dashboard-editor-resize-handle:hover .sg-dashboard-editor-resize-handle-grip,
|
|
289
|
+
.sg-dashboard-editor-resize-handle:focus-visible .sg-dashboard-editor-resize-handle-grip {
|
|
290
|
+
/* On hover the grip lines pick up the primary color so the handle
|
|
291
|
+
* reads as "actively armed for resize". */
|
|
292
|
+
background-image:
|
|
293
|
+
linear-gradient(135deg, transparent 0 60%, var(--sg-color-primary) 60% 70%, transparent 70% 80%, var(--sg-color-primary) 80% 90%, transparent 90%);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.sg-dashboard-editor-resize-handle:focus-visible {
|
|
297
|
+
outline: 2px solid var(--sg-color-primary);
|
|
298
|
+
outline-offset: -1px;
|
|
299
|
+
}
|