@graview/primitives 0.1.15 → 0.1.17
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 +55 -4
- package/dist/app-bar.d.ts +109 -0
- package/dist/app-bar.d.ts.map +1 -0
- package/dist/app-bar.js +289 -0
- package/dist/app-bar.js.map +1 -0
- package/dist/app-title.d.ts +28 -0
- package/dist/app-title.d.ts.map +1 -0
- package/dist/app-title.js +76 -0
- package/dist/app-title.js.map +1 -0
- package/dist/arrange-bar.d.ts +1 -1
- package/dist/arrange-bar.js +3 -3
- package/dist/arrange-bar.js.map +1 -1
- package/dist/bar-panes.d.ts +26 -0
- package/dist/bar-panes.d.ts.map +1 -0
- package/dist/bar-panes.js +95 -0
- package/dist/bar-panes.js.map +1 -0
- package/dist/choice.d.ts +9 -0
- package/dist/choice.d.ts.map +1 -0
- package/dist/choice.js +21 -0
- package/dist/choice.js.map +1 -0
- package/dist/companion.d.ts.map +1 -1
- package/dist/companion.js +8 -6
- package/dist/companion.js.map +1 -1
- package/dist/connections.d.ts +1 -1
- package/dist/connections.js +4 -4
- package/dist/connections.js.map +1 -1
- package/dist/declared-lens-doors.d.ts.map +1 -1
- package/dist/declared-lens-doors.js +8 -1
- package/dist/declared-lens-doors.js.map +1 -1
- package/dist/default-views.js +9 -9
- package/dist/default-views.js.map +1 -1
- package/dist/editable.d.ts +3 -3
- package/dist/editable.js +4 -4
- package/dist/find.d.ts.map +1 -1
- package/dist/find.js +25 -6
- package/dist/find.js.map +1 -1
- package/dist/frame.d.ts +5 -1
- package/dist/frame.d.ts.map +1 -1
- package/dist/frame.js +4 -1
- package/dist/frame.js.map +1 -1
- package/dist/graview-mark.d.ts +21 -0
- package/dist/graview-mark.d.ts.map +1 -0
- package/dist/graview-mark.js +24 -0
- package/dist/graview-mark.js.map +1 -0
- package/dist/index.d.ts +8 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/dist/installation.d.ts +1 -1
- package/dist/installation.js +1 -1
- package/dist/ladder.d.ts.map +1 -1
- package/dist/ladder.js +4 -10
- package/dist/ladder.js.map +1 -1
- package/dist/lens/board.js +3 -3
- package/dist/lens/calendar-view.js +1 -1
- package/dist/lens/coverage.d.ts +2 -2
- package/dist/lens/coverage.js +7 -7
- package/dist/lens/coverage.js.map +1 -1
- package/dist/lens/plan-state.d.ts +2 -2
- package/dist/lens/plan-state.js +1 -1
- package/dist/lens/plan-view.js +4 -4
- package/dist/lens/plan.d.ts +1 -1
- package/dist/lens/plan.js +1 -1
- package/dist/lens/timeline.d.ts +2 -2
- package/dist/lens/timeline.js +7 -7
- package/dist/lens/timeline.js.map +1 -1
- package/dist/markup.d.ts +1 -1
- package/dist/markup.js +1 -1
- package/dist/notice-place.d.ts +30 -0
- package/dist/notice-place.d.ts.map +1 -0
- package/dist/notice-place.js +91 -0
- package/dist/notice-place.js.map +1 -0
- package/dist/notices.d.ts +5 -3
- package/dist/notices.d.ts.map +1 -1
- package/dist/notices.js +11 -12
- package/dist/notices.js.map +1 -1
- package/dist/pages.d.ts +8 -1
- package/dist/pages.d.ts.map +1 -1
- package/dist/pages.js +8 -1
- package/dist/pages.js.map +1 -1
- package/dist/primitives/index.d.ts +7 -7
- package/dist/primitives/index.d.ts.map +1 -1
- package/dist/primitives/index.js +6 -6
- package/dist/primitives/index.js.map +1 -1
- package/dist/profile.d.ts +2 -4
- package/dist/profile.d.ts.map +1 -1
- package/dist/profile.js +38 -103
- package/dist/profile.js.map +1 -1
- package/dist/quick-relations.js +1 -1
- package/dist/relation-key.d.ts +2 -2
- package/dist/relation-key.js +3 -3
- package/dist/scene-css.d.ts.map +1 -1
- package/dist/scene-css.js +14 -13
- package/dist/scene-css.js.map +1 -1
- package/dist/scene.d.ts +2 -1
- package/dist/scene.d.ts.map +1 -1
- package/dist/scene.js +2 -1
- package/dist/scene.js.map +1 -1
- package/dist/seats.d.ts.map +1 -1
- package/dist/seats.js +2 -11
- package/dist/seats.js.map +1 -1
- package/dist/shell.d.ts.map +1 -1
- package/dist/shell.js +13 -9
- package/dist/shell.js.map +1 -1
- package/dist/spec-views.d.ts +15 -0
- package/dist/spec-views.d.ts.map +1 -1
- package/dist/spec-views.js +26 -4
- package/dist/spec-views.js.map +1 -1
- package/dist/theme.d.ts +3 -3
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +34 -28
- package/dist/theme.js.map +1 -1
- package/dist/views-css.d.ts +9 -0
- package/dist/views-css.d.ts.map +1 -0
- package/dist/views-css.js +12 -0
- package/dist/views-css.js.map +1 -0
- package/dist/wordmark.d.ts +1 -1
- package/dist/wordmark.d.ts.map +1 -1
- package/dist/wordmark.js +5 -10
- package/dist/wordmark.js.map +1 -1
- package/dist/workbench/activity.js +3 -3
- package/dist/workbench/activity.js.map +1 -1
- package/dist/workbench/answer-args.js +4 -4
- package/dist/workbench/back-out.d.ts +1 -1
- package/dist/workbench/back-out.js +2 -2
- package/dist/workbench/inspector.d.ts +2 -2
- package/dist/workbench/inspector.js +6 -6
- package/dist/workbench/inspector.js.map +1 -1
- package/dist/workbench/standing.d.ts +8 -4
- package/dist/workbench/standing.d.ts.map +1 -1
- package/dist/workbench/standing.js +26 -41
- package/dist/workbench/standing.js.map +1 -1
- package/dist/workbench/trail.d.ts +1 -1
- package/dist/workbench/trail.js +1 -1
- package/fonts/OFL-Montserrat.txt +93 -0
- package/fonts/montserrat-latin.woff2 +0 -0
- package/fonts/montserrat.css +23 -0
- package/package.json +13 -8
- package/dist/home-landing.d.ts +0 -18
- package/dist/home-landing.d.ts.map +0 -1
- package/dist/home-landing.js +0 -59
- package/dist/home-landing.js.map +0 -1
package/README.md
CHANGED
|
@@ -38,10 +38,61 @@ is selected and what can be done with it, whether the rules hold, what just
|
|
|
38
38
|
happened and how to take it back, how to back out of a view. All derived from
|
|
39
39
|
the schema, the invariants and the op log.
|
|
40
40
|
|
|
41
|
+
**The app, said once** — `AppBar`: one bar over every face (FR-131) — the
|
|
42
|
+
brand's mark (`AppMark`, drawn as given, never an SVG that could act) and
|
|
43
|
+
the app's name as the page's heading, the switch between the scene and the
|
|
44
|
+
pages (`faces`, FR-137), on Pages the place you are on as one control that
|
|
45
|
+
opens every place (`barPlaces`: the home, the Lists, the Pictures, FR-138),
|
|
46
|
+
and three tools of one size: the Find a
|
|
47
|
+
face puts in it (`useBarFind`), `Standing` and `Profile`. `AppTitle` draws
|
|
48
|
+
the mark, the name and the line under it elsewhere; `useFavicon` is for a
|
|
49
|
+
face that owns the page.
|
|
50
|
+
|
|
41
51
|
**Visual system** — `themeCss(scheme, brand)`. Two schemes that are not
|
|
42
52
|
inversions of each other: dark loses luminance, light loses contrast and gains
|
|
43
53
|
haze. A brand supplies its own and `graview check` measures it. The sheet is
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
54
|
+
three parts: `themeBaseCss`, what every face draws on; `viewsCss`, the blocks
|
|
55
|
+
a view spec is drawn with, which each face that draws a view draws beside it;
|
|
56
|
+
and `sceneCss`, the rules only the scene draws (the districts from altitude,
|
|
57
|
+
the plots, the village, the billboards), which an embed's scene face draws
|
|
58
|
+
beside it so a page on the pages face carries none of them.
|
|
59
|
+
|
|
60
|
+
## Design language
|
|
61
|
+
|
|
62
|
+
Three layers, and a component reads only the middle one:
|
|
63
|
+
|
|
64
|
+
| Layer | Where | What it holds |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| The identity | @graview/core (the design kit, revision 03) | En Dash navy #001769 and turquoise #00E5B9, paper #F7F7F2, ink #18213A, muted #586174; Montserrat at 550, 450 and 600; the shared-plane symbol |
|
|
67
|
+
| The semantic tokens | `themeCss` writes them as custom properties | surfaces (`--graview-ground`, `-panel`, `-panel-muted`, `-panel-warning`, `-bar`, `-float`), text (`--graview-ink`, `-ink-muted`, `-ink-faint`), interaction (`--graview-accent`, `-accent-dim`, `-accent-ink`, `-edge`, `-edge-bright`), state (`--graview-warn`, `-good`, `-bad`), type (`--graview-font-body`, `-display`, `-mono`, `--graview-weight-display`, `-body`, `-label`), shape (`--graview-radius`, `-radius-sm`, `-pad`, `-pad-sm`, `-gap`), depth (`--graview-lift-low`, `-lift-high`, `--graview-layer-*`) and the kit (`--graview-kit-*`) |
|
|
68
|
+
| The app's overrides | the app's brand | name, logo, page icon, both schemes' tokens, faces and weights, radius and density, a hue per kind, the kit |
|
|
69
|
+
|
|
70
|
+
The shipped schemes are built on the identity: paper, reading ink and navy in
|
|
71
|
+
the light, a deep navy ground with the navy's hue made light in the dark.
|
|
72
|
+
Neither paints a wash or a glow; hover firms an edge rather than glowing.
|
|
73
|
+
Turquoise is not a token at all: it is the symbol's point, a fill that is
|
|
74
|
+
never text (1.5:1 on paper; navy reads on it at 9.7:1), so nothing the
|
|
75
|
+
framework draws depends on it. An app that declares its own brand keeps its
|
|
76
|
+
own colors, faces and logo, and the framework never puts Graview's mark in it.
|
|
77
|
+
|
|
78
|
+
How the scene reads against any district's color: a kind's hue is the
|
|
79
|
+
brand's (`accents`) or a stable hash, and only the hue: the lighting of a
|
|
80
|
+
block's three faces and the plot under it is the scene's, so a block reads
|
|
81
|
+
as a block on both grounds. Selection and the keyboard's place are drawn in
|
|
82
|
+
the accent, as an outline set off from the block, never as a change of the
|
|
83
|
+
block's own hue, so a selected block in a navy-ish district still reads as
|
|
84
|
+
selected. A relation is told from another by its pattern, its end cap and its
|
|
85
|
+
width as well as its color, and every district, block and relation carries
|
|
86
|
+
its name in words, so nothing is said by color alone. Disabled is a dimmed
|
|
87
|
+
control that cannot be pressed; empty, loading and refused are said in
|
|
88
|
+
sentences.
|
|
89
|
+
|
|
90
|
+
The words are set in Montserrat when the host has it, and in the reader's
|
|
91
|
+
system sans otherwise: the framework names the face and never fetches it.
|
|
92
|
+
A host that wants it imports the optional copy once —
|
|
93
|
+
`import "@graview/primitives/montserrat.css"`, 32 KB of woff2, weights
|
|
94
|
+
400–700, Latin, under the SIL Open Font License (beside it in the package).
|
|
95
|
+
`GraviewMark` is the symbol for a host drawing Graview's own identity — a
|
|
96
|
+
signature, a hosting service's chrome — inline in the ink it stands in, the
|
|
97
|
+
point in `--graview-mark-point` when set, decorative unless given a `title`,
|
|
98
|
+
and the optical micro cut under 28 px.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { type AnySchema, type Brand, type PagesArrangement, type Place, type Principal, type Store } from "@graview/core";
|
|
2
|
+
import { type CSSProperties, type ReactNode } from "react";
|
|
3
|
+
/** Which of the places a place is: the home, a kind's list, or a picture. */
|
|
4
|
+
export type BarPlaceGroup = "home" | "lists" | "pictures";
|
|
5
|
+
/** One of the app's places, as the bar's place control lists it: what it is called, and where it is on the routed face. */
|
|
6
|
+
export interface BarPlace {
|
|
7
|
+
readonly key: string;
|
|
8
|
+
readonly label: string;
|
|
9
|
+
/** Its path on the routed face. */
|
|
10
|
+
readonly path: string;
|
|
11
|
+
readonly group: BarPlaceGroup;
|
|
12
|
+
/** The kind it is a list or a picture of, for its mark. */
|
|
13
|
+
readonly kind?: string;
|
|
14
|
+
}
|
|
15
|
+
/** The key the home's place has (FR-136): the app's front page, first in the list, at the app's own address. */
|
|
16
|
+
export declare const HOME_KEY = "home";
|
|
17
|
+
/** The home's address on the routed face: the app's own. */
|
|
18
|
+
export declare const HOME_PATH = "/";
|
|
19
|
+
/**
|
|
20
|
+
* THE APP'S PLACES, IN THE LIST'S ORDER (FR-138): the home; each kind's list
|
|
21
|
+
* in the declaration's order; each named picture, then how the kinds
|
|
22
|
+
* connect, when they do. What a seat may not see is not offered: a kind
|
|
23
|
+
* kept from it, a disabled module's kind, a picture over either. The scene
|
|
24
|
+
* is not a place here: it is the switch's (FR-137).
|
|
25
|
+
*/
|
|
26
|
+
export declare function barPlaces(input: {
|
|
27
|
+
readonly store: Store<AnySchema>;
|
|
28
|
+
readonly principal?: Principal | undefined;
|
|
29
|
+
readonly views?: {
|
|
30
|
+
places(): readonly Place[];
|
|
31
|
+
arrangement?(): PagesArrangement | undefined;
|
|
32
|
+
} | undefined;
|
|
33
|
+
}): readonly BarPlace[];
|
|
34
|
+
/** Which of the places a path on the routed face is: its own, a record's kind's, or none (Find, the problems). */
|
|
35
|
+
export declare function barPlaceAt(places: readonly BarPlace[], path: string): string | null;
|
|
36
|
+
/**
|
|
37
|
+
* WHERE A FACE PUTS ITS FIND BOX (FR-131). The bar draws the place; the
|
|
38
|
+
* face drawn under it — the scene's Find, or the routed face's — puts its
|
|
39
|
+
* own box there, so Find is one box in one place whichever face is drawn.
|
|
40
|
+
*/
|
|
41
|
+
export interface BarFind {
|
|
42
|
+
readonly slot: HTMLElement;
|
|
43
|
+
/** A phone's bar: the box opens over the bar's row when it is asked for. */
|
|
44
|
+
readonly compact: boolean;
|
|
45
|
+
}
|
|
46
|
+
export declare const BarFindContext: import("react").Context<BarFind | null>;
|
|
47
|
+
/** The bar's place for a Find box, when a bar above this face has one. */
|
|
48
|
+
export declare const useBarFind: () => BarFind | null;
|
|
49
|
+
/** How a place is reached: a link when it has an address, a press when the bar decides. */
|
|
50
|
+
export interface BarGo {
|
|
51
|
+
/** The address a place's link carries; none, and the entry is a button. */
|
|
52
|
+
readonly href?: (path: string) => string | undefined;
|
|
53
|
+
/** Goes to a place; a link's ordinary press is handed here rather than followed. */
|
|
54
|
+
readonly go?: (place: BarPlace) => void;
|
|
55
|
+
}
|
|
56
|
+
/** One of the switch's two faces: what it is called, whether it is drawn, and the way to it. */
|
|
57
|
+
export interface BarFace {
|
|
58
|
+
readonly label: string;
|
|
59
|
+
readonly current: boolean;
|
|
60
|
+
readonly go: () => void;
|
|
61
|
+
}
|
|
62
|
+
/** THE SWITCH (FR-137): the scene and the pages, the app's two faces. */
|
|
63
|
+
export interface BarFaces {
|
|
64
|
+
readonly scene: BarFace;
|
|
65
|
+
readonly pages: BarFace;
|
|
66
|
+
}
|
|
67
|
+
/** One size for every tool on the bar (FR-131). */
|
|
68
|
+
export declare const TOOL = 30;
|
|
69
|
+
/** The bar's one row, its rule under it included, on a desk and a phone alike (FR-138). */
|
|
70
|
+
export declare const BAR_HEIGHT = 48;
|
|
71
|
+
/** A tool's own box: one size, square, its name in words for whoever cannot see the mark. */
|
|
72
|
+
export declare const toolStyle: CSSProperties;
|
|
73
|
+
/**
|
|
74
|
+
* THE BAR. The app at the left — its mark, its name as the page's heading,
|
|
75
|
+
* the way home — then the switch between the scene and the pages (FR-137),
|
|
76
|
+
* then, on Pages, the place you are on (FR-138), and the tools at the
|
|
77
|
+
* right: the Find a face puts in it, then `tools` (the standing and the
|
|
78
|
+
* person). One row of one height on a desk and a phone; on a phone the
|
|
79
|
+
* place is the page's first line, under the bar.
|
|
80
|
+
*/
|
|
81
|
+
export declare function AppBar({ brand, name, heading, home, faces, places, current, reach, tools, find, description, findBox, onFind, }: {
|
|
82
|
+
readonly brand: Brand | undefined;
|
|
83
|
+
readonly name: string;
|
|
84
|
+
/** The level the app's name is said at: 1 when the page is the app's, `false` when the host's own heading already says it. */
|
|
85
|
+
readonly heading?: 1 | 2 | 3 | 4 | 5 | 6 | false;
|
|
86
|
+
/** The way home, and whether the reader is there. */
|
|
87
|
+
readonly home: {
|
|
88
|
+
readonly href?: string | undefined;
|
|
89
|
+
readonly go?: (() => void) | undefined;
|
|
90
|
+
readonly current: boolean;
|
|
91
|
+
};
|
|
92
|
+
/** The switch between the scene and the pages; none where the face cannot draw the scene. */
|
|
93
|
+
readonly faces?: BarFaces | undefined;
|
|
94
|
+
readonly places: readonly BarPlace[];
|
|
95
|
+
/** The key of the place the reader is on; null at Find, at the problems. */
|
|
96
|
+
readonly current: string | null;
|
|
97
|
+
readonly reach: BarGo;
|
|
98
|
+
/** The standing and the person, after Find. */
|
|
99
|
+
readonly tools: ReactNode;
|
|
100
|
+
/** Whether a face puts a Find box in the bar. */
|
|
101
|
+
readonly find?: boolean;
|
|
102
|
+
/** The line under the app's name (the brand's `subtitle`): said on the home, and as the name's hover here. */
|
|
103
|
+
readonly description?: string | undefined;
|
|
104
|
+
/** A Find box the bar is handed to draw in its place, for a face drawn inside the bar's own tree; otherwise the face puts its own there. */
|
|
105
|
+
readonly findBox?: ReactNode;
|
|
106
|
+
/** Told where the bar keeps the Find box, for the face under it (`BarFindContext`). */
|
|
107
|
+
readonly onFind?: (find: BarFind | null) => void;
|
|
108
|
+
}): import("react").JSX.Element;
|
|
109
|
+
//# sourceMappingURL=app-bar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-bar.d.ts","sourceRoot":"","sources":["../src/app-bar.tsx"],"names":[],"mappings":"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"}
|
package/dist/app-bar.js
ADDED
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { hueFor, orderKinds, OVERVIEW_SLUG, placeSlug } from "@graview/core";
|
|
3
|
+
import { POPOVER_STYLE, usePopover } from "@graview/react/provider";
|
|
4
|
+
import { createContext, useCallback, useContext, useLayoutEffect, useRef, useState } from "react";
|
|
5
|
+
import { AppMark } from "./app-title.js";
|
|
6
|
+
/** The key the home's place has (FR-136): the app's front page, first in the list, at the app's own address. */
|
|
7
|
+
export const HOME_KEY = "home";
|
|
8
|
+
/** The home's address on the routed face: the app's own. */
|
|
9
|
+
export const HOME_PATH = "/";
|
|
10
|
+
const upper = (word) => word.charAt(0).toUpperCase() + word.slice(1);
|
|
11
|
+
/**
|
|
12
|
+
* THE APP'S PLACES, IN THE LIST'S ORDER (FR-138): the home; each kind's list
|
|
13
|
+
* in the declaration's order; each named picture, then how the kinds
|
|
14
|
+
* connect, when they do. What a seat may not see is not offered: a kind
|
|
15
|
+
* kept from it, a disabled module's kind, a picture over either. The scene
|
|
16
|
+
* is not a place here: it is the switch's (FR-137).
|
|
17
|
+
*/
|
|
18
|
+
export function barPlaces(input) {
|
|
19
|
+
const { store, principal, views } = input;
|
|
20
|
+
const kept = store.kindsKeptFrom(principal);
|
|
21
|
+
const live = store.schema.kinds.filter((kind) => !store.modules.disabledKinds.has(kind) && !kept.has(kind));
|
|
22
|
+
const arrangement = views?.arrangement?.();
|
|
23
|
+
const plural = (kind) => store.schema.tryDefinition(kind)?.plural ?? `${kind}s`;
|
|
24
|
+
const out = [{ key: HOME_KEY, label: "Home", path: HOME_PATH, group: "home" }];
|
|
25
|
+
for (const kind of orderKinds(live, arrangement?.order))
|
|
26
|
+
out.push({ key: `kind:${kind}`, label: upper(plural(kind)), path: `/${placeSlug(plural(kind))}`, group: "lists", kind });
|
|
27
|
+
const all = views?.places() ?? [];
|
|
28
|
+
for (const place of all) {
|
|
29
|
+
// A place at the scene's address is not offered: the address is the scene's (FR-132).
|
|
30
|
+
if (!live.includes(place.kind) || place.as === OVERVIEW_SLUG)
|
|
31
|
+
continue;
|
|
32
|
+
// Two kinds' pictures of one name say whose with `?of=` (as the routed face addresses them).
|
|
33
|
+
const shared = all.some((other) => other.as === place.as && other.kind !== place.kind);
|
|
34
|
+
const path = `/places/${encodeURIComponent(place.as)}${shared ? `?of=${placeSlug(plural(place.kind))}` : ""}`;
|
|
35
|
+
if (!out.some((held) => held.path === path))
|
|
36
|
+
out.push({ key: `place:${place.kind}:${place.as}`, label: place.title, path, group: "pictures", kind: place.kind });
|
|
37
|
+
}
|
|
38
|
+
const connects = live.some((kind) => Object.keys((store.schema.tryDefinition(kind)?.edges ?? {})).length > 0);
|
|
39
|
+
if (connects)
|
|
40
|
+
out.push({ key: "connections", label: "Connections", path: "/map", group: "pictures" });
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
/** Which of the places a path on the routed face is: its own, a record's kind's, or none (Find, the problems). */
|
|
44
|
+
export function barPlaceAt(places, path) {
|
|
45
|
+
const [pathname = "/", search = ""] = path.split("?");
|
|
46
|
+
const exact = places.find((place) => place.path === (search ? `${pathname}?${search}` : pathname)) ?? places.find((place) => place.path === pathname);
|
|
47
|
+
if (exact)
|
|
48
|
+
return exact.key;
|
|
49
|
+
const first = `/${pathname.split("/").filter(Boolean)[0] ?? ""}`;
|
|
50
|
+
// A record's page is under its kind's list.
|
|
51
|
+
return places.find((place) => place.group === "lists" && place.path === first)?.key ?? null;
|
|
52
|
+
}
|
|
53
|
+
export const BarFindContext = createContext(null);
|
|
54
|
+
/** The bar's place for a Find box, when a bar above this face has one. */
|
|
55
|
+
export const useBarFind = () => useContext(BarFindContext);
|
|
56
|
+
/** One size for every tool on the bar (FR-131). */
|
|
57
|
+
export const TOOL = 30;
|
|
58
|
+
/** The bar's one row, its rule under it included, on a desk and a phone alike (FR-138). */
|
|
59
|
+
export const BAR_HEIGHT = 48;
|
|
60
|
+
const BAR_CSS = `
|
|
61
|
+
.graview-bar{display:block;margin:0;padding:0;container-type:inline-size;flex:0 0 auto;position:relative;background:var(--graview-bar);border-bottom:1px solid var(--graview-edge);color:var(--graview-ink);font-family:var(--graview-font-body,system-ui)}
|
|
62
|
+
.graview-bar-row{display:flex;flex-wrap:nowrap;align-items:center;gap:16px;height:${BAR_HEIGHT - 1}px;margin:0;padding:0 16px}
|
|
63
|
+
.graview-bar-home,.graview-bar-face,.graview-bar-place,.graview-bar-item{display:inline-flex;align-items:center;box-sizing:border-box;min-width:0;margin:0;border:0;background:none;box-shadow:none;font:inherit;letter-spacing:normal;text-transform:none;text-decoration:none;color:var(--graview-ink);cursor:pointer;text-align:left}
|
|
64
|
+
.graview-bar-app{display:flex;flex:0 1 auto;min-width:0;max-width:34%}
|
|
65
|
+
.graview-bar-name{margin:0;min-width:0;display:flex;font-family:var(--graview-font-display,var(--graview-font-body,system-ui));font-size:.9375rem;font-weight:600;line-height:1.25}
|
|
66
|
+
.graview-bar-home{gap:8px;min-height:30px;padding:0;letter-spacing:-.005em;overflow-wrap:anywhere}
|
|
67
|
+
.graview-bar-faces{display:inline-flex;flex:0 0 auto;box-sizing:border-box;height:30px;margin:0;padding:2px;gap:2px;border:1px solid var(--graview-edge);border-radius:8px}
|
|
68
|
+
.graview-bar-face{gap:6px;padding:0 10px;border-radius:6px;font-size:.8125rem;white-space:nowrap;color:var(--graview-ink-muted)}
|
|
69
|
+
.graview-bar-face span{min-width:0;max-width:11em;overflow:hidden;text-overflow:ellipsis}
|
|
70
|
+
.graview-bar-face[aria-pressed=true]{color:var(--graview-ink);font-weight:600;background:color-mix(in srgb,var(--graview-accent) 16%,transparent)}
|
|
71
|
+
.graview-bar-mid{display:flex;flex:1 1 auto;min-width:0}
|
|
72
|
+
.graview-bar-place-at{position:relative;display:inline-flex;min-width:0;max-width:100%}
|
|
73
|
+
.graview-bar-place{gap:6px;height:30px;max-width:100%;padding:0 8px;border:1px solid transparent;border-radius:8px;font-size:.875rem;font-weight:600}
|
|
74
|
+
.graview-bar-face:hover,.graview-bar-place:hover{border-color:var(--graview-edge);color:var(--graview-ink)}
|
|
75
|
+
.graview-bar-place-words{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
76
|
+
.graview-bar-list{display:grid;width:min(320px,calc(100vw - 24px));max-height:min(70vh,560px);overflow:auto;margin:0;padding:6px;border-radius:10px;border:1px solid var(--graview-edge);background:var(--graview-float);box-shadow:var(--graview-lift-high);color:var(--graview-ink)}
|
|
77
|
+
.graview-bar-list[hidden]{display:none}
|
|
78
|
+
.graview-bar-list p{margin:8px 8px 2px;font-size:.6875rem;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--graview-ink-muted)}
|
|
79
|
+
.graview-bar-list ul,.graview-bar-list li{display:grid;margin:0;padding:0;list-style:none}
|
|
80
|
+
.graview-bar-item{align-items:flex-start;gap:10px;width:100%;padding:7px 8px;border-radius:7px;font-size:.875rem;line-height:1.3;overflow-wrap:anywhere}
|
|
81
|
+
.graview-bar-item:hover{background:color-mix(in srgb,var(--graview-ink) 7%,transparent)}
|
|
82
|
+
.graview-bar-item[aria-current]{font-weight:600;background:color-mix(in srgb,var(--graview-accent) 14%,transparent)}
|
|
83
|
+
.graview-bar-mark{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;width:14px;height:1.3em;color:var(--graview-ink-muted)}
|
|
84
|
+
.graview-bar :focus-visible{outline:2px solid var(--graview-accent);outline-offset:1px}
|
|
85
|
+
.graview-bar-tools{display:flex;align-items:center;flex:0 0 auto;gap:8px;margin-left:auto}
|
|
86
|
+
.graview-bar-find{display:flex;width:15rem;min-width:7rem;flex:0 1 auto}
|
|
87
|
+
.graview-bar-find-open{display:none}
|
|
88
|
+
.graview-bar-line{display:flex;flex:0 0 auto;padding:6px 8px;background:var(--graview-ground);border-bottom:1px solid var(--graview-edge);font-family:var(--graview-font-body,system-ui)}
|
|
89
|
+
.graview-bar-line .graview-bar-place{height:auto;min-height:32px}
|
|
90
|
+
.graview-bar-line .graview-bar-place-words{white-space:normal}
|
|
91
|
+
@container (max-width: 639px){
|
|
92
|
+
.graview-bar-row{gap:10px;padding:0 12px}
|
|
93
|
+
.graview-bar-app{max-width:none;flex:1 1 auto}
|
|
94
|
+
.graview-bar-app-name{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}
|
|
95
|
+
.graview-bar-face{padding:0 8px}
|
|
96
|
+
.graview-bar-face span{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
|
|
97
|
+
.graview-bar-mid,.graview-bar-find{display:none}
|
|
98
|
+
.graview-bar-find-open{display:inline-flex}
|
|
99
|
+
.graview-bar[data-finding] :is(.graview-bar-app,.graview-bar-faces,.graview-bar-find-open){display:none}
|
|
100
|
+
.graview-bar[data-finding] .graview-bar-tools{flex:1 1 auto}
|
|
101
|
+
.graview-bar[data-finding] .graview-bar-find{display:flex;flex:1 1 auto;width:auto;min-width:0}
|
|
102
|
+
}`;
|
|
103
|
+
/** A tool's own box: one size, square, its name in words for whoever cannot see the mark. */
|
|
104
|
+
export const toolStyle = {
|
|
105
|
+
display: "inline-flex",
|
|
106
|
+
alignItems: "center",
|
|
107
|
+
justifyContent: "center",
|
|
108
|
+
gap: 6,
|
|
109
|
+
minWidth: TOOL,
|
|
110
|
+
height: TOOL,
|
|
111
|
+
padding: 0,
|
|
112
|
+
borderRadius: 8,
|
|
113
|
+
border: "1px solid transparent",
|
|
114
|
+
background: "none",
|
|
115
|
+
boxShadow: "none",
|
|
116
|
+
color: "var(--graview-ink-muted)",
|
|
117
|
+
font: "inherit",
|
|
118
|
+
fontSize: "0.875rem",
|
|
119
|
+
cursor: "pointer",
|
|
120
|
+
flex: "0 0 auto",
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* THE BAR. The app at the left — its mark, its name as the page's heading,
|
|
124
|
+
* the way home — then the switch between the scene and the pages (FR-137),
|
|
125
|
+
* then, on Pages, the place you are on (FR-138), and the tools at the
|
|
126
|
+
* right: the Find a face puts in it, then `tools` (the standing and the
|
|
127
|
+
* person). One row of one height on a desk and a phone; on a phone the
|
|
128
|
+
* place is the page's first line, under the bar.
|
|
129
|
+
*/
|
|
130
|
+
export function AppBar({ brand, name, heading = 1, home, faces, places, current, reach, tools, find = true, description, findBox, onFind, }) {
|
|
131
|
+
const bar = useRef(null);
|
|
132
|
+
const [slot, setSlot] = useState(null);
|
|
133
|
+
const [compact, setCompact] = useState(false);
|
|
134
|
+
const [finding, setFinding] = useState(false);
|
|
135
|
+
useLayoutEffect(() => {
|
|
136
|
+
const element = bar.current;
|
|
137
|
+
if (!element)
|
|
138
|
+
return;
|
|
139
|
+
const read = () => setCompact(element.getBoundingClientRect().width < 640);
|
|
140
|
+
read();
|
|
141
|
+
if (typeof ResizeObserver === "undefined")
|
|
142
|
+
return;
|
|
143
|
+
const watch = new ResizeObserver(read);
|
|
144
|
+
watch.observe(element);
|
|
145
|
+
return () => watch.disconnect();
|
|
146
|
+
}, []);
|
|
147
|
+
const told = useRef(onFind);
|
|
148
|
+
told.current = onFind;
|
|
149
|
+
useLayoutEffect(() => {
|
|
150
|
+
told.current?.(find && slot ? { slot, compact } : null);
|
|
151
|
+
}, [find, slot, compact]);
|
|
152
|
+
useLayoutEffect(() => () => told.current?.(null), []);
|
|
153
|
+
const openFind = useCallback(() => {
|
|
154
|
+
setFinding(true);
|
|
155
|
+
requestAnimationFrame(() => slot?.querySelector("input")?.focus());
|
|
156
|
+
}, [slot]);
|
|
157
|
+
/*
|
|
158
|
+
* Put away on a phone by Escape, the box gives the keyboard back to the
|
|
159
|
+
* magnifier that opened it — never to the page's body.
|
|
160
|
+
*/
|
|
161
|
+
const opener = useRef(null);
|
|
162
|
+
const escaping = useRef(false);
|
|
163
|
+
const putAway = useCallback(() => {
|
|
164
|
+
setFinding(false);
|
|
165
|
+
if (!escaping.current)
|
|
166
|
+
return;
|
|
167
|
+
escaping.current = false;
|
|
168
|
+
requestAnimationFrame(() => opener.current?.focus());
|
|
169
|
+
}, []);
|
|
170
|
+
const Heading = heading === false ? "span" : `h${heading}`;
|
|
171
|
+
const Home = (home.href !== undefined ? "a" : "button");
|
|
172
|
+
const press = (go) => (event) => {
|
|
173
|
+
if (!go || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)
|
|
174
|
+
return;
|
|
175
|
+
event.preventDefault();
|
|
176
|
+
go();
|
|
177
|
+
};
|
|
178
|
+
// The place control stands on Pages: in the bar on a desk, as the page's first line on a phone.
|
|
179
|
+
const onPages = !faces || faces.pages.current;
|
|
180
|
+
const placeControl = onPages && places.length > 0 ? _jsx(PlaceControl, { places: places, current: current, reach: reach }) : null;
|
|
181
|
+
return (_jsxs(_Fragment, { children: [_jsxs("header", { ref: bar, className: "graview-bar", "data-testid": "app-bar", "data-graview-app-bar": "", ...(finding && compact ? { "data-finding": "" } : {}), children: [_jsx("style", { children: BAR_CSS }), _jsxs("div", { className: "graview-bar-row", children: [_jsx("div", { className: "graview-bar-app", children: _jsx(Heading, { className: "graview-bar-name", children: _jsxs(Home, { ...(home.href !== undefined ? { href: home.href, onClick: press(home.go) } : { type: "button", onClick: home.go }), "data-testid": "app-home", ...(home.current ? { "aria-current": "page" } : {}), title: description ? `${name} — ${description}` : `${name} — home`, className: "graview-bar-home", children: [_jsx(AppMark, { brand: brand, size: 20 }), _jsx("span", { className: "graview-bar-app-name", "data-testid": "app-name", children: name })] }) }) }), faces ? _jsx(FaceSwitch, { faces: faces }) : null, _jsx("div", { className: "graview-bar-mid", children: compact ? null : placeControl }), _jsxs("div", { className: "graview-bar-tools", children: [find ? (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", className: "graview-bar-find-open", ref: opener, "data-testid": "app-find-open", "aria-label": "Find", title: "Find", onClick: openFind, style: { ...toolStyle, display: undefined }, children: _jsx(FindMark, {}) }), _jsx("div", { ref: setSlot, className: "graview-bar-find", "data-testid": "app-find", onBlur: (event) => {
|
|
182
|
+
// Put away on a phone when the keyboard leaves it with nothing typed.
|
|
183
|
+
const next = event.relatedTarget;
|
|
184
|
+
if (next instanceof Node && event.currentTarget.contains(next))
|
|
185
|
+
return;
|
|
186
|
+
if (!event.currentTarget.querySelector("input")?.value)
|
|
187
|
+
putAway();
|
|
188
|
+
}, onKeyDownCapture: (event) => {
|
|
189
|
+
if (event.key === "Escape" && compact)
|
|
190
|
+
escaping.current = true;
|
|
191
|
+
}, onKeyDown: (event) => {
|
|
192
|
+
if (event.key !== "Escape" || !compact)
|
|
193
|
+
return;
|
|
194
|
+
// The scene's Find takes Escape for its words first; an empty box is put away.
|
|
195
|
+
if (!event.defaultPrevented || !event.currentTarget.querySelector("input")?.value)
|
|
196
|
+
putAway();
|
|
197
|
+
else
|
|
198
|
+
escaping.current = false;
|
|
199
|
+
}, children: findBox })] })) : null, tools] })] })] }), compact && placeControl ? (_jsx("div", { className: "graview-bar-line", "data-graview-place-line": "", "data-testid": "app-place-line", children: placeControl })) : null] }));
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* THE SWITCH (FR-137): the scene and the pages, side by side, an icon and a
|
|
203
|
+
* word each — the words the accessible names alone on a phone — the one
|
|
204
|
+
* drawn pressed. Choosing the scene draws it under the bar; choosing the
|
|
205
|
+
* pages goes back to the page you were on.
|
|
206
|
+
*/
|
|
207
|
+
function FaceSwitch({ faces }) {
|
|
208
|
+
const face = (which) => {
|
|
209
|
+
const one = faces[which];
|
|
210
|
+
return (_jsxs("button", { type: "button", className: "graview-bar-face", "data-testid": `app-face-${which}`, "aria-pressed": one.current, title: one.label, onClick: () => {
|
|
211
|
+
if (!one.current)
|
|
212
|
+
one.go();
|
|
213
|
+
}, children: [which === "scene" ? _jsx(SceneMark, {}) : _jsx(PagesMark, {}), _jsx("span", { children: one.label })] }));
|
|
214
|
+
};
|
|
215
|
+
return (_jsxs("div", { className: "graview-bar-faces", role: "group", "aria-label": `${faces.scene.label} or ${faces.pages.label}`, "data-testid": "app-faces", children: [face("scene"), face("pages")] }));
|
|
216
|
+
}
|
|
217
|
+
/** The scene's mark: a plot of the city, seen from above at an angle. */
|
|
218
|
+
function SceneMark() {
|
|
219
|
+
return (_jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", "aria-hidden": "true", focusable: "false", style: { flex: "0 0 auto" }, children: [_jsx("path", { d: "M7 1.5 L12.5 4.5 L7 7.5 L1.5 4.5 Z", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinejoin: "round" }), _jsx("path", { d: "M1.5 7.5 L7 10.5 L12.5 7.5", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinejoin: "round", strokeLinecap: "round" })] }));
|
|
220
|
+
}
|
|
221
|
+
/** The pages' mark: a page of lines. */
|
|
222
|
+
function PagesMark() {
|
|
223
|
+
return (_jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", "aria-hidden": "true", focusable: "false", style: { flex: "0 0 auto" }, children: [_jsx("rect", { x: "2.25", y: "1.75", width: "9.5", height: "10.5", rx: "1.5", fill: "none", stroke: "currentColor", strokeWidth: "1.3" }), _jsx("path", { d: "M4.5 5 H9.5 M4.5 7.25 H9.5 M4.5 9.5 H7.5", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round" })] }));
|
|
224
|
+
}
|
|
225
|
+
/** The way a menu opens: a chevron drawn, not a glyph a face may draw as a dot. */
|
|
226
|
+
function Chevron() {
|
|
227
|
+
return (_jsx("svg", { width: "10", height: "10", viewBox: "0 0 10 10", "aria-hidden": "true", focusable: "false", style: { flex: "0 0 auto" }, children: _jsx("path", { d: "M2 3.5 L5 6.5 L8 3.5", fill: "none", stroke: "currentColor", strokeWidth: "1.4", strokeLinecap: "round", strokeLinejoin: "round" }) }));
|
|
228
|
+
}
|
|
229
|
+
/** A magnifier: the mark for Find where there is no room for the box. */
|
|
230
|
+
function FindMark() {
|
|
231
|
+
return (_jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", "aria-hidden": "true", focusable: "false", children: [_jsx("circle", { cx: "7", cy: "7", r: "4.75", fill: "none", stroke: "currentColor", strokeWidth: "1.5" }), _jsx("path", { d: "M10.5 10.5 L14 14", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })] }));
|
|
232
|
+
}
|
|
233
|
+
/** A place's mark in the list: the home's house, a kind's plot in its own hue. */
|
|
234
|
+
function PlaceMark({ place }) {
|
|
235
|
+
if (place.group === "home") {
|
|
236
|
+
return (_jsx("svg", { width: "13", height: "13", viewBox: "0 0 14 14", "aria-hidden": "true", focusable: "false", children: _jsx("path", { d: "M2 6.5 L7 2 L12 6.5 V12 H2 Z", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinejoin: "round" }) }));
|
|
237
|
+
}
|
|
238
|
+
// A kind's plot, as the scene draws it from altitude (the mark FR-117 gave a kind with no drawing); a picture of it wears its outline; how the kinds connect, the ink's.
|
|
239
|
+
const hue = place.kind ? `hsl(${Math.round(hueFor(place.kind))} 55% 52%` : "rgb(128 128 128";
|
|
240
|
+
return (_jsx("span", { "aria-hidden": "true", style: {
|
|
241
|
+
display: "inline-block",
|
|
242
|
+
width: 12,
|
|
243
|
+
height: 8,
|
|
244
|
+
clipPath: "polygon(50% 0, 100% 50%, 50% 100%, 0 50%)",
|
|
245
|
+
background: place.group === "lists" ? `${hue})` : `linear-gradient(${hue}), ${hue})) center / 6px 4px no-repeat, ${hue} / 0.35)`,
|
|
246
|
+
} }));
|
|
247
|
+
}
|
|
248
|
+
const GROUPS = [{ group: "home" }, { group: "lists", heading: "Lists" }, { group: "pictures", heading: "Pictures" }];
|
|
249
|
+
/**
|
|
250
|
+
* THE PLACE YOU ARE ON, AND EVERY OTHER (FR-138): one control, the place's
|
|
251
|
+
* name and a chevron, that opens the app's places — the home first, then
|
|
252
|
+
* the Lists and the Pictures, each with its mark, a long name wrapped
|
|
253
|
+
* rather than cut. Every place is two presses away, and the bar is one row
|
|
254
|
+
* of one height however many there are.
|
|
255
|
+
*/
|
|
256
|
+
function PlaceControl({ places, current, reach }) {
|
|
257
|
+
const popover = usePopover("places");
|
|
258
|
+
const here = places.find((place) => place.key === current);
|
|
259
|
+
const said = here?.label ?? "Places";
|
|
260
|
+
const entry = (place) => {
|
|
261
|
+
const at = place.key === current;
|
|
262
|
+
const href = reach.href?.(place.path);
|
|
263
|
+
const common = {
|
|
264
|
+
className: "graview-bar-item",
|
|
265
|
+
"data-testid": `app-place-${place.key}`,
|
|
266
|
+
"data-place-path": place.path,
|
|
267
|
+
...(at ? { "aria-current": "page" } : {}),
|
|
268
|
+
onClick: (event) => {
|
|
269
|
+
popover.setOpen(false);
|
|
270
|
+
if (!reach.go)
|
|
271
|
+
return;
|
|
272
|
+
if (href !== undefined && (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey))
|
|
273
|
+
return;
|
|
274
|
+
event.preventDefault();
|
|
275
|
+
reach.go(place);
|
|
276
|
+
},
|
|
277
|
+
};
|
|
278
|
+
const Entry = (href !== undefined ? "a" : "button");
|
|
279
|
+
return (_jsxs(Entry, { ...common, ...(href !== undefined ? { href } : { type: "button" }), children: [_jsx("span", { className: "graview-bar-mark", children: _jsx(PlaceMark, { place: place }) }), _jsx("span", { children: place.label })] }, place.key));
|
|
280
|
+
};
|
|
281
|
+
return (_jsxs("span", { className: "graview-bar-place-at", children: [_jsxs("button", { type: "button", className: "graview-bar-place", "data-testid": "app-places-open", ...popover.trigger, onClick: popover.toggle, "aria-label": `${said} — every place`, title: said, children: [_jsx("span", { className: "graview-bar-place-words", "data-testid": "app-place-current", children: said }), _jsx(Chevron, {})] }), _jsx("nav", { ...popover.pane, "data-testid": "app-places", "aria-label": "The app\u2019s places", hidden: !popover.open, className: "graview-bar-list", style: POPOVER_STYLE, children: GROUPS.map(({ group, heading }) => {
|
|
282
|
+
const listed = places.filter((place) => place.group === group);
|
|
283
|
+
if (listed.length === 0)
|
|
284
|
+
return null;
|
|
285
|
+
const id = `${popover.pane.id}-${group}`;
|
|
286
|
+
return (_jsxs("div", { role: "group", ...(heading ? { "aria-labelledby": id } : { "aria-label": "Home" }), "data-place-group": group, children: [heading ? (_jsx("p", { id: id, children: heading })) : null, _jsx("ul", { children: listed.map((place) => (_jsx("li", { children: entry(place) }, place.key))) })] }, group));
|
|
287
|
+
}) })] }));
|
|
288
|
+
}
|
|
289
|
+
//# sourceMappingURL=app-bar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-bar.js","sourceRoot":"","sources":["../src/app-bar.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type Brand } from "@graview/core";
|
|
2
|
+
/** The brand's mark alone, `size` pixels tall; nothing when there is none, or none that may be drawn. */
|
|
3
|
+
export declare function AppMark({ brand, size }: {
|
|
4
|
+
readonly brand: Brand | undefined;
|
|
5
|
+
readonly size?: number;
|
|
6
|
+
}): import("react").JSX.Element | null;
|
|
7
|
+
/**
|
|
8
|
+
* The mark, the name and — where `subtitle` asks and the brand has one —
|
|
9
|
+
* the line under the name. Its type is the container's: the name takes
|
|
10
|
+
* the font, size and case it is drawn in; the line under it is the body's,
|
|
11
|
+
* quiet, and wraps rather than being cut.
|
|
12
|
+
*/
|
|
13
|
+
export declare function AppTitle({ brand, name, subtitle, size }: {
|
|
14
|
+
readonly brand: Brand | undefined;
|
|
15
|
+
readonly name?: string;
|
|
16
|
+
readonly subtitle?: boolean;
|
|
17
|
+
readonly size?: number;
|
|
18
|
+
}): import("react").JSX.Element;
|
|
19
|
+
/**
|
|
20
|
+
* THE PAGE'S ICON (FR-124), for a face that owns the whole page — the
|
|
21
|
+
* Shell, the routed face on its own, an embed its host told `favicon:
|
|
22
|
+
* true`. Every `<link rel="icon">` the page has points at it while the face
|
|
23
|
+
* is drawn, and back at what it pointed at after; a page with none gets
|
|
24
|
+
* one. `undefined` touches nothing, which is what an embed on somebody
|
|
25
|
+
* else's page passes.
|
|
26
|
+
*/
|
|
27
|
+
export declare function useFavicon(href: string | undefined): void;
|
|
28
|
+
//# sourceMappingURL=app-title.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-title.d.ts","sourceRoot":"","sources":["../src/app-title.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqC,KAAK,KAAK,EAAE,MAAM,eAAe,CAAC;AAkB9E,yGAAyG;AACzG,wBAAgB,OAAO,CAAC,EAAE,KAAK,EAAE,IAAS,EAAE,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,CAAC;IAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,sCAU1G;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAgB,EAAE,IAAI,EAAE,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,CAAC;IAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,+BAkBnL;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAqBzD"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { isInlineSvg, markHref, svgProblem } from "@graview/core";
|
|
3
|
+
import { useEffect } from "react";
|
|
4
|
+
import { useMarkup } from "./markup.js";
|
|
5
|
+
/*
|
|
6
|
+
* THE APP, SAID ONCE (FR-124, FR-125): its mark, its name, and the line
|
|
7
|
+
* under the name — the one component every face draws its title with, so
|
|
8
|
+
* the whole-page Shell's wordmark and the one app bar (FR-131, with `AppMark`)
|
|
9
|
+
* say the same app the same way.
|
|
10
|
+
*
|
|
11
|
+
* The mark is drawn as the brand gives it, never redrawn: an SVG written
|
|
12
|
+
* inline is put in the page as it is (so `currentColor` takes the accent,
|
|
13
|
+
* and nothing else is recolored), and only when it could not act — an
|
|
14
|
+
* SVG with a script, a handler or a load in it is not drawn at all. A path
|
|
15
|
+
* is an `<img>`. Beside the name the mark is said only when its alt text
|
|
16
|
+
* says more than the name does.
|
|
17
|
+
*/
|
|
18
|
+
/** The brand's mark alone, `size` pixels tall; nothing when there is none, or none that may be drawn. */
|
|
19
|
+
export function AppMark({ brand, size = 22 }) {
|
|
20
|
+
const logo = brand?.logo;
|
|
21
|
+
const inline = logo !== undefined && isInlineSvg(logo) && svgProblem(logo) === null ? logo : undefined;
|
|
22
|
+
const markup = useMarkup(inline);
|
|
23
|
+
if (!logo || !markHref(logo))
|
|
24
|
+
return null;
|
|
25
|
+
const alt = brand?.logoAlt ?? brand?.name ?? "";
|
|
26
|
+
const said = alt !== "" && alt !== brand?.name;
|
|
27
|
+
const box = { display: "inline-flex", flex: "0 0 auto", height: size, color: "var(--graview-accent)" };
|
|
28
|
+
if (inline)
|
|
29
|
+
return _jsx("span", { className: "graview-logo", "data-testid": "app-mark", style: box, ...(said ? { role: "img", "aria-label": alt } : { "aria-hidden": true }), dangerouslySetInnerHTML: markup });
|
|
30
|
+
return _jsx("img", { className: "graview-logo", "data-testid": "app-mark", src: logo, alt: said ? alt : "", style: { ...box, width: "auto" } });
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The mark, the name and — where `subtitle` asks and the brand has one —
|
|
34
|
+
* the line under the name. Its type is the container's: the name takes
|
|
35
|
+
* the font, size and case it is drawn in; the line under it is the body's,
|
|
36
|
+
* quiet, and wraps rather than being cut.
|
|
37
|
+
*/
|
|
38
|
+
export function AppTitle({ brand, name, subtitle = false, size }) {
|
|
39
|
+
const line = subtitle ? brand?.subtitle : undefined;
|
|
40
|
+
return (_jsxs("span", { className: "graview-app-title", style: { display: "inline-flex", alignItems: "center", gap: 8, minWidth: 0 }, children: [_jsx(AppMark, { brand: brand, ...(size !== undefined ? { size } : {}) }), _jsxs("span", { style: { display: "inline-flex", flexDirection: "column", minWidth: 0 }, children: [_jsx("span", { "data-testid": "app-name", children: name ?? brand?.name ?? "Graview" }), line ? (_jsx("span", { "data-testid": "app-subtitle", style: { fontFamily: "var(--graview-font-body)", fontSize: "0.8125rem", fontWeight: 400, letterSpacing: "normal", textTransform: "none", lineHeight: 1.35, color: "var(--graview-ink-muted)", whiteSpace: "normal", overflowWrap: "anywhere" }, children: line })) : null] })] }));
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* THE PAGE'S ICON (FR-124), for a face that owns the whole page — the
|
|
44
|
+
* Shell, the routed face on its own, an embed its host told `favicon:
|
|
45
|
+
* true`. Every `<link rel="icon">` the page has points at it while the face
|
|
46
|
+
* is drawn, and back at what it pointed at after; a page with none gets
|
|
47
|
+
* one. `undefined` touches nothing, which is what an embed on somebody
|
|
48
|
+
* else's page passes.
|
|
49
|
+
*/
|
|
50
|
+
export function useFavicon(href) {
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (!href || typeof document === "undefined")
|
|
53
|
+
return;
|
|
54
|
+
const links = [...document.querySelectorAll('link[rel~="icon"]')];
|
|
55
|
+
const was = links.map((link) => link.getAttribute("href"));
|
|
56
|
+
let made;
|
|
57
|
+
if (links.length === 0) {
|
|
58
|
+
made = document.createElement("link");
|
|
59
|
+
made.rel = "icon";
|
|
60
|
+
made.setAttribute("data-graview-favicon", "");
|
|
61
|
+
document.head.appendChild(made);
|
|
62
|
+
links.push(made);
|
|
63
|
+
}
|
|
64
|
+
for (const link of links)
|
|
65
|
+
link.href = href;
|
|
66
|
+
return () => {
|
|
67
|
+
if (made)
|
|
68
|
+
made.remove();
|
|
69
|
+
links.forEach((link, i) => {
|
|
70
|
+
if (link !== made && was[i] !== null && was[i] !== undefined)
|
|
71
|
+
link.setAttribute("href", was[i]);
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
}, [href]);
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=app-title.js.map
|