rimecms 0.26.9 → 0.27.1
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/README.md +26 -24
- package/dist/core/collections/auth/fields.d.ts +40 -40
- package/dist/core/fields/builders/select.js +1 -0
- package/dist/core/i18n/en/fields.d.ts +1 -0
- package/dist/core/i18n/en/fields.js +2 -1
- package/dist/core/i18n/fr/fields.d.ts +1 -0
- package/dist/core/i18n/fr/fields.js +2 -1
- package/dist/core/operations/hooks/before-read/set-document-thumbnail.server.js +2 -2
- package/dist/core/operations/hooks/before-read/sort-document-props.server.js +3 -1
- package/dist/fields/group/component/Group.svelte +1 -0
- package/dist/fields/group/index.d.ts +12 -8
- package/dist/fields/group/index.js +4 -0
- package/dist/fields/link/component/RessourceInput.svelte +2 -2
- package/dist/fields/relation/component/Cell.svelte +2 -2
- package/dist/fields/relation/component/Relation.svelte +18 -11
- package/dist/fields/relation/component/Relation.svelte.d.ts +2 -1
- package/dist/fields/relation/component/upload/Browse.svelte +2 -2
- package/dist/fields/relation/index.d.ts +1 -1
- package/dist/fields/rich-text/client.d.ts +9 -9
- package/dist/fields/rich-text/client.js +1 -1
- package/dist/fields/rich-text/component/RichText.svelte +1 -1
- package/dist/fields/rich-text/core/{config-builders.js → build-editor-config.js} +9 -2
- package/dist/fields/rich-text/core/features/fields/extension.d.ts +10 -3
- package/dist/fields/rich-text/core/features/fields/extension.js +3 -8
- package/dist/fields/rich-text/core/features/fields/fields.css +4 -0
- package/dist/fields/rich-text/core/features/fields/fields.svelte +13 -6
- package/dist/fields/rich-text/core/features/fields/fields.svelte.d.ts +4 -1
- package/dist/fields/rich-text/core/features/fields/index.d.ts +7 -5
- package/dist/fields/rich-text/core/features/fields/index.js +4 -3
- package/dist/fields/rich-text/core/features/link/component/link-selector.svelte +9 -13
- package/dist/fields/rich-text/core/features/link/index.d.ts +1 -4
- package/dist/fields/rich-text/core/features/resource/index.d.ts +2 -5
- package/dist/fields/rich-text/core/features/resource/index.js +17 -12
- package/dist/fields/rich-text/core/features/resource/resource-extension.d.ts +7 -2
- package/dist/fields/rich-text/core/features/resource/resource-extension.js +6 -10
- package/dist/fields/rich-text/core/features/resource/resource.svelte +19 -21
- package/dist/fields/rich-text/core/features/upload/index.d.ts +2 -5
- package/dist/fields/rich-text/core/features/upload/index.js +15 -12
- package/dist/fields/rich-text/core/features/upload/upload-extension.d.ts +13 -1
- package/dist/fields/rich-text/core/features/upload/upload-extension.js +6 -11
- package/dist/fields/rich-text/core/features/upload/upload.svelte +15 -10
- package/dist/fields/rich-text/core/svelte/node-view-renderer.svelte.js +10 -5
- package/dist/fields/rich-text/core/svelte/node-view-wrapper.svelte +1 -0
- package/dist/fields/rich-text/core/svelte/renderer.d.ts +1 -1
- package/dist/fields/types.d.ts +13 -0
- package/dist/panel/components/Root.svelte +4 -4
- package/dist/panel/components/fields/FieldsPreview.svelte +34 -27
- package/dist/panel/components/fields/FieldsPreview.svelte.d.ts +5 -6
- package/dist/panel/components/fields/FieldsPreviewTrigger.svelte +1 -1
- package/dist/panel/components/fields/index.d.ts +2 -2
- package/dist/panel/components/sections/collection/folder/FolderEdit.svelte +0 -2
- package/dist/panel/components/sections/collection/folder/FolderWithActions.svelte +2 -2
- package/dist/panel/components/sections/collection/grid/create-directory-dialog/CreateDirectoryDialog.svelte +0 -2
- package/dist/panel/components/sections/collection/upload-thumb-cell/UploadThumbCell.svelte +3 -2
- package/dist/panel/components/sections/document/Header.svelte +1 -0
- package/dist/panel/components/sections/document/Settings.svelte +3 -2
- package/dist/panel/components/sections/document/Settings.svelte.d.ts +2 -1
- package/dist/panel/components/sections/document/upload-header/UploadHeader.svelte +2 -7
- package/dist/panel/components/sections/live/SidePanel.svelte +7 -9
- package/dist/panel/components/ui/breadcrumb/BreadCrumb.svelte +12 -6
- package/dist/panel/components/ui/card-document/card-document.svelte +2 -2
- package/dist/panel/components/ui/command/command-dialog.svelte +3 -1
- package/dist/panel/components/ui/command/command-dialog.svelte.d.ts +1 -0
- package/dist/panel/context/api-proxy.svelte.d.ts +2 -1
- package/dist/panel/context/api-proxy.svelte.js +9 -3
- package/dist/panel/context/documentForm.svelte.d.ts +2 -2
- package/dist/panel/context/documentForm.svelte.js +7 -6
- package/dist/panel/context/form.svelte.js +0 -1
- package/dist/panel/context/locale.svelte.d.ts +1 -0
- package/dist/panel/context/locale.svelte.js +3 -3
- package/dist/panel/context/title.d.ts +7 -0
- package/dist/panel/context/title.js +9 -0
- package/dist/panel/pages/area/Area.svelte +1 -4
- package/dist/panel/pages/area/AreaVersionsDoc.svelte +0 -3
- package/dist/panel/pages/collection/Collection.svelte +2 -2
- package/dist/panel/pages/collection-document/CollectionDocVersions.svelte +0 -5
- package/dist/panel/pages/collection-document/CollectionDocument.svelte +0 -3
- package/dist/panel/pages/live/Live.svelte +3 -8
- package/dist/types.d.ts +1 -1
- package/package.json +4 -4
- /package/dist/fields/rich-text/core/{config-builders.d.ts → build-editor-config.d.ts} +0 -0
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
import type { Level } from '@tiptap/extension-heading';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { type FieldsFeatureOptions } from './core/features/fields/index.js';
|
|
3
|
+
import { type LinkFeatureOptions } from './core/features/link/index.js';
|
|
4
|
+
import type { ResourceFeatureExtensionOptions } from './core/features/resource/resource-extension.js';
|
|
5
5
|
import type { RichTextResource } from './core/features/resource/types.js';
|
|
6
|
-
import {
|
|
6
|
+
import type { UploadFeatureExtensionOptions } from './core/features/upload/upload-extension.js';
|
|
7
7
|
import RenderRichText from './core/render-rich-text.svelte';
|
|
8
8
|
import SvelteNodeViewRenderer from './core/svelte/node-view-renderer.svelte';
|
|
9
9
|
import NodeViewWrapper from './core/svelte/node-view-wrapper.svelte';
|
|
10
10
|
import type { RichTextNodeRenderer, RichTextNodeRendererProps } from './core/types.js';
|
|
11
11
|
import { richTextJSONToText } from './index.js';
|
|
12
|
-
export declare const fields: (args:
|
|
12
|
+
export declare const fields: (args: FieldsFeatureOptions) => import("./core/types.js").RichTextFeature;
|
|
13
13
|
export declare const bold: () => import("./core/types.js").RichTextFeature;
|
|
14
14
|
export declare const bulletList: () => import("./core/types.js").RichTextFeature;
|
|
15
15
|
export declare const heading: (...levels: Level[]) => import("./core/types.js").RichTextFeature;
|
|
16
16
|
export declare const hr: () => import("./core/types.js").RichTextFeature;
|
|
17
|
-
export declare const link: (options?:
|
|
17
|
+
export declare const link: (options?: Partial<LinkFeatureOptions>) => import("./core/types.js").RichTextFeature;
|
|
18
18
|
export declare const paragraph: () => import("./core/types.js").RichTextFeature;
|
|
19
|
-
export declare const
|
|
19
|
+
export declare const orderedList: () => import("./core/types.js").RichTextFeature;
|
|
20
20
|
export declare const blockquote: () => import("./core/types.js").RichTextFeature;
|
|
21
21
|
export declare const italic: () => import("./core/types.js").RichTextFeature;
|
|
22
|
-
export declare const upload: (args:
|
|
23
|
-
export declare const resource: (args:
|
|
22
|
+
export declare const upload: (args: UploadFeatureExtensionOptions) => import("./core/types.js").RichTextFeature;
|
|
23
|
+
export declare const resource: (args: ResourceFeatureExtensionOptions) => import("./core/types.js").RichTextFeature;
|
|
24
24
|
export { NodeViewWrapper, RenderRichText, richTextJSONToText, SvelteNodeViewRenderer };
|
|
25
25
|
export type { RichTextNodeRenderer, RichTextNodeRendererProps, RichTextResource };
|
|
@@ -21,7 +21,7 @@ export const heading = (...levels) => HeadingFeature(...levels);
|
|
|
21
21
|
export const hr = () => HorizontalRuleFeature;
|
|
22
22
|
export const link = (options) => LinkFeature(options);
|
|
23
23
|
export const paragraph = () => ParagraphFeature;
|
|
24
|
-
export const
|
|
24
|
+
export const orderedList = () => OrderedListFeature;
|
|
25
25
|
export const blockquote = () => BlockquoteFeature;
|
|
26
26
|
export const italic = () => ItalicFeature;
|
|
27
27
|
export const upload = (args) => UploadFeature(args);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { root } from '../../../panel/components/fields/root.svelte.js';
|
|
4
4
|
import { Editor, type JSONContent } from '@tiptap/core';
|
|
5
5
|
import { onMount } from 'svelte';
|
|
6
|
-
import { buildEditorConfig } from '../core/config
|
|
6
|
+
import { buildEditorConfig } from '../core/build-editor-config.js';
|
|
7
7
|
import type { RichTextFeature } from '../core/types';
|
|
8
8
|
import { hasSuggestion } from '../util.js';
|
|
9
9
|
import EditorBubbleMenu from './bubble-menu/bubble-menu.svelte';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { t__ } from '../../../core/i18n/index.js';
|
|
2
|
+
import { getTitleContext, TITLE_CTX } from '../../../panel/context/title.js';
|
|
2
3
|
import Document from '@tiptap/extension-document';
|
|
3
4
|
import HardBreak from '@tiptap/extension-hard-break';
|
|
4
5
|
import { ListItem } from '@tiptap/extension-list';
|
|
@@ -7,6 +8,7 @@ import Typography from '@tiptap/extension-typography';
|
|
|
7
8
|
import { Dropcursor, Gapcursor, Placeholder, UndoRedo } from '@tiptap/extensions';
|
|
8
9
|
import { API_PROXY, getAPIProxyContext } from '../../../panel/context/api-proxy.svelte.js';
|
|
9
10
|
import { CONFIG_CTX, getConfigContext } from '../../../panel/context/config.svelte.js';
|
|
11
|
+
import { getLocaleContext, LOCALE_CTX } from '../../../panel/context/locale.svelte.js';
|
|
10
12
|
import { getUserContext, USER_CTX } from '../../../panel/context/user.svelte.js';
|
|
11
13
|
import { hasSuggestion } from '../util.js';
|
|
12
14
|
import { CurrentNodeAttribute } from './extensions/current-node/current-node.js';
|
|
@@ -60,12 +62,17 @@ export function buildEditorConfig(args) {
|
|
|
60
62
|
if ('addNodeView' in feature.extension.config) {
|
|
61
63
|
const originalAddOption = feature.extension.config.addOptions || (() => ({}));
|
|
62
64
|
const contexts = new Map();
|
|
65
|
+
const localeContext = getLocaleContext();
|
|
63
66
|
const configContext = getConfigContext();
|
|
64
|
-
const apiProxyContext = getAPIProxyContext(
|
|
67
|
+
const apiProxyContext = getAPIProxyContext();
|
|
65
68
|
const userContext = getUserContext();
|
|
69
|
+
const titleContext = getTitleContext();
|
|
70
|
+
contexts.set(TITLE_CTX, titleContext);
|
|
66
71
|
contexts.set(CONFIG_CTX, configContext);
|
|
67
|
-
contexts.set(
|
|
72
|
+
contexts.set(CONFIG_CTX, configContext);
|
|
73
|
+
contexts.set(API_PROXY.ROOT, apiProxyContext);
|
|
68
74
|
contexts.set(USER_CTX, userContext);
|
|
75
|
+
contexts.set(LOCALE_CTX, localeContext);
|
|
69
76
|
feature.extension.config.addOptions = () => {
|
|
70
77
|
// @ts-expect-error
|
|
71
78
|
return { ...originalAddOption(), contexts };
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
+
import type { FieldBuilder } from '../../../../../core/fields/builders';
|
|
2
|
+
import type { FieldsPreviewProps } from '../../../../types';
|
|
1
3
|
import type { Dic } from '../../../../../util/types.js';
|
|
2
4
|
import { Node } from '@tiptap/core';
|
|
5
|
+
import type { Component } from 'svelte';
|
|
3
6
|
declare module '@tiptap/core' {
|
|
4
7
|
interface Commands<ReturnType> {
|
|
5
|
-
|
|
6
|
-
insertSheet: (attributes
|
|
8
|
+
'richt-text-fields': {
|
|
9
|
+
insertSheet: (attributes?: Dic) => ReturnType;
|
|
7
10
|
};
|
|
8
11
|
}
|
|
9
12
|
}
|
|
10
|
-
export
|
|
13
|
+
export interface FieldsFeatureExtensionOptions {
|
|
14
|
+
fields: FieldBuilder[];
|
|
15
|
+
preview?: Component<FieldsPreviewProps>;
|
|
16
|
+
}
|
|
17
|
+
export declare const FieldsExtension: Node<FieldsFeatureExtensionOptions, any>;
|
|
@@ -5,13 +5,8 @@ export const FieldsExtension = Node.create({
|
|
|
5
5
|
name: 'richt-text-fields',
|
|
6
6
|
group: 'block',
|
|
7
7
|
atom: true,
|
|
8
|
-
draggable: true,
|
|
8
|
+
draggable: true,
|
|
9
9
|
inline: false,
|
|
10
|
-
addOptions() {
|
|
11
|
-
return {
|
|
12
|
-
fields: null
|
|
13
|
-
};
|
|
14
|
-
},
|
|
15
10
|
addAttributes() {
|
|
16
11
|
return ['json'].reduce((acc, key) => {
|
|
17
12
|
acc[key] = { default: null };
|
|
@@ -29,10 +24,10 @@ export const FieldsExtension = Node.create({
|
|
|
29
24
|
};
|
|
30
25
|
},
|
|
31
26
|
parseHTML() {
|
|
32
|
-
return [{ tag:
|
|
27
|
+
return [{ tag: this.name }];
|
|
33
28
|
},
|
|
34
29
|
renderHTML({ HTMLAttributes }) {
|
|
35
|
-
return [
|
|
30
|
+
return [this.name, mergeAttributes(HTMLAttributes)];
|
|
36
31
|
},
|
|
37
32
|
addNodeView() {
|
|
38
33
|
return SvelteNodeViewRenderer(FieldsComponent);
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { page } from '$app/state';
|
|
3
2
|
import { FieldBuilder, FormFieldBuilder } from '../../../../../core/fields/builders';
|
|
3
|
+
import type { FieldsPreviewProps } from '../../../../types';
|
|
4
4
|
import FieldsPreview from '../../../../../panel/components/fields/FieldsPreview.svelte';
|
|
5
5
|
import FieldsPreviewTrigger from '../../../../../panel/components/fields/FieldsPreviewTrigger.svelte';
|
|
6
6
|
import * as Sheet from '../../../../../panel/components/ui/sheet/index.js';
|
|
7
7
|
import { setFormContext } from '../../../../../panel/context/form.svelte';
|
|
8
|
-
import { setLocaleContext } from '../../../../../panel/context/locale.svelte';
|
|
9
8
|
import type { NodeViewProps } from '@tiptap/core';
|
|
10
|
-
import { onMount } from 'svelte';
|
|
9
|
+
import { onMount, type Component } from 'svelte';
|
|
11
10
|
import NodeViewWrapper from '../../svelte/node-view-wrapper.svelte';
|
|
12
11
|
import './fields.css';
|
|
13
12
|
|
|
@@ -15,6 +14,7 @@
|
|
|
15
14
|
extension: {
|
|
16
15
|
options: {
|
|
17
16
|
fields: FieldBuilder[];
|
|
17
|
+
preview?: Component<FieldsPreviewProps>;
|
|
18
18
|
};
|
|
19
19
|
};
|
|
20
20
|
};
|
|
@@ -22,7 +22,6 @@
|
|
|
22
22
|
let { node, extension, updateAttributes }: Props = $props();
|
|
23
23
|
let isSheetOpen = $state(false);
|
|
24
24
|
|
|
25
|
-
setLocaleContext(page.data.locale || 'en');
|
|
26
25
|
// svelte-ignore state_referenced_locally
|
|
27
26
|
const form = setFormContext(node.attrs.json || {}, 'fields');
|
|
28
27
|
|
|
@@ -43,19 +42,27 @@
|
|
|
43
42
|
const previewFields = $derived.by(() => {
|
|
44
43
|
return extension.options.fields.filter((field) => field instanceof FormFieldBuilder);
|
|
45
44
|
});
|
|
45
|
+
|
|
46
|
+
const classModifiers = $derived(
|
|
47
|
+
extension.options.preview ? 'rz-rich-text-fields-preview--custom' : ''
|
|
48
|
+
);
|
|
46
49
|
</script>
|
|
47
50
|
|
|
48
51
|
<NodeViewWrapper>
|
|
49
|
-
<FieldsPreviewTrigger
|
|
52
|
+
<FieldsPreviewTrigger
|
|
53
|
+
class="rz-rich-text-fields-preview {classModifiers}"
|
|
54
|
+
onclick={() => (isSheetOpen = true)}
|
|
55
|
+
>
|
|
50
56
|
<FieldsPreview
|
|
51
57
|
fields={previewFields}
|
|
52
58
|
getField={(field) => form.useField(field.name, field.raw)}
|
|
59
|
+
preview={extension.options.preview}
|
|
53
60
|
/>
|
|
54
61
|
</FieldsPreviewTrigger>
|
|
55
62
|
</NodeViewWrapper>
|
|
56
63
|
|
|
57
64
|
<Sheet.Root bind:open={isSheetOpen}>
|
|
58
|
-
<Sheet.Content side="right" class="rz-rich-text-sheet">
|
|
65
|
+
<Sheet.Content preventScroll={false} side="right" class="rz-rich-text-sheet">
|
|
59
66
|
{#each previewFields || [] as field, index (index)}
|
|
60
67
|
{@const FieldComponent = field.component}
|
|
61
68
|
<FieldComponent path={field.raw.name} config={field.raw} {form} />
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { FieldBuilder } from '../../../../../core/fields/builders';
|
|
2
|
+
import type { FieldsPreviewProps } from '../../../../types';
|
|
2
3
|
import type { NodeViewProps } from '@tiptap/core';
|
|
4
|
+
import { type Component } from 'svelte';
|
|
3
5
|
import './fields.css';
|
|
4
6
|
type Props = Omit<NodeViewProps, 'extension'> & {
|
|
5
7
|
extension: {
|
|
6
8
|
options: {
|
|
7
9
|
fields: FieldBuilder[];
|
|
10
|
+
preview?: Component<FieldsPreviewProps>;
|
|
8
11
|
};
|
|
9
12
|
};
|
|
10
13
|
};
|
|
11
|
-
declare const Fields:
|
|
14
|
+
declare const Fields: Component<Props, {}, "">;
|
|
12
15
|
type Fields = ReturnType<typeof Fields>;
|
|
13
16
|
export default Fields;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { FieldBuilder } from '../../../../../core/fields/builders/field-builder.js';
|
|
2
|
+
import type { FieldsPreviewProps } from '../../../../types.js';
|
|
3
|
+
import type { Component } from 'svelte';
|
|
2
4
|
import type { RichTextFeature } from '../../../../../types.js';
|
|
3
|
-
|
|
5
|
+
export interface FieldsFeatureOptions {
|
|
4
6
|
name: string;
|
|
5
|
-
label
|
|
7
|
+
label?: string;
|
|
6
8
|
fields: FieldBuilder[];
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export
|
|
9
|
+
preview?: Component<FieldsPreviewProps>;
|
|
10
|
+
}
|
|
11
|
+
export declare const FieldsFeature: (args: FieldsFeatureOptions) => RichTextFeature;
|
|
@@ -3,13 +3,14 @@ import { FieldsExtension } from './extension.js';
|
|
|
3
3
|
const fieldsFeatureNode = (args) => ({
|
|
4
4
|
label: args.label || args.name,
|
|
5
5
|
icon: SheetIcon,
|
|
6
|
-
isActive: ({ editor }) => editor.isActive('richt-text-fields'),
|
|
6
|
+
isActive: ({ editor }) => editor.isActive('richt-text-fields-' + args.name),
|
|
7
7
|
suggestion: {
|
|
8
|
-
//@ts-expect-error annoying
|
|
9
8
|
command: ({ editor }) => editor.chain().focus().insertSheet().run()
|
|
10
9
|
}
|
|
11
10
|
});
|
|
12
11
|
export const FieldsFeature = (args) => ({
|
|
13
|
-
extension: FieldsExtension.configure(args)
|
|
12
|
+
extension: FieldsExtension.configure({ fields: args.fields, preview: args.preview }).extend({
|
|
13
|
+
name: 'richt-text-fields-' + args.name
|
|
14
|
+
}),
|
|
14
15
|
nodes: [fieldsFeatureNode(args)]
|
|
15
16
|
});
|
|
@@ -6,11 +6,7 @@
|
|
|
6
6
|
import Button from '../../../../../../panel/components/ui/button/button.svelte';
|
|
7
7
|
import * as Command from '../../../../../../panel/components/ui/command/index.js';
|
|
8
8
|
import Input from '../../../../../../panel/components/ui/input/input.svelte';
|
|
9
|
-
import {
|
|
10
|
-
API_PROXY,
|
|
11
|
-
getAPIProxyContext,
|
|
12
|
-
type Resource
|
|
13
|
-
} from '../../../../../../panel/context/api-proxy.svelte.js';
|
|
9
|
+
import { getAPIProxyContext, type Resource } from '../../../../../../panel/context/api-proxy.svelte.js';
|
|
14
10
|
import { getLocaleContext } from '../../../../../../panel/context/locale.svelte';
|
|
15
11
|
import validate from '../../../../../../util/validate.js';
|
|
16
12
|
import { CornerDownLeft, ExternalLink, Link2, Newspaper, Trash } from '@lucide/svelte';
|
|
@@ -40,18 +36,18 @@
|
|
|
40
36
|
/**
|
|
41
37
|
* Logic to get internal resources e.g., collections, areas
|
|
42
38
|
*/
|
|
43
|
-
const APIProxy = getAPIProxyContext(
|
|
39
|
+
const APIProxy = getAPIProxyContext();
|
|
44
40
|
const locale = getLocaleContext();
|
|
45
41
|
let resources = $state<Resource<LinkResource[]>[]>([]);
|
|
46
42
|
let resourcesFlatMap = $state<LinkResource[]>();
|
|
43
|
+
|
|
47
44
|
$effect(() => {
|
|
48
|
-
if (Array.isArray(options?.
|
|
49
|
-
resources = options.
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
: '?select=title,url';
|
|
45
|
+
if (Array.isArray(options?.sources) && !resources.length) {
|
|
46
|
+
resources = options.sources.map((source) => {
|
|
47
|
+
const [slug, query] = source.split('?');
|
|
48
|
+
let params = query || '' ? `?${query}&select=title,url` : '?select=title,url';
|
|
53
49
|
params = locale.code ? `${params}&locale=${locale.code}` : params;
|
|
54
|
-
const url = `${apiUrl(
|
|
50
|
+
const url = `${apiUrl(slug)}${params}`;
|
|
55
51
|
return APIProxy.getRessource<LinkResource[]>(url, {
|
|
56
52
|
transformData: (data) => {
|
|
57
53
|
return 'docs' in data ? data.docs : 'doc' in data ? [data.doc] : data;
|
|
@@ -212,7 +208,7 @@
|
|
|
212
208
|
/>
|
|
213
209
|
<Button size="icon-sm" variant="ghost" icon={Trash} onclick={onDelete} />
|
|
214
210
|
{:else}
|
|
215
|
-
{#if options?.
|
|
211
|
+
{#if options?.sources?.length}
|
|
216
212
|
<Button
|
|
217
213
|
onclick={() => (resourceDialogOpen = true)}
|
|
218
214
|
size="icon-sm"
|
|
@@ -2,9 +2,6 @@ import type { PrototypeSlug } from '../../../../../types.js';
|
|
|
2
2
|
import { type LinkOptions } from '@tiptap/extension-link';
|
|
3
3
|
import type { RichTextFeature } from '../../types.js';
|
|
4
4
|
export type LinkFeatureOptions = LinkOptions & {
|
|
5
|
-
|
|
6
|
-
slug: PrototypeSlug;
|
|
7
|
-
query?: string;
|
|
8
|
-
}>;
|
|
5
|
+
sources?: Array<`${PrototypeSlug}${string}`>;
|
|
9
6
|
};
|
|
10
7
|
export declare const LinkFeature: (options?: Partial<LinkFeatureOptions>) => RichTextFeature;
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import type { PrototypeSlug } from '../../../../../types.js';
|
|
2
1
|
import type { RichTextFeature } from '../../types.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
slug: PrototypeSlug;
|
|
6
|
-
}) => RichTextFeature;
|
|
2
|
+
import { type ResourceFeatureExtensionOptions } from './resource-extension.js';
|
|
3
|
+
export declare const ResourceFeature: (args: ResourceFeatureExtensionOptions) => RichTextFeature;
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import { Images } from '@lucide/svelte';
|
|
2
2
|
import { Resource } from './resource-extension.js';
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
export const ResourceFeature = (args) => {
|
|
4
|
+
const slug = args.source.split('?')[0];
|
|
5
|
+
return {
|
|
6
|
+
extension: Resource.configure(args).extend({
|
|
7
|
+
name: 'richt-text-resource-' + slug
|
|
8
|
+
}),
|
|
9
|
+
nodes: [
|
|
10
|
+
{
|
|
11
|
+
label: args.label || slug,
|
|
12
|
+
icon: Images,
|
|
13
|
+
isActive: ({ editor }) => editor.isActive('richt-text-resource-' + slug),
|
|
14
|
+
suggestion: {
|
|
15
|
+
command: ({ editor }) => editor.chain().focus().insertResource().run()
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
};
|
|
11
20
|
};
|
|
12
|
-
export const ResourceFeature = (args) => ({
|
|
13
|
-
extension: Resource.configure(args),
|
|
14
|
-
nodes: [resourceFeatureNode]
|
|
15
|
-
});
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
import type { PrototypeSlug } from '../../../../../core/types/doc';
|
|
1
2
|
import type { Dic } from '../../../../../util/types.js';
|
|
2
3
|
import { Node } from '@tiptap/core';
|
|
3
4
|
declare module '@tiptap/core' {
|
|
4
5
|
interface Commands<ReturnType> {
|
|
5
6
|
resource: {
|
|
6
|
-
insertResource: (attributes
|
|
7
|
+
insertResource: (attributes?: Dic) => ReturnType;
|
|
7
8
|
};
|
|
8
9
|
}
|
|
9
10
|
}
|
|
10
|
-
export
|
|
11
|
+
export interface ResourceFeatureExtensionOptions {
|
|
12
|
+
label?: string;
|
|
13
|
+
source: `${PrototypeSlug}${string}`;
|
|
14
|
+
}
|
|
15
|
+
export declare const Resource: Node<ResourceFeatureExtensionOptions, any>;
|
|
@@ -5,19 +5,15 @@ export const Resource = Node.create({
|
|
|
5
5
|
name: 'resource',
|
|
6
6
|
group: 'block',
|
|
7
7
|
atom: true,
|
|
8
|
-
draggable: true,
|
|
8
|
+
draggable: true,
|
|
9
9
|
inline: false,
|
|
10
|
-
addOptions() {
|
|
11
|
-
return {
|
|
12
|
-
query: null,
|
|
13
|
-
_type: null
|
|
14
|
-
};
|
|
15
|
-
},
|
|
16
10
|
addAttributes() {
|
|
17
11
|
return ['id', 'title', '_type', '_thumbnail'].reduce((acc, key) => {
|
|
18
12
|
acc[key] = { default: null };
|
|
19
13
|
return acc;
|
|
20
|
-
},
|
|
14
|
+
},
|
|
15
|
+
// Fresh attributes allowing to show the dialog immediately after insertion
|
|
16
|
+
{ _fresh: { default: true } });
|
|
21
17
|
},
|
|
22
18
|
addCommands() {
|
|
23
19
|
return {
|
|
@@ -30,10 +26,10 @@ export const Resource = Node.create({
|
|
|
30
26
|
};
|
|
31
27
|
},
|
|
32
28
|
parseHTML() {
|
|
33
|
-
return [{ tag:
|
|
29
|
+
return [{ tag: this.name }];
|
|
34
30
|
},
|
|
35
31
|
renderHTML({ HTMLAttributes }) {
|
|
36
|
-
return [
|
|
32
|
+
return [this.name, mergeAttributes(HTMLAttributes)];
|
|
37
33
|
},
|
|
38
34
|
addNodeView() {
|
|
39
35
|
return SvelteNodeViewRenderer(ResourceComponent);
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import Button from '../../../../../panel/components/ui/button/button.svelte';
|
|
5
5
|
import CardResource from '../../../../../panel/components/ui/card-resource/card-resource.svelte';
|
|
6
6
|
import * as Command from '../../../../../panel/components/ui/command/index.js';
|
|
7
|
-
import {
|
|
7
|
+
import { getAPIProxyContext } from '../../../../../panel/context/api-proxy.svelte.js';
|
|
8
8
|
import type { NodeViewProps } from '@tiptap/core';
|
|
9
9
|
import { onMount } from 'svelte';
|
|
10
10
|
import NodeViewWrapper from '../../svelte/node-view-wrapper.svelte';
|
|
@@ -35,14 +35,16 @@
|
|
|
35
35
|
} else {
|
|
36
36
|
selected = null;
|
|
37
37
|
}
|
|
38
|
+
if (node.attrs._fresh) {
|
|
39
|
+
// If the resource is fresh, we want to open the dialog to select a resource
|
|
40
|
+
isDialogOpen = true;
|
|
41
|
+
}
|
|
38
42
|
});
|
|
39
43
|
|
|
40
|
-
const APIProxy = getAPIProxyContext(
|
|
44
|
+
const APIProxy = getAPIProxyContext();
|
|
41
45
|
|
|
42
46
|
// svelte-ignore state_referenced_locally
|
|
43
|
-
const url = extension.options.
|
|
44
|
-
? apiUrl(extension.options.slug, `?${extension.options.query}`)
|
|
45
|
-
: apiUrl(extension.options.slug);
|
|
47
|
+
const url = apiUrl(extension.options.source);
|
|
46
48
|
|
|
47
49
|
const ressource = APIProxy.getRessource<{ docs: GenericDoc[] }>(url);
|
|
48
50
|
let docs = $state<GenericDoc[]>([]);
|
|
@@ -50,7 +52,7 @@
|
|
|
50
52
|
$effect(() => {
|
|
51
53
|
if (ressource.data) {
|
|
52
54
|
docs = ressource.data.docs;
|
|
53
|
-
// Update atttributes if document
|
|
55
|
+
// Update atttributes if document has changed
|
|
54
56
|
if (node.attrs.id) {
|
|
55
57
|
selected = docs.find((doc) => doc.id === node.attrs.id);
|
|
56
58
|
}
|
|
@@ -58,27 +60,22 @@
|
|
|
58
60
|
});
|
|
59
61
|
|
|
60
62
|
// Handle dialog selection
|
|
61
|
-
function handleResourceSelection(doc:
|
|
62
|
-
// Close the dialog
|
|
63
|
+
function handleResourceSelection(doc: RequiredNodeAttributes) {
|
|
63
64
|
isDialogOpen = false;
|
|
64
|
-
|
|
65
|
-
// Update the selected resource
|
|
66
65
|
selected = doc;
|
|
67
|
-
|
|
68
|
-
// Update node attributes
|
|
69
66
|
updateNodeAttributes();
|
|
70
67
|
}
|
|
71
68
|
|
|
72
69
|
// Handle removing resource
|
|
73
70
|
function removeResource() {
|
|
74
71
|
selected = null;
|
|
75
|
-
|
|
76
72
|
// Update node attributes with empty values
|
|
77
73
|
updateAttributes({
|
|
78
74
|
id: null,
|
|
79
75
|
title: null,
|
|
80
|
-
|
|
81
|
-
_thumbnail: null
|
|
76
|
+
_type: null,
|
|
77
|
+
_thumbnail: null,
|
|
78
|
+
_fresh: false
|
|
82
79
|
});
|
|
83
80
|
}
|
|
84
81
|
|
|
@@ -89,8 +86,9 @@
|
|
|
89
86
|
updateAttributes({
|
|
90
87
|
id: selected.id,
|
|
91
88
|
title: selected.title,
|
|
92
|
-
_type: extension.options.
|
|
93
|
-
_thumbnail: selected._thumbnail
|
|
89
|
+
_type: extension.options.source,
|
|
90
|
+
_thumbnail: selected._thumbnail,
|
|
91
|
+
_fresh: false
|
|
94
92
|
});
|
|
95
93
|
}
|
|
96
94
|
</script>
|
|
@@ -102,16 +100,16 @@
|
|
|
102
100
|
class:rz-richtext-resource--selected={!!selected}
|
|
103
101
|
>
|
|
104
102
|
{#if !selected}
|
|
105
|
-
<Button class="rz-richtext-resource__add" variant="outline" size="sm" onclick={handleClick}
|
|
106
|
-
|
|
107
|
-
>
|
|
103
|
+
<Button class="rz-richtext-resource__add" variant="outline" size="sm" onclick={handleClick}>
|
|
104
|
+
Add a resource
|
|
105
|
+
</Button>
|
|
108
106
|
{:else}
|
|
109
107
|
<CardResource resource={selected as RequiredNodeAttributes} onCloseClick={removeResource} />
|
|
110
108
|
{/if}
|
|
111
109
|
</div>
|
|
112
110
|
</NodeViewWrapper>
|
|
113
111
|
|
|
114
|
-
<Command.Dialog bind:open={isDialogOpen}>
|
|
112
|
+
<Command.Dialog bind:open={isDialogOpen} preventScroll={false}>
|
|
115
113
|
<Command.Input placeholder="Select a resource" />
|
|
116
114
|
|
|
117
115
|
<Command.List>
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import type { CollectionSlug } from '../../../../../types.js';
|
|
2
1
|
import type { RichTextFeature } from '../../types.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
query?: string;
|
|
6
|
-
}) => RichTextFeature;
|
|
2
|
+
import { type UploadFeatureExtensionOptions } from './upload-extension.js';
|
|
3
|
+
export declare const UploadFeature: (args: UploadFeatureExtensionOptions) => RichTextFeature;
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { Images } from '@lucide/svelte';
|
|
2
2
|
import { Upload } from './upload-extension.js';
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
export const UploadFeature = (args) => {
|
|
4
|
+
const slug = args.source.split('?')[0];
|
|
5
|
+
return {
|
|
6
|
+
extension: Upload.configure(args).extend({ name: 'richt-text-upload-' + slug }),
|
|
7
|
+
nodes: [
|
|
8
|
+
{
|
|
9
|
+
label: 'Media',
|
|
10
|
+
icon: Images,
|
|
11
|
+
isActive: ({ editor }) => editor.isActive('richt-text-upload-' + slug),
|
|
12
|
+
suggestion: {
|
|
13
|
+
command: ({ editor }) => editor.chain().focus().insertUpload().run()
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
};
|
|
11
18
|
};
|
|
12
|
-
export const UploadFeature = (args) => ({
|
|
13
|
-
extension: Upload.configure(args),
|
|
14
|
-
nodes: [uploadFeatureNode]
|
|
15
|
-
});
|
|
@@ -1,2 +1,14 @@
|
|
|
1
|
+
import type { CollectionSlug } from '../../../../../types';
|
|
2
|
+
import type { Dic } from '../../../../../util/types.js';
|
|
1
3
|
import { Node } from '@tiptap/core';
|
|
2
|
-
export
|
|
4
|
+
export interface UploadFeatureExtensionOptions {
|
|
5
|
+
source: `${CollectionSlug}${string}`;
|
|
6
|
+
}
|
|
7
|
+
declare module '@tiptap/core' {
|
|
8
|
+
interface Commands<ReturnType> {
|
|
9
|
+
upload: {
|
|
10
|
+
insertUpload: (attributes?: Dic) => ReturnType;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export declare const Upload: Node<UploadFeatureExtensionOptions, any>;
|
|
@@ -5,25 +5,20 @@ export const Upload = Node.create({
|
|
|
5
5
|
name: 'upload',
|
|
6
6
|
group: 'block',
|
|
7
7
|
atom: true,
|
|
8
|
-
draggable: true,
|
|
8
|
+
draggable: true,
|
|
9
9
|
inline: false,
|
|
10
|
-
addOptions() {
|
|
11
|
-
return {
|
|
12
|
-
query: null
|
|
13
|
-
};
|
|
14
|
-
},
|
|
15
10
|
addAttributes() {
|
|
16
11
|
return ['id', 'title', 'sizes', 'mimeType', 'url', 'filename', 'legend'].reduce((acc, key) => {
|
|
17
12
|
acc[key] = { default: null };
|
|
18
13
|
return acc;
|
|
19
|
-
},
|
|
14
|
+
},
|
|
15
|
+
// We use this attribute to determine if the resource is fresh or not.
|
|
16
|
+
// If it's fresh, we want to open the dialog
|
|
17
|
+
{ _fresh: { default: true } });
|
|
20
18
|
},
|
|
21
|
-
//@ts-expect-error annoying
|
|
22
19
|
addCommands() {
|
|
23
20
|
return {
|
|
24
|
-
|
|
25
|
-
//@ts-expect-error annoying
|
|
26
|
-
({ commands }) => {
|
|
21
|
+
insertUpload: (attributes = {}) => ({ commands }) => {
|
|
27
22
|
return commands.insertContent({
|
|
28
23
|
type: this.name,
|
|
29
24
|
attrs: attributes
|