@vit-foundation/ui 0.15.0 → 0.17.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/README.md +10 -10
- package/dist/components/jobs/JobList.svelte +11 -19
- package/dist/components/jobs/JobList.svelte.d.ts +1 -1
- package/dist/components/layout/Footer.svelte +9 -15
- package/dist/components/layout/Nav.svelte +10 -15
- package/dist/components/projects/ProjectCard.svelte +2 -2
- package/dist/components/projects/ProjectCard.svelte.d.ts +1 -1
- package/dist/components/team/CollaboratorList.svelte +10 -16
- package/dist/components/timeline/Timeline.svelte +10 -23
- package/dist/components/timeline/TimelineMilestone.svelte +2 -2
- package/dist/components/timeline/TimelineMilestone.svelte.d.ts +1 -1
- package/dist/components/weeklies/WeeklieCard.svelte +2 -2
- package/dist/components/weeklies/WeeklieCard.svelte.d.ts +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/messages.js +5 -1
- package/dist/config/types.d.ts +35 -3
- package/dist/content-components.d.ts +6 -1
- package/dist/content-components.js +4 -1
- package/dist/edit/Editable.svelte +22 -38
- package/dist/edit/chrome/EditPanel.svelte +2 -2
- package/dist/edit/chrome/EditPanel.svelte.d.ts +2 -2
- package/dist/edit/chrome/LinkEdit.svelte +36 -4
- package/dist/edit/chrome/LinkEdit.svelte.d.ts +5 -1
- package/dist/edit/chrome/PropertyRow.svelte +69 -55
- package/dist/edit/chrome/PropertyRow.svelte.d.ts +11 -5
- package/dist/edit/collection.svelte.d.ts +49 -0
- package/dist/edit/collection.svelte.js +39 -0
- package/dist/edit/commit.svelte.d.ts +58 -0
- package/dist/edit/commit.svelte.js +70 -0
- package/dist/edit/helpers.d.ts +5 -5
- package/dist/edit/helpers.js +2 -2
- package/dist/edit/index.d.ts +4 -1
- package/dist/edit/index.js +1 -0
- package/dist/edit/types.d.ts +24 -9
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/utils/milestones.d.ts +15 -0
- package/dist/utils/milestones.js +17 -0
- package/dist/utils/paths.d.ts +6 -0
- package/dist/utils/paths.js +14 -0
- package/dist/utils/url-filters.svelte.d.ts +58 -0
- package/dist/utils/url-filters.svelte.js +47 -0
- package/dist/utils/weekly-list.svelte.d.ts +82 -0
- package/dist/utils/weekly-list.svelte.js +120 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,16 +22,16 @@ Requires `svelte` ^5.0.0 as a peer. Import the two stylesheets once:
|
|
|
22
22
|
|
|
23
23
|
Everything exports flat from the root, and again grouped by role:
|
|
24
24
|
|
|
25
|
-
| Entry point | What lives there
|
|
26
|
-
| --------------------------------------------------------------- |
|
|
27
|
-
| [`/primitives`](./docs/components/primitives.md) | Button, GhostButton, Link, CardMedia, CardTitle, CopyIntro, DateText, DecorShapes, FilterChips, Pagination, RichText, SearchInput, ShareRow
|
|
28
|
-
| [`/forms`](./docs/forms.md) | Field, FormFeedback, FormErrorFeedback, FormResultSlot, Honeypot, LocaleField, NewsletterIntentField — plus the remote-form seam: structural types, transport constants, field bounds
|
|
29
|
-
| [`/chrome`](./docs/components/chrome.md) | PageShell, Nav, Footer
|
|
30
|
-
| [`/content`](./docs/components/content.md) | WeeklieCard, ProjectCard, Timeline, TimelineMilestone, TeamMemberCard, CollaboratorList, JobList, SortSelect — plus the data shapes and
|
|
31
|
-
| [`/community`](./docs/components/community.md) | AuthPageShell, LoginForm, SignupForm, GoogleAuthForm, AccountPanel, NewsletterSignup, CommentSection, ReactionBar, ContactForm
|
|
32
|
-
| [`/edit`](./docs/edit-mode.md) | Editable, setEditAdapter/getEditAdapter, descriptors and helpers, LocalizedText |
|
|
33
|
-
| [`/config`](./docs/getting-started.md#wiring-an-app-uiprovider) | UiProvider, UiConfig, the locale set, the default Catalan messages
|
|
34
|
-
| `/testing` | createRemoteFormMock — the remote-form stand-in for stories and tests
|
|
25
|
+
| Entry point | What lives there |
|
|
26
|
+
| --------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
27
|
+
| [`/primitives`](./docs/components/primitives.md) | Button, GhostButton, Link, CardMedia, CardTitle, CopyIntro, DateText, DecorShapes, FilterChips, Pagination, RichText, SearchInput, ShareRow |
|
|
28
|
+
| [`/forms`](./docs/forms.md) | Field, FormFeedback, FormErrorFeedback, FormResultSlot, Honeypot, LocaleField, NewsletterIntentField — plus the remote-form seam: structural types, transport constants, field bounds |
|
|
29
|
+
| [`/chrome`](./docs/components/chrome.md) | PageShell, Nav, Footer |
|
|
30
|
+
| [`/content`](./docs/components/content.md) | WeeklieCard, ProjectCard, Timeline, TimelineMilestone, TeamMemberCard, CollaboratorList, JobList, SortSelect — plus the data shapes, helpers and the two list rules (createWeeklyList, createUrlFilters) |
|
|
31
|
+
| [`/community`](./docs/components/community.md) | AuthPageShell, LoginForm, SignupForm, GoogleAuthForm, AccountPanel, NewsletterSignup, CommentSection, ReactionBar, ContactForm |
|
|
32
|
+
| [`/edit`](./docs/edit-mode.md) | Editable, setEditAdapter/getEditAdapter, descriptors and helpers, collectionEditing, LocalizedText |
|
|
33
|
+
| [`/config`](./docs/getting-started.md#wiring-an-app-uiprovider) | UiProvider, UiConfig, the locale set, the default Catalan messages |
|
|
34
|
+
| `/testing` | createRemoteFormMock — the remote-form stand-in for stories and tests |
|
|
35
35
|
|
|
36
36
|
Every component renders standalone (Catalan copy, identity hrefs); an app
|
|
37
37
|
integrates its i18n and router through one `UiProvider` in the root layout.
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
title?: EditDescriptor;
|
|
10
10
|
description?: EditDescriptor;
|
|
11
11
|
postedOn?: PropertyDescriptor;
|
|
12
|
-
/** Editorial
|
|
12
|
+
/** Editorial-state `flag` row; on while the opening is not a draft. */
|
|
13
13
|
status?: PropertyDescriptor;
|
|
14
14
|
/** Accessible name for the frame — usually the opening's title. */
|
|
15
15
|
label?: string;
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
import DraftBadge from '../../edit/chrome/DraftBadge.svelte';
|
|
26
26
|
import EditFrame from '../../edit/chrome/EditFrame.svelte';
|
|
27
27
|
import EditPanel from '../../edit/chrome/EditPanel.svelte';
|
|
28
|
-
import {
|
|
28
|
+
import { collectionEditing } from '../../edit/collection.svelte.js';
|
|
29
29
|
import Editable from '../../edit/Editable.svelte';
|
|
30
30
|
import type { CollectionRef } from '../../edit/types.js';
|
|
31
31
|
import DateText from '../ui/DateText.svelte';
|
|
@@ -48,27 +48,19 @@
|
|
|
48
48
|
let { jobs, editFor, collection }: Props = $props();
|
|
49
49
|
|
|
50
50
|
const config = getUiConfig();
|
|
51
|
-
const adapter = getEditAdapter();
|
|
52
51
|
const msg = $derived(config.messages);
|
|
53
52
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
/** The map the host gave, plus removal — the list owns identity. */
|
|
59
|
-
function editMapFor(job: JobOpeningData): JobEditMap | undefined {
|
|
60
|
-
const map = editFor?.(job);
|
|
61
|
-
if (!structural || !collection || job.id === undefined) return map;
|
|
62
|
-
return { ...map, removeOp: { kind: 'remove', collection, id: job.id } };
|
|
63
|
-
}
|
|
53
|
+
// The structural half (add slot, removal for rows with an id) — see
|
|
54
|
+
// collectionEditing.
|
|
55
|
+
const list = collectionEditing<JobOpeningData, JobEditMap>(() => ({ collection, editFor }));
|
|
64
56
|
</script>
|
|
65
57
|
|
|
66
58
|
{#if jobs.length === 0}
|
|
67
59
|
<Editable edit={config.messageEdit?.('jobs_empty')} value={msg.jobs_empty()}>
|
|
68
60
|
{#snippet children(text, attrs)}<p class="empty" {...attrs}>{text}</p>{/snippet}
|
|
69
61
|
</Editable>
|
|
70
|
-
{#if
|
|
71
|
-
<AddSlot op={
|
|
62
|
+
{#if list.add}
|
|
63
|
+
<AddSlot op={list.add} />
|
|
72
64
|
{/if}
|
|
73
65
|
<Editable edit={config.messageEdit?.('jobs_newsletterNudge')} value={msg.jobs_newsletterNudge()}>
|
|
74
66
|
{#snippet children(text, attrs)}<p class="nudge" {...attrs}>{text}</p>{/snippet}
|
|
@@ -76,10 +68,10 @@
|
|
|
76
68
|
{:else}
|
|
77
69
|
<ul>
|
|
78
70
|
{#each jobs as job (job.slug)}
|
|
79
|
-
{@const edit =
|
|
71
|
+
{@const edit = list.mapFor(job)}
|
|
80
72
|
{@const rows = [
|
|
81
73
|
edit?.postedOn && { descriptor: edit.postedOn, value: job.postedOn },
|
|
82
|
-
edit?.status && { descriptor: edit.status, value: job.draft
|
|
74
|
+
edit?.status && { descriptor: edit.status, value: !job.draft }
|
|
83
75
|
].filter((row) => row !== undefined)}
|
|
84
76
|
<li>
|
|
85
77
|
<!-- Inside the li — see CollaboratorList. -->
|
|
@@ -108,9 +100,9 @@
|
|
|
108
100
|
</EditFrame>
|
|
109
101
|
</li>
|
|
110
102
|
{/each}
|
|
111
|
-
{#if
|
|
103
|
+
{#if list.add}
|
|
112
104
|
<li class="add-slot">
|
|
113
|
-
<AddSlot op={
|
|
105
|
+
<AddSlot op={list.add} />
|
|
114
106
|
</li>
|
|
115
107
|
{/if}
|
|
116
108
|
</ul>
|
|
@@ -7,7 +7,7 @@ export interface JobEditMap {
|
|
|
7
7
|
title?: EditDescriptor;
|
|
8
8
|
description?: EditDescriptor;
|
|
9
9
|
postedOn?: PropertyDescriptor;
|
|
10
|
-
/** Editorial
|
|
10
|
+
/** Editorial-state `flag` row; on while the opening is not a draft. */
|
|
11
11
|
status?: PropertyDescriptor;
|
|
12
12
|
/** Accessible name for the frame — usually the opening's title. */
|
|
13
13
|
label?: string;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import type { SiteLink } from '../../config/types.js';
|
|
4
4
|
import AddSlot from '../../edit/chrome/AddSlot.svelte';
|
|
5
5
|
import LinkEdit from '../../edit/chrome/LinkEdit.svelte';
|
|
6
|
-
import {
|
|
6
|
+
import { collectionEditing } from '../../edit/collection.svelte.js';
|
|
7
7
|
import Editable from '../../edit/Editable.svelte';
|
|
8
8
|
import type { CollectionRef, EditDescriptor } from '../../edit/types.js';
|
|
9
9
|
import Link from '../ui/Link.svelte';
|
|
@@ -27,18 +27,12 @@
|
|
|
27
27
|
let { links, editFor = undefined, propertiesFor = undefined, collection }: Props = $props();
|
|
28
28
|
|
|
29
29
|
const config = getUiConfig();
|
|
30
|
-
const adapter = getEditAdapter();
|
|
31
30
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
function editMapFor(link: SiteLink): SiteLinkEditMap | undefined {
|
|
38
|
-
const map = propertiesFor?.(link);
|
|
39
|
-
if (!structural || !collection || link.id === undefined) return map;
|
|
40
|
-
return { ...map, removeOp: { kind: 'remove', collection, id: link.id } };
|
|
41
|
-
}
|
|
31
|
+
// Same structural half as Nav — see collectionEditing.
|
|
32
|
+
const list = collectionEditing<SiteLink, SiteLinkEditMap>(() => ({
|
|
33
|
+
collection,
|
|
34
|
+
editFor: propertiesFor
|
|
35
|
+
}));
|
|
42
36
|
|
|
43
37
|
const year = new Date().getFullYear();
|
|
44
38
|
</script>
|
|
@@ -50,7 +44,7 @@
|
|
|
50
44
|
</span>
|
|
51
45
|
<ul>
|
|
52
46
|
{#each links as link (link.href)}
|
|
53
|
-
{@const map =
|
|
47
|
+
{@const map = list.mapFor(link)}
|
|
54
48
|
<li>
|
|
55
49
|
<!-- One gesture: the modal edits text, destination, order, removal. -->
|
|
56
50
|
<LinkEdit
|
|
@@ -66,9 +60,9 @@
|
|
|
66
60
|
</LinkEdit>
|
|
67
61
|
</li>
|
|
68
62
|
{/each}
|
|
69
|
-
{#if
|
|
63
|
+
{#if list.add}
|
|
70
64
|
<li>
|
|
71
|
-
<AddSlot op={
|
|
65
|
+
<AddSlot op={list.add} />
|
|
72
66
|
</li>
|
|
73
67
|
{/if}
|
|
74
68
|
</ul>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import type { SiteLink } from '../../config/types.js';
|
|
4
4
|
import AddSlot from '../../edit/chrome/AddSlot.svelte';
|
|
5
5
|
import LinkEdit from '../../edit/chrome/LinkEdit.svelte';
|
|
6
|
-
import {
|
|
6
|
+
import { collectionEditing } from '../../edit/collection.svelte.js';
|
|
7
7
|
import type { CollectionRef, EditDescriptor } from '../../edit/types.js';
|
|
8
8
|
import { isPathUnder } from '../../utils/paths.js';
|
|
9
9
|
import GhostButton from '../ui/GhostButton.svelte';
|
|
@@ -45,18 +45,13 @@
|
|
|
45
45
|
}: Props = $props();
|
|
46
46
|
|
|
47
47
|
const config = getUiConfig();
|
|
48
|
-
const adapter = getEditAdapter();
|
|
49
48
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const map = propertiesFor?.(link);
|
|
57
|
-
if (!structural || !collection || link.id === undefined) return map;
|
|
58
|
-
return { ...map, removeOp: { kind: 'remove', collection, id: link.id } };
|
|
59
|
-
}
|
|
49
|
+
// The structural half — add slot and per-link removal — shared with every
|
|
50
|
+
// other editable list; see collectionEditing.
|
|
51
|
+
const list = collectionEditing<SiteLink, SiteLinkEditMap>(() => ({
|
|
52
|
+
collection,
|
|
53
|
+
editFor: propertiesFor
|
|
54
|
+
}));
|
|
60
55
|
|
|
61
56
|
const msg = $derived(config.messages);
|
|
62
57
|
|
|
@@ -113,7 +108,7 @@
|
|
|
113
108
|
<div class="menu" id="site-menu" class:open={isMenuOpen}>
|
|
114
109
|
<ul class="links">
|
|
115
110
|
{#each links as link (link.href)}
|
|
116
|
-
{@const map =
|
|
111
|
+
{@const map = list.mapFor(link)}
|
|
117
112
|
<li>
|
|
118
113
|
<!-- One gesture: clicking the entry opens the modal that edits
|
|
119
114
|
its text, destination, order and removal together. -->
|
|
@@ -134,9 +129,9 @@
|
|
|
134
129
|
</LinkEdit>
|
|
135
130
|
</li>
|
|
136
131
|
{/each}
|
|
137
|
-
{#if
|
|
132
|
+
{#if list.add}
|
|
138
133
|
<li>
|
|
139
|
-
<AddSlot op={
|
|
134
|
+
<AddSlot op={list.add} />
|
|
140
135
|
</li>
|
|
141
136
|
{/if}
|
|
142
137
|
</ul>
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
publishedOn?: PropertyDescriptor;
|
|
13
13
|
externalUrl?: PropertyDescriptor;
|
|
14
14
|
image?: PropertyDescriptor;
|
|
15
|
-
/** Editorial
|
|
15
|
+
/** Editorial-state `flag` row; on while the project is not a draft. */
|
|
16
16
|
status?: PropertyDescriptor;
|
|
17
17
|
/** Accessible name for the frame, e.g. the project's title. */
|
|
18
18
|
label?: string;
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
edit?.publishedOn && { descriptor: edit.publishedOn, value: project.publishedOn },
|
|
71
71
|
edit?.externalUrl && { descriptor: edit.externalUrl, value: project.externalUrl },
|
|
72
72
|
edit?.image && { descriptor: edit.image, value: project.imageUrl },
|
|
73
|
-
edit?.status && { descriptor: edit.status, value: project.draft
|
|
73
|
+
edit?.status && { descriptor: edit.status, value: !project.draft }
|
|
74
74
|
].filter((row) => row !== undefined)
|
|
75
75
|
);
|
|
76
76
|
const frameSpec = $derived(
|
|
@@ -10,7 +10,7 @@ export interface ProjectEditMap {
|
|
|
10
10
|
publishedOn?: PropertyDescriptor;
|
|
11
11
|
externalUrl?: PropertyDescriptor;
|
|
12
12
|
image?: PropertyDescriptor;
|
|
13
|
-
/** Editorial
|
|
13
|
+
/** Editorial-state `flag` row; on while the project is not a draft. */
|
|
14
14
|
status?: PropertyDescriptor;
|
|
15
15
|
/** Accessible name for the frame, e.g. the project's title. */
|
|
16
16
|
label?: string;
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
import AddSlot from '../../edit/chrome/AddSlot.svelte';
|
|
23
23
|
import EditFrame from '../../edit/chrome/EditFrame.svelte';
|
|
24
24
|
import EditPanel from '../../edit/chrome/EditPanel.svelte';
|
|
25
|
-
import {
|
|
25
|
+
import { collectionEditing } from '../../edit/collection.svelte.js';
|
|
26
26
|
import type { CollectionRef } from '../../edit/types.js';
|
|
27
27
|
|
|
28
28
|
interface Props {
|
|
@@ -39,18 +39,12 @@
|
|
|
39
39
|
|
|
40
40
|
let { collaborators, editFor, collection }: Props = $props();
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const
|
|
45
|
-
collection
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
/** The map the host gave, plus removal — the list owns identity. */
|
|
49
|
-
function editMapFor(collaborator: CollaboratorData): CollaboratorEditMap | undefined {
|
|
50
|
-
const map = editFor?.(collaborator);
|
|
51
|
-
if (!structural || !collection || collaborator.id === undefined) return map;
|
|
52
|
-
return { ...map, removeOp: { kind: 'remove', collection, id: collaborator.id } };
|
|
53
|
-
}
|
|
42
|
+
// The structural half (add slot, removal for rows with an id) — see
|
|
43
|
+
// collectionEditing.
|
|
44
|
+
const list = collectionEditing<CollaboratorData, CollaboratorEditMap>(() => ({
|
|
45
|
+
collection,
|
|
46
|
+
editFor
|
|
47
|
+
}));
|
|
54
48
|
|
|
55
49
|
function rowsFor(collaborator: CollaboratorData, map: CollaboratorEditMap | undefined) {
|
|
56
50
|
return [
|
|
@@ -63,7 +57,7 @@
|
|
|
63
57
|
|
|
64
58
|
<ul>
|
|
65
59
|
{#each collaborators as collaborator (collaborator.id ?? collaborator.personName + collaborator.affiliation)}
|
|
66
|
-
{@const map =
|
|
60
|
+
{@const map = list.mapFor(collaborator)}
|
|
67
61
|
{@const rows = rowsFor(collaborator, map)}
|
|
68
62
|
<li>
|
|
69
63
|
<!-- Inside the li, so the list's own layout never gains a child. -->
|
|
@@ -89,9 +83,9 @@
|
|
|
89
83
|
</EditFrame>
|
|
90
84
|
</li>
|
|
91
85
|
{/each}
|
|
92
|
-
{#if
|
|
86
|
+
{#if list.add}
|
|
93
87
|
<li class="add-slot">
|
|
94
|
-
<AddSlot op={
|
|
88
|
+
<AddSlot op={list.add} />
|
|
95
89
|
</li>
|
|
96
90
|
{/if}
|
|
97
91
|
</ul>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import type { MilestoneData } from '../../content/types.js';
|
|
4
4
|
import type { MilestoneEditMap } from './TimelineMilestone.svelte';
|
|
5
5
|
import AddSlot from '../../edit/chrome/AddSlot.svelte';
|
|
6
|
-
import {
|
|
6
|
+
import { collectionEditing } from '../../edit/collection.svelte.js';
|
|
7
7
|
import type { CollectionRef } from '../../edit/types.js';
|
|
8
8
|
import { yearOf } from '../../utils/dates.js';
|
|
9
9
|
import TimelineMilestone from './TimelineMilestone.svelte';
|
|
@@ -26,18 +26,10 @@
|
|
|
26
26
|
let { milestones, variant = 'compact', editFor, collection }: Props = $props();
|
|
27
27
|
|
|
28
28
|
const config = getUiConfig();
|
|
29
|
-
const adapter = getEditAdapter();
|
|
30
29
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
/** The map the host gave, plus removal — the list owns identity and order. */
|
|
36
|
-
function editMapFor(milestone: MilestoneData): MilestoneEditMap | undefined {
|
|
37
|
-
const map = editFor?.(milestone);
|
|
38
|
-
if (!structural || !collection) return map;
|
|
39
|
-
return { ...map, removeOp: { kind: 'remove', collection, id: milestone.id } };
|
|
40
|
-
}
|
|
30
|
+
// The structural half (add slots, per-card removal); the list owns
|
|
31
|
+
// identity and order — see collectionEditing.
|
|
32
|
+
const list = collectionEditing<MilestoneData, MilestoneEditMap>(() => ({ collection, editFor }));
|
|
41
33
|
|
|
42
34
|
interface TimelineEntry {
|
|
43
35
|
milestone: MilestoneData;
|
|
@@ -68,27 +60,22 @@
|
|
|
68
60
|
>
|
|
69
61
|
<ol>
|
|
70
62
|
{#each entries as entry (entry.milestone.id)}
|
|
71
|
-
{
|
|
63
|
+
{@const before = list.addBefore(entry.milestone.id)}
|
|
64
|
+
{#if before}
|
|
72
65
|
<li class="add-slot">
|
|
73
|
-
<AddSlot
|
|
74
|
-
op={{
|
|
75
|
-
kind: 'create',
|
|
76
|
-
collection,
|
|
77
|
-
anchor: { id: entry.milestone.id, placement: 'before' }
|
|
78
|
-
}}
|
|
79
|
-
/>
|
|
66
|
+
<AddSlot op={before} />
|
|
80
67
|
</li>
|
|
81
68
|
{/if}
|
|
82
69
|
<li>
|
|
83
70
|
{#if entry.yearMarker}
|
|
84
71
|
<span class="year">{entry.yearMarker}</span>
|
|
85
72
|
{/if}
|
|
86
|
-
<TimelineMilestone milestone={entry.milestone} edit={
|
|
73
|
+
<TimelineMilestone milestone={entry.milestone} edit={list.mapFor(entry.milestone)} />
|
|
87
74
|
</li>
|
|
88
75
|
{/each}
|
|
89
|
-
{#if
|
|
76
|
+
{#if list.add}
|
|
90
77
|
<li class="add-slot">
|
|
91
|
-
<AddSlot op={
|
|
78
|
+
<AddSlot op={list.add} />
|
|
92
79
|
</li>
|
|
93
80
|
{/if}
|
|
94
81
|
</ol>
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
category?: PropertyDescriptor;
|
|
14
14
|
linkUrl?: PropertyDescriptor;
|
|
15
15
|
image?: PropertyDescriptor;
|
|
16
|
-
/** Editorial
|
|
16
|
+
/** Editorial-state `flag` row; on while the milestone is not a draft. */
|
|
17
17
|
status?: PropertyDescriptor;
|
|
18
18
|
/** Accessible name for the frame, e.g. "Fita: Neix la fundació". */
|
|
19
19
|
label?: string;
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
},
|
|
68
68
|
edit?.linkUrl && { descriptor: edit.linkUrl, value: milestone.linkUrl },
|
|
69
69
|
edit?.image && { descriptor: edit.image, value: milestone.imageUrls[0] ?? null },
|
|
70
|
-
edit?.status && { descriptor: edit.status, value: milestone.draft
|
|
70
|
+
edit?.status && { descriptor: edit.status, value: !milestone.draft }
|
|
71
71
|
].filter((row) => row !== undefined)
|
|
72
72
|
);
|
|
73
73
|
|
|
@@ -11,7 +11,7 @@ export interface MilestoneEditMap {
|
|
|
11
11
|
category?: PropertyDescriptor;
|
|
12
12
|
linkUrl?: PropertyDescriptor;
|
|
13
13
|
image?: PropertyDescriptor;
|
|
14
|
-
/** Editorial
|
|
14
|
+
/** Editorial-state `flag` row; on while the milestone is not a draft. */
|
|
15
15
|
status?: PropertyDescriptor;
|
|
16
16
|
/** Accessible name for the frame, e.g. "Fita: Neix la fundació". */
|
|
17
17
|
label?: string;
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
title?: EditDescriptor;
|
|
11
11
|
excerpt?: EditDescriptor;
|
|
12
12
|
image?: PropertyDescriptor;
|
|
13
|
-
/** Editorial
|
|
13
|
+
/** Editorial-state `flag` row; on while the weekly is not a draft. */
|
|
14
14
|
status?: PropertyDescriptor;
|
|
15
15
|
/** Accessible name for the frame, e.g. "Weekly #12". */
|
|
16
16
|
label?: string;
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
const panelRows = $derived(
|
|
50
50
|
[
|
|
51
51
|
edit?.image && { descriptor: edit.image, value: weekly.imageUrl },
|
|
52
|
-
edit?.status && { descriptor: edit.status, value: weekly.draft
|
|
52
|
+
edit?.status && { descriptor: edit.status, value: !weekly.draft }
|
|
53
53
|
].filter((row) => row !== undefined)
|
|
54
54
|
);
|
|
55
55
|
const frameSpec = $derived(
|
|
@@ -8,7 +8,7 @@ export interface WeeklyEditMap {
|
|
|
8
8
|
title?: EditDescriptor;
|
|
9
9
|
excerpt?: EditDescriptor;
|
|
10
10
|
image?: PropertyDescriptor;
|
|
11
|
-
/** Editorial
|
|
11
|
+
/** Editorial-state `flag` row; on while the weekly is not a draft. */
|
|
12
12
|
status?: PropertyDescriptor;
|
|
13
13
|
/** Accessible name for the frame, e.g. "Weekly #12". */
|
|
14
14
|
label?: string;
|
package/dist/config/index.d.ts
CHANGED
|
@@ -4,4 +4,4 @@ export type { EditMessages } from './edit-messages.js';
|
|
|
4
4
|
export { defaultMessages } from './messages.js';
|
|
5
5
|
export { default as UiProvider } from './UiProvider.svelte';
|
|
6
6
|
export { BASE_LOCALE, LOCALES } from './types.js';
|
|
7
|
-
export type { Locale, SiteLink, UiConfig, UiConfigInput, UiMessages } from './types.js';
|
|
7
|
+
export type { Locale, NotParameterized, ParameterizedKey, ParameterlessKey, SiteLink, UiConfig, UiConfigInput, UiMessages } from './types.js';
|
package/dist/config/messages.js
CHANGED
|
@@ -104,5 +104,9 @@ export const defaultMessages = {
|
|
|
104
104
|
category_lab: () => 'Laboratori',
|
|
105
105
|
category_education: () => 'Educació',
|
|
106
106
|
category_collaboration: () => 'Col·laboració',
|
|
107
|
-
category_press: () => 'Premsa'
|
|
107
|
+
category_press: () => 'Premsa',
|
|
108
|
+
status_published: () => 'Publicat',
|
|
109
|
+
status_draft: () => 'Esborrany',
|
|
110
|
+
status_open: () => 'Oberta',
|
|
111
|
+
status_closed: () => 'Tancada'
|
|
108
112
|
};
|
package/dist/config/types.d.ts
CHANGED
|
@@ -142,7 +142,39 @@ export interface UiMessages {
|
|
|
142
142
|
category_education(): string;
|
|
143
143
|
category_collaboration(): string;
|
|
144
144
|
category_press(): string;
|
|
145
|
+
/**
|
|
146
|
+
* Editorial state, as the panel's `flag` rows word it: a card's
|
|
147
|
+
* published/draft pair, an opening's open/closed pair. Catalog keys rather
|
|
148
|
+
* than editor strings because the CMS edits them per locale like any other
|
|
149
|
+
* wording — and required, like every key but the *Href pair, because
|
|
150
|
+
* `messages` is all-or-nothing (see ./messages.js).
|
|
151
|
+
*/
|
|
152
|
+
status_published(): string;
|
|
153
|
+
status_draft(): string;
|
|
154
|
+
status_open(): string;
|
|
155
|
+
status_closed(): string;
|
|
145
156
|
}
|
|
157
|
+
/**
|
|
158
|
+
* The catalog keys whose message takes NO parameters — the only ones edit
|
|
159
|
+
* mode may offer as text, inline or in a panel: editing the RENDERED text of
|
|
160
|
+
* a parameterized message (`pagination_status`, `weeklie_number`) would
|
|
161
|
+
* overwrite its template with one interpolation. Derived from the message
|
|
162
|
+
* signatures, so the rule is checked where a key is named; the optional
|
|
163
|
+
* *Href pair qualifies like any other zero-argument message.
|
|
164
|
+
*/
|
|
165
|
+
export type ParameterlessKey = {
|
|
166
|
+
[K in keyof UiMessages]-?: NonNullable<UiMessages[K]> extends () => string ? K : never;
|
|
167
|
+
}[keyof UiMessages];
|
|
168
|
+
/** The complement: keys whose message interpolates something. */
|
|
169
|
+
export type ParameterizedKey = Exclude<keyof UiMessages, ParameterlessKey>;
|
|
170
|
+
/**
|
|
171
|
+
* A key a chrome PROPERTY may name: any string but one of the package's own
|
|
172
|
+
* parameterized keys. Wider than `ParameterlessKey` on purpose — the site's
|
|
173
|
+
* catalog has wording the components never render themselves (a search
|
|
174
|
+
* placeholder is the host's), and that key the host vouches for; the
|
|
175
|
+
* package refuses only what it can check.
|
|
176
|
+
*/
|
|
177
|
+
export type NotParameterized<K extends string> = K extends ParameterizedKey ? never : K;
|
|
146
178
|
/**
|
|
147
179
|
* Everything the components read from their host app, resolved. Apps provide
|
|
148
180
|
* a partial (`UiConfigInput`) through UiProvider; components read this
|
|
@@ -179,10 +211,10 @@ export interface UiConfig {
|
|
|
179
211
|
* Edit descriptor for one of THIS config's message strings, by catalog
|
|
180
212
|
* key — the interface-wording half of edit mode. Optional and undefined by
|
|
181
213
|
* default, so a read-only app (and every story/test) renders the messages
|
|
182
|
-
* as plain text. A CMS-shaped host supplies it alongside an EditAdapter
|
|
183
|
-
*
|
|
214
|
+
* as plain text. A CMS-shaped host supplies it alongside an EditAdapter.
|
|
215
|
+
* The key type is the rule: only a `ParameterlessKey` may edit as text.
|
|
184
216
|
*/
|
|
185
|
-
messageEdit?: (key:
|
|
217
|
+
messageEdit?: (key: ParameterlessKey) => EditDescriptor | undefined;
|
|
186
218
|
}
|
|
187
219
|
/** What an app hands UiProvider: any subset; the rest keeps package defaults. */
|
|
188
220
|
export interface UiConfigInput {
|
|
@@ -11,12 +11,17 @@ export type { ProjectEditMap } from './components/projects/ProjectCard.svelte';
|
|
|
11
11
|
export { default as SortSelect } from './components/weeklies/SortSelect.svelte';
|
|
12
12
|
export { default as TeamMemberCard } from './components/team/TeamMemberCard.svelte';
|
|
13
13
|
export type { TeamMemberEditMap } from './components/team/TeamMemberCard.svelte';
|
|
14
|
+
export type { CollaboratorEditMap } from './components/team/CollaboratorList.svelte';
|
|
14
15
|
export { default as Timeline } from './components/timeline/Timeline.svelte';
|
|
15
16
|
export { default as TimelineMilestone } from './components/timeline/TimelineMilestone.svelte';
|
|
16
17
|
export type { MilestoneEditMap } from './components/timeline/TimelineMilestone.svelte';
|
|
17
18
|
export { default as WeeklieCard } from './components/weeklies/WeeklieCard.svelte';
|
|
18
19
|
export type { WeeklyEditMap } from './components/weeklies/WeeklieCard.svelte';
|
|
19
20
|
export * from './content/index.js';
|
|
20
|
-
export { MILESTONE_CATEGORY_COLOR, milestoneCategoryLabel } from './utils/milestones.js';
|
|
21
|
+
export { MILESTONE_CATEGORY_COLOR, matchesMilestoneFilter, milestoneCategoryLabel } from './utils/milestones.js';
|
|
22
|
+
export { createUrlFilters } from './utils/url-filters.svelte.js';
|
|
23
|
+
export type { UrlFilters, UrlFiltersConfig } from './utils/url-filters.svelte.js';
|
|
24
|
+
export { createWeeklyList, WEEKLY_LIST_DEFAULTS } from './utils/weekly-list.svelte.js';
|
|
25
|
+
export type { WeeklyList, WeeklyListConfig, WeeklyListFilters, WeeklyListPage, WeeklyListServerData } from './utils/weekly-list.svelte.js';
|
|
21
26
|
export { contactCategoryLabel } from './utils/contact.js';
|
|
22
27
|
export { formatDate, yearOf } from './utils/dates.js';
|
|
@@ -12,6 +12,9 @@ export { default as Timeline } from './components/timeline/Timeline.svelte';
|
|
|
12
12
|
export { default as TimelineMilestone } from './components/timeline/TimelineMilestone.svelte';
|
|
13
13
|
export { default as WeeklieCard } from './components/weeklies/WeeklieCard.svelte';
|
|
14
14
|
export * from './content/index.js';
|
|
15
|
-
export { MILESTONE_CATEGORY_COLOR, milestoneCategoryLabel } from './utils/milestones.js';
|
|
15
|
+
export { MILESTONE_CATEGORY_COLOR, matchesMilestoneFilter, milestoneCategoryLabel } from './utils/milestones.js';
|
|
16
|
+
// The two list rules: URL-mirrored filters, and the weeklies index over them.
|
|
17
|
+
export { createUrlFilters } from './utils/url-filters.svelte.js';
|
|
18
|
+
export { createWeeklyList, WEEKLY_LIST_DEFAULTS } from './utils/weekly-list.svelte.js';
|
|
16
19
|
export { contactCategoryLabel } from './utils/contact.js';
|
|
17
20
|
export { formatDate, yearOf } from './utils/dates.js';
|