@vit-foundation/ui 0.24.1 → 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.
- package/README.md +11 -11
- package/dist/components/pages/GetInvolvedPage.svelte +139 -0
- package/dist/components/pages/GetInvolvedPage.svelte.d.ts +36 -0
- package/dist/components/pages/HomePage.svelte +256 -0
- package/dist/components/pages/HomePage.svelte.d.ts +36 -0
- package/dist/components/pages/LegalPage.svelte +39 -0
- package/dist/components/pages/LegalPage.svelte.d.ts +14 -0
- package/dist/components/pages/ProjectPage.svelte +128 -0
- package/dist/components/pages/ProjectPage.svelte.d.ts +17 -0
- package/dist/components/pages/TransparencyPage.svelte +164 -0
- package/dist/components/pages/TransparencyPage.svelte.d.ts +40 -0
- package/dist/components/pages/WeekliesPage.svelte +184 -0
- package/dist/components/pages/WeekliesPage.svelte.d.ts +46 -0
- package/dist/components/pages/WeeklyPage.svelte +203 -0
- package/dist/components/pages/WeeklyPage.svelte.d.ts +35 -0
- package/dist/components/pages/WhatWeDoPage.svelte +107 -0
- package/dist/components/pages/WhatWeDoPage.svelte.d.ts +27 -0
- package/dist/components/pages/WhoWeArePage.svelte +108 -0
- package/dist/components/pages/WhoWeArePage.svelte.d.ts +32 -0
- package/dist/components/ui/Logo.svelte +19 -3
- package/dist/config/messages.js +22 -0
- package/dist/config/types.d.ts +36 -0
- package/dist/content/index.d.ts +3 -1
- package/dist/content/index.js +1 -0
- package/dist/content/pages.d.ts +64 -0
- package/dist/content/pages.js +71 -0
- package/dist/content/types.d.ts +45 -0
- package/dist/content/types.js +0 -5
- package/dist/content-components.d.ts +18 -0
- package/dist/content-components.js +12 -0
- package/dist/contract.d.ts +3 -0
- package/dist/contract.js +4 -0
- 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;
|
|
@@ -9,16 +9,32 @@
|
|
|
9
9
|
let { size = 32, withWordmark = false }: Props = $props();
|
|
10
10
|
</script>
|
|
11
11
|
|
|
12
|
+
<!--
|
|
13
|
+
The mark is ALWAYS decorative. It carries no accessible name of its own, in
|
|
14
|
+
either branch, because at every call site something else already supplies
|
|
15
|
+
one — and when it tried, it doubled.
|
|
16
|
+
|
|
17
|
+
`withWordmark` used to flip three accessibility facts together:
|
|
18
|
+
`aria-hidden`, `role="img"` and the presence of `<title>`. With the wordmark
|
|
19
|
+
on, the mark was named "Brain VIT" AND the wordmark rendered the same string
|
|
20
|
+
beside it, so a screen reader announced the name twice on all three of
|
|
21
|
+
Brain's sign-in pages. Inverting the branch does not help: with the wordmark
|
|
22
|
+
off, the rail already names it through `<a aria-label="Home">` and the print
|
|
23
|
+
sheet sits it beside an `<h1>`, so naming the mark there doubles at the other
|
|
24
|
+
end.
|
|
25
|
+
|
|
26
|
+
Which leaves one honest rule — never name it — and the naming stays where
|
|
27
|
+
the context is: the visible wordmark below, the anchor around it, or the
|
|
28
|
+
heading beside it. `Logo.svelte.test.ts` pins both branches.
|
|
29
|
+
-->
|
|
12
30
|
<span class="logo">
|
|
13
31
|
<svg
|
|
14
32
|
viewBox="0 0 48 56"
|
|
15
33
|
width={size * (48 / 56)}
|
|
16
34
|
height={size}
|
|
17
|
-
aria-hidden=
|
|
18
|
-
role={withWordmark ? 'img' : undefined}
|
|
35
|
+
aria-hidden="true"
|
|
19
36
|
focusable="false"
|
|
20
37
|
>
|
|
21
|
-
{#if withWordmark}<title>Brain VIT</title>{/if}
|
|
22
38
|
<path
|
|
23
39
|
d="M25 2c11.6 0 21 9.4 21 21 0 6.9-3.3 13-8.5 16.8V54H17v-9h-4.5A4.5 4.5 0 0 1 8 40.5V34H4.2c-1.7 0-2.7-1.9-1.7-3.3L8 22.4C9 11 16.2 2 25 2Z"
|
|
24
40
|
fill="currentColor"
|
package/dist/config/messages.js
CHANGED
|
@@ -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',
|
package/dist/config/types.d.ts
CHANGED
|
@@ -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
|
package/dist/content/index.d.ts
CHANGED
|
@@ -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';
|
package/dist/content/index.js
CHANGED