extension-create 4.0.13 → 4.0.14-canary.1784515910.7d7da9cc
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/messages.d.ts +2 -0
- package/dist/module.cjs +123 -11
- package/dist/steps/import-external-template.d.ts +9 -0
- package/package.json +1 -1
- package/dist/test-template-javascript/README.md +0 -41
- package/dist/test-template-javascript/extension.config.js +0 -19
- package/dist/test-template-javascript/package.json +0 -32
- package/dist/test-template-javascript/public/screenshot.png +0 -0
- package/dist/test-template-javascript/src/background.js +0 -44
- package/dist/test-template-javascript/src/content/ContentApp.js +0 -41
- package/dist/test-template-javascript/src/content/scripts.js +0 -44
- package/dist/test-template-javascript/src/content/styles.css +0 -45
- package/dist/test-template-javascript/src/images/icon.png +0 -0
- package/dist/test-template-javascript/src/manifest.json +0 -63
- package/dist/test-template-javascript/src/sidebar/SidebarApp.js +0 -28
- package/dist/test-template-javascript/src/sidebar/index.html +0 -13
- package/dist/test-template-javascript/src/sidebar/scripts.js +0 -4
- package/dist/test-template-javascript/src/sidebar/styles.css +0 -60
package/dist/lib/messages.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ export declare function writingTypeDefinitionsError(error: any): string;
|
|
|
12
12
|
export declare function installingFromTemplate(projectName: string, templateName: string): string;
|
|
13
13
|
export declare function installingFromTemplateError(projectName: string, template: string, error: any): string;
|
|
14
14
|
export declare function templateFetchTimedOut(templateName: string, ms: number): string;
|
|
15
|
+
export declare function templateNotFoundInCatalog(templateName: string, error?: any): string;
|
|
16
|
+
export declare function templateDownloadFailed(templateName: string, error: any): string;
|
|
15
17
|
export declare function initializingGitForRepository(projectName: string): string;
|
|
16
18
|
export declare function initializingGitSkipped(projectName: string, reason: string): string;
|
|
17
19
|
export declare function installingDependencies(): string;
|
package/dist/module.cjs
CHANGED
|
@@ -129,6 +129,12 @@ function installingFromTemplateError(projectName, template, error) {
|
|
|
129
129
|
function templateFetchTimedOut(templateName, ms) {
|
|
130
130
|
return `${external_pintor_default().red('Error')} Timed out after ${external_pintor_default().yellow(`${Math.round(ms / 1000)}s`)} fetching template ${external_pintor_default().yellow(templateName)}.\n${external_pintor_default().red('Next step: check your network, or set EXTENSION_CREATE_TIMEOUT_MS to allow more time.')}`;
|
|
131
131
|
}
|
|
132
|
+
function templateNotFoundInCatalog(templateName, error) {
|
|
133
|
+
return `${external_pintor_default().red('Error')} Template ${external_pintor_default().yellow(templateName)} is not in the extension-js/examples catalog.\n` + (error ? `${external_pintor_default().red(String(error))}\n` : '') + `${external_pintor_default().red('Next step: run')} ${external_pintor_default().yellow('extension create --help')} ` + `${external_pintor_default().red('to list valid template names, or pass a GitHub URL.')}`;
|
|
134
|
+
}
|
|
135
|
+
function templateDownloadFailed(templateName, error) {
|
|
136
|
+
return `${external_pintor_default().red('Error')} Couldn't download template ${external_pintor_default().yellow(templateName)} from ${external_pintor_default().yellow('github.com/extension-js/examples')}.\n${external_pintor_default().red(String(error && error.message || error))}\n${external_pintor_default().red('Next step: check your network (or GitHub rate limits) and try again; set EXTENSION_CREATE_TIMEOUT_MS to allow more time.')}`;
|
|
137
|
+
}
|
|
132
138
|
function initializingGitForRepository(projectName) {
|
|
133
139
|
return `${statusPrefix} Initializing git repository for ${external_pintor_default().blue(projectName)}...`;
|
|
134
140
|
}
|
|
@@ -313,10 +319,88 @@ const external_adm_zip_namespaceObject = require("adm-zip");
|
|
|
313
319
|
var external_adm_zip_default = /*#__PURE__*/ __webpack_require__.n(external_adm_zip_namespaceObject);
|
|
314
320
|
const external_go_git_it_namespaceObject = require("go-git-it");
|
|
315
321
|
var external_go_git_it_default = /*#__PURE__*/ __webpack_require__.n(external_go_git_it_namespaceObject);
|
|
322
|
+
function _define_property(obj, key, value) {
|
|
323
|
+
if (key in obj) Object.defineProperty(obj, key, {
|
|
324
|
+
value: value,
|
|
325
|
+
enumerable: true,
|
|
326
|
+
configurable: true,
|
|
327
|
+
writable: true
|
|
328
|
+
});
|
|
329
|
+
else obj[key] = value;
|
|
330
|
+
return obj;
|
|
331
|
+
}
|
|
316
332
|
const NETWORK_TIMEOUT_MS = (()=>{
|
|
317
333
|
const raw = parseInt(String(process.env.EXTENSION_CREATE_TIMEOUT_MS || ''), 10);
|
|
318
334
|
return Number.isFinite(raw) && raw > 0 ? raw : 60000;
|
|
319
335
|
})();
|
|
336
|
+
const EXAMPLES_REF = process.env.EXTENSION_CREATE_TEMPLATE_REF || 'main';
|
|
337
|
+
class TemplateNotFoundError extends Error {
|
|
338
|
+
constructor(templateName, cause){
|
|
339
|
+
super(`template not found in catalog: ${templateName}`), _define_property(this, "templateName", void 0);
|
|
340
|
+
this.name = 'TemplateNotFoundError';
|
|
341
|
+
this.templateName = templateName;
|
|
342
|
+
if (cause) this.cause = cause;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
class TemplateDownloadError extends Error {
|
|
346
|
+
constructor(templateName, cause){
|
|
347
|
+
const msg = cause?.message ?? String(cause);
|
|
348
|
+
super(msg), _define_property(this, "templateName", void 0);
|
|
349
|
+
this.name = 'TemplateDownloadError';
|
|
350
|
+
this.templateName = templateName;
|
|
351
|
+
this.cause = cause;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
const sleep = (ms)=>new Promise((r)=>setTimeout(r, ms));
|
|
355
|
+
async function downloadArchive(url, timeoutMs, attempts = 2) {
|
|
356
|
+
let lastError;
|
|
357
|
+
for(let attempt = 1; attempt <= attempts; attempt++)try {
|
|
358
|
+
const { data } = await external_axios_default().get(url, {
|
|
359
|
+
responseType: 'arraybuffer',
|
|
360
|
+
maxRedirects: 5,
|
|
361
|
+
timeout: timeoutMs,
|
|
362
|
+
headers: {
|
|
363
|
+
'User-Agent': 'extension-create'
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
return Buffer.from(data);
|
|
367
|
+
} catch (error) {
|
|
368
|
+
lastError = error;
|
|
369
|
+
if (attempt < attempts) await sleep(400 * attempt);
|
|
370
|
+
}
|
|
371
|
+
throw lastError;
|
|
372
|
+
}
|
|
373
|
+
async function extractExamplesTemplateFromZip(zipBuffer, templateName, projectPath) {
|
|
374
|
+
const zip = new (external_adm_zip_default())(zipBuffer);
|
|
375
|
+
const entries = zip.getEntries();
|
|
376
|
+
if (!entries.length) throw new TemplateNotFoundError(templateName, new Error('empty archive'));
|
|
377
|
+
const archiveRoot = entries[0].entryName.split('/')[0];
|
|
378
|
+
const wanted = `${archiveRoot}/examples/${templateName}/`;
|
|
379
|
+
const files = entries.filter((e)=>!e.isDirectory && e.entryName.startsWith(wanted));
|
|
380
|
+
if (!files.length) throw new TemplateNotFoundError(templateName);
|
|
381
|
+
let written = 0;
|
|
382
|
+
for (const entry of files){
|
|
383
|
+
const rel = entry.entryName.slice(wanted.length);
|
|
384
|
+
if (!rel) continue;
|
|
385
|
+
const dest = external_path_namespaceObject.join(projectPath, rel);
|
|
386
|
+
await promises_namespaceObject.mkdir(external_path_namespaceObject.dirname(dest), {
|
|
387
|
+
recursive: true
|
|
388
|
+
});
|
|
389
|
+
await promises_namespaceObject.writeFile(dest, entry.getData());
|
|
390
|
+
written++;
|
|
391
|
+
}
|
|
392
|
+
return written;
|
|
393
|
+
}
|
|
394
|
+
async function importFromExamplesCatalog(templateName, projectPath) {
|
|
395
|
+
const url = `https://codeload.github.com/extension-js/examples/zip/refs/heads/${EXAMPLES_REF}`;
|
|
396
|
+
let buffer;
|
|
397
|
+
try {
|
|
398
|
+
buffer = await downloadArchive(url, NETWORK_TIMEOUT_MS);
|
|
399
|
+
} catch (error) {
|
|
400
|
+
throw new TemplateDownloadError(templateName, error);
|
|
401
|
+
}
|
|
402
|
+
await extractExamplesTemplateFromZip(buffer, templateName, projectPath);
|
|
403
|
+
}
|
|
320
404
|
function isAuthorOrDevMode() {
|
|
321
405
|
return 'development' === process.env.EXTENSION_ENV || 'true' === process.env.EXTENSION_AUTHOR_MODE;
|
|
322
406
|
}
|
|
@@ -384,10 +468,8 @@ async function getZipSourcePath(tempPath, templateUrl) {
|
|
|
384
468
|
}
|
|
385
469
|
async function importExternalTemplate(projectPath, projectName, template, logger) {
|
|
386
470
|
const templateName = external_path_namespaceObject.basename(template);
|
|
387
|
-
const examplesUrl = 'https://github.com/extension-js/examples/tree/main/examples';
|
|
388
471
|
const resolvedTemplate = 'init' === templateName ? "javascript" : template;
|
|
389
472
|
const resolvedTemplateName = 'init' === templateName ? "javascript" : templateName;
|
|
390
|
-
const templateUrl = `${examplesUrl}/${resolvedTemplate}`;
|
|
391
473
|
const isHttp = /^https?:\/\//i.test(template);
|
|
392
474
|
const isGithub = /^https?:\/\/github\.com\//i.test(template);
|
|
393
475
|
try {
|
|
@@ -408,7 +490,22 @@ async function importExternalTemplate(projectPath, projectName, template, logger
|
|
|
408
490
|
recursive: true
|
|
409
491
|
});
|
|
410
492
|
const runGoGitIt = async (templatePath, destination)=>{
|
|
411
|
-
|
|
493
|
+
const gitEnvKeys = {
|
|
494
|
+
GIT_TERMINAL_PROMPT: '0',
|
|
495
|
+
GIT_ASKPASS: '',
|
|
496
|
+
GCM_INTERACTIVE: 'never'
|
|
497
|
+
};
|
|
498
|
+
const savedEnv = {};
|
|
499
|
+
for (const [k, v] of Object.entries(gitEnvKeys)){
|
|
500
|
+
savedEnv[k] = process.env[k];
|
|
501
|
+
process.env[k] = v;
|
|
502
|
+
}
|
|
503
|
+
try {
|
|
504
|
+
await withTimeout(withSuppressedOutput(async ()=>external_go_git_it_default()(templatePath, destination, installingFromTemplate(projectName, templateName))), NETWORK_TIMEOUT_MS, ()=>new Error(templateFetchTimedOut(templateName, NETWORK_TIMEOUT_MS)));
|
|
505
|
+
} finally{
|
|
506
|
+
for (const [k, v] of Object.entries(savedEnv))if (void 0 === v) delete process.env[k];
|
|
507
|
+
else process.env[k] = v;
|
|
508
|
+
}
|
|
412
509
|
};
|
|
413
510
|
if (isGithub) {
|
|
414
511
|
await runGoGitIt(template, tempPath);
|
|
@@ -431,18 +528,20 @@ async function importExternalTemplate(projectPath, projectName, template, logger
|
|
|
431
528
|
zip.extractAllTo(tempPath, true);
|
|
432
529
|
const sourcePath = await getZipSourcePath(tempPath, template);
|
|
433
530
|
await moveDirectoryContents(sourcePath, projectPath);
|
|
434
|
-
} else
|
|
435
|
-
await runGoGitIt(templateUrl, tempPath);
|
|
436
|
-
const srcPath = external_path_namespaceObject.join(tempPath, resolvedTemplateName);
|
|
437
|
-
await moveDirectoryContents(srcPath, projectPath);
|
|
438
|
-
}
|
|
531
|
+
} else await importFromExamplesCatalog(resolvedTemplateName, projectPath);
|
|
439
532
|
await removeTemplateScaffoldingFiles(projectPath);
|
|
440
533
|
await promises_namespaceObject.rm(tempRoot, {
|
|
441
534
|
recursive: true,
|
|
442
535
|
force: true
|
|
443
536
|
});
|
|
444
537
|
} catch (error) {
|
|
445
|
-
logger.error(
|
|
538
|
+
if (error instanceof TemplateNotFoundError) logger.error(templateNotFoundInCatalog(templateName, error.cause));
|
|
539
|
+
else if (error instanceof TemplateDownloadError) logger.error(templateDownloadFailed(templateName, error));
|
|
540
|
+
else logger.error(installingFromTemplateError(projectName, templateName, error));
|
|
541
|
+
await promises_namespaceObject.rm(projectPath, {
|
|
542
|
+
recursive: true,
|
|
543
|
+
force: true
|
|
544
|
+
}).catch(()=>{});
|
|
446
545
|
throw error;
|
|
447
546
|
}
|
|
448
547
|
}
|
|
@@ -497,9 +596,22 @@ const ML_DEP_TRIGGERS = [
|
|
|
497
596
|
'@xenova/transformers'
|
|
498
597
|
];
|
|
499
598
|
const uniq = (values)=>Array.from(new Set(values.filter(Boolean)));
|
|
599
|
+
function engineVersionOverrideFromEnv() {
|
|
600
|
+
const raw = (process.env.EXTENSION_CREATE_ENGINE_VERSION || process.env.EXTENSION_MCP_CLI_VERSION || '').trim();
|
|
601
|
+
return raw || void 0;
|
|
602
|
+
}
|
|
603
|
+
function ownCreatePackageVersion() {
|
|
604
|
+
try {
|
|
605
|
+
const pkg = JSON.parse((0, external_fs_namespaceObject.readFileSync)(external_path_namespaceObject.join(__dirname, '..', 'package.json'), 'utf8'));
|
|
606
|
+
return 'string' == typeof pkg.version && pkg.version ? pkg.version : void 0;
|
|
607
|
+
} catch {
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
500
611
|
function resolveExtensionDevDependencyVersion(cliVersion) {
|
|
501
|
-
|
|
502
|
-
|
|
612
|
+
const resolved = cliVersion || engineVersionOverrideFromEnv() || ownCreatePackageVersion();
|
|
613
|
+
if (!resolved) return 'latest';
|
|
614
|
+
return resolved.includes('-') ? resolved : `^${resolved}`;
|
|
503
615
|
}
|
|
504
616
|
async function overridePackageJson(projectPath, projectName, { template = "javascript", cliVersion }, logger) {
|
|
505
617
|
const extensionBinary = await resolveExtensionBinary();
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
export declare class TemplateNotFoundError extends Error {
|
|
2
|
+
readonly templateName: string;
|
|
3
|
+
constructor(templateName: string, cause?: unknown);
|
|
4
|
+
}
|
|
5
|
+
export declare class TemplateDownloadError extends Error {
|
|
6
|
+
readonly templateName: string;
|
|
7
|
+
constructor(templateName: string, cause: unknown);
|
|
8
|
+
}
|
|
9
|
+
export declare function extractExamplesTemplateFromZip(zipBuffer: Buffer, templateName: string, projectPath: string): Promise<number>;
|
|
1
10
|
export declare const TEMPLATE_SCAFFOLDING_FILES: string[];
|
|
2
11
|
export declare function removeTemplateScaffoldingFiles(projectPath: string): Promise<void>;
|
|
3
12
|
export declare function importExternalTemplate(projectPath: string, projectName: string, template: string, logger: {
|
package/package.json
CHANGED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
<a href="https://extension.js.org" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/badge/Powered%20by%20%7C%20Extension.js-0971fe" alt="Powered by Extension.js" align="right" /></a>
|
|
2
|
-
|
|
3
|
-
# test-template-javascript
|
|
4
|
-
|
|
5
|
-
> JavaScript-based extension with a sidebar panel. Adds a sidebar with a simple page.
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-

|
|
9
|
-
## Commands
|
|
10
|
-
|
|
11
|
-
### dev
|
|
12
|
-
|
|
13
|
-
Run the extension in development mode. Target a browser with `--browser`:
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
pnpm run dev
|
|
17
|
-
pnpm run dev -- --browser=firefox
|
|
18
|
-
pnpm run dev -- --browser=edge
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
### build
|
|
22
|
-
|
|
23
|
-
Build for production. Convenience scripts target each browser:
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
pnpm run build # Chrome (default)
|
|
27
|
-
pnpm run build:firefox
|
|
28
|
-
pnpm run build:edge
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
### preview
|
|
32
|
-
|
|
33
|
-
Preview the production build in the browser:
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
pnpm run preview
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## Learn more
|
|
40
|
-
|
|
41
|
-
[Extension.js docs](https://extension.js.org).
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/** @type {import('extension').FileConfig} */
|
|
2
|
-
// Extension.js uses a fresh profile on every run.
|
|
3
|
-
// Prefer that default? Remove the profile config below.
|
|
4
|
-
const profile = (name) => `./dist/extension-profile-${name}`
|
|
5
|
-
const ciFlags = process.env.CI ? ['--no-sandbox', '--disable-gpu'] : []
|
|
6
|
-
|
|
7
|
-
export default {
|
|
8
|
-
browser: {
|
|
9
|
-
chrome: {profile: profile('chrome'), browserFlags: ciFlags},
|
|
10
|
-
chromium: {profile: profile('chromium'), browserFlags: ciFlags},
|
|
11
|
-
edge: {profile: profile('edge'), browserFlags: ciFlags},
|
|
12
|
-
firefox: {profile: profile('firefox')},
|
|
13
|
-
'chromium-based': {
|
|
14
|
-
profile: profile('chromium-based'),
|
|
15
|
-
browserFlags: ciFlags
|
|
16
|
-
},
|
|
17
|
-
'gecko-based': {profile: profile('gecko-based')}
|
|
18
|
-
}
|
|
19
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"private": true,
|
|
3
|
-
"name": "test-template-javascript",
|
|
4
|
-
"description": "JavaScript-based extension with a sidebar panel. Adds a sidebar with a simple page.",
|
|
5
|
-
"version": "1.0.0",
|
|
6
|
-
"license": "MIT",
|
|
7
|
-
"type": "module",
|
|
8
|
-
"author": {
|
|
9
|
-
"name": "Your Name",
|
|
10
|
-
"email": "your@email.com",
|
|
11
|
-
"url": "https://yourwebsite.com"
|
|
12
|
-
},
|
|
13
|
-
"scripts": {
|
|
14
|
-
"dev": "extension dev",
|
|
15
|
-
"start": "extension start",
|
|
16
|
-
"build": "extension build",
|
|
17
|
-
"preview": "extension preview",
|
|
18
|
-
"build:chrome": "extension build --browser chrome",
|
|
19
|
-
"build:firefox": "extension build --browser firefox",
|
|
20
|
-
"build:edge": "extension build --browser edge"
|
|
21
|
-
},
|
|
22
|
-
"dependencies": {},
|
|
23
|
-
"devDependencies": {
|
|
24
|
-
"extension": "latest"
|
|
25
|
-
},
|
|
26
|
-
"packageManager": "pnpm@10.28.0",
|
|
27
|
-
"pnpm": {
|
|
28
|
-
"ignoredBuiltDependencies": [
|
|
29
|
-
"less"
|
|
30
|
-
]
|
|
31
|
-
}
|
|
32
|
-
}
|
|
Binary file
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
console.log(
|
|
2
|
-
'[From the background context] Hello from the background worker/script!'
|
|
3
|
-
)
|
|
4
|
-
|
|
5
|
-
const isFirefoxLike =
|
|
6
|
-
import.meta.env.EXTENSION_PUBLIC_BROWSER === 'firefox' ||
|
|
7
|
-
import.meta.env.EXTENSION_PUBLIC_BROWSER === 'gecko-based'
|
|
8
|
-
|
|
9
|
-
if (isFirefoxLike) {
|
|
10
|
-
browser.browserAction.onClicked.addListener(() => {
|
|
11
|
-
browser.sidebarAction.open()
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
browser.runtime.onMessage.addListener((message) => {
|
|
15
|
-
if (!message || message.type !== 'openSidebar') return
|
|
16
|
-
|
|
17
|
-
browser.sidebarAction.open()
|
|
18
|
-
})
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (!isFirefoxLike) {
|
|
22
|
-
// setPanelBehavior only affects FUTURE action clicks — registering it
|
|
23
|
-
// inside onClicked would swallow the first toolbar click.
|
|
24
|
-
chrome.sidePanel.setPanelBehavior({openPanelOnActionClick: true})
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
chrome.runtime.onMessage.addListener((message) => {
|
|
28
|
-
if (!message || message.type !== 'openSidebar') return
|
|
29
|
-
|
|
30
|
-
chrome.sidePanel.setPanelBehavior({openPanelOnActionClick: true})
|
|
31
|
-
|
|
32
|
-
if (!chrome.sidePanel.open) return
|
|
33
|
-
|
|
34
|
-
chrome.tabs.query({active: true, currentWindow: true}, (tabs) => {
|
|
35
|
-
const activeTabId = tabs && tabs[0] && tabs[0].id
|
|
36
|
-
if (!activeTabId) return
|
|
37
|
-
|
|
38
|
-
try {
|
|
39
|
-
chrome.sidePanel.open({tabId: activeTabId})
|
|
40
|
-
} catch (error) {
|
|
41
|
-
console.error(error)
|
|
42
|
-
}
|
|
43
|
-
})
|
|
44
|
-
})
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import logo from '../images/icon.png'
|
|
2
|
-
|
|
3
|
-
export default function createContentApp() {
|
|
4
|
-
const container = document.createElement('div')
|
|
5
|
-
container.className = 'content_script'
|
|
6
|
-
|
|
7
|
-
const pill = document.createElement('button')
|
|
8
|
-
pill.type = 'button'
|
|
9
|
-
pill.className = 'content_pill'
|
|
10
|
-
pill.setAttribute('aria-label', 'Open sidebar')
|
|
11
|
-
pill.addEventListener('click', () => {
|
|
12
|
-
try {
|
|
13
|
-
if (
|
|
14
|
-
import.meta.env.EXTENSION_PUBLIC_BROWSER === 'firefox' ||
|
|
15
|
-
import.meta.env.EXTENSION_PUBLIC_BROWSER === 'gecko-based'
|
|
16
|
-
) {
|
|
17
|
-
browser.runtime.sendMessage({type: 'openSidebar'})
|
|
18
|
-
} else {
|
|
19
|
-
chrome.runtime.sendMessage({type: 'openSidebar'})
|
|
20
|
-
}
|
|
21
|
-
} catch (error) {
|
|
22
|
-
console.error(error)
|
|
23
|
-
}
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
const img = document.createElement('img')
|
|
27
|
-
img.className = 'content_pill_logo'
|
|
28
|
-
img.src = logo
|
|
29
|
-
img.alt = ''
|
|
30
|
-
img.setAttribute('aria-hidden', 'true')
|
|
31
|
-
|
|
32
|
-
const text = document.createElement('span')
|
|
33
|
-
text.className = 'content_pill_text'
|
|
34
|
-
text.textContent = 'Open sidebar'
|
|
35
|
-
|
|
36
|
-
pill.appendChild(img)
|
|
37
|
-
pill.appendChild(text)
|
|
38
|
-
container.appendChild(pill)
|
|
39
|
-
|
|
40
|
-
return container
|
|
41
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import createContentApp from './ContentApp.js'
|
|
2
|
-
import './styles.css'
|
|
3
|
-
|
|
4
|
-
console.log('[From the page context] Hello from content_scripts!')
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Extension.js content_script entrypoint. The framework calls this on
|
|
8
|
-
* injection and calls the returned function on HMR/teardown to clean up.
|
|
9
|
-
* Do not invoke it yourself.
|
|
10
|
-
*/
|
|
11
|
-
export default function initial() {
|
|
12
|
-
const rootDiv = document.createElement('div')
|
|
13
|
-
rootDiv.setAttribute('data-extension-root', 'true')
|
|
14
|
-
// Isolate the host from page styles (e.g. example.com ships div{opacity:.8},
|
|
15
|
-
// which would otherwise fade the whole widget): the shadow DOM only protects
|
|
16
|
-
// descendants; the host element itself still takes page CSS.
|
|
17
|
-
rootDiv.style.cssText = 'all: initial !important'
|
|
18
|
-
document.body.appendChild(rootDiv)
|
|
19
|
-
|
|
20
|
-
// Injecting content_scripts inside a shadow dom
|
|
21
|
-
// prevents conflicts with the host page's styles.
|
|
22
|
-
// This way, styles from the extension won't leak into the host page.
|
|
23
|
-
const shadowRoot = rootDiv.attachShadow({mode: 'open'})
|
|
24
|
-
|
|
25
|
-
const styleElement = document.createElement('style')
|
|
26
|
-
shadowRoot.appendChild(styleElement)
|
|
27
|
-
|
|
28
|
-
fetchCSS().then((response) => (styleElement.textContent = response))
|
|
29
|
-
|
|
30
|
-
// Render ContentApp inside shadow root
|
|
31
|
-
const container = createContentApp()
|
|
32
|
-
shadowRoot.appendChild(container)
|
|
33
|
-
|
|
34
|
-
return () => {
|
|
35
|
-
rootDiv.remove()
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async function fetchCSS() {
|
|
40
|
-
const cssUrl = new URL('./styles.css', import.meta.url)
|
|
41
|
-
const response = await fetch(cssUrl)
|
|
42
|
-
const text = await response.text()
|
|
43
|
-
return response.ok ? text : Promise.reject(text)
|
|
44
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
.content_script {
|
|
2
|
-
position: absolute;
|
|
3
|
-
right: 0.75rem;
|
|
4
|
-
bottom: 0.75rem;
|
|
5
|
-
z-index: 9999;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
.content_pill {
|
|
9
|
-
-webkit-font-smoothing: antialiased;
|
|
10
|
-
-moz-osx-font-smoothing: grayscale;
|
|
11
|
-
appearance: none;
|
|
12
|
-
border: none;
|
|
13
|
-
outline: none;
|
|
14
|
-
cursor: pointer;
|
|
15
|
-
display: inline-flex;
|
|
16
|
-
align-items: center;
|
|
17
|
-
gap: 0.5rem;
|
|
18
|
-
background: var(--sidebar-bg, #0a0c10);
|
|
19
|
-
color: var(--sidebar-text, #c9c9c9);
|
|
20
|
-
padding: 0.5rem 1rem 0.5rem 0.5rem;
|
|
21
|
-
border-radius: 9999px;
|
|
22
|
-
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
.content_pill:hover {
|
|
26
|
-
background: #11151c;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
.content_pill_logo {
|
|
30
|
-
height: 1.5rem;
|
|
31
|
-
border-radius: 9999px;
|
|
32
|
-
background: rgba(255, 255, 255, 0.08);
|
|
33
|
-
object-fit: contain;
|
|
34
|
-
aspect-ratio: 1 / 1;
|
|
35
|
-
padding: 0.125rem;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.content_pill_text {
|
|
39
|
-
font-size: 0.85rem;
|
|
40
|
-
font-weight: 600;
|
|
41
|
-
line-height: 1;
|
|
42
|
-
font-family:
|
|
43
|
-
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
|
|
44
|
-
Arial, "Noto Sans", sans-serif;
|
|
45
|
-
}
|
|
Binary file
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://json.schemastore.org/chrome-manifest.json",
|
|
3
|
-
"chromium:manifest_version": 3,
|
|
4
|
-
"firefox:manifest_version": 2,
|
|
5
|
-
"version": "1.0.0",
|
|
6
|
-
"name": "test-template-javascript",
|
|
7
|
-
"description": "JavaScript-based extension with a sidebar panel. Adds a sidebar with a simple page.",
|
|
8
|
-
"icons": {
|
|
9
|
-
"16": "images/icon.png",
|
|
10
|
-
"32": "images/icon.png",
|
|
11
|
-
"48": "images/icon.png",
|
|
12
|
-
"64": "images/icon.png",
|
|
13
|
-
"128": "images/icon.png"
|
|
14
|
-
},
|
|
15
|
-
"chromium:action": {
|
|
16
|
-
"default_icon": {
|
|
17
|
-
"16": "images/icon.png",
|
|
18
|
-
"32": "images/icon.png",
|
|
19
|
-
"48": "images/icon.png",
|
|
20
|
-
"64": "images/icon.png",
|
|
21
|
-
"128": "images/icon.png"
|
|
22
|
-
},
|
|
23
|
-
"default_title": "Open Side Panel"
|
|
24
|
-
},
|
|
25
|
-
"firefox:browser_action": {
|
|
26
|
-
"default_icon": {
|
|
27
|
-
"16": "images/icon.png",
|
|
28
|
-
"32": "images/icon.png",
|
|
29
|
-
"48": "images/icon.png",
|
|
30
|
-
"64": "images/icon.png",
|
|
31
|
-
"128": "images/icon.png"
|
|
32
|
-
},
|
|
33
|
-
"default_title": "Open Side Panel"
|
|
34
|
-
},
|
|
35
|
-
"chromium:side_panel": {
|
|
36
|
-
"default_path": "sidebar/index.html",
|
|
37
|
-
"default_title": "Side Panel Content"
|
|
38
|
-
},
|
|
39
|
-
"firefox:sidebar_action": {
|
|
40
|
-
"default_panel": "sidebar/index.html",
|
|
41
|
-
"default_title": "Side Panel Content"
|
|
42
|
-
},
|
|
43
|
-
"chromium:permissions": [
|
|
44
|
-
"sidePanel"
|
|
45
|
-
],
|
|
46
|
-
"background": {
|
|
47
|
-
"chromium:service_worker": "background.js",
|
|
48
|
-
"firefox:scripts": [
|
|
49
|
-
"background.js"
|
|
50
|
-
]
|
|
51
|
-
},
|
|
52
|
-
"content_scripts": [
|
|
53
|
-
{
|
|
54
|
-
"matches": [
|
|
55
|
-
"<all_urls>"
|
|
56
|
-
],
|
|
57
|
-
"js": [
|
|
58
|
-
"content/scripts.js"
|
|
59
|
-
]
|
|
60
|
-
}
|
|
61
|
-
],
|
|
62
|
-
"author": "Your Name"
|
|
63
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import './styles.css'
|
|
2
|
-
import javascriptLogo from '../images/icon.png'
|
|
3
|
-
|
|
4
|
-
function SidebarApp() {
|
|
5
|
-
const root = document.getElementById('root')
|
|
6
|
-
if (!root) return
|
|
7
|
-
|
|
8
|
-
root.innerHTML = `
|
|
9
|
-
<div class="sidebar_app">
|
|
10
|
-
<img
|
|
11
|
-
class="sidebar_logo"
|
|
12
|
-
src="${javascriptLogo}"
|
|
13
|
-
alt="The JavaScript logo"
|
|
14
|
-
/>
|
|
15
|
-
<h1 class="sidebar_title">Sidebar Panel</h1>
|
|
16
|
-
<p class="sidebar_description">
|
|
17
|
-
Learn more in the
|
|
18
|
-
<a
|
|
19
|
-
href="https://extension.js.org"
|
|
20
|
-
target="_blank" rel="noopener noreferrer"
|
|
21
|
-
>Extension.js docs</a>
|
|
22
|
-
.
|
|
23
|
-
</p>
|
|
24
|
-
</div>
|
|
25
|
-
`
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
SidebarApp()
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
-
<title>JavaScript Sidebar</title>
|
|
7
|
-
</head>
|
|
8
|
-
<body>
|
|
9
|
-
<noscript>You need to enable JavaScript to run this extension.</noscript>
|
|
10
|
-
<div id="root"></div>
|
|
11
|
-
</body>
|
|
12
|
-
<script src="./scripts.js"></script>
|
|
13
|
-
</html>
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/* @import 'sakura.css'; */
|
|
2
|
-
|
|
3
|
-
:root {
|
|
4
|
-
--sidebar-margin: 1rem;
|
|
5
|
-
--sidebar-bg: #0a0c10;
|
|
6
|
-
--sidebar-text: #c9c9c9;
|
|
7
|
-
--sidebar-link: #e5e7eb;
|
|
8
|
-
--sidebar-border: #c9c9c9;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
body {
|
|
12
|
-
background-color: var(--sidebar-bg);
|
|
13
|
-
color: var(--sidebar-text);
|
|
14
|
-
height: 100vh;
|
|
15
|
-
margin: var(--sidebar-margin);
|
|
16
|
-
border-radius: 6px;
|
|
17
|
-
display: flex;
|
|
18
|
-
justify-content: center;
|
|
19
|
-
align-items: center;
|
|
20
|
-
overflow: hidden;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.sidebar_app {
|
|
24
|
-
display: flex;
|
|
25
|
-
flex-direction: column;
|
|
26
|
-
align-items: center;
|
|
27
|
-
padding: 0 1rem;
|
|
28
|
-
text-align: center;
|
|
29
|
-
max-height: 100vh;
|
|
30
|
-
overflow-y: auto;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
.sidebar_logo {
|
|
34
|
-
width: 72px;
|
|
35
|
-
margin: 0 auto 1rem;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.sidebar_title {
|
|
39
|
-
font-size: 1.85em;
|
|
40
|
-
line-height: 1.1;
|
|
41
|
-
font-family:
|
|
42
|
-
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
|
|
43
|
-
Arial, "Noto Sans", sans-serif;
|
|
44
|
-
font-weight: 700;
|
|
45
|
-
margin: 0;
|
|
46
|
-
text-align: center;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
.sidebar_description {
|
|
50
|
-
font-size: small;
|
|
51
|
-
margin: 0.5rem 0 0;
|
|
52
|
-
text-align: center;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
.sidebar_description a {
|
|
56
|
-
text-decoration: none;
|
|
57
|
-
border-bottom: 2px solid var(--sidebar-border);
|
|
58
|
-
color: var(--sidebar-link);
|
|
59
|
-
margin: 0;
|
|
60
|
-
}
|