react-cheminfo 0.53.0 → 0.55.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 +14 -0
- package/lib/chrome/ui/SiteHeader.d.ts +17 -1
- package/lib/chrome/ui/SiteHeader.d.ts.map +1 -1
- package/lib/chrome/ui/SiteHeader.js +9 -2
- package/lib/chrome/ui/SiteHeader.js.map +1 -1
- package/lib/contact/core/contactUrl.d.ts +35 -0
- package/lib/contact/core/contactUrl.d.ts.map +1 -0
- package/lib/contact/core/contactUrl.js +33 -0
- package/lib/contact/core/contactUrl.js.map +1 -0
- package/lib/contact/core/index.d.ts +3 -0
- package/lib/contact/core/index.d.ts.map +1 -0
- package/lib/contact/core/index.js +2 -0
- package/lib/contact/core/index.js.map +1 -0
- package/lib/contact/ui/ContactButton.d.ts +41 -0
- package/lib/contact/ui/ContactButton.d.ts.map +1 -0
- package/lib/contact/ui/ContactButton.js +29 -0
- package/lib/contact/ui/ContactButton.js.map +1 -0
- package/lib/contact/ui/index.d.ts +3 -0
- package/lib/contact/ui/index.d.ts.map +1 -0
- package/lib/contact/ui/index.js +2 -0
- package/lib/contact/ui/index.js.map +1 -0
- package/lib/core.d.ts +1 -0
- package/lib/core.d.ts.map +1 -1
- package/lib/core.js +1 -0
- package/lib/core.js.map +1 -1
- package/lib/i18n/core/chromeCatalog.d.ts +1 -1
- package/lib/i18n/core/chromeCatalog.d.ts.map +1 -1
- package/lib/i18n/core/index.d.ts +2 -0
- package/lib/i18n/core/index.d.ts.map +1 -1
- package/lib/i18n/core/index.js +1 -0
- package/lib/i18n/core/index.js.map +1 -1
- package/lib/i18n/core/messageCatalog.d.ts +10 -0
- package/lib/i18n/core/messageCatalog.d.ts.map +1 -1
- package/lib/i18n/core/messageCatalog.js +12 -0
- package/lib/i18n/core/messageCatalog.js.map +1 -1
- package/lib/i18n/core/translate.d.ts +35 -0
- package/lib/i18n/core/translate.d.ts.map +1 -0
- package/lib/i18n/core/translate.js +27 -0
- package/lib/i18n/core/translate.js.map +1 -0
- package/lib/i18n/ui/useT.d.ts +2 -12
- package/lib/i18n/ui/useT.d.ts.map +1 -1
- package/lib/i18n/ui/useT.js +2 -8
- package/lib/i18n/ui/useT.js.map +1 -1
- package/lib/i18n/vite/index.d.ts +3 -0
- package/lib/i18n/vite/index.d.ts.map +1 -0
- package/lib/i18n/vite/index.js +2 -0
- package/lib/i18n/vite/index.js.map +1 -0
- package/lib/i18n/vite/localeCatalog.d.ts +70 -0
- package/lib/i18n/vite/localeCatalog.d.ts.map +1 -0
- package/lib/i18n/vite/localeCatalog.js +80 -0
- package/lib/i18n/vite/localeCatalog.js.map +1 -0
- package/lib/locales/de.json +2 -0
- package/lib/locales/en.json +2 -0
- package/lib/locales/es.json +2 -0
- package/lib/locales/fr.json +2 -0
- package/lib/locales/it.json +2 -0
- package/lib/ui.d.ts +1 -0
- package/lib/ui.d.ts.map +1 -1
- package/lib/ui.js +1 -0
- package/lib/ui.js.map +1 -1
- package/lib/vite.d.ts +1 -0
- package/lib/vite.d.ts.map +1 -1
- package/lib/vite.js +1 -0
- package/lib/vite.js.map +1 -1
- package/package.json +1 -1
- package/src/chrome/ui/SiteHeader.tsx +35 -3
- package/src/contact/core/contactUrl.ts +53 -0
- package/src/contact/core/index.ts +2 -0
- package/src/contact/ui/ContactButton.tsx +74 -0
- package/src/contact/ui/index.ts +2 -0
- package/src/core.ts +1 -0
- package/src/i18n/core/index.ts +2 -0
- package/src/i18n/core/messageCatalog.ts +13 -0
- package/src/i18n/core/translate.ts +51 -0
- package/src/i18n/ui/useT.ts +6 -29
- package/src/i18n/vite/index.ts +5 -0
- package/src/i18n/vite/localeCatalog.ts +121 -0
- package/src/locales/de.json +2 -0
- package/src/locales/en.json +2 -0
- package/src/locales/es.json +2 -0
- package/src/locales/fr.json +2 -0
- package/src/locales/it.json +2 -0
- package/src/ui.ts +1 -0
- package/src/vite.ts +1 -0
- package/styles/chrome.css +21 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { ReactElement } from 'react';
|
|
2
|
+
|
|
3
|
+
import { NavLink } from '../../chrome/ui/NavLink.tsx';
|
|
4
|
+
import { useLanguage } from '../../i18n/ui/useLanguage.ts';
|
|
5
|
+
import { useChromeT } from '../../i18n/ui/useT.ts';
|
|
6
|
+
import { contactFormUrl, contactUrl } from '../core/contactUrl.ts';
|
|
7
|
+
|
|
8
|
+
/** What the Contact entry of a header needs. */
|
|
9
|
+
export interface ContactButtonProps {
|
|
10
|
+
/** The site the reader writes about, written into the form. */
|
|
11
|
+
siteId: string;
|
|
12
|
+
/**
|
|
13
|
+
* Address of the form, with `{site}` and `{page}` where they are written.
|
|
14
|
+
* @default the family's form in the language of the page (`CONTACT_FORM_URLS`)
|
|
15
|
+
*/
|
|
16
|
+
formUrl?: string;
|
|
17
|
+
/**
|
|
18
|
+
* The page the reader is on, written into the form.
|
|
19
|
+
* @default the address of the current page
|
|
20
|
+
*/
|
|
21
|
+
page?: string;
|
|
22
|
+
/**
|
|
23
|
+
* What the entry reads. In a compact bar it is not written, but it stays what
|
|
24
|
+
* the pointer and a screen reader are told.
|
|
25
|
+
* @default the chrome's own word for it, in the language of the page
|
|
26
|
+
*/
|
|
27
|
+
label?: string;
|
|
28
|
+
/**
|
|
29
|
+
* What the pointer is told.
|
|
30
|
+
* @default the chrome's own sentence, in the language of the page
|
|
31
|
+
*/
|
|
32
|
+
title?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Class names added after the component's own.
|
|
35
|
+
* @default undefined
|
|
36
|
+
*/
|
|
37
|
+
className?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The Contact entry of a site header: it opens the family's contact form in a new tab,
|
|
42
|
+
* with the site and the page already filled in, so the reader only writes the message.
|
|
43
|
+
* The form is opened, never embedded, so nothing is loaded from it before the click.
|
|
44
|
+
* @param props - The site, and the form it opens.
|
|
45
|
+
* @returns The entry, or nothing while no form address is set.
|
|
46
|
+
*/
|
|
47
|
+
export function ContactButton(props: ContactButtonProps): ReactElement | null {
|
|
48
|
+
const {
|
|
49
|
+
siteId,
|
|
50
|
+
page = globalThis.location?.href ?? '',
|
|
51
|
+
label,
|
|
52
|
+
title,
|
|
53
|
+
className,
|
|
54
|
+
} = props;
|
|
55
|
+
const t = useChromeT();
|
|
56
|
+
const language = useLanguage();
|
|
57
|
+
const formUrl = props.formUrl ?? contactFormUrl(language);
|
|
58
|
+
|
|
59
|
+
if (formUrl === '') return null;
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<NavLink
|
|
63
|
+
item={{
|
|
64
|
+
id: 'contact',
|
|
65
|
+
label: label ?? t('chrome.contact'),
|
|
66
|
+
icon: 'chat',
|
|
67
|
+
href: contactUrl(formUrl, { site: siteId, page }),
|
|
68
|
+
external: true,
|
|
69
|
+
title: title ?? t('chrome.contactTitle'),
|
|
70
|
+
}}
|
|
71
|
+
className={className}
|
|
72
|
+
/>
|
|
73
|
+
);
|
|
74
|
+
}
|
package/src/core.ts
CHANGED
|
@@ -5,6 +5,7 @@ export * from './chart/core/index.ts';
|
|
|
5
5
|
export * from './citation/core/index.ts';
|
|
6
6
|
export * from './clipboard/core/index.ts';
|
|
7
7
|
export * from './color/core/index.ts';
|
|
8
|
+
export * from './contact/core/index.ts';
|
|
8
9
|
export * from './credits/core/index.ts';
|
|
9
10
|
export * from './delimited/core/index.ts';
|
|
10
11
|
export * from './download/core/index.ts';
|
package/src/i18n/core/index.ts
CHANGED
|
@@ -15,6 +15,8 @@ export type {
|
|
|
15
15
|
} from './messageCatalog.ts';
|
|
16
16
|
export { MessageCatalog } from './messageCatalog.ts';
|
|
17
17
|
export type { MessageValues } from './messageValues.ts';
|
|
18
|
+
export type { Translate } from './translate.ts';
|
|
19
|
+
export { catalogTranslate } from './translate.ts';
|
|
18
20
|
export type { ProsePiece } from './prose.ts';
|
|
19
21
|
export { splitProse } from './prose.ts';
|
|
20
22
|
export type { MessageSession } from './session.ts';
|
|
@@ -141,6 +141,19 @@ export class MessageCatalog<TKey extends string = string> {
|
|
|
141
141
|
return fill(message, values);
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Whether the catalog declares a key at all.
|
|
146
|
+
*
|
|
147
|
+
* English is the list of keys, so this is what a loop walking a numbered
|
|
148
|
+
* family of messages — `how.limits.p1`, `p2`, … — stops on, and what tells a
|
|
149
|
+
* page a section was never written from one left untranslated.
|
|
150
|
+
* @param key - Key to look for.
|
|
151
|
+
* @returns True when English carries it.
|
|
152
|
+
*/
|
|
153
|
+
public declares(key: string): boolean {
|
|
154
|
+
return ownMessage(this.source.messages, key) !== undefined;
|
|
155
|
+
}
|
|
156
|
+
|
|
144
157
|
/**
|
|
145
158
|
* The messages of a language, once they are in memory.
|
|
146
159
|
* @param language - Language asked for.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The formatter a catalog's text is read through, outside React.
|
|
3
|
+
*
|
|
4
|
+
* `useT` is this function with the page's language and a redraw wired to it;
|
|
5
|
+
* the build and a site's own tests need the same shape without either, so it
|
|
6
|
+
* lives here rather than in the hook. A site never writes its own: four of
|
|
7
|
+
* them had, each with a slightly different fallback.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { Language } from './languages.ts';
|
|
11
|
+
import type { LooseKey, MessageCatalog } from './messageCatalog.ts';
|
|
12
|
+
import type { MessageValues } from './messageValues.ts';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* What text is read with.
|
|
16
|
+
*
|
|
17
|
+
* `t(key)` is a key the catalog declares, checked at compile time.
|
|
18
|
+
* `t.or(key, fallback)` is a key built from the data — a site's id, an
|
|
19
|
+
* element's symbol — which the catalog may not have caught up with yet; it
|
|
20
|
+
* reads as the fallback rather than as a raw key.
|
|
21
|
+
*/
|
|
22
|
+
export type Translate<TKey extends string> = ((
|
|
23
|
+
key: LooseKey<TKey>,
|
|
24
|
+
values?: MessageValues,
|
|
25
|
+
) => string) & {
|
|
26
|
+
or: (key: string, fallback: string, values?: MessageValues) => string;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* A catalog's formatter, in one language.
|
|
31
|
+
*
|
|
32
|
+
* In a component this is `useT`, which also redraws when the language or a
|
|
33
|
+
* translator's edit changes it. Here it is for the places a hook cannot go:
|
|
34
|
+
* the build writing a head per address per language, a test asserting on the
|
|
35
|
+
* text a page shows, a label computed in a module helper.
|
|
36
|
+
* @param catalog - The catalog to read, typed by its English keys.
|
|
37
|
+
* @param language - The language to read it in.
|
|
38
|
+
* @returns See {@link Translate}.
|
|
39
|
+
*/
|
|
40
|
+
export function catalogTranslate<TKey extends string>(
|
|
41
|
+
catalog: MessageCatalog<TKey>,
|
|
42
|
+
language: Language,
|
|
43
|
+
): Translate<TKey> {
|
|
44
|
+
// `or` is a property of the function itself, so the two are built together
|
|
45
|
+
// rather than assigned onto a value a render may already have read.
|
|
46
|
+
const translate = (key: LooseKey<TKey>, values?: MessageValues) =>
|
|
47
|
+
catalog.translate(key, language, { values });
|
|
48
|
+
translate.or = (key: string, fallback: string, values?: MessageValues) =>
|
|
49
|
+
catalog.translate(key, language, { fallback, values });
|
|
50
|
+
return translate;
|
|
51
|
+
}
|
package/src/i18n/ui/useT.ts
CHANGED
|
@@ -3,27 +3,17 @@ import { CHROME_CATALOG } from '../core/chromeCatalog.ts';
|
|
|
3
3
|
import type {
|
|
4
4
|
Language,
|
|
5
5
|
LooseKey,
|
|
6
|
-
|
|
6
|
+
Translate,
|
|
7
7
|
TranslateOptions,
|
|
8
8
|
} from '../core/index.ts';
|
|
9
|
+
import { catalogTranslate } from '../core/index.ts';
|
|
9
10
|
import type { MessageCatalog } from '../core/messageCatalog.ts';
|
|
10
11
|
|
|
11
12
|
import { useLanguage, useMessagesVersion } from './useLanguage.ts';
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
* `t(key)` is a key the catalog declares, checked at compile time.
|
|
17
|
-
* `t.or(key, fallback)` is a key built from the data — a site's id, an
|
|
18
|
-
* element's symbol — which the catalog may not have caught up with yet; it
|
|
19
|
-
* reads as the fallback rather than as a raw key.
|
|
20
|
-
*/
|
|
21
|
-
export type Translate<TKey extends string> = ((
|
|
22
|
-
key: LooseKey<TKey>,
|
|
23
|
-
values?: MessageValues,
|
|
24
|
-
) => string) & {
|
|
25
|
-
or: (key: string, fallback: string, values?: MessageValues) => string;
|
|
26
|
-
};
|
|
14
|
+
// The formatter's own shape belongs to the catalog, not to the hook, and a site
|
|
15
|
+
// reads it from either entry point.
|
|
16
|
+
export type { Translate } from '../core/index.ts';
|
|
27
17
|
|
|
28
18
|
/**
|
|
29
19
|
* The formatter of a catalog's text, in the language the page is written in.
|
|
@@ -40,20 +30,7 @@ export function useT<TKey extends string>(
|
|
|
40
30
|
const language = useLanguage();
|
|
41
31
|
useMessagesVersion();
|
|
42
32
|
catalog.prefetch(language);
|
|
43
|
-
return
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Built outside the hook, because the `or` form is a property of the function
|
|
47
|
-
// itself and a render may not write to a value it has just read.
|
|
48
|
-
function translator<TKey extends string>(
|
|
49
|
-
catalog: MessageCatalog<TKey>,
|
|
50
|
-
language: Language,
|
|
51
|
-
): Translate<TKey> {
|
|
52
|
-
const translate = (key: LooseKey<TKey>, values?: MessageValues) =>
|
|
53
|
-
catalog.translate(key, language, { values });
|
|
54
|
-
translate.or = (key: string, fallback: string, values?: MessageValues) =>
|
|
55
|
-
catalog.translate(key, language, { fallback, values });
|
|
56
|
-
return translate;
|
|
33
|
+
return catalogTranslate(catalog, language);
|
|
57
34
|
}
|
|
58
35
|
|
|
59
36
|
/**
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A site's catalogs as the build reads them: all of them, off disk, at once.
|
|
3
|
+
*
|
|
4
|
+
* The page and the build want opposite things from the same files. A browser
|
|
5
|
+
* fetches one language — the one being read — so `en.json` is part of the
|
|
6
|
+
* bundle and the others are `import()`ed when a visitor asks, which is what
|
|
7
|
+
* keeps a site nobody reads in German from downloading the German. The build
|
|
8
|
+
* writes a head per address per language in one pass, so it wants every
|
|
9
|
+
* language, synchronously, before the first route table is asked for.
|
|
10
|
+
*
|
|
11
|
+
* Reading them rather than fetching them is what makes that possible. The
|
|
12
|
+
* page's loaders are written bare — `import('../locales/fr.json')` with no
|
|
13
|
+
* `with { type: 'json' }` — because the dev server serves a JSON file as a
|
|
14
|
+
* JavaScript module and a browser refuses a chunk it was promised JSON for.
|
|
15
|
+
* Node demands the attribute, so it cannot run those loaders: a build that
|
|
16
|
+
* awaited them had to be async and still only worked by keeping a second,
|
|
17
|
+
* eagerly imported copy of every catalog beside the first. `readFileSync` has
|
|
18
|
+
* no attribute, so there is nothing to work around.
|
|
19
|
+
*
|
|
20
|
+
* The identity comes from the page's own catalog, never re-typed here: pass
|
|
21
|
+
* `SITE_CATALOG.source` and the two provably name the same files.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { readFileSync } from 'node:fs';
|
|
25
|
+
import { join, resolve } from 'node:path';
|
|
26
|
+
|
|
27
|
+
import type { Language } from '../core/index.ts';
|
|
28
|
+
import { DEFAULT_LANGUAGE, LANGUAGES, MessageCatalog } from '../core/index.ts';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Which catalog to read, which is the page catalog's own `source`.
|
|
32
|
+
*
|
|
33
|
+
* `MessageCatalog` publishes it for the translate overlay, and it already
|
|
34
|
+
* carries the three things a reader needs. Hand it over rather than writing
|
|
35
|
+
* them twice: a build that names its own directory is a build that can come to
|
|
36
|
+
* disagree with the page about which files the site is translated in.
|
|
37
|
+
*/
|
|
38
|
+
export interface LocaleCatalogSource {
|
|
39
|
+
/**
|
|
40
|
+
* The name the page knows the catalog by, which is the site's host, e.g.
|
|
41
|
+
* `surge.cheminfo.org`. A translator's edit is routed back to the right
|
|
42
|
+
* repository with it, so the build and the page must agree on it.
|
|
43
|
+
*/
|
|
44
|
+
id: string;
|
|
45
|
+
/** The GitHub repository the files live in, written `owner/repo`. */
|
|
46
|
+
repository: string;
|
|
47
|
+
/** The directory holding the locale files, relative to the repository root. */
|
|
48
|
+
directory: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Where the directory is looked for. */
|
|
52
|
+
export interface LocaleCatalogOptions {
|
|
53
|
+
/**
|
|
54
|
+
* What the source's relative `directory` is resolved against. The default is
|
|
55
|
+
* the working directory, which is the repository root for both callers: a
|
|
56
|
+
* Vite config and a vitest run.
|
|
57
|
+
* @default process.cwd()
|
|
58
|
+
*/
|
|
59
|
+
root?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Every language a site is written in, read off disk into one catalog.
|
|
64
|
+
*
|
|
65
|
+
* For the build and for a site's own tests, never for the page: it reads the
|
|
66
|
+
* filesystem, and the translations it holds are tens of kilobytes a first
|
|
67
|
+
* visit must not pay for. Read one language out of it with `catalogTranslate`.
|
|
68
|
+
*
|
|
69
|
+
* A language whose file is absent is left out, which the catalog already reads
|
|
70
|
+
* as English — a half-translated site serves the pages it has rather than
|
|
71
|
+
* failing the build. A missing English file is a misconfiguration and throws:
|
|
72
|
+
* every key and every fallback is declared there.
|
|
73
|
+
* @param source - The page catalog's own `source`. See {@link LocaleCatalogSource}.
|
|
74
|
+
* @param options - See {@link LocaleCatalogOptions}.
|
|
75
|
+
* @returns The catalog, every language it carries already in memory.
|
|
76
|
+
*/
|
|
77
|
+
export function readLocaleCatalog<TKey extends string = string>(
|
|
78
|
+
source: LocaleCatalogSource,
|
|
79
|
+
options: LocaleCatalogOptions = {},
|
|
80
|
+
): MessageCatalog<TKey> {
|
|
81
|
+
const { id, repository, directory } = source;
|
|
82
|
+
const folder = resolve(options.root ?? process.cwd(), directory);
|
|
83
|
+
const english = readMessages(folder, DEFAULT_LANGUAGE);
|
|
84
|
+
if (english === undefined) {
|
|
85
|
+
throw new Error(
|
|
86
|
+
`no ${DEFAULT_LANGUAGE}.json in ${folder}: a catalog declares its keys and its fallbacks there`,
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
const translations: Partial<Record<Language, Record<string, string>>> = {};
|
|
90
|
+
for (const language of LANGUAGES) {
|
|
91
|
+
if (language === DEFAULT_LANGUAGE) continue;
|
|
92
|
+
const messages = readMessages(folder, language);
|
|
93
|
+
if (messages !== undefined) translations[language] = messages;
|
|
94
|
+
}
|
|
95
|
+
return new MessageCatalog<TKey>({
|
|
96
|
+
id,
|
|
97
|
+
repository,
|
|
98
|
+
directory,
|
|
99
|
+
source: english,
|
|
100
|
+
translations,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* One language's messages, read off disk.
|
|
106
|
+
* @param folder - The resolved directory holding the locale files.
|
|
107
|
+
* @param language - The language whose file to read.
|
|
108
|
+
* @returns Its messages, or `undefined` when the site does not carry it.
|
|
109
|
+
*/
|
|
110
|
+
function readMessages(
|
|
111
|
+
folder: string,
|
|
112
|
+
language: Language,
|
|
113
|
+
): Record<string, string> | undefined {
|
|
114
|
+
let text: string;
|
|
115
|
+
try {
|
|
116
|
+
text = readFileSync(join(folder, `${language}.json`), 'utf8');
|
|
117
|
+
} catch {
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
return JSON.parse(text) as Record<string, string>;
|
|
121
|
+
}
|
package/src/locales/de.json
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
"chrome.pages": "Seiten",
|
|
4
4
|
"chrome.about": "Über",
|
|
5
5
|
"chrome.aboutTitle": "Was diese Seite ist, worauf sie aufbaut und wie man sie zitiert",
|
|
6
|
+
"chrome.contact": "Kontakt",
|
|
7
|
+
"chrome.contactTitle": "Eine Frage, ein Problem, eine Idee? Schreiben Sie uns",
|
|
6
8
|
"account.signIn": "Anmelden",
|
|
7
9
|
"account.signOut": "Abmelden",
|
|
8
10
|
"account.signedInAs": "Angemeldet als {name}",
|
package/src/locales/en.json
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
"chrome.pages": "Pages",
|
|
4
4
|
"chrome.about": "About",
|
|
5
5
|
"chrome.aboutTitle": "What this site is, what it is built on, and how to cite it",
|
|
6
|
+
"chrome.contact": "Contact",
|
|
7
|
+
"chrome.contactTitle": "A question, a problem or an idea? Write to us",
|
|
6
8
|
"account.signIn": "Sign in",
|
|
7
9
|
"account.signOut": "Sign out",
|
|
8
10
|
"account.signedInAs": "Signed in as {name}",
|
package/src/locales/es.json
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
"chrome.pages": "Páginas",
|
|
4
4
|
"chrome.about": "Acerca de",
|
|
5
5
|
"chrome.aboutTitle": "Qué es este sitio, en qué se basa y cómo citarlo",
|
|
6
|
+
"chrome.contact": "Contacto",
|
|
7
|
+
"chrome.contactTitle": "¿Una pregunta, un problema, una idea? Escríbanos",
|
|
6
8
|
"account.signIn": "Iniciar sesión",
|
|
7
9
|
"account.signOut": "Cerrar sesión",
|
|
8
10
|
"account.signedInAs": "Sesión iniciada como {name}",
|
package/src/locales/fr.json
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
"chrome.pages": "Pages",
|
|
4
4
|
"chrome.about": "À propos",
|
|
5
5
|
"chrome.aboutTitle": "Ce qu'est ce site, sur quoi il est bâti et comment le citer",
|
|
6
|
+
"chrome.contact": "Contact",
|
|
7
|
+
"chrome.contactTitle": "Une question, un problème, une idée ? Écrivez-nous",
|
|
6
8
|
"account.signIn": "Se connecter",
|
|
7
9
|
"account.signOut": "Se déconnecter",
|
|
8
10
|
"account.signedInAs": "Connecté comme {name}",
|
package/src/locales/it.json
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
"chrome.pages": "Pagine",
|
|
4
4
|
"chrome.about": "Informazioni",
|
|
5
5
|
"chrome.aboutTitle": "Cosa è questo sito, su cosa si basa e come citarlo",
|
|
6
|
+
"chrome.contact": "Contatto",
|
|
7
|
+
"chrome.contactTitle": "Una domanda, un problema, un'idea? Scriveteci",
|
|
6
8
|
"account.signIn": "Accedi",
|
|
7
9
|
"account.signOut": "Esci",
|
|
8
10
|
"account.signedInAs": "Accesso effettuato come {name}",
|
package/src/ui.ts
CHANGED
|
@@ -4,6 +4,7 @@ export * from './capsule/ui/index.ts';
|
|
|
4
4
|
export * from './chart/ui/index.ts';
|
|
5
5
|
export * from './chrome/ui/index.ts';
|
|
6
6
|
export * from './citation/ui/index.ts';
|
|
7
|
+
export * from './contact/ui/index.ts';
|
|
7
8
|
export * from './clipboard/ui/index.ts';
|
|
8
9
|
export * from './color/ui/index.ts';
|
|
9
10
|
export * from './confirm/ui/index.ts';
|
package/src/vite.ts
CHANGED
package/styles/chrome.css
CHANGED
|
@@ -192,6 +192,27 @@ button {
|
|
|
192
192
|
padding: 0.3rem 0.5rem;
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
+
/* Every utility of the bar takes the same box, whatever it is built on — a link,
|
|
196
|
+
or a Blueprint button opening a menu — so the marks stand evenly spaced: the
|
|
197
|
+
same padding, no minimum width, no room kept beside the glyph for the hidden
|
|
198
|
+
label, and one glyph size. */
|
|
199
|
+
.app-header-actions .bp6-button:has(> .bp6-icon:not(.bp6-icon-caret-down)) {
|
|
200
|
+
min-width: 0;
|
|
201
|
+
padding: 0.3rem 0.5rem;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.app-header-actions
|
|
205
|
+
.bp6-button:has(> .bp6-icon:not(.bp6-icon-caret-down))
|
|
206
|
+
> .bp6-icon {
|
|
207
|
+
margin: 0;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.app-header-actions .nav-link--icon > .bp6-icon > svg,
|
|
211
|
+
.app-header-actions .bp6-button > .bp6-icon > svg {
|
|
212
|
+
width: 16px;
|
|
213
|
+
height: 16px;
|
|
214
|
+
}
|
|
215
|
+
|
|
195
216
|
/* A setting the bar shows as its own values — the language, the scale a
|
|
196
217
|
temperature is read on — the one in force pressed. The values carry no
|
|
197
218
|
glyph, which is what keeps them written where a utility is only its mark. */
|