Skip to content

Commit

Permalink
Add Side Panel support (#45)
Browse files Browse the repository at this point in the history
  • Loading branch information
dutiyesh committed Sep 18, 2023
1 parent 95c92b4 commit 11d66aa
Show file tree
Hide file tree
Showing 17 changed files with 488 additions and 1 deletion.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,17 @@ Add features to Chrome Developer Tools.
</figure>
</div>


### Side Panel

Add features to Chrome Side Panel.

<div align="center">
<figure>
<img width="500" height="322" src="./assets/template-side-panel.png" alt="Side Panel template">
</figure>
</div>

More information about [templates](templates/README.md).

## CLI options
Expand All @@ -187,6 +198,10 @@ chrome-extension-cli my-extension --override-page=history // Override Histo

Creates a Panel inside developer tools.

#### `chrome-extension-cli my-extension --side-panel`

Creates a Panel in the browser's side panel alongside the main content of a webpage.

#### `chrome-extension-cli my-extension --language`

Creates an extension for supported languages like JavaScript and TypeScript.<br>
Expand Down
Binary file added assets/template-side-panel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 12 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const program = new commander.Command(packageFile.name)
'override default page like New Tab, Bookmarks, or History page'
)
.option('--devtools', 'add features to Chrome Developer Tools')
.option('--side-panel', 'add features to Chrome Side Panel')
.option(
'--language [language-name]',
'language like JavaScript and TypeScript'
Expand Down Expand Up @@ -134,7 +135,7 @@ function logOptionsConflictError() {
process.exit(1);
}

function createExtension(name, { overridePage, devtools, language }) {
function createExtension(name, { overridePage, devtools, sidePanel, language }) {
const root = path.resolve(name);
let overridePageName;
let languageName = 'javascript';
Expand Down Expand Up @@ -247,6 +248,8 @@ function createExtension(name, { overridePage, devtools, language }) {
templateName = 'override-page';
} else if (devtools) {
templateName = 'devtools';
} else if (sidePanel) {
templateName = 'side-panel';
} else {
templateName = 'popup';
}
Expand Down Expand Up @@ -335,6 +338,13 @@ function createExtension(name, { overridePage, devtools, language }) {
appManifest = Object.assign({}, appManifest, {
devtools_page: 'devtools.html',
});
} else if (sidePanel) {
appManifest = Object.assign({}, appManifest, {
side_panel: {
default_path: 'sidepanel.html',
},
permissions: ['sidePanel', 'tabs'],
});
} else {
appManifest = Object.assign({}, appManifest, {
action: {
Expand Down Expand Up @@ -398,5 +408,6 @@ function createExtension(name, { overridePage, devtools, language }) {
createExtension(projectName, {
overridePage: program.overridePage,
devtools: program.devtools,
sidePanel: program.sidePanel,
language: program.language,
});
15 changes: 15 additions & 0 deletions templates/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,18 @@ With DevTools extension you can add new features to Chrome Developer Tools.
</figcaption>
</figure>
</div>

---

## Side Panel

With Side Panel extension you can add new features to Chrome Side Panel.

<div align="center">
<figure>
<img width="600" height="386" src="../assets/template-side-panel.png" alt="Side Panel template">
<figcaption>
<p>A side panel extension that provides a list of all open tabs in active window.</p>
</figcaption>
</figure>
</div>
18 changes: 18 additions & 0 deletions templates/javascript/side-panel/config/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use strict';

const { merge } = require('webpack-merge');

const common = require('./webpack.common.js');
const PATHS = require('./paths');

// Merge webpack configuration files
const config = (env, argv) =>
merge(common, {
entry: {
sidepanel: PATHS.src + '/sidepanel.js',
background: PATHS.src + '/background.js',
},
devtool: argv.mode === 'production' ? false : 'source-map',
});

module.exports = config;
20 changes: 20 additions & 0 deletions templates/javascript/side-panel/src/background.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict';

// With background scripts you can communicate with sidepanel
// and contentScript files.
// For more information on background script,
// See https://developer.chrome.com/extensions/background_pages

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.type === 'GREETINGS') {
const message =
"Hi Syd, my name is Bac. I am from Background. It's great to hear from you.";

// Log message coming from the `request` parameter
console.log(request.payload.message);
// Send a response message
sendResponse({
message,
});
}
});
95 changes: 95 additions & 0 deletions templates/javascript/side-panel/src/sidepanel.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/* normalize css starts here */
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}

ul {
list-style: none;
}
/* normalize css ends here */

html {
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial,
sans-serif;
color: #222;
}

.app {
height: 100%;
text-align: left;
padding: 20px;
}

.app-heading {
font-size: 20px;
font-weight: 700;
}

.tabs-list {
margin: 15px -8px;
}

.tab-container {
display: flex;
align-items: center;
padding: 8px;
cursor: pointer;
border-radius: 4px;
}

.tab-container:hover {
background-color: #fafafa;
}

.tab-image {
width: 20px;
height: 20px;
margin-right: 8px;
flex-shrink: 0;
}

.tab-image-placeholder {
font-size: 22px;
color: #555;
display: inline-flex;
align-items: center;
justify-content: center;
}

.tab-title {
font-size: 14px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}

.title {
font-size: 18px;
font-weight: 600;
margin-bottom: 10px;
text-align: center;
}

.subtitle {
font-size: 12px;
text-align: center;
}

code {
font-size: 12px;
font-family: inherit;
background-color: rgba(254, 237, 185, 0.3);
padding: 2px 4px;
border-radius: 2px;
}

.divider {
margin: 30px auto 25px;
width: 50px;
border: 0.5px dashed #000;
opacity: 0.1;
}
74 changes: 74 additions & 0 deletions templates/javascript/side-panel/src/sidepanel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
'use strict';

import './sidepanel.css';

(function () {
function initList(tabs) {
const list = document.getElementById('tabs-list');

const listItem = tabs.map((tab) => {
return `
<li>
<div data-tab-id="${tab.id}" class="tab-container">
${
tab.favIconUrl
? `<img src="${tab.favIconUrl}" alt="" class="tab-image" />`
: '<span class="tab-image tab-image-placeholder">&#x2750;</span>'
}
<p class="tab-title" title="${tab.title}">${tab.title}</p>
</div>
</li>
`;
});

list.innerHTML = listItem.join('\n');

list.addEventListener('click', (event) => {
if (event.target && event.target.closest('.tab-container')) {
const tabId = event.target
.closest('.tab-container')
.getAttribute('data-tab-id');

chrome.tabs.update(Number(tabId), {
active: true,
});
}
});
}

function setupTabList() {
chrome.tabs.query(
{
currentWindow: true,
},
(tabs) => {
initList(tabs);
}
);
}

function setupTabListeners() {
chrome.tabs.onCreated.addListener(setupTabList);
chrome.tabs.onMoved.addListener(setupTabList);
chrome.tabs.onRemoved.addListener(setupTabList);
chrome.tabs.onUpdated.addListener(setupTabList);
}

document.addEventListener('DOMContentLoaded', () => {
setupTabList();
setupTabListeners();
});

// Communicate with background file by sending a message
chrome.runtime.sendMessage(
{
type: 'GREETINGS',
payload: {
message: 'Hello, my name is Syd. I am from SidePanel.',
},
},
(response) => {
console.log(response.message);
}
);
})();
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added templates/shared/side-panel/public/icons/icon_16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 29 additions & 0 deletions templates/shared/side-panel/public/sidepanel.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>My Sidepanel</title>
<link rel="stylesheet" href="sidepanel.css" />
</head>
<body>
<div class="app">
<p class="app-heading">Tabs</p>

<ul id="tabs-list" class="tabs-list"></ul>

<hr class="divider" />

<p class="title">Chrome Extension is Ready!</p>
<p class="subtitle">Start by updating <code>sidepanel.html</code></p>
</div>

<script src="sidepanel.js"></script>

<!--
This HTML file opens when you click on icon from the toolbar.
To begin the development, run `npm run watch`.
To create a production bundle, use `npm run build`.
-->
</body>
</html>
18 changes: 18 additions & 0 deletions templates/typescript/side-panel/config/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use strict';

const { merge } = require('webpack-merge');

const common = require('./webpack.common.js');
const PATHS = require('./paths');

// Merge webpack configuration files
const config = (env, argv) =>
merge(common, {
entry: {
sidepanel: PATHS.src + '/sidepanel.ts',
background: PATHS.src + '/background.ts',
},
devtool: argv.mode === 'production' ? false : 'source-map',
});

module.exports = config;
20 changes: 20 additions & 0 deletions templates/typescript/side-panel/src/background.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict';

// With background scripts you can communicate with sidepanel
// and contentScript files.
// For more information on background script,
// See https://developer.chrome.com/extensions/background_pages

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.type === 'GREETINGS') {
const message: string =
"Hi Syd, my name is Bac. I am from Background. It's great to hear from you.";

// Log message coming from the `request` parameter
console.log(request.payload.message);
// Send a response message
sendResponse({
message,
});
}
});
Loading

0 comments on commit 11d66aa

Please sign in to comment.