-
Notifications
You must be signed in to change notification settings - Fork 1
feat: add question collection and bookmark feature #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -47,6 +47,25 @@ function setupEventListeners() { | |
| const aboutTab = document.getElementById('about-tab'); | ||
| const settingsContent = document.getElementById('settings-content'); | ||
| const aboutContent = document.getElementById('about-content'); | ||
|
|
||
| // 收藏Tab功能 | ||
| const tabBtns = document.querySelectorAll('.tab-btn'); | ||
| const tabContents = document.querySelectorAll('.tab-content'); | ||
| tabBtns.forEach(btn => { | ||
| btn.addEventListener('click', () => { | ||
| const tab = btn.dataset.tab; | ||
| // 切换按钮状态 | ||
| tabBtns.forEach(b => b.classList.remove('active')); | ||
| btn.classList.add('active'); | ||
| // 切换内容 | ||
| tabContents.forEach(content => content.classList.remove('active')); | ||
| document.getElementById(`${tab}-tab`).classList.add('active'); | ||
| // 如果是收藏tab,加载收藏列表 | ||
| if (tab === 'favorites') { | ||
| renderFavorites(); | ||
| } | ||
| }); | ||
| }); | ||
|
Comment on lines
+52
to
+68
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The new favorites tab wiring does not match the popup DOM.
🤖 Prompt for AI Agents |
||
|
|
||
| if (settingsTab && aboutTab && settingsContent && aboutContent) { | ||
| settingsTab.addEventListener('click', function() { | ||
|
|
@@ -270,4 +289,82 @@ function showErrorMessage(message) { | |
| } catch (error) { | ||
| console.error('Error showing error message:', error); | ||
| } | ||
| } | ||
|
|
||
| // 渲染收藏列表 | ||
| function renderFavorites() { | ||
| const favoritesTab = document.getElementById('favorites-tab'); | ||
| if (!favoritesTab) return; | ||
|
|
||
| chrome.storage.local.get('favorites', (result) => { | ||
| const favorites = result.favorites || []; | ||
| if (favorites.length === 0) { | ||
| favoritesTab.innerHTML = ` | ||
| <div class="empty-state" style="text-align: center; padding: 40px 20px; color: var(--medium-text);"> | ||
| <i class="fas fa-star" style="font-size: 48px; margin-bottom: 16px; opacity: 0.3;"></i> | ||
| <p>No favorite problems yet</p> | ||
| <p style="font-size: 14px; margin-top: 8px;">Star problems on LeetCode pages to save them here</p> | ||
| </div> | ||
| `; | ||
| return; | ||
| } | ||
|
|
||
| // 按收藏时间倒序排列 | ||
| favorites.sort((a, b) => b.timestamp - a.timestamp); | ||
|
|
||
| let html = ` | ||
| <div style="margin-bottom: 16px;"> | ||
| <h3 style="margin-bottom: 8px;"><i class="fas fa-star" style="color: #f1c40f; margin-right: 6px;"></i> Your Favorites</h3> | ||
| <p style="font-size: 14px; color: var(--medium-text);">${favorites.length} saved problems</p> | ||
| </div> | ||
| <div style="max-height: 400px; overflow-y: auto; padding-right: 4px;"> | ||
| `; | ||
|
|
||
| favorites.forEach((item, index) => { | ||
| html += ` | ||
| <div class="favorite-item" style="background: var(--dark-card); border: 1px solid var(--dark-border); border-radius: 8px; padding: 12px; margin-bottom: 8px; display: flex; align-items: center; justify-content: space-between;"> | ||
| <a href="${item.url}" target="_blank" style="color: var(--light-text); text-decoration: none; flex: 1; margin-right: 8px;"> | ||
| <div style="font-weight: 500; margin-bottom: 4px;">${item.title}</div> | ||
| <div style="font-size: 12px; color: var(--medium-text);">${new Date(item.timestamp).toLocaleDateString()}</div> | ||
| </a> | ||
|
Comment on lines
+324
to
+329
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do not inject stored favorites into
🤖 Prompt for AI Agents |
||
| <button class="remove-favorite" data-index="${index}" style="background: transparent; border: none; color: var(--error-color); cursor: pointer; padding: 4px 8px; border-radius: 4px; transition: background 0.2s;"> | ||
| <i class="fas fa-trash"></i> | ||
| </button> | ||
| </div> | ||
| `; | ||
| }); | ||
|
|
||
| html += '</div>'; | ||
| favoritesTab.innerHTML = html; | ||
|
|
||
| // 添加删除收藏事件 | ||
| document.querySelectorAll('.remove-favorite').forEach(btn => { | ||
| btn.addEventListener('click', (e) => { | ||
| e.stopPropagation(); | ||
| const index = parseInt(btn.dataset.index); | ||
| removeFavorite(index); | ||
|
Comment on lines
+312
to
+345
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Delete favorites by a stable identifier, not the sorted row index. The list is rendered after sorting by Suggested fix- favorites.forEach((item, index) => {
+ favorites.forEach((item) => {
html += `
<div class="favorite-item" style="background: var(--dark-card); border: 1px solid var(--dark-border); border-radius: 8px; padding: 12px; margin-bottom: 8px; display: flex; align-items: center; justify-content: space-between;">
<a href="${item.url}" target="_blank" style="color: var(--light-text); text-decoration: none; flex: 1; margin-right: 8px;">
<div style="font-weight: 500; margin-bottom: 4px;">${item.title}</div>
<div style="font-size: 12px; color: var(--medium-text);">${new Date(item.timestamp).toLocaleDateString()}</div>
</a>
- <button class="remove-favorite" data-index="${index}" style="background: transparent; border: none; color: var(--error-color); cursor: pointer; padding: 4px 8px; border-radius: 4px; transition: background 0.2s;">
+ <button class="remove-favorite" data-url="${encodeURIComponent(item.url)}" data-timestamp="${item.timestamp}" style="background: transparent; border: none; color: var(--error-color); cursor: pointer; padding: 4px 8px; border-radius: 4px; transition: background 0.2s;">
<i class="fas fa-trash"></i>
</button>
</div>
`;
});
@@
document.querySelectorAll('.remove-favorite').forEach(btn => {
btn.addEventListener('click', (e) => {
e.stopPropagation();
- const index = parseInt(btn.dataset.index);
- removeFavorite(index);
+ removeFavorite(decodeURIComponent(btn.dataset.url), Number(btn.dataset.timestamp));
});
});
@@
-function removeFavorite(index) {
+function removeFavorite(url, timestamp) {
chrome.storage.local.get('favorites', (result) => {
- let favorites = result.favorites || [];
- favorites.splice(index, 1);
+ const favorites = (result.favorites || []).filter(
+ item => !(item.url === url && item.timestamp === timestamp)
+ );
chrome.storage.local.set({favorites: favorites}, () => {
renderFavorites();
});
});
}Also applies to: 362-368 🤖 Prompt for AI Agents |
||
| }); | ||
| }); | ||
|
|
||
| // 添加悬停效果 | ||
| document.querySelectorAll('.favorite-item').forEach(item => { | ||
| item.addEventListener('mouseenter', () => { | ||
| item.style.borderColor = 'var(--primary-color)'; | ||
| }); | ||
| item.addEventListener('mouseleave', () => { | ||
| item.style.borderColor = 'var(--dark-border)'; | ||
| }); | ||
| }); | ||
| }); | ||
| } | ||
|
|
||
| // 删除收藏 | ||
| function removeFavorite(index) { | ||
| chrome.storage.local.get('favorites', (result) => { | ||
| let favorites = result.favorites || []; | ||
| favorites.splice(index, 1); | ||
| chrome.storage.local.set({favorites: favorites}, () => { | ||
| renderFavorites(); | ||
| }); | ||
| }); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re-sync the star when
favoriteschanges outside the page.This only checks storage once during initialization. If the popup removes the current problem from
favorites(extension/popup.jsLines 362-369), the overlay icon stays filled and the next click can add the bookmark back instead of removing it.Suggested fix
document.getElementById('leetcode-helper-favorite').addEventListener('click', toggleFavorite); - // 检查当前题目是否已收藏 checkIsFavorite(); + chrome.storage.onChanged.addListener((changes, areaName) => { + if (areaName === 'local' && changes.favorites) { + checkIsFavorite(); + } + });📝 Committable suggestion
🤖 Prompt for AI Agents