diff --git a/icons/gk-green-128.png b/icons/gk-green-128.png new file mode 100644 index 0000000..38b200b Binary files /dev/null and b/icons/gk-green-128.png differ diff --git a/icons/gk-green-16.png b/icons/gk-green-16.png new file mode 100644 index 0000000..726412d Binary files /dev/null and b/icons/gk-green-16.png differ diff --git a/icons/gk-green-32.png b/icons/gk-green-32.png new file mode 100644 index 0000000..f85647d Binary files /dev/null and b/icons/gk-green-32.png differ diff --git a/icons/gk-green-48.png b/icons/gk-green-48.png new file mode 100644 index 0000000..4b1ea34 Binary files /dev/null and b/icons/gk-green-48.png differ diff --git a/icons/gk-grey-128.png b/icons/gk-grey-128.png new file mode 100644 index 0000000..ae39082 Binary files /dev/null and b/icons/gk-grey-128.png differ diff --git a/icons/gk-grey-16.png b/icons/gk-grey-16.png new file mode 100644 index 0000000..9a169ab Binary files /dev/null and b/icons/gk-grey-16.png differ diff --git a/icons/gk-grey-32.png b/icons/gk-grey-32.png new file mode 100644 index 0000000..9978ed7 Binary files /dev/null and b/icons/gk-grey-32.png differ diff --git a/icons/gk-grey-48.png b/icons/gk-grey-48.png new file mode 100644 index 0000000..65a98ed Binary files /dev/null and b/icons/gk-grey-48.png differ diff --git a/icons/logo-128.png b/icons/logo-128.png deleted file mode 100644 index 9ded6c4..0000000 Binary files a/icons/logo-128.png and /dev/null differ diff --git a/icons/logo-16.png b/icons/logo-16.png deleted file mode 100644 index c1650f5..0000000 Binary files a/icons/logo-16.png and /dev/null differ diff --git a/icons/logo-32.png b/icons/logo-32.png deleted file mode 100644 index 542e40d..0000000 Binary files a/icons/logo-32.png and /dev/null differ diff --git a/icons/logo-48.png b/icons/logo-48.png deleted file mode 100644 index e50ef19..0000000 Binary files a/icons/logo-48.png and /dev/null differ diff --git a/scripts/makeManifest.js b/scripts/makeManifest.js index fcc7df7..ae6b58c 100644 --- a/scripts/makeManifest.js +++ b/scripts/makeManifest.js @@ -13,10 +13,10 @@ const manifestBase = { description: packageJson['description'], version: packageJson['version'], icons: { - 16: 'icons/logo-16.png', - 32: 'icons/logo-32.png', - 48: 'icons/logo-48.png', - 128: 'icons/logo-128.png', + 16: 'icons/gk-grey-16.png', + 32: 'icons/gk-grey-32.png', + 48: 'icons/gk-grey-48.png', + 128: 'icons/gk-grey-128.png', }, permissions: [ 'cookies', diff --git a/src/background.ts b/src/background.ts index 61b862e..8b6969c 100644 --- a/src/background.ts +++ b/src/background.ts @@ -4,6 +4,7 @@ import { injectionScope as inject_azureDevops } from './hosts/azureDevops'; import { injectionScope as inject_bitbucket } from './hosts/bitbucket'; import { injectionScope as inject_github } from './hosts/github'; import { injectionScope as inject_gitlab } from './hosts/gitlab'; +import { fetchUser, updateExtensionIcon } from './shared'; webNavigation.onDOMContentLoaded.addListener(injectScript, { url: [ @@ -55,3 +56,11 @@ function getInjectionFn(url: string): (url: string) => void { console.error('Unsupported host'); throw new Error('Unsupported host'); } + +const main = async () => { + // Update the extension icon based on whether the user is logged in. + const user = await fetchUser(); + void updateExtensionIcon(Boolean(user)); +}; + +void main(); diff --git a/src/popup.ts b/src/popup.ts index 262342d..b4bb9f4 100644 --- a/src/popup.ts +++ b/src/popup.ts @@ -1,17 +1,8 @@ // Note: This code runs every time the extension popup is opened. import { cookies } from 'webextension-polyfill'; - -interface User { - email: string; - name?: string; - proAccessState?: { - trial?: { - end?: string; - } - }; - username: string; -} +import { fetchUser, getAccessToken, updateExtensionIcon } from './shared'; +import type { User } from './types'; // Source: https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#basic_example const sha256 = async (text: string) => { @@ -41,38 +32,6 @@ const getUserTrialDaysLeft = (user: User) => { return Math.ceil(diff / (1000 * 60 * 60 * 24)); }; -const getAccessToken = async () => { - // Attempt to get the access token cookie from GitKraken.dev - const cookie = await cookies.get({ - url: 'https://gitkraken.dev', - name: 'accessToken' - }); - - return cookie?.value; -}; - -const fetchUser = async () => { - const token = await getAccessToken(); - if (!token) { - // The user is not logged in. - return; - } - - const res = await fetch('https://api.gitkraken.dev/user', { - headers: { - Authorization: `Bearer ${token}` - } - }); - - if (!res.ok) { - // The access token is invalid or expired. - return; - } - - const user = await res.json(); - return user as User; -}; - const logout = async () => { const token = await getAccessToken(); if (!token) { @@ -97,6 +56,8 @@ const logout = async () => { url: 'https://gitkraken.dev', name: 'accessToken' }); + + await updateExtensionIcon(false); }; const makeIcon = (faIcon: string) => { @@ -239,8 +200,10 @@ const main = async () => { const user = await fetchUser(); if (user) { void renderLoggedInContent(user); + void updateExtensionIcon(true); } else { renderLoggedOutContent(); + void updateExtensionIcon(false); } const loadingIcon = document.getElementById('loading-icon'); diff --git a/src/shared.ts b/src/shared.ts new file mode 100644 index 0000000..83321af --- /dev/null +++ b/src/shared.ts @@ -0,0 +1,51 @@ +import { action, cookies } from 'webextension-polyfill'; +import type { User } from './types'; + +const IconPaths = { + Grey: { + 16: '/icons/gk-grey-16.png', + 32: '/icons/gk-grey-32.png', + 48: '/icons/gk-grey-48.png', + 128: '/icons/gk-grey-128.png', + }, + Green: { + 16: '/icons/gk-green-16.png', + 32: '/icons/gk-green-32.png', + 48: '/icons/gk-green-48.png', + 128: '/icons/gk-green-128.png', + }, +}; + +export const updateExtensionIcon = (isLoggedIn: boolean) => action.setIcon({ path: isLoggedIn ? IconPaths.Green : IconPaths.Grey }); + +export const getAccessToken = async () => { + // Attempt to get the access token cookie from GitKraken.dev + const cookie = await cookies.get({ + url: 'https://gitkraken.dev', + name: 'accessToken' + }); + + return cookie?.value; +}; + +export const fetchUser = async () => { + const token = await getAccessToken(); + if (!token) { + // The user is not logged in. + return; + } + + const res = await fetch('https://api.gitkraken.dev/user', { + headers: { + Authorization: `Bearer ${token}` + } + }); + + if (!res.ok) { + // The access token is invalid or expired. + return; + } + + const user = await res.json(); + return user as User; +}; diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..d59e538 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,10 @@ +export interface User { + email: string; + name?: string; + proAccessState?: { + trial?: { + end?: string; + } + }; + username: string; +} diff --git a/static/popup.css b/static/popup.css index f7ce4d6..6b2bdec 100644 --- a/static/popup.css +++ b/static/popup.css @@ -3,6 +3,7 @@ margin: 0; padding: 0; font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; + color: #25292F; } #main-content { @@ -16,7 +17,6 @@ } a.menu-row-btn { - color: black; text-decoration: none; display: block; padding: 5px; @@ -42,6 +42,7 @@ img.avatar { .user { display: flex; align-items: center; + background-color: #F7F8FA; border: 1px solid #D7D8DB; border-radius: 6px; padding: 8px;