@svadmin/editor 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.
@@ -0,0 +1,697 @@
1
+ /* ─── @svadmin/editor — ProseMirror & Custom Styles ──────────────── */
2
+
3
+ /* Base editor container */
4
+ .svadmin-editor {
5
+ --editor-border: hsl(var(--border));
6
+ --editor-bg: hsl(var(--background));
7
+ --editor-fg: hsl(var(--foreground));
8
+ --editor-muted: hsl(var(--muted-foreground));
9
+ --editor-primary: hsl(var(--primary));
10
+ --editor-primary-fg: hsl(var(--primary-foreground));
11
+ --editor-ring: hsl(var(--ring));
12
+ --editor-radius: var(--radius, 0.5rem);
13
+
14
+ position: relative;
15
+ border: 1px solid var(--editor-border);
16
+ border-radius: var(--editor-radius);
17
+ background: var(--editor-bg);
18
+ overflow: hidden;
19
+ transition: border-color 0.2s ease, box-shadow 0.2s ease;
20
+ }
21
+
22
+ .svadmin-editor:focus-within {
23
+ border-color: var(--editor-ring);
24
+ box-shadow: 0 0 0 2px hsl(var(--ring) / 0.15);
25
+ }
26
+
27
+ /* ─── Toolbar ─────────────────────────────────────────────────── */
28
+
29
+ .svadmin-editor-toolbar {
30
+ display: flex;
31
+ flex-wrap: wrap;
32
+ align-items: center;
33
+ gap: 1px;
34
+ padding: 4px 6px;
35
+ border-bottom: 1px solid var(--editor-border);
36
+ background: hsl(var(--muted) / 0.3);
37
+ min-height: 40px;
38
+ }
39
+
40
+ .svadmin-toolbar-group {
41
+ display: flex;
42
+ align-items: center;
43
+ gap: 1px;
44
+ }
45
+
46
+ .svadmin-toolbar-group + .svadmin-toolbar-group::before {
47
+ content: '';
48
+ display: block;
49
+ width: 1px;
50
+ height: 20px;
51
+ margin: 0 4px;
52
+ background: var(--editor-border);
53
+ opacity: 0.6;
54
+ }
55
+
56
+ .svadmin-toolbar-btn {
57
+ display: inline-flex;
58
+ align-items: center;
59
+ justify-content: center;
60
+ width: 32px;
61
+ height: 32px;
62
+ border: none;
63
+ border-radius: 6px;
64
+ background: transparent;
65
+ color: var(--editor-fg);
66
+ cursor: pointer;
67
+ transition: all 0.15s ease;
68
+ position: relative;
69
+ flex-shrink: 0;
70
+ }
71
+
72
+ .svadmin-toolbar-btn:hover {
73
+ background: hsl(var(--muted) / 0.7);
74
+ }
75
+
76
+ .svadmin-toolbar-btn:active {
77
+ transform: scale(0.95);
78
+ }
79
+
80
+ .svadmin-toolbar-btn[data-active="true"] {
81
+ background: hsl(var(--primary) / 0.1);
82
+ color: var(--editor-primary);
83
+ }
84
+
85
+ .svadmin-toolbar-btn[data-active="true"]::after {
86
+ content: '';
87
+ position: absolute;
88
+ bottom: 2px;
89
+ left: 50%;
90
+ transform: translateX(-50%);
91
+ width: 12px;
92
+ height: 2px;
93
+ border-radius: 1px;
94
+ background: var(--editor-primary);
95
+ }
96
+
97
+ .svadmin-toolbar-btn:disabled {
98
+ opacity: 0.4;
99
+ cursor: not-allowed;
100
+ }
101
+
102
+ .svadmin-toolbar-btn svg {
103
+ width: 16px;
104
+ height: 16px;
105
+ }
106
+
107
+ /* Toolbar select */
108
+ .svadmin-toolbar-select {
109
+ height: 32px;
110
+ padding: 0 8px;
111
+ padding-right: 24px;
112
+ border: none;
113
+ border-radius: 6px;
114
+ background: transparent;
115
+ color: var(--editor-fg);
116
+ font-size: 13px;
117
+ cursor: pointer;
118
+ appearance: none;
119
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
120
+ background-repeat: no-repeat;
121
+ background-position: right 6px center;
122
+ transition: background-color 0.15s ease;
123
+ }
124
+
125
+ .svadmin-toolbar-select:hover {
126
+ background-color: hsl(var(--muted) / 0.7);
127
+ }
128
+
129
+ .svadmin-toolbar-select:focus {
130
+ outline: none;
131
+ background-color: hsl(var(--muted) / 0.7);
132
+ }
133
+
134
+ /* ─── Editor Content Area ─────────────────────────────────────── */
135
+
136
+ .svadmin-editor-content {
137
+ padding: 16px 20px;
138
+ min-height: 200px;
139
+ max-height: 600px;
140
+ overflow-y: auto;
141
+ }
142
+
143
+ .svadmin-editor-content .tiptap {
144
+ outline: none;
145
+ min-height: 180px;
146
+ font-size: 15px;
147
+ line-height: 1.7;
148
+ color: var(--editor-fg);
149
+ }
150
+
151
+ .svadmin-editor-content .tiptap > * + * {
152
+ margin-top: 0.75em;
153
+ }
154
+
155
+ /* Placeholder */
156
+ .svadmin-editor-content .tiptap p.is-editor-empty:first-child::before {
157
+ content: attr(data-placeholder);
158
+ float: left;
159
+ color: var(--editor-muted);
160
+ pointer-events: none;
161
+ height: 0;
162
+ font-style: italic;
163
+ opacity: 0.6;
164
+ }
165
+
166
+ /* ─── Typography ──────────────────────────────────────────────── */
167
+
168
+ .svadmin-editor-content .tiptap h1 {
169
+ font-size: 2em;
170
+ font-weight: 700;
171
+ line-height: 1.2;
172
+ margin-top: 1em;
173
+ margin-bottom: 0.4em;
174
+ }
175
+
176
+ .svadmin-editor-content .tiptap h2 {
177
+ font-size: 1.5em;
178
+ font-weight: 650;
179
+ line-height: 1.3;
180
+ margin-top: 0.8em;
181
+ margin-bottom: 0.3em;
182
+ }
183
+
184
+ .svadmin-editor-content .tiptap h3 {
185
+ font-size: 1.25em;
186
+ font-weight: 600;
187
+ line-height: 1.35;
188
+ margin-top: 0.6em;
189
+ margin-bottom: 0.25em;
190
+ }
191
+
192
+ .svadmin-editor-content .tiptap h4 {
193
+ font-size: 1.1em;
194
+ font-weight: 600;
195
+ line-height: 1.4;
196
+ }
197
+
198
+ .svadmin-editor-content .tiptap p {
199
+ margin: 0;
200
+ }
201
+
202
+ .svadmin-editor-content .tiptap strong {
203
+ font-weight: 650;
204
+ }
205
+
206
+ .svadmin-editor-content .tiptap em {
207
+ font-style: italic;
208
+ }
209
+
210
+ .svadmin-editor-content .tiptap u {
211
+ text-decoration: underline;
212
+ text-underline-offset: 2px;
213
+ }
214
+
215
+ .svadmin-editor-content .tiptap s {
216
+ text-decoration: line-through;
217
+ }
218
+
219
+ .svadmin-editor-content .tiptap sub {
220
+ vertical-align: sub;
221
+ font-size: 0.75em;
222
+ }
223
+
224
+ .svadmin-editor-content .tiptap sup {
225
+ vertical-align: super;
226
+ font-size: 0.75em;
227
+ }
228
+
229
+ /* ─── Links ───────────────────────────────────────────────────── */
230
+
231
+ .svadmin-editor-content .tiptap a {
232
+ color: var(--editor-primary);
233
+ text-decoration: underline;
234
+ text-underline-offset: 2px;
235
+ cursor: pointer;
236
+ transition: opacity 0.15s;
237
+ }
238
+
239
+ .svadmin-editor-content .tiptap a:hover {
240
+ opacity: 0.8;
241
+ }
242
+
243
+ /* ─── Lists ───────────────────────────────────────────────────── */
244
+
245
+ .svadmin-editor-content .tiptap ul {
246
+ list-style-type: disc;
247
+ padding-left: 1.5em;
248
+ }
249
+
250
+ .svadmin-editor-content .tiptap ol {
251
+ list-style-type: decimal;
252
+ padding-left: 1.5em;
253
+ }
254
+
255
+ .svadmin-editor-content .tiptap li {
256
+ margin: 0.2em 0;
257
+ }
258
+
259
+ .svadmin-editor-content .tiptap li > p {
260
+ margin: 0;
261
+ }
262
+
263
+ /* Task lists */
264
+ .svadmin-editor-content .tiptap ul[data-type="taskList"] {
265
+ list-style: none;
266
+ padding-left: 0;
267
+ }
268
+
269
+ .svadmin-editor-content .tiptap ul[data-type="taskList"] li {
270
+ display: flex;
271
+ align-items: flex-start;
272
+ gap: 8px;
273
+ }
274
+
275
+ .svadmin-editor-content .tiptap ul[data-type="taskList"] li > label {
276
+ flex-shrink: 0;
277
+ margin-top: 3px;
278
+ }
279
+
280
+ .svadmin-editor-content .tiptap ul[data-type="taskList"] li > label input[type="checkbox"] {
281
+ width: 16px;
282
+ height: 16px;
283
+ accent-color: var(--editor-primary);
284
+ cursor: pointer;
285
+ border-radius: 3px;
286
+ }
287
+
288
+ .svadmin-editor-content .tiptap ul[data-type="taskList"] li[data-checked="true"] > div > p {
289
+ text-decoration: line-through;
290
+ opacity: 0.5;
291
+ }
292
+
293
+ /* ─── Blockquote ──────────────────────────────────────────────── */
294
+
295
+ .svadmin-editor-content .tiptap blockquote {
296
+ border-left: 3px solid var(--editor-primary);
297
+ padding-left: 1em;
298
+ margin-left: 0;
299
+ color: var(--editor-muted);
300
+ font-style: italic;
301
+ }
302
+
303
+ /* ─── Code ────────────────────────────────────────────────────── */
304
+
305
+ .svadmin-editor-content .tiptap code {
306
+ background: hsl(var(--muted) / 0.5);
307
+ color: hsl(var(--destructive, 0 84% 60%));
308
+ padding: 2px 6px;
309
+ border-radius: 4px;
310
+ font-size: 0.875em;
311
+ font-family: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace;
312
+ }
313
+
314
+ .svadmin-editor-content .tiptap pre {
315
+ background: hsl(var(--card));
316
+ border: 1px solid var(--editor-border);
317
+ border-radius: 8px;
318
+ padding: 16px 20px;
319
+ overflow-x: auto;
320
+ font-family: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace;
321
+ font-size: 0.875em;
322
+ line-height: 1.6;
323
+ }
324
+
325
+ .svadmin-editor-content .tiptap pre code {
326
+ background: none;
327
+ color: inherit;
328
+ padding: 0;
329
+ border-radius: 0;
330
+ font-size: inherit;
331
+ }
332
+
333
+ /* ─── Horizontal Rule ─────────────────────────────────────────── */
334
+
335
+ .svadmin-editor-content .tiptap hr {
336
+ border: none;
337
+ border-top: 1px solid var(--editor-border);
338
+ margin: 1.5em 0;
339
+ }
340
+
341
+ /* ─── Images ──────────────────────────────────────────────────── */
342
+
343
+ .svadmin-editor-content .tiptap img {
344
+ max-width: 100%;
345
+ height: auto;
346
+ border-radius: 8px;
347
+ margin: 0.5em 0;
348
+ cursor: pointer;
349
+ transition: box-shadow 0.2s ease;
350
+ }
351
+
352
+ .svadmin-editor-content .tiptap img:hover {
353
+ box-shadow: 0 0 0 2px var(--editor-primary);
354
+ }
355
+
356
+ .svadmin-editor-content .tiptap img.ProseMirror-selectednode {
357
+ box-shadow: 0 0 0 2px var(--editor-primary);
358
+ }
359
+
360
+ /* ─── Tables ──────────────────────────────────────────────────── */
361
+
362
+ .svadmin-editor-content .tiptap table {
363
+ border-collapse: collapse;
364
+ width: 100%;
365
+ margin: 0.5em 0;
366
+ overflow: hidden;
367
+ border-radius: 6px;
368
+ border: 1px solid var(--editor-border);
369
+ }
370
+
371
+ .svadmin-editor-content .tiptap table td,
372
+ .svadmin-editor-content .tiptap table th {
373
+ border: 1px solid var(--editor-border);
374
+ padding: 8px 12px;
375
+ min-width: 80px;
376
+ vertical-align: top;
377
+ position: relative;
378
+ }
379
+
380
+ .svadmin-editor-content .tiptap table th {
381
+ background: hsl(var(--muted) / 0.4);
382
+ font-weight: 600;
383
+ text-align: left;
384
+ }
385
+
386
+ .svadmin-editor-content .tiptap table td > p,
387
+ .svadmin-editor-content .tiptap table th > p {
388
+ margin: 0;
389
+ }
390
+
391
+ .svadmin-editor-content .tiptap table .selectedCell {
392
+ background: hsl(var(--primary) / 0.08);
393
+ }
394
+
395
+ .svadmin-editor-content .tiptap table .selectedCell::after {
396
+ content: '';
397
+ position: absolute;
398
+ inset: 0;
399
+ border: 2px solid hsl(var(--primary) / 0.3);
400
+ pointer-events: none;
401
+ }
402
+
403
+ /* Table column resize handle */
404
+ .svadmin-editor-content .tiptap .column-resize-handle {
405
+ position: absolute;
406
+ right: -2px;
407
+ top: 0;
408
+ bottom: -2px;
409
+ width: 4px;
410
+ background: var(--editor-primary);
411
+ cursor: col-resize;
412
+ z-index: 10;
413
+ }
414
+
415
+ .svadmin-editor-content .tiptap .tableWrapper {
416
+ overflow-x: auto;
417
+ margin: 0.5em 0;
418
+ }
419
+
420
+ /* ─── Highlight ───────────────────────────────────────────────── */
421
+
422
+ .svadmin-editor-content .tiptap mark {
423
+ background: hsl(50 100% 70% / 0.5);
424
+ padding: 1px 2px;
425
+ border-radius: 2px;
426
+ }
427
+
428
+ /* ─── Text alignment ──────────────────────────────────────────── */
429
+
430
+ .svadmin-editor-content .tiptap [style*="text-align: center"] {
431
+ text-align: center;
432
+ }
433
+
434
+ .svadmin-editor-content .tiptap [style*="text-align: right"] {
435
+ text-align: right;
436
+ }
437
+
438
+ .svadmin-editor-content .tiptap [style*="text-align: justify"] {
439
+ text-align: justify;
440
+ }
441
+
442
+ /* ─── Bubble Menu ─────────────────────────────────────────────── */
443
+
444
+ .svadmin-bubble-menu {
445
+ display: flex;
446
+ align-items: center;
447
+ gap: 2px;
448
+ padding: 4px 6px;
449
+ background: hsl(var(--popover));
450
+ border: 1px solid var(--editor-border);
451
+ border-radius: 8px;
452
+ box-shadow:
453
+ 0 4px 6px -1px hsl(0 0% 0% / 0.1),
454
+ 0 2px 4px -2px hsl(0 0% 0% / 0.1);
455
+ z-index: 50;
456
+ animation: svadmin-menu-in 0.15s ease-out;
457
+ }
458
+
459
+ .svadmin-bubble-menu .svadmin-toolbar-btn {
460
+ width: 30px;
461
+ height: 30px;
462
+ }
463
+
464
+ .svadmin-bubble-menu .svadmin-toolbar-btn svg {
465
+ width: 14px;
466
+ height: 14px;
467
+ }
468
+
469
+ /* ─── Floating Menu ───────────────────────────────────────────── */
470
+
471
+ .svadmin-floating-menu {
472
+ display: flex;
473
+ align-items: center;
474
+ gap: 2px;
475
+ padding: 4px 6px;
476
+ background: hsl(var(--popover));
477
+ border: 1px solid var(--editor-border);
478
+ border-radius: 8px;
479
+ box-shadow:
480
+ 0 4px 6px -1px hsl(0 0% 0% / 0.1),
481
+ 0 2px 4px -2px hsl(0 0% 0% / 0.1);
482
+ z-index: 50;
483
+ animation: svadmin-menu-in 0.15s ease-out;
484
+ }
485
+
486
+ .svadmin-floating-menu .svadmin-toolbar-btn {
487
+ width: 30px;
488
+ height: 30px;
489
+ }
490
+
491
+ .svadmin-floating-menu .svadmin-toolbar-btn svg {
492
+ width: 14px;
493
+ height: 14px;
494
+ }
495
+
496
+ /* ─── Slash Command Menu ──────────────────────────────────────── */
497
+
498
+ .svadmin-slash-menu {
499
+ position: absolute;
500
+ min-width: 220px;
501
+ max-height: 320px;
502
+ overflow-y: auto;
503
+ background: hsl(var(--popover));
504
+ border: 1px solid var(--editor-border);
505
+ border-radius: 8px;
506
+ box-shadow:
507
+ 0 10px 15px -3px hsl(0 0% 0% / 0.1),
508
+ 0 4px 6px -4px hsl(0 0% 0% / 0.1);
509
+ padding: 6px;
510
+ z-index: 100;
511
+ animation: svadmin-menu-in 0.15s ease-out;
512
+ }
513
+
514
+ .svadmin-slash-menu-item {
515
+ display: flex;
516
+ align-items: center;
517
+ gap: 10px;
518
+ width: 100%;
519
+ padding: 8px 10px;
520
+ border: none;
521
+ border-radius: 6px;
522
+ background: transparent;
523
+ color: var(--editor-fg);
524
+ font-size: 13px;
525
+ cursor: pointer;
526
+ transition: background-color 0.1s ease;
527
+ text-align: left;
528
+ }
529
+
530
+ .svadmin-slash-menu-item:hover,
531
+ .svadmin-slash-menu-item[data-selected="true"] {
532
+ background: hsl(var(--muted) / 0.5);
533
+ }
534
+
535
+ .svadmin-slash-menu-item-icon {
536
+ display: flex;
537
+ align-items: center;
538
+ justify-content: center;
539
+ width: 28px;
540
+ height: 28px;
541
+ border-radius: 6px;
542
+ background: hsl(var(--muted) / 0.5);
543
+ flex-shrink: 0;
544
+ }
545
+
546
+ .svadmin-slash-menu-item-icon svg {
547
+ width: 14px;
548
+ height: 14px;
549
+ }
550
+
551
+ .svadmin-slash-menu-item-label {
552
+ font-weight: 500;
553
+ }
554
+
555
+ .svadmin-slash-menu-item-desc {
556
+ font-size: 11px;
557
+ color: var(--editor-muted);
558
+ }
559
+
560
+ .svadmin-slash-menu-group {
561
+ font-size: 11px;
562
+ font-weight: 600;
563
+ text-transform: uppercase;
564
+ letter-spacing: 0.05em;
565
+ color: var(--editor-muted);
566
+ padding: 8px 10px 4px;
567
+ }
568
+
569
+ /* ─── Color picker ────────────────────────────────────────────── */
570
+
571
+ .svadmin-color-picker {
572
+ padding: 8px;
573
+ background: hsl(var(--popover));
574
+ border: 1px solid var(--editor-border);
575
+ border-radius: 8px;
576
+ box-shadow:
577
+ 0 4px 6px -1px hsl(0 0% 0% / 0.1),
578
+ 0 2px 4px -2px hsl(0 0% 0% / 0.1);
579
+ z-index: 50;
580
+ animation: svadmin-menu-in 0.15s ease-out;
581
+ }
582
+
583
+ .svadmin-color-grid {
584
+ display: grid;
585
+ grid-template-columns: repeat(8, 1fr);
586
+ gap: 3px;
587
+ }
588
+
589
+ .svadmin-color-swatch {
590
+ width: 24px;
591
+ height: 24px;
592
+ border-radius: 4px;
593
+ border: 1px solid hsl(0 0% 0% / 0.1);
594
+ cursor: pointer;
595
+ transition: transform 0.1s ease, box-shadow 0.1s ease;
596
+ }
597
+
598
+ .svadmin-color-swatch:hover {
599
+ transform: scale(1.2);
600
+ box-shadow: 0 0 0 2px var(--editor-primary);
601
+ z-index: 1;
602
+ }
603
+
604
+ /* ─── Link popover ────────────────────────────────────────────── */
605
+
606
+ .svadmin-link-popover {
607
+ display: flex;
608
+ align-items: center;
609
+ gap: 6px;
610
+ padding: 6px 8px;
611
+ background: hsl(var(--popover));
612
+ border: 1px solid var(--editor-border);
613
+ border-radius: 8px;
614
+ box-shadow:
615
+ 0 4px 6px -1px hsl(0 0% 0% / 0.1),
616
+ 0 2px 4px -2px hsl(0 0% 0% / 0.1);
617
+ z-index: 50;
618
+ animation: svadmin-menu-in 0.15s ease-out;
619
+ }
620
+
621
+ .svadmin-link-input {
622
+ height: 30px;
623
+ padding: 0 8px;
624
+ border: 1px solid var(--editor-border);
625
+ border-radius: 6px;
626
+ background: var(--editor-bg);
627
+ color: var(--editor-fg);
628
+ font-size: 13px;
629
+ min-width: 240px;
630
+ outline: none;
631
+ transition: border-color 0.15s ease;
632
+ }
633
+
634
+ .svadmin-link-input:focus {
635
+ border-color: var(--editor-ring);
636
+ }
637
+
638
+ /* ─── Footer / Status bar ─────────────────────────────────────── */
639
+
640
+ .svadmin-editor-footer {
641
+ display: flex;
642
+ align-items: center;
643
+ justify-content: flex-end;
644
+ gap: 12px;
645
+ padding: 4px 12px;
646
+ border-top: 1px solid var(--editor-border);
647
+ background: hsl(var(--muted) / 0.2);
648
+ font-size: 11px;
649
+ color: var(--editor-muted);
650
+ }
651
+
652
+ /* ─── Animations ──────────────────────────────────────────────── */
653
+
654
+ @keyframes svadmin-menu-in {
655
+ from {
656
+ opacity: 0;
657
+ transform: translateY(-4px) scale(0.98);
658
+ }
659
+ to {
660
+ opacity: 1;
661
+ transform: translateY(0) scale(1);
662
+ }
663
+ }
664
+
665
+ /* ─── Drop cursor ─────────────────────────────────────────────── */
666
+
667
+ .svadmin-editor-content .ProseMirror-gapcursor {
668
+ position: relative;
669
+ }
670
+
671
+ .svadmin-editor-content .ProseMirror-gapcursor::after {
672
+ border-top: 1px solid var(--editor-fg);
673
+ }
674
+
675
+ /* Drag handle indicator */
676
+ .svadmin-editor-content .ProseMirror .is-empty::before {
677
+ transition: opacity 0.15s ease;
678
+ }
679
+
680
+ /* ─── Scrollbar styling ───────────────────────────────────────── */
681
+
682
+ .svadmin-editor-content::-webkit-scrollbar {
683
+ width: 6px;
684
+ }
685
+
686
+ .svadmin-editor-content::-webkit-scrollbar-track {
687
+ background: transparent;
688
+ }
689
+
690
+ .svadmin-editor-content::-webkit-scrollbar-thumb {
691
+ background: hsl(var(--muted-foreground) / 0.3);
692
+ border-radius: 3px;
693
+ }
694
+
695
+ .svadmin-editor-content::-webkit-scrollbar-thumb:hover {
696
+ background: hsl(var(--muted-foreground) / 0.5);
697
+ }