rimecms 0.23.19 → 0.23.21
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/fields/relation/client.d.ts +28 -0
- package/dist/fields/relation/client.js +37 -0
- package/dist/panel/components/sections/document/upload-header/UploadHeader.svelte +15 -3
- package/dist/panel/components/ui/card-document/card-document.svelte +6 -6
- package/dist/site/components/avatar/avatar.svelte +34 -0
- package/dist/site/components/avatar/avatar.svelte.d.ts +6 -0
- package/dist/site/components/feed/feed.svelte +12 -3
- package/dist/site/components/nav/nav.svelte +48 -0
- package/dist/site/components/nav/nav.svelte.d.ts +18 -0
- package/dist/site/components/post/post-actions/post-actions.svelte +20 -0
- package/dist/site/components/post/post-actions/post-actions.svelte.d.ts +6 -0
- package/dist/site/components/post/post.svelte +43 -2
- package/dist/site/components/post/post.svelte.d.ts +2 -1
- package/dist/site/components/user-inline/user-inline.svelte +23 -0
- package/dist/site/components/user-inline/user-inline.svelte.d.ts +6 -0
- package/package.json +5 -1
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { RelationValue } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Checks if a relation field's value is populated with full documents.
|
|
4
|
+
*
|
|
5
|
+
* A relation is considered populated if it is an array of objects that do not
|
|
6
|
+
* contain only the relation identifiers (`id`, `relationTo`, `documentId`).
|
|
7
|
+
* If the value is a string or an array of relation identifier objects,
|
|
8
|
+
* it is considered not populated.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* // Returns: false
|
|
12
|
+
* isRelationPopulated('7674e91b-598a-4a72-a5cd-9594736a34dd');
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* // Returns: false
|
|
16
|
+
* isRelationPopulated([]);
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* // Returns: false
|
|
20
|
+
* isRelationPopulated([
|
|
21
|
+
* {
|
|
22
|
+
* id: '7674e91b-598a-4a72-a5cd-9594736a34dd',
|
|
23
|
+
* relationTo: 'articles',
|
|
24
|
+
* documentId: 'b674e91b-598a-4a72-a5cd-9594736a34dd'
|
|
25
|
+
* }
|
|
26
|
+
* ]);
|
|
27
|
+
*/
|
|
28
|
+
export declare const isRelationPopulated: <T>(value: RelationValue<T>) => value is T[];
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { hasProps, isObjectLiteral } from '../../util/object';
|
|
2
|
+
/**
|
|
3
|
+
* Checks if a relation field's value is populated with full documents.
|
|
4
|
+
*
|
|
5
|
+
* A relation is considered populated if it is an array of objects that do not
|
|
6
|
+
* contain only the relation identifiers (`id`, `relationTo`, `documentId`).
|
|
7
|
+
* If the value is a string or an array of relation identifier objects,
|
|
8
|
+
* it is considered not populated.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* // Returns: false
|
|
12
|
+
* isRelationPopulated('7674e91b-598a-4a72-a5cd-9594736a34dd');
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* // Returns: false
|
|
16
|
+
* isRelationPopulated([]);
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* // Returns: false
|
|
20
|
+
* isRelationPopulated([
|
|
21
|
+
* {
|
|
22
|
+
* id: '7674e91b-598a-4a72-a5cd-9594736a34dd',
|
|
23
|
+
* relationTo: 'articles',
|
|
24
|
+
* documentId: 'b674e91b-598a-4a72-a5cd-9594736a34dd'
|
|
25
|
+
* }
|
|
26
|
+
* ]);
|
|
27
|
+
*/
|
|
28
|
+
export const isRelationPopulated = (value) => {
|
|
29
|
+
if (Array.isArray(value)) {
|
|
30
|
+
if (value.length === 0)
|
|
31
|
+
return false;
|
|
32
|
+
return value.every((v) => {
|
|
33
|
+
return isObjectLiteral(v) && !hasProps(['id', 'relationTo', 'documentId'], v);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return typeof value !== 'string';
|
|
37
|
+
};
|
|
@@ -82,7 +82,10 @@
|
|
|
82
82
|
</div>
|
|
83
83
|
{:else}
|
|
84
84
|
{@const FileIcon = mimeTypeToIcon(form.values.mimeType)}
|
|
85
|
-
<
|
|
85
|
+
<div class="rz-doc-upload-header__prewiew-file">
|
|
86
|
+
<FileIcon size="40" />
|
|
87
|
+
<span>{form.values.mimeType}</span>
|
|
88
|
+
</div>
|
|
86
89
|
{/if}
|
|
87
90
|
</div>
|
|
88
91
|
<div class="rz-doc-upload-header__info">
|
|
@@ -109,6 +112,7 @@
|
|
|
109
112
|
}
|
|
110
113
|
|
|
111
114
|
.rz-doc-upload-header__file {
|
|
115
|
+
min-height: 250px;
|
|
112
116
|
border: var(--rz-border);
|
|
113
117
|
overflow: hidden;
|
|
114
118
|
border-radius: var(--radius-md);
|
|
@@ -122,6 +126,7 @@
|
|
|
122
126
|
overflow: hidden;
|
|
123
127
|
width: clamp(var(--rz-size-60), 40vw, 80%);
|
|
124
128
|
max-height: 400px;
|
|
129
|
+
background-color: light-dark(hsl(var(--rz-gray-12)), hsl(var(--rz-gray-3)));
|
|
125
130
|
border-top-right-radius: var(--rz-radius-md);
|
|
126
131
|
border-top-left-radius: var(--rz-radius-md);
|
|
127
132
|
}
|
|
@@ -206,8 +211,8 @@
|
|
|
206
211
|
padding-bottom: var(--rz-size-4);
|
|
207
212
|
}
|
|
208
213
|
.rz-doc-upload-header__info h4 {
|
|
209
|
-
|
|
210
|
-
|
|
214
|
+
opacity: 0.4;
|
|
215
|
+
margin-bottom: var(--rz-size-1);
|
|
211
216
|
font-size: var(--rz-text-xs);
|
|
212
217
|
}
|
|
213
218
|
.rz-doc-upload-header__info a {
|
|
@@ -218,4 +223,11 @@
|
|
|
218
223
|
.rz-doc-upload-header__info p {
|
|
219
224
|
margin-bottom: var(--rz-size-3);
|
|
220
225
|
}
|
|
226
|
+
.rz-doc-upload-header__prewiew-file {
|
|
227
|
+
display: flex;
|
|
228
|
+
flex-direction: column;
|
|
229
|
+
align-items: center;
|
|
230
|
+
justify-content: center;
|
|
231
|
+
gap: var(--rz-size-2);
|
|
232
|
+
}
|
|
221
233
|
</style>
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
type Props = { doc: GenericDoc };
|
|
6
6
|
const { doc }: Props = $props();
|
|
7
7
|
|
|
8
|
-
const hasPreview = $derived(doc.mimeType && doc.mimeType.includes('image'));
|
|
9
8
|
const thumbnailUrl = $derived.by(() => {
|
|
10
9
|
if (doc.mimeType && doc.mimeType.includes('image')) {
|
|
11
10
|
return doc._thumbnail;
|
|
@@ -16,9 +15,7 @@
|
|
|
16
15
|
|
|
17
16
|
<div class="rz-document-card">
|
|
18
17
|
<div class="rz-document-card__preview">
|
|
19
|
-
{
|
|
20
|
-
<UploadThumbCell mimeType={doc.mimeType} url={thumbnailUrl} />
|
|
21
|
-
{/if}
|
|
18
|
+
<UploadThumbCell mimeType={doc.mimeType} url={thumbnailUrl} />
|
|
22
19
|
</div>
|
|
23
20
|
|
|
24
21
|
<div class="rz-document-card__body">
|
|
@@ -37,7 +34,8 @@
|
|
|
37
34
|
<style>
|
|
38
35
|
/** */
|
|
39
36
|
:root {
|
|
40
|
-
--rz-card-hover-bg: light-dark(hsl(var(--rz-gray-14)), hsl(var(--rz-gray-
|
|
37
|
+
--rz-card-hover-bg: light-dark(hsl(var(--rz-gray-14)), hsl(var(--rz-gray-4)));
|
|
38
|
+
--rz-card-bg: light-dark(hsl(var(--rz-gray-16)), hsl(var(--rz-gray-3)));
|
|
41
39
|
}
|
|
42
40
|
|
|
43
41
|
.rz-document-card {
|
|
@@ -80,7 +78,9 @@
|
|
|
80
78
|
}
|
|
81
79
|
|
|
82
80
|
.rz-document-card__body {
|
|
83
|
-
display:
|
|
81
|
+
display: flex;
|
|
82
|
+
flex-direction: column;
|
|
83
|
+
gap: var(--rz-size-2);
|
|
84
84
|
text-align: left;
|
|
85
85
|
padding: 0 0.6rem 0.6rem 0.6rem;
|
|
86
86
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { isRelationPopulated } from '../../../fields/relation/client';
|
|
3
|
+
|
|
4
|
+
type Props = { user: UsersDoc };
|
|
5
|
+
const { user }: Props = $props();
|
|
6
|
+
|
|
7
|
+
const avatar = $derived(user.avatar && isRelationPopulated(user.avatar) ? user.avatar : null);
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
{#if avatar}
|
|
11
|
+
<img src={avatar[0].sizes.thumbnail} alt={user.name || 'User Avatar'} class="avatar-image" />
|
|
12
|
+
{:else}
|
|
13
|
+
<div class="avatar-placeholder">
|
|
14
|
+
{user.name.charAt(0).toUpperCase()}
|
|
15
|
+
</div>
|
|
16
|
+
{/if}
|
|
17
|
+
|
|
18
|
+
<style>
|
|
19
|
+
.avatar-image,
|
|
20
|
+
.avatar-placeholder {
|
|
21
|
+
width: 32px;
|
|
22
|
+
height: 32px;
|
|
23
|
+
border-radius: 50%;
|
|
24
|
+
-o-object-fit: cover;
|
|
25
|
+
object-fit: cover;
|
|
26
|
+
background-color: light-dark(var(--gray-10), var(--gray-3));
|
|
27
|
+
color: var(--gray-7);
|
|
28
|
+
display: flex;
|
|
29
|
+
align-items: center;
|
|
30
|
+
justify-content: center;
|
|
31
|
+
font-weight: bold;
|
|
32
|
+
font-size: 1rem;
|
|
33
|
+
}
|
|
34
|
+
</style>
|
|
@@ -3,6 +3,15 @@
|
|
|
3
3
|
import Post from '../post/post.svelte';
|
|
4
4
|
</script>
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
{
|
|
6
|
+
<div>
|
|
7
|
+
{#each page.data.posts as post}
|
|
8
|
+
<Post {post} />
|
|
9
|
+
{/each}
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
<style>
|
|
13
|
+
div {
|
|
14
|
+
padding-inline: var(--size-8);
|
|
15
|
+
padding-block: var(--size-8);
|
|
16
|
+
}
|
|
17
|
+
</style>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { BookText, House, User } from '@lucide/svelte';
|
|
3
|
+
import Button from '../button/button.svelte';
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<div class="nav">
|
|
7
|
+
<div class="nav__inner">
|
|
8
|
+
<nav>
|
|
9
|
+
<ul>
|
|
10
|
+
<li><House size="18" /><a href="/">Accueil</a></li>
|
|
11
|
+
<li><BookText size="18" /><a href="/documents">Documents</a></li>
|
|
12
|
+
<li><User size="18" /><a href="/me">Profil</a></li>
|
|
13
|
+
</ul>
|
|
14
|
+
</nav>
|
|
15
|
+
|
|
16
|
+
<Button variant="default" size="lg">Poster</Button>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<style>
|
|
21
|
+
.nav {
|
|
22
|
+
display: flex;
|
|
23
|
+
flex-direction: column;
|
|
24
|
+
align-items: flex-end;
|
|
25
|
+
padding: var(--size-40) var(--size-8);
|
|
26
|
+
:global(.button) {
|
|
27
|
+
min-width: 240px;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.nav__inner {
|
|
32
|
+
display: grid;
|
|
33
|
+
gap: var(--size-4);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
nav {
|
|
37
|
+
font-size: var(--size-5);
|
|
38
|
+
ul {
|
|
39
|
+
display: grid;
|
|
40
|
+
gap: var(--size-2);
|
|
41
|
+
}
|
|
42
|
+
li {
|
|
43
|
+
display: flex;
|
|
44
|
+
align-items: center;
|
|
45
|
+
gap: var(--size-2);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
</style>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
2
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
3
|
+
$$bindings?: Bindings;
|
|
4
|
+
} & Exports;
|
|
5
|
+
(internal: unknown, props: {
|
|
6
|
+
$$events?: Events;
|
|
7
|
+
$$slots?: Slots;
|
|
8
|
+
}): Exports & {
|
|
9
|
+
$set?: any;
|
|
10
|
+
$on?: any;
|
|
11
|
+
};
|
|
12
|
+
z_$$bindings?: Bindings;
|
|
13
|
+
}
|
|
14
|
+
declare const Nav: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
+
[evt: string]: CustomEvent<any>;
|
|
16
|
+
}, {}, {}, string>;
|
|
17
|
+
type Nav = InstanceType<typeof Nav>;
|
|
18
|
+
export default Nav;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Heart, MessageCircle } from '@lucide/svelte';
|
|
3
|
+
import Button from '../../button/button.svelte';
|
|
4
|
+
|
|
5
|
+
type Props = { id: string };
|
|
6
|
+
const { id }: Props = $props();
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<div class="post-actions">
|
|
10
|
+
<Button variant="text" icon={Heart} aria-label="Like post" />
|
|
11
|
+
<Button variant="text" icon={MessageCircle} aria-label="Comment on post" />
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<style>
|
|
15
|
+
.post-actions {
|
|
16
|
+
display: flex;
|
|
17
|
+
align-items: center;
|
|
18
|
+
gap: var(--size-4);
|
|
19
|
+
}
|
|
20
|
+
</style>
|
|
@@ -1,6 +1,47 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
|
|
2
|
+
import { RenderRichText } from '../../../fields/rich-text/client.js';
|
|
3
|
+
import type { WithRelationPopulated } from '../../../types';
|
|
4
|
+
|
|
5
|
+
import UserInline from '../user-inline/user-inline.svelte';
|
|
6
|
+
import PostActions from './post-actions/post-actions.svelte';
|
|
7
|
+
import { isRelationPopulated } from '../../../fields/relation/client';
|
|
8
|
+
|
|
9
|
+
type Props = { post: WithRelationPopulated<PostsDoc> };
|
|
3
10
|
const { post }: Props = $props();
|
|
11
|
+
|
|
12
|
+
const author = $derived(post.author && isRelationPopulated(post.author) ? post.author : null);
|
|
4
13
|
</script>
|
|
5
14
|
|
|
6
|
-
<
|
|
15
|
+
<article>
|
|
16
|
+
<header>
|
|
17
|
+
{#if author}
|
|
18
|
+
<UserInline user={author[0]} />
|
|
19
|
+
{/if}
|
|
20
|
+
|
|
21
|
+
{#if post.createdAt}
|
|
22
|
+
{new Date(post.createdAt).toLocaleDateString('en-US', {
|
|
23
|
+
year: 'numeric',
|
|
24
|
+
month: 'long',
|
|
25
|
+
day: 'numeric'
|
|
26
|
+
})}
|
|
27
|
+
{/if}
|
|
28
|
+
</header>
|
|
29
|
+
|
|
30
|
+
<RenderRichText json={post.text} />
|
|
31
|
+
|
|
32
|
+
<footer>
|
|
33
|
+
<PostActions id={post.id} />
|
|
34
|
+
</footer>
|
|
35
|
+
</article>
|
|
36
|
+
|
|
37
|
+
<style>
|
|
38
|
+
article {
|
|
39
|
+
display: grid;
|
|
40
|
+
gap: var(--size-4);
|
|
41
|
+
}
|
|
42
|
+
header {
|
|
43
|
+
display: flex;
|
|
44
|
+
align-items: center;
|
|
45
|
+
justify-content: space-between;
|
|
46
|
+
}
|
|
47
|
+
</style>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Avatar from '../avatar/avatar.svelte';
|
|
3
|
+
|
|
4
|
+
type Props = { user: UsersDoc };
|
|
5
|
+
const { user }: Props = $props();
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<div class="user-inline">
|
|
9
|
+
<Avatar {user} />
|
|
10
|
+
<span>{user.name || user.email}</span>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<style>
|
|
14
|
+
.user-inline {
|
|
15
|
+
display: flex;
|
|
16
|
+
align-items: center;
|
|
17
|
+
gap: var(--size-2);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.user-inline span {
|
|
21
|
+
font-weight: 500;
|
|
22
|
+
}
|
|
23
|
+
</style>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rimecms",
|
|
3
|
-
"version": "0.23.
|
|
3
|
+
"version": "0.23.21",
|
|
4
4
|
"homepage": "https://github.com/bienbiendev/rime",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "vite dev",
|
|
@@ -70,6 +70,10 @@
|
|
|
70
70
|
"types": "./dist/fields/rich-text/client.d.ts",
|
|
71
71
|
"import": "./dist/fields/rich-text/client.js"
|
|
72
72
|
},
|
|
73
|
+
"./fields/relation": {
|
|
74
|
+
"types": "./dist/fields/relation/client.d.ts",
|
|
75
|
+
"import": "./dist/fields/relation/client.js"
|
|
76
|
+
},
|
|
73
77
|
"./i18n": {
|
|
74
78
|
"types": "./dist/core/i18n/index.d.ts",
|
|
75
79
|
"import": "./dist/core/i18n/index.js"
|