react-cheminfo 0.34.0 → 0.36.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 +28 -28
- package/bin/check-seo.mjs +333 -0
- package/lib/about/core/about.d.ts +1 -30
- package/lib/about/core/about.d.ts.map +1 -1
- package/lib/about/core/about.js +0 -16
- package/lib/about/core/about.js.map +1 -1
- package/lib/about/core/index.d.ts +0 -1
- package/lib/about/core/index.d.ts.map +1 -1
- package/lib/about/core/index.js +0 -1
- package/lib/about/core/index.js.map +1 -1
- package/lib/about/ui/AboutBuild.d.ts +2 -5
- package/lib/about/ui/AboutBuild.d.ts.map +1 -1
- package/lib/about/ui/AboutBuild.js +7 -19
- package/lib/about/ui/AboutBuild.js.map +1 -1
- package/lib/about/ui/AboutPage.d.ts +2 -2
- package/lib/about/ui/AboutPage.d.ts.map +1 -1
- package/lib/about/ui/AboutPage.js +3 -14
- package/lib/about/ui/AboutPage.js.map +1 -1
- package/lib/about/ui/AboutVersion.d.ts +0 -4
- package/lib/about/ui/AboutVersion.d.ts.map +1 -1
- package/lib/about/ui/AboutVersion.js +3 -31
- package/lib/about/ui/AboutVersion.js.map +1 -1
- package/lib/download/core/index.d.ts +0 -5
- package/lib/download/core/index.d.ts.map +1 -1
- package/lib/download/core/index.js +0 -3
- package/lib/download/core/index.js.map +1 -1
- package/lib/download/ui/FigureDownload.d.ts +4 -55
- package/lib/download/ui/FigureDownload.d.ts.map +1 -1
- package/lib/download/ui/FigureDownload.js +6 -66
- package/lib/download/ui/FigureDownload.js.map +1 -1
- package/lib/download/ui/FigureDownloadPanel.d.ts +16 -2
- package/lib/download/ui/FigureDownloadPanel.d.ts.map +1 -1
- package/lib/download/ui/FigureDownloadPanel.js +11 -30
- package/lib/download/ui/FigureDownloadPanel.js.map +1 -1
- package/lib/download/ui/figureDownloadHint.d.ts +30 -0
- package/lib/download/ui/figureDownloadHint.d.ts.map +1 -0
- package/lib/download/ui/figureDownloadHint.js +33 -0
- package/lib/download/ui/figureDownloadHint.js.map +1 -0
- package/lib/download/ui/index.d.ts +3 -10
- package/lib/download/ui/index.d.ts.map +1 -1
- package/lib/download/ui/index.js +1 -5
- package/lib/download/ui/index.js.map +1 -1
- package/lib/download/ui/useFigureActions.d.ts +50 -0
- package/lib/download/ui/useFigureActions.d.ts.map +1 -0
- package/lib/download/ui/useFigureActions.js +58 -0
- package/lib/download/ui/useFigureActions.js.map +1 -0
- package/lib/download/ui/useFigureDownload.d.ts +85 -0
- package/lib/download/ui/useFigureDownload.d.ts.map +1 -0
- package/lib/download/ui/useFigureDownload.js +75 -0
- package/lib/download/ui/useFigureDownload.js.map +1 -0
- package/lib/ecosystem/core/sites.d.ts.map +1 -1
- package/lib/ecosystem/core/sites.js +0 -40
- package/lib/ecosystem/core/sites.js.map +1 -1
- package/lib/ecosystem/core/types.d.ts +0 -10
- package/lib/ecosystem/core/types.d.ts.map +1 -1
- package/lib/i18n/core/chromeCatalog.d.ts +1 -1
- package/lib/i18n/core/chromeCatalog.d.ts.map +1 -1
- package/lib/ir/core/irCommands.d.ts +2 -2
- package/lib/ir/core/irCommands.js +2 -2
- package/lib/ir/core/irCommands.js.map +1 -1
- package/lib/ir/ui/IrAboutDialog.d.ts.map +1 -1
- package/lib/ir/ui/IrAboutDialog.js +1 -1
- package/lib/ir/ui/IrAboutDialog.js.map +1 -1
- package/lib/ir/ui/IrCanvas.d.ts +6 -0
- package/lib/ir/ui/IrCanvas.d.ts.map +1 -1
- package/lib/ir/ui/IrCanvas.js +2 -2
- package/lib/ir/ui/IrCanvas.js.map +1 -1
- package/lib/ir/ui/IrShell.d.ts.map +1 -1
- package/lib/ir/ui/IrShell.js +16 -11
- package/lib/ir/ui/IrShell.js.map +1 -1
- package/lib/ir/ui/IrToolbar.d.ts +11 -1
- package/lib/ir/ui/IrToolbar.d.ts.map +1 -1
- package/lib/ir/ui/IrToolbar.js +12 -2
- package/lib/ir/ui/IrToolbar.js.map +1 -1
- package/lib/ir/ui/index.d.ts +1 -0
- package/lib/ir/ui/index.d.ts.map +1 -1
- package/lib/ir/ui/index.js.map +1 -1
- package/lib/language/core/index.d.ts +2 -0
- package/lib/language/core/index.d.ts.map +1 -1
- package/lib/language/core/index.js +1 -0
- package/lib/language/core/index.js.map +1 -1
- package/lib/language/core/languagePath.d.ts +52 -0
- package/lib/language/core/languagePath.d.ts.map +1 -0
- package/lib/language/core/languagePath.js +65 -0
- package/lib/language/core/languagePath.js.map +1 -0
- package/lib/locales/de.json +2 -4
- package/lib/locales/en.json +2 -4
- package/lib/locales/es.json +2 -4
- package/lib/locales/fr.json +2 -4
- package/lib/locales/it.json +2 -4
- package/lib/overlay/ui/OverlayPanel.d.ts +6 -0
- package/lib/overlay/ui/OverlayPanel.d.ts.map +1 -1
- package/lib/overlay/ui/OverlayPanel.js +2 -2
- package/lib/overlay/ui/OverlayPanel.js.map +1 -1
- package/lib/overlay/ui/overlayPanelStyles.d.ts +2 -1
- package/lib/overlay/ui/overlayPanelStyles.d.ts.map +1 -1
- package/lib/overlay/ui/overlayPanelStyles.js +3 -1
- package/lib/overlay/ui/overlayPanelStyles.js.map +1 -1
- package/lib/periodic/ui/ElementCell.d.ts +0 -6
- package/lib/periodic/ui/ElementCell.d.ts.map +1 -1
- package/lib/periodic/ui/ElementCell.js +34 -30
- package/lib/periodic/ui/ElementCell.js.map +1 -1
- package/lib/periodic/ui/PeriodicTable.d.ts.map +1 -1
- package/lib/periodic/ui/PeriodicTable.js +12 -15
- package/lib/periodic/ui/PeriodicTable.js.map +1 -1
- package/lib/seo/core/alternates.d.ts +40 -0
- package/lib/seo/core/alternates.d.ts.map +1 -0
- package/lib/seo/core/alternates.js +42 -0
- package/lib/seo/core/alternates.js.map +1 -0
- package/lib/seo/core/index.d.ts +3 -0
- package/lib/seo/core/index.d.ts.map +1 -1
- package/lib/seo/core/index.js +2 -0
- package/lib/seo/core/index.js.map +1 -1
- package/lib/seo/core/noscript.d.ts +9 -0
- package/lib/seo/core/noscript.d.ts.map +1 -1
- package/lib/seo/core/noscript.js +7 -2
- package/lib/seo/core/noscript.js.map +1 -1
- package/lib/seo/core/pageMeta.d.ts +23 -0
- package/lib/seo/core/pageMeta.d.ts.map +1 -1
- package/lib/seo/core/pageMeta.js +52 -3
- package/lib/seo/core/pageMeta.js.map +1 -1
- package/lib/seo/core/pageProse.d.ts +76 -0
- package/lib/seo/core/pageProse.d.ts.map +1 -0
- package/lib/seo/core/pageProse.js +92 -0
- package/lib/seo/core/pageProse.js.map +1 -0
- package/lib/seo/core/routeProblems.d.ts +33 -0
- package/lib/seo/core/routeProblems.d.ts.map +1 -0
- package/lib/seo/core/routeProblems.js +89 -0
- package/lib/seo/core/routeProblems.js.map +1 -0
- package/lib/seo/core/routes.d.ts +14 -0
- package/lib/seo/core/routes.d.ts.map +1 -1
- package/lib/seo/core/routes.js.map +1 -1
- package/lib/seo/core/siteFiles.d.ts.map +1 -1
- package/lib/seo/core/siteFiles.js +2 -1
- package/lib/seo/core/siteFiles.js.map +1 -1
- package/lib/seo/vite/prerender.d.ts +13 -0
- package/lib/seo/vite/prerender.d.ts.map +1 -1
- package/lib/seo/vite/prerender.js +17 -10
- package/lib/seo/vite/prerender.js.map +1 -1
- package/package.json +2 -1
- package/src/about/core/about.ts +1 -51
- package/src/about/core/index.ts +0 -1
- package/src/about/ui/AboutBuild.tsx +8 -37
- package/src/about/ui/AboutPage.tsx +8 -64
- package/src/about/ui/AboutVersion.tsx +5 -45
- package/src/download/core/index.ts +0 -25
- package/src/download/ui/FigureDownload.tsx +11 -148
- package/src/download/ui/FigureDownloadPanel.tsx +46 -45
- package/src/download/ui/figureDownloadHint.ts +52 -0
- package/src/download/ui/index.ts +6 -10
- package/src/download/ui/useFigureActions.ts +113 -0
- package/src/download/ui/useFigureDownload.tsx +191 -0
- package/src/ecosystem/core/sites.ts +0 -40
- package/src/ecosystem/core/types.ts +0 -10
- package/src/ir/core/irCommands.ts +2 -2
- package/src/ir/ui/IrAboutDialog.tsx +0 -13
- package/src/ir/ui/IrCanvas.tsx +8 -2
- package/src/ir/ui/IrShell.tsx +23 -25
- package/src/ir/ui/IrToolbar.tsx +36 -6
- package/src/ir/ui/index.ts +1 -0
- package/src/language/core/index.ts +2 -0
- package/src/language/core/languagePath.ts +78 -0
- package/src/locales/de.json +2 -4
- package/src/locales/en.json +2 -4
- package/src/locales/es.json +2 -4
- package/src/locales/fr.json +2 -4
- package/src/locales/it.json +2 -4
- package/src/overlay/ui/OverlayPanel.tsx +8 -2
- package/src/overlay/ui/overlayPanelStyles.ts +3 -0
- package/src/periodic/ui/ElementCell.tsx +34 -37
- package/src/periodic/ui/PeriodicTable.tsx +12 -17
- package/src/seo/core/alternates.ts +65 -0
- package/src/seo/core/index.ts +3 -0
- package/src/seo/core/noscript.ts +18 -2
- package/src/seo/core/pageMeta.ts +74 -3
- package/src/seo/core/pageProse.ts +146 -0
- package/src/seo/core/routeProblems.ts +111 -0
- package/src/seo/core/routes.ts +14 -0
- package/src/seo/core/siteFiles.ts +2 -1
- package/src/seo/vite/prerender.ts +30 -11
- package/lib/about/core/repository.d.ts +0 -14
- package/lib/about/core/repository.d.ts.map +0 -1
- package/lib/about/core/repository.js +0 -21
- package/lib/about/core/repository.js.map +0 -1
- package/lib/download/core/exportStyles.d.ts +0 -22
- package/lib/download/core/exportStyles.d.ts.map +0 -1
- package/lib/download/core/exportStyles.js +0 -19
- package/lib/download/core/exportStyles.js.map +0 -1
- package/lib/download/core/imageResolution.d.ts +0 -88
- package/lib/download/core/imageResolution.d.ts.map +0 -1
- package/lib/download/core/imageResolution.js +0 -77
- package/lib/download/core/imageResolution.js.map +0 -1
- package/lib/download/core/pictureExport.d.ts +0 -93
- package/lib/download/core/pictureExport.d.ts.map +0 -1
- package/lib/download/core/pictureExport.js +0 -116
- package/lib/download/core/pictureExport.js.map +0 -1
- package/lib/download/ui/ExportDialogFrame.d.ts +0 -46
- package/lib/download/ui/ExportDialogFrame.d.ts.map +0 -1
- package/lib/download/ui/ExportDialogFrame.js +0 -24
- package/lib/download/ui/ExportDialogFrame.js.map +0 -1
- package/lib/download/ui/ExportImageDialog.d.ts +0 -47
- package/lib/download/ui/ExportImageDialog.d.ts.map +0 -1
- package/lib/download/ui/ExportImageDialog.js +0 -25
- package/lib/download/ui/ExportImageDialog.js.map +0 -1
- package/lib/download/ui/ExportNameField.d.ts +0 -29
- package/lib/download/ui/ExportNameField.d.ts.map +0 -1
- package/lib/download/ui/ExportNameField.js +0 -99
- package/lib/download/ui/ExportNameField.js.map +0 -1
- package/lib/download/ui/ExportPictureSection.d.ts +0 -38
- package/lib/download/ui/ExportPictureSection.d.ts.map +0 -1
- package/lib/download/ui/ExportPictureSection.js +0 -48
- package/lib/download/ui/ExportPictureSection.js.map +0 -1
- package/lib/download/ui/useDrawingBox.d.ts +0 -23
- package/lib/download/ui/useDrawingBox.d.ts.map +0 -1
- package/lib/download/ui/useDrawingBox.js +0 -21
- package/lib/download/ui/useDrawingBox.js.map +0 -1
- package/src/about/core/repository.ts +0 -22
- package/src/download/core/exportStyles.ts +0 -20
- package/src/download/core/imageResolution.ts +0 -118
- package/src/download/core/pictureExport.ts +0 -207
- package/src/download/ui/ExportDialogFrame.tsx +0 -86
- package/src/download/ui/ExportImageDialog.tsx +0 -91
- package/src/download/ui/ExportNameField.tsx +0 -148
- package/src/download/ui/ExportPictureSection.tsx +0 -142
- package/src/download/ui/useDrawingBox.ts +0 -37
package/src/about/core/about.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { providers } from './providers.ts';
|
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* What a site says about itself: the one page a visitor opens to find out what
|
|
13
|
-
* the tool is,
|
|
13
|
+
* the tool is, who provides it, and what it stands on.
|
|
14
14
|
*
|
|
15
15
|
* Every field is content, never markup. A site writes this record and the page
|
|
16
16
|
* is drawn from it, which is what keeps fourteen About pages in one order and
|
|
@@ -53,35 +53,12 @@ export interface AboutContent {
|
|
|
53
53
|
* @default undefined
|
|
54
54
|
*/
|
|
55
55
|
providedBy?: readonly ProviderId[];
|
|
56
|
-
/**
|
|
57
|
-
* Licence the site itself is published under.
|
|
58
|
-
* @default 'MIT'
|
|
59
|
-
*/
|
|
60
|
-
license?: string;
|
|
61
|
-
/**
|
|
62
|
-
* Where the sources live.
|
|
63
|
-
* @default the repository of the ECOSYSTEM_SITES record
|
|
64
|
-
*/
|
|
65
|
-
repository?: string;
|
|
66
|
-
/**
|
|
67
|
-
* Whether a visitor can open that repository. A site naming a repository of
|
|
68
|
-
* its own says so here too, since the family's record then describes another
|
|
69
|
-
* one.
|
|
70
|
-
* @default the `publicRepository` of the ECOSYSTEM_SITES record
|
|
71
|
-
*/
|
|
72
|
-
publicRepository?: boolean;
|
|
73
56
|
/**
|
|
74
57
|
* Which build is running, from `react-cheminfo/build-info` — never written
|
|
75
58
|
* by hand, which is what keeps it true after the next release.
|
|
76
59
|
* @default undefined — the site's build does not publish one
|
|
77
60
|
*/
|
|
78
61
|
build?: BuildInfo;
|
|
79
|
-
/**
|
|
80
|
-
* Where a problem is reported: an address a visitor can actually open, so a
|
|
81
|
-
* site whose sources are private names one of its own or says nothing.
|
|
82
|
-
* @default the repository's /issues, and none at all when it is private
|
|
83
|
-
*/
|
|
84
|
-
issues?: string;
|
|
85
62
|
}
|
|
86
63
|
|
|
87
64
|
/** One person who made a site. */
|
|
@@ -114,14 +91,8 @@ export interface ResolvedAbout {
|
|
|
114
91
|
people: readonly AboutPerson[];
|
|
115
92
|
/** The institutions providing the site, empty when the site names none. */
|
|
116
93
|
providedBy: ProviderEntry[];
|
|
117
|
-
license: string;
|
|
118
|
-
repository: string;
|
|
119
|
-
/** Whether a visitor can open the repository, and so whether it is named. */
|
|
120
|
-
publicRepository: boolean;
|
|
121
94
|
/** Which build is running, or `undefined` when the site does not say. */
|
|
122
95
|
build: BuildInfo | undefined;
|
|
123
|
-
/** Where a problem is reported, or `undefined` when there is nowhere open. */
|
|
124
|
-
issues: string | undefined;
|
|
125
96
|
}
|
|
126
97
|
|
|
127
98
|
/**
|
|
@@ -137,10 +108,6 @@ export function resolveAbout(content: AboutContent): ResolvedAbout {
|
|
|
137
108
|
typeof content.siteId === 'string'
|
|
138
109
|
? siteById(content.siteId)
|
|
139
110
|
: content.siteId;
|
|
140
|
-
const repository = content.repository ?? site.repository;
|
|
141
|
-
const publicRepository =
|
|
142
|
-
content.publicRepository ?? site.publicRepository ?? false;
|
|
143
|
-
|
|
144
111
|
return {
|
|
145
112
|
site,
|
|
146
113
|
what: content.what,
|
|
@@ -150,17 +117,7 @@ export function resolveAbout(content: AboutContent): ResolvedAbout {
|
|
|
150
117
|
cite: content.cite ?? [],
|
|
151
118
|
people: content.people ?? [],
|
|
152
119
|
providedBy: providers(content.providedBy ?? []),
|
|
153
|
-
license: content.license ?? DEFAULT_LICENSE,
|
|
154
|
-
repository,
|
|
155
|
-
publicRepository,
|
|
156
120
|
build: content.build,
|
|
157
|
-
// A tracker behind a private repository answers 404 to every visitor, so
|
|
158
|
-
// a site that names none of its own asks for a report nowhere.
|
|
159
|
-
issues:
|
|
160
|
-
content.issues ??
|
|
161
|
-
(publicRepository
|
|
162
|
-
? `${withoutTrailingSlash(repository)}/issues`
|
|
163
|
-
: undefined),
|
|
164
121
|
};
|
|
165
122
|
}
|
|
166
123
|
|
|
@@ -222,16 +179,9 @@ export function aboutProblems(content: AboutContent): string[] {
|
|
|
222
179
|
return problems;
|
|
223
180
|
}
|
|
224
181
|
|
|
225
|
-
/** What a site is published under unless it says otherwise. */
|
|
226
|
-
const DEFAULT_LICENSE = 'MIT';
|
|
227
|
-
|
|
228
182
|
const WHAT_LIMIT = 160;
|
|
229
183
|
const CAN_MIN = 3;
|
|
230
184
|
const CAN_MAX = 6;
|
|
231
185
|
const CAN_LINE_LIMIT = 90;
|
|
232
186
|
const PARAGRAPH_MAX = 2;
|
|
233
187
|
const PARAGRAPH_LIMIT = 400;
|
|
234
|
-
|
|
235
|
-
function withoutTrailingSlash(url: string): string {
|
|
236
|
-
return url.endsWith('/') ? url.slice(0, -1) : url;
|
|
237
|
-
}
|
package/src/about/core/index.ts
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
import type { CSSProperties, ReactElement
|
|
1
|
+
import type { CSSProperties, ReactElement } from 'react';
|
|
2
2
|
|
|
3
3
|
import type { BuildInfo } from '../../build/core/buildInfo.ts';
|
|
4
4
|
import { formatBuiltAt, shortCommit } from '../../build/core/buildInfo.ts';
|
|
5
5
|
import { useChromeT } from '../../i18n/ui/useT.ts';
|
|
6
|
-
import { githubSources } from '../core/repository.ts';
|
|
7
6
|
|
|
8
7
|
export interface AboutBuildProps {
|
|
9
8
|
/** What the build published about itself. */
|
|
10
9
|
build: BuildInfo;
|
|
11
|
-
/** Where the sources live, which is what the version and commit link into. */
|
|
12
|
-
repository: string;
|
|
13
10
|
}
|
|
14
11
|
|
|
15
12
|
/**
|
|
@@ -17,23 +14,21 @@ export interface AboutBuildProps {
|
|
|
17
14
|
*
|
|
18
15
|
* A report of something going wrong is worth answering only when we know what
|
|
19
16
|
* was running. The version itself is in the hero, where a reader is asked to
|
|
20
|
-
* quote it from; this line carries the rest,
|
|
21
|
-
*
|
|
22
|
-
* that shows it.
|
|
17
|
+
* quote it from; this line carries the rest, so a report can name the exact
|
|
18
|
+
* build the problem was seen on.
|
|
23
19
|
* @param props - See {@link AboutBuildProps}.
|
|
24
20
|
* @returns The line.
|
|
25
21
|
*/
|
|
26
22
|
export function AboutBuild(props: AboutBuildProps): ReactElement {
|
|
27
|
-
const { build
|
|
23
|
+
const { build } = props;
|
|
28
24
|
const t = useChromeT();
|
|
29
|
-
const sources = githubSources(repository);
|
|
30
25
|
const builtAt = formatBuiltAt(build.builtAt);
|
|
31
26
|
if (build.commit === undefined) {
|
|
32
27
|
return <p style={PARAGRAPH_STYLE}>{t('about.built', { builtAt })}</p>;
|
|
33
28
|
}
|
|
34
29
|
|
|
35
|
-
// The commit
|
|
36
|
-
//
|
|
30
|
+
// The commit sits inside a sentence whose word order is the translator's,
|
|
31
|
+
// so the message names where it goes and is split there.
|
|
37
32
|
const [before = '', after = ''] = t('about.builtFromCommit', {
|
|
38
33
|
builtAt,
|
|
39
34
|
}).split('{commit}');
|
|
@@ -41,36 +36,14 @@ export function AboutBuild(props: AboutBuildProps): ReactElement {
|
|
|
41
36
|
return (
|
|
42
37
|
<p style={PARAGRAPH_STYLE}>
|
|
43
38
|
{before}
|
|
44
|
-
<
|
|
45
|
-
href={
|
|
46
|
-
sources === undefined
|
|
47
|
-
? undefined
|
|
48
|
-
: `${sources}/commit/${build.commit}`
|
|
49
|
-
}
|
|
50
|
-
>
|
|
51
|
-
{shortCommit(build.commit)}
|
|
52
|
-
</Reference>
|
|
39
|
+
<code style={CODE_STYLE}>{shortCommit(build.commit)}</code>
|
|
53
40
|
{after}
|
|
54
41
|
</p>
|
|
55
42
|
);
|
|
56
43
|
}
|
|
57
44
|
|
|
58
|
-
function Reference(props: {
|
|
59
|
-
href: string | undefined;
|
|
60
|
-
children: ReactNode;
|
|
61
|
-
}): ReactElement {
|
|
62
|
-
const { href, children } = props;
|
|
63
|
-
if (href === undefined) return <code style={CODE_STYLE}>{children}</code>;
|
|
64
|
-
|
|
65
|
-
return (
|
|
66
|
-
<a href={href} target="_blank" rel="noopener noreferrer" style={LINK_STYLE}>
|
|
67
|
-
<code style={CODE_STYLE}>{children}</code>
|
|
68
|
-
</a>
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
45
|
const PARAGRAPH_STYLE = {
|
|
73
|
-
margin:
|
|
46
|
+
margin: 0,
|
|
74
47
|
color: 'var(--text-muted)',
|
|
75
48
|
fontSize: 13,
|
|
76
49
|
} as const satisfies CSSProperties;
|
|
@@ -79,5 +52,3 @@ const CODE_STYLE = {
|
|
|
79
52
|
fontFamily: 'var(--font-mono, ui-monospace, monospace)',
|
|
80
53
|
fontSize: 13,
|
|
81
54
|
} as const satisfies CSSProperties;
|
|
82
|
-
|
|
83
|
-
const LINK_STYLE = { color: 'var(--accent)' } as const satisfies CSSProperties;
|
|
@@ -47,8 +47,8 @@ export interface AboutPageProps {
|
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
49
|
* The About page of a site of the family: what the tool is, who provides it,
|
|
50
|
-
* what a visitor can do with it, what it is built on, how to cite it
|
|
51
|
-
*
|
|
50
|
+
* what a visitor can do with it, what it is built on, and how to cite it —
|
|
51
|
+
* always in that order.
|
|
52
52
|
*
|
|
53
53
|
* The order is the point. A reader who has read one of our About pages knows
|
|
54
54
|
* where the credits are on the other thirteen, and a site that writes its own
|
|
@@ -83,11 +83,7 @@ export function AboutPage(props: AboutPageProps): ReactElement {
|
|
|
83
83
|
</p>
|
|
84
84
|
<p style={WHAT_STYLE}>{about.what}</p>
|
|
85
85
|
</div>
|
|
86
|
-
<AboutVersion
|
|
87
|
-
build={about.build}
|
|
88
|
-
repository={about.repository}
|
|
89
|
-
publicRepository={about.publicRepository}
|
|
90
|
-
/>
|
|
86
|
+
<AboutVersion build={about.build} />
|
|
91
87
|
</header>
|
|
92
88
|
|
|
93
89
|
{about.people.length === 0 && about.providedBy.length === 0 ? null : (
|
|
@@ -133,68 +129,18 @@ export function AboutPage(props: AboutPageProps): ReactElement {
|
|
|
133
129
|
)}
|
|
134
130
|
|
|
135
131
|
{/*
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
The version stays in the hero, unlinked, so a report still names a build.
|
|
132
|
+
The build the reader has open, last and under no heading: it is what a
|
|
133
|
+
report has to name, not something anybody came to the page to read.
|
|
139
134
|
*/}
|
|
140
|
-
{
|
|
141
|
-
<AboutSection
|
|
142
|
-
|
|
143
|
-
className="about-licence"
|
|
144
|
-
>
|
|
145
|
-
<p style={FIRST_PARAGRAPH_STYLE}>
|
|
146
|
-
{around(
|
|
147
|
-
t('about.licence', { license: about.license }),
|
|
148
|
-
'sources',
|
|
149
|
-
<ExternalLink key="sources" href={about.repository} />,
|
|
150
|
-
)}
|
|
151
|
-
</p>
|
|
152
|
-
{about.build === undefined ? null : (
|
|
153
|
-
<AboutBuild build={about.build} repository={about.repository} />
|
|
154
|
-
)}
|
|
155
|
-
</AboutSection>
|
|
156
|
-
)}
|
|
157
|
-
|
|
158
|
-
{/*
|
|
159
|
-
Asking for a report is worth nothing without somewhere to send it, and
|
|
160
|
-
the tracker of a private repository answers 404 to every visitor.
|
|
161
|
-
*/}
|
|
162
|
-
{about.issues === undefined ? null : (
|
|
163
|
-
<AboutSection title={t('about.foundAProblem')} className="about-issues">
|
|
164
|
-
<p style={FIRST_PARAGRAPH_STYLE}>
|
|
165
|
-
{around(
|
|
166
|
-
t('about.reportIt'),
|
|
167
|
-
'tracker',
|
|
168
|
-
<ExternalLink key="tracker" href={about.issues} />,
|
|
169
|
-
)}
|
|
170
|
-
</p>
|
|
135
|
+
{about.build === undefined ? null : (
|
|
136
|
+
<AboutSection className="about-build">
|
|
137
|
+
<AboutBuild build={about.build} />
|
|
171
138
|
</AboutSection>
|
|
172
139
|
)}
|
|
173
140
|
</div>
|
|
174
141
|
);
|
|
175
142
|
}
|
|
176
143
|
|
|
177
|
-
// A link sits inside a sentence whose word order is the translator's, so the
|
|
178
|
-
// message names where it goes with a placeholder and is split there.
|
|
179
|
-
function around(
|
|
180
|
-
message: string,
|
|
181
|
-
placeholder: string,
|
|
182
|
-
link: ReactNode,
|
|
183
|
-
): ReactNode[] {
|
|
184
|
-
const [before = '', after = ''] = message.split(`{${placeholder}}`);
|
|
185
|
-
return [before, link, after];
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
function ExternalLink(props: { href: string }): ReactElement {
|
|
189
|
-
const { href } = props;
|
|
190
|
-
|
|
191
|
-
return (
|
|
192
|
-
<a href={href} target="_blank" rel="noopener noreferrer" style={LINK_STYLE}>
|
|
193
|
-
{href.replace(/^https?:\/\//, '')}
|
|
194
|
-
</a>
|
|
195
|
-
);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
144
|
const PAGE_STYLE = {
|
|
199
145
|
display: 'flex',
|
|
200
146
|
flexDirection: 'column',
|
|
@@ -250,5 +196,3 @@ const FIRST_PARAGRAPH_STYLE = {
|
|
|
250
196
|
const PARAGRAPH_STYLE = {
|
|
251
197
|
margin: '8px 0 0',
|
|
252
198
|
} as const satisfies CSSProperties;
|
|
253
|
-
|
|
254
|
-
const LINK_STYLE = { color: 'var(--accent)' } as const satisfies CSSProperties;
|
|
@@ -14,17 +14,11 @@ import {
|
|
|
14
14
|
buildLabel,
|
|
15
15
|
buildStamp,
|
|
16
16
|
buildSummary,
|
|
17
|
-
releasedVersion,
|
|
18
17
|
} from '../../build/core/buildInfo.ts';
|
|
19
|
-
import { githubSources } from '../core/repository.ts';
|
|
20
18
|
|
|
21
19
|
export interface AboutVersionProps {
|
|
22
20
|
/** What the build published about itself, or `undefined` when it published none. */
|
|
23
21
|
build: BuildInfo | undefined;
|
|
24
|
-
/** Where the sources live, which is what the badge links into. */
|
|
25
|
-
repository: string;
|
|
26
|
-
/** Whether a visitor can open that repository, and so whether it is linked. */
|
|
27
|
-
publicRepository: boolean;
|
|
28
22
|
}
|
|
29
23
|
|
|
30
24
|
/**
|
|
@@ -34,53 +28,24 @@ export interface AboutVersionProps {
|
|
|
34
28
|
* @returns The badge, or `null` when the build says nothing worth showing.
|
|
35
29
|
*/
|
|
36
30
|
export function AboutVersion(props: AboutVersionProps): ReactElement | null {
|
|
37
|
-
const { build
|
|
31
|
+
const { build } = props;
|
|
38
32
|
const label = buildLabel(build);
|
|
39
33
|
if (build === undefined || label === undefined) return null;
|
|
40
|
-
const href = publicRepository ? addressOf(build, repository) : undefined;
|
|
41
|
-
const summary = buildSummary(build);
|
|
42
34
|
// The instant belongs on the badge rather than in its hover: a version
|
|
43
35
|
// nobody can date says nothing about how old the page they read is.
|
|
44
36
|
const badge = `${label} · ${buildStamp(build.builtAt)}`;
|
|
45
|
-
if (href === undefined) {
|
|
46
|
-
return (
|
|
47
|
-
<span style={BADGE_STYLE} className="about-version" title={summary}>
|
|
48
|
-
{badge}
|
|
49
|
-
</span>
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
37
|
|
|
53
38
|
return (
|
|
54
|
-
<
|
|
39
|
+
<span
|
|
40
|
+
style={BADGE_STYLE}
|
|
55
41
|
className="about-version"
|
|
56
|
-
|
|
57
|
-
title={summary}
|
|
58
|
-
target="_blank"
|
|
59
|
-
rel="noopener noreferrer"
|
|
60
|
-
style={LINK_BADGE_STYLE}
|
|
42
|
+
title={buildSummary(build)}
|
|
61
43
|
>
|
|
62
44
|
{badge}
|
|
63
|
-
</
|
|
45
|
+
</span>
|
|
64
46
|
);
|
|
65
47
|
}
|
|
66
48
|
|
|
67
|
-
/**
|
|
68
|
-
* What the badge opens: the release it names, or the commit it was built from.
|
|
69
|
-
* @param build - What the build published about itself.
|
|
70
|
-
* @param repository - Where the sources live.
|
|
71
|
-
* @returns The address, or `undefined` when nothing inside the repository can
|
|
72
|
-
* be addressed.
|
|
73
|
-
*/
|
|
74
|
-
function addressOf(build: BuildInfo, repository: string): string | undefined {
|
|
75
|
-
const sources = githubSources(repository);
|
|
76
|
-
if (sources === undefined) return undefined;
|
|
77
|
-
const version = releasedVersion(build);
|
|
78
|
-
if (version !== undefined) return `${sources}/releases/tag/v${version}`;
|
|
79
|
-
return build.commit === undefined
|
|
80
|
-
? undefined
|
|
81
|
-
: `${sources}/commit/${build.commit}`;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
49
|
const BADGE_STYLE = {
|
|
85
50
|
flex: '0 0 auto',
|
|
86
51
|
fontFamily: 'var(--font-mono, ui-monospace, monospace)',
|
|
@@ -88,8 +53,3 @@ const BADGE_STYLE = {
|
|
|
88
53
|
color: 'var(--text-muted)',
|
|
89
54
|
whiteSpace: 'nowrap',
|
|
90
55
|
} as const satisfies CSSProperties;
|
|
91
|
-
|
|
92
|
-
const LINK_BADGE_STYLE = {
|
|
93
|
-
...BADGE_STYLE,
|
|
94
|
-
color: 'var(--accent)',
|
|
95
|
-
} as const satisfies CSSProperties;
|
|
@@ -51,31 +51,6 @@ export {
|
|
|
51
51
|
} from './figureTarget.ts';
|
|
52
52
|
export { sanitizeFileName } from './sanitizeFileName.ts';
|
|
53
53
|
|
|
54
|
-
export {
|
|
55
|
-
exportButtonsStyle,
|
|
56
|
-
exportNoteStyle,
|
|
57
|
-
exportSectionStyle,
|
|
58
|
-
} from './exportStyles.ts';
|
|
59
|
-
export type {
|
|
60
|
-
ImageResolution,
|
|
61
|
-
ImageResolutionId,
|
|
62
|
-
ImageSize,
|
|
63
|
-
} from './imageResolution.ts';
|
|
64
|
-
export {
|
|
65
|
-
DEFAULT_IMAGE_RESOLUTION,
|
|
66
|
-
IMAGE_RESOLUTIONS,
|
|
67
|
-
formatImageSize,
|
|
68
|
-
imageResolution,
|
|
69
|
-
imageSize,
|
|
70
|
-
} from './imageResolution.ts';
|
|
71
|
-
export type { PictureFrame, PictureOptions } from './pictureExport.ts';
|
|
72
|
-
export {
|
|
73
|
-
PICTURE_PADDING,
|
|
74
|
-
copyPicture,
|
|
75
|
-
pictureSize,
|
|
76
|
-
savePngPicture,
|
|
77
|
-
saveSvgPicture,
|
|
78
|
-
} from './pictureExport.ts';
|
|
79
54
|
export { drawingIn, stackDrawings } from './stackedDrawing.ts';
|
|
80
55
|
export type { SvgBox } from './svgBounds.ts';
|
|
81
56
|
export { CONTENT_ATTRIBUTE, contentBox, elementBox } from './svgBounds.ts';
|
|
@@ -1,74 +1,20 @@
|
|
|
1
1
|
import type { IconName } from '@blueprintjs/core';
|
|
2
2
|
import { PopoverNext } from '@blueprintjs/core';
|
|
3
3
|
import type { ReactElement } from 'react';
|
|
4
|
-
import { useState } from 'react';
|
|
5
4
|
|
|
6
5
|
import { useChromeT } from '../../i18n/ui/useT.ts';
|
|
7
6
|
import { OverlayIconButton } from '../../overlay/ui/OverlayIconButton.tsx';
|
|
8
|
-
import type { FigureFormat } from '../core/downloadFigure.ts';
|
|
9
|
-
import { downloadFigure } from '../core/downloadFigure.ts';
|
|
10
|
-
import type { FigureLayout } from '../core/figureLayout.ts';
|
|
11
|
-
import { figureLayoutRedraws, figureLayoutSize } from '../core/figureLayout.ts';
|
|
12
|
-
import type { FigurePixels } from '../core/figureScale.ts';
|
|
13
|
-
import {
|
|
14
|
-
DEFAULT_FIGURE_SCALE,
|
|
15
|
-
FIGURE_SCALES,
|
|
16
|
-
defaultFigureScale,
|
|
17
|
-
} from '../core/figureScale.ts';
|
|
18
|
-
import { figureSize } from '../core/figureTarget.ts';
|
|
19
7
|
|
|
20
|
-
import {
|
|
21
|
-
import
|
|
22
|
-
import { useFigureRedraw } from './useFigureRedraw.tsx';
|
|
8
|
+
import type { FigureDownloadOptions } from './useFigureDownload.tsx';
|
|
9
|
+
import { useFigureDownload } from './useFigureDownload.tsx';
|
|
23
10
|
|
|
24
11
|
/** What {@link FigureDownload} needs. */
|
|
25
|
-
export interface FigureDownloadProps {
|
|
26
|
-
/**
|
|
27
|
-
* The `id` of the box the figure is mounted in. Everything drawn inside it
|
|
28
|
-
* is saved — sixteen charts of a pair grid as readily as one scatter plot —
|
|
29
|
-
* and the controls floating over it are left behind.
|
|
30
|
-
*/
|
|
31
|
-
targetId: string;
|
|
32
|
-
/**
|
|
33
|
-
* What the saved file is called, without its extension. Name it after the
|
|
34
|
-
* data rather than after the tool: a reader with four of these in a
|
|
35
|
-
* downloads folder cannot tell four `figure.png` apart.
|
|
36
|
-
* @default 'figure'
|
|
37
|
-
*/
|
|
38
|
-
fileName?: string;
|
|
39
|
-
/**
|
|
40
|
-
* The format it opens on.
|
|
41
|
-
* @default 'png'
|
|
42
|
-
*/
|
|
43
|
-
defaultFormat?: FigureFormat;
|
|
44
|
-
/**
|
|
45
|
-
* The resolution a PNG opens on, as a multiple of the figure on screen. An
|
|
46
|
-
* SVG opens at 1×, the size it has on screen, and each format keeps the
|
|
47
|
-
* multiple the reader last picked for it.
|
|
48
|
-
* @default 2
|
|
49
|
-
*/
|
|
50
|
-
defaultScale?: number;
|
|
51
|
-
/**
|
|
52
|
-
* The resolutions offered.
|
|
53
|
-
* @default [1, 2, 3, 4]
|
|
54
|
-
*/
|
|
55
|
-
scales?: readonly number[];
|
|
56
|
-
/**
|
|
57
|
-
* What is painted under the figure. `transparent` leaves it unpainted, for a
|
|
58
|
-
* figure going onto a coloured slide.
|
|
59
|
-
* @default the surface the figure is drawn on
|
|
60
|
-
*/
|
|
61
|
-
background?: string;
|
|
12
|
+
export interface FigureDownloadProps extends FigureDownloadOptions {
|
|
62
13
|
/**
|
|
63
14
|
* What the glyph is called, for the pointer and for a screen reader.
|
|
64
15
|
* @default the chrome's own line, in the language of the page
|
|
65
16
|
*/
|
|
66
17
|
label?: string;
|
|
67
|
-
/**
|
|
68
|
-
* What the panel behind it is called.
|
|
69
|
-
* @default the chrome's own line, in the language of the page
|
|
70
|
-
*/
|
|
71
|
-
title?: string;
|
|
72
18
|
/**
|
|
73
19
|
* Its glyph.
|
|
74
20
|
* @default 'download'
|
|
@@ -79,20 +25,11 @@ export interface FigureDownloadProps {
|
|
|
79
25
|
* @default undefined
|
|
80
26
|
*/
|
|
81
27
|
testId?: string;
|
|
82
|
-
/**
|
|
83
|
-
* Draws the figure at a size, for a file. When it is given the panel offers
|
|
84
|
-
* a size — as shown, 4:3, 16:9, a journal column, or typed — and a figure
|
|
85
|
-
* saved at a size other than its own is drawn again at that size, off the
|
|
86
|
-
* page, so its axes and labels are laid out for the new shape rather than
|
|
87
|
-
* stretched into it. Draw exactly what is on screen, with the same data,
|
|
88
|
-
* zoom and colours; only the box changes.
|
|
89
|
-
* @default undefined — the figure is saved at the size it has on screen
|
|
90
|
-
*/
|
|
91
|
-
renderFigure?: FigureRenderer;
|
|
92
28
|
}
|
|
93
29
|
|
|
94
30
|
/**
|
|
95
|
-
* The glyph that takes the figure off the page as a file
|
|
31
|
+
* The glyph that takes the figure off the page, as a file or onto the
|
|
32
|
+
* clipboard.
|
|
96
33
|
*
|
|
97
34
|
* It works from the `id` of the box the figure is mounted in rather than from
|
|
98
35
|
* the figure itself, so the control is free to sit in the bar above the
|
|
@@ -112,97 +49,23 @@ export interface FigureDownloadProps {
|
|
|
112
49
|
* @returns The glyph and its panel.
|
|
113
50
|
*/
|
|
114
51
|
export function FigureDownload(props: FigureDownloadProps): ReactElement {
|
|
115
|
-
const {
|
|
116
|
-
const { defaultFormat = 'png', defaultScale = DEFAULT_FIGURE_SCALE } = props;
|
|
117
|
-
const { label, title } = props;
|
|
118
|
-
const { icon = 'download', testId, renderFigure } = props;
|
|
119
|
-
|
|
52
|
+
const { label, icon = 'download', testId, ...options } = props;
|
|
120
53
|
const t = useChromeT();
|
|
121
|
-
const
|
|
122
|
-
const [format, setFormat] = useState<FigureFormat>(defaultFormat);
|
|
123
|
-
const [picked, setPicked] = useState<Record<FigureFormat, number>>(() => ({
|
|
124
|
-
png: defaultScale,
|
|
125
|
-
svg: defaultFigureScale('svg'),
|
|
126
|
-
}));
|
|
127
|
-
const scale = picked[format];
|
|
128
|
-
const [size, setSize] = useState<FigurePixels | null>(null);
|
|
129
|
-
const [failure, setFailure] = useState<string | null>(null);
|
|
130
|
-
const [saving, setSaving] = useState(false);
|
|
131
|
-
const [layout, setLayout] = useState<FigureLayout>('screen');
|
|
132
|
-
const [custom, setCustom] = useState<FigurePixels | null>(null);
|
|
133
|
-
const { redraw, portal } = useFigureRedraw(renderFigure);
|
|
134
|
-
|
|
135
|
-
// The panel is held open from here rather than left to itself, because the
|
|
136
|
-
// figure has to be measured at the moment it opens: its size is what the
|
|
137
|
-
// panel writes out, and reading a bounding box on every render would cost a
|
|
138
|
-
// layout pass on a bar that is re-rendered on every pointer move.
|
|
139
|
-
function interact(next: boolean): void {
|
|
140
|
-
setOpen(next);
|
|
141
|
-
if (!next) return;
|
|
142
|
-
setSize(figureSize(targetId));
|
|
143
|
-
setFailure(null);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
async function save(): Promise<void> {
|
|
147
|
-
setSaving(true);
|
|
148
|
-
try {
|
|
149
|
-
const options = { format, scale, fileName, background };
|
|
150
|
-
if (
|
|
151
|
-
renderFigure !== undefined &&
|
|
152
|
-
size !== null &&
|
|
153
|
-
figureLayoutRedraws(layout, size, custom ?? size)
|
|
154
|
-
) {
|
|
155
|
-
const drawn = figureLayoutSize(layout, size, custom ?? size);
|
|
156
|
-
await redraw(targetId, drawn, (box) => downloadFigure(box, options));
|
|
157
|
-
} else {
|
|
158
|
-
await downloadFigure(targetId, options);
|
|
159
|
-
}
|
|
160
|
-
setFailure(null);
|
|
161
|
-
} catch (error) {
|
|
162
|
-
setFailure(error instanceof Error ? error.message : String(error));
|
|
163
|
-
} finally {
|
|
164
|
-
setSaving(false);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
54
|
+
const { isOpen, setOpen, panel, format, portal } = useFigureDownload(options);
|
|
167
55
|
|
|
168
56
|
return (
|
|
169
57
|
<>
|
|
170
58
|
<PopoverNext
|
|
171
|
-
isOpen={
|
|
59
|
+
isOpen={isOpen}
|
|
172
60
|
placement="bottom-end"
|
|
173
|
-
onInteraction={
|
|
174
|
-
content={
|
|
175
|
-
<FigureDownloadPanel
|
|
176
|
-
title={title ?? t('download.saveFigure')}
|
|
177
|
-
format={format}
|
|
178
|
-
scale={scale}
|
|
179
|
-
scales={scales}
|
|
180
|
-
size={size}
|
|
181
|
-
failure={failure}
|
|
182
|
-
saving={saving}
|
|
183
|
-
onFormatChange={setFormat}
|
|
184
|
-
onScaleChange={(next) =>
|
|
185
|
-
setPicked((current) => ({ ...current, [format]: next }))
|
|
186
|
-
}
|
|
187
|
-
onSave={() => void save()}
|
|
188
|
-
sizing={
|
|
189
|
-
renderFigure === undefined
|
|
190
|
-
? undefined
|
|
191
|
-
: {
|
|
192
|
-
layout,
|
|
193
|
-
custom,
|
|
194
|
-
onLayoutChange: setLayout,
|
|
195
|
-
onCustomChange: setCustom,
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
/>
|
|
199
|
-
}
|
|
61
|
+
onInteraction={setOpen}
|
|
62
|
+
content={panel}
|
|
200
63
|
>
|
|
201
64
|
<OverlayIconButton
|
|
202
65
|
icon={icon}
|
|
203
66
|
label={label ?? t('download.saveThisFigure')}
|
|
204
67
|
value={format.toUpperCase()}
|
|
205
|
-
active={
|
|
68
|
+
active={isOpen}
|
|
206
69
|
testId={testId}
|
|
207
70
|
opensMenu
|
|
208
71
|
/>
|