From b4e1073347ba9a662381ee3774a48eb021b3edb0 Mon Sep 17 00:00:00 2001
From: martrend33 <145278472+martrend33@users.noreply.github.com>
Date: Tue, 9 Jun 2026 16:52:13 -0600
Subject: [PATCH 1/7] Add GitHub Chat extension manifest
---
manifest.json | 60 ++++++++++++++++++++++++---------------------------
1 file changed, 28 insertions(+), 32 deletions(-)
diff --git a/manifest.json b/manifest.json
index db0a183..1fc952e 100644
--- a/manifest.json
+++ b/manifest.json
@@ -1,36 +1,32 @@
+
{
- "name": "GitHub Stories",
- "version": "0.1",
- "description": "Stories on GitHub",
- "permissions": [
- "activeTab",
- "declarativeContent",
- "storage"
- ],
- "background": {
- "scripts": [
- "background.js"
+
+ "name": "GitHub Chat",
+ "version": "0.2.0",
+ "description": "Open GitHub Chat from any GitHub page.",
+ "manifest_version": 3,
+ "permissions": [
+ "storage"
],
- "persistent": false
- },
- "page_action": {},
- "content_scripts": [
- {
- "matches": [
- "https://github.com/",
- "https://github.com/orgs/*"
- ],
- "js": [
- "content-script.js"
- ],
- "css": [
- "story-list.css",
- "story-view.css"
- ]
+ "host_permissions": [
+ "https://github.com/*"
+ ],
+ "content_scripts": [
+ {
+ "matches": [
+ "https://github.com/*"
+ ],
+ "js": [
+ "content-script.js"
+ ],
+ "css": [
+ "github-chat.css"
+ ],
+ "run_at": "document_idle"
+ }
+ ],
+ "options_ui": {
+ "page": "options.html",
+ "open_in_tab": false
}
- ],
- "icons": {
- "128": "github-stories.png"
- },
- "manifest_version": 2
}
From 70547e008581b1ea1574ae61d5a86ba0a0b268e9 Mon Sep 17 00:00:00 2001
From: martrend33 <145278472+martrend33@users.noreply.github.com>
Date: Tue, 9 Jun 2026 16:53:32 -0600
Subject: [PATCH 2/7] Update README.mdDocument GitHub Chat extension
---
README.md | 45 ++++++++++++++++-----------------------------
1 file changed, 16 insertions(+), 29 deletions(-)
diff --git a/README.md b/README.md
index 0af0dd3..384f00b 100644
--- a/README.md
+++ b/README.md
@@ -1,29 +1,16 @@
-# GitHub Stories
-
-View stories on your GitHub dashboard.
-
-No uploads required. Just [install](#how-to-install) and visit [github.com](https://github.com).
-
-
-
-## How to Install
-
-1. [Download ZIP](https://github.com/inquid/github-stories/archive/master.zip) and unzip on your computer.
-
-2. Visit `chrome://extensions` (or click Menu -> Tools -> Extensions).
-
-3. Enable Developer mode by ticking the checkbox in the upper-right corner.
-
-4. Click on the "Load unpacked" button in the top-left corner.
-
-5. Select the downloaded folder.
-
-## Frequently Asked Questions
-
-**Q: Why?**
-
-Why not?
-
-## Disclaimer
-
-Free, fun side project. Not affiliated with GitHub.
+ GitHub Chat Extension
+
+ This Chrome extension adds a small chat toggle to the lower-right corner of every `github.com/*` page. Opening the toggle displays GitHub Chat in an iframe when the configured chat endpoint allows embedding, and passes the current GitHub URL as `github_url`.
+
+ ## Install locally
+
+ 1. Open `chrome://extensions`.
+ 2. 2. Enable Developer mode.
+ 3. 3. Click "Load unpacked".
+ 4. 4. Select this folder.
+ 5. 5. Visit any `https://github.com/*` page and click the "Chat" button.
+
+ 6. ## Configure the chat endpoint
+
+ 7. The default chat endpoint is `https://github-chat.com/`. That host currently blocks iframe embedding, so the extension shows an "Open Chat" fallback for the default URL. To use an embeddable chat endpoint, open the extension details page, select "Extension options", and save the preferred chat URL.
+ 8.
From a8913cc2b72470841910fe043d23e1572f9dc03c Mon Sep 17 00:00:00 2001
From: martrend33 <145278472+martrend33@users.noreply.github.com>
Date: Tue, 9 Jun 2026 16:56:24 -0600
Subject: [PATCH 3/7] Update content-script.jsAdd GitHub Chat toggle content
script
---
content-script.js | 475 ++++++++++------------------------------------
1 file changed, 95 insertions(+), 380 deletions(-)
diff --git a/content-script.js b/content-script.js
index 78cdb14..67d496d 100644
--- a/content-script.js
+++ b/content-script.js
@@ -1,397 +1,112 @@
-let tries = 0;
-
-let stories;
-let storyList = [];
-let storyViewIntervalId = null;
-let progressBarIntervalId = null;
-let automaticSliderIntervalId = null;
-
-const emojis = {
- added: '👋',
- made: '➕',
- starred: '⭐',
- 'pushed to': '🚀',
- 'started following': '🚶',
- forked: '🤓',
- deleted: '❌',
- 'commented on': '💬',
- left: '💬',
- created: '🏁',
- closed: '🚫',
- opened: '✨',
- merged: '📦',
- released: '🏷',
- bot: '🤖'
-};
-
-let time = 200;
-const AUTOMATIC_SCROLL_DELAY = 4200;
-const PROGRESS_BAR_UPDATE_DELAY = 100;
-const UPDATE_PROGRESS_BAR_VALUE =
- time / (AUTOMATIC_SCROLL_DELAY / PROGRESS_BAR_UPDATE_DELAY - 5);
-let storyViewOpen = false;
-
-function getActionFullText(element){
- let fullText = '';
-
- if(element.getElementsByClassName('repo-description')[0] != null){
- fullText += ' ' + element.getElementsByClassName('repo-description')[0].innerText;
- }
-
- if(element.getElementsByClassName('rpt-1')[0] != null){
- fullText += ' ' + element.getElementsByClassName('pt-1')[0].innerText;
- }
-
- console.log(element);
-
- return fullText;
+onst DEFAULT_CHAT_URL = 'https://github-chat.com/';
+const STORAGE_KEY = 'githubChatUrl';
+const ROOT_ID = 'github-chat-extension-root';
+
+function buildChatUrl(baseUrl) {
+ const url = new URL(baseUrl);
+ url.searchParams.set('source', 'extension');
+ url.searchParams.set('github_url', window.location.href);
+ return url.toString();
+}
+
+function shouldUseFallback(baseUrl) {
+ try {
+ return new URL(baseUrl).hostname === 'github-chat.com';
+ } catch (error) {
+ return true;
+ }
}
-const handle = setInterval(() => {
- let dashboardCards;
- try {
- dashboardCards = document
- .getElementById('dashboard')
- .querySelector(
- 'div[data-repository-hovercards-enabled]:not(.js-recent-activity-container)',
- ).children;
- } catch (error) {
- if (tries++ === 20) {
- clearInterval(handle);
- return;
- }
- return;
+function createChatFrame(chatUrl) {
+ const useFallback = shouldUseFallback(chatUrl);
+ const root = document.createElement('div');
+ root.id = ROOT_ID;
+ root.className = 'github-chat-extension is-collapsed';
+
+ const toggle = document.createElement('button');
+ toggle.type = 'button';
+ toggle.className = 'github-chat-extension__toggle';
+ toggle.setAttribute('aria-expanded', 'false');
+ toggle.setAttribute('aria-controls', 'github-chat-extension-panel');
+ toggle.textContent = 'Chat';
+
+ const panel = document.createElement('section');
+ panel.id = 'github-chat-extension-panel';
+ panel.className = 'github-chat-extension__panel';
+ panel.setAttribute('aria-label', 'GitHub Chat');
+
+ const header = document.createElement('div');
+ header.className = 'github-chat-extension__header';
+ header.textContent = 'GitHub Chat';
+
+ const close = document.createElement('button');
+ close.type = 'button';
+ close.className = 'github-chat-extension__close';
+ close.setAttribute('aria-label', 'Close GitHub Chat');
+ close.textContent = 'x';
+
+ const iframe = document.createElement('iframe');
+ iframe.className = 'github-chat-extension__frame';
+ iframe.src = buildChatUrl(chatUrl);
+ iframe.title = 'GitHub Chat';
+ iframe.loading = 'lazy';
+ iframe.referrerPolicy = 'strict-origin-when-cross-origin';
+ iframe.setAttribute('allow', 'clipboard-read; clipboard-write');
+
+ const fallback = document.createElement('div');
+ fallback.className = 'github-chat-extension__fallback';
+
+ const fallbackMessage = document.createElement('p');
+ fallbackMessage.textContent = 'This chat endpoint cannot be embedded on GitHub.';
+
+ const fallbackLink = document.createElement('a');
+ fallbackLink.className = 'github-chat-extension__fallback-link';
+ fallbackLink.href = buildChatUrl(chatUrl);
+ fallbackLink.target = '_blank';
+ fallbackLink.rel = 'noopener noreferrer';
+ fallbackLink.textContent = 'Open Chat';
+
+ fallback.append(fallbackMessage, fallbackLink);
+
+ if (useFallback) {
+ fallback.classList.add('is-visible');
}
- clearInterval(handle);
- stories = Array.prototype.slice
- .call(dashboardCards)
- .filter((element) => element.nodeName === 'DIV')
- .map((element) => {
- const [userName, action, repoOrUserName] = element.textContent
- .split('\n')
- .map((str) => str.trim())
- .filter((str) => str !== '');
-
- const themeID = Math.floor(Math.random() * 18); // 0 - 17
-
- let userImageUrl = 'https://image.flaticon.com/icons/png/512/25/25231.png';
- if(element.querySelector('.avatar.avatar-user')!=null){
- userImageUrl = element.querySelector('.avatar.avatar-user').src;
- }
+ const fallbackTimer = window.setTimeout(() => {
+ fallback.classList.add('is-visible');
+ }, 2500);
- let actionFull = getActionFullText(element);
-
- return {
- userImageURL: userImageUrl,
- userName,
- action,
- actionFull,
- repoOrUserName,
- repoOrUserURL: getGithubURL(repoOrUserName),
- themeID,
- };
- })
- .filter(
- (story) =>
- story.action !== 'created a' &&
- !story.action.includes('and') &&
- !story.repoOrUserName.includes('repositories'),
- );
-
- const batchStories = [];
- stories.forEach((story) => {
- let index = 0;
- const belongsToBatch = batchStories.some((batchStory, idx) => {
- if (batchStory[0].userName === story.userName) {
- index = idx;
- return true;
- }
- });
- if (belongsToBatch) {
- batchStories[index].push(story);
- } else {
- batchStories.push([story]);
- }
+ iframe.addEventListener('load', () => {
+ if (!useFallback) {
+ window.clearTimeout(fallbackTimer);
+ }
});
- storyList = [...batchStories];
-
- const storyListView = getStoryListView({ stories: storyList });
- document.querySelector('.news').prepend(getStoryViewer());
- document.querySelector('.news').prepend(storyListView);
-}, 1000);
-
-function onClickStoryBtn(event) {
- const path = event.path;
- const buttonElem = path.find((element) => element.className === 'user-story');
- const storyID = buttonElem.getAttribute('story-id');
-
- const batchStory = storyList[storyID];
- updateSingleStoryView(batchStory[0], storyID, 0);
-}
-
-function getStoryListView({ stories }) {
- const storyListWrapperElem = document.createElement('div');
- storyListWrapperElem.classList.add('stories-list-wrapper');
-
- const storyListElement = document.createElement('div');
- storyListElement.classList.add('stories-list');
-
- stories.forEach((singleStoryBatch, index) => {
- let story = singleStoryBatch[0];
-
- const userStoryElem = document.createElement('div');
- userStoryElem.classList.add('user-story');
- userStoryElem.setAttribute('story-id', index);
-
- {
- const btnElem = document.createElement('button');
- btnElem.innerHTML = `
-

-
-${story.userName}
`;
- btnElem.addEventListener('click', onClickStoryBtn);
- userStoryElem.appendChild(btnElem);
- }
+ function setOpen(isOpen) {
+ root.classList.toggle('is-collapsed', !isOpen);
+ toggle.setAttribute('aria-expanded', String(isOpen));
+ }
- storyListElement.appendChild(userStoryElem);
+ toggle.addEventListener('click', () => {
+ setOpen(root.classList.contains('is-collapsed'));
});
- storyListWrapperElem.appendChild(storyListElement);
-
- return storyListWrapperElem;
-}
-
-function getGithubURL(resource) {
- return `https://github.com/${resource}`;
-}
-
-function pause() {
- //alert();
-}
-
-function getStoryViewer() {
- const storyViewWrapperElem = document.createElement('div');
- storyViewWrapperElem.classList.add('story-view-wrapper', 'hidden');
- storyViewWrapperElem.addEventListener("click", function(event) {
- pause();
+ close.addEventListener('click', () => {
+ setOpen(false);
});
- storyViewWrapperElem.innerHTML = `
-
-
-
-
-
-
-
-
-
-
-
-
-`;
-
- const storyViewerCloseBtn = storyViewWrapperElem.querySelector(
- '.story-view-close-btn',
- );
- const storyViewPrevBtn = storyViewWrapperElem.querySelector(
- '.story-view-prev',
- );
- const storyViewNextBtn = storyViewWrapperElem.querySelector(
- '.story-view-next',
- );
-
- storyViewerCloseBtn.addEventListener('click', handleCloseStoryViewerBtnClick);
- storyViewPrevBtn.addEventListener('click', handleStoryViewPrevBtnClick);
- storyViewNextBtn.addEventListener('click', handleStoryViewNextBtnClick);
-
- document.addEventListener('keyup', onPressKey);
- window.addEventListener('resize', updateStoryViewWidth);
-
- return storyViewWrapperElem;
-}
-
-function updateStoryViewWidth() {
- const storyViewElem = document.querySelector('.story-view');
- const { height } = storyViewElem.getBoundingClientRect();
- storyViewElem.style.width = `${height / 1.77}px`;
+ header.appendChild(close);
+ panel.append(header, fallback, iframe);
+ root.append(toggle, panel);
+ document.body.appendChild(root);
}
-function onPressKey(event) {
- if (storyViewOpen) {
- switch (event.key) {
- case 'Escape':
- closeStoryView();
- break;
- case 'ArrowLeft':
- handleStoryViewPrevBtnClick();
- break;
- case 'ArrowRight':
- handleStoryViewNextBtnClick();
- break;
- }
- }
-}
-
-function moveSlide(story, storyID, storyIndex) {
- updateSingleStoryView(story, storyID, storyIndex);
-}
-
-function moveToNextSlide(storyID, storyIndex) {
- if (storyIndex + 1 >= storyList[storyID].length) {
- storyID++;
- storyIndex = 0;
- } else storyIndex++;
-
- if (storyID >= storyList.length) return;
-
- moveSlide(storyList[storyID][storyIndex], storyID, storyIndex);
-}
-function moveToPrevSlide(storyID, storyIndex) {
- if (storyIndex - 1 < 0) {
- storyID--;
- storyIndex = 0;
- } else storyIndex--;
- if (storyID < 0) return;
-
- moveSlide(storyList[storyID][storyIndex], storyID, storyIndex);
-}
+function init() {
+ if (document.getElementById(ROOT_ID)) return;
-function handleStoryViewNextBtnClick() {
- const storyViewer = document.querySelector('.story-view-wrapper');
- let storyID = parseInt(storyViewer.getAttribute('story-id'));
- let storyIndex = parseInt(storyViewer.getAttribute('story-index'));
-
- moveToNextSlide(storyID, storyIndex);
-}
-
-function handleStoryViewPrevBtnClick() {
- const storyViewer = document.querySelector('.story-view-wrapper');
- let storyID = storyViewer.getAttribute('story-id');
- let storyIndex = storyViewer.getAttribute('story-index');
-
- moveToPrevSlide(storyID, storyIndex);
-}
-
-function handleCloseStoryViewerBtnClick() {
- closeStoryView();
-}
-
-function closeStoryView() {
- document.querySelector('.story-view-wrapper').classList.add('hidden');
- clearInterval(storyViewIntervalId);
- clearInterval(progressBarIntervalId);
- storyViewOpen = false;
-}
-
-function automaticSlideScrolling() {
- if (storyViewIntervalId) clearInterval(storyViewIntervalId);
- if (progressBarIntervalId) clearInterval(progressBarIntervalId);
- handleStoryViewNextBtnClick();
-}
-
-function updateProgressBarProgress() {
- const progressBar = document.querySelector('.ex-progress-bar')
- .firstElementChild;
- const currValue = parseInt(progressBar.getAttribute('value'));
- progressBar.setAttribute(
- 'value',
- String(currValue + UPDATE_PROGRESS_BAR_VALUE),
- );
-}
-
-function updateProgressBar() {
- let initialValue = 0;
- let progressBarContainer = document.querySelector('.ex-progress-bar');
- progressBarContainer.innerHTML = ``;
-
- if (progressBarIntervalId) clearInterval(progressBarIntervalId);
- progressBarIntervalId = setInterval(
- updateProgressBarProgress,
- PROGRESS_BAR_UPDATE_DELAY,
- );
+ chrome.storage.sync.get({ [STORAGE_KEY]: DEFAULT_CHAT_URL }, (items) => {
+ createChatFrame(items[STORAGE_KEY] || DEFAULT_CHAT_URL);
+ });
}
-function updateSingleStoryView(story, storyId, storyIndex) {
- const storyViewer = document.querySelector('.story-view-wrapper');
-
- const imageLink = storyViewer.querySelector('.story-view-user-img-link');
- imageLink.href = getGithubURL(story.userName);
-
- const image = storyViewer.querySelector('.story-view-user-img');
- image.src = story.userImageURL;
- image.setAttribute('alt', story.userName);
-
- const name = storyViewer.querySelector('.story-view-user-name');
- name.href = getGithubURL(story.userName);
- name.innerText = story.userName;
-
- const nameOnStory = storyViewer.querySelector('.story-view-user-name-inside');
- nameOnStory.href = getGithubURL(story.userName);
- nameOnStory.innerText = story.userName;
-
- const content = storyViewer.querySelector('.story-view-content');
- content.setAttribute('theme', String(story.themeID));
-
- const contentAction = storyViewer.querySelector('.story-view-content-action');
- contentAction.innerHTML = story.action;
-
- const contentFullAction = storyViewer.querySelector('.story-view-full-text');
- contentFullAction.innerHTML = story.actionFull;
-
- const contentObject = storyViewer.querySelector('.story-view-content-object')
- .firstElementChild;
- contentObject.innerText = story.repoOrUserName;
- contentObject.href = story.repoOrUserURL;
-
- const contentEmoji = storyViewer.querySelector('.story-view-content-emoji');
- console.log('story action ->'+story.action+'<-');
- contentEmoji.innerText = emojis[story.action] || '';
-
- storyViewer.setAttribute('story-id', storyId);
- storyViewer.setAttribute('story-index', storyIndex);
-
- image.src = story.userImageURL;
- name.innerText = story.userName;
- name.href = getGithubURL(story.userName);
-
- if (storyViewIntervalId) clearInterval(storyViewIntervalId);
-
- updateProgressBar();
- storyViewIntervalId = setInterval(
- automaticSlideScrolling,
- AUTOMATIC_SCROLL_DELAY,
- );
-
- document.querySelector('.story-view-wrapper').classList.remove('hidden');
- storyViewOpen = true;
-
- updateStoryViewWidth();
-}
+init();
From ae7d8d3a087c1143b421afe5af8da25df3f4ad07 Mon Sep 17 00:00:00 2001
From: martrend33 <145278472+martrend33@users.noreply.github.com>
Date: Tue, 9 Jun 2026 16:59:01 -0600
Subject: [PATCH 4/7] Create github-chat.cssAdd GitHub Chat extension styles
---
github-chat.css | 129 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 129 insertions(+)
create mode 100644 github-chat.css
diff --git a/github-chat.css b/github-chat.css
new file mode 100644
index 0000000..1f025aa
--- /dev/null
+++ b/github-chat.css
@@ -0,0 +1,129 @@
+.github-chat-extension {
+ bottom: 24px;
+ position: fixed;
+ right: 24px;
+ z-index: 2147483647;
+}
+
+.github-chat-extension__toggle,
+.github-chat-extension__close {
+ align-items: center;
+ background: #24292f;
+ border: 0;
+ color: #ffffff;
+ cursor: pointer;
+ display: inline-flex;
+ font: 600 14px/1 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
+ justify-content: center;
+}
+
+.github-chat-extension__toggle {
+ border-radius: 999px;
+ box-shadow: 0 8px 24px rgb(140 149 159 / 30%);
+ height: 44px;
+ padding: 0 18px;
+}
+
+.github-chat-extension__toggle:hover,
+.github-chat-extension__close:hover {
+ background: #0969da;
+}
+
+.github-chat-extension__panel {
+ background: #ffffff;
+ border: 1px solid #d0d7de;
+ border-radius: 8px;
+ box-shadow: 0 16px 40px rgb(140 149 159 / 32%);
+ display: flex;
+ flex-direction: column;
+ height: min(680px, calc(100vh - 48px));
+ overflow: hidden;
+ width: min(420px, calc(100vw - 48px));
+}
+
+.github-chat-extension__header {
+ align-items: center;
+ background: #f6f8fa;
+ border-bottom: 1px solid #d0d7de;
+ color: #24292f;
+ display: flex;
+ font: 600 14px/1 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
+ justify-content: space-between;
+ min-height: 42px;
+ padding: 0 8px 0 14px;
+}
+
+.github-chat-extension__close {
+ border-radius: 6px;
+ height: 28px;
+ width: 28px;
+}
+
+.github-chat-extension__frame {
+ border: 0;
+ flex: 1;
+ min-height: 0;
+ width: 100%;
+}
+
+.github-chat-extension__fallback {
+ align-items: center;
+ background: #ffffff;
+ color: #57606a;
+ display: none;
+ flex: 1;
+ flex-direction: column;
+ font: 14px/1.4 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
+ gap: 12px;
+ justify-content: center;
+ padding: 24px;
+ text-align: center;
+}
+
+.github-chat-extension__fallback.is-visible {
+ display: flex;
+}
+
+.github-chat-extension__fallback.is-visible + .github-chat-extension__frame,
+.github-chat-extension__fallback.is-visible ~ .github-chat-extension__frame {
+ display: none;
+}
+
+.github-chat-extension__fallback p {
+ margin: 0;
+}
+
+.github-chat-extension__fallback-link {
+ background: #1f883d;
+ border-radius: 6px;
+ color: #ffffff;
+ font-weight: 600;
+ padding: 9px 14px;
+ text-decoration: none;
+}
+
+.github-chat-extension__fallback-link:hover {
+ background: #1a7f37;
+ color: #ffffff;
+ text-decoration: none;
+}
+
+.github-chat-extension.is-collapsed .github-chat-extension__panel {
+ display: none;
+}
+
+.github-chat-extension:not(.is-collapsed) .github-chat-extension__toggle {
+ display: none;
+}
+
+@media (max-width: 480px) {
+ .github-chat-extension {
+ bottom: 12px;
+ right: 12px;
+ }
+
+ .github-chat-extension__panel {
+ height: calc(100vh - 24px);
+ width: calc(100vw - 24px);
+ }
+}
From 6679d5304d38da5f56a6366dbeb722bc7876cd40 Mon Sep 17 00:00:00 2001
From: martrend33 <145278472+martrend33@users.noreply.github.com>
Date: Tue, 9 Jun 2026 17:00:25 -0600
Subject: [PATCH 5/7] Create options.htmlAdd GitHub Chat options page
---
options.html | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 61 insertions(+)
create mode 100644 options.html
diff --git a/options.html b/options.html
new file mode 100644
index 0000000..b92209e
--- /dev/null
+++ b/options.html
@@ -0,0 +1,61 @@
+
+
+
+
+ GitHub Chat Options
+
+
+
+ label>
+
+ button>
+ p>
+
+
+html>
+
+