@vit-foundation/ui 0.11.0 → 0.13.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/chrome.d.ts +1 -0
- package/dist/components/account/NewsletterSignup.svelte +19 -3
- package/dist/components/contact/ContactForm.svelte +62 -14
- package/dist/components/jobs/JobList.svelte +75 -12
- package/dist/components/jobs/JobList.svelte.d.ts +19 -2
- package/dist/components/layout/Footer.svelte +54 -5
- package/dist/components/layout/Footer.svelte.d.ts +6 -1
- package/dist/components/layout/Nav.svelte +64 -8
- package/dist/components/layout/Nav.svelte.d.ts +6 -1
- package/dist/components/layout/site-link-edit.d.ts +17 -0
- package/dist/components/layout/site-link-edit.js +1 -0
- package/dist/components/projects/ProjectCard.svelte +80 -33
- package/dist/components/projects/ProjectCard.svelte.d.ts +11 -2
- package/dist/components/team/CollaboratorList.svelte +87 -9
- package/dist/components/team/CollaboratorList.svelte.d.ts +26 -0
- package/dist/components/team/TeamMemberCard.svelte +41 -19
- package/dist/components/team/TeamMemberCard.svelte.d.ts +8 -4
- package/dist/components/timeline/TimelineMilestone.svelte +3 -1
- package/dist/components/ui/CardMedia.svelte +66 -3
- package/dist/components/ui/CardMedia.svelte.d.ts +6 -2
- package/dist/components/ui/SearchInput.svelte +31 -10
- package/dist/components/ui/SearchInput.svelte.d.ts +7 -0
- package/dist/components/weeklies/CommentSection.svelte +20 -3
- package/dist/components/weeklies/SortSelect.svelte +41 -11
- package/dist/components/weeklies/SortSelect.svelte.d.ts +8 -0
- package/dist/components/weeklies/WeeklieCard.svelte +46 -19
- package/dist/components/weeklies/WeeklieCard.svelte.d.ts +9 -2
- package/dist/config/edit-messages.d.ts +2 -0
- package/dist/config/edit-messages.js +1 -0
- package/dist/config/types.d.ts +4 -0
- package/dist/content/types.d.ts +12 -0
- package/dist/edit/chrome/DraftBadge.svelte +30 -0
- package/dist/edit/chrome/DraftBadge.svelte.d.ts +18 -0
- package/dist/edit/types.d.ts +1 -1
- package/package.json +1 -1
|
@@ -97,7 +97,14 @@
|
|
|
97
97
|
{@const reply = replyFormFor(String(thread.id))}
|
|
98
98
|
<!-- Native disclosure: the reply form opens without JS. -->
|
|
99
99
|
<details class="reply">
|
|
100
|
-
<summary>
|
|
100
|
+
<summary>
|
|
101
|
+
<ActionLabel
|
|
102
|
+
edit={config.messageEdit?.('comments_replyLabel')}
|
|
103
|
+
value={msg.comments_replyLabel()}
|
|
104
|
+
>
|
|
105
|
+
{#snippet control()}{msg.comments_replyLabel()}{/snippet}
|
|
106
|
+
</ActionLabel>
|
|
107
|
+
</summary>
|
|
101
108
|
<form class="form-stack" {...reply}>
|
|
102
109
|
<Field
|
|
103
110
|
id="reply-body-{thread.id}"
|
|
@@ -173,9 +180,19 @@
|
|
|
173
180
|
>
|
|
174
181
|
{#snippet children(text, attrs)}<span {...attrs}>{text}</span>{/snippet}
|
|
175
182
|
</Editable>
|
|
176
|
-
<
|
|
183
|
+
<ActionLabel
|
|
184
|
+
edit={config.messageEdit?.('comments_loginLink')}
|
|
185
|
+
value={msg.comments_loginLink()}
|
|
186
|
+
>
|
|
187
|
+
{#snippet control()}<Link href="/login">{msg.comments_loginLink()}</Link>{/snippet}
|
|
188
|
+
</ActionLabel>
|
|
177
189
|
·
|
|
178
|
-
<
|
|
190
|
+
<ActionLabel
|
|
191
|
+
edit={config.messageEdit?.('comments_signupLink')}
|
|
192
|
+
value={msg.comments_signupLink()}
|
|
193
|
+
>
|
|
194
|
+
{#snippet control()}<Link href="/signup">{msg.comments_signupLink()}</Link>{/snippet}
|
|
195
|
+
</ActionLabel>
|
|
179
196
|
</p>
|
|
180
197
|
{/if}
|
|
181
198
|
</section>
|
|
@@ -2,34 +2,64 @@
|
|
|
2
2
|
import { getUiConfig } from '../../config/context.js';
|
|
3
3
|
import type { SortDirection } from '../../content/types.js';
|
|
4
4
|
import ActionLabel from '../../edit/ActionLabel.svelte';
|
|
5
|
+
import EditFrame from '../../edit/chrome/EditFrame.svelte';
|
|
6
|
+
import EditPanel from '../../edit/chrome/EditPanel.svelte';
|
|
7
|
+
import type { PropertyDescriptor } from '../../edit/types.js';
|
|
5
8
|
|
|
6
9
|
interface Props {
|
|
7
10
|
value: SortDirection;
|
|
8
11
|
onchange: (value: SortDirection) => void;
|
|
12
|
+
/**
|
|
13
|
+
* An <option> cannot hold a caret, so the option labels edit through
|
|
14
|
+
* the frame's panel — one text row per direction, descriptors from the
|
|
15
|
+
* host (chrome keys on the foundation site). The visible label keeps
|
|
16
|
+
* its ActionLabel swap. Inert without an adapter.
|
|
17
|
+
*/
|
|
18
|
+
optionsEdit?: (direction: SortDirection) => PropertyDescriptor | undefined;
|
|
9
19
|
}
|
|
10
20
|
|
|
11
|
-
let { value, onchange }: Props = $props();
|
|
21
|
+
let { value, onchange, optionsEdit }: Props = $props();
|
|
12
22
|
|
|
13
23
|
const config = getUiConfig();
|
|
14
24
|
const msg = $derived(config.messages);
|
|
15
25
|
|
|
26
|
+
const panelRows = $derived(
|
|
27
|
+
(
|
|
28
|
+
[
|
|
29
|
+
['desc', msg.weeklies_sortDesc()],
|
|
30
|
+
['asc', msg.weeklies_sortAsc()]
|
|
31
|
+
] as const
|
|
32
|
+
).flatMap(([direction, label]) => {
|
|
33
|
+
const descriptor = optionsEdit?.(direction);
|
|
34
|
+
return descriptor ? [{ descriptor, value: label }] : [];
|
|
35
|
+
})
|
|
36
|
+
);
|
|
37
|
+
const frameSpec = $derived(
|
|
38
|
+
panelRows.length > 0 ? { label: msg.weeklies_sortLabel(), hasPanel: true } : undefined
|
|
39
|
+
);
|
|
40
|
+
|
|
16
41
|
function handleChange(event: Event): void {
|
|
17
42
|
const target = event.currentTarget as HTMLSelectElement;
|
|
18
43
|
onchange(target.value === 'asc' ? 'asc' : 'desc');
|
|
19
44
|
}
|
|
20
45
|
</script>
|
|
21
46
|
|
|
22
|
-
<
|
|
23
|
-
{#snippet
|
|
24
|
-
<
|
|
25
|
-
<span>{msg.weeklies_sortLabel()}</span>
|
|
26
|
-
<select class="control" {value} onchange={handleChange}>
|
|
27
|
-
<option value="desc">{msg.weeklies_sortDesc()}</option>
|
|
28
|
-
<option value="asc">{msg.weeklies_sortAsc()}</option>
|
|
29
|
-
</select>
|
|
30
|
-
</label>
|
|
47
|
+
<EditFrame spec={frameSpec}>
|
|
48
|
+
{#snippet panel()}
|
|
49
|
+
<EditPanel rows={panelRows} />
|
|
31
50
|
{/snippet}
|
|
32
|
-
|
|
51
|
+
<ActionLabel edit={config.messageEdit?.('weeklies_sortLabel')} value={msg.weeklies_sortLabel()}>
|
|
52
|
+
{#snippet control()}
|
|
53
|
+
<label>
|
|
54
|
+
<span>{msg.weeklies_sortLabel()}</span>
|
|
55
|
+
<select class="control" {value} onchange={handleChange}>
|
|
56
|
+
<option value="desc">{msg.weeklies_sortDesc()}</option>
|
|
57
|
+
<option value="asc">{msg.weeklies_sortAsc()}</option>
|
|
58
|
+
</select>
|
|
59
|
+
</label>
|
|
60
|
+
{/snippet}
|
|
61
|
+
</ActionLabel>
|
|
62
|
+
</EditFrame>
|
|
33
63
|
|
|
34
64
|
<style>
|
|
35
65
|
label {
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import type { SortDirection } from '../../content/types.js';
|
|
2
|
+
import type { PropertyDescriptor } from '../../edit/types.js';
|
|
2
3
|
interface Props {
|
|
3
4
|
value: SortDirection;
|
|
4
5
|
onchange: (value: SortDirection) => void;
|
|
6
|
+
/**
|
|
7
|
+
* An <option> cannot hold a caret, so the option labels edit through
|
|
8
|
+
* the frame's panel — one text row per direction, descriptors from the
|
|
9
|
+
* host (chrome keys on the foundation site). The visible label keeps
|
|
10
|
+
* its ActionLabel swap. Inert without an adapter.
|
|
11
|
+
*/
|
|
12
|
+
optionsEdit?: (direction: SortDirection) => PropertyDescriptor | undefined;
|
|
5
13
|
}
|
|
6
14
|
declare const SortSelect: import("svelte").Component<Props, {}, "">;
|
|
7
15
|
type SortSelect = ReturnType<typeof SortSelect>;
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
<script module lang="ts">
|
|
2
|
-
import type { EditDescriptor } from '../../edit/types.js';
|
|
2
|
+
import type { EditDescriptor, PropertyDescriptor } from '../../edit/types.js';
|
|
3
3
|
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* Which of the card's fields are editable at this render site: localized
|
|
6
|
+
* text inline, the cover image through the frame's panel. NO collection
|
|
7
|
+
* ops — weeklies keep their own authoring flow in the CMS.
|
|
8
|
+
*/
|
|
5
9
|
export interface WeeklyEditMap {
|
|
6
10
|
title?: EditDescriptor;
|
|
7
11
|
excerpt?: EditDescriptor;
|
|
12
|
+
image?: PropertyDescriptor;
|
|
13
|
+
/** Accessible name for the frame, e.g. "Weekly #12". */
|
|
14
|
+
label?: string;
|
|
8
15
|
}
|
|
9
16
|
</script>
|
|
10
17
|
|
|
@@ -13,7 +20,10 @@
|
|
|
13
20
|
import type { WeeklyCardData } from '../../content/types.js';
|
|
14
21
|
import { getEditAdapter } from '../../edit/context.js';
|
|
15
22
|
import Editable from '../../edit/Editable.svelte';
|
|
23
|
+
import EditFrame from '../../edit/chrome/EditFrame.svelte';
|
|
24
|
+
import EditPanel from '../../edit/chrome/EditPanel.svelte';
|
|
16
25
|
import CardMedia from '../ui/CardMedia.svelte';
|
|
26
|
+
import DraftBadge from '../../edit/chrome/DraftBadge.svelte';
|
|
17
27
|
import CardTitle from '../ui/CardTitle.svelte';
|
|
18
28
|
import DateText from '../ui/DateText.svelte';
|
|
19
29
|
import Link from '../ui/Link.svelte';
|
|
@@ -33,26 +43,43 @@
|
|
|
33
43
|
// a contenteditable inside an anchor still navigates on click, which
|
|
34
44
|
// would throw the editor off the page mid-draft.
|
|
35
45
|
const titleEditing = $derived(edit?.title !== undefined && (adapter?.isEditing ?? false));
|
|
46
|
+
|
|
47
|
+
const panelRows = $derived(
|
|
48
|
+
[edit?.image && { descriptor: edit.image, value: weekly.imageUrl }].filter(
|
|
49
|
+
(row) => row !== undefined
|
|
50
|
+
)
|
|
51
|
+
);
|
|
52
|
+
const frameSpec = $derived(
|
|
53
|
+
edit && panelRows.length > 0 ? { label: edit.label ?? weekly.title, hasPanel: true } : undefined
|
|
54
|
+
);
|
|
36
55
|
</script>
|
|
37
56
|
|
|
38
57
|
<article>
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
58
|
+
<!-- Inside the article, so the grid the host lays cards into never gains
|
|
59
|
+
an unexpected child; inactive it renders the content alone. -->
|
|
60
|
+
<EditFrame spec={frameSpec}>
|
|
61
|
+
{#snippet panel()}
|
|
62
|
+
<EditPanel rows={panelRows} />
|
|
63
|
+
{/snippet}
|
|
64
|
+
<header>
|
|
65
|
+
<span class="number">{config.messages.weeklie_number({ number: weekly.number })}</span>
|
|
66
|
+
{#if weekly.draft}<DraftBadge />{/if}
|
|
67
|
+
<DateText value={weekly.publishedOn} />
|
|
68
|
+
</header>
|
|
69
|
+
<CardMedia src={weekly.imageUrl} alt="" ratio="1 / 1" width="600" height="600" />
|
|
70
|
+
<CardTitle>
|
|
71
|
+
{#if titleEditing}
|
|
72
|
+
<Editable edit={edit?.title} value={weekly.title}>
|
|
73
|
+
{#snippet children(text, attrs)}<span {...attrs}>{text}</span>{/snippet}
|
|
74
|
+
</Editable>
|
|
75
|
+
{:else}
|
|
76
|
+
<Link href={`/weeklies/${weekly.slug}`}>{weekly.title}</Link>
|
|
77
|
+
{/if}
|
|
78
|
+
</CardTitle>
|
|
79
|
+
<Editable edit={edit?.excerpt} value={weekly.excerpt}>
|
|
80
|
+
{#snippet children(text, attrs)}<p {...attrs}>{text}</p>{/snippet}
|
|
81
|
+
</Editable>
|
|
82
|
+
</EditFrame>
|
|
56
83
|
</article>
|
|
57
84
|
|
|
58
85
|
<style>
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
-
import type { EditDescriptor } from '../../edit/types.js';
|
|
2
|
-
/**
|
|
1
|
+
import type { EditDescriptor, PropertyDescriptor } from '../../edit/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Which of the card's fields are editable at this render site: localized
|
|
4
|
+
* text inline, the cover image through the frame's panel. NO collection
|
|
5
|
+
* ops — weeklies keep their own authoring flow in the CMS.
|
|
6
|
+
*/
|
|
3
7
|
export interface WeeklyEditMap {
|
|
4
8
|
title?: EditDescriptor;
|
|
5
9
|
excerpt?: EditDescriptor;
|
|
10
|
+
image?: PropertyDescriptor;
|
|
11
|
+
/** Accessible name for the frame, e.g. "Weekly #12". */
|
|
12
|
+
label?: string;
|
|
6
13
|
}
|
|
7
14
|
import type { WeeklyCardData } from '../../content/types.js';
|
|
8
15
|
interface Props {
|
|
@@ -36,6 +36,8 @@ export interface EditMessages {
|
|
|
36
36
|
edit_addFailed(): string;
|
|
37
37
|
/** Property rows. */
|
|
38
38
|
edit_uploadImage(): string;
|
|
39
|
+
/** The chip a card wears while its row is unpublished. */
|
|
40
|
+
edit_draftBadge(): string;
|
|
39
41
|
edit_clearValue(): string;
|
|
40
42
|
edit_emptyRequired(): string;
|
|
41
43
|
}
|
|
@@ -19,6 +19,7 @@ export const defaultEditMessages = {
|
|
|
19
19
|
edit_add: ({ label }) => `Afegeix ${label}`,
|
|
20
20
|
edit_addFailed: () => 'No s’ha pogut afegir',
|
|
21
21
|
edit_uploadImage: () => 'Puja una imatge',
|
|
22
|
+
edit_draftBadge: () => 'Esborrany',
|
|
22
23
|
edit_clearValue: () => 'Buida el valor',
|
|
23
24
|
edit_emptyRequired: () => 'Aquest camp no pot quedar buit'
|
|
24
25
|
};
|
package/dist/config/types.d.ts
CHANGED
|
@@ -12,8 +12,12 @@ export type Locale = (typeof LOCALES)[number];
|
|
|
12
12
|
export declare const BASE_LOCALE: Locale;
|
|
13
13
|
/** One primary-navigation entry, rendered by Nav and repeated by Footer. */
|
|
14
14
|
export interface SiteLink {
|
|
15
|
+
/** Present only where the nav is editable — structural ops need identity. */
|
|
16
|
+
id?: string | number;
|
|
15
17
|
href: string;
|
|
16
18
|
label: string;
|
|
19
|
+
/** The row's sort_order, for the CMS's order panel row. */
|
|
20
|
+
order?: number;
|
|
17
21
|
}
|
|
18
22
|
/**
|
|
19
23
|
* The strings the components render, as message *functions* so the app's
|
package/dist/content/types.d.ts
CHANGED
|
@@ -18,6 +18,8 @@ export type SortDirection = 'asc' | 'desc';
|
|
|
18
18
|
/** A weekly as its listing card shows it. */
|
|
19
19
|
export interface WeeklyCardData {
|
|
20
20
|
id: number;
|
|
21
|
+
/** CMS-only: true renders the «Esborrany» badge. The public site never sets it. */
|
|
22
|
+
draft?: boolean;
|
|
21
23
|
number: number;
|
|
22
24
|
slug: string;
|
|
23
25
|
/** ISO date (2026-08-30). */
|
|
@@ -30,6 +32,8 @@ export type ProjectKind = 'collaboration' | 'passion';
|
|
|
30
32
|
/** A project as its card shows it. */
|
|
31
33
|
export interface ProjectCardData {
|
|
32
34
|
id: number;
|
|
35
|
+
/** CMS-only: true renders the «Esborrany» badge. The public site never sets it. */
|
|
36
|
+
draft?: boolean;
|
|
33
37
|
slug: string;
|
|
34
38
|
kind: ProjectKind;
|
|
35
39
|
publishedOn: string;
|
|
@@ -43,6 +47,8 @@ export type MilestoneCategory = 'education' | 'lab' | 'foundation' | 'collaborat
|
|
|
43
47
|
/** One timeline milestone. */
|
|
44
48
|
export interface MilestoneData {
|
|
45
49
|
id: number;
|
|
50
|
+
/** CMS-only: true renders the «Esborrany» badge. The public site never sets it. */
|
|
51
|
+
draft?: boolean;
|
|
46
52
|
occurredOn: string;
|
|
47
53
|
category: MilestoneCategory;
|
|
48
54
|
title: string;
|
|
@@ -59,11 +65,17 @@ export interface TeamMemberData {
|
|
|
59
65
|
isBoard: boolean;
|
|
60
66
|
}
|
|
61
67
|
export interface CollaboratorData {
|
|
68
|
+
/** Present only where the list is editable — remove ops need an identity. */
|
|
69
|
+
id?: string | number;
|
|
62
70
|
personName: string;
|
|
63
71
|
affiliation: string;
|
|
64
72
|
url: string | null;
|
|
65
73
|
}
|
|
66
74
|
export interface JobOpeningData {
|
|
75
|
+
/** Present only where the list is editable — remove ops need an identity. */
|
|
76
|
+
id?: string | number;
|
|
77
|
+
/** CMS-only: true renders the «Esborrany» badge. The public site never sets it. */
|
|
78
|
+
draft?: boolean;
|
|
67
79
|
slug: string;
|
|
68
80
|
title: string;
|
|
69
81
|
description: string | null;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { getUiConfig } from '../../config/context.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The «Esborrany» chip a card wears while its row is unpublished. The flag
|
|
6
|
+
* arrives on the DATA (`draft?: boolean`), set only by a CMS host — the
|
|
7
|
+
* public site never marks anything draft, so its cards render without this
|
|
8
|
+
* component ever mounting. Wording comes from editMessages for the same
|
|
9
|
+
* reason: it is editor-facing, never catalog copy.
|
|
10
|
+
*/
|
|
11
|
+
const config = getUiConfig();
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<span class="draft">{config.editMessages.edit_draftBadge()}</span>
|
|
15
|
+
|
|
16
|
+
<style>
|
|
17
|
+
.draft {
|
|
18
|
+
display: inline-block;
|
|
19
|
+
align-self: start;
|
|
20
|
+
border: 1px solid var(--color-ink-muted);
|
|
21
|
+
border-radius: 999px;
|
|
22
|
+
padding: 0.1em 0.7em;
|
|
23
|
+
font-size: var(--text-sm);
|
|
24
|
+
font-weight: 600;
|
|
25
|
+
letter-spacing: 0.04em;
|
|
26
|
+
text-transform: uppercase;
|
|
27
|
+
color: var(--color-ink-muted);
|
|
28
|
+
background: var(--color-surface);
|
|
29
|
+
}
|
|
30
|
+
</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 DraftBadge: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
+
[evt: string]: CustomEvent<any>;
|
|
16
|
+
}, {}, {}, string>;
|
|
17
|
+
type DraftBadge = InstanceType<typeof DraftBadge>;
|
|
18
|
+
export default DraftBadge;
|
package/dist/edit/types.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export declare function localize(value: LocalizedText, locale: Locale): string;
|
|
|
15
15
|
* The entities whose fields the components can mark editable. Names match
|
|
16
16
|
* the content tables so an adapter can route a save without a mapping layer.
|
|
17
17
|
*/
|
|
18
|
-
export type EditableEntity = 'weeklies' | 'projects' | 'milestones' | 'team_members' | 'job_openings' | 'themes';
|
|
18
|
+
export type EditableEntity = 'weeklies' | 'projects' | 'milestones' | 'team_members' | 'job_openings' | 'themes' | 'collaborators' | 'site_links';
|
|
19
19
|
/**
|
|
20
20
|
* The identity of one editable string in the content model: a page copy
|
|
21
21
|
* block (`page_content` row), one localized field of a domain entity, or one
|