@autumnsgrove/groveengine 0.1.1 → 0.3.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 +1 -2
- package/dist/components/admin/MarkdownEditor.svelte +1 -2
- package/dist/components/custom/InternalsPostViewer.svelte +95 -0
- package/dist/components/custom/InternalsPostViewer.svelte.d.ts +13 -0
- package/dist/components/ui/index.d.ts +0 -12
- package/dist/components/ui/index.js +2 -13
- package/dist/components/ui/select/select-separator.svelte +2 -3
- package/dist/components/ui/select/select-separator.svelte.d.ts +1 -1
- package/dist/utils/markdown.d.ts +42 -0
- package/dist/utils/markdown.js +104 -0
- package/package.json +2 -1
- package/dist/components/ui/Badge.svelte +0 -48
- package/dist/components/ui/Badge.svelte.d.ts +0 -26
- package/dist/components/ui/Button.svelte +0 -74
- package/dist/components/ui/Button.svelte.d.ts +0 -34
- package/dist/components/ui/Card.svelte +0 -102
- package/dist/components/ui/Card.svelte.d.ts +0 -46
- package/dist/components/ui/Input.svelte +0 -81
- package/dist/components/ui/Input.svelte.d.ts +0 -35
- package/dist/components/ui/Skeleton.svelte +0 -31
- package/dist/components/ui/Skeleton.svelte.d.ts +0 -26
- package/dist/components/ui/Textarea.svelte +0 -81
- package/dist/components/ui/Textarea.svelte.d.ts +0 -35
- package/dist/components/ui/badge/badge.svelte +0 -50
- package/dist/components/ui/badge/badge.svelte.d.ts +0 -60
- package/dist/components/ui/badge/index.d.ts +0 -2
- package/dist/components/ui/badge/index.js +0 -2
- package/dist/components/ui/button/button.svelte +0 -82
- package/dist/components/ui/button/button.svelte.d.ts +0 -132
- package/dist/components/ui/button/index.d.ts +0 -2
- package/dist/components/ui/button/index.js +0 -4
- package/dist/components/ui/card/card-content.svelte +0 -16
- package/dist/components/ui/card/card-content.svelte.d.ts +0 -5
- package/dist/components/ui/card/card-description.svelte +0 -16
- package/dist/components/ui/card/card-description.svelte.d.ts +0 -5
- package/dist/components/ui/card/card-footer.svelte +0 -16
- package/dist/components/ui/card/card-footer.svelte.d.ts +0 -5
- package/dist/components/ui/card/card-header.svelte +0 -16
- package/dist/components/ui/card/card-header.svelte.d.ts +0 -5
- package/dist/components/ui/card/card-title.svelte +0 -25
- package/dist/components/ui/card/card-title.svelte.d.ts +0 -8
- package/dist/components/ui/card/card.svelte +0 -20
- package/dist/components/ui/card/card.svelte.d.ts +0 -5
- package/dist/components/ui/card/index.d.ts +0 -7
- package/dist/components/ui/card/index.js +0 -9
- package/dist/components/ui/input/index.d.ts +0 -2
- package/dist/components/ui/input/index.js +0 -4
- package/dist/components/ui/input/input.svelte +0 -46
- package/dist/components/ui/input/input.svelte.d.ts +0 -13
- package/dist/components/ui/separator/index.d.ts +0 -2
- package/dist/components/ui/separator/index.js +0 -4
- package/dist/components/ui/separator/separator.svelte +0 -22
- package/dist/components/ui/separator/separator.svelte.d.ts +0 -4
- package/dist/components/ui/skeleton/index.d.ts +0 -2
- package/dist/components/ui/skeleton/index.js +0 -4
- package/dist/components/ui/skeleton/skeleton.svelte +0 -17
- package/dist/components/ui/skeleton/skeleton.svelte.d.ts +0 -5
- package/dist/components/ui/textarea/index.d.ts +0 -2
- package/dist/components/ui/textarea/index.js +0 -4
- package/dist/components/ui/textarea/textarea.svelte +0 -24
- package/dist/components/ui/textarea/textarea.svelte.d.ts +0 -6
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { marked } from "marked";
|
|
3
|
+
import { Input, Button } from '@groveengine/ui';
|
|
3
4
|
import Dialog from "../ui/Dialog.svelte";
|
|
4
|
-
import Input from "../ui/Input.svelte";
|
|
5
|
-
import Button from "../ui/Button.svelte";
|
|
6
5
|
import Select from "../ui/Select.svelte";
|
|
7
6
|
import { toast } from "../ui/toast";
|
|
8
7
|
|
|
@@ -4,9 +4,8 @@
|
|
|
4
4
|
import { onMount, tick } from "svelte";
|
|
5
5
|
import { sanitizeMarkdown } from "../../utils/sanitize.js";
|
|
6
6
|
import "../../styles/content.css";
|
|
7
|
+
import { Button, Input } from '@groveengine/ui';
|
|
7
8
|
import Dialog from "../ui/Dialog.svelte";
|
|
8
|
-
import Button from "../ui/Button.svelte";
|
|
9
|
-
import Input from "../ui/Input.svelte";
|
|
10
9
|
|
|
11
10
|
// Initialize mermaid with grove-themed dark config
|
|
12
11
|
mermaid.initialize({
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
/**
|
|
3
|
+
* Simple component to display a featured blog post
|
|
4
|
+
* @prop {{ title: string; description?: string; slug: string; date?: string }} post - Post data
|
|
5
|
+
* @prop {string} [caption] - Optional caption text
|
|
6
|
+
*/
|
|
7
|
+
let { post, caption = "" } = $props();
|
|
8
|
+
|
|
9
|
+
const formattedDate = $derived(post.date ? new Date(post.date).toLocaleDateString('en-US', {
|
|
10
|
+
year: 'numeric',
|
|
11
|
+
month: 'long',
|
|
12
|
+
day: 'numeric'
|
|
13
|
+
}) : null);
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<article class="post-viewer">
|
|
17
|
+
{#if caption}
|
|
18
|
+
<span class="caption">{caption}</span>
|
|
19
|
+
{/if}
|
|
20
|
+
<a href="/blog/{post.slug}" class="post-link">
|
|
21
|
+
<h3 class="title">{post.title}</h3>
|
|
22
|
+
{#if post.description}
|
|
23
|
+
<p class="description">{post.description}</p>
|
|
24
|
+
{/if}
|
|
25
|
+
{#if formattedDate}
|
|
26
|
+
<time class="date">{formattedDate}</time>
|
|
27
|
+
{/if}
|
|
28
|
+
</a>
|
|
29
|
+
</article>
|
|
30
|
+
|
|
31
|
+
<style>
|
|
32
|
+
.post-viewer {
|
|
33
|
+
background: var(--color-bg-secondary);
|
|
34
|
+
border: 1px solid var(--color-border);
|
|
35
|
+
border-radius: var(--border-radius-standard);
|
|
36
|
+
padding: 1.5rem;
|
|
37
|
+
transition: all 0.3s ease;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.caption {
|
|
41
|
+
display: block;
|
|
42
|
+
font-size: 0.75rem;
|
|
43
|
+
text-transform: uppercase;
|
|
44
|
+
letter-spacing: 0.05em;
|
|
45
|
+
color: var(--color-primary);
|
|
46
|
+
margin-bottom: 0.5rem;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.post-link {
|
|
50
|
+
text-decoration: none;
|
|
51
|
+
color: inherit;
|
|
52
|
+
display: block;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.post-link:hover .title {
|
|
56
|
+
color: var(--color-primary);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.title {
|
|
60
|
+
font-size: 1.25rem;
|
|
61
|
+
margin: 0 0 0.5rem 0;
|
|
62
|
+
color: var(--color-text);
|
|
63
|
+
transition: color 0.2s ease;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.description {
|
|
67
|
+
margin: 0 0 0.75rem 0;
|
|
68
|
+
color: var(--color-text-muted);
|
|
69
|
+
font-size: 0.95rem;
|
|
70
|
+
line-height: 1.6;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.date {
|
|
74
|
+
display: block;
|
|
75
|
+
font-size: 0.875rem;
|
|
76
|
+
color: var(--color-text-subtle);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
:global(.dark) .post-viewer {
|
|
80
|
+
background: var(--color-bg-tertiary-dark);
|
|
81
|
+
border-color: var(--color-border-dark);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
:global(.dark) .title {
|
|
85
|
+
color: var(--color-text-dark);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
:global(.dark) .description {
|
|
89
|
+
color: var(--color-text-subtle-dark);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
:global(.dark) .date {
|
|
93
|
+
color: var(--color-text-subtle-dark);
|
|
94
|
+
}
|
|
95
|
+
</style>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export default InternalsPostViewer;
|
|
2
|
+
type InternalsPostViewer = {
|
|
3
|
+
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
+
$set?(props: Partial<$$ComponentProps>): void;
|
|
5
|
+
};
|
|
6
|
+
declare const InternalsPostViewer: import("svelte").Component<{
|
|
7
|
+
post: any;
|
|
8
|
+
caption?: string;
|
|
9
|
+
}, {}, "">;
|
|
10
|
+
type $$ComponentProps = {
|
|
11
|
+
post: any;
|
|
12
|
+
caption?: string;
|
|
13
|
+
};
|
|
@@ -1,26 +1,14 @@
|
|
|
1
|
-
export { default as Button } from "./Button.svelte";
|
|
2
|
-
export { default as Card } from "./Card.svelte";
|
|
3
|
-
export { default as Badge } from "./Badge.svelte";
|
|
4
1
|
export { default as Dialog } from "./Dialog.svelte";
|
|
5
|
-
export { default as Input } from "./Input.svelte";
|
|
6
|
-
export { default as Textarea } from "./Textarea.svelte";
|
|
7
2
|
export { default as Select } from "./Select.svelte";
|
|
8
3
|
export { default as Tabs } from "./Tabs.svelte";
|
|
9
4
|
export { default as Accordion } from "./Accordion.svelte";
|
|
10
5
|
export { default as Sheet } from "./Sheet.svelte";
|
|
11
6
|
export { default as Toast } from "./Toast.svelte";
|
|
12
|
-
export { default as Skeleton } from "./Skeleton.svelte";
|
|
13
7
|
export { default as Table } from "./Table.svelte";
|
|
14
8
|
export { toast } from "./toast";
|
|
15
9
|
export { Root as DialogRoot, Trigger as DialogTrigger, Close as DialogClose, Portal as DialogPortal } from "./dialog";
|
|
16
10
|
export { Root as SheetRoot, Trigger as SheetTrigger, Close as SheetClose, Portal as SheetPortal, Content as SheetContent, Header as SheetHeader, Footer as SheetFooter, Title as SheetTitle, Description as SheetDescription } from "./sheet";
|
|
17
11
|
export { Root as TableRoot, Body as TableBody, Caption as TableCaption, Cell as TableCell, Footer as TableFooter, Head as TableHead, Header as TableHeader, Row as TableRow } from "./table";
|
|
18
|
-
export { Root as SkeletonRoot, Skeleton as SkeletonComponent } from "./skeleton";
|
|
19
12
|
export { Root as AccordionRoot } from "./accordion";
|
|
20
|
-
export { Root as BadgeRoot } from "./badge";
|
|
21
|
-
export { Root as ButtonRoot } from "./button";
|
|
22
|
-
export { Root as CardRoot, Header as CardHeader, Title as CardTitle, Description as CardDescription, Content as CardContent, Footer as CardFooter } from "./card";
|
|
23
|
-
export { Root as InputRoot } from "./input";
|
|
24
|
-
export { Root as TextareaRoot } from "./textarea";
|
|
25
13
|
export { Root as SelectRoot, Trigger as SelectTrigger, Content as SelectContent, Item as SelectItem, Group as SelectGroup, GroupHeading as SelectLabel, Separator as SelectSeparator, ScrollUpButton as SelectScrollUpButton, ScrollDownButton as SelectScrollDownButton } from "./select";
|
|
26
14
|
export { Root as TabsRoot, List as TabsList, Trigger as TabsTrigger, Content as TabsContent } from "./tabs";
|
|
@@ -1,16 +1,11 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
3
|
-
export { default as Card } from "./Card.svelte";
|
|
4
|
-
export { default as Badge } from "./Badge.svelte";
|
|
1
|
+
// Admin-specific UI component wrappers
|
|
2
|
+
// Generic UI components (Button, Card, Badge, Input, Textarea, Skeleton) are now in @groveengine/ui
|
|
5
3
|
export { default as Dialog } from "./Dialog.svelte";
|
|
6
|
-
export { default as Input } from "./Input.svelte";
|
|
7
|
-
export { default as Textarea } from "./Textarea.svelte";
|
|
8
4
|
export { default as Select } from "./Select.svelte";
|
|
9
5
|
export { default as Tabs } from "./Tabs.svelte";
|
|
10
6
|
export { default as Accordion } from "./Accordion.svelte";
|
|
11
7
|
export { default as Sheet } from "./Sheet.svelte";
|
|
12
8
|
export { default as Toast } from "./Toast.svelte";
|
|
13
|
-
export { default as Skeleton } from "./Skeleton.svelte";
|
|
14
9
|
export { default as Table } from "./Table.svelte";
|
|
15
10
|
// Toast utilities
|
|
16
11
|
export { toast } from "./toast";
|
|
@@ -18,12 +13,6 @@ export { toast } from "./toast";
|
|
|
18
13
|
export { Root as DialogRoot, Trigger as DialogTrigger, Close as DialogClose, Portal as DialogPortal } from "./dialog";
|
|
19
14
|
export { Root as SheetRoot, Trigger as SheetTrigger, Close as SheetClose, Portal as SheetPortal, Content as SheetContent, Header as SheetHeader, Footer as SheetFooter, Title as SheetTitle, Description as SheetDescription } from "./sheet";
|
|
20
15
|
export { Root as TableRoot, Body as TableBody, Caption as TableCaption, Cell as TableCell, Footer as TableFooter, Head as TableHead, Header as TableHeader, Row as TableRow } from "./table";
|
|
21
|
-
export { Root as SkeletonRoot, Skeleton as SkeletonComponent } from "./skeleton";
|
|
22
16
|
export { Root as AccordionRoot } from "./accordion";
|
|
23
|
-
export { Root as BadgeRoot } from "./badge";
|
|
24
|
-
export { Root as ButtonRoot } from "./button";
|
|
25
|
-
export { Root as CardRoot, Header as CardHeader, Title as CardTitle, Description as CardDescription, Content as CardContent, Footer as CardFooter } from "./card";
|
|
26
|
-
export { Root as InputRoot } from "./input";
|
|
27
|
-
export { Root as TextareaRoot } from "./textarea";
|
|
28
17
|
export { Root as SelectRoot, Trigger as SelectTrigger, Content as SelectContent, Item as SelectItem, Group as SelectGroup, GroupHeading as SelectLabel, Separator as SelectSeparator, ScrollUpButton as SelectScrollUpButton, ScrollDownButton as SelectScrollDownButton } from "./select";
|
|
29
18
|
export { Root as TabsRoot, List as TabsList, Trigger as TabsTrigger, Content as TabsContent } from "./tabs";
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import
|
|
3
|
-
import { Separator } from "../separator/index.js";
|
|
2
|
+
import { Separator as SeparatorPrimitive } from "bits-ui";
|
|
4
3
|
import { cn } from "../../../utils";
|
|
5
4
|
|
|
6
5
|
let {
|
|
@@ -10,4 +9,4 @@
|
|
|
10
9
|
}: SeparatorPrimitive.RootProps = $props();
|
|
11
10
|
</script>
|
|
12
11
|
|
|
13
|
-
<
|
|
12
|
+
<SeparatorPrimitive.Root bind:ref class={cn("bg-muted -mx-1 my-1 h-px", className)} {...restProps} />
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Separator as SeparatorPrimitive } from "bits-ui";
|
|
2
2
|
declare const SelectSeparator: import("svelte").Component<SeparatorPrimitive.RootProps, {}, "ref">;
|
|
3
3
|
type SelectSeparator = ReturnType<typeof SelectSeparator>;
|
|
4
4
|
export default SelectSeparator;
|
package/dist/utils/markdown.d.ts
CHANGED
|
@@ -121,3 +121,45 @@ export function createContentLoader(config: {
|
|
|
121
121
|
homeGutter: Object;
|
|
122
122
|
contactGutter: Object;
|
|
123
123
|
}): Object;
|
|
124
|
+
/**
|
|
125
|
+
* Register a content loader for the site
|
|
126
|
+
* This should be called by the consuming site to provide access to content
|
|
127
|
+
* @param {Object} loader - Object with getAllPosts, getSiteConfig, getLatestPost functions
|
|
128
|
+
*/
|
|
129
|
+
export function registerContentLoader(loader: Object): void;
|
|
130
|
+
/**
|
|
131
|
+
* Get all blog posts
|
|
132
|
+
* @returns {Array} Array of post objects
|
|
133
|
+
*/
|
|
134
|
+
export function getAllPosts(): any[];
|
|
135
|
+
/**
|
|
136
|
+
* Get site configuration
|
|
137
|
+
* @returns {Object} Site config object
|
|
138
|
+
*/
|
|
139
|
+
export function getSiteConfig(): Object;
|
|
140
|
+
/**
|
|
141
|
+
* Get the latest post
|
|
142
|
+
* @returns {Object|null} Latest post or null
|
|
143
|
+
*/
|
|
144
|
+
export function getLatestPost(): Object | null;
|
|
145
|
+
/**
|
|
146
|
+
* Get home page content
|
|
147
|
+
* @returns {Object|null} Home page data or null
|
|
148
|
+
*/
|
|
149
|
+
export function getHomePage(): Object | null;
|
|
150
|
+
/**
|
|
151
|
+
* Get a post by its slug
|
|
152
|
+
* @param {string} slug - The post slug
|
|
153
|
+
* @returns {Object|null} Post object or null
|
|
154
|
+
*/
|
|
155
|
+
export function getPostBySlug(slug: string): Object | null;
|
|
156
|
+
/**
|
|
157
|
+
* Get about page content
|
|
158
|
+
* @returns {Object|null} About page data or null
|
|
159
|
+
*/
|
|
160
|
+
export function getAboutPage(): Object | null;
|
|
161
|
+
/**
|
|
162
|
+
* Get contact page content
|
|
163
|
+
* @returns {Object|null} Contact page data or null
|
|
164
|
+
*/
|
|
165
|
+
export function getContactPage(): Object | null;
|
package/dist/utils/markdown.js
CHANGED
|
@@ -755,3 +755,107 @@ export function createContentLoader(config) {
|
|
|
755
755
|
},
|
|
756
756
|
};
|
|
757
757
|
}
|
|
758
|
+
|
|
759
|
+
/**
|
|
760
|
+
* Registry for site-specific content loaders
|
|
761
|
+
* Sites must register their content loaders using registerContentLoader()
|
|
762
|
+
*/
|
|
763
|
+
let contentLoader = null;
|
|
764
|
+
|
|
765
|
+
/**
|
|
766
|
+
* Register a content loader for the site
|
|
767
|
+
* This should be called by the consuming site to provide access to content
|
|
768
|
+
* @param {Object} loader - Object with getAllPosts, getSiteConfig, getLatestPost functions
|
|
769
|
+
*/
|
|
770
|
+
export function registerContentLoader(loader) {
|
|
771
|
+
contentLoader = loader;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
/**
|
|
775
|
+
* Get all blog posts
|
|
776
|
+
* @returns {Array} Array of post objects
|
|
777
|
+
*/
|
|
778
|
+
export function getAllPosts() {
|
|
779
|
+
if (!contentLoader || !contentLoader.getAllPosts) {
|
|
780
|
+
console.warn('getAllPosts: No content loader registered. Call registerContentLoader() in your site.');
|
|
781
|
+
return [];
|
|
782
|
+
}
|
|
783
|
+
return contentLoader.getAllPosts();
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
/**
|
|
787
|
+
* Get site configuration
|
|
788
|
+
* @returns {Object} Site config object
|
|
789
|
+
*/
|
|
790
|
+
export function getSiteConfig() {
|
|
791
|
+
if (!contentLoader || !contentLoader.getSiteConfig) {
|
|
792
|
+
console.warn('getSiteConfig: No content loader registered. Call registerContentLoader() in your site.');
|
|
793
|
+
return {
|
|
794
|
+
owner: { name: "Admin", email: "" },
|
|
795
|
+
site: { title: "GroveEngine Site", description: "", copyright: "" },
|
|
796
|
+
social: {},
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
return contentLoader.getSiteConfig();
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
/**
|
|
803
|
+
* Get the latest post
|
|
804
|
+
* @returns {Object|null} Latest post or null
|
|
805
|
+
*/
|
|
806
|
+
export function getLatestPost() {
|
|
807
|
+
if (!contentLoader || !contentLoader.getLatestPost) {
|
|
808
|
+
console.warn('getLatestPost: No content loader registered. Call registerContentLoader() in your site.');
|
|
809
|
+
return null;
|
|
810
|
+
}
|
|
811
|
+
return contentLoader.getLatestPost();
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
/**
|
|
815
|
+
* Get home page content
|
|
816
|
+
* @returns {Object|null} Home page data or null
|
|
817
|
+
*/
|
|
818
|
+
export function getHomePage() {
|
|
819
|
+
if (!contentLoader || !contentLoader.getHomePage) {
|
|
820
|
+
console.warn('getHomePage: No content loader registered. Call registerContentLoader() in your site.');
|
|
821
|
+
return null;
|
|
822
|
+
}
|
|
823
|
+
return contentLoader.getHomePage();
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
/**
|
|
827
|
+
* Get a post by its slug
|
|
828
|
+
* @param {string} slug - The post slug
|
|
829
|
+
* @returns {Object|null} Post object or null
|
|
830
|
+
*/
|
|
831
|
+
export function getPostBySlug(slug) {
|
|
832
|
+
if (!contentLoader || !contentLoader.getPostBySlug) {
|
|
833
|
+
console.warn('getPostBySlug: No content loader registered. Call registerContentLoader() in your site.');
|
|
834
|
+
return null;
|
|
835
|
+
}
|
|
836
|
+
return contentLoader.getPostBySlug(slug);
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
/**
|
|
840
|
+
* Get about page content
|
|
841
|
+
* @returns {Object|null} About page data or null
|
|
842
|
+
*/
|
|
843
|
+
export function getAboutPage() {
|
|
844
|
+
if (!contentLoader || !contentLoader.getAboutPage) {
|
|
845
|
+
console.warn('getAboutPage: No content loader registered. Call registerContentLoader() in your site.');
|
|
846
|
+
return null;
|
|
847
|
+
}
|
|
848
|
+
return contentLoader.getAboutPage();
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
/**
|
|
852
|
+
* Get contact page content
|
|
853
|
+
* @returns {Object|null} Contact page data or null
|
|
854
|
+
*/
|
|
855
|
+
export function getContactPage() {
|
|
856
|
+
if (!contentLoader || !contentLoader.getContactPage) {
|
|
857
|
+
console.warn('getContactPage: No content loader registered. Call registerContentLoader() in your site.');
|
|
858
|
+
return null;
|
|
859
|
+
}
|
|
860
|
+
return contentLoader.getContactPage();
|
|
861
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autumnsgrove/groveengine",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Multi-tenant blog engine for Grove Platform. Features gutter annotations, markdown editing, magic code auth, and Cloudflare Workers deployment.",
|
|
5
5
|
"author": "AutumnsGrove",
|
|
6
6
|
"license": "MIT",
|
|
@@ -114,6 +114,7 @@
|
|
|
114
114
|
"vitest": "^4.0.14"
|
|
115
115
|
},
|
|
116
116
|
"dependencies": {
|
|
117
|
+
"@groveengine/ui": "^0.3.0",
|
|
117
118
|
"@types/dompurify": "^3.0.5",
|
|
118
119
|
"chart.js": "^4.5.1",
|
|
119
120
|
"clsx": "^2.1.1",
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { Badge as ShadcnBadge } from "./badge";
|
|
3
|
-
import type { Snippet } from "svelte";
|
|
4
|
-
|
|
5
|
-
type BadgeVariant = "default" | "secondary" | "destructive" | "tag";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Badge component wrapper for displaying small labels, tags, or status indicators
|
|
9
|
-
*
|
|
10
|
-
* @prop {BadgeVariant} [variant="default"] - Badge style variant (default|secondary|destructive|tag)
|
|
11
|
-
* @prop {string} [class] - Additional CSS classes to apply
|
|
12
|
-
* @prop {Snippet} [children] - Badge content (typically short text)
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* <Badge variant="default">New</Badge>
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* <Badge variant="destructive">Error</Badge>
|
|
19
|
-
*
|
|
20
|
-
* @example
|
|
21
|
-
* <Badge variant="tag">TypeScript</Badge>
|
|
22
|
-
*/
|
|
23
|
-
interface Props {
|
|
24
|
-
variant?: BadgeVariant;
|
|
25
|
-
class?: string;
|
|
26
|
-
children?: Snippet;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
let {
|
|
30
|
-
variant = "default",
|
|
31
|
-
class: className,
|
|
32
|
-
children
|
|
33
|
-
}: Props = $props();
|
|
34
|
-
|
|
35
|
-
// Map tag variant to secondary styling
|
|
36
|
-
const variantMap: Record<BadgeVariant, "default" | "secondary" | "destructive"> = {
|
|
37
|
-
default: "default",
|
|
38
|
-
secondary: "secondary",
|
|
39
|
-
destructive: "destructive",
|
|
40
|
-
tag: "secondary"
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const shadcnVariant = $derived(variantMap[variant]);
|
|
44
|
-
</script>
|
|
45
|
-
|
|
46
|
-
<ShadcnBadge variant={shadcnVariant} class={className}>
|
|
47
|
-
{@render children?.()}
|
|
48
|
-
</ShadcnBadge>
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { Snippet } from "svelte";
|
|
2
|
-
type BadgeVariant = "default" | "secondary" | "destructive" | "tag";
|
|
3
|
-
/**
|
|
4
|
-
* Badge component wrapper for displaying small labels, tags, or status indicators
|
|
5
|
-
*
|
|
6
|
-
* @prop {BadgeVariant} [variant="default"] - Badge style variant (default|secondary|destructive|tag)
|
|
7
|
-
* @prop {string} [class] - Additional CSS classes to apply
|
|
8
|
-
* @prop {Snippet} [children] - Badge content (typically short text)
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* <Badge variant="default">New</Badge>
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* <Badge variant="destructive">Error</Badge>
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* <Badge variant="tag">TypeScript</Badge>
|
|
18
|
-
*/
|
|
19
|
-
interface Props {
|
|
20
|
-
variant?: BadgeVariant;
|
|
21
|
-
class?: string;
|
|
22
|
-
children?: Snippet;
|
|
23
|
-
}
|
|
24
|
-
declare const Badge: import("svelte").Component<Props, {}, "">;
|
|
25
|
-
type Badge = ReturnType<typeof Badge>;
|
|
26
|
-
export default Badge;
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { Button as ShadcnButton } from "./button";
|
|
3
|
-
import type { Snippet } from "svelte";
|
|
4
|
-
import type { HTMLButtonAttributes } from "svelte/elements";
|
|
5
|
-
|
|
6
|
-
type ButtonVariant = "primary" | "secondary" | "danger" | "ghost" | "link";
|
|
7
|
-
type ButtonSize = "sm" | "md" | "lg";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Button component wrapper around shadcn-svelte Button
|
|
11
|
-
*
|
|
12
|
-
* @prop {ButtonVariant} [variant="primary"] - Button style variant (primary|secondary|danger|ghost|link)
|
|
13
|
-
* @prop {ButtonSize} [size="md"] - Button size (sm|md|lg)
|
|
14
|
-
* @prop {boolean} [disabled=false] - Whether button is disabled
|
|
15
|
-
* @prop {Function} [onclick] - Click handler function
|
|
16
|
-
* @prop {string} [href] - Optional link href (renders as anchor element)
|
|
17
|
-
* @prop {string} [class] - Additional CSS classes to apply
|
|
18
|
-
* @prop {Snippet} [children] - Button content (text/icons/etc)
|
|
19
|
-
*
|
|
20
|
-
* @example
|
|
21
|
-
* <Button variant="primary" size="lg">Save Changes</Button>
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* <Button variant="danger" onclick={() => handleDelete()}>Delete</Button>
|
|
25
|
-
*
|
|
26
|
-
* @example
|
|
27
|
-
* <Button variant="ghost" href="/settings">Settings</Button>
|
|
28
|
-
*/
|
|
29
|
-
interface Props extends Omit<HTMLButtonAttributes, "class"> {
|
|
30
|
-
variant?: ButtonVariant;
|
|
31
|
-
size?: ButtonSize;
|
|
32
|
-
disabled?: boolean;
|
|
33
|
-
class?: string;
|
|
34
|
-
children?: Snippet;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
let {
|
|
38
|
-
variant = "primary",
|
|
39
|
-
size = "md",
|
|
40
|
-
disabled = false,
|
|
41
|
-
class: className,
|
|
42
|
-
children,
|
|
43
|
-
...restProps
|
|
44
|
-
}: Props = $props();
|
|
45
|
-
|
|
46
|
-
// Map our simplified variants to shadcn variants
|
|
47
|
-
const variantMap: Record<ButtonVariant, "default" | "secondary" | "destructive" | "ghost" | "link"> = {
|
|
48
|
-
primary: "default",
|
|
49
|
-
secondary: "secondary",
|
|
50
|
-
danger: "destructive",
|
|
51
|
-
ghost: "ghost",
|
|
52
|
-
link: "link"
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
// Map our size variants to shadcn sizes
|
|
56
|
-
const sizeMap: Record<ButtonSize, "sm" | "default" | "lg"> = {
|
|
57
|
-
sm: "sm",
|
|
58
|
-
md: "default",
|
|
59
|
-
lg: "lg"
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
const shadcnVariant = $derived(variantMap[variant]);
|
|
63
|
-
const shadcnSize = $derived(sizeMap[size]);
|
|
64
|
-
</script>
|
|
65
|
-
|
|
66
|
-
<ShadcnButton
|
|
67
|
-
variant={shadcnVariant}
|
|
68
|
-
size={shadcnSize}
|
|
69
|
-
disabled={disabled}
|
|
70
|
-
class={className}
|
|
71
|
-
{...restProps}
|
|
72
|
-
>
|
|
73
|
-
{@render children?.()}
|
|
74
|
-
</ShadcnButton>
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import type { Snippet } from "svelte";
|
|
2
|
-
import type { HTMLButtonAttributes } from "svelte/elements";
|
|
3
|
-
type ButtonVariant = "primary" | "secondary" | "danger" | "ghost" | "link";
|
|
4
|
-
type ButtonSize = "sm" | "md" | "lg";
|
|
5
|
-
/**
|
|
6
|
-
* Button component wrapper around shadcn-svelte Button
|
|
7
|
-
*
|
|
8
|
-
* @prop {ButtonVariant} [variant="primary"] - Button style variant (primary|secondary|danger|ghost|link)
|
|
9
|
-
* @prop {ButtonSize} [size="md"] - Button size (sm|md|lg)
|
|
10
|
-
* @prop {boolean} [disabled=false] - Whether button is disabled
|
|
11
|
-
* @prop {Function} [onclick] - Click handler function
|
|
12
|
-
* @prop {string} [href] - Optional link href (renders as anchor element)
|
|
13
|
-
* @prop {string} [class] - Additional CSS classes to apply
|
|
14
|
-
* @prop {Snippet} [children] - Button content (text/icons/etc)
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* <Button variant="primary" size="lg">Save Changes</Button>
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* <Button variant="danger" onclick={() => handleDelete()}>Delete</Button>
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* <Button variant="ghost" href="/settings">Settings</Button>
|
|
24
|
-
*/
|
|
25
|
-
interface Props extends Omit<HTMLButtonAttributes, "class"> {
|
|
26
|
-
variant?: ButtonVariant;
|
|
27
|
-
size?: ButtonSize;
|
|
28
|
-
disabled?: boolean;
|
|
29
|
-
class?: string;
|
|
30
|
-
children?: Snippet;
|
|
31
|
-
}
|
|
32
|
-
declare const Button: import("svelte").Component<Props, {}, "">;
|
|
33
|
-
type Button = ReturnType<typeof Button>;
|
|
34
|
-
export default Button;
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import {
|
|
3
|
-
Card as ShadcnCard,
|
|
4
|
-
CardHeader,
|
|
5
|
-
CardTitle,
|
|
6
|
-
CardDescription,
|
|
7
|
-
CardContent,
|
|
8
|
-
CardFooter
|
|
9
|
-
} from "./card";
|
|
10
|
-
import type { Snippet } from "svelte";
|
|
11
|
-
import { cn } from "../../utils";
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Card component wrapper providing structured layout with header, content, and footer
|
|
15
|
-
*
|
|
16
|
-
* @prop {string} [title] - Card title (renders in CardHeader with CardTitle)
|
|
17
|
-
* @prop {string} [description] - Card description (renders in CardHeader with CardDescription)
|
|
18
|
-
* @prop {boolean} [hoverable=false] - Enable hover shadow effect for interactive cards
|
|
19
|
-
* @prop {Snippet} [header] - Custom header content (overrides title/description)
|
|
20
|
-
* @prop {Snippet} [footer] - Footer content (rendered in CardFooter)
|
|
21
|
-
* @prop {Snippet} [children] - Main card content (rendered in CardContent)
|
|
22
|
-
* @prop {string} [class] - Additional CSS classes for Card root
|
|
23
|
-
*
|
|
24
|
-
* @example
|
|
25
|
-
* <Card title="Profile" description="Update your profile settings">
|
|
26
|
-
* <p>Card content here</p>
|
|
27
|
-
* </Card>
|
|
28
|
-
*
|
|
29
|
-
* @example
|
|
30
|
-
* <Card hoverable>
|
|
31
|
-
* {#snippet header()}
|
|
32
|
-
* <CustomHeader />
|
|
33
|
-
* {/snippet}
|
|
34
|
-
* Content here
|
|
35
|
-
* </Card>
|
|
36
|
-
*
|
|
37
|
-
* @example
|
|
38
|
-
* <Card title="Actions">
|
|
39
|
-
* {#snippet footer()}
|
|
40
|
-
* <Button>Save</Button>
|
|
41
|
-
* {/snippet}
|
|
42
|
-
* Form content
|
|
43
|
-
* </Card>
|
|
44
|
-
*/
|
|
45
|
-
interface Props {
|
|
46
|
-
title?: string;
|
|
47
|
-
description?: string;
|
|
48
|
-
hoverable?: boolean;
|
|
49
|
-
class?: string;
|
|
50
|
-
header?: Snippet;
|
|
51
|
-
footer?: Snippet;
|
|
52
|
-
children?: Snippet;
|
|
53
|
-
[key: string]: any; // Allow any additional props to be forwarded
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
let {
|
|
57
|
-
title,
|
|
58
|
-
description,
|
|
59
|
-
hoverable = false,
|
|
60
|
-
class: className,
|
|
61
|
-
header,
|
|
62
|
-
footer,
|
|
63
|
-
children,
|
|
64
|
-
...restProps
|
|
65
|
-
}: Props = $props();
|
|
66
|
-
|
|
67
|
-
const cardClass = $derived(
|
|
68
|
-
cn(
|
|
69
|
-
hoverable && "hover:shadow-lg transition-shadow cursor-pointer",
|
|
70
|
-
className
|
|
71
|
-
)
|
|
72
|
-
);
|
|
73
|
-
</script>
|
|
74
|
-
|
|
75
|
-
<ShadcnCard class={cardClass} {...restProps}>
|
|
76
|
-
{#if header || title || description}
|
|
77
|
-
<CardHeader>
|
|
78
|
-
{#if header}
|
|
79
|
-
{@render header()}
|
|
80
|
-
{:else}
|
|
81
|
-
{#if title}
|
|
82
|
-
<CardTitle>{title}</CardTitle>
|
|
83
|
-
{/if}
|
|
84
|
-
{#if description}
|
|
85
|
-
<CardDescription>{description}</CardDescription>
|
|
86
|
-
{/if}
|
|
87
|
-
{/if}
|
|
88
|
-
</CardHeader>
|
|
89
|
-
{/if}
|
|
90
|
-
|
|
91
|
-
{#if children}
|
|
92
|
-
<CardContent>
|
|
93
|
-
{@render children()}
|
|
94
|
-
</CardContent>
|
|
95
|
-
{/if}
|
|
96
|
-
|
|
97
|
-
{#if footer}
|
|
98
|
-
<CardFooter>
|
|
99
|
-
{@render footer()}
|
|
100
|
-
</CardFooter>
|
|
101
|
-
{/if}
|
|
102
|
-
</ShadcnCard>
|