diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f20969e..a97f69c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v6 with: - node-version: '18' + node-version: '24' cache: 'npm' - name: Install dependencies @@ -34,7 +34,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v6 with: - node-version: '18' + node-version: '24' cache: 'npm' - name: Install dependencies @@ -52,7 +52,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v6 with: - node-version: '18' + node-version: '24' cache: 'npm' - name: Install dependencies @@ -75,7 +75,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v6 with: - node-version: '18' + node-version: '24' cache: 'npm' - name: Install dependencies diff --git a/.gitignore b/.gitignore index 87a5f76..df42caa 100644 --- a/.gitignore +++ b/.gitignore @@ -43,6 +43,7 @@ WINDSURF.md # Legacy local design / planning artifacts .superpowers/ +.mockups/ docs/superpowers/ icon-concepts.html *-450.png diff --git a/CHANGELOG.md b/CHANGELOG.md index 8340065..c64e761 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Security -- GitHub sign-in sessions now stay in Chrome session storage only instead of persisting to local extension storage +- GitHub sign-in sessions now persist in local extension storage for the current Chrome profile instead of clearing at browser shutdown - Added validation for the GitHub device-flow verification URL before opening a browser tab - Tightened remote image handling for activity avatars and extension page CSP rules diff --git a/README.md b/README.md index 79f05fe..9cfd6b9 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Best for people who follow several repos and want one local review queue instead - Chrome or another Chromium-based browser that supports Manifest V3 extensions - A GitHub account to connect during setup - No separate hosted DevWatch account or backend service -- GitHub sign-in lasts for the current browser session and is cleared when that session ends +- GitHub sign-in persists in the current Chrome profile until you disconnect it or reset DevWatch ## Installation @@ -101,10 +101,6 @@ Settings are split into a few practical jobs: - Tune filters, notifications, refresh interval, snooze behavior, and item expiry - Change theme/color theme, export or import settings, and enable advanced repo-limit options -
- Settings page for configuring repositories -
- ## Typical Workflow Here's what using the extension looks like day-to-day: @@ -123,7 +119,7 @@ That said, this project has not gone through a formal accessibility audit or doc ## Privacy & Security Notes -The extension talks directly to GitHub's API and does not use a separate analytics or sync backend. It stores settings and cached activity in Chrome extension storage, while the current GitHub auth session stays in Chrome session storage so it is not persisted to disk. Legacy encrypted auth data from older builds is cleared when accessed. +The extension talks directly to GitHub's API and does not use a separate analytics or sync backend. It stores settings, cached activity, and the current GitHub auth session in Chrome extension storage for the current browser profile. Legacy encrypted auth data from older builds is cleared when accessed. - **Direct network access** - Requests go to `api.github.com` for activity checks, `github.com` for OAuth device-flow sign-in, and `registry.npmjs.org` only when you use package-name lookup - **Scoped browser permissions** - The manifest asks for `storage`, `alarms`, and `notifications` @@ -187,6 +183,8 @@ npm test npm run build ``` +For the same full local validation pass used in this repo before packaging or release prep, run `npm run validate`. + The automated checks cover shared logic, UI behavior, and a range of mocked extension flows. They do not replace manual testing in Chrome for permissions, service worker lifecycle behavior, or end-to-end interactions against live GitHub data. Jest enforces minimum global coverage thresholds of 47% lines, 46% branches, and 44% functions. That is a floor for the suite, not a claim of exhaustive coverage. diff --git a/background.js b/background.js index d8964d3..4aafd4a 100644 --- a/background.js +++ b/background.js @@ -109,11 +109,6 @@ async function checkGitHubActivity() { 'unmutedRepos' ]); - if (!githubToken) { - console.warn('[DevWatch] No GitHub connection found. Please connect GitHub in settings.'); - return; - } - if (!watchedRepos || watchedRepos.length === 0) { console.warn('[DevWatch] No repositories being watched. Please add repos in settings.'); return; @@ -192,7 +187,9 @@ async function checkGitHubActivity() { async function fetchRepoActivity(repo, token, since, filters) { const activities = []; - const headers = createHeaders(token); + const headers = token + ? createHeaders(token) + : { 'Accept': 'application/vnd.github.v3+json' }; async function fetchWithRateLimit(url) { try { @@ -312,9 +309,13 @@ async function fetchRepoActivity(repo, token, since, filters) { if (error.message.includes('401')) { userMessage = 'GitHub sign-in expired or was revoked. Reconnect GitHub in settings.'; } else if (error.message.includes('403')) { - userMessage = 'Access denied or rate limit exceeded.'; + userMessage = token + ? 'Access denied or rate limit exceeded.' + : 'Anonymous GitHub access hit the rate limit or this repo requires GitHub sign-in.'; } else if (error.message.includes('404')) { - userMessage = 'Repository not found or access denied.'; + userMessage = token + ? 'Repository not found or access denied.' + : 'Repository not found publicly. If it is private, connect GitHub and try again.'; } else if (error.message.includes('Network error')) { userMessage = 'Network connection error. Please check your internet connection.'; } diff --git a/icon.svg b/icon.svg index c29b4d7..119bd28 100644 --- a/icon.svg +++ b/icon.svg @@ -1,18 +1,32 @@ - - - - - + + + + + + + + + + + + + + - - - + + + + + - - - - - - - + + + + + + + + + + diff --git a/icons/icon128.png b/icons/icon128.png index 984ae0a..aa94077 100644 Binary files a/icons/icon128.png and b/icons/icon128.png differ diff --git a/icons/icon16.png b/icons/icon16.png index a1f35ea..afeb74c 100644 Binary files a/icons/icon16.png and b/icons/icon16.png differ diff --git a/icons/icon32.png b/icons/icon32.png index f2e3260..fea4c69 100644 Binary files a/icons/icon32.png and b/icons/icon32.png differ diff --git a/icons/icon48.png b/icons/icon48.png index 206f57b..6c2005f 100644 Binary files a/icons/icon48.png and b/icons/icon48.png differ diff --git a/options/controllers/import-controller.js b/options/controllers/import-controller.js index 0cea908..99ef5cd 100644 --- a/options/controllers/import-controller.js +++ b/options/controllers/import-controller.js @@ -1,6 +1,9 @@ import { STORAGE_CONFIG } from '../../shared/config.js'; import { getAccessToken, getSyncItem, setWatchedRepos } from '../../shared/storage-helpers.js'; -import { createHeaders } from '../../shared/github-api.js'; +import { + fetchGitHubRepoSource, + getGitHubRepoSourceConfig +} from '../../shared/github-repo-sources.js'; import { getRepoFullName, normalizeWatchedRepoRecord } from '../../shared/repo-service.js'; import { escapeHtml, unescapeHtml } from '../../shared/sanitize.js'; import { formatDateVerbose } from '../../shared/utils.js'; @@ -72,23 +75,16 @@ export async function openImportModal(type, watchedRepos) { importModalState.type = type; const modal = document.getElementById('importModal'); const title = document.getElementById('importModalTitle'); + const sourceConfig = getGitHubRepoSourceConfig(type); - const titles = { - watched: 'Import Watched Repositories', - starred: 'Import Starred Repositories', - participating: 'Import Participating Repositories', - mine: 'Import My Repositories' - }; - - title.textContent = titles[type] || 'Import Repositories'; + title.textContent = sourceConfig.modalTitle; importModalState.previousFocusElement = document.activeElement; modal.classList.add('show'); - document.getElementById('importLoadingState').style.display = 'flex'; + document.getElementById('importLoadingState').classList.remove('hidden'); const reposList = document.getElementById('importReposList'); reposList.classList.add('hidden'); - reposList.style.display = 'none'; - document.getElementById('importErrorState').style.display = 'none'; + document.getElementById('importErrorState').classList.add('hidden'); setupModalFocusTrap(modal); @@ -98,7 +94,7 @@ export async function openImportModal(type, watchedRepos) { }, 100); try { - const repos = await fetchReposFromGitHub(type, token); + const repos = await fetchGitHubRepoSource(type, token); const alreadyAdded = new Set( (watchedRepos || []) @@ -113,100 +109,17 @@ export async function openImportModal(type, watchedRepos) { importModalState.filteredRepos = [...importModalState.repos]; - document.getElementById('importLoadingState').style.display = 'none'; + document.getElementById('importLoadingState').classList.add('hidden'); const reposList = document.getElementById('importReposList'); reposList.classList.remove('hidden'); - reposList.style.display = 'block'; renderImportReposList(); } catch (error) { - document.getElementById('importLoadingState').style.display = 'none'; - document.getElementById('importErrorState').style.display = 'block'; + document.getElementById('importLoadingState').classList.add('hidden'); + document.getElementById('importErrorState').classList.remove('hidden'); document.getElementById('importErrorMessage').textContent = error.message || 'Failed to fetch repositories'; } } -async function fetchReposFromGitHub(type, token) { - const headers = createHeaders(token); - let allRepos = []; - let page = 1; - const perPage = 100; - const MAX_PAGES = 100; // Prevent infinite loops (10,000 repos max) - const MAX_REPOS = 10000; // Hard limit on total repos - - const endpoints = { - watched: 'https://api.github.com/user/subscriptions', - starred: 'https://api.github.com/user/starred', - participating: 'https://api.github.com/user/repos?affiliation=collaborator,organization_member&sort=pushed', - mine: 'https://api.github.com/user/repos?type=all&sort=updated' - }; - - const url = endpoints[type]; - if (!url) { - throw new Error(`Invalid import type: ${type}`); - } - - let hasMorePages = true; - let startTime = Date.now(); - const TIMEOUT_MS = 60000; // 60 second timeout - - while (hasMorePages && page <= MAX_PAGES && allRepos.length < MAX_REPOS) { - // Check for timeout to prevent hanging - if (Date.now() - startTime > TIMEOUT_MS) { - break; - } - - // Build URL safely with URLSearchParams - const urlObj = new URL(url); - urlObj.searchParams.set('per_page', perPage.toString()); - urlObj.searchParams.set('page', page.toString()); - - const response = await fetch(urlObj.toString(), { - headers - }); - - if (!response.ok) { - if (response.status === 401) { - throw new Error('GitHub sign-in expired or was revoked'); - } else if (response.status === 403) { - throw new Error('Rate limit exceeded or insufficient permissions'); - } else { - throw new Error(`GitHub API error: ${response.status}`); - } - } - - const repos = await response.json(); - if (!Array.isArray(repos) || repos.length === 0) { - hasMorePages = false; - break; - } - - const transformed = repos.map(repo => ({ - fullName: repo.full_name, - description: repo.description || 'No description provided', - language: repo.language || 'Unknown', - stars: repo.stargazers_count || 0, - forks: repo.forks_count || 0, - updatedAt: repo.updated_at || repo.pushed_at - })); - - allRepos.push(...transformed); - - // Stop if we've hit the max repos limit - if (allRepos.length >= MAX_REPOS) { - break; - } - - const linkHeader = response.headers.get('Link'); - if (!linkHeader || !linkHeader.includes('rel="next"')) { - hasMorePages = false; - } else { - page++; - } - } - - return allRepos; -} - export function closeImportModal() { const modal = document.getElementById('importModal'); modal.classList.remove('show'); diff --git a/options/controllers/token-controller.js b/options/controllers/token-controller.js index 2078be7..2b52550 100644 --- a/options/controllers/token-controller.js +++ b/options/controllers/token-controller.js @@ -13,18 +13,19 @@ function setRepoAccessState(isConnected) { const repoInput = document.getElementById('repoInput'); const addRepoBtn = document.getElementById('addRepoBtn'); const repoHelpText = document.getElementById('repoHelpText'); - const importSection = document.getElementById('importReposSection'); + const githubImportButtons = document.querySelectorAll('.github-import-btn'); - repoInput.disabled = !isConnected; + repoInput.disabled = false; repoInput.placeholder = isConnected ? 'e.g., react, facebook/react, or GitHub URL' - : 'Connect GitHub to add repositories'; - addRepoBtn.disabled = !isConnected; + : 'e.g., react, facebook/react, GitHub URL, or public npm package'; + addRepoBtn.disabled = false; repoHelpText.textContent = isConnected ? 'Add repositories to monitor (npm package, owner/repo, or GitHub URL)' - : 'Connect GitHub above to start adding repositories'; - importSection.classList.toggle('hidden', !isConnected); - importSection.style.display = isConnected ? 'block' : 'none'; + : 'Add public repositories manually now, or connect GitHub above to import your repos and access private ones.'; + githubImportButtons.forEach((button) => { + button.classList.toggle('hidden', !isConnected); + }); } function setDeviceCode(userCode = '') { @@ -37,7 +38,6 @@ function setDeviceCode(userCode = '') { deviceCodeInput.value = userCode; deviceCodeSection.classList.toggle('hidden', !userCode); - deviceCodeSection.style.display = userCode ? 'flex' : 'none'; } function setHelpText(message = '') { @@ -50,16 +50,54 @@ function setHelpText(message = '') { helpEl.textContent = message; } +function setStatusRowVisible(isVisible) { + const statusRow = document.querySelector('.github-connect-status-row'); + + if (!statusRow) { + return; + } + + statusRow.classList.toggle('hidden', !isVisible); +} + +function setConnectionUiMode(isConnected) { + const connectCard = document.querySelector('.github-connect-card'); + const introText = document.getElementById('githubConnectIntroText'); + const connectedNote = document.getElementById('githubConnectConnectedNote'); + const panelHeading = document.getElementById('githubConnectPanelHeading'); + const panelCopy = document.getElementById('githubConnectPanelCopy'); + + connectCard?.classList.toggle('is-connected', isConnected); + + if (introText) { + introText.textContent = 'Authorize DevWatch once so it can pull activity for the repositories you monitor without asking for a personal access token.'; + } + + if (connectedNote) { + connectedNote.textContent = 'You\'re all set. DevWatch keeps this browser profile connected until you disconnect or reset it.'; + } + + if (panelHeading) { + panelHeading.textContent = isConnected + ? 'Reconnect only if GitHub asks again' + : 'Connect once, then just paste if GitHub asks'; + } + + if (panelCopy) { + panelCopy.textContent = 'DevWatch opens GitHub for you and copies the verification code automatically, so the only extra step is pasting it if GitHub prompts for one.'; + } +} + function getHelpText({ isConnected = false, isWaiting = false } = {}) { if (isWaiting) { - return 'Approve access in the GitHub tab, then return here. If GitHub asks for a code, use the one shown below.'; + return 'Approve access in the GitHub tab, then return here. If GitHub asks for a code, just paste the one DevWatch already copied for you.'; } if (isConnected) { - return 'Reconnect any time if your session expires or if you want to switch accounts.'; + return 'Your GitHub connection stays in this Chrome profile until you disconnect it or reset DevWatch. If GitHub asks for a code during reconnect, just paste the one DevWatch copies for you.'; } - return 'We\'ll open GitHub in a new tab. Approve access there, then come back here and DevWatch will finish connecting.'; + return 'We\'ll open GitHub in a new tab and copy the code for you. If GitHub asks for one, just paste it there, approve access, and come back here.'; } function setStatus(message = '', statusClass = '') { @@ -78,7 +116,9 @@ export function applyStoredConnection(authSession, options = {}) { const clearBtn = document.getElementById('clearTokenBtn'); const isConnected = Boolean(authSession?.accessToken); const username = authSession?.username; + const hasStatusMessage = Boolean(options.statusMessage); + setConnectionUiMode(isConnected); setRepoAccessState(isConnected); setDeviceCode(options.userCode || ''); setHelpText(options.helpText || getHelpText({ @@ -92,11 +132,12 @@ export function applyStoredConnection(authSession, options = {}) { } if (clearBtn) { - clearBtn.style.display = isConnected ? 'block' : 'none'; + clearBtn.classList.toggle('hidden', !isConnected); } if (options.statusMessage) { setStatus(options.statusMessage, options.statusClass); + setStatusRowVisible(true); return; } @@ -105,8 +146,10 @@ export function applyStoredConnection(authSession, options = {}) { username ? `Connected as ${username}` : 'GitHub is connected', 'valid' ); + setStatusRowVisible(true); } else { setStatus('', ''); + setStatusRowVisible(hasStatusMessage); } } @@ -147,9 +190,11 @@ export async function connectGitHub(_toastManager) { connectBtn.textContent = 'Waiting for GitHub...'; } + setConnectionUiMode(Boolean(previousSession?.accessToken)); setRepoAccessState(Boolean(previousSession?.accessToken)); setStatus('Starting GitHub sign-in...', 'checking'); - setHelpText('We\'re opening GitHub so you can approve access. Come back here as soon as GitHub says the connection is ready.'); + setStatusRowVisible(true); + setHelpText('We\'re opening GitHub and copying the code for you. If GitHub asks for one, just paste it there, then come back here as soon as the connection is ready.'); try { const result = await completeGitHubDeviceAuth({ @@ -160,8 +205,8 @@ export async function connectGitHub(_toastManager) { : false; setStatus( copied - ? `Code ${userCode} copied to clipboard — paste it on the GitHub page that opens.` - : `Enter ${userCode} on GitHub to finish connecting.`, + ? `Code ${userCode} copied to your clipboard. Paste it on GitHub only if GitHub asks for it.` + : `If GitHub asks for a code, enter ${userCode}.`, 'checking' ); setHelpText(getHelpText({ isWaiting: true })); diff --git a/options/options.css b/options/options.css index ff59892..da86ef1 100644 --- a/options/options.css +++ b/options/options.css @@ -21,7 +21,7 @@ body { /* Utility classes */ .hidden { - display: none; + display: none !important; } /* Margin utilities */ @@ -75,7 +75,7 @@ body { /* Display utilities */ .d-none { - display: none; + display: none !important; } .d-block { @@ -137,6 +137,22 @@ body { background: transparent; } +.sidebar-shell { + display: flex; + flex-direction: column; + gap: 12px; + padding: 12px; + background: rgba(255, 255, 255, 0.035); + border-right: 1px solid var(--border-color); + min-width: 228px; + position: sticky; + top: 0; + height: 100vh; + overflow-y: auto; + scrollbar-width: thin; + backdrop-filter: blur(14px); +} + .content-wrapper { flex: 1; overflow-y: auto; @@ -164,16 +180,7 @@ h1 { .tab-navigation { display: flex; flex-direction: column; - padding: 12px; - background: rgba(255, 255, 255, 0.035); - border-right: 1px solid var(--border-color); - min-width: 228px; - position: sticky; - top: 0; - height: 100vh; - overflow-y: auto; - scrollbar-width: thin; - backdrop-filter: blur(14px); + min-height: 0; } .tab-list { @@ -182,6 +189,60 @@ h1 { gap: 8px; } +.sidebar-status-card { + margin-top: auto; + padding: 16px; + border: 1px solid var(--border-color); + border-radius: 18px; + background: rgba(255, 255, 255, 0.045); + box-shadow: 0 14px 32px rgba(0, 0, 0, 0.12); +} + +.sidebar-status-header-row { + display: flex; + align-items: center; + margin-bottom: 14px; +} + +.sidebar-status-eyebrow { + margin: 0; + color: var(--text-secondary); + font-size: 11px; + font-weight: 700; + letter-spacing: 0.14em; + text-transform: uppercase; +} + +.sidebar-status-section + .sidebar-status-section { + margin-top: 14px; + padding-top: 14px; + border-top: 1px solid var(--border-color); +} + +.sidebar-status-label { + margin: 0 0 6px; + color: var(--text-secondary); + font-size: 11px; + font-weight: 700; + letter-spacing: 0.1em; + text-transform: uppercase; +} + +.sidebar-status-value { + margin: 0; + color: var(--text-primary); + font-size: 14px; + font-weight: 700; + line-height: 1.35; +} + +.sidebar-status-meta { + margin: 4px 0 0; + color: var(--text-secondary); + font-size: 12px; + line-height: 1.45; +} + .sidebar-header { padding: 16px 16px 14px; margin-bottom: 10px; @@ -193,16 +254,16 @@ h1 { font-weight: 600; color: var(--text-primary); margin: 0; - font-family: 'IBM Plex Mono', ui-monospace, monospace; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; text-transform: uppercase; letter-spacing: -0.03em; } -.tab-navigation::-webkit-scrollbar { +.sidebar-shell::-webkit-scrollbar { width: 4px; } -.tab-navigation::-webkit-scrollbar-thumb { +.sidebar-shell::-webkit-scrollbar-thumb { background: var(--border-color); border-radius: 2px; } @@ -222,7 +283,7 @@ h1 { transition: all 0.2s ease; text-align: left; position: relative; - font-family: 'IBM Plex Mono', ui-monospace, monospace; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; text-transform: uppercase; } @@ -280,8 +341,11 @@ h1 { flex-direction: column; } - .tab-navigation { + .sidebar-shell { flex-direction: row; + flex-wrap: wrap; + align-items: stretch; + gap: 8px; min-width: unset; width: 100%; height: auto; @@ -292,11 +356,23 @@ h1 { padding: 4px; } + .tab-navigation { + flex: 1 1 100%; + } + .tab-list { flex-direction: row; + flex: 1 1 100%; min-width: max-content; } + .sidebar-header { + width: 100%; + margin-bottom: 0; + padding: 8px 10px 0; + border-bottom: none; + } + .tab-button { flex-direction: column; gap: 4px; @@ -315,28 +391,27 @@ h1 { height: 20px; } + .sidebar-status-card { + width: 100%; + margin-top: 0; + } + .content-wrapper { padding: 20px; } } .section { - margin-bottom: 32px; - padding-bottom: 32px; + margin-bottom: 40px; + padding: 0 0 36px; border-bottom: 1px solid var(--border-color); scroll-margin-top: 20px; - background: rgba(255, 255, 255, 0.03); - border: 1px solid var(--border-color); - border-radius: 24px; - padding: 28px; - box-shadow: 0 12px 30px rgba(0, 0, 0, 0.08); - backdrop-filter: blur(10px); } .section:last-child { - border-bottom: 1px solid var(--border-color); + border-bottom: none; margin-bottom: 0; - padding-bottom: 32px; + padding-bottom: 0; } h2 { @@ -402,9 +477,9 @@ select:focus { height: 14px; display: inline-block; vertical-align: middle; - margin-right: 4px; color: var(--link-color); flex-shrink: 0; + margin-top: 2px; } /* Warning icon with color - placed after .info-icon to take precedence */ @@ -414,20 +489,28 @@ select:focus { } .info-box { - background: rgba(255, 255, 255, 0.04); + display: flex; + flex-direction: column; + gap: 10px; + background: linear-gradient(180deg, rgba(255, 255, 255, 0.04) 0%, rgba(255, 255, 255, 0.025) 100%); border: 1px solid var(--border-color); - padding: 12px 16px; + padding: 14px 16px; margin: 12px 0; - border-radius: 16px; - box-shadow: 0 10px 24px rgba(0, 0, 0, 0.06); + border-radius: 18px; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03); } - .info-box .help-text { margin: 0; display: flex; align-items: flex-start; - gap: 8px; - font-size: 14px; + gap: 10px; + font-size: 13px; + line-height: 1.6; + color: var(--text-secondary); +} + +.info-box strong { + color: var(--text-primary); } .info-box-compact { @@ -447,6 +530,22 @@ select:focus { margin-top: 2px; } +.setup-inline-link { + color: var(--link-color); + font-weight: 600; + text-decoration: none; +} + +.setup-inline-link:hover { + text-decoration: underline; +} + +.setup-inline-link:focus-visible { + outline: 2px solid var(--link-color); + outline-offset: 3px; + border-radius: 6px; +} + button { padding: 8px 16px; border: 1px solid var(--border-color-dark); @@ -534,7 +633,7 @@ button.danger:hover { font-weight: 600; transition: all 0.2s ease; user-select: none; - font-family: 'IBM Plex Mono', ui-monospace, monospace; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; text-transform: uppercase; } @@ -574,6 +673,30 @@ button.danger:hover { border: 1px solid var(--border); } +.swatch-polar { + background: #0D9488; +} + +.swatch-graphite { + background: #6366F1; +} + +.swatch-nightfall { + background: #E87B00; +} + +.swatch-obsidian { + background: #10B981; +} + +.swatch-sand { + background: #9F1239; +} + +.swatch-terminal-ledger { + background: #D3A24B; +} + .subsection-heading { font-size: 15px; font-weight: 600; @@ -582,73 +705,56 @@ button.danger:hover { color: var(--foreground); } -/* Activity Cards Styles */ -.activity-cards { - display: flex; - flex-direction: column; - gap: 12px; - margin-top: 16px; -} - -.activity-card { - display: flex; - flex-direction: column; - background: rgba(255, 255, 255, 0.04); +/* Shared Settings Surfaces */ +.settings-surface { + background: rgba(255, 255, 255, 0.03); border: 1px solid var(--border-color); border-radius: 18px; - overflow: hidden; - transition: all 0.2s ease; - box-shadow: 0 10px 24px rgba(0, 0, 0, 0.08); + box-shadow: 0 1px 0 rgba(255, 255, 255, 0.03) inset; + transition: border-color 0.2s ease, box-shadow 0.2s ease, background 0.2s ease, transform 0.2s ease; } -.activity-card:hover { - border-color: var(--link-color); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); +.settings-surface:hover { + border-color: var(--border-hover); + box-shadow: 0 12px 24px rgba(0, 0, 0, 0.08); } -.card-header { +.settings-surface-header { display: flex; align-items: flex-start; - gap: 12px; - padding: 16px; - background: rgba(255, 255, 255, 0.025); + gap: 16px; } -.activity-icon { - width: 24px; - height: 24px; - color: var(--link-color); - flex-shrink: 0; - margin-top: 2px; +.settings-surface-body { + display: flex; + flex-direction: column; + gap: 16px; } -.activity-info { - flex: 1; +.settings-surface-actions { + display: flex; + gap: 24px; } -.activity-info h3 { - font-size: 16px; - font-weight: 600; - color: var(--text-primary); - margin: 0 0 4px 0; +.settings-surface-split { + display: flex; + flex-direction: column; + overflow: hidden; } -.activity-info p { - font-size: 14px; - color: var(--text-secondary); - margin: 0; - line-height: 1.4; +.settings-surface-split .settings-surface-header { + gap: 12px; + padding: 16px; + background: rgba(255, 255, 255, 0.025); } -.card-controls { - display: flex; +.settings-surface-split .settings-surface-actions { justify-content: space-around; - gap: 24px; padding: 12px 16px; background: rgba(0, 0, 0, 0.04); } -.control-section { +.settings-surface-split .settings-surface-action { display: flex; flex-direction: column; align-items: center; @@ -656,71 +762,235 @@ button.danger:hover { flex: 1; } -.control-label { - font-size: 12px; - font-weight: 500; - color: var(--text-secondary); - text-align: center; +.settings-surface-inline { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + padding: 20px; } -/* Enhanced Toggle Switch for Activity Cards */ -.activity-toggle { - position: relative; - display: inline-block; - width: 44px; - height: 24px; +.settings-surface-inline .settings-surface-header { + gap: 12px; + flex: 1; } -.activity-toggle input { - opacity: 0; - width: 0; - height: 0; +.settings-surface-inline .settings-surface-actions { + justify-content: flex-end; + padding: 0; + background: transparent; + flex-shrink: 0; } -.toggle-slider { - position: absolute; - cursor: pointer; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: var(--border-color); - transition: all 0.3s ease; - border-radius: 24px; +.settings-surface-prominent { + display: flex; + flex-direction: column; + gap: 18px; + padding: 20px; + border-radius: 22px; + background: rgba(255, 255, 255, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03), 0 16px 28px rgba(0, 0, 0, 0.08); } -.toggle-slider:before { - position: absolute; - content: ""; - height: 18px; - width: 18px; - left: 3px; - bottom: 3px; - background-color: var(--bg-primary); - transition: all 0.3s ease; - border-radius: 50%; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); +.settings-surface-prominent:hover { + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03), 0 18px 30px rgba(0, 0, 0, 0.1); } -.activity-toggle input:checked + .toggle-slider { - background-color: var(--primary); +.settings-surface-nested { + display: flex; + flex-direction: column; + gap: 12px; + padding: 16px; } -.activity-toggle input:focus + .toggle-slider { - box-shadow: 0 0 0 2px rgba(16, 185, 129, 0.2); +.settings-surface-dashed { + border-style: dashed; + border-color: var(--border-hover); + box-shadow: none; } -.activity-toggle input:checked + .toggle-slider:before { - transform: translateX(20px); +.settings-surface-dashed:hover { + box-shadow: none; } -/* Notification Toggle Specific Styling */ -.notification-toggle .toggle-slider { - background-color: var(--border-color-dark); +.settings-surface-danger:hover { + border-color: var(--destructive); } -.notification-toggle input:checked + .toggle-slider { - background-color: var(--primary); +.settings-row-group { + background: rgba(255, 255, 255, 0.03); + border: 1px solid var(--border-color); + border-radius: 20px; + overflow: hidden; + box-shadow: 0 1px 0 rgba(255, 255, 255, 0.03) inset; +} + +.settings-row-group > .settings-row { + margin: 0; + border: 0; + border-radius: 0; + background: transparent; + box-shadow: none; +} + +.settings-row-group > .settings-row:hover { + background: rgba(255, 255, 255, 0.025); + transform: none; + box-shadow: none; +} + +.settings-row-group > .settings-row + .settings-row { + border-top: 1px solid var(--border-color); +} + +/* Secondary support surfaces reused across Settings tabs */ +:where(.github-connect-fact, .filters-help-item, .repo-note, .resource-link, .version-badge, .changelog-content, .import-select-all) { + background: rgba(255, 255, 255, 0.04); + border: 1px solid var(--border-color); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03); +} + +/* Activity Cards Styles */ +.activity-cards { + margin-top: 16px; +} + +.activity-card { + min-width: 0; +} + +.activity-cards.settings-row-group > .activity-card.settings-row { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + align-items: center; + gap: 20px; + padding: 18px 20px; +} + +.activity-cards.settings-row-group .settings-surface-header, +.activity-cards.settings-row-group .settings-surface-actions { + padding: 0; + background: transparent; +} + +.activity-cards.settings-row-group .settings-surface-actions { + justify-content: flex-end; + gap: 14px; +} + +.activity-cards.settings-row-group .settings-surface-action { + min-width: 104px; + align-items: flex-start; + text-align: left; +} + +.activity-cards.settings-row-group .control-label { + text-align: left; +} + +.card-header { + min-width: 0; +} + +.activity-icon { + width: 24px; + height: 24px; + color: var(--link-color); + flex-shrink: 0; + margin-top: 2px; +} + +.activity-info { + flex: 1; +} + +.activity-info h3 { + font-size: 16px; + font-weight: 600; + color: var(--text-primary); + margin: 0 0 4px 0; +} + +.activity-info p { + font-size: 14px; + color: var(--text-secondary); + margin: 0; + line-height: 1.4; +} + +.card-controls { + min-width: 0; +} + +.control-section { + min-width: 0; +} + +.control-label { + font-size: 12px; + font-weight: 500; + color: var(--text-secondary); + text-align: center; +} + +/* Enhanced Toggle Switch for Activity Cards */ +.activity-toggle { + position: relative; + display: inline-block; + width: 44px; + height: 24px; +} + +.activity-toggle input { + opacity: 0; + width: 0; + height: 0; +} + +.toggle-slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: var(--border-color); + transition: all 0.3s ease; + border-radius: 24px; +} + +.toggle-slider:before { + position: absolute; + content: ""; + height: 18px; + width: 18px; + left: 3px; + bottom: 3px; + background-color: var(--bg-primary); + transition: all 0.3s ease; + border-radius: 50%; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); +} + +.activity-toggle input:checked + .toggle-slider { + background-color: var(--primary); +} + +.activity-toggle input:focus + .toggle-slider { + box-shadow: 0 0 0 2px rgba(16, 185, 129, 0.2); +} + +.activity-toggle input:checked + .toggle-slider:before { + transform: translateX(20px); +} + +/* Notification Toggle Specific Styling */ +.notification-toggle .toggle-slider { + background-color: var(--border-color-dark); +} + +.notification-toggle input:checked + .toggle-slider { + background-color: var(--primary); } body.dark-mode .notification-toggle input:checked + .toggle-slider { @@ -755,51 +1025,36 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { /* Feed Management Card */ .feed-management-card { - display: flex; - justify-content: space-between; - align-items: center; - background: var(--bg-tertiary); - border: 1px solid var(--border-color); - border-radius: 12px; - padding: 16px; margin-top: 16px; - transition: all 0.2s ease; } -.feed-management-card:hover { - border-color: var(--link-color); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); -} - -.feed-management-card .card-header { +.expiry-settings { display: flex; - align-items: flex-start; - gap: 12px; - padding: 0; - background: transparent; - flex: 1; + flex-direction: column; + gap: 14px; + margin-top: 16px; + padding: 18px; + background: rgba(255, 255, 255, 0.03); + border: 1px solid var(--border-color); + border-radius: 18px; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03); } -.feed-management-card .card-controls { - padding: 0; - background: transparent; +.expiry-settings .info-box { + margin: 0; } -.expiry-settings { - margin-top: 20px; - padding: 20px; - background: var(--bg-tertiary); - border: 1px solid var(--border-color); - border-radius: 8px; +.expiry-settings .input-label-styled { + margin-bottom: 0; } /* Styled Number Input */ .number-input-group { display: inline-flex; align-items: center; - background: var(--bg-primary); - border: 2px solid var(--border-color); - border-radius: 8px; + background: rgba(255, 255, 255, 0.025); + border: 1px solid var(--border-color); + border-radius: 14px; overflow: hidden; transition: all 0.2s ease; } @@ -827,7 +1082,7 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { .input-suffix { padding: 10px 16px; - background: var(--bg-tertiary); + background: rgba(255, 255, 255, 0.04); color: var(--text-secondary); font-size: 14px; font-weight: 500; @@ -847,11 +1102,11 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { align-items: flex-start; gap: 16px; padding: 20px; - background: rgba(255, 255, 255, 0.04); + background: rgba(255, 255, 255, 0.03); border: 1px solid var(--border-color); - border-radius: 18px; + border-radius: 20px; transition: all 0.2s ease; - box-shadow: 0 10px 24px rgba(0, 0, 0, 0.08); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03); } .setup-step.clickable { @@ -862,8 +1117,9 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { .setup-step:hover { border-color: var(--border-hover); - transform: translateY(-2px); - box-shadow: 0 14px 30px rgba(0, 0, 0, 0.12); + transform: translateY(-1px); + background: rgba(255, 255, 255, 0.04); + box-shadow: 0 12px 24px rgba(0, 0, 0, 0.08); } .step-number { @@ -879,7 +1135,7 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { font-size: 16px; font-weight: 700; flex-shrink: 0; - font-family: 'IBM Plex Mono', ui-monospace, monospace; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; } .step-content h3 { @@ -903,7 +1159,7 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { linear-gradient(135deg, rgba(255, 255, 255, 0.06), rgba(255, 255, 255, 0.03)); border-color: var(--border-hover); padding: 24px; - box-shadow: 0 14px 34px rgba(0, 0, 0, 0.12); + box-shadow: 0 14px 30px rgba(0, 0, 0, 0.08); } .setup-step-primary:hover { @@ -940,7 +1196,7 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { } .github-step-label { - font-family: 'IBM Plex Mono', ui-monospace, monospace; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; font-size: 12px; font-weight: 600; text-transform: uppercase; @@ -964,6 +1220,15 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { max-width: 60ch; } +.github-connect-connected-note { + display: none; + font-size: 14px; + line-height: 1.6; + color: var(--text-secondary); + margin-top: 2px; + max-width: 56ch; +} + .github-connect-facts { display: grid; gap: 12px; @@ -1005,7 +1270,7 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { font-weight: 700; letter-spacing: 0.01em; color: var(--text-primary); - font-family: 'IBM Plex Mono', ui-monospace, monospace; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; text-transform: uppercase; } @@ -1017,26 +1282,20 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { } .github-connect-panel { - display: flex; - flex-direction: column; - gap: 18px; - padding: 20px; - background: rgba(255, 255, 255, 0.05); - border: 1px solid var(--border-color); - border-radius: 22px; - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03), 0 18px 34px rgba(0, 0, 0, 0.08); + min-width: 0; } .github-connect-panel-header { - display: flex; - align-items: flex-start; - justify-content: space-between; - gap: 16px; + display: block; +} + +.github-connect-panel-title { + min-width: 0; } .github-panel-label { margin: 0 0 10px; - font-family: 'IBM Plex Mono', ui-monospace, monospace; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; font-size: 12px; font-weight: 600; text-transform: uppercase; @@ -1044,39 +1303,117 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { color: var(--text-secondary); } -.github-connect-panel-body { - display: flex; - flex-direction: column; - gap: 16px; +.github-connect-panel-heading { + margin: 0; + color: var(--text-primary); + font-size: 22px; + line-height: 1.15; + letter-spacing: -0.04em; } -.github-connect-btn { - display: inline-flex; - align-items: center; - justify-content: center; - width: 100%; - min-height: 48px; - font-size: 14px; - font-weight: 700; +.github-connect-panel-copy { + margin: 10px 0 0; + color: var(--text-secondary); + font-size: 13px; + line-height: 1.6; + max-width: 40ch; } -.github-connect-help { - margin: 0; - font-size: 13px; +.github-connect-panel-body { + min-width: 0; } -.github-connect-flow { - display: grid; +.github-connect-status-row { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + gap: 10px; + padding-bottom: 16px; + border-bottom: 1px solid var(--border-color); +} + +.github-connect-status-hint { + display: inline-flex; + align-items: center; + width: fit-content; + min-height: 34px; + padding: 8px 14px; + border-radius: 999px; + border: 1px solid var(--border-color); + background: rgba(255, 255, 255, 0.03); + color: var(--text-secondary); + font-size: 12px; + line-height: 1.5; + max-width: 34ch; +} + +.github-disconnect-btn { + display: inline-flex; + align-items: center; + justify-content: center; + min-height: 36px; + padding: 8px 14px; + border-radius: 999px; + border: 1px solid var(--error-border); + background: var(--error-bg); + color: var(--error-text); + font-size: 13px; + font-weight: 700; + line-height: 1; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12); +} + +.github-disconnect-btn:hover { + background: color-mix(in srgb, var(--error-bg) 72%, var(--destructive)); + border-color: var(--destructive); + color: var(--error-text); + transform: none; +} + +.github-disconnect-btn:focus-visible { + outline: 2px solid rgba(239, 68, 68, 0.45); + outline-offset: 2px; +} + +.github-connect-btn { + display: inline-flex; + align-items: center; + justify-content: center; + width: 100%; + min-height: 48px; + font-size: 14px; + font-weight: 700; +} + +.github-connect-help { + margin: 0; + font-size: 13px; + line-height: 1.6; +} + +.github-connect-inline-help { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 10px; +} + +.github-connect-flow { + display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; } .github-connect-flow-step { + display: flex; + flex-direction: column; + gap: 10px; padding: 12px; background: rgba(255, 255, 255, 0.04); border: 1px solid var(--border-color); border-radius: 16px; - min-height: 108px; + min-height: 96px; } .github-connect-flow-step span { @@ -1086,13 +1423,12 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { width: 28px; height: 28px; border-radius: 999px; - margin-bottom: 12px; background: rgba(255, 255, 255, 0.08); border: 1px solid var(--border-color); color: var(--text-primary); font-size: 12px; font-weight: 700; - font-family: 'IBM Plex Mono', ui-monospace, monospace; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; } .github-connect-flow-step p { @@ -1102,29 +1438,73 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { line-height: 1.5; } +.github-connect-card.is-connected .github-connect-intro { + gap: 14px; +} + +.github-connect-card.is-connected #githubConnectIntroText, +.github-connect-card.is-connected .github-connect-facts, +.github-connect-card.is-connected .github-connect-flow, +.github-connect-card.is-connected .github-connect-status-hint, +.github-connect-card.is-connected #githubConnectPanelCopy { + display: none; +} + +.github-connect-card.is-connected .github-connect-connected-note { + display: block; +} + +.github-connect-card.is-connected .github-connect-panel { + gap: 14px; +} + +.github-connect-card.is-connected .github-connect-panel-body { + gap: 14px; +} + +.github-connect-card.is-connected .github-connect-panel-heading { + font-size: 20px; + max-width: 20ch; +} + .device-code-card { - display: flex; - flex-direction: column; - gap: 12px; - padding: 16px; - background: rgba(255, 255, 255, 0.04); - border: 1px dashed var(--border-hover); - border-radius: 18px; + min-width: 0; } .device-code-header { display: flex; - align-items: center; + align-items: flex-start; justify-content: space-between; gap: 12px; } +.device-code-copy { + display: flex; + flex-direction: column; + gap: 4px; + min-width: 0; +} + +.device-code-copy-text { + margin: 0; + color: var(--text-secondary); + font-size: 12px; + line-height: 1.5; +} + .device-code-note { + display: inline-flex; + align-items: center; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.08em; - color: var(--text-secondary); + color: var(--text-primary); + padding: 6px 10px; + border-radius: 999px; + border: 1px solid var(--border-color); + background: rgba(255, 255, 255, 0.04); + white-space: nowrap; } .step-header-section { @@ -1202,6 +1582,26 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { align-items: stretch; } + .github-connect-panel-header { + display: flex; + } + + .github-connect-panel-heading { + font-size: 20px; + } + + .github-connect-status-row { + align-items: stretch; + } + + .github-disconnect-btn { + width: fit-content; + } + + .github-connect-status-hint { + max-width: none; + } + .github-connect-flow { grid-template-columns: 1fr; } @@ -1229,28 +1629,7 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { } .data-card { - display: flex; - align-items: center; - gap: 16px; - padding: 20px; - background: rgba(255, 255, 255, 0.04); - border: 1px solid var(--border-color); - border-radius: 18px; - transition: all 0.2s ease; - box-shadow: 0 10px 24px rgba(0, 0, 0, 0.08); -} - -.data-card:hover { - border-color: var(--border-hover); - box-shadow: 0 14px 30px rgba(0, 0, 0, 0.12); -} - -.data-card.danger-card { - border-color: var(--border-color); -} - -.data-card.danger-card:hover { - border-color: var(--destructive); + min-width: 0; } .data-icon { @@ -1282,37 +1661,51 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { line-height: 1.4; } -.data-action-btn { +/* Unified Settings button families */ +:is(.action-btn, .data-action-btn, .import-btn, .import-export-btn, .hide-pinned-btn, .unsnooze-btn, .pagination-controls button, #cancelImportBtn) { display: inline-flex; align-items: center; - gap: 6px; - padding: 8px 16px; - background: var(--link-color); - color: var(--background); - border: 1px solid var(--link-color); - border-radius: 12px; - font-size: 13px; + justify-content: center; + gap: 8px; + padding: 10px 18px; + background: rgba(255, 255, 255, 0.04); + color: var(--text-primary); + border: 1px solid var(--border-color); + border-radius: 14px; + font-size: 12px; font-weight: 600; cursor: pointer; transition: all 0.2s ease; flex-shrink: 0; - font-family: 'IBM Plex Mono', ui-monospace, monospace; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; text-transform: uppercase; } -.data-action-btn:hover { - background: var(--link-hover); +:is(.action-btn, .data-action-btn, .import-btn, .import-export-btn, .hide-pinned-btn, .unsnooze-btn, .pagination-controls button, #cancelImportBtn):hover { + background: var(--bg-secondary); + border-color: var(--link-color); transform: translateY(-1px); - box-shadow: 0 2px 8px rgba(24, 24, 27, 0.2); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); +} + +:is(.action-btn, .data-action-btn, .import-btn, .import-export-btn, .hide-pinned-btn, .unsnooze-btn, .pagination-controls button, #cancelImportBtn):active { + transform: translateY(0); + box-shadow: none; +} + +:is(.action-btn, .data-action-btn, .import-btn, .import-export-btn, .hide-pinned-btn, .unsnooze-btn, .pagination-controls button, #cancelImportBtn) svg { + flex-shrink: 0; } -.data-action-btn.danger-btn { - background: var(--destructive); +:is(.data-action-btn.danger-btn, .unsnooze-btn) { + border-color: rgba(239, 68, 68, 0.28); + color: var(--text-primary); } -.data-action-btn.danger-btn:hover { - background: var(--danger-hover); - box-shadow: 0 2px 8px rgba(239, 68, 68, 0.3); +:is(.data-action-btn.danger-btn, .unsnooze-btn):hover { + background: rgba(239, 68, 68, 0.08); + border-color: var(--destructive); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); } /* Help Tab Styles */ @@ -1323,10 +1716,12 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { } .help-logo { - width: 64px; - height: 64px; + display: block; + width: 72px; + height: 72px; margin: 0 auto 16px; - color: var(--accent-color); + border-radius: 18px; + box-shadow: 0 12px 24px rgba(0, 0, 0, 0.12); } .help-hero h2 { @@ -1452,115 +1847,345 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { border-top: 1px solid var(--border-color); } +.help-version-header { + margin-bottom: 20px; +} + .help-version-changelog h3 { font-size: 20px; font-weight: 600; color: var(--text-primary); - margin: 0 0 20px; - text-align: center; -} - -.version-info { - margin-bottom: 24px; - text-align: center; + margin: 0 0 8px; } -.version-badge { - display: inline-flex; - align-items: center; - gap: 8px; - padding: 12px 20px; - background: rgba(255, 255, 255, 0.04); - border: 1px solid var(--border-color); - border-radius: 16px; - color: var(--text-primary); +.help-version-intro { + margin: 0; + color: var(--text-secondary); + font-size: 14px; + line-height: 1.6; } -.version-badge svg { - color: var(--link-color); - flex-shrink: 0; +.version-info { + margin-bottom: 16px; } -.changelog-content { - background: rgba(255, 255, 255, 0.04); +.version-brief { + display: grid; + gap: 16px; + padding: 20px; + background: + linear-gradient(180deg, rgba(255, 255, 255, 0.045) 0%, rgba(255, 255, 255, 0.025) 100%), + var(--card); border: 1px solid var(--border-color); - border-radius: 18px; - padding: 24px; - max-height: 600px; - overflow-y: auto; + border-radius: 20px; + color: var(--text-primary); } -.changelog-content h2 { - font-size: 24px; - font-weight: 700; - color: var(--text-primary); - margin: 0 0 16px; - padding-bottom: 12px; - border-bottom: 2px solid var(--border-color); +.version-brief-top { + display: flex; + justify-content: space-between; + align-items: flex-start; + gap: 16px; } -.changelog-content h3 { - font-size: 18px; +.version-label { + display: inline-flex; + align-items: center; + gap: 8px; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; + font-size: 11px; font-weight: 600; + letter-spacing: 0.08em; + text-transform: uppercase; color: var(--link-color); - margin: 24px 0 12px; + margin-bottom: 10px; } -.changelog-content h4 { - font-size: 14px; - font-weight: 600; - color: var(--text-primary); - margin: 16px 0 8px; +.version-headline { + font-size: 24px; + font-weight: 700; + letter-spacing: -0.04em; + line-height: 1.15; + margin: 0; } -.changelog-content p { +.version-summary { + margin: 0; font-size: 14px; - color: var(--text-secondary); line-height: 1.6; - margin: 8px 0; -} - -.changelog-content ul { - margin: 12px 0; - padding-left: 24px; + color: var(--text-secondary); } -.changelog-content li { - font-size: 14px; - color: var(--text-secondary); - line-height: 1.6; - margin: 4px 0; +.release-pills { + display: flex; + flex-wrap: wrap; + gap: 8px; } -.changelog-content code { - background: var(--bg-secondary); - padding: 2px 6px; - border-radius: 4px; - font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; +.version-badge, +.release-pill { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 10px 14px; + background: rgba(255, 255, 255, 0.04); + border: 1px solid var(--border-color); + border-radius: 999px; + color: var(--text-primary); + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; + font-size: 11px; + letter-spacing: 0.06em; + text-transform: uppercase; +} + +.version-badge svg, +.release-pill svg { + color: var(--link-color); + flex-shrink: 0; +} + +.release-highlight-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 12px; +} + +.release-highlight-card { + padding: 14px; + border-radius: 16px; + border: 1px solid var(--border-color); + background: rgba(255, 255, 255, 0.03); + display: grid; + gap: 6px; +} + +.release-highlight-title, +.release-chip, +.release-section-count { + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; +} + +.release-highlight-title { + font-size: 11px; + font-weight: 600; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--text-primary); +} + +.release-highlight-copy { + margin: 0; + font-size: 13px; + line-height: 1.55; + color: var(--text-secondary); +} + +.changelog-content { + background: + linear-gradient(180deg, rgba(255, 255, 255, 0.035) 0%, rgba(255, 255, 255, 0.02) 100%), + var(--card); + border: 1px solid var(--border-color); + border-radius: 20px; + overflow: hidden; +} + +.release-chip-row { + display: flex; + flex-wrap: wrap; + gap: 8px; + padding: 16px 20px; + border-bottom: 1px solid var(--border-color); + background: rgba(255, 255, 255, 0.02); +} + +.release-chip { + appearance: none; + border: 1px solid var(--border-color); + background: rgba(255, 255, 255, 0.03); + color: var(--text-secondary); + border-radius: 999px; + padding: 8px 12px; + font-size: 11px; + font-weight: 600; + letter-spacing: 0.08em; + text-transform: uppercase; + cursor: pointer; + transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease; +} + +.release-chip:hover, +.release-chip:focus-visible, +.release-chip.active { + background: rgba(255, 255, 255, 0.08); + border-color: color-mix(in srgb, var(--link-color) 30%, var(--border-color)); + color: var(--text-primary); + outline: none; +} + +.release-notes-list { + display: grid; + gap: 12px; + padding: 16px 20px 20px; + max-height: 620px; + overflow-y: auto; +} + +.release-section { + padding: 16px; + border-radius: 18px; + border: 1px solid var(--border-color); + background: rgba(255, 255, 255, 0.03); + display: grid; + gap: 12px; + scroll-margin-top: 16px; +} + +.release-section-head { + display: flex; + justify-content: space-between; + align-items: baseline; + gap: 12px; +} + +.release-section-title { + margin: 0; + font-size: 16px; + font-weight: 700; + color: var(--text-primary); + letter-spacing: -0.02em; +} + +.release-section-count { + font-size: 11px; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--text-secondary); +} + +.release-section-body { + display: grid; + gap: 10px; +} + +.release-section-body p { + margin: 0; font-size: 14px; + line-height: 1.6; + color: var(--text-secondary); +} + +.release-section-body ul { + margin: 0; + padding-left: 20px; + display: grid; + gap: 6px; +} + +.release-section-body li { + font-size: 14px; + line-height: 1.6; + color: var(--text-secondary); +} + +.release-section-body code { + background: var(--bg-secondary); + padding: 2px 6px; + border-radius: 6px; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; + font-size: 13px; color: var(--link-color); } -.changelog-content a { +.release-section-body a { color: var(--link-color); text-decoration: none; font-weight: 500; } -.changelog-content a:hover { +.release-section-body a:hover { text-decoration: underline; } -.changelog-content strong { +.release-section-body strong { color: var(--text-primary); font-weight: 600; } -.changelog-footer { +.changelog-content > h2, +.changelog-content > h3, +.changelog-content > h4, +.changelog-content > p, +.changelog-content > ul { + margin-left: 20px; + margin-right: 20px; +} + +.changelog-content > h2 { margin-top: 20px; - padding-top: 16px; + margin-bottom: 12px; + font-size: 22px; + font-weight: 700; + letter-spacing: -0.03em; + color: var(--text-primary); +} + +.changelog-content > h3 { + margin-top: 20px; + margin-bottom: 10px; + font-size: 17px; + font-weight: 600; + color: var(--text-primary); +} + +.changelog-content > h4 { + margin-top: 16px; + margin-bottom: 8px; + font-size: 14px; + font-weight: 600; + color: var(--text-primary); +} + +.changelog-content > p, +.changelog-content > li, +.changelog-content > ul li { + font-size: 14px; + line-height: 1.6; + color: var(--text-secondary); +} + +.changelog-content > ul { + margin-top: 0; + margin-bottom: 0; + padding-left: 40px; +} + +.changelog-content > p code, +.changelog-content > ul code { + background: var(--bg-secondary); + padding: 2px 6px; + border-radius: 6px; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; + font-size: 13px; + color: var(--link-color); +} + +.changelog-content > p a, +.changelog-content > ul a { + color: var(--link-color); + text-decoration: none; +} + +.changelog-content > p a:hover, +.changelog-content > ul a:hover { + text-decoration: underline; +} + +.changelog-footer { + display: flex; + justify-content: center; + padding: 16px 20px 20px; border-top: 1px solid var(--border-color); - text-align: center; + background: rgba(255, 255, 255, 0.02); } .changelog-link { @@ -1571,14 +2196,37 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { text-decoration: none; font-size: 14px; font-weight: 500; - padding: 8px 16px; - border-radius: 8px; - transition: all 0.2s ease; + padding: 10px 16px; + border-radius: 999px; + border: 1px solid var(--border-color); + background: rgba(255, 255, 255, 0.03); + transition: background-color 0.2s ease, border-color 0.2s ease; } -.changelog-link:hover { - background: var(--bg-secondary); - text-decoration: none; +.changelog-link:hover, +.changelog-link:focus-visible { + background: rgba(255, 255, 255, 0.06); + border-color: color-mix(in srgb, var(--link-color) 24%, var(--border-color)); + outline: none; +} + +.release-empty-state { + padding: 24px 20px; + color: var(--text-secondary); + font-size: 14px; + line-height: 1.6; +} + +@media (max-width: 900px) { + .version-brief-top, + .release-section-head { + flex-direction: column; + align-items: flex-start; + } + + .release-highlight-grid { + grid-template-columns: 1fr; + } } .changelog-link svg { @@ -1608,6 +2256,20 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { /* Responsive Design */ @media (max-width: 768px) { + .activity-cards.settings-row-group > .activity-card.settings-row { + grid-template-columns: 1fr; + } + + .activity-cards.settings-row-group .settings-surface-actions { + width: 100%; + justify-content: space-between; + } + + .activity-cards.settings-row-group .settings-surface-action { + min-width: 0; + flex: 1; + } + .repo-section-header { flex-wrap: wrap; } @@ -1628,29 +2290,17 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { @media (max-width: 480px) { .activity-card { - margin: 0 -8px; - border-radius: 8px; - } - - .card-header { - padding: 12px; + margin: 0; + border-radius: 0; } - .card-controls { - padding: 10px 12px; - } - - .control-section { - gap: 6px; - } - - .feed-management-card { + .settings-surface-inline { flex-direction: column; gap: 16px; align-items: flex-start; } - .feed-management-card .card-controls { + .settings-surface-inline .settings-surface-actions { width: 100%; display: flex; justify-content: flex-end; @@ -1661,6 +2311,16 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { margin-bottom: 16px; } + .repo-item { + align-items: flex-start; + flex-direction: column; + } + + .repo-actions { + width: 100%; + justify-content: flex-start; + } + .repo-section-header { flex-direction: column; gap: 12px; @@ -1696,12 +2356,79 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { } } -.filters-help .help-text { +.filters-help { + gap: 14px; + padding: 16px 18px; +} + +.filters-help-header { + display: flex; + flex-direction: column; + gap: 6px; +} + +.filters-help-eyebrow { + display: inline-flex; + align-self: flex-start; + padding: 4px 8px; + border-radius: 999px; + border: 1px solid rgba(255, 255, 255, 0.05); + background: rgba(255, 255, 255, 0.05); + color: var(--text-primary); + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; + font-size: 11px; + font-weight: 600; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.filters-help-intro { + margin: 0; + color: var(--text-secondary); + font-size: 13px; line-height: 1.6; } -.filters-help .help-text:first-of-type { - margin-bottom: 8px; +.filters-help-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); + gap: 12px; +} + +.filters-help-item { + display: flex; + align-items: flex-start; + gap: 10px; + padding: 12px 14px; + border-radius: 14px; + background: rgba(255, 255, 255, 0.04); + border: 1px solid var(--border-color); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03); +} + +.filters-help-copy { + display: flex; + flex-direction: column; + gap: 4px; + min-width: 0; +} + +.filters-help-label { + color: var(--text-primary); + font-size: 13px; + font-weight: 600; +} + +.filters-help-detail { + color: var(--text-secondary); + font-size: 13px; + line-height: 1.5; +} + +.filters-help .info-icon { + color: var(--text-primary); + opacity: 0.82; + margin-top: 1px; } .subsection { @@ -1720,25 +2447,30 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { .repo-list { list-style: none; margin-top: 16px; + padding: 0; } .repo-item { display: flex; justify-content: space-between; - align-items: flex-start; - padding: 16px; - border: 1px solid var(--border-color); - border-radius: 16px; - margin-bottom: 12px; - background: rgba(255, 255, 255, 0.04); + align-items: center; + padding: 18px 20px; + border: none; + border-radius: 0; + margin-bottom: 0; + background: transparent; gap: 16px; transition: all 0.15s ease; } .repo-item:hover { - border-color: var(--border-hover); - transform: translateY(-1px); - box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); + background: rgba(255, 255, 255, 0.025); + transform: none; + box-shadow: none; +} + +.repo-list.settings-row-group .repo-item + .repo-item { + border-top: 1px solid var(--border-color); } .repo-content { @@ -1749,7 +2481,7 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { .repo-name { display: flex; align-items: center; - font-family: 'IBM Plex Mono', ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; font-size: 13px; font-weight: 600; color: var(--text-primary); @@ -1787,13 +2519,13 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { /* Repository Section Cards */ .repo-section-card { - background: rgba(255, 255, 255, 0.04); - border: 1px solid var(--border-color); + display: flex; + flex-direction: column; + gap: 18px; border-radius: 22px; padding: 24px; margin-bottom: 24px; - transition: all 0.2s ease; - box-shadow: 0 12px 28px rgba(0, 0, 0, 0.08); + box-shadow: 0 1px 0 rgba(255, 255, 255, 0.03) inset; } .add-repo-card { @@ -1810,11 +2542,133 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { display: flex; align-items: flex-start; gap: 16px; - margin-bottom: 20px; + margin-bottom: 0; padding-bottom: 16px; border-bottom: 1px solid var(--border-color); } +#addRepoPanel { + display: grid; + gap: 12px; +} + +.import-btn.active { + background: rgba(255, 255, 255, 0.08); + border-color: var(--border-hover); + color: var(--text-primary); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03); +} + +.popular-repos-panel { + margin: 0; +} + +.popular-repos-surface { + display: grid; + gap: 14px; + padding: 18px; + background: rgba(255, 255, 255, 0.035); + border-color: var(--border-color); +} + +.popular-repos-panel-header { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 16px; +} + +.popular-repos-panel-header h3 { + margin: 0; + color: var(--text-primary); + font-size: 16px; +} + +.popular-repos-panel-header .help-text { + margin: 6px 0 0; +} + +.popular-repos-state { + font-size: 14px; + color: var(--text-secondary); +} + +.popular-repo-suggestions { + display: flex; + flex-direction: column; + gap: 10px; +} + +.popular-repo-card { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + padding: 16px 18px; + background: rgba(255, 255, 255, 0.03); + border: 1px solid var(--border-color); + border-radius: 18px; + transition: all 0.15s ease; +} + +.popular-repo-card:hover { + border-color: var(--border-hover); + background: rgba(255, 255, 255, 0.045); + transform: translateY(-1px); + box-shadow: 0 12px 24px rgba(0, 0, 0, 0.08); +} + +.popular-repo-info { + flex: 1; + min-width: 0; +} + +.popular-repo-name { + display: flex; + align-items: center; + gap: 0; + margin-bottom: 6px; + font-size: 13px; + font-weight: 600; + color: var(--text-primary); + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; +} + +.popular-repo-description { + margin-bottom: 8px; + font-size: 14px; + line-height: 1.45; + color: var(--text-secondary); +} + +.popular-repo-meta { + display: flex; + flex-wrap: wrap; + gap: 12px; + font-size: 12px; + color: var(--text-secondary); +} + +.popular-repo-add-btn { + width: 38px; + height: 38px; + padding: 0; + border-radius: 14px; + flex-shrink: 0; + font-size: 18px; + font-weight: 700; +} + +.popular-repo-add-btn:disabled { + opacity: 1; +} + +.popular-repo-add-btn.added { + background: var(--success-bg); + border-color: var(--success-border); + color: var(--success-text); +} + .repo-section-icon { width: 32px; height: 32px; @@ -1862,7 +2716,7 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { font-size: 12px; font-weight: 700; margin-left: 4px; - font-family: 'IBM Plex Mono', ui-monospace, monospace; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; } /* Action Buttons Layout */ @@ -1884,39 +2738,6 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { align-items: center; } -.action-btn { - display: flex; - align-items: center; - gap: 8px; - padding: 10px 16px; - border: 1px solid var(--border-color); - border-radius: 12px; - background: rgba(255, 255, 255, 0.04); - color: var(--text-primary); - cursor: pointer; - font-size: 13px; - font-weight: 600; - transition: all 0.2s ease; - font-family: 'IBM Plex Mono', ui-monospace, monospace; - text-transform: uppercase; -} - -.action-btn:hover { - background: var(--input-bg); - border-color: var(--link-color); - transform: translateY(-1px); - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); -} - -.action-btn:active { - transform: translateY(0); - box-shadow: none; -} - -.action-btn svg { - flex-shrink: 0; -} - .action-btn.active { background: var(--link-color); color: white; @@ -1930,17 +2751,74 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { /* Collapsible Panels */ .repo-panel { - margin: 16px 0 24px 0; + margin: 0 0 16px 0; overflow: hidden; opacity: 0; max-height: 0; transition: all 0.2s ease-in-out; /* Simpler transition */ + border-radius: 0; +} + +.repo-panel.show { + opacity: 1; + max-height: 300px; /* Increased max-height to accommodate import buttons */ +} + +.popular-repos-panel.show { + max-height: 520px; +} + +.repo-toolbar.show { + padding-bottom: 14px; + border-bottom: 1px solid var(--border-color); +} + +.repo-notes { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 12px; + margin-top: 16px; +} + +.repo-note { + display: flex; + align-items: flex-start; + gap: 10px; + min-height: 100%; + padding: 14px 16px; border-radius: 18px; + background: rgba(255, 255, 255, 0.04); + border: 1px solid var(--border-color); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03); +} + +.repo-note-copy { + display: flex; + flex-direction: column; + gap: 4px; + min-width: 0; +} + +.repo-note-label { + color: var(--text-primary); + font-size: 13px; + font-weight: 600; +} + +.repo-note-detail { + color: var(--text-secondary); + font-size: 13px; + line-height: 1.55; } -.repo-panel.show { - opacity: 1; - max-height: 300px; /* Increased max-height to accommodate import buttons */ +.repo-notes .info-icon { + color: var(--text-primary); + opacity: 0.82; +} + +.repo-notes .help-text { + margin: 0; + font-size: 13px; } .repo-search-container { @@ -1967,23 +2845,26 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { background: rgba(255, 255, 255, 0.04); } -.search-clear-btn { - position: absolute; - right: 8px; - background: none; +:is(.search-clear-btn, .close-modal) { + background: transparent; border: none; - padding: 4px; - cursor: pointer; color: var(--text-secondary); display: flex; align-items: center; justify-content: center; - border-radius: 3px; + border-radius: 10px; transition: all 0.2s ease; } -.search-clear-btn:hover { - background-color: var(--hover-bg); +.search-clear-btn { + position: absolute; + right: 8px; + padding: 4px; + cursor: pointer; +} + +:is(.search-clear-btn, .close-modal):hover { + background: var(--bg-secondary); color: var(--text-primary); } @@ -1992,26 +2873,14 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { } .hide-pinned-btn { - display: inline-flex; - align-items: center; gap: 6px; - padding: 8px 12px; - background: rgba(255, 255, 255, 0.04); - border: 1px solid var(--border-color-dark); - border-radius: 12px; - cursor: pointer; font-size: 12px; font-weight: 600; color: var(--text-secondary); - transition: all 0.2s; white-space: nowrap; - font-family: 'IBM Plex Mono', ui-monospace, monospace; - text-transform: uppercase; } .hide-pinned-btn:hover { - background: var(--bg-secondary); - border-color: var(--link-color); color: var(--link-color); } @@ -2050,13 +2919,16 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { .pagination-controls button:disabled { opacity: 0.5; cursor: not-allowed; + transform: none; + box-shadow: none; + border-color: var(--border-color); } .add-repo-form { display: flex; align-items: center; gap: 8px; - margin-top: 16px; + margin-top: 0; } .repo-input-label { @@ -2131,20 +3003,22 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { /* Import Repos Section */ .import-repos-section { - margin: 16px 0; - padding: 16px; - background: var(--bg-tertiary); - border: 1px solid var(--border-color); - border-radius: 6px; + margin: 12px 0 0; + padding: 12px 0 0; + background: transparent; + border: none; + border-top: 1px solid var(--border-color); + border-radius: 0; } /* Import Repos Section when inside panel */ .repo-panel .import-repos-section { - margin: 16px 0 0 0; - padding: 12px 16px; - background: var(--bg-secondary); - border: 1px solid var(--border-color); - border-radius: 6px; + margin: 12px 0 0; + padding: 12px 0 0; + background: transparent; + border: none; + border-top: 1px solid var(--border-color); + border-radius: 0; } .import-repos-section .help-text { @@ -2163,27 +3037,9 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { flex-wrap: wrap; } -.import-btn { - display: inline-flex; - align-items: center; - gap: 8px; - padding: 8px 16px; - border: 1px solid var(--border-color-dark); - border-radius: 12px; - background: rgba(255, 255, 255, 0.04); - color: var(--text-primary); - cursor: pointer; - font-size: 12px; - font-family: 'IBM Plex Mono', ui-monospace, monospace; - transition: all 0.2s; - text-transform: uppercase; - font-weight: 600; -} - /* Import buttons when inside panel - make them smaller */ .repo-panel .import-btn { - padding: 6px 12px; - font-size: 14px; + padding: 8px 14px; } .repo-panel .import-icon { @@ -2191,14 +3047,11 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { height: 16px; } -.import-btn:hover { - background: var(--bg-secondary); - border-color: var(--link-color); -} - .import-btn:disabled { opacity: 0.5; cursor: not-allowed; + transform: none; + box-shadow: none; } .import-icon { @@ -2231,7 +3084,9 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { } .modal-content { - background: rgba(24, 22, 20, 0.96); + background: + linear-gradient(180deg, rgba(255, 255, 255, 0.05) 0%, rgba(255, 255, 255, 0.03) 100%), + var(--card); border: 1px solid var(--border-color); border-radius: 22px; width: 90%; @@ -2267,30 +3122,17 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { margin: 0; font-size: 18px; color: var(--text-primary); - font-family: 'IBM Plex Mono', ui-monospace, monospace; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; text-transform: uppercase; letter-spacing: -0.03em; } .close-modal { - background: none; - border: none; font-size: 24px; - color: var(--text-secondary); - cursor: pointer; padding: 0; width: 32px; height: 32px; - display: flex; - align-items: center; - justify-content: center; - border-radius: 4px; - transition: all 0.2s; -} - -.close-modal:hover { - background: var(--bg-tertiary); - color: var(--text-primary); + cursor: pointer; } .modal-body { @@ -2381,14 +3223,14 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { } .repo-item.import-variant.selected { - border-color: var(--link-color); - box-shadow: 0 0 0 2px var(--link-color); - background: var(--bg-tertiary); + border-color: rgba(16, 185, 129, 0.48); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03), 0 0 0 1px rgba(16, 185, 129, 0.34); + background: rgba(16, 185, 129, 0.12); } .repo-item.import-variant.selected:hover { transform: translateY(-1px); - box-shadow: 0 0 0 2px var(--link-color), 0 2px 4px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03), 0 0 0 1px rgba(16, 185, 129, 0.34), 0 2px 4px rgba(0, 0, 0, 0.1); } .repo-item.import-variant.already-added { @@ -2405,7 +3247,8 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { padding: 6px 12px; background: var(--success-bg); color: var(--success-text); - border-radius: 4px; + border: 1px solid var(--success-border); + border-radius: 999px; font-size: 12px; font-weight: 500; white-space: nowrap; @@ -2457,14 +3300,14 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { color: var(--text-primary); text-transform: uppercase; letter-spacing: 0.08em; - font-family: 'IBM Plex Mono', ui-monospace, monospace; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; } #deviceCodeSection input { letter-spacing: 0.22em; font-weight: 600; text-align: center; - font-family: 'IBM Plex Mono', ui-monospace, monospace; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; font-size: 20px; padding: 16px 14px; } @@ -2511,11 +3354,14 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { align-items: center; gap: 8px; flex-shrink: 0; + align-self: center; + flex-wrap: wrap; + justify-content: flex-end; } -.pin-btn { +:is(.pin-btn, .mute-btn, .link-btn) { background: rgba(255, 255, 255, 0.04); - border: 1px solid var(--border-color-dark); + border: 1px solid var(--border-color); border-radius: 12px; padding: 8px 10px; cursor: pointer; @@ -2523,13 +3369,13 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { align-items: center; justify-content: center; color: var(--text-secondary); - transition: all 0.2s; + transition: all 0.2s ease; } -.pin-btn:hover { - background: var(--bg-tertiary); +:is(.pin-btn, .mute-btn, .link-btn):hover { + background: var(--bg-secondary); border-color: var(--link-color); - color: var(--link-color); + color: var(--text-primary); } .pin-btn.pinned { @@ -2543,50 +3389,14 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { border-color: #f59e0b; } -.mute-btn { - background: rgba(255, 255, 255, 0.04); - border: 1px solid var(--border-color-dark); - border-radius: 12px; - padding: 8px 10px; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - color: var(--link-color); - transition: all 0.2s; -} - -.mute-btn:hover { - background: var(--bg-tertiary); - border-color: var(--link-color); -} - .mute-btn.muted { color: var(--text-secondary); border-color: var(--border-color); } .mute-btn.muted:hover { - color: var(--error-text); - border-color: var(--error-text); -} - -.link-btn { - background: rgba(255, 255, 255, 0.04); - border: 1px solid var(--border-color-dark); - border-radius: 12px; - padding: 8px 10px; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - color: var(--link-color); - transition: all 0.2s; -} - -.link-btn:hover { - background: var(--bg-tertiary); - border-color: var(--link-color); + color: var(--destructive); + border-color: var(--destructive); } .link-btn:focus-visible { @@ -2622,7 +3432,7 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { } .repo-item.pinned { - border-left: 3px solid #f59e0b; + box-shadow: inset 3px 0 0 #f59e0b; background: rgba(245, 158, 11, 0.05); } @@ -2634,44 +3444,12 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider { flex-wrap: wrap; } -.import-export-btn { - display: inline-flex; - align-items: center; - gap: 8px; - padding: 10px 20px; - background: rgba(255, 255, 255, 0.04); - border: 1px solid var(--border-color); - border-radius: 14px; - cursor: pointer; - font-size: 12px; - font-weight: 600; - transition: all 0.2s ease; - color: var(--text-primary); - font-family: 'IBM Plex Mono', ui-monospace, monospace; - text-transform: uppercase; -} - -.import-export-btn:hover { - background: var(--bg-secondary); - border-color: var(--link-color); - transform: translateY(-1px); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); -} - -.import-export-btn:active { - transform: translateY(0); -} - .ie-icon { width: 18px; height: 18px; flex-shrink: 0; } -body.dark-mode .import-export-btn:hover { - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); -} - /* Focus indicators for accessibility */ button:focus-visible, .import-btn:focus-visible, @@ -2711,9 +3489,17 @@ body.dark-mode select:focus-visible { outline-offset: 2px; } +.repo-item.import-variant:focus { + outline: none; +} + .repo-item.import-variant:focus-visible { - outline: 2px solid var(--link-color); - outline-offset: -2px; + outline: none; + border-color: rgba(16, 185, 129, 0.6); + box-shadow: + inset 0 1px 0 rgba(255, 255, 255, 0.03), + 0 0 0 1px rgba(16, 185, 129, 0.4), + 0 0 0 4px rgba(16, 185, 129, 0.16); } .search-clear-btn:focus-visible { @@ -2724,6 +3510,8 @@ body.dark-mode select:focus-visible { /* Current Snoozes Section */ .current-snoozes { margin-top: 24px; + padding-top: 20px; + border-top: 1px solid var(--border-color); } .current-snoozes h3 { @@ -2737,13 +3525,17 @@ body.dark-mode select:focus-visible { margin-top: 16px; } +.snoozed-repos-list.settings-row-group .snoozed-repo-item + .snoozed-repo-item { + border-top: 1px solid var(--border-color); +} + .empty-snoozes { text-align: center; - padding: 40px 20px; + padding: 28px 20px; color: var(--text-secondary); - background: var(--bg-secondary); - border: 2px dashed var(--border-color); - border-radius: 8px; + background: transparent; + border: none; + border-radius: 0; } .empty-snoozes p { @@ -2761,10 +3553,11 @@ body.dark-mode select:focus-visible { .empty-repos-card { text-align: center; padding: 48px 32px; - background: rgba(255, 255, 255, 0.04); - border: 1px dashed var(--border-color); + background: rgba(255, 255, 255, 0.03); + border: 1px solid var(--border-color); border-radius: 20px; - margin: 16px 0; + margin: 0; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03); } .empty-repos-icon { @@ -2800,10 +3593,11 @@ body.dark-mode select:focus-visible { color: var(--text-secondary); line-height: 1.6; margin: 0; - padding: 16px; - background: rgba(255, 255, 255, 0.04); - border-radius: 16px; - border: 1px solid var(--border-color); + padding: 16px 0 0; + background: transparent; + border-radius: 0; + border: none; + border-top: 1px solid var(--border-color); text-align: left; } @@ -2812,16 +3606,15 @@ body.dark-mode select:focus-visible { align-items: center; justify-content: space-between; padding: 16px; - margin-bottom: 8px; - background: rgba(255, 255, 255, 0.04); - border: 1px solid var(--border-color); - border-radius: 16px; + margin-bottom: 0; + background: transparent; + border: none; + border-radius: 0; transition: all 0.2s; } .snoozed-repo-item:hover { - background: var(--bg-tertiary); - border-color: var(--border-color-dark); + background: rgba(255, 255, 255, 0.025); } .snoozed-repo-info { @@ -2831,7 +3624,7 @@ body.dark-mode select:focus-visible { .snoozed-repo-name { font-weight: 600; color: var(--text-primary); - font-family: 'IBM Plex Mono', ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; font-size: 13px; margin-bottom: 4px; } @@ -2847,26 +3640,6 @@ body.dark-mode select:focus-visible { align-items: center; } -.unsnooze-btn { - background: var(--danger-bg); - color: white; - border: 1px solid var(--danger-bg); - padding: 8px 16px; - border-radius: 12px; - font-size: 12px; - font-weight: 600; - cursor: pointer; - transition: all 0.2s; - font-family: 'IBM Plex Mono', ui-monospace, monospace; - text-transform: uppercase; -} - -.unsnooze-btn:hover { - background: var(--danger-hover); - transform: translateY(-1px); - box-shadow: 0 2px 8px rgba(239, 68, 68, 0.3); -} - .unsnooze-btn:focus-visible { outline: 2px solid var(--link-color); outline-offset: 2px; @@ -2896,8 +3669,11 @@ body.dark-mode .snooze-expiry-warning { } .toast { - background: rgba(24, 22, 20, 0.96); - border: 1px solid var(--border-color); + position: relative; + overflow: hidden; + background: var(--card); + color: var(--foreground); + border: 1px solid var(--border); border-radius: 16px; padding: 12px 16px; box-shadow: 0 18px 32px rgba(0, 0, 0, 0.22); @@ -2958,14 +3734,14 @@ body.dark-mode .snooze-expiry-warning { .toast-message { flex: 1; - color: var(--text-primary); + color: var(--foreground); } .toast-close { flex-shrink: 0; background: none; border: none; - color: var(--text-secondary); + color: var(--muted-foreground); cursor: pointer; padding: 4px; border-radius: 10px; @@ -2978,7 +3754,25 @@ body.dark-mode .snooze-expiry-warning { .toast-close:hover { opacity: 1; - background: var(--bg-secondary); + background: var(--accent); +} + +.toast-action { + flex-shrink: 0; + background: transparent; + color: var(--foreground); + border: 1px solid var(--border); + border-radius: 10px; + padding: 6px 10px; + font-size: 12px; + font-weight: 600; + cursor: pointer; + transition: background 0.2s ease, border-color 0.2s ease, color 0.2s ease; +} + +.toast-action:hover { + background: var(--accent); + color: var(--accent-foreground); } /* Auto-remove toast progress bar */ @@ -2987,7 +3781,7 @@ body.dark-mode .snooze-expiry-warning { bottom: 0; left: 0; height: 3px; - background: var(--border-color); + background: var(--border); border-radius: 0 0 6px 6px; transition: width linear; } @@ -3021,7 +3815,7 @@ body.dark-mode .snooze-expiry-warning { cursor: pointer; transition: all 0.2s; text-decoration: none; - font-family: 'IBM Plex Mono', ui-monospace, monospace; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; text-transform: uppercase; } @@ -3075,7 +3869,7 @@ body.dark-mode .snooze-expiry-warning { padding: 8px 10px; border-radius: 10px; transition: background 0.2s, transform 0.2s; - font-family: 'IBM Plex Mono', ui-monospace, monospace; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; text-transform: uppercase; } @@ -3112,7 +3906,7 @@ body.dark-mode .setup-btn:hover { font-size: 16px; margin-bottom: 12px; font-weight: 600; - font-family: 'IBM Plex Mono', ui-monospace, monospace; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; text-transform: uppercase; } @@ -3136,7 +3930,7 @@ body.dark-mode .setup-btn:hover { font-weight: 600; text-transform: uppercase; letter-spacing: 0.08em; - font-family: 'IBM Plex Mono', ui-monospace, monospace; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; } .footer-column ul { @@ -3159,7 +3953,7 @@ body.dark-mode .setup-btn:hover { padding: 6px 8px; border-radius: 10px; transition: all 0.2s; - font-family: 'IBM Plex Mono', ui-monospace, monospace; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; text-transform: uppercase; } diff --git a/options/options.html b/options/options.html index 390aff8..41ba0fc 100644 --- a/options/options.html +++ b/options/options.html @@ -4,24 +4,20 @@ GitHub DevWatch - Settings - + + - -
- -
+
-
+ @@ -104,21 +125,29 @@

Connect GitHub

-
-
-
+
+
+

Connection status

- +

Connect once, then just paste if GitHub asks

+

DevWatch opens GitHub for you and copies the verification code automatically, so the only extra step is pasting it if GitHub prompts for one.

-
-
+
+
+ + +
+ -

- We'll open GitHub in a new tab. Approve access there, then come back here and DevWatch will finish connecting. -

+
+ Paste the copied code only if GitHub asks for it. +

+ We'll open GitHub in a new tab and copy the code for you. If GitHub asks for one, just paste it there, approve access, and come back here. +

+
-
@@ -152,7 +184,7 @@

Connect GitHub

2

Add Repositories

-

Go to the Repositories tab to add repositories you want to monitor. You can add them manually or import from your GitHub account.

+

Go to the Repositories tab to add public repositories manually, or connect GitHub to import your repos and include private ones.

@@ -178,24 +210,24 @@

View Help & Changelog

- Tip: DevWatch checks for new activity every 15 minutes by default. You'll see a badge on the extension icon when there's new activity to review. + Tip: DevWatch checks for new activity every 15 minutes by default. Change the check interval in Preferences. You'll still see a badge on the extension icon when there's new activity to review.

-