@nowline/preview-shell 0.4.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/src/styles.ts ADDED
@@ -0,0 +1,293 @@
1
+ // Stylesheet for `mountPreview()`. Uses neutral `--nl-preview-*` CSS
2
+ // custom properties throughout so consumers can re-skin the viewport
3
+ // without forking the package. Sensible defaults baked in so the
4
+ // viewport works out of the box on a blank page.
5
+ //
6
+ // VS Code consumers paste `VSCODE_THEME_BRIDGE_CSS` (below) into their
7
+ // webview to map `--nl-preview-*` to the matching `--vscode-*` tokens
8
+ // — that keeps the viewport in lock-step with the user's workbench
9
+ // theme without having to keep two sets of variables in sync.
10
+
11
+ /**
12
+ * Bridge CSS for VS Code webview consumers. Maps every `--nl-preview-*`
13
+ * token to the matching `--vscode-*` variable so the viewport renders
14
+ * in the active workbench colour theme automatically.
15
+ *
16
+ * Inject as a `<style>` block after the preview-shell stylesheet.
17
+ */
18
+ export const VSCODE_THEME_BRIDGE_CSS = `
19
+ :root {
20
+ --nl-preview-bg: var(--vscode-editor-background, #1e1e1e);
21
+ --nl-preview-fg: var(--vscode-editor-foreground, #d4d4d4);
22
+ --nl-preview-font-family: var(--vscode-font-family, system-ui, sans-serif);
23
+ --nl-preview-font-size: var(--vscode-font-size, 13px);
24
+ --nl-preview-widget-bg: var(--vscode-editorWidget-background, rgba(40,40,40,0.9));
25
+ --nl-preview-widget-border: var(--vscode-editorWidget-border, rgba(255,255,255,0.1));
26
+ --nl-preview-toolbar-hover: var(--vscode-toolbar-hoverBackground, rgba(255,255,255,0.08));
27
+ --nl-preview-toolbar-active: var(--vscode-toolbar-activeBackground, rgba(255,255,255,0.12));
28
+ --nl-preview-list-hover: var(--vscode-list-hoverBackground, rgba(255,255,255,0.04));
29
+ --nl-preview-description: var(--vscode-descriptionForeground, #999);
30
+ --nl-preview-error: var(--vscode-editorError-foreground, #f48771);
31
+ --nl-preview-warning: var(--vscode-editorWarning-foreground, #cca700);
32
+ --nl-preview-link: var(--vscode-textLink-foreground, #3794ff);
33
+ --nl-preview-focus: var(--vscode-focusBorder, #007acc);
34
+ --nl-preview-code-bg: var(--vscode-textBlockQuote-background, rgba(255,255,255,0.05));
35
+ --nl-preview-mono: var(--vscode-editor-font-family, monospace);
36
+ }
37
+ `;
38
+
39
+ /**
40
+ * Default stylesheet for the viewport. Provides reasonable defaults
41
+ * for every `--nl-preview-*` token so the viewport works on a blank
42
+ * page; consumers override by re-declaring the variables on a
43
+ * higher-specificity selector.
44
+ */
45
+ export const PREVIEW_SHELL_CSS = `
46
+ :root {
47
+ color-scheme: light dark;
48
+ --nl-preview-bg: #1e1e1e;
49
+ --nl-preview-fg: #d4d4d4;
50
+ --nl-preview-font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
51
+ --nl-preview-font-size: 13px;
52
+ --nl-preview-widget-bg: rgba(40,40,40,0.9);
53
+ --nl-preview-widget-border: rgba(255,255,255,0.1);
54
+ --nl-preview-toolbar-hover: rgba(255,255,255,0.08);
55
+ --nl-preview-toolbar-active: rgba(255,255,255,0.12);
56
+ --nl-preview-list-hover: rgba(255,255,255,0.04);
57
+ --nl-preview-description: #999;
58
+ --nl-preview-error: #f48771;
59
+ --nl-preview-warning: #cca700;
60
+ --nl-preview-link: #3794ff;
61
+ --nl-preview-focus: #007acc;
62
+ --nl-preview-code-bg: rgba(255,255,255,0.05);
63
+ --nl-preview-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
64
+ }
65
+ .nl-preview-root {
66
+ position: relative;
67
+ width: 100%; height: 100%;
68
+ background: var(--nl-preview-bg);
69
+ color: var(--nl-preview-fg);
70
+ font-family: var(--nl-preview-font-family);
71
+ font-size: var(--nl-preview-font-size);
72
+ overflow: hidden;
73
+ }
74
+ .nl-preview-root .viewport {
75
+ position: absolute; inset: 0;
76
+ overflow: auto;
77
+ }
78
+ .nl-preview-root .canvas {
79
+ transform-origin: 0 0;
80
+ will-change: transform;
81
+ }
82
+ .nl-preview-root .canvas svg { display: block; max-width: none; height: auto; }
83
+ .nl-preview-root .canvas.dimmed { opacity: 0.25; pointer-events: none; }
84
+
85
+ /* === Toolbar (top-right) === */
86
+ .nl-preview-root .chrome {
87
+ position: absolute; top: 8px; right: 8px;
88
+ display: flex; gap: 4px;
89
+ transition: opacity 200ms ease;
90
+ z-index: 10;
91
+ }
92
+ .nl-preview-root .chrome.faded { opacity: 0.25; }
93
+ .nl-preview-root .chrome:hover { opacity: 1; }
94
+ .nl-preview-root .toolbar {
95
+ display: flex; align-items: center; gap: 2px;
96
+ padding: 2px;
97
+ background: var(--nl-preview-widget-bg);
98
+ border: 1px solid var(--nl-preview-widget-border);
99
+ border-radius: 6px;
100
+ box-shadow: 0 2px 8px rgba(0,0,0,0.2);
101
+ }
102
+ .nl-preview-root .toolbar .sep {
103
+ width: 1px; height: 20px;
104
+ background: var(--nl-preview-widget-border);
105
+ margin: 0 4px;
106
+ }
107
+ .nl-preview-root .btn {
108
+ appearance: none;
109
+ background: transparent;
110
+ color: inherit;
111
+ border: 0;
112
+ padding: 4px 8px;
113
+ border-radius: 4px;
114
+ font-family: inherit;
115
+ font-size: inherit;
116
+ cursor: pointer;
117
+ line-height: 1;
118
+ min-width: 28px;
119
+ }
120
+ .nl-preview-root .btn:hover { background: var(--nl-preview-toolbar-hover); }
121
+ .nl-preview-root .btn:active { background: var(--nl-preview-toolbar-active); }
122
+ .nl-preview-root .btn.zoom-label { min-width: 48px; font-variant-numeric: tabular-nums; }
123
+ .nl-preview-root .btn.glyph { font-size: 16px; line-height: 1; padding: 4px 6px; }
124
+ .nl-preview-root .dropdown { position: relative; }
125
+ .nl-preview-root .menu {
126
+ position: absolute; top: 100%; right: 0; margin-top: 4px;
127
+ list-style: none; padding: 4px; min-width: 140px;
128
+ background: var(--nl-preview-widget-bg);
129
+ border: 1px solid var(--nl-preview-widget-border);
130
+ border-radius: 6px;
131
+ box-shadow: 0 4px 12px rgba(0,0,0,0.3);
132
+ z-index: 20;
133
+ }
134
+ .nl-preview-root .menu li { padding: 0; }
135
+ .nl-preview-root .menu .btn {
136
+ display: block; width: 100%; text-align: left;
137
+ padding: 6px 10px;
138
+ }
139
+ .nl-preview-root .menu li.menu-section {
140
+ padding: 4px 10px 2px;
141
+ font-size: 0.85em;
142
+ text-transform: uppercase;
143
+ letter-spacing: 0.05em;
144
+ color: var(--nl-preview-description);
145
+ }
146
+ .nl-preview-root .menu li.menu-divider {
147
+ height: 1px;
148
+ margin: 4px 6px;
149
+ background: var(--nl-preview-widget-border);
150
+ }
151
+ .nl-preview-root .menu .btn.view-opt {
152
+ padding-left: 22px;
153
+ position: relative;
154
+ }
155
+ .nl-preview-root .menu .btn.view-opt[data-active="true"]::before {
156
+ content: '\\2713';
157
+ position: absolute;
158
+ left: 8px;
159
+ }
160
+
161
+ /* === Minimap === */
162
+ .nl-preview-root .minimap {
163
+ position: absolute; bottom: 12px; right: 12px;
164
+ width: 160px; max-height: 120px;
165
+ background: var(--nl-preview-widget-bg);
166
+ border: 1px solid var(--nl-preview-widget-border);
167
+ border-radius: 4px;
168
+ overflow: hidden;
169
+ box-shadow: 0 2px 8px rgba(0,0,0,0.2);
170
+ z-index: 8;
171
+ }
172
+ .nl-preview-root .minimap.hidden { display: none; }
173
+ .nl-preview-root .minimap-canvas {
174
+ display: block;
175
+ cursor: pointer;
176
+ user-select: none;
177
+ }
178
+ .nl-preview-root .minimap-canvas svg {
179
+ display: block;
180
+ width: 100%;
181
+ height: auto;
182
+ pointer-events: none;
183
+ }
184
+ .nl-preview-root .minimap-rect {
185
+ position: absolute;
186
+ border: 2px solid var(--nl-preview-focus);
187
+ background-color: color-mix(in srgb, var(--nl-preview-focus) 18%, transparent);
188
+ pointer-events: none;
189
+ box-sizing: border-box;
190
+ }
191
+ .nl-preview-root .minimap-close {
192
+ position: absolute; top: 2px; right: 2px;
193
+ width: 18px; height: 18px; padding: 0;
194
+ border-radius: 4px;
195
+ line-height: 1;
196
+ font-size: 12px;
197
+ z-index: 1;
198
+ }
199
+
200
+ /* === Diagnostics overlay === */
201
+ .nl-preview-root .diagnostics {
202
+ position: absolute; left: 0; right: 0; bottom: 0;
203
+ max-height: 60%;
204
+ background: var(--nl-preview-widget-bg);
205
+ border-top: 1px solid var(--nl-preview-widget-border);
206
+ overflow: auto;
207
+ z-index: 12;
208
+ padding: 0;
209
+ display: none;
210
+ }
211
+ .nl-preview-root .diagnostics.show { display: block; }
212
+ .nl-preview-root .diag-header {
213
+ position: sticky; top: 0;
214
+ display: flex; align-items: center; justify-content: space-between;
215
+ padding: 6px 12px;
216
+ background: inherit;
217
+ border-bottom: 1px solid var(--nl-preview-widget-border);
218
+ font-weight: 600;
219
+ }
220
+ .nl-preview-root .diag-summary {
221
+ color: var(--nl-preview-error);
222
+ }
223
+ .nl-preview-root .diag-summary.warn-only {
224
+ color: var(--nl-preview-warning);
225
+ }
226
+ .nl-preview-root .diag-summary.clean {
227
+ color: var(--nl-preview-description);
228
+ font-weight: normal;
229
+ }
230
+ .nl-preview-root .open-problems {
231
+ color: var(--nl-preview-link);
232
+ cursor: pointer;
233
+ text-decoration: none;
234
+ font-weight: normal;
235
+ }
236
+ .nl-preview-root .open-problems:hover { text-decoration: underline; }
237
+ .nl-preview-root .diag-table {
238
+ width: 100%;
239
+ border-collapse: collapse;
240
+ }
241
+ .nl-preview-root .diag-table tr {
242
+ cursor: pointer;
243
+ border-bottom: 1px solid var(--nl-preview-widget-border);
244
+ }
245
+ .nl-preview-root .diag-table tr:hover {
246
+ background: var(--nl-preview-list-hover);
247
+ }
248
+ .nl-preview-root .diag-table td {
249
+ padding: 6px 8px;
250
+ vertical-align: top;
251
+ }
252
+ .nl-preview-root .sev-cell {
253
+ width: 24px; text-align: center;
254
+ font-weight: bold;
255
+ }
256
+ .nl-preview-root .sev-error { color: var(--nl-preview-error); }
257
+ .nl-preview-root .sev-warning { color: var(--nl-preview-warning); }
258
+ .nl-preview-root .loc-cell {
259
+ white-space: nowrap;
260
+ color: var(--nl-preview-description);
261
+ font-variant-numeric: tabular-nums;
262
+ width: 90px;
263
+ }
264
+ .nl-preview-root .code-cell {
265
+ white-space: nowrap;
266
+ width: 1%;
267
+ }
268
+ .nl-preview-root .code-pill {
269
+ display: inline-block;
270
+ padding: 1px 6px;
271
+ border-radius: 3px;
272
+ background: var(--nl-preview-code-bg);
273
+ color: var(--nl-preview-description);
274
+ font-family: var(--nl-preview-mono);
275
+ font-size: 0.9em;
276
+ }
277
+ .nl-preview-root .msg-cell { word-break: break-word; }
278
+ .nl-preview-root .suggestion {
279
+ display: block; margin-top: 2px;
280
+ color: var(--nl-preview-description);
281
+ font-style: italic;
282
+ font-size: 0.95em;
283
+ }
284
+
285
+ /* === Empty state === */
286
+ .nl-preview-root .empty {
287
+ position: absolute; inset: 0;
288
+ display: flex; align-items: center; justify-content: center;
289
+ color: var(--nl-preview-description);
290
+ pointer-events: none;
291
+ }
292
+ .nl-preview-root .empty.hidden { display: none; }
293
+ `;