Feature/modify dashboard style#3
Open
KanoCifer wants to merge 9 commits into
Open
Conversation
- 合并 AddLinkByOpenTabs 组件,支持 manual/tabs 两种模式切换 - 新增 favicon 缺失时的 Google logo SVG 回退 - 主题选择器改用 SunIcon/MoonIcon 替换色圆 - 分组导航增加高亮闪烁动画 - 调整搜索框 focus 样式、active-bg 透明度
…d code -修复copilot review的提出的问题
- Replace onCreated listener with onUpdated dedup logic for index.html - Add closeDuplicateNewTabs to close extra blank/new-tab pages on load - Register background service worker and default_popup in manifest - Remove dead onUpdated log listener and stale comments - Normalize imports, semicolons, lang/title in index.html
- Redesign all components to Material Design 3 spec - Add collapsible MissionCard with chevron toggle and smooth animation - Replace purple MD3 palette with Google Blue color system - Update cards, buttons, inputs, modals, and drawer to MD3 surface containers - Increase nav height to 64px and adjust layout spacing - Center search form and quick links in DashboardHeader
There was a problem hiding this comment.
Pull request overview
This PR updates the extension UI to align with Material Design 3 styling, adds a collapsible MissionCard interaction, and introduces an action popup with an optional “auto-close duplicate new tabs” behavior.
Changes:
- Refactors theme tokens to MD3 surface-container elevations and switches the palette to Google Blue.
- Adds collapsible MissionCard UI + group navigation highlight animation.
- Adds an extension action popup and a new setting to auto-close duplicate “new tab” pages.
Reviewed changes
Copilot reviewed 33 out of 36 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| tsconfig.json | Includes extension/** files in TypeScript compilation. |
| src/utils/helpers.ts | Adds getDomain() helper for extracting a display domain. |
| src/stores/theme.ts | Introduces MD3 extended color tokens and updates light/dark palettes. |
| src/stores/tabs.ts | Filters blank/newtab entries on initial fetch; adds closeDuplicateNewTabs(). |
| src/stores/settings.ts | Adds doCloseDuplicateNewTabs setting and default value. |
| src/popup/PopupApp.vue | New popup UI to open/focus the extension new tab and optionally close duplicates. |
| src/popup/main.ts | Boots the popup Vue app with Pinia. |
| src/components/tabs/PageChip.vue | Updates chip styling and adds a Globe fallback icon for missing favicons. |
| src/components/tabs/OpenTabsSection.vue | Tweaks empty-state color/typography for MD3 tokens. |
| src/components/tabs/MissionCard.vue | Adds collapsible card behavior + toggle control and MD3 styling. |
| src/components/settings/SettingsPanel.vue | Updates theme selector UI and adds a new auto-close setting switch. |
| src/components/layout/GroupNav.vue | Updates styles and adds “scroll-to + highlight” behavior for groups. |
| src/components/layout/Footer.vue | Updates footer colors/border to MD3 tokens. |
| src/components/layout/AppLayout.vue | Adjusts layout padding and header offset for the new nav height. |
| src/components/icons/SunIcon.vue | Adds Sun icon component. |
| src/components/icons/MoonIcon.vue | Adds Moon icon component. |
| src/components/icons/index.ts | Exports the new icons plus GlobeIcon. |
| src/components/icons/GlobeIcon.vue | Adds Globe icon component (used as favicon fallback). |
| src/components/drawer/SearchInput.vue | Updates search input sizing and MD3 token usage. |
| src/components/drawer/DrawerPanel.vue | Updates drawer container styling and token usage. |
| src/components/dashboard/QuickLinks.vue | Updates quick links section typography to MD3 styling. |
| src/components/dashboard/QuickLinkFrame.vue | Rotates the More icon for the frame action UI. |
| src/components/dashboard/DashboardHeader.vue | Adjusts header spacing/typography and constrains search/quick-links width. |
| src/components/dashboard/Dashboard.vue | Updates sticky offset to match new nav height. |
| src/components/dashboard/AddLinkForm.vue | Adds “Add from Open Tabs” mode with animated tab picker UI. |
| src/components/common/ModalForm.vue | Updates modal overlay + container styling to MD3 tokens. |
| src/assets/variables.scss | Adds MD3 extended tokens + updates radii and base theme variables. |
| src/assets/animations.scss | Adds group highlight animation (.group-highlight). |
| src/App.vue | Calls closeDuplicateNewTabs() conditionally after load. |
| popup.html | Adds popup entry HTML for the extension action. |
| package.json | Bumps @types/chrome version. |
| package-lock.json | Updates @types/chrome and lock metadata. |
| index.html | Updates lang/title and switches entry to /src/main.ts. |
| extension/manifest.json | Adds MV3 service worker and action popup config. |
| extension/background.ts | Adds TS chrome reference and install log. |
| .gitignore | Adds ignores for Claude/Zed-related files. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+41
to
+54
|
|
||
| function scrollToGroup(domain: string) { | ||
| const el = document.getElementById(`group-${domain}`); | ||
| if (el) { | ||
| if (highlightTimer) { | ||
| el.classList.remove('group-highlight'); | ||
| clearTimeout(highlightTimer); | ||
| highlightTimer = null; | ||
| } | ||
| el.scrollIntoView({ behavior: 'smooth', block: 'start' }); | ||
| el.classList.add('group-highlight'); | ||
| highlightTimer = setTimeout(() => { | ||
| el.classList.remove('group-highlight'); | ||
| highlightTimer = null; |
Comment on lines
59
to
73
| async function fetchTabs() { | ||
| isLoading.value = true | ||
| try { | ||
| const chromeTabs = await chrome.tabs.query({}) | ||
| tabs.value = chromeTabs.map(tab => ({ | ||
| id: tab.id!, | ||
| url: tab.url || '', | ||
| title: tab.title || 'Untitled', | ||
| windowId: tab.windowId, | ||
| active: tab.active || false, | ||
| favIconUrl: tab.favIconUrl || '', | ||
| isTabOut: false, | ||
| })) | ||
| })).filter(tab => tab.url !== 'chrome://newtab/' && tab.url !== '' && tab.url !== undefined) | ||
| } catch (error) { | ||
| console.error('Failed to fetch tabs:', error) |
Comment on lines
+88
to
+103
| async function closeDuplicateNewTabs() { | ||
| const newTabUrl = chrome.runtime.getURL('index.html') | ||
| const allTabs = await chrome.tabs.query({}) | ||
|
|
||
| // 筛选出空白新标签页(Ctrl+T 打开的 chrome://newtab/ 或扩展的 index.html) | ||
| const blankTabs = allTabs.filter( | ||
| tab => | ||
| tab.url === 'chrome://newtab/' || | ||
| tab.url === newTabUrl || | ||
| tab.url === '' || | ||
| (tab.status === 'loading' && !tab.url), | ||
| ) | ||
|
|
||
| console.log('Blank tabs found:', blankTabs) | ||
| console.log('New tab:', newTabUrl) | ||
|
|
Comment on lines
+6
to
+28
| const tabsStore = useTabsStore() | ||
| const settingsStore = useSettingsStore() | ||
| const tabCount = ref(0) | ||
|
|
||
| onMounted(async () => { | ||
| const tabs = await chrome.tabs.query({}) | ||
| tabCount.value = tabs.length | ||
| }) | ||
|
|
||
| async function openNewTab() { | ||
| const newTabUrl = chrome.runtime.getURL('index.html') | ||
| const allTabs = await chrome.tabs.query({}) | ||
| const blankTabs = allTabs.filter( | ||
| t => t.url === 'chrome://newtab/' || t.url === newTabUrl, | ||
| ) | ||
|
|
||
| if (blankTabs.length > 0) { | ||
| const latest = blankTabs.reduce((a, b) => (a.id! > b.id! ? a : b)) | ||
| await chrome.tabs.update(latest.id!, { active: true }) | ||
| if (settingsStore.settings.doCloseDuplicateNewTabs) { | ||
| await tabsStore.closeDuplicateNewTabs() | ||
| } | ||
| } else { |
Comment on lines
+38
to
+52
| <template> | ||
| <div class="popup" @click="openNewTab"> | ||
| <div class="logo"> | ||
| <img src="/icons/icon128.png" alt="" width="20" height="20"> | ||
| </div> | ||
| <div class="info"> | ||
| <div class="title">Tab Harbor Vue</div> | ||
| <div class="subtitle">{{ tabCount }} tabs open</div> | ||
| </div> | ||
| <div class="arrow"> | ||
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | ||
| <path d="M7 17l9.2-9.2M17 17V7H7"/> | ||
| </svg> | ||
| </div> | ||
| </div> |
|
|
||
| // 开始监听标签页变化 | ||
|
|
||
| nextTick() |
Comment on lines
+147
to
+155
| max-height: 2000px; | ||
| transition: max-height var(--transition-base), opacity var(--transition-base), transform var(--transition-base); | ||
| transform: translateY(0); | ||
| opacity: 1; | ||
|
|
||
| &--collapsed { | ||
| max-height: 0; | ||
| transform: translateY(-8px); | ||
| opacity: 0; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Change
Preview