Skip to content

Commit 0794cf3

Browse files
committed
feat: Improve settings page and popup UI
- Fixes an issue where the add/search repository buttons on the settings page were not working. - Simplifies the animation for the add/search panels to be quicker and less prone to visual glitches. - Adds tooltips to buttons in the popup for better usability. - Updates the theme toggle to cycle between light and dark modes.
1 parent a95ed1e commit 0794cf3

8 files changed

Lines changed: 225 additions & 64 deletions

File tree

options/options.css

Lines changed: 82 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,81 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider {
564564
margin-right: 2px;
565565
}
566566

567+
/* Action Buttons Layout */
568+
.repo-action-buttons {
569+
display: flex;
570+
justify-content: space-between;
571+
align-items: center;
572+
margin: 20px 0;
573+
padding: 16px;
574+
background: var(--card-bg);
575+
border: 1px solid var(--border-color);
576+
border-radius: 8px;
577+
}
578+
579+
.action-buttons-left,
580+
.action-buttons-right {
581+
display: flex;
582+
gap: 12px;
583+
align-items: center;
584+
}
585+
586+
.action-btn {
587+
display: flex;
588+
align-items: center;
589+
gap: 8px;
590+
padding: 10px 16px;
591+
border: 1px solid var(--border-color);
592+
border-radius: 6px;
593+
background: var(--background);
594+
color: var(--text);
595+
cursor: pointer;
596+
font-size: 14px;
597+
font-weight: 500;
598+
transition: all 0.2s ease;
599+
}
600+
601+
.action-btn:hover {
602+
background: var(--input-bg);
603+
border-color: var(--link-color);
604+
transform: translateY(-1px);
605+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
606+
}
607+
608+
.action-btn:active {
609+
transform: translateY(0);
610+
box-shadow: none;
611+
}
612+
613+
.action-btn svg {
614+
flex-shrink: 0;
615+
}
616+
617+
.action-btn.active {
618+
background: var(--link-color);
619+
color: white;
620+
border-color: var(--link-color);
621+
}
622+
623+
.action-btn.active:hover {
624+
background: var(--link-hover);
625+
border-color: var(--link-hover);
626+
}
627+
628+
/* Collapsible Panels */
629+
.repo-panel {
630+
margin: 16px 0 24px 0;
631+
overflow: hidden;
632+
opacity: 0;
633+
max-height: 0;
634+
transition: all 0.2s ease-in-out; /* Simpler transition */
635+
}
636+
637+
.repo-panel.show {
638+
opacity: 1;
639+
max-height: 150px; /* Reduced max-height to be closer to content size */
640+
}
641+
567642
.repo-search-container {
568643
margin-top: 16px;
569644
margin-bottom: 12px;
@@ -696,7 +771,13 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider {
696771
}
697772

698773
.repo-validation-status.checking::after {
699-
content: "⏳";
774+
content: "";
775+
display: inline-block;
776+
width: 16px;
777+
height: 16px;
778+
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg width='16' height='16' viewBox='0 0 16 16' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='6' stroke='%23ccc' stroke-width='2' fill='none'/%3e%3ccircle cx='8' cy='8' r='6' stroke='%233366cc' stroke-width='2' fill='none' stroke-dasharray='40' stroke-dashoffset='0' transform='rotate(-90 8 8)'%3e%3canimateTransform attributeName='transform' type='rotate' from='0 8 8' to='360 8 8' dur='1s' repeatCount='indefinite'/%3e%3canimate attributeName='stroke-dasharray' values='0 40;20 20;0 40' dur='1s' repeatCount='indefinite'/%3e%3c/circle%3e%3c/svg%3e");
779+
background-size: contain;
780+
background-repeat: no-repeat;
700781
animation: pulse 1s ease-in-out infinite;
701782
}
702783

@@ -888,20 +969,11 @@ body.dark-mode .notification-toggle input:checked + .toggle-slider {
888969
}
889970

890971
.import-loading .spinner {
891-
border: 3px solid var(--border-color);
892-
border-top: 3px solid var(--link-color);
893-
border-radius: 50%;
894972
width: 40px;
895973
height: 40px;
896-
animation: spin 1s linear infinite;
897974
margin-bottom: 16px;
898975
}
899976

900-
@keyframes spin {
901-
0% { transform: rotate(0deg); }
902-
100% { transform: rotate(360deg); }
903-
}
904-
905977
.import-loading p {
906978
color: var(--text-secondary);
907979
font-size: 14px;

options/options.html

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -80,17 +80,48 @@ <h2>GitHub Personal Access Token</h2>
8080
<h2>Watched Repositories</h2>
8181
<p class="help-text" id="repoHelpText">Add a valid GitHub token above to start adding repositories</p>
8282

83-
<div class="add-repo-form" role="form" aria-label="Add new repository">
84-
<div class="repo-input-wrapper">
85-
<input type="text" id="repoInput" placeholder="e.g., react, facebook/react, or GitHub URL" disabled aria-describedby="repo-help">
86-
<span id="repoValidationStatus" class="repo-validation-status" aria-live="polite"></span>
83+
<!-- Action Buttons Container -->
84+
<div class="repo-action-buttons">
85+
<div class="action-buttons-left">
86+
<button id="toggleAddBtn" class="action-btn" aria-label="Toggle add repository form">
87+
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
88+
<path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z"/>
89+
</svg>
90+
<span>Add</span>
91+
</button>
92+
<button id="toggleSearchBtn" class="action-btn" aria-label="Toggle search repositories">
93+
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
94+
<path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"/>
95+
</svg>
96+
<span>Search</span>
97+
</button>
98+
</div>
99+
<div class="action-buttons-right">
100+
<button id="hidePinnedToggleBtn" class="action-btn" aria-label="Toggle hide pinned repositories">
101+
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
102+
<path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.133 13.133 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.133 13.133 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5c-2.12 0-3.879-1.168-5.168-2.457A13.134 13.134 0 0 1 1.172 8z"/>
103+
<path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0z"/>
104+
</svg>
105+
<span>Hide Pinned</span>
106+
</button>
87107
</div>
88-
<button id="addRepoBtn" class="primary" disabled aria-label="Add repository to watch list">Add</button>
89108
</div>
90-
<p id="repo-help" class="help-text">Enter repository name in format owner/repo, just repo name, or full GitHub URL</p>
91-
<div id="repoError" class="repo-error"></div>
92109

93-
<div class="repo-search-container" id="repoSearchContainer" style="display: none;">
110+
<!-- Add Repository Panel (Hidden by default) -->
111+
<div class="repo-panel" id="addRepoPanel">
112+
<div class="add-repo-form" role="form" aria-label="Add new repository">
113+
<div class="repo-input-wrapper">
114+
<input type="text" id="repoInput" placeholder="e.g., react, facebook/react, or GitHub URL" disabled aria-describedby="repo-help">
115+
<span id="repoValidationStatus" class="repo-validation-status" aria-live="polite"></span>
116+
</div>
117+
<button id="addRepoBtn" class="primary" disabled aria-label="Add repository to watch list">Add</button>
118+
</div>
119+
<p id="repo-help" class="help-text">Enter repository name in format owner/repo, just repo name, or full GitHub URL</p>
120+
<div id="repoError" class="repo-error"></div>
121+
</div>
122+
123+
<!-- Search Repository Panel (Hidden by default) -->
124+
<div class="repo-panel" id="searchRepoPanel">
94125
<div class="repo-search-controls">
95126
<div class="search-input-wrapper">
96127
<input type="text" id="repoSearch" placeholder="Search repositories...">
@@ -100,13 +131,6 @@ <h2>Watched Repositories</h2>
100131
</svg>
101132
</button>
102133
</div>
103-
<button id="hidePinnedBtn" class="hide-pinned-btn" title="Hide pinned repositories" aria-label="Hide pinned repositories">
104-
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
105-
<path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.133 13.133 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.133 13.133 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5c-2.12 0-3.879-1.168-5.168-2.457A13.134 13.134 0 0 1 1.172 8z"/>
106-
<path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0z"/>
107-
</svg>
108-
<span>Hide pinned</span>
109-
</button>
110134
</div>
111135
</div>
112136

@@ -350,7 +374,18 @@ <h3 id="importModalTitle">Import Repositories</h3>
350374
</div>
351375
<div class="modal-body">
352376
<div id="importLoadingState" class="import-loading">
353-
<div class="spinner"></div>
377+
<div class="spinner">
378+
<svg width="40" height="40" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg">
379+
<circle cx="20" cy="20" r="16" stroke="var(--border-color)" stroke-width="3" fill="none"/>
380+
<circle cx="20" cy="20" r="16" stroke="var(--link-color)" stroke-width="3" fill="none"
381+
stroke-dasharray="100" stroke-dashoffset="0"
382+
transform="rotate(-90 20 20)">
383+
<animateTransform attributeName="transform" type="rotate"
384+
from="0 20 20" to="360 20 20" dur="1s" repeatCount="indefinite"/>
385+
<animate attributeName="stroke-dasharray" values="0 100;50 50;0 100" dur="1s" repeatCount="indefinite"/>
386+
</circle>
387+
</svg>
388+
</div>
354389
<p>Fetching repositories from GitHub...</p>
355390
</div>
356391
<div id="importReposList" class="import-repos-list" style="display: none;">

options/options.js

Lines changed: 73 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,21 @@ function setupEventListeners() {
3737
document.getElementById('addRepoBtn').addEventListener('click', addRepo);
3838
document.getElementById('clearTokenBtn').addEventListener('click', clearToken);
3939

40+
// Action button toggles
41+
const toggleAddBtn = document.getElementById('toggleAddBtn');
42+
const toggleSearchBtn = document.getElementById('toggleSearchBtn');
43+
const hidePinnedToggleBtn = document.getElementById('hidePinnedToggleBtn');
44+
45+
if (toggleAddBtn) {
46+
toggleAddBtn.addEventListener('click', () => togglePanel('add'));
47+
}
48+
if (toggleSearchBtn) {
49+
toggleSearchBtn.addEventListener('click', () => togglePanel('search'));
50+
}
51+
if (hidePinnedToggleBtn) {
52+
hidePinnedToggleBtn.addEventListener('click', toggleHidePinned);
53+
}
54+
4055
// Import repos buttons
4156
document.getElementById('importWatchedBtn').addEventListener('click', () => openImportModal('watched'));
4257
document.getElementById('importStarredBtn').addEventListener('click', () => openImportModal('starred'));
@@ -78,26 +93,11 @@ function setupEventListeners() {
7893
repoSearchInput.focus();
7994
});
8095

81-
// Hide/show pinned repos button
82-
const hidePinnedBtn = document.getElementById('hidePinnedBtn');
83-
hidePinnedBtn.addEventListener('click', () => {
84-
state.hidePinnedRepos = !state.hidePinnedRepos;
96+
// Listen for custom hide pinned toggle event
97+
document.addEventListener('hidePinnedToggle', (e) => {
98+
state.hidePinnedRepos = e.detail.hidden;
8599
state.currentPage = 1; // Reset to first page
86100
renderRepoList();
87-
88-
// Update button text and title
89-
const btnText = hidePinnedBtn.querySelector('span');
90-
if (state.hidePinnedRepos) {
91-
btnText.textContent = 'Show pinned';
92-
hidePinnedBtn.title = 'Show pinned repositories';
93-
hidePinnedBtn.setAttribute('aria-label', 'Show pinned repositories');
94-
hidePinnedBtn.classList.add('active');
95-
} else {
96-
btnText.textContent = 'Hide pinned';
97-
hidePinnedBtn.title = 'Hide pinned repositories';
98-
hidePinnedBtn.setAttribute('aria-label', 'Hide pinned repositories');
99-
hidePinnedBtn.classList.remove('active');
100-
}
101101
});
102102

103103
// Pagination controls
@@ -265,6 +265,61 @@ function setupEventListeners() {
265265
});
266266
}
267267

268+
// Panel toggle functionality
269+
function togglePanel(type) {
270+
const addPanel = document.getElementById('addRepoPanel');
271+
const searchPanel = document.getElementById('searchRepoPanel');
272+
const addBtn = document.getElementById('toggleAddBtn');
273+
const searchBtn = document.getElementById('toggleSearchBtn');
274+
275+
const isAddVisible = addPanel.classList.contains('show');
276+
const isSearchVisible = searchPanel.classList.contains('show');
277+
278+
// Clicked 'add'
279+
if (type === 'add') {
280+
if (isAddVisible) {
281+
addPanel.classList.remove('show');
282+
addBtn.classList.remove('active');
283+
} else {
284+
addPanel.classList.add('show');
285+
addBtn.classList.add('active');
286+
searchPanel.classList.remove('show');
287+
searchBtn.classList.remove('active');
288+
// Focus on input after animation
289+
setTimeout(() => {
290+
document.getElementById('repoInput').focus();
291+
}, 300);
292+
}
293+
}
294+
// Clicked 'search'
295+
else if (type === 'search') {
296+
if (isSearchVisible) {
297+
searchPanel.classList.remove('show');
298+
searchBtn.classList.remove('active');
299+
} else {
300+
searchPanel.classList.add('show');
301+
searchBtn.classList.add('active');
302+
addPanel.classList.remove('show');
303+
addBtn.classList.remove('active');
304+
// Focus on search input after animation
305+
setTimeout(() => {
306+
document.getElementById('repoSearch').focus();
307+
}, 300);
308+
}
309+
}
310+
}
311+
312+
function toggleHidePinned() {
313+
const btn = document.getElementById('hidePinnedToggleBtn');
314+
btn.classList.toggle('active');
315+
316+
// Trigger existing hide pinned functionality
317+
const event = new CustomEvent('hidePinnedToggle', {
318+
detail: { hidden: btn.classList.contains('active') }
319+
});
320+
document.dispatchEvent(event);
321+
}
322+
268323
function updateNotificationToggleStates() {
269324
// Update notification toggle states based on filter states
270325
const categories = ['prs', 'issues', 'releases'];
@@ -759,19 +814,14 @@ function formatDateLocal(dateString) {
759814

760815
function renderRepoList() {
761816
const list = document.getElementById('repoList');
762-
const searchContainer = document.getElementById('repoSearchContainer');
763817
const paginationControls = document.getElementById('paginationControls');
764818

765819
if (state.watchedRepos.length === 0) {
766820
list.innerHTML = '<p class="help-text">No repositories added yet</p>';
767-
searchContainer.style.display = 'none';
768821
paginationControls.style.display = 'none';
769822
return;
770823
}
771824

772-
// Show search if we have repos
773-
searchContainer.style.display = state.watchedRepos.length > 0 ? 'block' : 'none';
774-
775825
const filteredRepos = getFilteredRepos();
776826

777827
if (filteredRepos.length === 0) {

popup/popup.css

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ h1 {
341341
background: none;
342342
border: none;
343343
cursor: pointer;
344-
padding: 4px;
344+
padding: 8px;
345345
border-radius: 4px;
346346
display: flex;
347347
align-items: center;
@@ -350,6 +350,11 @@ h1 {
350350
transition: all 0.2s;
351351
}
352352

353+
.repo-snooze-btn svg {
354+
width: 16px;
355+
height: 16px;
356+
}
357+
353358
.repo-snooze-btn:hover {
354359
background: var(--bg-hover);
355360
color: var(--text-primary);

0 commit comments

Comments
 (0)