-
Notifications
You must be signed in to change notification settings - Fork 45
feat(sharing): add Xiaohongshu sharing guide to three share-option popups #2222
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
Conversation
🔍 PR Review CompleteReviewed PR #2222 that adds Xiaohongshu sharing functionality to the project sharing components. 📋 Analysis SummaryThis PR adds comprehensive Xiaohongshu (Little Red Book) sharing support across all three sharing components. The changes include: Core Changes:
Files Modified:
🐛 Issues FoundHigh Priority Issues1. Code Duplication
2. Magic String Usage
3. Missing Error Handling
Medium Priority Issues4. CSS Color Hardcoding
5. Accessibility Concerns
6. Inconsistent Loading States
Low Priority Issues7. CSS Comments Inconsistency
8. Layout Responsiveness
🏗️ Architecture Suggestions
📚 Documentation Consistency
✅ Positive Aspects
👉 Want me to re-run this review? Just 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.
Summary of Changes
Hello @Dshuishui, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
This pull request significantly enhances the user experience for sharing content to Xiaohongshu by integrating a clear, guided workflow into the existing direct project, recording, and screenshot sharing functionalities. The primary goal is to provide users with explicit instructions for manual sharing, circumventing current API limitations, while also refining the UI and underlying code for a more cohesive and robust sharing platform.
Highlights
- Xiaohongshu Sharing Guide: Introduced a dedicated, step-by-step guide for sharing content to Xiaohongshu within the direct project share, recording share, and screenshot share popups. This guide explicitly outlines the manual process (download, open app, upload) due to API limitations.
- UI Enhancements: Added new UI components and extensive styling to support the Xiaohongshu sharing guide, including a prominent 'Download Poster' or 'Download Video' button, and a notice about API limitations. This ensures a consistent and branded experience for Xiaohongshu users.
- Layout and Styling Adjustments: Refactored various CSS properties across sharing components to accommodate the new guide and improve overall layout and spacing, such as adjusting gaps, padding, and flexbox properties.
- Code Cleanup and Refinement: Removed outdated comments and streamlined error handling logic in the video sharing component, specifically by removing a
DefaultExceptionfor unsupported video/URL sharing and updating the associated error message.
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.
| Feature | Command | Description |
|---|---|---|
| Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
| Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
| Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in pull request comments and review comments. |
| Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
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 adds Xiaohongshu sharing guide functionality to three share-option popups. It replaces the standard QR code interface with a step-by-step guide specifically for Xiaohongshu sharing, providing users with manual upload instructions due to API limitations.
- Adds conditional rendering to show Xiaohongshu-specific sharing guides when the platform is selected
- Updates layout and styling to accommodate the new guide component
- Removes some error handling logic for unsupported video sharing platforms
Reviewed Changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| ProjectScreenshotSharing.vue | Adds Xiaohongshu guide for screenshot sharing with step-by-step instructions and styled component |
| ProjectRecordingSharing.vue | Adds Xiaohongshu guide for video sharing and removes platform compatibility error handling |
| ProjectPoster.vue | Minor layout adjustments to poster component spacing and alignment |
| ProjectDirectShare.vue | Adds Xiaohongshu guide for direct sharing with restructured layout and new styling |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| .xiaohongshu-guide { | ||
| width: 100%; | ||
| max-width: 350px; | ||
| padding: 16px; | ||
| background: linear-gradient(135deg, #fff5f5 0%, #ffeef0 100%); | ||
| border-radius: 10px; | ||
| border: 1px solid #ffb3ba; | ||
| box-shadow: 0 3px 12px rgba(255, 0, 53, 0.12); | ||
| h3 { | ||
| margin: 0 0 14px 0; | ||
| font-size: 15px; | ||
| font-weight: 600; | ||
| color: #ff0035; | ||
| text-align: center; | ||
| line-height: 1.2; | ||
| } | ||
| } | ||
| .guide-steps { | ||
| margin-bottom: 14px; | ||
| .step { | ||
| display: flex; | ||
| align-items: flex-start; | ||
| margin-bottom: 12px; | ||
| &:last-child { | ||
| margin-bottom: 0; | ||
| } | ||
| } | ||
| .step-number { | ||
| font-size: 14px; | ||
| margin-right: 8px; | ||
| flex-shrink: 0; | ||
| line-height: 1.2; | ||
| width: 16px; | ||
| } | ||
| .step-content { | ||
| flex: 1; | ||
| min-width: 0; | ||
| strong { | ||
| display: block; | ||
| font-size: 13px; | ||
| font-weight: 600; | ||
| color: #333; | ||
| margin-bottom: 3px; | ||
| line-height: 1.3; | ||
| } | ||
| p { | ||
| font-size: 12px; | ||
| color: #666; | ||
| margin: 0; | ||
| line-height: 1.4; | ||
| word-wrap: break-word; | ||
| } | ||
| } | ||
| } | ||
| .api-notice { | ||
| display: flex; | ||
| align-items: flex-start; | ||
| margin-bottom: 14px; | ||
| padding: 8px 10px; | ||
| background: rgba(255, 255, 255, 0.8); | ||
| border-radius: 6px; | ||
| .notice-icon { | ||
| font-size: 12px; | ||
| margin-right: 6px; | ||
| flex-shrink: 0; | ||
| } | ||
| p { | ||
| margin: 0; | ||
| font-size: 11px; | ||
| color: #888; | ||
| line-height: 1.4; | ||
| word-wrap: break-word; | ||
| } | ||
| } | ||
| .download-btn.primary { | ||
| width: 100%; | ||
| background: linear-gradient(135deg, #ff0035 0%, #ff4d6d 100%); | ||
| color: white; | ||
| border: none; | ||
| padding: 10px 16px; | ||
| border-radius: 8px; | ||
| font-size: 13px; | ||
| font-weight: 600; | ||
| cursor: pointer; | ||
| transition: all 0.3s ease; | ||
| box-shadow: 0 3px 8px rgba(255, 0, 53, 0.25); | ||
| &:hover:not(:disabled) { | ||
| background: linear-gradient(135deg, #e6002f 0%, #ff3366 100%); | ||
| transform: translateY(-1px); | ||
| box-shadow: 0 4px 14px rgba(255, 0, 53, 0.35); | ||
| } | ||
| &:disabled { | ||
| opacity: 0.6; | ||
| cursor: not-allowed; | ||
| } | ||
| } |
Copilot
AI
Sep 17, 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 Xiaohongshu guide styles are duplicated across multiple components (ProjectScreenshotSharing.vue, ProjectRecordingSharing.vue, and ProjectDirectShare.vue). This code duplication makes maintenance difficult. Consider extracting these styles into a shared CSS file or creating a reusable component.
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.
Code Review
This pull request adds a sharing guide for Xiaohongshu to the project, recording, and screenshot sharing popups. The implementation correctly displays the guide when Xiaohongshu is selected. However, there is significant code duplication for both the HTML structure and the CSS of the guide across the three components. My main feedback is to refactor this duplicated code into a single reusable component to improve maintainability. I've left specific comments on the relevant files.
| <div v-if="selectedPlatform?.basicInfo.name === 'xiaohongshu'" class="xiaohongshu-guide"> | ||
| <h3>📱 {{ $t({ en: 'How to share to Xiaohongshu?', zh: '如何分享到小红书?' }) }}</h3> | ||
|
|
||
| <div class="guide-steps"> | ||
| <div class="step"> | ||
| <span class="step-number">1️⃣</span> | ||
| <div class="step-content"> | ||
| <strong>{{ $t({ en: 'Download Poster', zh: '下载海报' }) }}</strong> | ||
| <p>{{ $t({ en: 'Click the button below to save poster', zh: '点击下方按钮保存海报到设备' }) }}</p> | ||
| </div> | ||
| </div> | ||
|
|
||
| <div class="step"> | ||
| <span class="step-number">2️⃣</span> | ||
| <div class="step-content"> | ||
| <strong>{{ $t({ en: 'Open Xiaohongshu App', zh: '打开小红书APP' }) }}</strong> | ||
| <p>{{ $t({ en: 'Tap "+" to create new post', zh: '点击"+"号发布新笔记' }) }}</p> | ||
| </div> | ||
| </div> | ||
|
|
||
| <div class="step"> | ||
| <span class="step-number">3️⃣</span> | ||
| <div class="step-content"> | ||
| <strong>{{ $t({ en: 'Upload & Share', zh: '上传分享' }) }}</strong> | ||
| <p>{{ $t({ en: 'Select the downloaded poster to share', zh: '选择刚下载的海报进行分享' }) }}</p> | ||
| </div> | ||
| </div> | ||
| </div> | ||
|
|
||
| <div class="api-notice"> | ||
| <span class="notice-icon">💡</span> | ||
| <p> | ||
| {{ | ||
| $t({ en: 'Manual upload required due to API limitations', zh: '由于API限制,需要手动上传,感谢理解' }) | ||
| }} | ||
| </p> | ||
| </div> | ||
|
|
||
| <button class="download-btn primary" :disabled="!posterCompRef" @click="handleDownloadPoster"> | ||
| {{ $t({ en: 'Download Poster', zh: '下载海报' }) }} | ||
| </button> | ||
| </div> |
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.
This block for the Xiaohongshu sharing guide is duplicated in ProjectRecordingSharing.vue (lines 270-322) and ProjectScreenshotSharing.vue (lines 192-244). To improve maintainability and reduce code redundancy, consider extracting this into a reusable component (e.g., XiaohongshuShareGuide.vue). This new component could accept a prop to differentiate between 'poster' and 'video' to display the correct text, and emit an event for the download action.
| .xiaohongshu-guide { | ||
| width: 100%; | ||
| max-width: 320px; | ||
| padding: 10px; | ||
| background: linear-gradient(135deg, #fff5f5 0%, #ffeef0 100%); | ||
| border-radius: 12px; | ||
| border: 2px solid #ffb3ba; | ||
| box-shadow: 0 4px 12px rgba(255, 0, 53, 0.1); | ||
| h3 { | ||
| margin: 0 0 16px 0; | ||
| font-size: 16px; | ||
| font-weight: 600; | ||
| color: #ff0035; | ||
| text-align: center; | ||
| } | ||
| } | ||
| .guide-steps { | ||
| margin-bottom: 16px; | ||
| .step { | ||
| display: flex; | ||
| align-items: flex-start; | ||
| margin-bottom: 12px; | ||
| &:last-child { | ||
| margin-bottom: 0; | ||
| } | ||
| } | ||
| .step-number { | ||
| font-size: 16px; | ||
| margin-right: 10px; | ||
| flex-shrink: 0; | ||
| line-height: 1.2; | ||
| } | ||
| .step-content { | ||
| flex: 1; | ||
| strong { | ||
| display: block; | ||
| font-size: 13px; | ||
| font-weight: 600; | ||
| color: #333; | ||
| margin-bottom: 2px; | ||
| } | ||
| p { | ||
| font-size: 12px; | ||
| color: #666; | ||
| margin: 0; | ||
| line-height: 1.3; | ||
| } | ||
| } | ||
| } | ||
| .api-notice { | ||
| display: flex; | ||
| align-items: flex-start; | ||
| margin-bottom: 16px; | ||
| padding: 10px 12px; | ||
| background: rgba(255, 255, 255, 0.8); | ||
| border-radius: 8px; | ||
| .notice-icon { | ||
| font-size: 14px; | ||
| margin-right: 6px; | ||
| flex-shrink: 0; | ||
| } | ||
| p { | ||
| margin: 0; | ||
| font-size: 11px; | ||
| color: #888; | ||
| line-height: 1.4; | ||
| } | ||
| } | ||
| .download-btn { | ||
| width: 100%; | ||
| margin-top: 8px; | ||
| border-radius: 6px; | ||
| padding: 8px 16px; | ||
| border: 1px solid var(--ui-color-primary-main); | ||
| background: var(--ui-color-primary-main); | ||
| color: white; | ||
| cursor: pointer; | ||
| transition: all 0.2s ease; | ||
| &:hover:not(:disabled) { | ||
| background: var(--ui-color-primary-shade); | ||
| color: var(--ui-color-primary-main); | ||
| } | ||
| &:disabled { | ||
| background: var(--ui-color-hint-2); | ||
| border-color: var(--ui-color-hint-2); | ||
| cursor: not-allowed; | ||
| } | ||
| } | ||
| .download-btn.primary { | ||
| width: 100%; | ||
| background: linear-gradient(135deg, #ff0035 0%, #ff4d6d 100%); | ||
| color: white; | ||
| border: none; | ||
| padding: 12px 20px; | ||
| border-radius: 8px; | ||
| font-size: 14px; | ||
| font-weight: 600; | ||
| cursor: pointer; | ||
| transition: all 0.3s ease; | ||
| &:hover:not(:disabled) { | ||
| background: linear-gradient(135deg, #e6002f 0%, #ff3366 100%); | ||
| transform: translateY(-1px); | ||
| box-shadow: 0 4px 12px rgba(255, 0, 53, 0.3); | ||
| } | ||
| &:disabled { | ||
| opacity: 0.6; | ||
| cursor: not-allowed; | ||
| } | ||
| } |
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 styles for the Xiaohongshu sharing guide are duplicated across ProjectDirectShare.vue, ProjectRecordingSharing.vue (lines 640-749), and ProjectScreenshotSharing.vue (lines 471-580). When refactoring the guide into a reusable component, these styles should be moved into that component's <style> block. This will centralize the styling and make future changes much easier.
| <span class="loading-text">{{ $t({ en: 'Generating QR code...', zh: '正在生成二维码...' }) }}</span> | ||
|
|
||
| <div class="side-content"> | ||
| <div v-if="selectedPlatform?.basicInfo.name === 'xiaohongshu'" class="xiaohongshu-guide"> |
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.
| align-items: center; | ||
| gap: 8px; | ||
| margin-bottom: 16px; | ||
| // margin-bottom: 16px; |
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.
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.
Code Review: Xiaohongshu Sharing Implementation
Found several issues requiring attention:
High Priority
• Code Duplication: Xiaohongshu guide component duplicated across 3 files
• Missing Error Handling: Download operations lack proper error handling
• Magic Strings: Platform identifiers hardcoded in multiple places
Medium Priority
• Accessibility: Emoji step numbers not screen reader friendly
• CSS Maintenance: Hardcoded brand colors throughout styles
• Loading States: Inconsistent loading state implementations
Architectural Recommendations
• Extract XiaohongshuGuide into reusable component
• Create platform constants file for maintainability
• Implement proper error boundaries for download operations
| // 清理URL对象 | ||
| URL.revokeObjectURL(url) | ||
| } catch (error) { | ||
| console.error('Failed to download poster:', error) |
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.
Add proper error handling with user-friendly error messages. Original code only logs error without notifying user or handling the exception properly.
| console.error('Failed to download poster:', error) | |
| } catch (error) { | |
| console.error('Failed to download poster:', error) | |
| // Show user-friendly error message | |
| throw new Error('Download failed. Please try again.') | |
| } |
| <span class="loading-text">{{ $t({ en: 'Generating QR code...', zh: '正在生成二维码...' }) }}</span> | ||
|
|
||
| <div class="side-content"> | ||
| <div v-if="selectedPlatform?.basicInfo.name === 'xiaohongshu'" class="xiaohongshu-guide"> |
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.
Replace magic string with constant to prevent typos and improve maintainability. This requires defining PLATFORM_CONSTANTS at the top of the file.
| <div v-if="selectedPlatform?.basicInfo.name === 'xiaohongshu'" class="xiaohongshu-guide"> | |
| <div v-if="selectedPlatform?.basicInfo.name === PLATFORM_CONSTANTS.XIAOHONGSHU" class="xiaohongshu-guide"> |
| <div class="qr-section"> | ||
| <div class="qr-section-inner"> | ||
| <div class="qr-content"> | ||
| <div v-if="selectedPlatform?.basicInfo.name === 'xiaohongshu'" class="xiaohongshu-guide"> |
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.
Replace magic string with constant for consistency and maintainability. Same magic string appears in multiple components.
| <div v-if="selectedPlatform?.basicInfo.name === 'xiaohongshu'" class="xiaohongshu-guide"> | |
| <div v-if="selectedPlatform?.basicInfo.name === PLATFORM_CONSTANTS.XIAOHONGSHU" class="xiaohongshu-guide"> |
| <div class="qr-section"> | ||
| <div class="qr-section-inner"> | ||
| <div class="qr-content"> | ||
| <div v-if="selectedPlatform?.basicInfo.name === 'xiaohongshu'" class="xiaohongshu-guide"> |
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.
Replace magic string with constant for consistency. This pattern should be consistent across all components.
| <div v-if="selectedPlatform?.basicInfo.name === 'xiaohongshu'" class="xiaohongshu-guide"> | |
| <div v-if="selectedPlatform?.basicInfo.name === PLATFORM_CONSTANTS.XIAOHONGSHU" class="xiaohongshu-guide"> |
|
|
||
| <div class="guide-steps"> | ||
| <div class="step"> | ||
| <span class="step-number">1️⃣</span> |
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.
Replace emoji with number and add aria-label for better accessibility. Emoji step numbers are not accessible to screen readers.
| <span class="step-number">1️⃣</span> | |
| <span class="step-number" aria-label="Step 1">1</span> |
| </div> | ||
|
|
||
| <div class="step"> | ||
| <span class="step-number">2️⃣</span> |
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.
Replace emoji with number and add aria-label for better accessibility.
| <span class="step-number">2️⃣</span> | |
| <span class="step-number" aria-label="Step 2">2</span> |
| </div> | ||
|
|
||
| <div class="step"> | ||
| <span class="step-number">3️⃣</span> |
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.
Replace emoji with number and add aria-label for better accessibility.
| <span class="step-number">3️⃣</span> | |
| <span class="step-number" aria-label="Step 3">3</span> |
3b62db9 to
b042d99
Compare
|
/gemini review Performs a code review for the current pull request in its current state. |
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.
Code Review
This pull request introduces a sharing guide for Xiaohongshu across three different sharing popups. A new XiaohongshuShareGuide component has been created for this purpose. The changes are well-structured, but there are a few areas for improvement. I've pointed out an inconsistency in ProjectDirectShare.vue regarding user feedback during downloads, which should be addressed. I've also made some suggestions for improving maintainability and consistency in the new XiaohongshuShareGuide component and cleaning up some commented-out code in ProjectRecordingSharing.vue.
| align-items: center; | ||
| gap: 8px; | ||
| margin-bottom: 16px; | ||
| // margin-bottom: 16px; |
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.
| <strong>{{ | ||
| type === 'video' | ||
| ? $t({ en: 'Download Video', zh: '下载视频' }) | ||
| : $t({ en: 'Download Poster', zh: '下载海报' }) | ||
| }}</strong> | ||
| <p> | ||
| {{ | ||
| type === 'video' | ||
| ? $t({ en: 'Click the button below to save video', zh: '点击下方按钮保存视频到设备' }) | ||
| : $t({ en: 'Click the button below to save poster', zh: '点击下方按钮保存海报到设备' }) | ||
| }} | ||
| </p> | ||
| </div> | ||
| </div> | ||
|
|
||
| <div class="step"> | ||
| <span class="step-number">2️⃣</span> | ||
| <div class="step-content"> | ||
| <strong>{{ $t({ en: 'Open Xiaohongshu App', zh: '打开小红书APP' }) }}</strong> | ||
| <p>{{ $t({ en: 'Tap "+" to create new post', zh: '点击"+"号发布新笔记' }) }}</p> | ||
| </div> | ||
| </div> | ||
|
|
||
| <div class="step"> | ||
| <span class="step-number">3️⃣</span> | ||
| <div class="step-content"> | ||
| <strong>{{ $t({ en: 'Upload & Share', zh: '上传分享' }) }}</strong> | ||
| <p> | ||
| {{ | ||
| type === 'video' | ||
| ? $t({ en: 'Select the downloaded video to share', zh: '选择刚下载的视频进行分享' }) | ||
| : $t({ en: 'Select the downloaded poster to share', zh: '选择刚下载的海报进行分享' }) | ||
| }} | ||
| </p> | ||
| </div> | ||
| </div> | ||
| </div> | ||
|
|
||
| <div class="api-notice"> | ||
| <span class="notice-icon">💡</span> | ||
| <p> | ||
| {{ $t({ en: 'Manual upload required due to API limitations', zh: '由于API限制,需要手动上传,感谢理解' }) }} | ||
| </p> | ||
| </div> | ||
|
|
||
| <button class="download-btn primary" :disabled="isLoading" @click="$emit('download')"> | ||
| {{ | ||
| isLoading | ||
| ? $t({ en: 'Downloading...', zh: '下载中...' }) | ||
| : type === 'video' | ||
| ? $t({ en: 'Download Video', zh: '下载视频' }) | ||
| : $t({ en: 'Download Poster', zh: '下载海报' }) | ||
| }} |
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 template contains several instances of duplicated logic for selecting translated text based on the type and isLoading props (lines 9-20, 35-42, 55-61). This can be simplified by using computed properties in the <script setup> block. This will make the template cleaner and the logic more maintainable.
For example, you could define:
import { computed } from 'vue'
import { useI18n } from 'vue-i18n' // or your i18n path
const { t } = useI18n()
const step1Title = computed(() =>
props.type === 'video'
? t({ en: 'Download Video', zh: '下载视频' })
: t({ en: 'Download Poster', zh: '下载海报' })
)
// ... and so on for other dynamic textsThen use {{ step1Title }} in your template.
| .xiaohongshu-guide { | ||
| width: 100%; | ||
| max-width: 350px; | ||
| padding: 16px; | ||
| background: linear-gradient(135deg, #fff5f5 0%, #ffeef0 100%); | ||
| border-radius: 10px; | ||
| border: 1px solid #ffb3ba; | ||
| box-shadow: 0 3px 12px rgba(255, 0, 53, 0.12); | ||
| h3 { | ||
| margin: 0 0 14px 0; | ||
| font-size: 15px; | ||
| font-weight: 600; | ||
| color: #ff0035; | ||
| text-align: center; | ||
| line-height: 1.2; | ||
| } | ||
| } | ||
| .guide-steps { | ||
| margin-bottom: 14px; | ||
| .step { | ||
| display: flex; | ||
| align-items: flex-start; | ||
| margin-bottom: 12px; | ||
| &:last-child { | ||
| margin-bottom: 0; | ||
| } | ||
| } | ||
| .step-number { | ||
| font-size: 14px; | ||
| margin-right: 8px; | ||
| flex-shrink: 0; | ||
| line-height: 1.2; | ||
| width: 16px; | ||
| } | ||
| .step-content { | ||
| flex: 1; | ||
| min-width: 0; | ||
| strong { | ||
| display: block; | ||
| font-size: 13px; | ||
| font-weight: 600; | ||
| color: #333; | ||
| margin-bottom: 3px; | ||
| line-height: 1.3; | ||
| } | ||
| p { | ||
| font-size: 12px; | ||
| color: #666; | ||
| margin: 0; | ||
| line-height: 1.4; | ||
| word-wrap: break-word; | ||
| } | ||
| } | ||
| } | ||
| .api-notice { | ||
| display: flex; | ||
| align-items: flex-start; | ||
| margin-bottom: 14px; | ||
| padding: 8px 10px; | ||
| background: rgba(255, 255, 255, 0.8); | ||
| border-radius: 6px; | ||
| .notice-icon { | ||
| font-size: 12px; | ||
| margin-right: 6px; | ||
| flex-shrink: 0; | ||
| } | ||
| p { | ||
| margin: 0; | ||
| font-size: 11px; | ||
| color: #888; | ||
| line-height: 1.4; | ||
| word-wrap: break-word; | ||
| } | ||
| } | ||
| .download-btn.primary { | ||
| width: 100%; | ||
| background: linear-gradient(135deg, #ff0035 0%, #ff4d6d 100%); | ||
| color: white; | ||
| border: none; | ||
| padding: 10px 16px; | ||
| border-radius: 8px; | ||
| font-size: 13px; | ||
| font-weight: 600; | ||
| cursor: pointer; | ||
| transition: all 0.3s ease; | ||
| box-shadow: 0 3px 8px rgba(255, 0, 53, 0.25); | ||
| &:hover:not(:disabled) { | ||
| background: linear-gradient(135deg, #e6002f 0%, #ff3366 100%); | ||
| transform: translateY(-1px); | ||
| box-shadow: 0 4px 14px rgba(255, 0, 53, 0.35); | ||
| } | ||
| &:disabled { | ||
| opacity: 0.6; | ||
| cursor: not-allowed; | ||
| } | ||
| } | ||
| </style> |
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.
This component uses hardcoded color values (e.g., #fff5f5, #ffb3ba, #ff0035). Other components in the project consistently use CSS variables from a design system (e.g., var(--ui-color-primary-main)). To maintain consistency and make theming easier, consider replacing these hardcoded colors with existing or new CSS variables. For example, #ff0035 seems to be the brand color for Xiaohongshu, which could be defined as a CSS variable like --ui-color-xiaohongshu-main.
|
/gemini review Performs a code review for the current pull request in its current state. |
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.
Code Review
This pull request introduces a sharing guide for Xiaohongshu across three different sharing popups. A new XiaohongshuShareGuide component has been created for this purpose. The changes are well-structured, but there are a few areas for improvement. I've suggested refactoring some duplicated code in the new component, improving the download handling in ProjectDirectShare.vue to be consistent with other components, and pointed out a potential regression in ProjectRecordingSharing.vue where an important platform capability check was removed. I've also noted some commented-out code that could be cleaned up.
| <XiaohongshuShareGuide | ||
| v-if="selectedPlatform?.basicInfo.name === 'xiaohongshu'" | ||
| type="poster" | ||
| :is-loading="false" | ||
| @download="handleDownloadPoster" | ||
| /> |
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 new XiaohongshuShareGuide component is used here, but its props are not correctly wired up, leading to a poor user experience and inconsistency with other parts of the application.
:is-loadingis hardcoded tofalse. This will prevent the user from seeing a loading indicator during download.@downloadis bound tohandleDownloadPoster, but this function doesn't provide a loading state or user feedback on completion/error.
To fix this, handleDownloadPoster should be wrapped with useMessageHandle, similar to how it's done in ProjectScreenshotSharing.vue and ProjectRecordingSharing.vue.
First, update handleDownloadPoster (around line 142) to use useMessageHandle:
const handleDownloadPoster = useMessageHandle(
async () => {
if (!posterCompRef.value) {
throw new Error('Poster component is not available.')
}
const posterFile = await posterCompRef.value.createPoster()
const url = URL.createObjectURL(posterFile)
const link = document.createElement('a')
link.href = url
link.download = `${props.projectData.name}-poster.png`
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
URL.revokeObjectURL(url)
},
{ en: 'Failed to download poster', zh: '下载海报失败' },
{ en: 'Poster downloaded successfully', zh: '海报下载成功' }
)Then, update the template with the suggestion below to correctly wire up the props.
<XiaohongshuShareGuide
v-if="selectedPlatform?.basicInfo.name === 'xiaohongshu'"
type="poster"
:is-loading="handleDownloadPoster.isLoading.value"
@download="handleDownloadPoster.fn"
/>
| function handlePlatformChange(platform: PlatformConfig) { | ||
| selectedPlatform.value = platform | ||
| // 检查是否需要显示下载提示 | ||
| if (!platform.shareType.supportVideo && !platform.shareType.supportURL) { | ||
| throw new DefaultException({ | ||
| en: `Please download the video to local and share it on ${platform.basicInfo.label.en}`, | ||
| zh: `请下载视频到本地,然后去${platform.basicInfo.label.zh}分享` | ||
| }) | ||
| } | ||
| // QR code generation is handled automatically by watch, no need to call manually | ||
| } |
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 check for unsupported sharing types has been removed from handlePlatformChange. Previously, if a platform supported neither video nor URL sharing (e.g., Bilibili), an informative message was shown to the user. The current implementation falls back to generating a QR code for the project URL, which can be confusing since the selected platform may not support this sharing method. This check should be restored or replaced with a more user-friendly guide for such platforms, similar to the one implemented for Xiaohongshu.
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 check for unsupported sharing types has been removed from
handlePlatformChange. Previously, if a platform supported neither video nor URL sharing (e.g., Bilibili), an informative message was shown to the user. The current implementation falls back to generating a QR code for the project URL, which can be confusing since the selected platform may not support this sharing method. This check should be restored or replaced with a more user-friendly guide for such platforms, similar to the one implemented for Xiaohongshu.
这个暂时不用,因为抖音后面可以支持了,小红书直接显示不支持,B站后面如果确定了行或者不行,就也给出比较明确的提示
| align-items: center; | ||
| gap: 8px; | ||
| margin-bottom: 16px; | ||
| // margin-bottom: 16px; |
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.
| const step1Title = computed(() => | ||
| props.type === 'video' ? t({ en: 'Download Video', zh: '下载视频' }) : t({ en: 'Download Poster', zh: '下载海报' }) | ||
| ) | ||
| const step1Description = computed(() => | ||
| props.type === 'video' | ||
| ? t({ en: 'Click the button below to save video', zh: '点击下方按钮保存视频到设备' }) | ||
| : t({ en: 'Click the button below to save poster', zh: '点击下方按钮保存海报到设备' }) | ||
| ) | ||
| const step2Title = computed(() => t({ en: 'Open Xiaohongshu App', zh: '打开小红书APP' })) | ||
| const step2Description = computed(() => t({ en: 'Tap "+" to create new post', zh: '点击"+"号发布新笔记' })) | ||
| const step3Title = computed(() => t({ en: 'Upload & Share', zh: '上传分享' })) | ||
| const step3Description = computed(() => | ||
| props.type === 'video' | ||
| ? t({ en: 'Select the downloaded video to share', zh: '选择刚下载的视频进行分享' }) | ||
| : t({ en: 'Select the downloaded poster to share', zh: '选择刚下载的海报进行分享' }) | ||
| ) | ||
| const apiNoticeText = computed(() => | ||
| t({ en: 'Manual upload required due to API limitations', zh: '由于API限制,需要手动上传,感谢理解' }) | ||
| ) | ||
| const downloadButtonText = computed(() => { | ||
| if (props.isLoading) { | ||
| return t({ en: 'Downloading...', zh: '下载中...' }) | ||
| } | ||
| return props.type === 'video' | ||
| ? t({ en: 'Download Video', zh: '下载视频' }) | ||
| : t({ en: 'Download Poster', zh: '下载海报' }) | ||
| }) |
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 properties for step1Title and downloadButtonText contain duplicate logic for generating the button/title text. This can be refactored by creating a shared computed property to avoid repetition and improve maintainability.
const downloadActionText = computed(() =>
props.type === 'video'
? t({ en: 'Download Video', zh: '下载视频' })
: t({ en: 'Download Poster', zh: '下载海报' })
)
const step1Title = downloadActionText
const step1Description = computed(() =>
props.type === 'video'
? t({ en: 'Click the button below to save video', zh: '点击下方按钮保存视频到设备' })
: t({ en: 'Click the button below to save poster', zh: '点击下方按钮保存海报到设备' })
)
const step2Title = computed(() => t({ en: 'Open Xiaohongshu App', zh: '打开小红书APP' }))
const step2Description = computed(() => t({ en: 'Tap "+" to create new post', zh: '点击"+"号发布新笔记' }))
const step3Title = computed(() => t({ en: 'Upload & Share', zh: '上传分享' }))
const step3Description = computed(() =>
props.type === 'video'
? t({ en: 'Select the downloaded video to share', zh: '选择刚下载的视频进行分享' })
: t({ en: 'Select the downloaded poster to share', zh: '选择刚下载的海报进行分享' })
)
const apiNoticeText = computed(() =>
t({ en: 'Manual upload required due to API limitations', zh: '由于API限制,需要手动上传,感谢理解' })
)
const downloadButtonText = computed(() => {
if (props.isLoading) {
return t({ en: 'Downloading...', zh: '下载中...' })
}
return downloadActionText.value
})
|
/gemini review Performs a code review for the current pull request in its current state. |
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.
Code Review
This pull request introduces a sharing guide for Xiaohongshu across three different sharing popups: direct project sharing, recording sharing, and screenshot sharing. A new XiaohongshuShareGuide component has been created for this purpose. The changes also include refactoring the download logic to use useMessageHandle for better user feedback and some style adjustments for layout consistency.
The implementation is generally good, but I've identified a potential regression in the recording sharing flow for platforms other than Xiaohongshu that require manual downloads. I've also suggested some improvements for accessibility and code maintainability in the new XiaohongshuShareGuide component.
edfb66d to
1b2ea00
Compare
… proper loading states and error handling
1b2ea00 to
3dfa9fc
Compare
|
This PR has been deployed to the preview environment. You can explore it using the preview URL. Warning Please note that deployments in the preview environment are temporary and will be automatically cleaned up after a certain period. Make sure to explore it before it is removed. For any questions, contact the XBuilder team. |
| <span class="unsupported-text">{{ $t({ en: 'Unsupported', zh: '暂不支持' }) }}</span> | ||
|
|
||
| <div class="side-content"> | ||
| <XiaohongshuShareGuide |
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.
这个跟 #2189 (comment) 这里提到的有关,我们定义 platform-share 模块的目标是,把每个平台自身的逻辑统一维护(在 platform-share),而不需要扩散到每一个具体的业务模块(如 ProjectDirectSharing, ProjectRecordingSharing, ProjectScreenshotSharing)中;因此在这里出现针对 xiaohongshu 的逻辑不是我们预期的
这里要想一下怎么把 <XiaohongshuShareGuide> 的逻辑也做进现有的 PlatformConfig 中(我们大概率需要扩展 PlatformConfig);它可能体现为一个 component(component 可以看成是返回一份 UI 描述的函数),也可能体现为返回结构化的 steps 信息或者 markdown 字符串的函数,也可能是别的
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.
这个跟 #2189 (comment) 这里提到的有关,我们定义 platform-share 模块的目标是,把每个平台自身的逻辑统一维护(在 platform-share),而不需要扩散到每一个具体的业务模块(如 ProjectDirectSharing, ProjectRecordingSharing, ProjectScreenshotSharing)中;因此在这里出现针对 xiaohongshu 的逻辑不是我们预期的
这里要想一下怎么把
<XiaohongshuShareGuide>的逻辑也做进现有的PlatformConfig中(我们大概率需要扩展PlatformConfig);它可能体现为一个 component(component 可以看成是返回一份 UI 描述的函数),也可能体现为返回结构化的 steps 信息或者 markdown 字符串的函数,也可能是别的
明白,我去和海龙沟通改进一下
No description provided.