@vit-foundation/ui 0.21.0 → 0.23.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/admin.d.ts +0 -1
- package/dist/admin.js +9 -1
- package/dist/components/timeline/TimelineMilestone.svelte +3 -3
- package/dist/components/timeline/TimelineMilestone.svelte.d.ts +1 -1
- package/dist/content/index.d.ts +2 -2
- package/dist/content/index.js +1 -1
- package/dist/content/types.d.ts +36 -2
- package/dist/content/types.js +39 -0
- package/dist/content-components.d.ts +1 -1
- package/dist/content-components.js +1 -1
- package/dist/contract.d.ts +18 -3
- package/dist/contract.js +26 -2
- package/dist/index.js +3 -9
- package/dist/utils/milestones.d.ts +5 -0
- package/dist/utils/milestones.js +5 -0
- package/dist/utils/paths.d.ts +27 -0
- package/dist/utils/paths.js +27 -0
- package/dist/utils/weekly-list-contract.d.ts +35 -0
- package/dist/utils/weekly-list-contract.js +46 -0
- package/package.json +1 -1
- package/dist/components/admin/AdminShell.svelte +0 -42
- package/dist/components/admin/AdminShell.svelte.d.ts +0 -18
- package/dist/components/jobs/index.d.ts +0 -2
- package/dist/components/jobs/index.js +0 -1
- package/dist/components/layout/index.d.ts +0 -3
- package/dist/components/layout/index.js +0 -3
- package/dist/components/projects/index.d.ts +0 -2
- package/dist/components/projects/index.js +0 -1
- package/dist/components/team/index.d.ts +0 -3
- package/dist/components/team/index.js +0 -2
- package/dist/components/timeline/index.d.ts +0 -3
- package/dist/components/timeline/index.js +0 -2
- package/dist/components/ui/index.d.ts +0 -20
- package/dist/components/ui/index.js +0 -20
- package/dist/components/weeklies/index.d.ts +0 -7
- package/dist/components/weeklies/index.js +0 -4
package/dist/admin.d.ts
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
* components receive already-filtered data through props, the Nav/Footer
|
|
6
6
|
* genericization pattern.
|
|
7
7
|
*/
|
|
8
|
-
export { default as AdminShell } from './components/admin/AdminShell.svelte';
|
|
9
8
|
export { default as DecorMosaic } from './components/admin/DecorMosaic.svelte';
|
|
10
9
|
export { default as PageHeading } from './components/admin/PageHeading.svelte';
|
|
11
10
|
export { default as Sidebar, type SidebarItem } from './components/admin/Sidebar.svelte';
|
package/dist/admin.js
CHANGED
|
@@ -5,7 +5,15 @@
|
|
|
5
5
|
* components receive already-filtered data through props, the Nav/Footer
|
|
6
6
|
* genericization pattern.
|
|
7
7
|
*/
|
|
8
|
-
|
|
8
|
+
/*
|
|
9
|
+
* `AdminShell` was exported here — a public name behind two doors with zero
|
|
10
|
+
* readers in either host, no test, and one story. Seven props, five of them
|
|
11
|
+
* forwarded verbatim to `Sidebar`, and the only implementation it added beyond
|
|
12
|
+
* the forwarding was `main { margin-left: 4.5rem }`. The one admin host went
|
|
13
|
+
* the other way: vit-brain imports `Sidebar` directly and composes its own
|
|
14
|
+
* shell with a different offset, so the rail's width had two answers and the
|
|
15
|
+
* untested one was nobody's. Deleting it left nothing to reappear.
|
|
16
|
+
*/
|
|
9
17
|
export { default as DecorMosaic } from './components/admin/DecorMosaic.svelte';
|
|
10
18
|
export { default as PageHeading } from './components/admin/PageHeading.svelte';
|
|
11
19
|
export { default as Sidebar } from './components/admin/Sidebar.svelte';
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
<script lang="ts">
|
|
26
26
|
import { getUiConfig } from '../../config/context.js';
|
|
27
27
|
import ActionLabel from '../../edit/ActionLabel.svelte';
|
|
28
|
-
import
|
|
28
|
+
import { MILESTONE_CATEGORIES, type MilestoneData } from '../../content/types.js';
|
|
29
29
|
import EditFrame from '../../edit/chrome/EditFrame.svelte';
|
|
30
30
|
import EditPanel from '../../edit/chrome/EditPanel.svelte';
|
|
31
31
|
import Editable from '../../edit/Editable.svelte';
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
|
|
47
47
|
const config = getUiConfig();
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
// The set's own order, not a colour map's key order and not a cast.
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
52
|
* The panel rows, zipped from the map's descriptors and this milestone's
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
edit?.occurredOn && { descriptor: edit.occurredOn, value: milestone.occurredOn },
|
|
59
59
|
edit?.category && {
|
|
60
60
|
descriptor: {
|
|
61
|
-
options:
|
|
61
|
+
options: MILESTONE_CATEGORIES.map((category) => ({
|
|
62
62
|
value: category,
|
|
63
63
|
label: milestoneCategoryLabel(category, config.messages)
|
|
64
64
|
})),
|
|
@@ -20,7 +20,7 @@ export interface MilestoneEditMap {
|
|
|
20
20
|
kind: 'remove';
|
|
21
21
|
}>;
|
|
22
22
|
}
|
|
23
|
-
import type
|
|
23
|
+
import { type MilestoneData } from '../../content/types.js';
|
|
24
24
|
interface Props {
|
|
25
25
|
milestone: MilestoneData;
|
|
26
26
|
/** Marks fields editable where an edit adapter is active. */
|
package/dist/content/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { renderBody } from './richtext.js';
|
|
2
2
|
export type { RichTextBlock } from './richtext.js';
|
|
3
|
-
export { CONTACT_CATEGORIES, REACTIONS } from './types.js';
|
|
4
|
-
export type { CollaboratorData, CommentData, CommentThreadData, ContactCategory, FieldConstraint, FormFailReason, JobOpeningData, MilestoneCategory, MilestoneData, ProjectCardData, ProjectKind, Reaction, ReactionSummary, ReactionTarget, SortDirection, TeamMemberData, WeeklyCardData } from './types.js';
|
|
3
|
+
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';
|
package/dist/content/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { renderBody } from './richtext.js';
|
|
2
|
-
export { CONTACT_CATEGORIES, REACTIONS } from './types.js';
|
|
2
|
+
export { COMMENT_STATUSES, CONTACT_CATEGORIES, MILESTONE_CATEGORIES, PROJECT_KINDS, REACTIONS } from './types.js';
|
package/dist/content/types.d.ts
CHANGED
|
@@ -28,7 +28,9 @@ export interface WeeklyCardData {
|
|
|
28
28
|
excerpt: string;
|
|
29
29
|
imageUrl: string;
|
|
30
30
|
}
|
|
31
|
-
|
|
31
|
+
/** The kinds a project can have, in display order — a host's enum derives from this. */
|
|
32
|
+
export declare const PROJECT_KINDS: readonly ["collaboration", "passion"];
|
|
33
|
+
export type ProjectKind = (typeof PROJECT_KINDS)[number];
|
|
32
34
|
/** A project as its card shows it. */
|
|
33
35
|
export interface ProjectCardData {
|
|
34
36
|
id: number;
|
|
@@ -43,7 +45,23 @@ export interface ProjectCardData {
|
|
|
43
45
|
externalUrl: string | null;
|
|
44
46
|
hasStory: boolean;
|
|
45
47
|
}
|
|
46
|
-
|
|
48
|
+
/**
|
|
49
|
+
* The timeline's categories, in DISPLAY ORDER — every select that offers them
|
|
50
|
+
* and every host enum derives from this.
|
|
51
|
+
*
|
|
52
|
+
* The order was an emergent property of two unrelated literals before: the
|
|
53
|
+
* panel select read `Object.keys(MILESTONE_CATEGORY_COLOR)` while vit-brain's
|
|
54
|
+
* record form spelled its own array, so one CMS offered the same field in two
|
|
55
|
+
* orders and seeded a new row with the third member of one of them. The order
|
|
56
|
+
* kept here is the colour map's, which is the one with a reason attached (its
|
|
57
|
+
* slots are fixed and never reordered).
|
|
58
|
+
*
|
|
59
|
+
* A tuple rather than a union for the reason `CONTACT_CATEGORIES` is one: a
|
|
60
|
+
* `satisfies readonly MilestoneCategory[]` binds the element type and never
|
|
61
|
+
* the list, so a host could drop a member and still compile.
|
|
62
|
+
*/
|
|
63
|
+
export declare const MILESTONE_CATEGORIES: readonly ["foundation", "lab", "education", "collaboration", "press"];
|
|
64
|
+
export type MilestoneCategory = (typeof MILESTONE_CATEGORIES)[number];
|
|
47
65
|
/** One timeline milestone. */
|
|
48
66
|
export interface MilestoneData {
|
|
49
67
|
id: number;
|
|
@@ -108,6 +126,22 @@ export interface CommentData {
|
|
|
108
126
|
createdAt: string;
|
|
109
127
|
reactions: ReactionSummary[];
|
|
110
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* A comment's moderation state, as the database constrains it.
|
|
131
|
+
*
|
|
132
|
+
* The set is `comments.status`'s CHECK in fndvit-website and the vocabulary
|
|
133
|
+
* vit-brain's Comentaris tab moderates through — two repositories that cannot
|
|
134
|
+
* import each other — and it had no owner in TypeScript at all: the site read
|
|
135
|
+
* `status = 'published'` as a bare SQL literal in four queries, typed the
|
|
136
|
+
* field `z.string()`, and never named the other two states anywhere. A test
|
|
137
|
+
* fixture using `'visible'`, a value the CHECK refuses, passed green.
|
|
138
|
+
*
|
|
139
|
+
* `published` is what a reader sees; `hidden` is moderated away; `pending`
|
|
140
|
+
* awaits review. Which of them a given surface SHOWS is that surface's rule,
|
|
141
|
+
* not this list's.
|
|
142
|
+
*/
|
|
143
|
+
export declare const COMMENT_STATUSES: readonly ["published", "pending", "hidden"];
|
|
144
|
+
export type CommentStatus = (typeof COMMENT_STATUSES)[number];
|
|
111
145
|
/** A top-level comment with its flat reply list. */
|
|
112
146
|
export interface CommentThreadData extends CommentData {
|
|
113
147
|
replies: CommentData[];
|
package/dist/content/types.js
CHANGED
|
@@ -3,7 +3,46 @@
|
|
|
3
3
|
* applied. The website's zod-inferred types satisfy these structurally; the
|
|
4
4
|
* package states them itself so consumers owe it no schema library.
|
|
5
5
|
*/
|
|
6
|
+
/** The kinds a project can have, in display order — a host's enum derives from this. */
|
|
7
|
+
export const PROJECT_KINDS = ['collaboration', 'passion'];
|
|
8
|
+
/**
|
|
9
|
+
* The timeline's categories, in DISPLAY ORDER — every select that offers them
|
|
10
|
+
* and every host enum derives from this.
|
|
11
|
+
*
|
|
12
|
+
* The order was an emergent property of two unrelated literals before: the
|
|
13
|
+
* panel select read `Object.keys(MILESTONE_CATEGORY_COLOR)` while vit-brain's
|
|
14
|
+
* record form spelled its own array, so one CMS offered the same field in two
|
|
15
|
+
* orders and seeded a new row with the third member of one of them. The order
|
|
16
|
+
* kept here is the colour map's, which is the one with a reason attached (its
|
|
17
|
+
* slots are fixed and never reordered).
|
|
18
|
+
*
|
|
19
|
+
* A tuple rather than a union for the reason `CONTACT_CATEGORIES` is one: a
|
|
20
|
+
* `satisfies readonly MilestoneCategory[]` binds the element type and never
|
|
21
|
+
* the list, so a host could drop a member and still compile.
|
|
22
|
+
*/
|
|
23
|
+
export const MILESTONE_CATEGORIES = [
|
|
24
|
+
'foundation',
|
|
25
|
+
'lab',
|
|
26
|
+
'education',
|
|
27
|
+
'collaboration',
|
|
28
|
+
'press'
|
|
29
|
+
];
|
|
6
30
|
/** The reactions a weekly or comment can carry, in display order. */
|
|
7
31
|
export const REACTIONS = ['like', 'love', 'clap'];
|
|
32
|
+
/**
|
|
33
|
+
* A comment's moderation state, as the database constrains it.
|
|
34
|
+
*
|
|
35
|
+
* The set is `comments.status`'s CHECK in fndvit-website and the vocabulary
|
|
36
|
+
* vit-brain's Comentaris tab moderates through — two repositories that cannot
|
|
37
|
+
* import each other — and it had no owner in TypeScript at all: the site read
|
|
38
|
+
* `status = 'published'` as a bare SQL literal in four queries, typed the
|
|
39
|
+
* field `z.string()`, and never named the other two states anywhere. A test
|
|
40
|
+
* fixture using `'visible'`, a value the CHECK refuses, passed green.
|
|
41
|
+
*
|
|
42
|
+
* `published` is what a reader sees; `hidden` is moderated away; `pending`
|
|
43
|
+
* awaits review. Which of them a given surface SHOWS is that surface's rule,
|
|
44
|
+
* not this list's.
|
|
45
|
+
*/
|
|
46
|
+
export const COMMENT_STATUSES = ['published', 'pending', 'hidden'];
|
|
8
47
|
/** The contact form's reasons, in display order — the host schema derives its enum from this. */
|
|
9
48
|
export const CONTACT_CATEGORIES = ['collaborate', 'event', 'press', 'brand', 'other'];
|
|
@@ -23,7 +23,7 @@ export { createUrlFilters } from './utils/url-filters.svelte.js';
|
|
|
23
23
|
export type { UrlFilters, UrlFiltersConfig } from './utils/url-filters.svelte.js';
|
|
24
24
|
export { createWeeklyList } from './utils/weekly-list.svelte.js';
|
|
25
25
|
export type { WeeklyList, WeeklyListConfig } from './utils/weekly-list.svelte.js';
|
|
26
|
-
export { WEEKLY_LIST_DEFAULTS } from './utils/weekly-list-contract.js';
|
|
26
|
+
export { WEEKLY_LIST_DEFAULTS, WEEKLY_LIST_PARAMS, parseWeeklyListUrl } from './utils/weekly-list-contract.js';
|
|
27
27
|
export type { WeeklyListFilters, WeeklyListPage, WeeklyListServerData } from './utils/weekly-list-contract.js';
|
|
28
28
|
export { contactCategoryLabel } from './utils/contact.js';
|
|
29
29
|
export { formatDate, yearOf } from './utils/dates.js';
|
|
@@ -18,6 +18,6 @@ export { createUrlFilters } from './utils/url-filters.svelte.js';
|
|
|
18
18
|
export { createWeeklyList } from './utils/weekly-list.svelte.js';
|
|
19
19
|
// The list's contract is component-free on purpose, so ./contract carries it
|
|
20
20
|
// too — a host's +page.server.ts reads these without loading the grid.
|
|
21
|
-
export { WEEKLY_LIST_DEFAULTS } from './utils/weekly-list-contract.js';
|
|
21
|
+
export { WEEKLY_LIST_DEFAULTS, WEEKLY_LIST_PARAMS, parseWeeklyListUrl } from './utils/weekly-list-contract.js';
|
|
22
22
|
export { contactCategoryLabel } from './utils/contact.js';
|
|
23
23
|
export { formatDate, yearOf } from './utils/dates.js';
|
package/dist/contract.d.ts
CHANGED
|
@@ -43,11 +43,26 @@ export { localize } from './edit/types.js';
|
|
|
43
43
|
export type { CollectionRef, ContentRef, EditableEntity, EditDescriptor, EntityOp, LocalizedText, PropertyDescriptor, PropertyOption, PropertyType, PropertyValue } from './edit/types.js';
|
|
44
44
|
export { REACTIONS } from './content/types.js';
|
|
45
45
|
export type { Reaction, ReactionSummary, SortDirection } from './content/types.js';
|
|
46
|
-
export {
|
|
46
|
+
export { MILESTONE_CATEGORIES, PROJECT_KINDS } from './content/types.js';
|
|
47
|
+
export type { MilestoneCategory, ProjectKind } from './content/types.js';
|
|
48
|
+
export { WEEKLY_LIST_DEFAULTS, WEEKLY_LIST_PARAMS, parseWeeklyListUrl } from './utils/weekly-list-contract.js';
|
|
47
49
|
export type { WeeklyListFilters, WeeklyListPage, WeeklyListServerData } from './utils/weekly-list-contract.js';
|
|
48
50
|
export { CONTACT_CATEGORIES } from './content/types.js';
|
|
49
|
-
export
|
|
51
|
+
export { COMMENT_STATUSES } from './content/types.js';
|
|
52
|
+
export type { CommentStatus, ContactCategory, FieldConstraint, FormFailReason } from './content/types.js';
|
|
50
53
|
export { COMMENT_BODY, CONTACT_MESSAGE, CONTACT_NAME, DISPLAY_NAME, EMAIL, LOGIN_PASSWORD, PASSWORD } from './forms/constraints.js';
|
|
51
54
|
export { hasNewsletterIntent, HONEYPOT_FIELD, isNewsletterIntent, NEWSLETTER_INTENT_PARAM, NEWSLETTER_INTENT_VALUE, withNewsletterIntent } from './forms/transport.js';
|
|
52
55
|
export type { FormFail, FormFieldIssue, FormResultLike, FormResultOf, KeyedRemoteForms, RemoteField, RemoteFormAttributes, RemoteFormInstance } from './forms/types.js';
|
|
53
|
-
export { buildQueryString, isExternalUrl, isInternalPath
|
|
56
|
+
export { buildQueryString, isExternalUrl, isInternalPath } from './utils/paths.js';
|
|
57
|
+
/**
|
|
58
|
+
* The descriptor factories. `edit/helpers.ts` imports nothing but types from
|
|
59
|
+
* two modules this subpath already anchors, so it needed a door rather than a
|
|
60
|
+
* split.
|
|
61
|
+
*
|
|
62
|
+
* They were reachable only beside the components, which cost vit-brain an
|
|
63
|
+
* eslint exception that switched `no-restricted-imports` off WHOLESALE for the
|
|
64
|
+
* two files calling one factory each — and one of those, `mirror.ts`, is
|
|
65
|
+
* already reached from a server repository by `import type`. A per-specifier
|
|
66
|
+
* door replaces a per-file hole.
|
|
67
|
+
*/
|
|
68
|
+
export { chromeEdit, chromeProperty, collectionOf, entityEdit, entityProperty, pageCopyEdit } from './edit/helpers.js';
|
package/dist/contract.js
CHANGED
|
@@ -40,8 +40,32 @@
|
|
|
40
40
|
export { LOCALES, BASE_LOCALE } from './config/types.js';
|
|
41
41
|
export { localize } from './edit/types.js';
|
|
42
42
|
export { REACTIONS } from './content/types.js';
|
|
43
|
-
|
|
43
|
+
// The two content vocabularies a host's zod enum derives from, the way its
|
|
44
|
+
// contact form already derives from CONTACT_CATEGORIES below. Values, because
|
|
45
|
+
// a type cannot be the source of an enum.
|
|
46
|
+
export { MILESTONE_CATEGORIES, PROJECT_KINDS } from './content/types.js';
|
|
47
|
+
// The weeklies URL contract, both halves: the values a param stands for when
|
|
48
|
+
// absent, the names it travels as, and the parse that reads one back. The read
|
|
49
|
+
// half had three spellings across two repositories and this package's own test,
|
|
50
|
+
// and the round-trip case guarding them crossed against the test's copy.
|
|
51
|
+
export { WEEKLY_LIST_DEFAULTS, WEEKLY_LIST_PARAMS, parseWeeklyListUrl } from './utils/weekly-list-contract.js';
|
|
44
52
|
export { CONTACT_CATEGORIES } from './content/types.js';
|
|
53
|
+
export { COMMENT_STATUSES } from './content/types.js';
|
|
45
54
|
export { COMMENT_BODY, CONTACT_MESSAGE, CONTACT_NAME, DISPLAY_NAME, EMAIL, LOGIN_PASSWORD, PASSWORD } from './forms/constraints.js';
|
|
46
55
|
export { hasNewsletterIntent, HONEYPOT_FIELD, isNewsletterIntent, NEWSLETTER_INTENT_PARAM, NEWSLETTER_INTENT_VALUE, withNewsletterIntent } from './forms/transport.js';
|
|
47
|
-
|
|
56
|
+
// `isPathUnder` is deliberately absent: `Nav` and `Sidebar` reach it by relative
|
|
57
|
+
// import and no host has ever imported it, so exporting it pinned a prefix rule
|
|
58
|
+
// into semver for nobody. See utils/paths.ts.
|
|
59
|
+
export { buildQueryString, isExternalUrl, isInternalPath } from './utils/paths.js';
|
|
60
|
+
/**
|
|
61
|
+
* The descriptor factories. `edit/helpers.ts` imports nothing but types from
|
|
62
|
+
* two modules this subpath already anchors, so it needed a door rather than a
|
|
63
|
+
* split.
|
|
64
|
+
*
|
|
65
|
+
* They were reachable only beside the components, which cost vit-brain an
|
|
66
|
+
* eslint exception that switched `no-restricted-imports` off WHOLESALE for the
|
|
67
|
+
* two files calling one factory each — and one of those, `mirror.ts`, is
|
|
68
|
+
* already reached from a server repository by `import type`. A per-specifier
|
|
69
|
+
* door replaces a per-file hole.
|
|
70
|
+
*/
|
|
71
|
+
export { chromeEdit, chromeProperty, collectionOf, entityEdit, entityProperty, pageCopyEdit } from './edit/helpers.js';
|
package/dist/index.js
CHANGED
|
@@ -12,13 +12,7 @@ export * from './forms/index.js';
|
|
|
12
12
|
// App wiring: configuration context and the edit-mode contract.
|
|
13
13
|
export * from './config/index.js';
|
|
14
14
|
export * from './edit/index.js';
|
|
15
|
-
// The one path utility
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
// The other three are NOT exported. `isInternalPath` and `isExternalUrl` are
|
|
19
|
-
// the destination classifiers `Link` and `TimelineMilestone` branch on, and
|
|
20
|
-
// `isPathUnder` is the prefix match `Nav` and `Sidebar` highlight the current
|
|
21
|
-
// section with — all four in-package readers reach them by deep import, and
|
|
22
|
-
// no host imports any of the three. Exporting them would pin their behaviour
|
|
23
|
-
// into semver for no reader; `paths.test.ts` is what holds them instead.
|
|
15
|
+
// The one path utility this BARREL carries. The destination classifiers are
|
|
16
|
+
// server-side rules, so they go through ./contract instead — see the note in
|
|
17
|
+
// utils/paths.ts, which is where the export surface for all of them is decided.
|
|
24
18
|
export { buildQueryString } from './utils/paths.js';
|
|
@@ -5,6 +5,11 @@ import type { MilestoneCategory } from '../content/types.js';
|
|
|
5
5
|
* teal, slots are never reordered). Labels always accompany the color dot,
|
|
6
6
|
* so color is never the only encoding. The --series-* tokens ship in
|
|
7
7
|
* tokens.css.
|
|
8
|
+
*
|
|
9
|
+
* Keyed, not positional, so a member added to `MILESTONE_CATEGORIES` fails to
|
|
10
|
+
* compile here rather than silently taking slot 6 — and so the display order
|
|
11
|
+
* is `MILESTONE_CATEGORIES`' to decide, not a side effect of this literal's
|
|
12
|
+
* key order, which is what the panel select used to read.
|
|
8
13
|
*/
|
|
9
14
|
export declare const MILESTONE_CATEGORY_COLOR: Record<MilestoneCategory, string>;
|
|
10
15
|
/**
|
package/dist/utils/milestones.js
CHANGED
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
* teal, slots are never reordered). Labels always accompany the color dot,
|
|
4
4
|
* so color is never the only encoding. The --series-* tokens ship in
|
|
5
5
|
* tokens.css.
|
|
6
|
+
*
|
|
7
|
+
* Keyed, not positional, so a member added to `MILESTONE_CATEGORIES` fails to
|
|
8
|
+
* compile here rather than silently taking slot 6 — and so the display order
|
|
9
|
+
* is `MILESTONE_CATEGORIES`' to decide, not a side effect of this literal's
|
|
10
|
+
* key order, which is what the panel select used to read.
|
|
6
11
|
*/
|
|
7
12
|
export const MILESTONE_CATEGORY_COLOR = {
|
|
8
13
|
foundation: 'var(--series-1)',
|
package/dist/utils/paths.d.ts
CHANGED
|
@@ -1,3 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The four path rules, and which doors they go out of.
|
|
3
|
+
*
|
|
4
|
+
* This note used to live in `index.ts` and argue that only `buildQueryString`
|
|
5
|
+
* was exported, that the other three were private, and that exporting them
|
|
6
|
+
* "would pin their behaviour into semver for no reader". All three claims had
|
|
7
|
+
* stopped being true:
|
|
8
|
+
*
|
|
9
|
+
* - `contract.ts` exports all four, and has since the subpath reached both
|
|
10
|
+
* hosts.
|
|
11
|
+
* - Two of them DO have a host reader. fndvit-website's repository integration
|
|
12
|
+
* suite asserts the `site_links.href` check constraint against
|
|
13
|
+
* `isInternalPath` byte for byte, and the https columns against
|
|
14
|
+
* `isExternalUrl` — that binding is the whole reason those cases exist, and
|
|
15
|
+
* it is why these two belong on `./contract`: a CHECK constraint is a
|
|
16
|
+
* server-side rule, and the classifier that has to agree with it must be
|
|
17
|
+
* importable without loading a component.
|
|
18
|
+
* - fndvit-website does not re-export `buildQueryString` from its `nav.ts`
|
|
19
|
+
* any more; that pass-through is deleted and its one reader imports the
|
|
20
|
+
* package directly.
|
|
21
|
+
*
|
|
22
|
+
* What the old note got right is the principle, and `isPathUnder` is the name
|
|
23
|
+
* it applies to: it is the prefix match `Nav` and `Sidebar` highlight the
|
|
24
|
+
* current section with, both of them reach it by relative import, and no host
|
|
25
|
+
* has ever imported it. So it is the one of the four that stays in, held by
|
|
26
|
+
* `paths.test.ts` rather than by semver.
|
|
27
|
+
*/
|
|
1
28
|
/** Prefix match over a URL pathname: '/what-we-do' covers '/what-we-do/<slug>'. */
|
|
2
29
|
export declare function isPathUnder(pathname: string, prefix: string): boolean;
|
|
3
30
|
/**
|
package/dist/utils/paths.js
CHANGED
|
@@ -1,3 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The four path rules, and which doors they go out of.
|
|
3
|
+
*
|
|
4
|
+
* This note used to live in `index.ts` and argue that only `buildQueryString`
|
|
5
|
+
* was exported, that the other three were private, and that exporting them
|
|
6
|
+
* "would pin their behaviour into semver for no reader". All three claims had
|
|
7
|
+
* stopped being true:
|
|
8
|
+
*
|
|
9
|
+
* - `contract.ts` exports all four, and has since the subpath reached both
|
|
10
|
+
* hosts.
|
|
11
|
+
* - Two of them DO have a host reader. fndvit-website's repository integration
|
|
12
|
+
* suite asserts the `site_links.href` check constraint against
|
|
13
|
+
* `isInternalPath` byte for byte, and the https columns against
|
|
14
|
+
* `isExternalUrl` — that binding is the whole reason those cases exist, and
|
|
15
|
+
* it is why these two belong on `./contract`: a CHECK constraint is a
|
|
16
|
+
* server-side rule, and the classifier that has to agree with it must be
|
|
17
|
+
* importable without loading a component.
|
|
18
|
+
* - fndvit-website does not re-export `buildQueryString` from its `nav.ts`
|
|
19
|
+
* any more; that pass-through is deleted and its one reader imports the
|
|
20
|
+
* package directly.
|
|
21
|
+
*
|
|
22
|
+
* What the old note got right is the principle, and `isPathUnder` is the name
|
|
23
|
+
* it applies to: it is the prefix match `Nav` and `Sidebar` highlight the
|
|
24
|
+
* current section with, both of them reach it by relative import, and no host
|
|
25
|
+
* has ever imported it. So it is the one of the four that stays in, held by
|
|
26
|
+
* `paths.test.ts` rather than by semver.
|
|
27
|
+
*/
|
|
1
28
|
/** Prefix match over a URL pathname: '/what-we-do' covers '/what-we-do/<slug>'. */
|
|
2
29
|
export function isPathUnder(pathname, prefix) {
|
|
3
30
|
return pathname === prefix || pathname.startsWith(`${prefix}/`);
|
|
@@ -64,3 +64,38 @@ export interface WeeklyListServerData {
|
|
|
64
64
|
pageSize: number;
|
|
65
65
|
query: WeeklyListFilters;
|
|
66
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* The four params this list travels as, in the order a URL reads.
|
|
69
|
+
*
|
|
70
|
+
* Exported so a host's query schema can be bound to them rather than agreeing
|
|
71
|
+
* by coincidence: fndvit-website's `weeklyListQuerySchema` names all four as
|
|
72
|
+
* zod fields, and nothing said they were these four.
|
|
73
|
+
*/
|
|
74
|
+
export declare const WEEKLY_LIST_PARAMS: readonly ["q", "theme", "sort", "page"];
|
|
75
|
+
/**
|
|
76
|
+
* The READ half of the weeklies URL contract — what a URL this package wrote
|
|
77
|
+
* means when it comes back.
|
|
78
|
+
*
|
|
79
|
+
* `WEEKLY_LIST_DEFAULTS` gave the VALUES one owner and both hosts derive from
|
|
80
|
+
* it correctly. The param NAMES and the parse had none: they were spelled four
|
|
81
|
+
* times across three repositories — `toQuery`/`hrefFor` here, a `parseListUrl`
|
|
82
|
+
* declared inside this package's own test, `weeklyListQuerySchema` in
|
|
83
|
+
* fndvit-website and `weeklyQuery` in vit-brain — and the two repositories
|
|
84
|
+
* cannot import each other, so nothing could disagree out loud. vit-brain's
|
|
85
|
+
* docblock states the failure exactly: rename a param here and the read side
|
|
86
|
+
* drops the filter silently while the write side keeps producing it.
|
|
87
|
+
*
|
|
88
|
+
* Worse, the round-trip case that exists to catch precisely that
|
|
89
|
+
* ("builds URLs that parse back to the filters they were built from") crossed
|
|
90
|
+
* the write half against the stand-in in the test file, not against either
|
|
91
|
+
* real reader. It could not fail for the reason it was written.
|
|
92
|
+
*
|
|
93
|
+
* TOLERANT, because these URLs are shared and hand-edited: an unknown sort or
|
|
94
|
+
* a junk page falls back to its default rather than refusing the page. A host
|
|
95
|
+
* may still layer its own tolerance on top — fndvit-website trims and caps
|
|
96
|
+
* lengths in zod, vit-brain clamps nothing further — but the names, and what
|
|
97
|
+
* an absent or bad value means, are answered once, here.
|
|
98
|
+
*/
|
|
99
|
+
export declare function parseWeeklyListUrl(url: URL | string): WeeklyListFilters & {
|
|
100
|
+
page: number;
|
|
101
|
+
};
|
|
@@ -40,3 +40,49 @@
|
|
|
40
40
|
* is the value it should answer unless it means to differ.
|
|
41
41
|
*/
|
|
42
42
|
export const WEEKLY_LIST_DEFAULTS = { sort: 'desc', page: 1, pageSize: 12 };
|
|
43
|
+
/**
|
|
44
|
+
* The four params this list travels as, in the order a URL reads.
|
|
45
|
+
*
|
|
46
|
+
* Exported so a host's query schema can be bound to them rather than agreeing
|
|
47
|
+
* by coincidence: fndvit-website's `weeklyListQuerySchema` names all four as
|
|
48
|
+
* zod fields, and nothing said they were these four.
|
|
49
|
+
*/
|
|
50
|
+
export const WEEKLY_LIST_PARAMS = ['q', 'theme', 'sort', 'page'];
|
|
51
|
+
/**
|
|
52
|
+
* The READ half of the weeklies URL contract — what a URL this package wrote
|
|
53
|
+
* means when it comes back.
|
|
54
|
+
*
|
|
55
|
+
* `WEEKLY_LIST_DEFAULTS` gave the VALUES one owner and both hosts derive from
|
|
56
|
+
* it correctly. The param NAMES and the parse had none: they were spelled four
|
|
57
|
+
* times across three repositories — `toQuery`/`hrefFor` here, a `parseListUrl`
|
|
58
|
+
* declared inside this package's own test, `weeklyListQuerySchema` in
|
|
59
|
+
* fndvit-website and `weeklyQuery` in vit-brain — and the two repositories
|
|
60
|
+
* cannot import each other, so nothing could disagree out loud. vit-brain's
|
|
61
|
+
* docblock states the failure exactly: rename a param here and the read side
|
|
62
|
+
* drops the filter silently while the write side keeps producing it.
|
|
63
|
+
*
|
|
64
|
+
* Worse, the round-trip case that exists to catch precisely that
|
|
65
|
+
* ("builds URLs that parse back to the filters they were built from") crossed
|
|
66
|
+
* the write half against the stand-in in the test file, not against either
|
|
67
|
+
* real reader. It could not fail for the reason it was written.
|
|
68
|
+
*
|
|
69
|
+
* TOLERANT, because these URLs are shared and hand-edited: an unknown sort or
|
|
70
|
+
* a junk page falls back to its default rather than refusing the page. A host
|
|
71
|
+
* may still layer its own tolerance on top — fndvit-website trims and caps
|
|
72
|
+
* lengths in zod, vit-brain clamps nothing further — but the names, and what
|
|
73
|
+
* an absent or bad value means, are answered once, here.
|
|
74
|
+
*/
|
|
75
|
+
export function parseWeeklyListUrl(url) {
|
|
76
|
+
// A relative href (`hrefFor` writes one) needs a base to parse against; it
|
|
77
|
+
// is never read, only discarded with the rest of the origin.
|
|
78
|
+
const params = (typeof url === 'string' ? new URL(url, 'https://weekly-list.invalid') : url)
|
|
79
|
+
.searchParams;
|
|
80
|
+
const sort = params.get('sort');
|
|
81
|
+
const page = Math.trunc(Number(params.get('page')));
|
|
82
|
+
return {
|
|
83
|
+
q: params.get('q') ?? '',
|
|
84
|
+
theme: params.get('theme'),
|
|
85
|
+
sort: sort === 'asc' || sort === 'desc' ? sort : WEEKLY_LIST_DEFAULTS.sort,
|
|
86
|
+
page: page >= WEEKLY_LIST_DEFAULTS.page ? page : WEEKLY_LIST_DEFAULTS.page
|
|
87
|
+
};
|
|
88
|
+
}
|
package/package.json
CHANGED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { Snippet } from 'svelte';
|
|
3
|
-
import Sidebar, { type SidebarItem } from './Sidebar.svelte';
|
|
4
|
-
|
|
5
|
-
interface Props {
|
|
6
|
-
/** Rail entries, already permission-filtered by the host. */
|
|
7
|
-
items: SidebarItem[];
|
|
8
|
-
/** Accessible name of the sidebar nav landmark. */
|
|
9
|
-
navLabel?: string;
|
|
10
|
-
logo?: Snippet;
|
|
11
|
-
/** Bottom of the rail — the host's logout form. */
|
|
12
|
-
footer?: Snippet;
|
|
13
|
-
/** The page content. */
|
|
14
|
-
children: Snippet;
|
|
15
|
-
/** Highlighting override for tests and stories. */
|
|
16
|
-
url?: URL;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
let { items, navLabel = 'Principal', logo, footer, children, url = undefined }: Props = $props();
|
|
20
|
-
</script>
|
|
21
|
-
|
|
22
|
-
<div class="shell">
|
|
23
|
-
<Sidebar {items} label={navLabel} {logo} {footer} {url} />
|
|
24
|
-
<main class="content">
|
|
25
|
-
{@render children()}
|
|
26
|
-
</main>
|
|
27
|
-
</div>
|
|
28
|
-
|
|
29
|
-
<style>
|
|
30
|
-
/* The sidebar is fixed at 4.5rem; the content pays for it once, here,
|
|
31
|
-
instead of every page knowing the rail's width. */
|
|
32
|
-
.content {
|
|
33
|
-
margin-left: 4.5rem;
|
|
34
|
-
min-height: 100vh;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
@media print {
|
|
38
|
-
.content {
|
|
39
|
-
margin-left: 0;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
</style>
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { Snippet } from 'svelte';
|
|
2
|
-
import { type SidebarItem } from './Sidebar.svelte';
|
|
3
|
-
interface Props {
|
|
4
|
-
/** Rail entries, already permission-filtered by the host. */
|
|
5
|
-
items: SidebarItem[];
|
|
6
|
-
/** Accessible name of the sidebar nav landmark. */
|
|
7
|
-
navLabel?: string;
|
|
8
|
-
logo?: Snippet;
|
|
9
|
-
/** Bottom of the rail — the host's logout form. */
|
|
10
|
-
footer?: Snippet;
|
|
11
|
-
/** The page content. */
|
|
12
|
-
children: Snippet;
|
|
13
|
-
/** Highlighting override for tests and stories. */
|
|
14
|
-
url?: URL;
|
|
15
|
-
}
|
|
16
|
-
declare const AdminShell: import("svelte").Component<Props, {}, "">;
|
|
17
|
-
type AdminShell = ReturnType<typeof AdminShell>;
|
|
18
|
-
export default AdminShell;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default as JobList } from './JobList.svelte';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default as ProjectCard } from './ProjectCard.svelte';
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export { default as Button } from './Button.svelte';
|
|
2
|
-
export { default as CardMedia } from './CardMedia.svelte';
|
|
3
|
-
export { default as CardTitle } from './CardTitle.svelte';
|
|
4
|
-
export { default as CopyIntro } from './CopyIntro.svelte';
|
|
5
|
-
export { default as DateText } from './DateText.svelte';
|
|
6
|
-
export { default as DecorShapes } from './DecorShapes.svelte';
|
|
7
|
-
export { default as Field } from './Field.svelte';
|
|
8
|
-
export { default as FilterChips } from './FilterChips.svelte';
|
|
9
|
-
export { default as FormErrorFeedback } from './FormErrorFeedback.svelte';
|
|
10
|
-
export { default as FormFeedback } from './FormFeedback.svelte';
|
|
11
|
-
export { default as FormResultSlot } from './FormResultSlot.svelte';
|
|
12
|
-
export { default as GhostButton } from './GhostButton.svelte';
|
|
13
|
-
export { default as Honeypot } from './Honeypot.svelte';
|
|
14
|
-
export { default as Link } from './Link.svelte';
|
|
15
|
-
export { default as LocaleField } from './LocaleField.svelte';
|
|
16
|
-
export { default as NewsletterIntentField } from './NewsletterIntentField.svelte';
|
|
17
|
-
export { default as Pagination } from './Pagination.svelte';
|
|
18
|
-
export { default as RichText } from './RichText.svelte';
|
|
19
|
-
export { default as SearchInput } from './SearchInput.svelte';
|
|
20
|
-
export { default as ShareRow } from './ShareRow.svelte';
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export { default as Button } from './Button.svelte';
|
|
2
|
-
export { default as CardMedia } from './CardMedia.svelte';
|
|
3
|
-
export { default as CardTitle } from './CardTitle.svelte';
|
|
4
|
-
export { default as CopyIntro } from './CopyIntro.svelte';
|
|
5
|
-
export { default as DateText } from './DateText.svelte';
|
|
6
|
-
export { default as DecorShapes } from './DecorShapes.svelte';
|
|
7
|
-
export { default as Field } from './Field.svelte';
|
|
8
|
-
export { default as FilterChips } from './FilterChips.svelte';
|
|
9
|
-
export { default as FormErrorFeedback } from './FormErrorFeedback.svelte';
|
|
10
|
-
export { default as FormFeedback } from './FormFeedback.svelte';
|
|
11
|
-
export { default as FormResultSlot } from './FormResultSlot.svelte';
|
|
12
|
-
export { default as GhostButton } from './GhostButton.svelte';
|
|
13
|
-
export { default as Honeypot } from './Honeypot.svelte';
|
|
14
|
-
export { default as Link } from './Link.svelte';
|
|
15
|
-
export { default as LocaleField } from './LocaleField.svelte';
|
|
16
|
-
export { default as NewsletterIntentField } from './NewsletterIntentField.svelte';
|
|
17
|
-
export { default as Pagination } from './Pagination.svelte';
|
|
18
|
-
export { default as RichText } from './RichText.svelte';
|
|
19
|
-
export { default as SearchInput } from './SearchInput.svelte';
|
|
20
|
-
export { default as ShareRow } from './ShareRow.svelte';
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export { default as CommentSection } from './CommentSection.svelte';
|
|
2
|
-
export type { CommentFormInstance } from './CommentSection.svelte';
|
|
3
|
-
export { default as ReactionBar } from './ReactionBar.svelte';
|
|
4
|
-
export type { CommentReactionChip, ReactionBarForms, WeeklyReactionChip } from './ReactionBar.svelte';
|
|
5
|
-
export { default as SortSelect } from './SortSelect.svelte';
|
|
6
|
-
export { default as WeeklieCard } from './WeeklieCard.svelte';
|
|
7
|
-
export type { WeeklyEditMap } from './WeeklieCard.svelte';
|