@autumnsgrove/groveengine 0.3.2 → 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/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.js +5 -0
- package/dist/components/admin/GutterManager.svelte +4 -4
- package/dist/components/admin/MarkdownEditor.svelte +381 -1311
- package/dist/components/admin/MarkdownEditor.svelte.d.ts +2 -8
- package/dist/components/admin/composables/index.d.ts +7 -0
- package/dist/components/admin/composables/index.js +12 -0
- package/dist/components/admin/composables/useAmbientSounds.svelte.d.ts +53 -0
- package/dist/components/admin/composables/useAmbientSounds.svelte.js +192 -0
- package/dist/components/admin/composables/useCommandPalette.svelte.d.ts +17 -0
- package/dist/components/admin/composables/useCommandPalette.svelte.js +118 -0
- package/dist/components/admin/composables/useDraftManager.svelte.d.ts +17 -0
- package/dist/components/admin/composables/useDraftManager.svelte.js +154 -0
- package/dist/components/admin/composables/useEditorTheme.svelte.d.ts +195 -0
- package/dist/components/admin/composables/useEditorTheme.svelte.js +182 -0
- package/dist/components/admin/composables/useSlashCommands.svelte.d.ts +32 -0
- package/dist/components/admin/composables/useSlashCommands.svelte.js +166 -0
- package/dist/components/admin/composables/useSnippets.svelte.d.ts +5 -0
- package/dist/components/admin/composables/useSnippets.svelte.js +122 -0
- package/dist/components/admin/composables/useWritingSession.svelte.d.ts +13 -0
- package/dist/components/admin/composables/useWritingSession.svelte.js +100 -0
- package/dist/components/custom/ContentWithGutter.svelte +1 -1
- package/dist/components/custom/GutterItem.svelte +2 -2
- package/dist/config/ai-models.d.ts +25 -0
- package/dist/config/ai-models.js +50 -0
- package/dist/config/index.d.ts +1 -0
- package/dist/config/index.js +4 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.js +6 -6
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +4 -0
- package/dist/ui/components/charts/ActivityOverview.svelte +293 -0
- package/dist/ui/components/charts/ActivityOverview.svelte.d.ts +12 -0
- package/dist/ui/components/charts/LOCBar.svelte +129 -0
- package/dist/ui/components/charts/LOCBar.svelte.d.ts +21 -0
- package/dist/ui/components/charts/RepoBreakdown.svelte +136 -0
- package/dist/ui/components/charts/RepoBreakdown.svelte.d.ts +16 -0
- package/dist/ui/components/charts/Sparkline.svelte +139 -0
- package/dist/ui/components/charts/Sparkline.svelte.d.ts +6 -0
- package/dist/ui/components/charts/index.d.ts +5 -0
- package/dist/ui/components/charts/index.js +11 -0
- package/dist/ui/components/content/PlanCard.svelte +91 -0
- package/dist/ui/components/content/PlanCard.svelte.d.ts +13 -0
- package/dist/ui/components/content/ProductCard.svelte +125 -0
- package/dist/ui/components/content/ProductCard.svelte.d.ts +14 -0
- package/dist/ui/components/content/SearchCard.svelte +60 -0
- package/dist/ui/components/content/SearchCard.svelte.d.ts +10 -0
- package/dist/ui/components/content/index.d.ts +4 -0
- package/dist/ui/components/content/index.js +10 -0
- package/dist/ui/components/forms/SearchInput.svelte +89 -0
- package/dist/ui/components/forms/SearchInput.svelte.d.ts +11 -0
- package/dist/ui/components/forms/index.d.ts +2 -0
- package/dist/ui/components/forms/index.js +8 -0
- package/dist/ui/components/gallery/index.d.ts +5 -0
- package/dist/ui/components/gallery/index.js +13 -0
- package/dist/ui/components/icons/IconLegend.svelte +83 -0
- package/dist/ui/components/icons/IconLegend.svelte.d.ts +11 -0
- package/dist/ui/components/icons/Icons.svelte +115 -0
- package/dist/ui/components/icons/Icons.svelte.d.ts +8 -0
- package/dist/ui/components/icons/index.d.ts +3 -0
- package/dist/ui/components/icons/index.js +9 -0
- package/dist/ui/components/indicators/CreditBalance.svelte +67 -0
- package/dist/ui/components/indicators/CreditBalance.svelte.d.ts +9 -0
- package/dist/ui/components/indicators/ScoreBar.svelte +63 -0
- package/dist/ui/components/indicators/ScoreBar.svelte.d.ts +9 -0
- package/dist/ui/components/indicators/StatusBadge.svelte +46 -0
- package/dist/ui/components/indicators/StatusBadge.svelte.d.ts +7 -0
- package/dist/ui/components/indicators/index.d.ts +4 -0
- package/dist/ui/components/indicators/index.js +10 -0
- package/dist/{components/ui → ui/components/primitives}/accordion/accordion-content.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/accordion/accordion-item.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/accordion/accordion-trigger.svelte +1 -1
- package/dist/ui/components/primitives/badge/badge.svelte +50 -0
- package/dist/ui/components/primitives/badge/badge.svelte.d.ts +60 -0
- package/dist/ui/components/primitives/badge/index.d.ts +2 -0
- package/dist/ui/components/primitives/badge/index.js +2 -0
- package/dist/ui/components/primitives/button/button.svelte +82 -0
- package/dist/ui/components/primitives/button/button.svelte.d.ts +132 -0
- package/dist/ui/components/primitives/button/index.d.ts +2 -0
- package/dist/ui/components/primitives/button/index.js +4 -0
- package/dist/ui/components/primitives/card/card-content.svelte +16 -0
- package/dist/ui/components/primitives/card/card-content.svelte.d.ts +5 -0
- package/dist/ui/components/primitives/card/card-description.svelte +16 -0
- package/dist/ui/components/primitives/card/card-description.svelte.d.ts +5 -0
- package/dist/ui/components/primitives/card/card-footer.svelte +16 -0
- package/dist/ui/components/primitives/card/card-footer.svelte.d.ts +5 -0
- package/dist/ui/components/primitives/card/card-header.svelte +16 -0
- package/dist/ui/components/primitives/card/card-header.svelte.d.ts +5 -0
- package/dist/ui/components/primitives/card/card-title.svelte +25 -0
- package/dist/ui/components/primitives/card/card-title.svelte.d.ts +8 -0
- package/dist/ui/components/primitives/card/card.svelte +20 -0
- package/dist/ui/components/primitives/card/card.svelte.d.ts +5 -0
- package/dist/ui/components/primitives/card/index.d.ts +7 -0
- package/dist/ui/components/primitives/card/index.js +9 -0
- package/dist/{components/ui → ui/components/primitives}/dialog/dialog-content.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/dialog/dialog-description.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/dialog/dialog-footer.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/dialog/dialog-header.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/dialog/dialog-overlay.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/dialog/dialog-title.svelte +1 -1
- package/dist/ui/components/primitives/input/index.d.ts +2 -0
- package/dist/ui/components/primitives/input/index.js +4 -0
- package/dist/ui/components/primitives/input/input.svelte +46 -0
- package/dist/ui/components/primitives/input/input.svelte.d.ts +13 -0
- package/dist/{components/ui → ui/components/primitives}/select/select-content.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/select/select-group-heading.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/select/select-item.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/select/select-scroll-down-button.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/select/select-scroll-up-button.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/select/select-separator.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/select/select-trigger.svelte +1 -1
- package/dist/ui/components/primitives/separator/index.d.ts +2 -0
- package/dist/ui/components/primitives/separator/index.js +4 -0
- package/dist/ui/components/primitives/separator/separator.svelte +22 -0
- package/dist/ui/components/primitives/separator/separator.svelte.d.ts +4 -0
- package/dist/{components/ui → ui/components/primitives}/sheet/sheet-content.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/sheet/sheet-description.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/sheet/sheet-footer.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/sheet/sheet-header.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/sheet/sheet-overlay.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/sheet/sheet-title.svelte +1 -1
- package/dist/ui/components/primitives/skeleton/index.d.ts +2 -0
- package/dist/ui/components/primitives/skeleton/index.js +4 -0
- package/dist/ui/components/primitives/skeleton/skeleton.svelte +17 -0
- package/dist/ui/components/primitives/skeleton/skeleton.svelte.d.ts +5 -0
- package/dist/{components/ui → ui/components/primitives}/table/table-body.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/table/table-caption.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/table/table-cell.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/table/table-footer.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/table/table-head.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/table/table-header.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/table/table-row.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/table/table.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/tabs/tabs-content.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/tabs/tabs-list.svelte +1 -1
- package/dist/{components/ui → ui/components/primitives}/tabs/tabs-trigger.svelte +1 -1
- package/dist/ui/components/primitives/textarea/index.d.ts +2 -0
- package/dist/ui/components/primitives/textarea/index.js +4 -0
- package/dist/ui/components/primitives/textarea/textarea.svelte +24 -0
- package/dist/ui/components/primitives/textarea/textarea.svelte.d.ts +6 -0
- package/dist/ui/components/states/EmptyState.svelte +28 -0
- package/dist/ui/components/states/EmptyState.svelte.d.ts +10 -0
- package/dist/ui/components/states/Loading.svelte +62 -0
- package/dist/ui/components/states/Loading.svelte.d.ts +7 -0
- package/dist/ui/components/states/LoadingSkeleton.svelte +46 -0
- package/dist/ui/components/states/LoadingSkeleton.svelte.d.ts +8 -0
- package/dist/ui/components/states/ThemeToggle.svelte +138 -0
- package/dist/ui/components/states/ThemeToggle.svelte.d.ts +6 -0
- package/dist/ui/components/states/index.d.ts +5 -0
- package/dist/ui/components/states/index.js +11 -0
- package/dist/{components → ui/components}/ui/Accordion.svelte +1 -1
- package/dist/ui/components/ui/Badge.svelte +52 -0
- package/dist/ui/components/ui/Badge.svelte.d.ts +28 -0
- package/dist/ui/components/ui/Button.svelte +77 -0
- package/dist/ui/components/ui/Button.svelte.d.ts +34 -0
- package/dist/ui/components/ui/Card.svelte +102 -0
- package/dist/ui/components/ui/Card.svelte.d.ts +46 -0
- package/dist/ui/components/ui/CollapsibleSection.svelte +65 -0
- package/dist/ui/components/ui/CollapsibleSection.svelte.d.ts +10 -0
- package/dist/{components → ui/components}/ui/Dialog.svelte +1 -1
- package/dist/ui/components/ui/Input.svelte +81 -0
- package/dist/ui/components/ui/Input.svelte.d.ts +35 -0
- package/dist/{components → ui/components}/ui/Select.svelte +1 -1
- package/dist/{components → ui/components}/ui/Sheet.svelte +1 -1
- package/dist/ui/components/ui/Skeleton.svelte +31 -0
- package/dist/ui/components/ui/Skeleton.svelte.d.ts +26 -0
- package/dist/ui/components/ui/Spinner.svelte +45 -0
- package/dist/ui/components/ui/Spinner.svelte.d.ts +15 -0
- package/dist/{components → ui/components}/ui/Table.svelte +2 -2
- package/dist/{components → ui/components}/ui/Table.svelte.d.ts +1 -1
- package/dist/{components → ui/components}/ui/Tabs.svelte +2 -2
- package/dist/ui/components/ui/Textarea.svelte +81 -0
- package/dist/ui/components/ui/Textarea.svelte.d.ts +35 -0
- package/dist/{components → ui/components}/ui/Toast.svelte +1 -1
- package/dist/ui/components/ui/index.d.ts +18 -0
- package/dist/ui/components/ui/index.js +28 -0
- package/dist/{components → ui/components}/ui/toast.d.ts +1 -1
- package/dist/{components → ui/components}/ui/toast.js +2 -2
- package/dist/ui/index.d.ts +10 -0
- package/dist/ui/index.js +22 -0
- package/dist/ui/stores/theme.d.ts +12 -0
- package/dist/ui/stores/theme.js +52 -0
- package/dist/ui/styles/content.css +514 -0
- package/dist/ui/styles/grove.css +715 -0
- package/dist/ui/styles/tokens.css +429 -0
- package/dist/ui/tailwind.preset.d.ts +340 -0
- package/dist/ui/tailwind.preset.js +441 -0
- package/dist/ui/tokens/animation.d.ts +417 -0
- package/dist/ui/tokens/animation.js +139 -0
- package/dist/ui/tokens/colors.d.ts +183 -0
- package/dist/ui/tokens/colors.js +97 -0
- package/dist/ui/tokens/effects.d.ts +111 -0
- package/dist/ui/tokens/effects.js +61 -0
- package/dist/ui/tokens/index.d.ts +6 -0
- package/dist/ui/tokens/index.js +19 -0
- package/dist/ui/tokens/spacing.d.ts +89 -0
- package/dist/ui/tokens/spacing.js +49 -0
- package/dist/ui/tokens/typography.d.ts +85 -0
- package/dist/ui/tokens/typography.js +68 -0
- package/dist/ui/utils/cn.d.ts +13 -0
- package/dist/ui/utils/cn.js +24 -0
- package/dist/ui/utils/index.d.ts +2 -0
- package/dist/ui/utils/index.js +8 -0
- package/dist/utils/index.d.ts +11 -0
- package/dist/utils/index.js +14 -0
- package/dist/utils/markdown.d.ts +11 -0
- package/dist/utils/markdown.js +25 -0
- package/dist/utils/sanitize.js +2 -3
- package/package.json +73 -10
- package/dist/components/ui/index.d.ts +0 -14
- package/dist/components/ui/index.js +0 -18
- /package/dist/{components → ui/components}/gallery/ImageGallery.svelte +0 -0
- /package/dist/{components → ui/components}/gallery/ImageGallery.svelte.d.ts +0 -0
- /package/dist/{components → ui/components}/gallery/Lightbox.svelte +0 -0
- /package/dist/{components → ui/components}/gallery/Lightbox.svelte.d.ts +0 -0
- /package/dist/{components → ui/components}/gallery/LightboxCaption.svelte +0 -0
- /package/dist/{components → ui/components}/gallery/LightboxCaption.svelte.d.ts +0 -0
- /package/dist/{components → ui/components}/gallery/ZoomableImage.svelte +0 -0
- /package/dist/{components → ui/components}/gallery/ZoomableImage.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/accordion/accordion-content.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/accordion/accordion-item.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/accordion/accordion-trigger.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/accordion/index.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/accordion/index.js +0 -0
- /package/dist/{components/ui → ui/components/primitives}/dialog/dialog-content.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/dialog/dialog-description.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/dialog/dialog-footer.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/dialog/dialog-header.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/dialog/dialog-overlay.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/dialog/dialog-title.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/dialog/index.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/dialog/index.js +0 -0
- /package/dist/{components/ui → ui/components/primitives}/select/index.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/select/index.js +0 -0
- /package/dist/{components/ui → ui/components/primitives}/select/select-content.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/select/select-group-heading.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/select/select-item.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/select/select-scroll-down-button.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/select/select-scroll-up-button.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/select/select-separator.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/select/select-trigger.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/sheet/index.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/sheet/index.js +0 -0
- /package/dist/{components/ui → ui/components/primitives}/sheet/sheet-content.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/sheet/sheet-description.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/sheet/sheet-footer.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/sheet/sheet-header.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/sheet/sheet-overlay.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/sheet/sheet-title.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/table/index.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/table/index.js +0 -0
- /package/dist/{components/ui → ui/components/primitives}/table/table-body.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/table/table-caption.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/table/table-cell.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/table/table-footer.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/table/table-head.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/table/table-header.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/table/table-row.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/table/table.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/tabs/index.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/tabs/index.js +0 -0
- /package/dist/{components/ui → ui/components/primitives}/tabs/tabs-content.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/tabs/tabs-list.svelte.d.ts +0 -0
- /package/dist/{components/ui → ui/components/primitives}/tabs/tabs-trigger.svelte.d.ts +0 -0
- /package/dist/{components → ui/components}/ui/Accordion.svelte.d.ts +0 -0
- /package/dist/{components → ui/components}/ui/Dialog.svelte.d.ts +0 -0
- /package/dist/{components → ui/components}/ui/Select.svelte.d.ts +0 -0
- /package/dist/{components → ui/components}/ui/Sheet.svelte.d.ts +0 -0
- /package/dist/{components → ui/components}/ui/Tabs.svelte.d.ts +0 -0
- /package/dist/{components → ui/components}/ui/Toast.svelte.d.ts +0 -0
|
@@ -6,10 +6,7 @@ type MarkdownEditor = {
|
|
|
6
6
|
getAvailableAnchors: () => string[];
|
|
7
7
|
insertAnchor: (name: any) => void;
|
|
8
8
|
clearDraft: () => void;
|
|
9
|
-
getDraftStatus: () =>
|
|
10
|
-
hasDraft: boolean;
|
|
11
|
-
storedDraft: null;
|
|
12
|
-
};
|
|
9
|
+
getDraftStatus: () => any;
|
|
13
10
|
};
|
|
14
11
|
declare const MarkdownEditor: import("svelte").Component<{
|
|
15
12
|
content?: string;
|
|
@@ -25,10 +22,7 @@ declare const MarkdownEditor: import("svelte").Component<{
|
|
|
25
22
|
getAvailableAnchors: () => string[];
|
|
26
23
|
insertAnchor: (name: any) => void;
|
|
27
24
|
clearDraft: () => void;
|
|
28
|
-
getDraftStatus: () =>
|
|
29
|
-
hasDraft: boolean;
|
|
30
|
-
storedDraft: null;
|
|
31
|
-
};
|
|
25
|
+
getDraftStatus: () => any;
|
|
32
26
|
}, "content">;
|
|
33
27
|
type $$ComponentProps = {
|
|
34
28
|
content?: string;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { useSnippets } from "./useSnippets.svelte.js";
|
|
2
|
+
export { useDraftManager } from "./useDraftManager.svelte.js";
|
|
3
|
+
export { useWritingSession } from "./useWritingSession.svelte.js";
|
|
4
|
+
export { useCommandPalette } from "./useCommandPalette.svelte.js";
|
|
5
|
+
export { useAmbientSounds, soundLibrary } from "./useAmbientSounds.svelte.js";
|
|
6
|
+
export { useEditorTheme, themes } from "./useEditorTheme.svelte.js";
|
|
7
|
+
export { useSlashCommands, baseSlashCommands } from "./useSlashCommands.svelte.js";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MarkdownEditor Composables
|
|
3
|
+
* Extracted from MarkdownEditor.svelte for better maintainability
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export { useAmbientSounds, soundLibrary } from "./useAmbientSounds.svelte.js";
|
|
7
|
+
export { useEditorTheme, themes } from "./useEditorTheme.svelte.js";
|
|
8
|
+
export { useSnippets } from "./useSnippets.svelte.js";
|
|
9
|
+
export { useDraftManager } from "./useDraftManager.svelte.js";
|
|
10
|
+
export { useWritingSession } from "./useWritingSession.svelte.js";
|
|
11
|
+
export { useSlashCommands, baseSlashCommands } from "./useSlashCommands.svelte.js";
|
|
12
|
+
export { useCommandPalette } from "./useCommandPalette.svelte.js";
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates an ambient sounds manager with Svelte 5 runes
|
|
3
|
+
* @returns {object} Ambient sounds state and controls
|
|
4
|
+
*/
|
|
5
|
+
export function useAmbientSounds(): object;
|
|
6
|
+
export namespace soundLibrary {
|
|
7
|
+
namespace forest {
|
|
8
|
+
let name: string;
|
|
9
|
+
let key: string;
|
|
10
|
+
let url: string;
|
|
11
|
+
let description: string;
|
|
12
|
+
}
|
|
13
|
+
namespace rain {
|
|
14
|
+
let name_1: string;
|
|
15
|
+
export { name_1 as name };
|
|
16
|
+
let key_1: string;
|
|
17
|
+
export { key_1 as key };
|
|
18
|
+
let url_1: string;
|
|
19
|
+
export { url_1 as url };
|
|
20
|
+
let description_1: string;
|
|
21
|
+
export { description_1 as description };
|
|
22
|
+
}
|
|
23
|
+
namespace campfire {
|
|
24
|
+
let name_2: string;
|
|
25
|
+
export { name_2 as name };
|
|
26
|
+
let key_2: string;
|
|
27
|
+
export { key_2 as key };
|
|
28
|
+
let url_2: string;
|
|
29
|
+
export { url_2 as url };
|
|
30
|
+
let description_2: string;
|
|
31
|
+
export { description_2 as description };
|
|
32
|
+
}
|
|
33
|
+
namespace night {
|
|
34
|
+
let name_3: string;
|
|
35
|
+
export { name_3 as name };
|
|
36
|
+
let key_3: string;
|
|
37
|
+
export { key_3 as key };
|
|
38
|
+
let url_3: string;
|
|
39
|
+
export { url_3 as url };
|
|
40
|
+
let description_3: string;
|
|
41
|
+
export { description_3 as description };
|
|
42
|
+
}
|
|
43
|
+
namespace cafe {
|
|
44
|
+
let name_4: string;
|
|
45
|
+
export { name_4 as name };
|
|
46
|
+
let key_4: string;
|
|
47
|
+
export { key_4 as key };
|
|
48
|
+
let url_4: string;
|
|
49
|
+
export { url_4 as url };
|
|
50
|
+
let description_4: string;
|
|
51
|
+
export { description_4 as description };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ambient Sounds Composable
|
|
3
|
+
* Manages background audio for the editor (forest, rain, fire, etc.)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const SOUNDS_STORAGE_KEY = "grove-editor-sounds";
|
|
7
|
+
|
|
8
|
+
// Sound definitions with ambient loops
|
|
9
|
+
export const soundLibrary = {
|
|
10
|
+
forest: {
|
|
11
|
+
name: "forest",
|
|
12
|
+
key: "f",
|
|
13
|
+
url: "/sounds/forest-ambience.mp3",
|
|
14
|
+
description: "birds, wind",
|
|
15
|
+
},
|
|
16
|
+
rain: {
|
|
17
|
+
name: "rain",
|
|
18
|
+
key: "r",
|
|
19
|
+
url: "/sounds/rain-ambience.mp3",
|
|
20
|
+
description: "gentle rainfall",
|
|
21
|
+
},
|
|
22
|
+
campfire: {
|
|
23
|
+
name: "fire",
|
|
24
|
+
key: "i",
|
|
25
|
+
url: "/sounds/campfire-ambience.mp3",
|
|
26
|
+
description: "crackling embers",
|
|
27
|
+
},
|
|
28
|
+
night: {
|
|
29
|
+
name: "night",
|
|
30
|
+
key: "n",
|
|
31
|
+
url: "/sounds/night-ambience.mp3",
|
|
32
|
+
description: "crickets, breeze",
|
|
33
|
+
},
|
|
34
|
+
cafe: {
|
|
35
|
+
name: "cafe",
|
|
36
|
+
key: "a",
|
|
37
|
+
url: "/sounds/cafe-ambience.mp3",
|
|
38
|
+
description: "soft murmurs",
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Creates an ambient sounds manager with Svelte 5 runes
|
|
44
|
+
* @returns {object} Ambient sounds state and controls
|
|
45
|
+
*/
|
|
46
|
+
export function useAmbientSounds() {
|
|
47
|
+
let state = $state({
|
|
48
|
+
enabled: false,
|
|
49
|
+
currentSound: "forest",
|
|
50
|
+
volume: 0.3,
|
|
51
|
+
showPanel: false,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
let audioElement = $state(null);
|
|
55
|
+
|
|
56
|
+
function loadSettings() {
|
|
57
|
+
try {
|
|
58
|
+
const stored = localStorage.getItem(SOUNDS_STORAGE_KEY);
|
|
59
|
+
if (stored) {
|
|
60
|
+
const settings = JSON.parse(stored);
|
|
61
|
+
state.currentSound = settings.currentSound || "forest";
|
|
62
|
+
state.volume = settings.volume ?? 0.3;
|
|
63
|
+
// Don't auto-enable on load - user must click to start
|
|
64
|
+
}
|
|
65
|
+
} catch (e) {
|
|
66
|
+
console.warn("Failed to load sound settings:", e);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function saveSettings() {
|
|
71
|
+
try {
|
|
72
|
+
localStorage.setItem(
|
|
73
|
+
SOUNDS_STORAGE_KEY,
|
|
74
|
+
JSON.stringify({
|
|
75
|
+
currentSound: state.currentSound,
|
|
76
|
+
volume: state.volume,
|
|
77
|
+
})
|
|
78
|
+
);
|
|
79
|
+
} catch (e) {
|
|
80
|
+
console.warn("Failed to save sound settings:", e);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function toggle() {
|
|
85
|
+
if (state.enabled) {
|
|
86
|
+
stop();
|
|
87
|
+
} else {
|
|
88
|
+
play(state.currentSound);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function play(soundKey) {
|
|
93
|
+
const sound = soundLibrary[soundKey];
|
|
94
|
+
if (!sound) return;
|
|
95
|
+
|
|
96
|
+
// Stop current sound if playing
|
|
97
|
+
if (audioElement) {
|
|
98
|
+
audioElement.pause();
|
|
99
|
+
audioElement = null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Create new audio element
|
|
103
|
+
audioElement = new Audio(sound.url);
|
|
104
|
+
audioElement.loop = true;
|
|
105
|
+
audioElement.volume = state.volume;
|
|
106
|
+
|
|
107
|
+
// Handle playback errors gracefully
|
|
108
|
+
audioElement.onerror = () => {
|
|
109
|
+
console.warn(`Sound file not found: ${sound.url}`);
|
|
110
|
+
state.enabled = false;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
audioElement
|
|
114
|
+
.play()
|
|
115
|
+
.then(() => {
|
|
116
|
+
state.enabled = true;
|
|
117
|
+
state.currentSound = soundKey;
|
|
118
|
+
saveSettings();
|
|
119
|
+
})
|
|
120
|
+
.catch((e) => {
|
|
121
|
+
console.warn("Failed to play sound:", e);
|
|
122
|
+
state.enabled = false;
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function stop() {
|
|
127
|
+
if (audioElement) {
|
|
128
|
+
audioElement.pause();
|
|
129
|
+
audioElement = null;
|
|
130
|
+
}
|
|
131
|
+
state.enabled = false;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function setVolume(newVolume) {
|
|
135
|
+
state.volume = newVolume;
|
|
136
|
+
if (audioElement) {
|
|
137
|
+
audioElement.volume = newVolume;
|
|
138
|
+
}
|
|
139
|
+
saveSettings();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function selectSound(soundKey) {
|
|
143
|
+
if (state.enabled) {
|
|
144
|
+
play(soundKey);
|
|
145
|
+
} else {
|
|
146
|
+
state.currentSound = soundKey;
|
|
147
|
+
saveSettings();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function togglePanel() {
|
|
152
|
+
state.showPanel = !state.showPanel;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function closePanel() {
|
|
156
|
+
state.showPanel = false;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function cleanup() {
|
|
160
|
+
if (audioElement) {
|
|
161
|
+
audioElement.pause();
|
|
162
|
+
audioElement = null;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
get state() {
|
|
168
|
+
return state;
|
|
169
|
+
},
|
|
170
|
+
get enabled() {
|
|
171
|
+
return state.enabled;
|
|
172
|
+
},
|
|
173
|
+
get currentSound() {
|
|
174
|
+
return state.currentSound;
|
|
175
|
+
},
|
|
176
|
+
get volume() {
|
|
177
|
+
return state.volume;
|
|
178
|
+
},
|
|
179
|
+
get showPanel() {
|
|
180
|
+
return state.showPanel;
|
|
181
|
+
},
|
|
182
|
+
loadSettings,
|
|
183
|
+
toggle,
|
|
184
|
+
play,
|
|
185
|
+
stop,
|
|
186
|
+
setVolume,
|
|
187
|
+
selectSound,
|
|
188
|
+
togglePanel,
|
|
189
|
+
closePanel,
|
|
190
|
+
cleanup,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command Palette Composable
|
|
3
|
+
* Manages the command palette (Cmd+K) functionality
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Creates a command palette manager with Svelte 5 runes
|
|
7
|
+
* @param {object} options - Configuration options
|
|
8
|
+
* @param {Function} options.getActions - Function to get available actions
|
|
9
|
+
* @param {Function} options.getThemes - Function to get available themes
|
|
10
|
+
* @param {Function} options.getCurrentTheme - Function to get current theme
|
|
11
|
+
* @returns {object} Command palette state and controls
|
|
12
|
+
*/
|
|
13
|
+
export function useCommandPalette(options?: {
|
|
14
|
+
getActions: Function;
|
|
15
|
+
getThemes: Function;
|
|
16
|
+
getCurrentTheme: Function;
|
|
17
|
+
}): object;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command Palette Composable
|
|
3
|
+
* Manages the command palette (Cmd+K) functionality
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Creates a command palette manager with Svelte 5 runes
|
|
8
|
+
* @param {object} options - Configuration options
|
|
9
|
+
* @param {Function} options.getActions - Function to get available actions
|
|
10
|
+
* @param {Function} options.getThemes - Function to get available themes
|
|
11
|
+
* @param {Function} options.getCurrentTheme - Function to get current theme
|
|
12
|
+
* @returns {object} Command palette state and controls
|
|
13
|
+
*/
|
|
14
|
+
export function useCommandPalette(options = {}) {
|
|
15
|
+
const { getActions, getThemes, getCurrentTheme } = options;
|
|
16
|
+
|
|
17
|
+
let state = $state({
|
|
18
|
+
open: false,
|
|
19
|
+
query: "",
|
|
20
|
+
selectedIndex: 0,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Get all commands including theme commands
|
|
24
|
+
function getAllCommands() {
|
|
25
|
+
const actions = getActions ? getActions() : [];
|
|
26
|
+
const themes = getThemes ? getThemes() : {};
|
|
27
|
+
const currentTheme = getCurrentTheme ? getCurrentTheme() : "";
|
|
28
|
+
|
|
29
|
+
const themeCommands = Object.entries(themes).map(([key, theme]) => ({
|
|
30
|
+
id: `theme-${key}`,
|
|
31
|
+
label: `Theme: ${theme.label} (${theme.desc})`,
|
|
32
|
+
shortcut: currentTheme === key ? "●" : "",
|
|
33
|
+
action: () => {
|
|
34
|
+
// Theme action is handled by the caller
|
|
35
|
+
},
|
|
36
|
+
themeKey: key,
|
|
37
|
+
isTheme: true,
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
return [...actions, ...themeCommands];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Get filtered commands based on query
|
|
44
|
+
function getFilteredCommands() {
|
|
45
|
+
const allCommands = getAllCommands();
|
|
46
|
+
return allCommands.filter((cmd) =>
|
|
47
|
+
cmd.label.toLowerCase().includes(state.query.toLowerCase())
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function open() {
|
|
52
|
+
state.open = true;
|
|
53
|
+
state.query = "";
|
|
54
|
+
state.selectedIndex = 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function close() {
|
|
58
|
+
state.open = false;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function toggle() {
|
|
62
|
+
if (state.open) {
|
|
63
|
+
close();
|
|
64
|
+
} else {
|
|
65
|
+
open();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function navigate(direction) {
|
|
70
|
+
const filtered = getFilteredCommands();
|
|
71
|
+
const count = filtered.length;
|
|
72
|
+
if (count === 0) return;
|
|
73
|
+
|
|
74
|
+
if (direction === "down") {
|
|
75
|
+
state.selectedIndex = (state.selectedIndex + 1) % count;
|
|
76
|
+
} else if (direction === "up") {
|
|
77
|
+
state.selectedIndex = (state.selectedIndex - 1 + count) % count;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function execute(index) {
|
|
82
|
+
const filtered = getFilteredCommands();
|
|
83
|
+
const cmd = filtered[index];
|
|
84
|
+
if (cmd && cmd.action) {
|
|
85
|
+
cmd.action();
|
|
86
|
+
close();
|
|
87
|
+
}
|
|
88
|
+
return cmd;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function setQuery(query) {
|
|
92
|
+
state.query = query;
|
|
93
|
+
state.selectedIndex = 0;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
get state() {
|
|
98
|
+
return state;
|
|
99
|
+
},
|
|
100
|
+
get isOpen() {
|
|
101
|
+
return state.open;
|
|
102
|
+
},
|
|
103
|
+
get query() {
|
|
104
|
+
return state.query;
|
|
105
|
+
},
|
|
106
|
+
get selectedIndex() {
|
|
107
|
+
return state.selectedIndex;
|
|
108
|
+
},
|
|
109
|
+
getAllCommands,
|
|
110
|
+
getFilteredCommands,
|
|
111
|
+
open,
|
|
112
|
+
close,
|
|
113
|
+
toggle,
|
|
114
|
+
navigate,
|
|
115
|
+
execute,
|
|
116
|
+
setQuery,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a draft manager with Svelte 5 runes
|
|
3
|
+
* @param {object} options - Configuration options
|
|
4
|
+
* @param {string} options.draftKey - Unique key for localStorage
|
|
5
|
+
* @param {Function} options.getContent - Function to get current content
|
|
6
|
+
* @param {Function} options.setContent - Function to set content
|
|
7
|
+
* @param {Function} options.onDraftRestored - Callback when draft is restored
|
|
8
|
+
* @param {boolean} options.readonly - Whether editor is readonly
|
|
9
|
+
* @returns {object} Draft state and controls
|
|
10
|
+
*/
|
|
11
|
+
export function useDraftManager(options?: {
|
|
12
|
+
draftKey: string;
|
|
13
|
+
getContent: Function;
|
|
14
|
+
setContent: Function;
|
|
15
|
+
onDraftRestored: Function;
|
|
16
|
+
readonly: boolean;
|
|
17
|
+
}): object;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Draft Manager Composable
|
|
3
|
+
* Handles auto-saving drafts to localStorage
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const AUTO_SAVE_DELAY = 2000; // 2 seconds
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Creates a draft manager with Svelte 5 runes
|
|
10
|
+
* @param {object} options - Configuration options
|
|
11
|
+
* @param {string} options.draftKey - Unique key for localStorage
|
|
12
|
+
* @param {Function} options.getContent - Function to get current content
|
|
13
|
+
* @param {Function} options.setContent - Function to set content
|
|
14
|
+
* @param {Function} options.onDraftRestored - Callback when draft is restored
|
|
15
|
+
* @param {boolean} options.readonly - Whether editor is readonly
|
|
16
|
+
* @returns {object} Draft state and controls
|
|
17
|
+
*/
|
|
18
|
+
export function useDraftManager(options = {}) {
|
|
19
|
+
const { draftKey, getContent, setContent, onDraftRestored, readonly } = options;
|
|
20
|
+
|
|
21
|
+
let lastSavedContent = $state("");
|
|
22
|
+
let draftSaveTimer = $state(null);
|
|
23
|
+
let hasDraft = $state(false);
|
|
24
|
+
let draftRestorePrompt = $state(false);
|
|
25
|
+
let storedDraft = $state(null);
|
|
26
|
+
|
|
27
|
+
function saveDraft() {
|
|
28
|
+
if (!draftKey || readonly) return;
|
|
29
|
+
|
|
30
|
+
const content = getContent();
|
|
31
|
+
try {
|
|
32
|
+
const draft = {
|
|
33
|
+
content,
|
|
34
|
+
savedAt: new Date().toISOString(),
|
|
35
|
+
};
|
|
36
|
+
localStorage.setItem(`draft:${draftKey}`, JSON.stringify(draft));
|
|
37
|
+
lastSavedContent = content;
|
|
38
|
+
hasDraft = true;
|
|
39
|
+
} catch (e) {
|
|
40
|
+
console.warn("Failed to save draft:", e);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function loadDraft() {
|
|
45
|
+
if (!draftKey) return null;
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
const stored = localStorage.getItem(`draft:${draftKey}`);
|
|
49
|
+
if (stored) {
|
|
50
|
+
return JSON.parse(stored);
|
|
51
|
+
}
|
|
52
|
+
} catch (e) {
|
|
53
|
+
console.warn("Failed to load draft:", e);
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function clearDraft() {
|
|
59
|
+
if (!draftKey) return;
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
localStorage.removeItem(`draft:${draftKey}`);
|
|
63
|
+
hasDraft = false;
|
|
64
|
+
storedDraft = null;
|
|
65
|
+
draftRestorePrompt = false;
|
|
66
|
+
} catch (e) {
|
|
67
|
+
console.warn("Failed to clear draft:", e);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function restoreDraft() {
|
|
72
|
+
if (storedDraft && setContent) {
|
|
73
|
+
setContent(storedDraft.content);
|
|
74
|
+
lastSavedContent = storedDraft.content;
|
|
75
|
+
if (onDraftRestored) {
|
|
76
|
+
onDraftRestored(storedDraft);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
draftRestorePrompt = false;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function discardDraft() {
|
|
83
|
+
clearDraft();
|
|
84
|
+
lastSavedContent = getContent();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function scheduleSave(content) {
|
|
88
|
+
if (!draftKey || readonly) return;
|
|
89
|
+
|
|
90
|
+
// Clear previous timer
|
|
91
|
+
if (draftSaveTimer) {
|
|
92
|
+
clearTimeout(draftSaveTimer);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Don't save if content hasn't changed from last saved version
|
|
96
|
+
if (content === lastSavedContent) return;
|
|
97
|
+
|
|
98
|
+
// Schedule a draft save
|
|
99
|
+
draftSaveTimer = setTimeout(() => {
|
|
100
|
+
saveDraft();
|
|
101
|
+
}, AUTO_SAVE_DELAY);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function init(initialContent) {
|
|
105
|
+
// Check for existing draft on mount
|
|
106
|
+
if (draftKey) {
|
|
107
|
+
const draft = loadDraft();
|
|
108
|
+
if (draft && draft.content !== initialContent) {
|
|
109
|
+
storedDraft = draft;
|
|
110
|
+
draftRestorePrompt = true;
|
|
111
|
+
} else {
|
|
112
|
+
lastSavedContent = initialContent;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function cleanup() {
|
|
118
|
+
if (draftSaveTimer) {
|
|
119
|
+
clearTimeout(draftSaveTimer);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function getStatus() {
|
|
124
|
+
return { hasDraft, storedDraft };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function hasUnsavedChanges(content) {
|
|
128
|
+
return content !== lastSavedContent;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
get hasDraft() {
|
|
133
|
+
return hasDraft;
|
|
134
|
+
},
|
|
135
|
+
get draftRestorePrompt() {
|
|
136
|
+
return draftRestorePrompt;
|
|
137
|
+
},
|
|
138
|
+
get storedDraft() {
|
|
139
|
+
return storedDraft;
|
|
140
|
+
},
|
|
141
|
+
get lastSavedContent() {
|
|
142
|
+
return lastSavedContent;
|
|
143
|
+
},
|
|
144
|
+
init,
|
|
145
|
+
scheduleSave,
|
|
146
|
+
saveDraft,
|
|
147
|
+
clearDraft,
|
|
148
|
+
restoreDraft,
|
|
149
|
+
discardDraft,
|
|
150
|
+
getStatus,
|
|
151
|
+
hasUnsavedChanges,
|
|
152
|
+
cleanup,
|
|
153
|
+
};
|
|
154
|
+
}
|