@autumnsgrove/groveengine 0.8.6 → 0.9.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/dist/components/admin/GutterManager.svelte +213 -101
- package/dist/components/admin/MarkdownEditor.svelte +6 -3
- package/dist/components/custom/GutterItem.svelte +8 -2
- package/dist/components/quota/UpgradePrompt.svelte +1 -0
- package/dist/config/domain-blocklist.d.ts +59 -0
- package/dist/config/domain-blocklist.js +731 -0
- package/dist/config/index.d.ts +3 -1
- package/dist/config/index.js +2 -1
- package/dist/config/offensive-blocklist.d.ts +44 -0
- package/dist/config/offensive-blocklist.js +751 -0
- package/dist/config/terrarium.d.ts +109 -0
- package/dist/config/terrarium.js +125 -0
- package/dist/styles/tokens.css +90 -0
- package/dist/types/dom-to-image-more.d.ts +39 -0
- package/dist/ui/components/chrome/Footer.svelte +137 -0
- package/dist/ui/components/chrome/Footer.svelte.d.ts +11 -0
- package/dist/ui/components/chrome/FooterMinimal.svelte +75 -0
- package/dist/ui/components/chrome/FooterMinimal.svelte.d.ts +10 -0
- package/dist/ui/components/chrome/Header.svelte +113 -0
- package/dist/ui/components/chrome/Header.svelte.d.ts +11 -0
- package/dist/ui/components/chrome/HeaderMinimal.svelte +68 -0
- package/dist/ui/components/chrome/HeaderMinimal.svelte.d.ts +9 -0
- package/dist/ui/components/chrome/MobileMenu.svelte +145 -0
- package/dist/ui/components/chrome/MobileMenu.svelte.d.ts +9 -0
- package/dist/ui/components/chrome/ThemeToggle.svelte +34 -0
- package/dist/ui/components/chrome/ThemeToggle.svelte.d.ts +3 -0
- package/dist/ui/components/chrome/defaults.d.ts +6 -0
- package/dist/ui/components/chrome/defaults.js +65 -0
- package/dist/ui/components/chrome/index.d.ts +13 -0
- package/dist/ui/components/chrome/index.js +14 -0
- package/dist/ui/components/chrome/types.d.ts +19 -0
- package/dist/ui/components/chrome/types.js +8 -0
- package/dist/ui/components/content/RoadmapPreview.svelte +2 -1
- package/dist/ui/components/forms/ContentSearch.svelte +406 -0
- package/dist/ui/components/forms/ContentSearch.svelte.d.ts +71 -0
- package/dist/ui/components/forms/filterUtils.d.ts +138 -0
- package/dist/ui/components/forms/filterUtils.js +240 -0
- package/dist/ui/components/forms/index.d.ts +2 -0
- package/dist/ui/components/forms/index.js +5 -1
- package/dist/ui/components/gallery/ImageGallery.svelte +3 -0
- package/dist/ui/components/gallery/Lightbox.svelte +3 -0
- package/dist/ui/components/gallery/ZoomableImage.svelte +1 -0
- package/dist/ui/components/icons/index.d.ts +2 -1
- package/dist/ui/components/icons/index.js +14 -3
- package/dist/ui/components/icons/lucide.d.ts +213 -0
- package/dist/ui/components/icons/lucide.js +224 -0
- package/dist/ui/components/terrarium/AssetPalette.svelte +207 -0
- package/dist/ui/components/terrarium/AssetPalette.svelte.d.ts +7 -0
- package/dist/ui/components/terrarium/Canvas.svelte +231 -0
- package/dist/ui/components/terrarium/Canvas.svelte.d.ts +14 -0
- package/dist/ui/components/terrarium/ExportDialog.svelte +307 -0
- package/dist/ui/components/terrarium/ExportDialog.svelte.d.ts +18 -0
- package/dist/ui/components/terrarium/PaletteItem.svelte +169 -0
- package/dist/ui/components/terrarium/PaletteItem.svelte.d.ts +9 -0
- package/dist/ui/components/terrarium/PlacedAsset.svelte +222 -0
- package/dist/ui/components/terrarium/PlacedAsset.svelte.d.ts +11 -0
- package/dist/ui/components/terrarium/Terrarium.svelte +266 -0
- package/dist/ui/components/terrarium/Terrarium.svelte.d.ts +3 -0
- package/dist/ui/components/terrarium/Toolbar.svelte +299 -0
- package/dist/ui/components/terrarium/Toolbar.svelte.d.ts +24 -0
- package/dist/ui/components/terrarium/index.d.ts +31 -0
- package/dist/ui/components/terrarium/index.js +33 -0
- package/dist/ui/components/terrarium/terrariumState.svelte.d.ts +45 -0
- package/dist/ui/components/terrarium/terrariumState.svelte.js +291 -0
- package/dist/ui/components/terrarium/types.d.ts +139 -0
- package/dist/ui/components/terrarium/types.js +43 -0
- package/dist/ui/components/terrarium/utils/export.d.ts +48 -0
- package/dist/ui/components/terrarium/utils/export.js +148 -0
- package/dist/ui/components/ui/CollapsibleSection.svelte +2 -0
- package/dist/ui/components/ui/GlassConfirmDialog.svelte +9 -0
- package/dist/ui/components/ui/GlassOverlay.svelte +2 -1
- package/dist/ui/components/ui/Input.svelte +9 -1
- package/dist/ui/components/ui/Input.svelte.d.ts +2 -0
- package/dist/ui/components/ui/Textarea.svelte +9 -1
- package/dist/ui/components/ui/Textarea.svelte.d.ts +2 -0
- package/dist/ui/stores/index.d.ts +6 -0
- package/dist/ui/stores/index.js +6 -0
- package/dist/ui/stores/season.d.ts +14 -0
- package/dist/ui/stores/season.js +65 -0
- package/package.json +27 -4
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import Dialog from "../../ui/components/ui/Dialog.svelte";
|
|
5
5
|
import Select from "../../ui/components/ui/Select.svelte";
|
|
6
6
|
import { toast } from "../../ui/components/ui/toast";
|
|
7
|
+
import { MessageSquare, ImageIcon, Images, Pin, Plus, ChevronUp, ChevronDown, Pencil, X } from "lucide-svelte";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* @typedef {Object} GutterItem
|
|
@@ -122,7 +123,7 @@
|
|
|
122
123
|
/** @param {number} index */
|
|
123
124
|
function deleteItem(index) {
|
|
124
125
|
gutterItems = gutterItems.filter((/** @type {GutterItem} */ _, /** @type {number} */ i) => i !== index);
|
|
125
|
-
toast.success("
|
|
126
|
+
toast.success("Vine removed");
|
|
126
127
|
}
|
|
127
128
|
|
|
128
129
|
/**
|
|
@@ -249,38 +250,38 @@
|
|
|
249
250
|
return "";
|
|
250
251
|
}
|
|
251
252
|
|
|
252
|
-
/** @param {string} type */
|
|
253
|
-
function getTypeIcon(type) {
|
|
254
|
-
switch (type) {
|
|
255
|
-
case "comment":
|
|
256
|
-
return "💬";
|
|
257
|
-
case "photo":
|
|
258
|
-
return "🖼️";
|
|
259
|
-
case "gallery":
|
|
260
|
-
return "🎞️";
|
|
261
|
-
default:
|
|
262
|
-
return "📌";
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
253
|
</script>
|
|
266
254
|
|
|
267
|
-
<div class="
|
|
268
|
-
<div class="
|
|
269
|
-
<h3>
|
|
270
|
-
<button class="add-btn" onclick={openAddModal}
|
|
255
|
+
<div class="vines-manager">
|
|
256
|
+
<div class="vines-header">
|
|
257
|
+
<h3>Vines</h3>
|
|
258
|
+
<button class="add-btn" onclick={openAddModal}>
|
|
259
|
+
<Plus class="btn-icon" />
|
|
260
|
+
<span>Add Item</span>
|
|
261
|
+
</button>
|
|
271
262
|
</div>
|
|
272
263
|
|
|
273
264
|
{#if gutterItems.length === 0}
|
|
274
265
|
<div class="empty-state">
|
|
275
|
-
<p>No
|
|
266
|
+
<p>No vines yet.</p>
|
|
276
267
|
<p class="hint">Add comments, images, or galleries that appear alongside your content.</p>
|
|
277
268
|
</div>
|
|
278
269
|
{:else}
|
|
279
|
-
<div class="
|
|
270
|
+
<div class="vines-list">
|
|
280
271
|
{#each gutterItems as item, index (index)}
|
|
281
|
-
<div class="
|
|
272
|
+
<div class="vine-item">
|
|
282
273
|
<div class="item-header">
|
|
283
|
-
<span class="item-type">
|
|
274
|
+
<span class="item-type">
|
|
275
|
+
{#if item.type === "comment"}
|
|
276
|
+
<MessageSquare class="type-icon" />
|
|
277
|
+
{:else if item.type === "photo"}
|
|
278
|
+
<ImageIcon class="type-icon" />
|
|
279
|
+
{:else if item.type === "gallery"}
|
|
280
|
+
<Images class="type-icon" />
|
|
281
|
+
{:else}
|
|
282
|
+
<Pin class="type-icon" />
|
|
283
|
+
{/if}
|
|
284
|
+
</span>
|
|
284
285
|
<span class="item-anchor" title={item.anchor}>{item.anchor || "No anchor"}</span>
|
|
285
286
|
<div class="item-actions">
|
|
286
287
|
<button
|
|
@@ -288,23 +289,35 @@
|
|
|
288
289
|
onclick={() => moveItem(index, -1)}
|
|
289
290
|
disabled={index === 0}
|
|
290
291
|
title="Move up"
|
|
291
|
-
|
|
292
|
+
aria-label="Move item up"
|
|
293
|
+
>
|
|
294
|
+
<ChevronUp class="action-icon" />
|
|
295
|
+
</button>
|
|
292
296
|
<button
|
|
293
297
|
class="action-btn"
|
|
294
298
|
onclick={() => moveItem(index, 1)}
|
|
295
299
|
disabled={index === gutterItems.length - 1}
|
|
296
300
|
title="Move down"
|
|
297
|
-
|
|
301
|
+
aria-label="Move item down"
|
|
302
|
+
>
|
|
303
|
+
<ChevronDown class="action-icon" />
|
|
304
|
+
</button>
|
|
298
305
|
<button
|
|
299
306
|
class="action-btn"
|
|
300
307
|
onclick={() => openEditModal(index)}
|
|
301
308
|
title="Edit"
|
|
302
|
-
|
|
309
|
+
aria-label="Edit item"
|
|
310
|
+
>
|
|
311
|
+
<Pencil class="action-icon" />
|
|
312
|
+
</button>
|
|
303
313
|
<button
|
|
304
314
|
class="action-btn delete"
|
|
305
315
|
onclick={() => deleteItem(index)}
|
|
306
316
|
title="Delete"
|
|
307
|
-
|
|
317
|
+
aria-label="Delete item"
|
|
318
|
+
>
|
|
319
|
+
<X class="action-icon" />
|
|
320
|
+
</button>
|
|
308
321
|
</div>
|
|
309
322
|
</div>
|
|
310
323
|
<div class="item-preview">{getItemPreview(item)}</div>
|
|
@@ -315,7 +328,7 @@
|
|
|
315
328
|
</div>
|
|
316
329
|
|
|
317
330
|
<!-- Add/Edit Modal -->
|
|
318
|
-
<Dialog bind:open={showAddModal} title={editingIndex !== null ? "Edit
|
|
331
|
+
<Dialog bind:open={showAddModal} title={editingIndex !== null ? "Edit Vine" : "Add Vine"}>
|
|
319
332
|
{#snippet children()}
|
|
320
333
|
<div class="form-group">
|
|
321
334
|
<label for="item-type">Type</label>
|
|
@@ -500,49 +513,71 @@
|
|
|
500
513
|
</Dialog>
|
|
501
514
|
|
|
502
515
|
<style>
|
|
503
|
-
.
|
|
504
|
-
background:
|
|
505
|
-
|
|
506
|
-
border
|
|
516
|
+
.vines-manager {
|
|
517
|
+
background: var(--glass-bg);
|
|
518
|
+
backdrop-filter: blur(12px);
|
|
519
|
+
border: 1px solid var(--grove-overlay-15);
|
|
520
|
+
border-radius: 12px;
|
|
507
521
|
overflow: hidden;
|
|
508
522
|
}
|
|
509
523
|
|
|
510
|
-
.
|
|
524
|
+
.vines-header {
|
|
511
525
|
display: flex;
|
|
512
526
|
justify-content: space-between;
|
|
513
527
|
align-items: center;
|
|
514
|
-
padding: 0.
|
|
515
|
-
background:
|
|
516
|
-
border-bottom: 1px solid
|
|
528
|
+
padding: 0.875rem 1rem;
|
|
529
|
+
background: var(--grove-overlay-5);
|
|
530
|
+
border-bottom: 1px solid var(--grove-border-subtle);
|
|
517
531
|
}
|
|
518
532
|
|
|
519
|
-
.
|
|
533
|
+
.vines-header h3 {
|
|
520
534
|
margin: 0;
|
|
521
|
-
font-size: 0.
|
|
522
|
-
color:
|
|
535
|
+
font-size: 0.95rem;
|
|
536
|
+
color: var(--color-primary);
|
|
523
537
|
font-weight: 600;
|
|
524
538
|
}
|
|
525
539
|
|
|
540
|
+
:global(.dark) .vines-header h3 {
|
|
541
|
+
color: #86efac;
|
|
542
|
+
}
|
|
543
|
+
|
|
526
544
|
.add-btn {
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
545
|
+
display: flex;
|
|
546
|
+
align-items: center;
|
|
547
|
+
gap: 0.35rem;
|
|
548
|
+
padding: 0.4rem 0.75rem;
|
|
549
|
+
background: var(--grove-overlay-10);
|
|
550
|
+
color: var(--color-primary);
|
|
551
|
+
border: 1px solid var(--grove-border);
|
|
552
|
+
border-radius: var(--border-radius-button);
|
|
532
553
|
font-size: 0.8rem;
|
|
554
|
+
font-weight: 500;
|
|
533
555
|
cursor: pointer;
|
|
534
556
|
transition: all 0.15s ease;
|
|
535
557
|
}
|
|
536
558
|
|
|
559
|
+
:global(.dark) .add-btn {
|
|
560
|
+
color: #86efac;
|
|
561
|
+
}
|
|
562
|
+
|
|
537
563
|
.add-btn:hover {
|
|
538
|
-
background:
|
|
539
|
-
color:
|
|
564
|
+
background: var(--grove-overlay-18);
|
|
565
|
+
border-color: var(--grove-border-strong);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
:global(.btn-icon) {
|
|
569
|
+
width: 0.875rem;
|
|
570
|
+
height: 0.875rem;
|
|
540
571
|
}
|
|
541
572
|
|
|
542
573
|
.empty-state {
|
|
543
574
|
padding: 2rem 1rem;
|
|
544
575
|
text-align: center;
|
|
545
|
-
color:
|
|
576
|
+
color: var(--color-text-muted);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
:global(.dark) .empty-state {
|
|
580
|
+
color: var(--grove-text-muted);
|
|
546
581
|
}
|
|
547
582
|
|
|
548
583
|
.empty-state p {
|
|
@@ -551,19 +586,32 @@
|
|
|
551
586
|
|
|
552
587
|
.empty-state .hint {
|
|
553
588
|
font-size: 0.85rem;
|
|
554
|
-
color:
|
|
589
|
+
color: var(--color-text-subtle);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
:global(.dark) .empty-state .hint {
|
|
593
|
+
color: var(--grove-text-subtle);
|
|
555
594
|
}
|
|
556
595
|
|
|
557
|
-
.
|
|
596
|
+
.vines-list {
|
|
558
597
|
padding: 0.5rem;
|
|
559
598
|
}
|
|
560
599
|
|
|
561
|
-
.
|
|
562
|
-
background:
|
|
563
|
-
border: 1px solid
|
|
564
|
-
border-radius:
|
|
565
|
-
padding: 0.
|
|
600
|
+
.vine-item {
|
|
601
|
+
background: var(--glass-bg-medium);
|
|
602
|
+
border: 1px solid var(--grove-border-subtle);
|
|
603
|
+
border-radius: 8px;
|
|
604
|
+
padding: 0.625rem 0.875rem;
|
|
566
605
|
margin-bottom: 0.5rem;
|
|
606
|
+
transition: border-color 0.15s ease;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
.vine-item:hover {
|
|
610
|
+
border-color: var(--grove-overlay-25);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
:global(.dark) .vine-item:hover {
|
|
614
|
+
border-color: var(--grove-overlay-30);
|
|
567
615
|
}
|
|
568
616
|
|
|
569
617
|
.item-header {
|
|
@@ -573,38 +621,70 @@
|
|
|
573
621
|
}
|
|
574
622
|
|
|
575
623
|
.item-type {
|
|
576
|
-
|
|
624
|
+
display: flex;
|
|
625
|
+
align-items: center;
|
|
626
|
+
justify-content: center;
|
|
627
|
+
color: var(--color-primary);
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
:global(.dark) .item-type {
|
|
631
|
+
color: #86efac;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
:global(.type-icon) {
|
|
635
|
+
width: 1rem;
|
|
636
|
+
height: 1rem;
|
|
577
637
|
}
|
|
578
638
|
|
|
579
639
|
.item-anchor {
|
|
580
640
|
flex: 1;
|
|
581
641
|
font-family: monospace;
|
|
582
642
|
font-size: 0.8rem;
|
|
583
|
-
color:
|
|
643
|
+
color: var(--color-text-muted);
|
|
584
644
|
white-space: nowrap;
|
|
585
645
|
overflow: hidden;
|
|
586
646
|
text-overflow: ellipsis;
|
|
587
647
|
}
|
|
588
648
|
|
|
649
|
+
:global(.dark) .item-anchor {
|
|
650
|
+
color: var(--grove-text-strong);
|
|
651
|
+
}
|
|
652
|
+
|
|
589
653
|
.item-actions {
|
|
590
654
|
display: flex;
|
|
591
|
-
gap: 0.
|
|
655
|
+
gap: 0.125rem;
|
|
592
656
|
}
|
|
593
657
|
|
|
594
658
|
.action-btn {
|
|
595
|
-
|
|
659
|
+
display: flex;
|
|
660
|
+
align-items: center;
|
|
661
|
+
justify-content: center;
|
|
662
|
+
padding: 0.25rem;
|
|
596
663
|
background: transparent;
|
|
597
664
|
border: 1px solid transparent;
|
|
598
|
-
color:
|
|
599
|
-
border-radius:
|
|
665
|
+
color: var(--color-text-subtle);
|
|
666
|
+
border-radius: 4px;
|
|
600
667
|
cursor: pointer;
|
|
601
|
-
font-size: 0.85rem;
|
|
602
668
|
transition: all 0.15s ease;
|
|
603
669
|
}
|
|
604
670
|
|
|
671
|
+
:global(.dark) .action-btn {
|
|
672
|
+
color: var(--grove-text-subtle);
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
:global(.action-icon) {
|
|
676
|
+
width: 0.875rem;
|
|
677
|
+
height: 0.875rem;
|
|
678
|
+
}
|
|
679
|
+
|
|
605
680
|
.action-btn:hover:not(:disabled) {
|
|
606
|
-
background:
|
|
607
|
-
color:
|
|
681
|
+
background: var(--grove-overlay-10);
|
|
682
|
+
color: var(--color-primary);
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
:global(.dark) .action-btn:hover:not(:disabled) {
|
|
686
|
+
background: var(--grove-overlay-15);
|
|
687
|
+
color: #86efac;
|
|
608
688
|
}
|
|
609
689
|
|
|
610
690
|
.action-btn:disabled {
|
|
@@ -613,20 +693,29 @@
|
|
|
613
693
|
}
|
|
614
694
|
|
|
615
695
|
.action-btn.delete:hover {
|
|
616
|
-
background: rgba(
|
|
617
|
-
color: #
|
|
696
|
+
background: rgba(239, 68, 68, 0.1);
|
|
697
|
+
color: #ef4444;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
:global(.dark) .action-btn.delete:hover {
|
|
701
|
+
background: rgba(239, 68, 68, 0.15);
|
|
702
|
+
color: #f87171;
|
|
618
703
|
}
|
|
619
704
|
|
|
620
705
|
.item-preview {
|
|
621
706
|
margin-top: 0.35rem;
|
|
622
707
|
font-size: 0.8rem;
|
|
623
|
-
color:
|
|
708
|
+
color: var(--color-text-subtle);
|
|
624
709
|
white-space: nowrap;
|
|
625
710
|
overflow: hidden;
|
|
626
711
|
text-overflow: ellipsis;
|
|
627
712
|
}
|
|
628
713
|
|
|
629
|
-
|
|
714
|
+
:global(.dark) .item-preview {
|
|
715
|
+
color: var(--grove-text-subtle);
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/* Form Styles - These appear in the Dialog component */
|
|
630
719
|
.form-group {
|
|
631
720
|
margin-bottom: 1rem;
|
|
632
721
|
}
|
|
@@ -636,23 +725,23 @@
|
|
|
636
725
|
display: block;
|
|
637
726
|
margin-bottom: 0.4rem;
|
|
638
727
|
font-size: 0.85rem;
|
|
639
|
-
color:
|
|
728
|
+
color: var(--color-text-muted);
|
|
640
729
|
}
|
|
641
730
|
|
|
642
731
|
.form-input {
|
|
643
732
|
width: 100%;
|
|
644
733
|
padding: 0.5rem 0.75rem;
|
|
645
|
-
background:
|
|
646
|
-
border: 1px solid
|
|
647
|
-
border-radius:
|
|
648
|
-
color:
|
|
734
|
+
background: var(--color-bg-secondary);
|
|
735
|
+
border: 1px solid var(--color-border);
|
|
736
|
+
border-radius: var(--border-radius-small);
|
|
737
|
+
color: var(--color-text);
|
|
649
738
|
font-size: 0.9rem;
|
|
650
739
|
font-family: inherit;
|
|
651
740
|
}
|
|
652
741
|
|
|
653
742
|
.form-input:focus {
|
|
654
743
|
outline: none;
|
|
655
|
-
border-color:
|
|
744
|
+
border-color: var(--color-primary);
|
|
656
745
|
}
|
|
657
746
|
|
|
658
747
|
.form-textarea {
|
|
@@ -665,14 +754,14 @@
|
|
|
665
754
|
display: block;
|
|
666
755
|
margin-top: 0.35rem;
|
|
667
756
|
font-size: 0.75rem;
|
|
668
|
-
color:
|
|
757
|
+
color: var(--color-text-subtle);
|
|
669
758
|
}
|
|
670
759
|
|
|
671
760
|
.form-hint code {
|
|
672
|
-
background:
|
|
761
|
+
background: var(--color-bg-secondary);
|
|
673
762
|
padding: 0.1rem 0.3rem;
|
|
674
763
|
border-radius: 2px;
|
|
675
|
-
color:
|
|
764
|
+
color: var(--color-primary);
|
|
676
765
|
}
|
|
677
766
|
|
|
678
767
|
.anchor-input-row,
|
|
@@ -696,31 +785,37 @@
|
|
|
696
785
|
|
|
697
786
|
.anchors-label {
|
|
698
787
|
font-size: 0.75rem;
|
|
699
|
-
color:
|
|
788
|
+
color: var(--color-text-subtle);
|
|
700
789
|
}
|
|
701
790
|
|
|
702
791
|
.anchor-chip {
|
|
703
792
|
padding: 0.2rem 0.5rem;
|
|
704
|
-
background:
|
|
705
|
-
border: 1px solid
|
|
793
|
+
background: var(--grove-overlay-10);
|
|
794
|
+
border: 1px solid var(--grove-border);
|
|
706
795
|
border-radius: 12px;
|
|
707
|
-
color:
|
|
796
|
+
color: var(--color-text-muted);
|
|
708
797
|
font-size: 0.7rem;
|
|
709
798
|
font-family: monospace;
|
|
710
799
|
cursor: pointer;
|
|
800
|
+
transition: all 0.15s ease;
|
|
711
801
|
}
|
|
712
802
|
|
|
713
803
|
.anchor-chip:hover {
|
|
714
|
-
background:
|
|
715
|
-
color:
|
|
804
|
+
background: var(--grove-overlay-20);
|
|
805
|
+
color: var(--color-primary);
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
:global(.dark) .anchor-chip:hover {
|
|
809
|
+
color: #86efac;
|
|
716
810
|
}
|
|
717
811
|
|
|
718
812
|
.image-preview {
|
|
719
813
|
margin-top: 0.5rem;
|
|
720
814
|
max-height: 150px;
|
|
721
815
|
overflow: hidden;
|
|
722
|
-
border-radius:
|
|
723
|
-
background:
|
|
816
|
+
border-radius: 8px;
|
|
817
|
+
background: var(--color-bg-secondary);
|
|
818
|
+
border: 1px solid var(--color-border);
|
|
724
819
|
}
|
|
725
820
|
|
|
726
821
|
.image-preview img {
|
|
@@ -741,10 +836,10 @@
|
|
|
741
836
|
display: flex;
|
|
742
837
|
gap: 0.5rem;
|
|
743
838
|
align-items: center;
|
|
744
|
-
background:
|
|
839
|
+
background: var(--color-bg-secondary);
|
|
745
840
|
padding: 0.5rem;
|
|
746
|
-
border-radius:
|
|
747
|
-
border: 1px solid
|
|
841
|
+
border-radius: 8px;
|
|
842
|
+
border: 1px solid var(--color-border);
|
|
748
843
|
}
|
|
749
844
|
|
|
750
845
|
.gallery-thumb {
|
|
@@ -752,7 +847,7 @@
|
|
|
752
847
|
height: 50px;
|
|
753
848
|
-o-object-fit: cover;
|
|
754
849
|
object-fit: cover;
|
|
755
|
-
border-radius:
|
|
850
|
+
border-radius: 4px;
|
|
756
851
|
}
|
|
757
852
|
|
|
758
853
|
.gallery-image-fields {
|
|
@@ -766,25 +861,37 @@
|
|
|
766
861
|
padding: 0.25rem 0.5rem;
|
|
767
862
|
background: transparent;
|
|
768
863
|
border: none;
|
|
769
|
-
color: #
|
|
864
|
+
color: #ef4444;
|
|
770
865
|
font-size: 1.2rem;
|
|
771
866
|
cursor: pointer;
|
|
867
|
+
transition: color 0.15s ease;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
.remove-btn:hover {
|
|
871
|
+
color: #f87171;
|
|
772
872
|
}
|
|
773
873
|
|
|
774
874
|
.add-image-btn {
|
|
775
875
|
padding: 0.5rem;
|
|
776
876
|
background: transparent;
|
|
777
|
-
border: 1px dashed
|
|
778
|
-
border-radius:
|
|
779
|
-
color:
|
|
877
|
+
border: 1px dashed var(--grove-overlay-30);
|
|
878
|
+
border-radius: 8px;
|
|
879
|
+
color: var(--color-text-muted);
|
|
780
880
|
cursor: pointer;
|
|
781
881
|
font-size: 0.85rem;
|
|
782
882
|
width: 100%;
|
|
883
|
+
transition: all 0.15s ease;
|
|
783
884
|
}
|
|
784
885
|
|
|
785
886
|
.add-image-btn:hover {
|
|
786
|
-
border-color:
|
|
787
|
-
color:
|
|
887
|
+
border-color: var(--color-primary);
|
|
888
|
+
color: var(--color-primary);
|
|
889
|
+
background: var(--grove-overlay-5);
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
:global(.dark) .add-image-btn:hover {
|
|
893
|
+
border-color: #86efac;
|
|
894
|
+
color: #86efac;
|
|
788
895
|
}
|
|
789
896
|
|
|
790
897
|
/* Image Picker */
|
|
@@ -805,8 +912,9 @@
|
|
|
805
912
|
max-height: 400px;
|
|
806
913
|
overflow-y: auto;
|
|
807
914
|
padding: 0.5rem;
|
|
808
|
-
background:
|
|
809
|
-
border-radius:
|
|
915
|
+
background: var(--color-bg-secondary);
|
|
916
|
+
border-radius: 8px;
|
|
917
|
+
border: 1px solid var(--color-border);
|
|
810
918
|
}
|
|
811
919
|
|
|
812
920
|
.loading,
|
|
@@ -814,22 +922,26 @@
|
|
|
814
922
|
grid-column: 1 / -1;
|
|
815
923
|
text-align: center;
|
|
816
924
|
padding: 2rem;
|
|
817
|
-
color:
|
|
925
|
+
color: var(--color-text-muted);
|
|
818
926
|
}
|
|
819
927
|
|
|
820
928
|
.image-option {
|
|
821
929
|
display: flex;
|
|
822
930
|
flex-direction: column;
|
|
823
|
-
background:
|
|
931
|
+
background: var(--color-bg-secondary);
|
|
824
932
|
border: 2px solid transparent;
|
|
825
|
-
border-radius:
|
|
933
|
+
border-radius: 6px;
|
|
826
934
|
padding: 0.25rem;
|
|
827
935
|
cursor: pointer;
|
|
828
936
|
transition: border-color 0.15s ease;
|
|
829
937
|
}
|
|
830
938
|
|
|
831
939
|
.image-option:hover {
|
|
832
|
-
border-color:
|
|
940
|
+
border-color: var(--color-primary);
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
:global(.dark) .image-option:hover {
|
|
944
|
+
border-color: #86efac;
|
|
833
945
|
}
|
|
834
946
|
|
|
835
947
|
.image-option img {
|
|
@@ -837,12 +949,12 @@
|
|
|
837
949
|
aspect-ratio: 1;
|
|
838
950
|
-o-object-fit: cover;
|
|
839
951
|
object-fit: cover;
|
|
840
|
-
border-radius:
|
|
952
|
+
border-radius: 4px;
|
|
841
953
|
}
|
|
842
954
|
|
|
843
955
|
.image-name {
|
|
844
956
|
font-size: 0.65rem;
|
|
845
|
-
color:
|
|
957
|
+
color: var(--color-text-subtle);
|
|
846
958
|
margin-top: 0.25rem;
|
|
847
959
|
white-space: nowrap;
|
|
848
960
|
overflow: hidden;
|
|
@@ -824,9 +824,8 @@
|
|
|
824
824
|
|
|
825
825
|
<!-- Full Preview Modal -->
|
|
826
826
|
{#if showFullPreview}
|
|
827
|
-
<div class="full-preview-modal" role="dialog" aria-modal="true" aria-label="Full article preview">
|
|
828
|
-
|
|
829
|
-
<div class="full-preview-backdrop" onclick={() => (showFullPreview = false)}></div>
|
|
827
|
+
<div class="full-preview-modal" role="dialog" aria-modal="true" aria-label="Full article preview" tabindex="-1" onkeydown={(e) => e.key === 'Escape' && (showFullPreview = false)}>
|
|
828
|
+
<button type="button" class="full-preview-backdrop" onclick={() => (showFullPreview = false)} aria-label="Close preview"></button>
|
|
830
829
|
<div class="full-preview-container">
|
|
831
830
|
<header class="full-preview-header">
|
|
832
831
|
<h2>:: full preview</h2>
|
|
@@ -1100,6 +1099,7 @@
|
|
|
1100
1099
|
.toolbar-btn.full-preview-btn .key {
|
|
1101
1100
|
color: #9ac5ff;
|
|
1102
1101
|
}
|
|
1102
|
+
/* svelte-ignore css-unused-selector */
|
|
1103
1103
|
.toolbar-divider {
|
|
1104
1104
|
color: #4a4a4a;
|
|
1105
1105
|
margin: 0 0.25rem;
|
|
@@ -1775,6 +1775,9 @@
|
|
|
1775
1775
|
position: absolute;
|
|
1776
1776
|
inset: 0;
|
|
1777
1777
|
background: rgba(0, 0, 0, 0.7);
|
|
1778
|
+
border: none;
|
|
1779
|
+
padding: 0;
|
|
1780
|
+
cursor: pointer;
|
|
1778
1781
|
}
|
|
1779
1782
|
.full-preview-container {
|
|
1780
1783
|
position: relative;
|
|
@@ -31,8 +31,14 @@
|
|
|
31
31
|
|
|
32
32
|
<div class="gutter-item" data-anchor={item.anchor || ''}>
|
|
33
33
|
{#if item.type === 'comment' || item.type === 'markdown'}
|
|
34
|
-
<!-- svelte-ignore
|
|
35
|
-
<div
|
|
34
|
+
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
|
35
|
+
<div
|
|
36
|
+
class="gutter-comment"
|
|
37
|
+
onclick={handleContentClick}
|
|
38
|
+
onkeydown={(e) => e.key === 'Enter' && handleContentClick(e)}
|
|
39
|
+
role="group"
|
|
40
|
+
aria-label="Gutter annotation - click images to enlarge"
|
|
41
|
+
>
|
|
36
42
|
{@html sanitizeHTML(item.content)}
|
|
37
43
|
</div>
|
|
38
44
|
{:else if item.type === 'photo' || item.type === 'image'}
|
|
@@ -173,6 +173,7 @@
|
|
|
173
173
|
|
|
174
174
|
{#if open}
|
|
175
175
|
<!-- Backdrop -->
|
|
176
|
+
<!-- svelte-ignore a11y_click_events_have_key_events a11y_no_static_element_interactions -->
|
|
176
177
|
<div
|
|
177
178
|
class="fixed inset-0 bg-black/50 backdrop-blur-sm z-50 flex items-center justify-center p-4"
|
|
178
179
|
onclick={onClose}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loam - Domain Blocklist Configuration
|
|
3
|
+
*
|
|
4
|
+
* Part of the Loam name protection system.
|
|
5
|
+
* Comprehensive list of blocked usernames/subdomains organized by category.
|
|
6
|
+
*
|
|
7
|
+
* @see docs/specs/loam-spec.md
|
|
8
|
+
* @module domain-blocklist
|
|
9
|
+
*/
|
|
10
|
+
export type BlocklistReason = 'system' | 'grove_service' | 'trademark' | 'impersonation' | 'offensive' | 'fraud' | 'future_reserved';
|
|
11
|
+
/**
|
|
12
|
+
* Array of valid blocklist reasons for runtime validation
|
|
13
|
+
* Use this to validate database values before type assertion
|
|
14
|
+
*/
|
|
15
|
+
export declare const VALID_BLOCKLIST_REASONS: BlocklistReason[];
|
|
16
|
+
export interface BlocklistEntry {
|
|
17
|
+
username: string;
|
|
18
|
+
reason: BlocklistReason;
|
|
19
|
+
category?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare const SYSTEM_RESERVED: string[];
|
|
22
|
+
export declare const GROVE_SERVICES: string[];
|
|
23
|
+
export declare const GROVE_TRADEMARKS: string[];
|
|
24
|
+
export declare const IMPERSONATION_TERMS: string[];
|
|
25
|
+
export declare const FRAUD_TERMS: string[];
|
|
26
|
+
export declare const FUTURE_RESERVED: string[];
|
|
27
|
+
/**
|
|
28
|
+
* Complete blocklist with all categories
|
|
29
|
+
*/
|
|
30
|
+
export declare const COMPLETE_BLOCKLIST: BlocklistEntry[];
|
|
31
|
+
/**
|
|
32
|
+
* Fast lookup Set for validation (checks existence only)
|
|
33
|
+
*/
|
|
34
|
+
export declare const BLOCKED_USERNAMES: Set<string>;
|
|
35
|
+
/**
|
|
36
|
+
* Fast lookup Map for validation with reason (O(1) lookup)
|
|
37
|
+
*/
|
|
38
|
+
export declare const BLOCKED_USERNAMES_MAP: Map<string, BlocklistReason>;
|
|
39
|
+
/**
|
|
40
|
+
* Check if a username is blocked
|
|
41
|
+
* @param username - The username to check (will be lowercased)
|
|
42
|
+
* @returns The blocking reason if blocked, null if allowed
|
|
43
|
+
*/
|
|
44
|
+
export declare function isUsernameBlocked(username: string): BlocklistReason | null;
|
|
45
|
+
/**
|
|
46
|
+
* Get a user-friendly error message for a blocked username
|
|
47
|
+
* @param reason - The blocking reason
|
|
48
|
+
* @returns A user-friendly error message
|
|
49
|
+
*/
|
|
50
|
+
export declare function getBlockedMessage(reason: BlocklistReason): string;
|
|
51
|
+
/**
|
|
52
|
+
* Validation configuration
|
|
53
|
+
*/
|
|
54
|
+
export declare const VALIDATION_CONFIG: {
|
|
55
|
+
minLength: number;
|
|
56
|
+
maxLength: number;
|
|
57
|
+
pattern: RegExp;
|
|
58
|
+
patternDescription: string;
|
|
59
|
+
};
|