includio-cms 0.0.31 → 0.0.32
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/admin/components/fields/relation-field.svelte +22 -8
- package/dist/admin/components/fields/relation-field.svelte.d.ts +6 -6
- package/dist/admin/components/fields/seo-field.svelte +40 -3
- package/dist/core/fields/fieldSchemaToTs.js +5 -1
- package/dist/core/server/generator/fields.js +5 -1
- package/dist/sveltekit/components/image.svelte +4 -3
- package/dist/sveltekit/components/image.svelte.d.ts +2 -2
- package/dist/sveltekit/components/seo.svelte +21 -5
- package/dist/sveltekit/components/seo.svelte.d.ts +2 -5
- package/dist/types/fields.d.ts +7 -3
- package/package.json +1 -1
|
@@ -14,13 +14,14 @@
|
|
|
14
14
|
import Button, { buttonVariants } from '../../../components/ui/button/button.svelte';
|
|
15
15
|
import { getCollectionEntryLabel } from '../../utils/entryLabel.js';
|
|
16
16
|
import { getContentLanguage } from '../../state/content-language.svelte.js';
|
|
17
|
-
import { tick } from 'svelte';
|
|
17
|
+
import { onMount, tick } from 'svelte';
|
|
18
18
|
import { useId } from 'bits-ui';
|
|
19
19
|
import * as Popover from '../../../components/ui/popover/index.js';
|
|
20
20
|
import * as Command from '../../../components/ui/command/index.js';
|
|
21
21
|
import { cn } from '../../../utils.js';
|
|
22
22
|
import Selector from '@tabler/icons-svelte/icons/selector';
|
|
23
23
|
import Check from '@tabler/icons-svelte/icons/check';
|
|
24
|
+
import type { CollectionConfigWithType } from '../../../types/collections.js';
|
|
24
25
|
|
|
25
26
|
const remotes = getRemotes();
|
|
26
27
|
|
|
@@ -32,19 +33,32 @@
|
|
|
32
33
|
|
|
33
34
|
let { field, form, path, ...props }: Props = $props();
|
|
34
35
|
|
|
35
|
-
let collectionConfig = await remotes.getCollection(field.collection);
|
|
36
|
-
|
|
37
36
|
const { value } = formFieldProxy(form, path) satisfies FormFieldProxy<RelationFieldData>;
|
|
38
37
|
|
|
39
|
-
|
|
38
|
+
let options = $state<{ label: string; value: string }[]>([]);
|
|
39
|
+
let collectionConfig = $state<CollectionConfigWithType | null>(null);
|
|
40
|
+
|
|
41
|
+
async function getCollectionConfig() {
|
|
42
|
+
collectionConfig = await remotes.getCollection(field.collection);
|
|
43
|
+
|
|
44
|
+
return collectionConfig;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function getOptionsQuery(config: CollectionConfigWithType) {
|
|
40
48
|
const entries = await remotes.getRawCollectionEntries(field.collection);
|
|
41
49
|
|
|
42
|
-
|
|
43
|
-
label: getCollectionEntryLabel(entry,
|
|
50
|
+
options = entries.map((entry) => ({
|
|
51
|
+
label: getCollectionEntryLabel(entry, config, getContentLanguage()),
|
|
44
52
|
value: entry.id
|
|
45
53
|
}));
|
|
46
54
|
}
|
|
47
55
|
|
|
56
|
+
onMount(() => {
|
|
57
|
+
getCollectionConfig().then((config) => {
|
|
58
|
+
getOptionsQuery(config);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
48
62
|
let open = $state(false);
|
|
49
63
|
|
|
50
64
|
// We want to refocus the trigger button when the user selects
|
|
@@ -59,7 +73,7 @@
|
|
|
59
73
|
const triggerId = useId();
|
|
60
74
|
</script>
|
|
61
75
|
|
|
62
|
-
{#
|
|
76
|
+
{#if options.length > 0 && collectionConfig}
|
|
63
77
|
<Popover.Root bind:open>
|
|
64
78
|
<Popover.Trigger
|
|
65
79
|
id={triggerId}
|
|
@@ -102,4 +116,4 @@
|
|
|
102
116
|
</Command.Root>
|
|
103
117
|
</Popover.Content>
|
|
104
118
|
</Popover.Root>
|
|
105
|
-
{/
|
|
119
|
+
{/if}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { RelationFieldData, RelationField } from '../../../types/fields.js';
|
|
2
2
|
import { type FormPathLeaves, type SuperForm } from 'sveltekit-superforms';
|
|
3
|
-
declare function $$render<T extends Record<string, unknown>>():
|
|
3
|
+
declare function $$render<T extends Record<string, unknown>>(): {
|
|
4
4
|
props: {
|
|
5
5
|
field: RelationField;
|
|
6
6
|
form: SuperForm<T>;
|
|
@@ -10,13 +10,13 @@ declare function $$render<T extends Record<string, unknown>>(): Promise<{
|
|
|
10
10
|
bindings: "";
|
|
11
11
|
slots: {};
|
|
12
12
|
events: {};
|
|
13
|
-
}
|
|
13
|
+
};
|
|
14
14
|
declare class __sveltets_Render<T extends Record<string, unknown>> {
|
|
15
|
-
props():
|
|
16
|
-
events():
|
|
17
|
-
slots():
|
|
15
|
+
props(): ReturnType<typeof $$render<T>>['props'];
|
|
16
|
+
events(): ReturnType<typeof $$render<T>>['events'];
|
|
17
|
+
slots(): ReturnType<typeof $$render<T>>['slots'];
|
|
18
18
|
bindings(): "";
|
|
19
|
-
exports():
|
|
19
|
+
exports(): {};
|
|
20
20
|
}
|
|
21
21
|
interface $$IsomorphicComponent {
|
|
22
22
|
new <T extends Record<string, unknown>>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import { joinPath } from '../../utils/objectPath.js';
|
|
14
14
|
import type {
|
|
15
15
|
Field,
|
|
16
|
+
ImageField,
|
|
16
17
|
ObjectFieldData,
|
|
17
18
|
SeoField,
|
|
18
19
|
SeoFieldData,
|
|
@@ -29,8 +30,6 @@
|
|
|
29
30
|
|
|
30
31
|
let { field, form, path, ...props }: Props = $props();
|
|
31
32
|
|
|
32
|
-
// const { value } = formFieldProxy(form, path) satisfies FormFieldProxy<SeoFieldData | undefined>;
|
|
33
|
-
|
|
34
33
|
const slugField: TextField = {
|
|
35
34
|
type: 'text',
|
|
36
35
|
slug: 'slug',
|
|
@@ -38,6 +37,13 @@
|
|
|
38
37
|
required: true
|
|
39
38
|
};
|
|
40
39
|
|
|
40
|
+
const canonicalUrlField: TextField = {
|
|
41
|
+
type: 'text',
|
|
42
|
+
slug: 'canonicalUrl',
|
|
43
|
+
label: 'Canonical Url',
|
|
44
|
+
required: false
|
|
45
|
+
};
|
|
46
|
+
|
|
41
47
|
const titleField: TextField = {
|
|
42
48
|
type: 'text',
|
|
43
49
|
slug: 'title',
|
|
@@ -53,7 +59,38 @@
|
|
|
53
59
|
multiline: true
|
|
54
60
|
};
|
|
55
61
|
|
|
56
|
-
const
|
|
62
|
+
const keyWordsField: TextField = {
|
|
63
|
+
type: 'text',
|
|
64
|
+
slug: 'keywords',
|
|
65
|
+
label: 'Keywords',
|
|
66
|
+
required: false,
|
|
67
|
+
multiline: true
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const ogImageField: ImageField = {
|
|
71
|
+
type: 'image',
|
|
72
|
+
slug: 'ogImage',
|
|
73
|
+
label: 'Open Graph Image',
|
|
74
|
+
required: false
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const customCodeField: TextField = {
|
|
78
|
+
type: 'text',
|
|
79
|
+
slug: 'customCode',
|
|
80
|
+
label: 'Custom Code',
|
|
81
|
+
required: false,
|
|
82
|
+
multiline: true
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const fields: Field[] = [
|
|
86
|
+
slugField,
|
|
87
|
+
canonicalUrlField,
|
|
88
|
+
titleField,
|
|
89
|
+
descriptionField,
|
|
90
|
+
keyWordsField,
|
|
91
|
+
ogImageField,
|
|
92
|
+
customCodeField
|
|
93
|
+
];
|
|
57
94
|
</script>
|
|
58
95
|
|
|
59
96
|
<Item.Root variant="outline">
|
|
@@ -87,8 +87,12 @@ export function generateZodSchemaFromField(field, languages, options = {
|
|
|
87
87
|
case 'seo': {
|
|
88
88
|
return z.object({
|
|
89
89
|
slug: z.object(Object.fromEntries(languages.map((lang) => [lang, z.string()]))),
|
|
90
|
+
canonicalUrl: z.object(Object.fromEntries(languages.map((lang) => [lang, z.string().optional()]))),
|
|
90
91
|
title: z.object(Object.fromEntries(languages.map((lang) => [lang, z.string()]))),
|
|
91
|
-
description: z.object(Object.fromEntries(languages.map((lang) => [lang, z.string()])))
|
|
92
|
+
description: z.object(Object.fromEntries(languages.map((lang) => [lang, z.string()]))),
|
|
93
|
+
keywords: z.object(Object.fromEntries(languages.map((lang) => [lang, z.string().optional()]))),
|
|
94
|
+
ogImage: z.string(),
|
|
95
|
+
customCode: z.object(Object.fromEntries(languages.map((lang) => [lang, z.string().optional()])))
|
|
92
96
|
});
|
|
93
97
|
}
|
|
94
98
|
case 'url': {
|
|
@@ -47,8 +47,12 @@ function getFieldTypeAsString(field) {
|
|
|
47
47
|
case 'seo':
|
|
48
48
|
return `{
|
|
49
49
|
slug?: string;
|
|
50
|
+
canonicalUrl?: string;
|
|
50
51
|
title?: string;
|
|
51
52
|
description?: string;
|
|
53
|
+
ogImage?: string;
|
|
54
|
+
keywords?: string;
|
|
55
|
+
customCode?: string;
|
|
52
56
|
}`;
|
|
53
57
|
case 'url':
|
|
54
58
|
return 'string';
|
|
@@ -58,6 +62,6 @@ function getFieldTypeAsString(field) {
|
|
|
58
62
|
}
|
|
59
63
|
export function generateTsTypeFromFields(fields) {
|
|
60
64
|
return `{
|
|
61
|
-
${fields.map((f) => ` ${f.slug}${f.required ? '' : '?'}: ${getFieldTypeAsString(f)}`).join(';\n')};
|
|
65
|
+
${fields.map((f) => ` ${f.slug}${f.required || f.type === 'seo' ? '' : '?'}: ${getFieldTypeAsString(f)}`).join(';\n')};
|
|
62
66
|
}`;
|
|
63
67
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { MediaFile } from '../../types/media.js';
|
|
3
|
+
import type { HTMLImgAttributes } from 'svelte/elements';
|
|
3
4
|
|
|
4
|
-
type Props = {
|
|
5
|
-
class?: string;
|
|
5
|
+
type Props = HTMLImgAttributes & {
|
|
6
6
|
data: MediaFile;
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
-
let { class: className = undefined, data }: Props = $props();
|
|
9
|
+
let { class: className = undefined, data, ...restProps }: Props = $props();
|
|
10
10
|
</script>
|
|
11
11
|
|
|
12
12
|
<img
|
|
@@ -16,4 +16,5 @@
|
|
|
16
16
|
width={data.width}
|
|
17
17
|
height={data.height}
|
|
18
18
|
loading="lazy"
|
|
19
|
+
{...restProps}
|
|
19
20
|
/>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { MediaFile } from '../../types/media.js';
|
|
2
|
-
type
|
|
3
|
-
|
|
2
|
+
import type { HTMLImgAttributes } from 'svelte/elements';
|
|
3
|
+
type Props = HTMLImgAttributes & {
|
|
4
4
|
data: MediaFile;
|
|
5
5
|
};
|
|
6
6
|
declare const Image: import("svelte").Component<Props, {}, "">;
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
type
|
|
3
|
-
title?: string;
|
|
4
|
-
description?: string;
|
|
5
|
-
};
|
|
2
|
+
import type { SeoFieldData } from '../../types/fields.js';
|
|
6
3
|
|
|
7
|
-
let { title, description }:
|
|
4
|
+
let { title, description, keywords, ogImage, customCode, canonicalUrl }: SeoFieldData = $props();
|
|
8
5
|
</script>
|
|
9
6
|
|
|
10
7
|
<svelte:head>
|
|
@@ -15,4 +12,23 @@
|
|
|
15
12
|
{#if description}
|
|
16
13
|
<meta name="description" content={description} />
|
|
17
14
|
{/if}
|
|
15
|
+
{#if keywords}
|
|
16
|
+
<meta name="keywords" content={keywords} />
|
|
17
|
+
{/if}
|
|
18
|
+
{#if canonicalUrl}
|
|
19
|
+
<link rel="canonical" href={canonicalUrl} />
|
|
20
|
+
{/if}
|
|
21
|
+
{#if title}
|
|
22
|
+
<meta property="og:title" content={title} />
|
|
23
|
+
{/if}
|
|
24
|
+
{#if description}
|
|
25
|
+
<meta property="og:description" content={description} />
|
|
26
|
+
{/if}
|
|
27
|
+
{#if ogImage}
|
|
28
|
+
<meta property="og:image" content={ogImage} />
|
|
29
|
+
<meta name="twitter:card" content="summary_large_image" />
|
|
30
|
+
{/if}
|
|
31
|
+
{#if customCode}
|
|
32
|
+
{@html customCode}
|
|
33
|
+
{/if}
|
|
18
34
|
</svelte:head>
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
type
|
|
2
|
-
|
|
3
|
-
description?: string;
|
|
4
|
-
};
|
|
5
|
-
declare const Seo: import("svelte").Component<Props, {}, "">;
|
|
1
|
+
import type { SeoFieldData } from '../../types/fields.js';
|
|
2
|
+
declare const Seo: import("svelte").Component<SeoFieldData, {}, "">;
|
|
6
3
|
type Seo = ReturnType<typeof Seo>;
|
|
7
4
|
export default Seo;
|
package/dist/types/fields.d.ts
CHANGED
|
@@ -122,9 +122,13 @@ export interface SeoField extends BaseField {
|
|
|
122
122
|
type: 'seo';
|
|
123
123
|
}
|
|
124
124
|
export interface SeoFieldData {
|
|
125
|
-
slug:
|
|
126
|
-
|
|
127
|
-
|
|
125
|
+
slug: string;
|
|
126
|
+
canonicalUrl?: string;
|
|
127
|
+
title: string;
|
|
128
|
+
description?: string;
|
|
129
|
+
ogImage?: string;
|
|
130
|
+
keywords?: string;
|
|
131
|
+
customCode?: string;
|
|
128
132
|
}
|
|
129
133
|
export interface UrlField extends BaseField {
|
|
130
134
|
type: 'url';
|