-
Notifications
You must be signed in to change notification settings - Fork 8
add/sharecard #56
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?
add/sharecard #56
Conversation
* feat(share): implement share functionality with popup and section buttons Add share state management, popup component with QR code generation, and section share buttons. Includes: - Share state management with reactive store - Popup component with content preview and image download - Automatic injection of share buttons to section headers - QR code generation for sharing links - New dependencies for QR code and DOM capture * Merge pull request #49 from dongguacute/main feat(share): implement share functionality with popup and section but… * feat(share): improve share functionality and UI - Add route path check to limit share button injection to docs pages - Make share button always visible and remove hover scale effect - Add click feedback with green text color on share button - Update share popup with better filename, body overflow handling, and style tweaks - Change button title from "分享此页" to "保存图片" * fix (#51) * feat(share): implement share functionality with popup and section buttons Add share state management, popup component with QR code generation, and section share buttons. Includes: - Share state management with reactive store - Popup component with content preview and image download - Automatic injection of share buttons to section headers - QR code generation for sharing links - New dependencies for QR code and DOM capture * feat(share): improve share functionality and UI - Add route path check to limit share button injection to docs pages - Make share button always visible and remove hover scale effect - Add click feedback with green text color on share button - Update share popup with better filename, body overflow handling, and style tweaks - Change button title from "分享此页" to "保存图片" --------- Signed-off-by: Cherry🍒 <132185099+dongguacute@users.noreply.github.com> * refactor(share): improve share button injection and styling - Change share button container positioning to appear at section end - Replace element class check with more reliable processed marker - Adjust popup backdrop styling for better visibility - Move container styles from inline to CSS class * fix (#52) * feat(share): implement share functionality with popup and section buttons Add share state management, popup component with QR code generation, and section share buttons. Includes: - Share state management with reactive store - Popup component with content preview and image download - Automatic injection of share buttons to section headers - QR code generation for sharing links - New dependencies for QR code and DOM capture * feat(share): improve share functionality and UI - Add route path check to limit share button injection to docs pages - Make share button always visible and remove hover scale effect - Add click feedback with green text color on share button - Update share popup with better filename, body overflow handling, and style tweaks - Change button title from "分享此页" to "保存图片" * refactor(share): improve share button injection and styling - Change share button container positioning to appear at section end - Replace element class check with more reliable processed marker - Adjust popup backdrop styling for better visibility - Move container styles from inline to CSS class --------- Signed-off-by: Cherry🍒 <132185099+dongguacute@users.noreply.github.com> * feat(share-button): improve styling and positioning of share button - Change button position to be aligned with heading - Update button styling to match theme colors - Simplify DOM insertion logic by removing section traversal - Add hover effects and consistent sizing * style: update share button background color for better visibility * fix (#53) * feat(share): implement share functionality with popup and section buttons Add share state management, popup component with QR code generation, and section share buttons. Includes: - Share state management with reactive store - Popup component with content preview and image download - Automatic injection of share buttons to section headers - QR code generation for sharing links - New dependencies for QR code and DOM capture * Merge pull request #49 from dongguacute/main feat(share): implement share functionality with popup and section but… * feat(share): improve share functionality and UI - Add route path check to limit share button injection to docs pages - Make share button always visible and remove hover scale effect - Add click feedback with green text color on share button - Update share popup with better filename, body overflow handling, and style tweaks - Change button title from "分享此页" to "保存图片" * refactor(share): improve share button injection and styling - Change share button container positioning to appear at section end - Replace element class check with more reliable processed marker - Adjust popup backdrop styling for better visibility - Move container styles from inline to CSS class * feat(share-button): improve styling and positioning of share button - Change button position to be aligned with heading - Update button styling to match theme colors - Simplify DOM insertion logic by removing section traversal - Add hover effects and consistent sizing * style: update share button background color for better visibility --------- Signed-off-by: Cherry🍒 <132185099+dongguacute@users.noreply.github.com> --------- Signed-off-by: Cherry🍒 <132185099+dongguacute@users.noreply.github.com>
Deploying ab with
|
| Latest commit: |
8f0441d
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://7f3a6695.ab-7pz.pages.dev |
| Branch Preview URL: | https://add-sharecard.ab-7pz.pages.dev |
Add ability to display tags in share popup by extending share state interface Include frontmatter tags and inline badges as share tags Style tags with appropriate colors based on their type
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.
Pull request overview
This PR implements a comprehensive share functionality for VitePress documentation, allowing users to share sections of documentation as images with QR codes. The implementation includes:
- State management for share operations with reactive store
- Popup component with content preview and image download capability
- Automatic injection of share buttons next to H2 headings
- QR code generation for sharing links
- Integration with VitePress theme system
Key Changes
- New dependencies: Added
qrcode,@zumer/snapdomfor QR code generation and DOM-to-image conversion - Component architecture: Created modular component system with SharePopup, ShareButtonInjector, and InjectedShareButton
- Theme integration: Extended VitePress theme with share functionality in navigation and content areas
Reviewed changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| pnpm-lock.yaml | Added new dependencies for QR code generation and DOM capture functionality |
| package.json | Added qrcode, @zumer/snapdom, @types/qrcode, and vue dependencies |
| docs/.vitepress/theme/style.css | Hidden header anchors to clean up share card appearance |
| docs/.vitepress/theme/index.ts | Integrated share components into theme layout |
| docs/.vitepress/theme/components/shareState.ts | Implemented reactive state management for share functionality |
| docs/.vitepress/theme/components/share.vue | Updated existing share component with disabled state logic |
| docs/.vitepress/theme/components/index.ts | Created component registry and export system |
| docs/.vitepress/theme/components/SharePopup.vue | Implemented modal popup with QR code and image download |
| docs/.vitepress/theme/components/ShareButtonInjector.vue | Created DOM mutation observer to inject share buttons dynamically |
| docs/.vitepress/theme/components/InjectedShareButton.vue | Implemented individual share button component |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| function getIsDisabled() { | ||
| return !isMounted.value || !shareLink.value || shareSuccess.value | ||
| } |
Copilot
AI
Dec 29, 2025
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.
The function name getIsDisabled is misleading because it sounds like a getter for a property, but it's actually computing a boolean value. The function should be renamed to a more descriptive name that indicates it's computing the disabled state, such as computeDisabledState or isButtonDisabled.
| <Transition name="fade"> | ||
| <div v-if="shareState.isOpen" class="share-overlay" @click.self="closeShare"> | ||
| <div class="share-container"> | ||
| <!-- The Card to Capture --> | ||
| <div ref="cardRef" class="share-card"> | ||
| <!-- Main Content --> | ||
| <div class="card-content"> | ||
| <h2 class="card-title"> | ||
| {{ shareState.title }} | ||
| <div class="card-tags" v-if="shareState.tags && shareState.tags.length"> | ||
| <span v-for="tag in shareState.tags" :key="tag.text" class="tag" :class="tag.type">{{ tag.text }}</span> | ||
| </div> | ||
| </h2> | ||
| <div class="card-url">{{ shareState.url }}</div> | ||
|
|
||
| <div class="card-body vp-doc" v-html="shareState.content"></div> | ||
|
|
||
| <div class="card-footer"> | ||
| <div class="footer-info"> | ||
| <div class="site-logo"> | ||
| aboutTrans | ||
| </div> | ||
| <div class="date">{{ formatDate() }}</div> | ||
| </div> | ||
| <div class="qr-code" v-if="state.qrCodeUrl"> | ||
| <img :src="state.qrCodeUrl" alt="QR Code" /> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
|
|
||
| <!-- Action Buttons --> | ||
| <div class="actions"> | ||
| <button class="action-btn cancel" @click="closeShare"> | ||
| 关闭 | ||
| </button> | ||
|
|
||
| <button class="action-btn download" @click="handleDownload" :disabled="state.isGenerating"> | ||
| 保存 | ||
| </button> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </Transition> |
Copilot
AI
Dec 29, 2025
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.
Missing accessibility: The share button in SharePopup.vue should have proper ARIA labels and keyboard navigation support. The overlay should also trap focus within the modal and restore focus when closed. Consider adding aria-modal="true", role="dialog", and implementing focus trap for better accessibility.
| const observeDocContainer = (doc: Element) => { | ||
| // Cleanup old doc observer | ||
| if (observer) observer.disconnect() | ||
| // Initial scan | ||
| scanAndInject() | ||
| // Watch for changes inside the doc container | ||
| observer = new MutationObserver(() => { | ||
| scanAndInject() | ||
| }) | ||
| observer.observe(doc, { childList: true, subtree: true }) |
Copilot
AI
Dec 29, 2025
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.
The scanAndInject function is called on every mutation, which could lead to performance issues on pages with frequent DOM changes. Consider debouncing this function call to reduce unnecessary processing.
| // Mount the Share Button Component | ||
| const app = createApp(InjectedShareButton, { onClick: handleShare }) | ||
| app.mount(btn) | ||
| mountedApps.push(app) | ||
| container.appendChild(btn) | ||
| // Insert container at the end of h2 | ||
| h2.appendChild(container) | ||
| } |
Copilot
AI
Dec 29, 2025
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.
The component creates a new Vue app instance for each share button using createApp and mounts it. This is an anti-pattern and inefficient. Consider using a single component instance or Vue's teleport feature instead of creating multiple app instances, which can lead to memory overhead and slower performance.
| watch(() => shareState.isOpen, async (val) => { | ||
| if (typeof window !== 'undefined') { | ||
| document.body.style.overflow = val ? 'hidden' : '' | ||
| } | ||
| if (val && shareState.url) { | ||
| try { | ||
| const QRCode = await import('qrcode') | ||
| // Handle both ESM default export and CJS export | ||
| const toDataURL = QRCode.toDataURL || (QRCode.default && QRCode.default.toDataURL) | ||
| if (toDataURL) { | ||
| state.qrCodeUrl = await toDataURL(shareState.url, { | ||
| margin: 2, | ||
| width: 200, | ||
| color: { | ||
| dark: '#3c3c43', | ||
| light: '#ffffff' | ||
| } | ||
| }) | ||
| } | ||
| } catch (e) { | ||
| console.error(e) | ||
| } | ||
| } | ||
| }) |
Copilot
AI
Dec 29, 2025
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.
Missing error handling for QR code generation. If the dynamic import or toDataURL call fails, the error is only logged to console but the user isn't notified. Consider showing a fallback UI or error message when QR code generation fails.
| const handleDownload = async () => { | ||
| if (!cardRef.value || state.isGenerating) return | ||
| state.isGenerating = true | ||
| try { | ||
| // Wait for fonts/images if needed | ||
| await nextTick() | ||
| // Dynamic import to avoid SSR issues | ||
| const { snapdom } = await import('@zumer/snapdom') | ||
| // Using snapdom to download | ||
| await snapdom.download(cardRef.value, { | ||
| filename: `${shareState.title}|aboutTrans`, | ||
| scale: 2, // High res | ||
| }) | ||
| } catch (e) { | ||
| console.error('Failed to generate image:', e) | ||
| } finally { | ||
| state.isGenerating = false | ||
| } | ||
| } |
Copilot
AI
Dec 29, 2025
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.
Missing error message for the user when image download fails. The error is logged to console but users won't know what went wrong. Consider adding a user-visible error notification when the download operation fails.
| // Doc container not ready, watch body for its appearance | ||
| bodyObserver = new MutationObserver(() => { | ||
| const doc = getDocContainer() | ||
| if (doc) { | ||
| bodyObserver?.disconnect() | ||
| bodyObserver = null | ||
| observeDocContainer(doc) | ||
| } | ||
| }) | ||
| bodyObserver.observe(document.body, { childList: true, subtree: true }) | ||
| } |
Copilot
AI
Dec 29, 2025
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.
Potential memory leak: The MutationObserver is watching for changes with childList: true, subtree: true on the entire document.body when the doc container isn't found. This can lead to performance issues on pages with frequent DOM mutations. Consider adding a timeout or maximum attempt limit to stop observing after a reasonable period, or use a more targeted selector.
| <button class="share-button" :class="[ | ||
| isClicked ? '!text-green-400' : '', | ||
| isMounted ? '' : '!cursor-wait', | ||
| ]" :disabled="!isMounted" @click.stop.prevent="handleClick()" title="保存图片"> | ||
| <span flex items-center justify-center> | ||
| <svg width="14" height="14" viewBox="0 0 18 18" fill="none" xmlns="www.w3.org/2000/svg"> | ||
| <path d="M10.5 2.8125H14.625C14.9357 2.8125 15.1875 3.06434 15.1875 3.375V14.625C15.1875 14.9357 14.9357 15.1875 14.625 15.1875H3.375C3.06434 15.1875 2.8125 14.9357 2.8125 14.625V8.5M3.98602 15.1875L11.6958 7.47703C11.748 7.42473 11.8101 7.38324 11.8783 7.35494C11.9466 7.32663 12.0198 7.31206 12.0938 7.31206C12.1677 7.31206 12.2409 7.32663 12.3092 7.35494C12.3774 7.38324 12.4395 7.42473 12.4917 7.47703L15.1875 10.1735M6 2L8 4L6 6M2 2L4 4L2 6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path> | ||
| </svg> | ||
| </span> | ||
| </button> |
Copilot
AI
Dec 29, 2025
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.
Missing accessibility: The injected share button lacks proper ARIA labels. The button has a title attribute but should also include aria-label for screen readers. Additionally, the button should be keyboard accessible and announce its state changes when clicked.
| function getIsDisabled() { | ||
| return !isMounted.value || !shareLink.value || shareSuccess.value | ||
| } |
Copilot
AI
Dec 29, 2025
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.
The computed function is not actually a computed property but a regular function. Since this function is called in the template directly, consider making it a proper computed property using computed() or simplifying the logic by inlining it in the template. This will improve performance by avoiding unnecessary function calls on each render.
| } | ||
|
|
||
| .header-anchor { | ||
| opacity: 0 !important; |
Copilot
AI
Dec 29, 2025
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.
The header-anchor opacity is set to !important which might interfere with VitePress's built-in functionality. This could break the default anchor link behavior. Consider using a more specific selector or checking if this is truly necessary, as hiding the anchor links completely may reduce usability.
| } | |
| .header-anchor { | |
| opacity: 0 !important; |
Add share state management, popup component with QR code generation, and section share buttons. Includes:
feat(share): implement share functionality with popup and section but…
Add share state management, popup component with QR code generation, and section share buttons. Includes:
Add share state management, popup component with QR code generation, and section share buttons. Includes:
style: update share button background color for better visibility
feat(share): implement share functionality with popup and section buttons
Add share state management, popup component with QR code generation, and section share buttons. Includes:
feat(share): implement share functionality with popup and section but…