@vit-foundation/ui 0.24.2 → 0.25.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.
Files changed (32) hide show
  1. package/README.md +11 -11
  2. package/dist/components/pages/GetInvolvedPage.svelte +139 -0
  3. package/dist/components/pages/GetInvolvedPage.svelte.d.ts +36 -0
  4. package/dist/components/pages/HomePage.svelte +256 -0
  5. package/dist/components/pages/HomePage.svelte.d.ts +36 -0
  6. package/dist/components/pages/LegalPage.svelte +39 -0
  7. package/dist/components/pages/LegalPage.svelte.d.ts +14 -0
  8. package/dist/components/pages/ProjectPage.svelte +128 -0
  9. package/dist/components/pages/ProjectPage.svelte.d.ts +17 -0
  10. package/dist/components/pages/TransparencyPage.svelte +164 -0
  11. package/dist/components/pages/TransparencyPage.svelte.d.ts +40 -0
  12. package/dist/components/pages/WeekliesPage.svelte +184 -0
  13. package/dist/components/pages/WeekliesPage.svelte.d.ts +46 -0
  14. package/dist/components/pages/WeeklyPage.svelte +203 -0
  15. package/dist/components/pages/WeeklyPage.svelte.d.ts +35 -0
  16. package/dist/components/pages/WhatWeDoPage.svelte +107 -0
  17. package/dist/components/pages/WhatWeDoPage.svelte.d.ts +27 -0
  18. package/dist/components/pages/WhoWeArePage.svelte +108 -0
  19. package/dist/components/pages/WhoWeArePage.svelte.d.ts +32 -0
  20. package/dist/config/messages.js +22 -0
  21. package/dist/config/types.d.ts +36 -0
  22. package/dist/content/index.d.ts +3 -1
  23. package/dist/content/index.js +1 -0
  24. package/dist/content/pages.d.ts +64 -0
  25. package/dist/content/pages.js +71 -0
  26. package/dist/content/types.d.ts +45 -0
  27. package/dist/content/types.js +0 -5
  28. package/dist/content-components.d.ts +18 -0
  29. package/dist/content-components.js +12 -0
  30. package/dist/contract.d.ts +3 -0
  31. package/dist/contract.js +4 -0
  32. package/package.json +1 -1
@@ -0,0 +1,203 @@
1
+ <script module lang="ts">
2
+ import type { ArticleEdit } from '../../content/types.js';
3
+
4
+ /**
5
+ * What a CMS may open on a weekly's own page: title, excerpt, and the body
6
+ * as rich text. The «Dades i fonts» and «Segueix explorant» headings and
7
+ * the back link edit through `config.messageEdit` over their own keys.
8
+ */
9
+ export type WeeklyPageEdit = ArticleEdit;
10
+ </script>
11
+
12
+ <script lang="ts">
13
+ import { getUiConfig } from '../../config/context.js';
14
+ import type {
15
+ CommentThreadData,
16
+ ReactionSummary,
17
+ WeeklyArticleData,
18
+ WeeklyCardData
19
+ } from '../../content/types.js';
20
+ import ActionLabel from '../../edit/ActionLabel.svelte';
21
+ import Editable from '../../edit/Editable.svelte';
22
+ import PageShell from '../layout/PageShell.svelte';
23
+ import DateText from '../ui/DateText.svelte';
24
+ import Link from '../ui/Link.svelte';
25
+ import RichText from '../ui/RichText.svelte';
26
+ import ShareRow from '../ui/ShareRow.svelte';
27
+ import CommentSection, { type CommentFormInstance } from '../weeklies/CommentSection.svelte';
28
+ import ReactionBar, { type ReactionBarForms } from '../weeklies/ReactionBar.svelte';
29
+ import WeeklieCard from '../weeklies/WeeklieCard.svelte';
30
+
31
+ /**
32
+ * A weekly's own page: number and date, title, excerpt, the square hero,
33
+ * the body, Instagram and sources, share, reactions, comments, and the
34
+ * related weeklies. The community forms arrive preflighted by the host —
35
+ * the website's remote forms, a CMS mirror's inert mocks — and
36
+ * `isLoggedIn` is the host's auth answer; those are the props the hosts
37
+ * fill differently. `related` is its own prop because vit-brain loads it
38
+ * apart from the weekly, where the website nests it.
39
+ */
40
+ interface Props {
41
+ weekly: WeeklyArticleData;
42
+ related: WeeklyCardData[];
43
+ comments: CommentThreadData[];
44
+ reactions: ReactionSummary[];
45
+ isLoggedIn: boolean;
46
+ /** The main comment box, preflighted; see CommentSection. */
47
+ commentForm: CommentFormInstance;
48
+ /** One preflighted instance per reply box; see CommentSection. */
49
+ replyFormFor: (threadId: string) => CommentFormInstance;
50
+ reactionForms: ReactionBarForms;
51
+ edit?: WeeklyPageEdit;
52
+ }
53
+
54
+ let {
55
+ weekly,
56
+ related,
57
+ comments,
58
+ reactions,
59
+ isLoggedIn,
60
+ commentForm,
61
+ replyFormFor,
62
+ reactionForms,
63
+ edit
64
+ }: Props = $props();
65
+
66
+ const config = getUiConfig();
67
+ const msg = $derived(config.messages);
68
+ </script>
69
+
70
+ <PageShell title={weekly.title} description={weekly.excerpt} variant="reading">
71
+ <p class="back">
72
+ <ActionLabel edit={config.messageEdit?.('back_label')} value={msg.back_label()}>
73
+ {#snippet control()}
74
+ <Link href="/weeklies">← {msg.back_label()}</Link>
75
+ {/snippet}
76
+ </ActionLabel>
77
+ </p>
78
+
79
+ <header>
80
+ <p class="meta">
81
+ <span class="number">{msg.weeklie_number({ number: weekly.number })}</span>
82
+ <DateText value={weekly.publishedOn} />
83
+ </p>
84
+ <Editable edit={edit?.title} value={weekly.title}>
85
+ {#snippet children(text, attrs)}<h1 {...attrs}>{text}</h1>{/snippet}
86
+ </Editable>
87
+ <Editable edit={edit?.excerpt} value={weekly.excerpt}>
88
+ {#snippet children(text, attrs)}<p class="excerpt" {...attrs}>{text}</p>{/snippet}
89
+ </Editable>
90
+ </header>
91
+
92
+ <img class="hero" src={weekly.imageUrl} alt="" width="600" height="600" />
93
+
94
+ {#if weekly.body}
95
+ <RichText body={weekly.body} edit={edit?.body} />
96
+ {/if}
97
+
98
+ {#if weekly.instagramUrl}
99
+ <p><a href={weekly.instagramUrl} rel="external noopener">Instagram ↗</a></p>
100
+ {/if}
101
+
102
+ {#if weekly.sources.length > 0}
103
+ <section aria-labelledby="sources-heading">
104
+ <Editable edit={config.messageEdit?.('weeklie_sources')} value={msg.weeklie_sources()}>
105
+ {#snippet children(text, attrs)}
106
+ <h2 class="subsection-heading" id="sources-heading" {...attrs}>{text}</h2>
107
+ {/snippet}
108
+ </Editable>
109
+ <ul>
110
+ {#each weekly.sources as source (source.url)}
111
+ <li><a href={source.url} rel="external noopener">{source.label}</a></li>
112
+ {/each}
113
+ </ul>
114
+ </section>
115
+ {/if}
116
+
117
+ <ShareRow title={weekly.title} />
118
+
119
+ <ReactionBar
120
+ {reactions}
121
+ target={{ kind: 'weekly', slug: weekly.slug }}
122
+ {isLoggedIn}
123
+ forms={reactionForms}
124
+ />
125
+
126
+ <CommentSection
127
+ {comments}
128
+ weeklySlug={weekly.slug}
129
+ {isLoggedIn}
130
+ {commentForm}
131
+ {replyFormFor}
132
+ {reactionForms}
133
+ />
134
+
135
+ {#if related.length > 0}
136
+ <section aria-labelledby="related-heading">
137
+ <Editable
138
+ edit={config.messageEdit?.('weeklie_keepExploring')}
139
+ value={msg.weeklie_keepExploring()}
140
+ >
141
+ {#snippet children(text, attrs)}
142
+ <h2 class="subsection-heading" id="related-heading" {...attrs}>{text}</h2>
143
+ {/snippet}
144
+ </Editable>
145
+ <div class="related">
146
+ {#each related as card (card.slug)}
147
+ <WeeklieCard weekly={card} />
148
+ {/each}
149
+ </div>
150
+ </section>
151
+ {/if}
152
+ </PageShell>
153
+
154
+ <style>
155
+ .back :global(a) {
156
+ text-decoration: none;
157
+ color: var(--color-ink-secondary);
158
+ }
159
+
160
+ .meta {
161
+ display: flex;
162
+ gap: var(--space-3);
163
+ color: var(--color-ink-muted);
164
+ font-size: var(--text-sm);
165
+ margin: 0;
166
+ }
167
+
168
+ .number {
169
+ font-weight: 700;
170
+ color: var(--color-brand);
171
+ }
172
+
173
+ h1 {
174
+ margin: var(--space-2) 0;
175
+ }
176
+
177
+ .excerpt {
178
+ font-size: var(--text-lg);
179
+ color: var(--color-ink-secondary);
180
+ }
181
+
182
+ .hero {
183
+ border-radius: var(--radius-lg);
184
+ margin-block: var(--space-4);
185
+ background: var(--color-band-grey);
186
+ width: 100%;
187
+ max-width: 32rem;
188
+ }
189
+
190
+ ul {
191
+ padding-left: var(--space-4);
192
+ }
193
+
194
+ a {
195
+ color: var(--color-brand);
196
+ }
197
+
198
+ .related {
199
+ display: grid;
200
+ grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
201
+ gap: var(--space-4);
202
+ }
203
+ </style>
@@ -0,0 +1,35 @@
1
+ import type { ArticleEdit } from '../../content/types.js';
2
+ /**
3
+ * What a CMS may open on a weekly's own page: title, excerpt, and the body
4
+ * as rich text. The «Dades i fonts» and «Segueix explorant» headings and
5
+ * the back link edit through `config.messageEdit` over their own keys.
6
+ */
7
+ export type WeeklyPageEdit = ArticleEdit;
8
+ import type { CommentThreadData, ReactionSummary, WeeklyArticleData, WeeklyCardData } from '../../content/types.js';
9
+ import { type CommentFormInstance } from '../weeklies/CommentSection.svelte';
10
+ import { type ReactionBarForms } from '../weeklies/ReactionBar.svelte';
11
+ /**
12
+ * A weekly's own page: number and date, title, excerpt, the square hero,
13
+ * the body, Instagram and sources, share, reactions, comments, and the
14
+ * related weeklies. The community forms arrive preflighted by the host —
15
+ * the website's remote forms, a CMS mirror's inert mocks — and
16
+ * `isLoggedIn` is the host's auth answer; those are the props the hosts
17
+ * fill differently. `related` is its own prop because vit-brain loads it
18
+ * apart from the weekly, where the website nests it.
19
+ */
20
+ interface Props {
21
+ weekly: WeeklyArticleData;
22
+ related: WeeklyCardData[];
23
+ comments: CommentThreadData[];
24
+ reactions: ReactionSummary[];
25
+ isLoggedIn: boolean;
26
+ /** The main comment box, preflighted; see CommentSection. */
27
+ commentForm: CommentFormInstance;
28
+ /** One preflighted instance per reply box; see CommentSection. */
29
+ replyFormFor: (threadId: string) => CommentFormInstance;
30
+ reactionForms: ReactionBarForms;
31
+ edit?: WeeklyPageEdit;
32
+ }
33
+ declare const WeeklyPage: import("svelte").Component<Props, {}, "">;
34
+ type WeeklyPage = ReturnType<typeof WeeklyPage>;
35
+ export default WeeklyPage;
@@ -0,0 +1,107 @@
1
+ <script module lang="ts">
2
+ import type { CopyEditFor } from '../../content/pages.js';
3
+ import type { ProjectCardData } from '../../content/types.js';
4
+ import type { ProjectEditMap } from '../projects/ProjectCard.svelte';
5
+
6
+ /** What a CMS may open on /what-we-do; `projectFor` answers per card by its `id`. */
7
+ export interface WhatWeDoPageEdit {
8
+ copy?: CopyEditFor<'what-we-do'>;
9
+ projectFor?: (project: ProjectCardData) => ProjectEditMap | undefined;
10
+ }
11
+ </script>
12
+
13
+ <script lang="ts">
14
+ import { getUiConfig } from '../../config/context.js';
15
+ import type { PageCopy } from '../../content/pages.js';
16
+ import Editable from '../../edit/Editable.svelte';
17
+ import PageShell from '../layout/PageShell.svelte';
18
+ import ProjectCard from '../projects/ProjectCard.svelte';
19
+ import CopyIntro from '../ui/CopyIntro.svelte';
20
+
21
+ /**
22
+ * The projects page: a showcase of the latest project, the collaborations
23
+ * as wide rows, the passion projects as a grid. The three groups are the
24
+ * website's load's (`getLatest`, one `list(kind)` each); a host that
25
+ * groups differently (vit-brain's `projectSections`) answers the same
26
+ * three props.
27
+ */
28
+ interface Props {
29
+ content: PageCopy<'what-we-do'>;
30
+ /** The showcase slot; `null`/absent renders no «Últim projecte» band. */
31
+ latest?: ProjectCardData | null;
32
+ collaborations: ProjectCardData[];
33
+ passion: ProjectCardData[];
34
+ edit?: WhatWeDoPageEdit;
35
+ }
36
+
37
+ let { content, latest = null, collaborations, passion, edit }: Props = $props();
38
+
39
+ const config = getUiConfig();
40
+ const msg = $derived(config.messages);
41
+ </script>
42
+
43
+ <PageShell title={msg.nav_whatWeDo()}>
44
+ <Editable edit={config.messageEdit?.('nav_whatWeDo')} value={msg.nav_whatWeDo()}>
45
+ {#snippet children(text, attrs)}<h1 {...attrs}>{text}</h1>{/snippet}
46
+ </Editable>
47
+
48
+ {#if latest}
49
+ <section class="latest" aria-labelledby="latest-heading">
50
+ <Editable edit={edit?.copy?.('latest_heading')} value={content.latest_heading}>
51
+ {#snippet children(text, attrs)}
52
+ <h2 class="section-heading" id="latest-heading" {...attrs}>{text}</h2>
53
+ {/snippet}
54
+ </Editable>
55
+ <ProjectCard project={latest} variant="wide" edit={edit?.projectFor?.(latest)} />
56
+ </section>
57
+ {/if}
58
+
59
+ <section aria-labelledby="collaborations-heading">
60
+ <Editable edit={edit?.copy?.('collaborations_heading')} value={content.collaborations_heading}>
61
+ {#snippet children(text, attrs)}
62
+ <h2 class="section-heading" id="collaborations-heading" {...attrs}>
63
+ {text}
64
+ </h2>
65
+ {/snippet}
66
+ </Editable>
67
+ <CopyIntro text={content.collaborations_intro} edit={edit?.copy?.('collaborations_intro')} />
68
+ <div class="stack">
69
+ {#each collaborations as project (project.slug)}
70
+ <ProjectCard {project} variant="wide" edit={edit?.projectFor?.(project)} />
71
+ {/each}
72
+ </div>
73
+ </section>
74
+
75
+ <section aria-labelledby="passion-heading">
76
+ <Editable edit={edit?.copy?.('passion_heading')} value={content.passion_heading}>
77
+ {#snippet children(text, attrs)}
78
+ <h2 class="section-heading" id="passion-heading" {...attrs}>{text}</h2>
79
+ {/snippet}
80
+ </Editable>
81
+ <CopyIntro text={content.passion_intro} edit={edit?.copy?.('passion_intro')} />
82
+ <div class="grid">
83
+ {#each passion as project (project.slug)}
84
+ <ProjectCard {project} variant="grid" edit={edit?.projectFor?.(project)} />
85
+ {/each}
86
+ </div>
87
+ </section>
88
+ </PageShell>
89
+
90
+ <style>
91
+ .latest {
92
+ padding-block-end: var(--space-4);
93
+ border-bottom: 1px solid var(--color-hairline);
94
+ }
95
+
96
+ .stack {
97
+ display: flex;
98
+ flex-direction: column;
99
+ gap: var(--space-5);
100
+ }
101
+
102
+ .grid {
103
+ display: grid;
104
+ grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
105
+ gap: var(--space-5) var(--space-4);
106
+ }
107
+ </style>
@@ -0,0 +1,27 @@
1
+ import type { CopyEditFor } from '../../content/pages.js';
2
+ import type { ProjectCardData } from '../../content/types.js';
3
+ import type { ProjectEditMap } from '../projects/ProjectCard.svelte';
4
+ /** What a CMS may open on /what-we-do; `projectFor` answers per card by its `id`. */
5
+ export interface WhatWeDoPageEdit {
6
+ copy?: CopyEditFor<'what-we-do'>;
7
+ projectFor?: (project: ProjectCardData) => ProjectEditMap | undefined;
8
+ }
9
+ import type { PageCopy } from '../../content/pages.js';
10
+ /**
11
+ * The projects page: a showcase of the latest project, the collaborations
12
+ * as wide rows, the passion projects as a grid. The three groups are the
13
+ * website's load's (`getLatest`, one `list(kind)` each); a host that
14
+ * groups differently (vit-brain's `projectSections`) answers the same
15
+ * three props.
16
+ */
17
+ interface Props {
18
+ content: PageCopy<'what-we-do'>;
19
+ /** The showcase slot; `null`/absent renders no «Últim projecte» band. */
20
+ latest?: ProjectCardData | null;
21
+ collaborations: ProjectCardData[];
22
+ passion: ProjectCardData[];
23
+ edit?: WhatWeDoPageEdit;
24
+ }
25
+ declare const WhatWeDoPage: import("svelte").Component<Props, {}, "">;
26
+ type WhatWeDoPage = ReturnType<typeof WhatWeDoPage>;
27
+ export default WhatWeDoPage;
@@ -0,0 +1,108 @@
1
+ <script module lang="ts">
2
+ import type { CopyEditFor } from '../../content/pages.js';
3
+ import type { CollaboratorData, TeamMemberData } from '../../content/types.js';
4
+ import type { CollectionRef } from '../../edit/types.js';
5
+ import type { CollaboratorEditMap } from '../team/CollaboratorList.svelte';
6
+ import type { TeamMemberEditMap } from '../team/TeamMemberCard.svelte';
7
+
8
+ /**
9
+ * What a CMS may open on /who-we-are. `memberFor` answers per row, so a
10
+ * host reads the identity it put on `TeamMemberData.id`; `collaborators`
11
+ * names the list's collection, which turns on its add slot and removes.
12
+ */
13
+ export interface WhoWeArePageEdit {
14
+ copy?: CopyEditFor<'who-we-are'>;
15
+ memberFor?: (member: TeamMemberData) => TeamMemberEditMap | undefined;
16
+ collaboratorFor?: (collaborator: CollaboratorData) => CollaboratorEditMap | undefined;
17
+ collaborators?: CollectionRef;
18
+ }
19
+ </script>
20
+
21
+ <script lang="ts">
22
+ import { getUiConfig } from '../../config/context.js';
23
+ import type { PageCopy } from '../../content/pages.js';
24
+ import Editable from '../../edit/Editable.svelte';
25
+ import PageShell from '../layout/PageShell.svelte';
26
+ import CollaboratorList from '../team/CollaboratorList.svelte';
27
+ import TeamMemberCard from '../team/TeamMemberCard.svelte';
28
+ import CopyIntro from '../ui/CopyIntro.svelte';
29
+
30
+ /**
31
+ * The team page: the featured members, the board, the collaborators. The
32
+ * split into `featured` and `board` is the website's load's (one `isBoard`
33
+ * filter each), so the module takes the two lists rather than re-deciding.
34
+ */
35
+ interface Props {
36
+ content: PageCopy<'who-we-are'>;
37
+ featured: TeamMemberData[];
38
+ board: TeamMemberData[];
39
+ collaborators: CollaboratorData[];
40
+ edit?: WhoWeArePageEdit;
41
+ }
42
+
43
+ let { content, featured, board, collaborators, edit }: Props = $props();
44
+
45
+ const config = getUiConfig();
46
+ const msg = $derived(config.messages);
47
+ </script>
48
+
49
+ <PageShell title={msg.nav_whoWeAre()}>
50
+ <Editable edit={config.messageEdit?.('nav_whoWeAre')} value={msg.nav_whoWeAre()}>
51
+ {#snippet children(text, attrs)}<h1 {...attrs}>{text}</h1>{/snippet}
52
+ </Editable>
53
+
54
+ <section aria-labelledby="team-heading">
55
+ <Editable edit={edit?.copy?.('team_heading')} value={content.team_heading}>
56
+ {#snippet children(text, attrs)}
57
+ <h2 class="section-heading" id="team-heading" {...attrs}>{text}</h2>
58
+ {/snippet}
59
+ </Editable>
60
+ <CopyIntro text={content.team_intro} edit={edit?.copy?.('team_intro')} />
61
+ <div class="featured">
62
+ {#each featured as member (member.slug)}
63
+ <TeamMemberCard {member} variant="featured" edit={edit?.memberFor?.(member)} />
64
+ {/each}
65
+ </div>
66
+ </section>
67
+
68
+ <section aria-labelledby="board-heading">
69
+ <Editable edit={edit?.copy?.('board_heading')} value={content.board_heading}>
70
+ {#snippet children(text, attrs)}
71
+ <h2 class="section-heading" id="board-heading" {...attrs}>{text}</h2>
72
+ {/snippet}
73
+ </Editable>
74
+ <CopyIntro text={content.board_intro} edit={edit?.copy?.('board_intro')} />
75
+ <div class="board">
76
+ {#each board as member (member.slug)}
77
+ <TeamMemberCard {member} variant="board" edit={edit?.memberFor?.(member)} />
78
+ {/each}
79
+ </div>
80
+ </section>
81
+
82
+ <section aria-labelledby="collaborators-heading">
83
+ <Editable edit={edit?.copy?.('collaborators_heading')} value={content.collaborators_heading}>
84
+ {#snippet children(text, attrs)}
85
+ <h2 class="section-heading" id="collaborators-heading" {...attrs}>{text}</h2>
86
+ {/snippet}
87
+ </Editable>
88
+ <CollaboratorList
89
+ {collaborators}
90
+ editFor={edit?.collaboratorFor}
91
+ collection={edit?.collaborators}
92
+ />
93
+ </section>
94
+ </PageShell>
95
+
96
+ <style>
97
+ .featured {
98
+ display: grid;
99
+ grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
100
+ gap: var(--space-4);
101
+ }
102
+
103
+ .board {
104
+ display: grid;
105
+ grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
106
+ gap: var(--space-4);
107
+ }
108
+ </style>
@@ -0,0 +1,32 @@
1
+ import type { CopyEditFor } from '../../content/pages.js';
2
+ import type { CollaboratorData, TeamMemberData } from '../../content/types.js';
3
+ import type { CollectionRef } from '../../edit/types.js';
4
+ import type { CollaboratorEditMap } from '../team/CollaboratorList.svelte';
5
+ import type { TeamMemberEditMap } from '../team/TeamMemberCard.svelte';
6
+ /**
7
+ * What a CMS may open on /who-we-are. `memberFor` answers per row, so a
8
+ * host reads the identity it put on `TeamMemberData.id`; `collaborators`
9
+ * names the list's collection, which turns on its add slot and removes.
10
+ */
11
+ export interface WhoWeArePageEdit {
12
+ copy?: CopyEditFor<'who-we-are'>;
13
+ memberFor?: (member: TeamMemberData) => TeamMemberEditMap | undefined;
14
+ collaboratorFor?: (collaborator: CollaboratorData) => CollaboratorEditMap | undefined;
15
+ collaborators?: CollectionRef;
16
+ }
17
+ import type { PageCopy } from '../../content/pages.js';
18
+ /**
19
+ * The team page: the featured members, the board, the collaborators. The
20
+ * split into `featured` and `board` is the website's load's (one `isBoard`
21
+ * filter each), so the module takes the two lists rather than re-deciding.
22
+ */
23
+ interface Props {
24
+ content: PageCopy<'who-we-are'>;
25
+ featured: TeamMemberData[];
26
+ board: TeamMemberData[];
27
+ collaborators: CollaboratorData[];
28
+ edit?: WhoWeArePageEdit;
29
+ }
30
+ declare const WhoWeArePage: import("svelte").Component<Props, {}, "">;
31
+ type WhoWeArePage = ReturnType<typeof WhoWeArePage>;
32
+ export default WhoWeArePage;
@@ -105,6 +105,28 @@ export const defaultMessages = {
105
105
  category_education: () => 'Educació',
106
106
  category_collaboration: () => 'Col·laboració',
107
107
  category_press: () => 'Premsa',
108
+ nav_whoWeAre: () => 'Qui som',
109
+ nav_whatWeDo: () => 'Què fem',
110
+ nav_getInvolved: () => "Implica-t'hi",
111
+ nav_weeklies: () => 'Weeklies',
112
+ common_seeAll: () => 'Mostra-ho tot',
113
+ common_seeAllHref: () => '/transparency',
114
+ cta_meetTeam: () => "Coneix l'equip",
115
+ cta_meetTeamHref: () => '/who-we-are',
116
+ cta_contactUs: () => "Contacta'ns",
117
+ cta_contactUsHref: () => '/get-involved',
118
+ weeklies_searchPlaceholder: () => 'Cerca un tema…',
119
+ weeklies_exploreOne: () => "…o explora'n un d'aquests",
120
+ weeklies_filterLabel: () => 'Filtra per tema',
121
+ weeklies_searchResultsLabel: () => 'Resultats de la cerca',
122
+ weeklies_loadError: () => "No s'han pogut carregar els resultats. Torna-ho a provar.",
123
+ weeklies_empty: () => 'No hem trobat cap weekly amb aquests criteris.',
124
+ timeline_searchPlaceholder: () => 'Què hem estat fent?',
125
+ timeline_filterLabel: () => 'Filtra per categoria',
126
+ timeline_empty: () => 'No hem trobat cap fita amb aquests criteris.',
127
+ back_label: () => 'Torna enrere',
128
+ weeklie_sources: () => 'Dades i fonts',
129
+ weeklie_keepExploring: () => 'Segueix explorant',
108
130
  status_published: () => 'Publicat',
109
131
  status_draft: () => 'Esborrany',
110
132
  status_open: () => 'Oberta',
@@ -149,6 +149,42 @@ export interface UiMessages {
149
149
  category_education(): string;
150
150
  category_collaboration(): string;
151
151
  category_press(): string;
152
+ /**
153
+ * The wording the PAGE MODULES read (`components/pages/*`), REQUIRED like
154
+ * every key but the *Href pair above.
155
+ *
156
+ * ⚠ Adding them was a compile-break for any host whose `messages` object
157
+ * lacked one — `messages` is all-or-nothing (see ./messages.js), so a
158
+ * catalog that compiled against 0.24 stops compiling here rather than
159
+ * rendering a hole. Both hosts already carried every key (the website's
160
+ * Paraglide catalog, vit-brain's `ui_messages` table) because the nine
161
+ * route files read them by hand before the pages moved in; the only thing
162
+ * that changed is that the package now names what it reads. The four
163
+ * `*Href` keys are destinations edited as wording (fndvit-website#11) —
164
+ * a link's text and address are one editorial gesture, so both are keys.
165
+ */
166
+ nav_whoWeAre(): string;
167
+ nav_whatWeDo(): string;
168
+ nav_getInvolved(): string;
169
+ nav_weeklies(): string;
170
+ common_seeAll(): string;
171
+ common_seeAllHref(): string;
172
+ cta_meetTeam(): string;
173
+ cta_meetTeamHref(): string;
174
+ cta_contactUs(): string;
175
+ cta_contactUsHref(): string;
176
+ weeklies_searchPlaceholder(): string;
177
+ weeklies_exploreOne(): string;
178
+ weeklies_filterLabel(): string;
179
+ weeklies_searchResultsLabel(): string;
180
+ weeklies_loadError(): string;
181
+ weeklies_empty(): string;
182
+ timeline_searchPlaceholder(): string;
183
+ timeline_filterLabel(): string;
184
+ timeline_empty(): string;
185
+ back_label(): string;
186
+ weeklie_sources(): string;
187
+ weeklie_keepExploring(): string;
152
188
  /**
153
189
  * Editorial state, as the panel's `flag` rows word it: a card's
154
190
  * published/draft pair, an opening's open/closed pair. Catalog keys rather
@@ -1,4 +1,6 @@
1
1
  export { renderBody } from './richtext.js';
2
2
  export type { RichTextBlock } from './richtext.js';
3
+ export { GET_INVOLVED_REASON_KEYS, PAGE_COPY_KEYS } from './pages.js';
4
+ export type { CopyEditFor, CopyKey, PageCopy, PageId } from './pages.js';
3
5
  export { COMMENT_STATUSES, CONTACT_CATEGORIES, MILESTONE_CATEGORIES, PROJECT_KINDS, REACTIONS } from './types.js';
4
- export type { CollaboratorData, CommentData, CommentThreadData, CommentStatus, ContactCategory, FieldConstraint, FormFailReason, JobOpeningData, MilestoneCategory, MilestoneData, ProjectCardData, ProjectKind, Reaction, ReactionSummary, ReactionTarget, SortDirection, TeamMemberData, WeeklyCardData } from './types.js';
6
+ export type { ArticleEdit, CollaboratorData, CommentData, CommentThreadData, CommentStatus, ContactCategory, FieldConstraint, FormFailReason, JobOpeningData, MilestoneCategory, MilestoneData, ProjectArticleData, ProjectCardData, ProjectKind, Reaction, ReactionSummary, ReactionTarget, SortDirection, TeamMemberData, ThemeData, WeeklyArticleData, WeeklyCardData, WeeklySourceData } from './types.js';
@@ -1,2 +1,3 @@
1
1
  export { renderBody } from './richtext.js';
2
+ export { GET_INVOLVED_REASON_KEYS, PAGE_COPY_KEYS } from './pages.js';
2
3
  export { COMMENT_STATUSES, CONTACT_CATEGORIES, MILESTONE_CATEGORIES, PROJECT_KINDS, REACTIONS } from './types.js';
@@ -0,0 +1,64 @@
1
+ import type { EditDescriptor } from '../edit/types.js';
2
+ /**
3
+ * Page copy: the editorial blocks of a static page, stored per page and
4
+ * section key in the website's `page_content` table. This module is the
5
+ * only declaration of which keys each page has — the website's `seed.sql`
6
+ * supplies their text and its repository integration test asserts the two
7
+ * agree, so a renamed or dropped row fails that suite instead of silently
8
+ * rendering nothing. vit-brain's `page-copy-keys.test.ts` pins the same set
9
+ * against the live table from the other side.
10
+ *
11
+ * It lived in fndvit-website's `schemas/page-copy.ts` and was restated in
12
+ * vit-brain's `mirror.ts` (with the FORMAT each block edits in — that half
13
+ * stays in brain, ADR-0019). Now that the page modules render from this
14
+ * package, the keys a page reads are the package's fact: a module indexes
15
+ * `copy.hero_title`, so the tuple that makes that compile has to live beside
16
+ * it. Component-free on purpose — `./contract` re-exports it for a host's
17
+ * `+page.server.ts` and a CMS's producer alike.
18
+ *
19
+ * UI chrome (labels, buttons, error messages) is not page copy: it lives in
20
+ * `UiMessages` and ships with the build.
21
+ */
22
+ /**
23
+ * The "why get in touch" blocks, rendered as one list on /get-involved.
24
+ *
25
+ * Named because a run of keys being a *group* is a fact about the copy, and it
26
+ * needs the same single owner the keys themselves have: the page used to
27
+ * restate these five, so adding a sixth reason here and to the seed left the
28
+ * page silently ignoring it — no type error, no failing test.
29
+ */
30
+ export declare const GET_INVOLVED_REASON_KEYS: readonly ["reason_collaborate", "reason_event", "reason_press", "reason_brand", "reason_other"];
31
+ export declare const PAGE_COPY_KEYS: {
32
+ readonly home: readonly ["hero_title", "hero_subtitle", "milestones_heading", "weeklies_heading", "weeklies_intro", "know_more_heading"];
33
+ readonly 'what-we-do': readonly ["latest_heading", "collaborations_heading", "collaborations_intro", "passion_heading", "passion_intro"];
34
+ readonly 'who-we-are': readonly ["team_heading", "team_intro", "board_heading", "board_intro", "collaborators_heading"];
35
+ readonly weeklies: readonly ["intro"];
36
+ readonly 'get-involved': readonly ["contact_heading", "contact_intro", "reason_collaborate", "reason_event", "reason_press", "reason_brand", "reason_other", "funding_heading", "funding_body", "careers_heading", "careers_intro"];
37
+ readonly transparency: readonly ["heading", "intro"];
38
+ readonly legal: readonly ["heading", "body"];
39
+ };
40
+ /** A page that has editorial copy. Matches the `page_content.page` column. */
41
+ export type PageId = keyof typeof PAGE_COPY_KEYS;
42
+ /** The section keys declared for one page. */
43
+ export type CopyKey<P extends PageId> = (typeof PAGE_COPY_KEYS)[P][number];
44
+ /**
45
+ * One page's copy, one locale already applied. Every declared key is present:
46
+ * a row missing from the database resolves to an empty string rather than
47
+ * `undefined`.
48
+ *
49
+ * The page modules do NOT guard for that empty string. It is not a state the
50
+ * site is meant to render around — the website's repository integration test
51
+ * asserts that every declared key resolves to non-empty copy, so a dropped or
52
+ * renamed row fails the suite. Guarding at the render site instead puts the
53
+ * decision back at every call site, which is what the assertion exists to
54
+ * avoid (the same answer `CopyIntro` gives).
55
+ */
56
+ export type PageCopy<P extends PageId> = Record<CopyKey<P>, string>;
57
+ /**
58
+ * How a page module asks for one copy block's edit descriptor: by the key it
59
+ * renders, so a module cannot name a block its page does not declare. A
60
+ * read-only host passes nothing; a CMS answers with a `page-copy` ref for the
61
+ * locale being edited (vit-brain's `pageCopyEditor`), or `undefined` to leave
62
+ * one block alone.
63
+ */
64
+ export type CopyEditFor<P extends PageId> = (key: CopyKey<P>) => EditDescriptor | undefined;