extension-create 4.1.19 → 4.1.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/project-name.d.ts +1 -0
- package/dist/module.cjs +5 -2
- package/dist/steps/import-external-template.d.ts +1 -1
- package/dist/steps/write-package-json.d.ts +0 -2
- package/dist/test-template-javascript/.extension-create.json +3 -3
- package/dist/test-template-javascript/STORE.md +1 -1
- package/dist/test-template-javascript/package.json +1 -1
- package/dist/test-template-javascript/src/background.ts +46 -7
- package/dist/test-template-javascript/src/content/ContentApp.ts +20 -11
- package/dist/test-template-javascript/src/content/scripts.ts +1 -0
- package/dist/test-template-javascript/src/content/styles.css +9 -3
- package/dist/test-template-javascript/src/sidebar/styles.css +6 -4
- package/package.json +2 -2
- package/templates/javascript/src/background.js +46 -7
- package/templates/javascript/src/content/ContentApp.js +23 -17
- package/templates/javascript/src/content/scripts.js +1 -0
- package/templates/javascript/src/content/styles.css +9 -3
- package/templates/javascript/src/sidebar/styles.css +6 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isUrlProjectName(projectNameInput: string): boolean;
|
package/dist/module.cjs
CHANGED
|
@@ -358,6 +358,9 @@ function keepingExistingGitignore(projectName) {
|
|
|
358
358
|
function existingRepositoryKept(projectName) {
|
|
359
359
|
return `${prefix('info')} ${external_pintor_default().blue(projectName)} is already a git repository with history.\nLeft it uncommitted. Review the scaffold and run ${external_pintor_default().blue('git add -A && git commit')} yourself.`;
|
|
360
360
|
}
|
|
361
|
+
function isUrlProjectName(projectNameInput) {
|
|
362
|
+
return /^https?:\/\//i.test(projectNameInput.trim());
|
|
363
|
+
}
|
|
361
364
|
const promises_namespaceObject = require("node:fs/promises");
|
|
362
365
|
async function copyDirectoryWithSymlinks(source, destination) {
|
|
363
366
|
const entries = await promises_namespaceObject.readdir(source, {
|
|
@@ -609,7 +612,7 @@ const NETWORK_TIMEOUT_MS = (()=>{
|
|
|
609
612
|
return Number.isFinite(raw) && raw > 0 ? raw : 60000;
|
|
610
613
|
})();
|
|
611
614
|
const CODELOAD_BASE = 'https://codeload.github.com/extension-js/examples/zip';
|
|
612
|
-
const DEFAULT_TEMPLATES_REF = '
|
|
615
|
+
const DEFAULT_TEMPLATES_REF = '39448a235ea1b02516e6d555bcae409db2258b7f';
|
|
613
616
|
const BUNDLED_TEMPLATES = [
|
|
614
617
|
"javascript"
|
|
615
618
|
];
|
|
@@ -2135,7 +2138,7 @@ async function extensionCreate(projectNameInput, { cliVersion, template, install
|
|
|
2135
2138
|
if (!projectNameInput) throw new Error(noProjectName());
|
|
2136
2139
|
const templateWasOmitted = null == template || '' === String(template).trim();
|
|
2137
2140
|
const effectiveTemplate = templateWasOmitted ? DEFAULT_TEMPLATE_NAME : String(template);
|
|
2138
|
-
if (projectNameInput
|
|
2141
|
+
if (isUrlProjectName(projectNameInput)) throw new Error(noUrlAllowed());
|
|
2139
2142
|
const projectPath = external_node_path_namespaceObject.isAbsolute(projectNameInput) ? projectNameInput : external_node_path_namespaceObject.join(process.cwd(), projectNameInput);
|
|
2140
2143
|
const projectName = external_node_path_namespaceObject.basename(projectPath);
|
|
2141
2144
|
const updateSuffix = process.env.EXTENSION_CLI_UPDATE_SUFFIX || '';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const DEFAULT_TEMPLATES_REF = "
|
|
1
|
+
export declare const DEFAULT_TEMPLATES_REF = "39448a235ea1b02516e6d555bcae409db2258b7f";
|
|
2
2
|
export declare const BUNDLED_TEMPLATES: readonly string[];
|
|
3
3
|
export declare const DEFAULT_TEMPLATE_NAME = "typescript";
|
|
4
4
|
export declare const OFFLINE_FALLBACK_TEMPLATE = "javascript";
|
|
@@ -2,10 +2,8 @@ import { type ScaffoldPackageManager } from '../lib/package-manager.js';
|
|
|
2
2
|
export declare function resolveExtensionBinary(): Promise<string>;
|
|
3
3
|
export declare function getTemplateAwareScripts(template: string, extensionBinary: string): Record<string, string>;
|
|
4
4
|
interface OverridePackageJsonOptions {
|
|
5
|
-
/** Defaults to `javascript` when omitted (same as `extensionCreate`). */
|
|
6
5
|
template?: string;
|
|
7
6
|
cliVersion?: string;
|
|
8
|
-
/** The one manager the project uses; resolved from the scaffold when omitted. */
|
|
9
7
|
packageManager?: ScaffoldPackageManager;
|
|
10
8
|
}
|
|
11
9
|
export declare function resolveExtensionDevDependencyVersion(cliVersion?: string): string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"createdWith": "extension-create@4.1.
|
|
2
|
+
"createdWith": "extension-create@4.1.19",
|
|
3
3
|
"template": "typescript",
|
|
4
|
-
"source": "https://codeload.github.com/extension-js/examples/zip/
|
|
5
|
-
"ref": "
|
|
4
|
+
"source": "https://codeload.github.com/extension-js/examples/zip/39448a235ea1b02516e6d555bcae409db2258b7f",
|
|
5
|
+
"ref": "39448a235ea1b02516e6d555bcae409db2258b7f"
|
|
6
6
|
}
|
|
@@ -9,7 +9,7 @@ Packaging your extension is local and free. Submitting the result to a
|
|
|
9
9
|
store is what [extension.dev](https://docs.extension.dev/publish/overview?utm_source=store-md)
|
|
10
10
|
does, and it sponsors Extension.js.
|
|
11
11
|
|
|
12
|
-
Last updated: 2026-09-
|
|
12
|
+
Last updated: 2026-09-16
|
|
13
13
|
|
|
14
14
|
## Listing
|
|
15
15
|
|
|
@@ -6,22 +6,61 @@ const isFirefoxLike =
|
|
|
6
6
|
import.meta.env.EXTENSION_PUBLIC_BROWSER === 'firefox' ||
|
|
7
7
|
import.meta.env.EXTENSION_PUBLIC_BROWSER === 'gecko-based'
|
|
8
8
|
|
|
9
|
+
const isSafariLike =
|
|
10
|
+
import.meta.env.EXTENSION_PUBLIC_BROWSER === 'safari' ||
|
|
11
|
+
import.meta.env.EXTENSION_PUBLIC_BROWSER === 'webkit-based'
|
|
12
|
+
|
|
13
|
+
// Safari has no side panel surface, so the sidebar page opens in a tab.
|
|
14
|
+
let sidebarTabId: number | undefined
|
|
15
|
+
|
|
16
|
+
function openSidebarTab() {
|
|
17
|
+
const url = chrome.runtime.getURL('sidebar/index.html')
|
|
18
|
+
|
|
19
|
+
const openNewTab = () => {
|
|
20
|
+
chrome.tabs.create({url}, (tab) => {
|
|
21
|
+
sidebarTabId = tab?.id
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// A repeat click focuses the tab already opened instead of a new copy.
|
|
26
|
+
const knownTabId = sidebarTabId
|
|
27
|
+
|
|
28
|
+
if (knownTabId === undefined) {
|
|
29
|
+
openNewTab()
|
|
30
|
+
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
chrome.tabs.update(knownTabId, {active: true}, () => {
|
|
35
|
+
if (chrome.runtime.lastError) openNewTab()
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
|
|
9
39
|
if (isFirefoxLike) {
|
|
40
|
+
// Firefox refuses sidebarAction.open() outside a user input handler, and a
|
|
41
|
+
// message listener is not one, so the toolbar click is the only route.
|
|
10
42
|
browser.browserAction.onClicked.addListener(() => {
|
|
11
43
|
browser.sidebarAction.open()
|
|
12
44
|
})
|
|
45
|
+
}
|
|
13
46
|
|
|
14
|
-
|
|
47
|
+
if (isSafariLike) {
|
|
48
|
+
// Safari never had setPanelBehavior, so the toolbar click needs a listener.
|
|
49
|
+
chrome.action?.onClicked.addListener(() => {
|
|
50
|
+
openSidebarTab()
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
chrome.runtime.onMessage.addListener((message) => {
|
|
15
54
|
if (!message || message.type !== 'openSidebar') return
|
|
16
55
|
|
|
17
|
-
|
|
56
|
+
openSidebarTab()
|
|
18
57
|
})
|
|
19
58
|
}
|
|
20
59
|
|
|
21
|
-
if (!isFirefoxLike) {
|
|
60
|
+
if (!isFirefoxLike && !isSafariLike) {
|
|
22
61
|
// setPanelBehavior only affects FUTURE action clicks, registering it
|
|
23
62
|
// inside onClicked would swallow the first toolbar click.
|
|
24
|
-
chrome.sidePanel
|
|
63
|
+
chrome.sidePanel?.setPanelBehavior({openPanelOnActionClick: true})
|
|
25
64
|
|
|
26
65
|
// The side panel API only exists in Chromium. Firefox opens the sidebar in
|
|
27
66
|
// the listener above, so this listener is compiled out of gecko builds.
|
|
@@ -32,13 +71,13 @@ if (!isFirefoxLike) {
|
|
|
32
71
|
// allowed inside the user gesture that the content-script click carries, and
|
|
33
72
|
// a tabs.query callback outlives it: the panel then silently refuses to open.
|
|
34
73
|
// sender.tab is the tab the click came from, so no lookup is needed at all.
|
|
35
|
-
chrome.sidePanel
|
|
74
|
+
chrome.sidePanel?.setPanelBehavior({openPanelOnActionClick: true})
|
|
36
75
|
|
|
37
76
|
const tabId = sender.tab?.id
|
|
38
|
-
if (!chrome.sidePanel
|
|
77
|
+
if (!chrome.sidePanel?.open || tabId === undefined) return
|
|
39
78
|
|
|
40
79
|
try {
|
|
41
|
-
chrome.sidePanel
|
|
80
|
+
chrome.sidePanel?.open({tabId})
|
|
42
81
|
} catch (error) {
|
|
43
82
|
console.error(error)
|
|
44
83
|
}
|
|
@@ -1,20 +1,27 @@
|
|
|
1
1
|
import logo from '../images/icon.png'
|
|
2
2
|
|
|
3
|
+
const isFirefoxLike =
|
|
4
|
+
import.meta.env.EXTENSION_PUBLIC_BROWSER === 'firefox' ||
|
|
5
|
+
import.meta.env.EXTENSION_PUBLIC_BROWSER === 'gecko-based'
|
|
6
|
+
|
|
3
7
|
export default function createContentApp(): HTMLDivElement {
|
|
4
8
|
const container = document.createElement('div')
|
|
5
9
|
container.className = 'content_script'
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
pill
|
|
10
|
-
pill.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
// Firefox cannot open a sidebar from a message listener, so the gecko build
|
|
12
|
+
// renders a hint naming the toolbar action instead of a dead control.
|
|
13
|
+
const pill = document.createElement(isFirefoxLike ? 'div' : 'button')
|
|
14
|
+
pill.className = isFirefoxLike
|
|
15
|
+
? 'content_pill content_pill_static'
|
|
16
|
+
: 'content_pill'
|
|
17
|
+
|
|
18
|
+
if (!isFirefoxLike) {
|
|
19
|
+
;(pill as HTMLButtonElement).type = 'button'
|
|
20
|
+
pill.setAttribute('aria-label', 'Open sidebar')
|
|
21
|
+
pill.addEventListener('click', () => {
|
|
15
22
|
chrome.runtime.sendMessage({type: 'openSidebar'})
|
|
16
|
-
}
|
|
17
|
-
}
|
|
23
|
+
})
|
|
24
|
+
}
|
|
18
25
|
|
|
19
26
|
const img = document.createElement('img')
|
|
20
27
|
img.className = 'content_pill_logo'
|
|
@@ -26,7 +33,9 @@ export default function createContentApp(): HTMLDivElement {
|
|
|
26
33
|
|
|
27
34
|
const text = document.createElement('span')
|
|
28
35
|
text.className = 'content_pill_text'
|
|
29
|
-
text.textContent =
|
|
36
|
+
text.textContent = isFirefoxLike
|
|
37
|
+
? 'Use the toolbar icon to open the sidebar'
|
|
38
|
+
: 'Open sidebar'
|
|
30
39
|
|
|
31
40
|
pill.appendChild(img)
|
|
32
41
|
pill.appendChild(text)
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
.content_pill:hover {
|
|
25
|
+
.content_pill:not(.content_pill_static):hover {
|
|
26
26
|
background: #11151c;
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -40,6 +40,12 @@
|
|
|
40
40
|
font-weight: 600;
|
|
41
41
|
line-height: 1;
|
|
42
42
|
font-family:
|
|
43
|
-
-apple-system, BlinkMacSystemFont,
|
|
44
|
-
Arial,
|
|
43
|
+
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue',
|
|
44
|
+
Arial, 'Noto Sans', sans-serif;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* The gecko build renders this hint in place of the pill, so it must not read
|
|
48
|
+
as a control: no pointer cursor and no hover response. */
|
|
49
|
+
.content_pill_static {
|
|
50
|
+
cursor: default;
|
|
45
51
|
}
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
body {
|
|
12
12
|
background-color: var(--sidebar-bg);
|
|
13
13
|
color: var(--sidebar-text);
|
|
14
|
-
height
|
|
14
|
+
/* The margin insets the panel, so a full-viewport height would push the
|
|
15
|
+
content below centre and overflow the panel by twice the margin. */
|
|
16
|
+
height: calc(100vh - 2 * var(--sidebar-margin));
|
|
15
17
|
margin: var(--sidebar-margin);
|
|
16
18
|
border-radius: 6px;
|
|
17
19
|
display: flex;
|
|
@@ -26,7 +28,7 @@ body {
|
|
|
26
28
|
align-items: center;
|
|
27
29
|
padding: 0 1rem;
|
|
28
30
|
text-align: center;
|
|
29
|
-
max-height:
|
|
31
|
+
max-height: 100%;
|
|
30
32
|
overflow-y: auto;
|
|
31
33
|
}
|
|
32
34
|
|
|
@@ -39,8 +41,8 @@ body {
|
|
|
39
41
|
font-size: 1.85em;
|
|
40
42
|
line-height: 1.1;
|
|
41
43
|
font-family:
|
|
42
|
-
-apple-system, BlinkMacSystemFont,
|
|
43
|
-
Arial,
|
|
44
|
+
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue',
|
|
45
|
+
Arial, 'Noto Sans', sans-serif;
|
|
44
46
|
font-weight: 700;
|
|
45
47
|
margin: 0;
|
|
46
48
|
text-align: center;
|
package/package.json
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"templates"
|
|
26
26
|
],
|
|
27
27
|
"name": "extension-create",
|
|
28
|
-
"version": "4.1.
|
|
28
|
+
"version": "4.1.20",
|
|
29
29
|
"description": "The standalone extension creation engine for Extension.js",
|
|
30
30
|
"author": {
|
|
31
31
|
"name": "Cezar Augusto",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"watch": "rslib build --watch",
|
|
46
46
|
"compile": "rslib build",
|
|
47
47
|
"format": "biome format --write .",
|
|
48
|
-
"lint": "biome lint .",
|
|
48
|
+
"lint": "biome lint . && eslint .",
|
|
49
49
|
"pretest:create": "pnpm compile",
|
|
50
50
|
"pretest": "pnpm compile",
|
|
51
51
|
"test": "vitest run",
|
|
@@ -6,22 +6,61 @@ const isFirefoxLike =
|
|
|
6
6
|
import.meta.env.EXTENSION_PUBLIC_BROWSER === 'firefox' ||
|
|
7
7
|
import.meta.env.EXTENSION_PUBLIC_BROWSER === 'gecko-based'
|
|
8
8
|
|
|
9
|
+
const isSafariLike =
|
|
10
|
+
import.meta.env.EXTENSION_PUBLIC_BROWSER === 'safari' ||
|
|
11
|
+
import.meta.env.EXTENSION_PUBLIC_BROWSER === 'webkit-based'
|
|
12
|
+
|
|
13
|
+
// Safari has no side panel surface, so the sidebar page opens in a tab.
|
|
14
|
+
let sidebarTabId
|
|
15
|
+
|
|
16
|
+
function openSidebarTab() {
|
|
17
|
+
const url = chrome.runtime.getURL('sidebar/index.html')
|
|
18
|
+
|
|
19
|
+
const openNewTab = () => {
|
|
20
|
+
chrome.tabs.create({url}, (tab) => {
|
|
21
|
+
sidebarTabId = tab?.id
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// A repeat click focuses the tab already opened instead of a new copy.
|
|
26
|
+
const knownTabId = sidebarTabId
|
|
27
|
+
|
|
28
|
+
if (knownTabId === undefined) {
|
|
29
|
+
openNewTab()
|
|
30
|
+
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
chrome.tabs.update(knownTabId, {active: true}, () => {
|
|
35
|
+
if (chrome.runtime.lastError) openNewTab()
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
|
|
9
39
|
if (isFirefoxLike) {
|
|
40
|
+
// Firefox refuses sidebarAction.open() outside a user input handler, and a
|
|
41
|
+
// message listener is not one, so the toolbar click is the only route.
|
|
10
42
|
browser.browserAction.onClicked.addListener(() => {
|
|
11
43
|
browser.sidebarAction.open()
|
|
12
44
|
})
|
|
45
|
+
}
|
|
13
46
|
|
|
14
|
-
|
|
47
|
+
if (isSafariLike) {
|
|
48
|
+
// Safari never had setPanelBehavior, so the toolbar click needs a listener.
|
|
49
|
+
chrome.action?.onClicked.addListener(() => {
|
|
50
|
+
openSidebarTab()
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
chrome.runtime.onMessage.addListener((message) => {
|
|
15
54
|
if (!message || message.type !== 'openSidebar') return
|
|
16
55
|
|
|
17
|
-
|
|
56
|
+
openSidebarTab()
|
|
18
57
|
})
|
|
19
58
|
}
|
|
20
59
|
|
|
21
|
-
if (!isFirefoxLike) {
|
|
60
|
+
if (!isFirefoxLike && !isSafariLike) {
|
|
22
61
|
// setPanelBehavior only affects FUTURE action clicks, registering it
|
|
23
62
|
// inside onClicked would swallow the first toolbar click.
|
|
24
|
-
chrome.sidePanel
|
|
63
|
+
chrome.sidePanel?.setPanelBehavior({openPanelOnActionClick: true})
|
|
25
64
|
|
|
26
65
|
// The side panel API only exists in Chromium. Firefox opens the sidebar in
|
|
27
66
|
// the listener above, so this listener is compiled out of gecko builds.
|
|
@@ -32,13 +71,13 @@ if (!isFirefoxLike) {
|
|
|
32
71
|
// allowed inside the user gesture that the content-script click carries, and
|
|
33
72
|
// a tabs.query callback outlives it: the panel then silently refuses to open.
|
|
34
73
|
// sender.tab is the tab the click came from, so no lookup is needed at all.
|
|
35
|
-
chrome.sidePanel
|
|
74
|
+
chrome.sidePanel?.setPanelBehavior({openPanelOnActionClick: true})
|
|
36
75
|
|
|
37
76
|
const tabId = sender.tab?.id
|
|
38
|
-
if (!chrome.sidePanel
|
|
77
|
+
if (!chrome.sidePanel?.open || tabId === undefined) return
|
|
39
78
|
|
|
40
79
|
try {
|
|
41
|
-
chrome.sidePanel
|
|
80
|
+
chrome.sidePanel?.open({tabId})
|
|
42
81
|
} catch (error) {
|
|
43
82
|
console.error(error)
|
|
44
83
|
}
|
|
@@ -1,27 +1,31 @@
|
|
|
1
1
|
import logo from '../images/icon.png'
|
|
2
2
|
|
|
3
|
+
const isFirefoxLike =
|
|
4
|
+
import.meta.env.EXTENSION_PUBLIC_BROWSER === 'firefox' ||
|
|
5
|
+
import.meta.env.EXTENSION_PUBLIC_BROWSER === 'gecko-based'
|
|
6
|
+
|
|
3
7
|
export default function createContentApp() {
|
|
4
8
|
const container = document.createElement('div')
|
|
5
9
|
container.className = 'content_script'
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
pill
|
|
10
|
-
pill.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
// Firefox cannot open a sidebar from a message listener, so the gecko build
|
|
12
|
+
// renders a hint naming the toolbar action instead of a dead control.
|
|
13
|
+
const pill = document.createElement(isFirefoxLike ? 'div' : 'button')
|
|
14
|
+
pill.className = isFirefoxLike
|
|
15
|
+
? 'content_pill content_pill_static'
|
|
16
|
+
: 'content_pill'
|
|
17
|
+
|
|
18
|
+
if (!isFirefoxLike) {
|
|
19
|
+
pill.type = 'button'
|
|
20
|
+
pill.setAttribute('aria-label', 'Open sidebar')
|
|
21
|
+
pill.addEventListener('click', () => {
|
|
22
|
+
try {
|
|
19
23
|
chrome.runtime.sendMessage({type: 'openSidebar'})
|
|
24
|
+
} catch (error) {
|
|
25
|
+
console.error(error)
|
|
20
26
|
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
})
|
|
27
|
+
})
|
|
28
|
+
}
|
|
25
29
|
|
|
26
30
|
const img = document.createElement('img')
|
|
27
31
|
img.className = 'content_pill_logo'
|
|
@@ -31,7 +35,9 @@ export default function createContentApp() {
|
|
|
31
35
|
|
|
32
36
|
const text = document.createElement('span')
|
|
33
37
|
text.className = 'content_pill_text'
|
|
34
|
-
text.textContent =
|
|
38
|
+
text.textContent = isFirefoxLike
|
|
39
|
+
? 'Use the toolbar icon to open the sidebar'
|
|
40
|
+
: 'Open sidebar'
|
|
35
41
|
|
|
36
42
|
pill.appendChild(img)
|
|
37
43
|
pill.appendChild(text)
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
.content_pill:hover {
|
|
25
|
+
.content_pill:not(.content_pill_static):hover {
|
|
26
26
|
background: #11151c;
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -40,6 +40,12 @@
|
|
|
40
40
|
font-weight: 600;
|
|
41
41
|
line-height: 1;
|
|
42
42
|
font-family:
|
|
43
|
-
-apple-system, BlinkMacSystemFont,
|
|
44
|
-
Arial,
|
|
43
|
+
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue',
|
|
44
|
+
Arial, 'Noto Sans', sans-serif;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* The gecko build renders this hint in place of the pill, so it must not read
|
|
48
|
+
as a control: no pointer cursor and no hover response. */
|
|
49
|
+
.content_pill_static {
|
|
50
|
+
cursor: default;
|
|
45
51
|
}
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
body {
|
|
12
12
|
background-color: var(--sidebar-bg);
|
|
13
13
|
color: var(--sidebar-text);
|
|
14
|
-
height
|
|
14
|
+
/* The margin insets the panel, so a full-viewport height would push the
|
|
15
|
+
content below centre and overflow the panel by twice the margin. */
|
|
16
|
+
height: calc(100vh - 2 * var(--sidebar-margin));
|
|
15
17
|
margin: var(--sidebar-margin);
|
|
16
18
|
border-radius: 6px;
|
|
17
19
|
display: flex;
|
|
@@ -26,7 +28,7 @@ body {
|
|
|
26
28
|
align-items: center;
|
|
27
29
|
padding: 0 1rem;
|
|
28
30
|
text-align: center;
|
|
29
|
-
max-height:
|
|
31
|
+
max-height: 100%;
|
|
30
32
|
overflow-y: auto;
|
|
31
33
|
}
|
|
32
34
|
|
|
@@ -39,8 +41,8 @@ body {
|
|
|
39
41
|
font-size: 1.85em;
|
|
40
42
|
line-height: 1.1;
|
|
41
43
|
font-family:
|
|
42
|
-
-apple-system, BlinkMacSystemFont,
|
|
43
|
-
Arial,
|
|
44
|
+
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue',
|
|
45
|
+
Arial, 'Noto Sans', sans-serif;
|
|
44
46
|
font-weight: 700;
|
|
45
47
|
margin: 0;
|
|
46
48
|
text-align: center;
|