-
Notifications
You must be signed in to change notification settings - Fork 492
feat: html预览新增尺寸切换 #618
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: dev
Are you sure you want to change the base?
feat: html预览新增尺寸切换 #618
Conversation
WalkthroughThis update adds a viewport simulation feature for HTML artifact previews, allowing users to toggle between desktop, tablet, and mobile views with customizable dimensions. The ArtifactDialog and HTMLArtifact components are enhanced to support interactive resizing, device controls, and localized UI labels in multiple languages. No existing logic is removed. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant ArtifactDialog
participant HTMLArtifact
User->>ArtifactDialog: Opens HTML artifact
ArtifactDialog->>ArtifactDialog: Show viewport toggle (desktop/tablet/mobile)
User->>ArtifactDialog: Selects viewport/device
ArtifactDialog->>HTMLArtifact: Pass viewport size and dimensions as props
HTMLArtifact->>HTMLArtifact: Render iframe with appropriate size/style
User->>HTMLArtifact: Drags resize handles (if tablet/mobile)
HTMLArtifact->>HTMLArtifact: Update width/height, emit changes
HTMLArtifact->>ArtifactDialog: Sync updated dimensions (v-model)
User->>ArtifactDialog: Adjusts dimension inputs (optional)
ArtifactDialog->>HTMLArtifact: Update props with new dimensions
HTMLArtifact->>HTMLArtifact: Rerender iframe with new dimensions
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~15 minutes Poem
Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (4)
✅ Files skipped from review due to trivial changes (3)
🚧 Files skipped from review as they are similar to previous changes (1)
✨ Finishing Touches🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
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.
Actionable comments posted: 7
🔭 Outside diff range comments (1)
src/renderer/src/components/artifacts/HTMLArtifact.vue (1)
520-529
: Security: Restore HTML content sanitizationI wasn’t able to find any other DOMPurify usage in the codebase, and the
sanitizedContent
computed property inHTMLArtifact.vue
(lines 520–529) is commented out. Rendering rawprops.block.content
into the iframe’ssrcdoc
can still allow XSS—even with sandbox attributes. Please address this by either:
Uncommenting/reinstating the DOMPurify sanitization in
HTMLArtifact.vue
and usingsanitizedContent
for the iframe’ssrcdoc
, for example:-// const sanitizedContent = computed(() => { -// if (!props.block.content) return '' -// return DOMPurify.sanitize(props.block.content, { … }) -// }) +const sanitizedContent = computed(() => { + if (!props.block.content) return '' + return DOMPurify.sanitize(props.block.content, { + WHOLE_DOCUMENT: true, + ADD_TAGS: ['script', 'style'], + ADD_ATTR: ['src', 'style', 'onclick'], + ALLOWED_URI_REGEXP: + /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp|xxx):|[^a-z]|[a-z+.]+(?:[^a-z+.:]|$))/i + }) +})…and swap the iframe’s
srcdoc="props.block.content"
tosrcdoc="sanitizedContent"
.Or ensure that all HTML content passed into this component has already been sanitized upstream—and document where that happens.
File needing changes:
•src/renderer/src/components/artifacts/HTMLArtifact.vue
(around lines 520–529)
🧹 Nitpick comments (2)
src/renderer/src/i18n/en-US/artifacts.json (1)
39-39
: Inconsistent punctuation with sibling keys
copyImageFailedDesc
ends with a period, whereascopyFailedDesc
and most other descriptions do not. Align punctuation to avoid UI inconsistency.- "copyImageFailedDesc": "Could not copy image to clipboard.", + "copyImageFailedDesc": "Could not copy image to clipboard"src/renderer/src/components/artifacts/HTMLArtifact.vue (1)
297-307
: Consider adjusting throttle rate for better performance balance.While the throttling implementation is good, 125fps (8ms) might be excessive. Most displays run at 60Hz, so 60fps (16ms) would provide smooth updates while reducing CPU usage.
-const UPDATE_THROTTLE = 8 // 约125fps,比60fps更流畅 +const UPDATE_THROTTLE = 16 // 60fps - matches typical display refresh rates
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
src/renderer/src/components/artifacts/ArtifactDialog.vue
(4 hunks)src/renderer/src/components/artifacts/HTMLArtifact.vue
(4 hunks)src/renderer/src/i18n/en-US/artifacts.json
(1 hunks)src/renderer/src/i18n/ko-KR/artifacts.json
(1 hunks)src/renderer/src/i18n/ru-RU/artifacts.json
(1 hunks)src/renderer/src/i18n/zh-CN/artifacts.json
(1 hunks)src/renderer/src/i18n/zh-HK/artifacts.json
(1 hunks)src/renderer/src/i18n/zh-TW/artifacts.json
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
src/renderer/src/**/*
Instructions used from:
Sources:
📄 CodeRabbit Inference Engine
- .cursor/rules/i18n.mdc
src/renderer/src/i18n/**/*.json
Instructions used from:
Sources:
📄 CodeRabbit Inference Engine
- .cursor/rules/i18n.mdc
src/renderer/**
Instructions used from:
Sources:
📄 CodeRabbit Inference Engine
- .cursor/rules/project-structure.mdc
🧠 Learnings (8)
src/renderer/src/i18n/ko-KR/artifacts.json (6)
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Keep the structure of translation files consistent across all languages
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : When adding a new translation, add shared translations to common.json and language-specific translations to the respective language file; keep all language files' keys consistent
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Each language must have a separate JSON file in src/renderer/src/i18n/, and shared translation keys must be placed in common.json
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Regularly check for and remove unused translation keys from translation files
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Translation key naming must use dot-separated hierarchy, lowercase letters, and meaningful descriptive names (e.g., 'common.button.submit')
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/**/* : All user-facing strings in the renderer must use i18n keys (do not hardcode user-visible text in code; use vue-i18n translation keys instead)
src/renderer/src/i18n/en-US/artifacts.json (7)
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Keep the structure of translation files consistent across all languages
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : When adding a new translation, add shared translations to common.json and language-specific translations to the respective language file; keep all language files' keys consistent
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Each language must have a separate JSON file in src/renderer/src/i18n/, and shared translation keys must be placed in common.json
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Translation key naming must use dot-separated hierarchy, lowercase letters, and meaningful descriptive names (e.g., 'common.button.submit')
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Regularly check for and remove unused translation keys from translation files
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/**/* : All user-facing strings in the renderer must use i18n keys (do not hardcode user-visible text in code; use vue-i18n translation keys instead)
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/**/* : Do not hardcode user-facing text in code; always use the translation system (vue-i18n) for all user-visible strings
src/renderer/src/i18n/zh-HK/artifacts.json (5)
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Keep the structure of translation files consistent across all languages
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : When adding a new translation, add shared translations to common.json and language-specific translations to the respective language file; keep all language files' keys consistent
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Each language must have a separate JSON file in src/renderer/src/i18n/, and shared translation keys must be placed in common.json
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Regularly check for and remove unused translation keys from translation files
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Translation key naming must use dot-separated hierarchy, lowercase letters, and meaningful descriptive names (e.g., 'common.button.submit')
src/renderer/src/i18n/zh-TW/artifacts.json (7)
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Keep the structure of translation files consistent across all languages
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : When adding a new translation, add shared translations to common.json and language-specific translations to the respective language file; keep all language files' keys consistent
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Each language must have a separate JSON file in src/renderer/src/i18n/, and shared translation keys must be placed in common.json
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Regularly check for and remove unused translation keys from translation files
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Translation key naming must use dot-separated hierarchy, lowercase letters, and meaningful descriptive names (e.g., 'common.button.submit')
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/**/* : All user-facing strings in the renderer must use i18n keys (do not hardcode user-visible text in code; use vue-i18n translation keys instead)
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/**/* : Do not hardcode user-facing text in code; always use the translation system (vue-i18n) for all user-visible strings
src/renderer/src/i18n/zh-CN/artifacts.json (7)
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Keep the structure of translation files consistent across all languages
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : When adding a new translation, add shared translations to common.json and language-specific translations to the respective language file; keep all language files' keys consistent
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Each language must have a separate JSON file in src/renderer/src/i18n/, and shared translation keys must be placed in common.json
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Regularly check for and remove unused translation keys from translation files
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Translation key naming must use dot-separated hierarchy, lowercase letters, and meaningful descriptive names (e.g., 'common.button.submit')
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/**/* : All user-facing strings in the renderer must use i18n keys (do not hardcode user-visible text in code; use vue-i18n translation keys instead)
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/**/* : Do not hardcode user-facing text in code; always use the translation system (vue-i18n) for all user-visible strings
src/renderer/src/i18n/ru-RU/artifacts.json (5)
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Keep the structure of translation files consistent across all languages
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : When adding a new translation, add shared translations to common.json and language-specific translations to the respective language file; keep all language files' keys consistent
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Each language must have a separate JSON file in src/renderer/src/i18n/, and shared translation keys must be placed in common.json
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Translation key naming must use dot-separated hierarchy, lowercase letters, and meaningful descriptive names (e.g., 'common.button.submit')
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-06-30T12:23:45.479Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Regularly check for and remove unused translation keys from translation files
src/renderer/src/components/artifacts/ArtifactDialog.vue (5)
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/pinia-best-practices.mdc:0-0
Timestamp: 2025-06-30T12:24:10.749Z
Learning: Applies to src/renderer/src/stores/**/*.{vue,ts,tsx,js,jsx} : Use modules to organize related state and actions
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/pinia-best-practices.mdc:0-0
Timestamp: 2025-06-30T12:24:10.749Z
Learning: Applies to src/renderer/src/stores/**/*.{vue,ts,tsx,js,jsx} : Keep the store focused on global state, not component-specific data
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/pinia-best-practices.mdc:0-0
Timestamp: 2025-06-30T12:24:10.749Z
Learning: Applies to src/renderer/src/stores/**/*.{vue,ts,tsx,js,jsx} : Implement proper state persistence for maintaining data across sessions
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/vue-shadcn.mdc:0-0
Timestamp: 2025-06-23T13:06:15.335Z
Learning: Use VueUse for common composables and utility functions to promote code reuse.
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/error-logging.mdc:0-0
Timestamp: 2025-06-30T12:23:33.814Z
Learning: Applies to **/*.tsx : 使用错误边界捕获渲染错误
src/renderer/src/components/artifacts/HTMLArtifact.vue (8)
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/vue-best-practices.mdc:0-0
Timestamp: 2025-06-23T13:06:02.806Z
Learning: In Vue.js applications, prefer the Composition API for better code organization and reusability.
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/vue-shadcn.mdc:0-0
Timestamp: 2025-06-23T13:06:15.336Z
Learning: Use <script setup> syntax for concise Vue 3 component definitions.
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/vue-shadcn.mdc:0-0
Timestamp: 2025-06-23T13:06:15.336Z
Learning: Implement custom composables for reusable logic in Vue 3/Nuxt 3 projects.
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/vue-shadcn.mdc:0-0
Timestamp: 2025-06-23T13:06:15.335Z
Learning: Use template syntax for declarative rendering in Vue components.
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/vue-shadcn.mdc:0-0
Timestamp: 2025-06-23T13:06:15.336Z
Learning: Leverage ref, reactive, and computed for reactive state management in the Composition API.
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/error-logging.mdc:0-0
Timestamp: 2025-06-30T12:23:33.814Z
Learning: Applies to **/*.tsx : 使用错误边界捕获渲染错误
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/vue-shadcn.mdc:0-0
Timestamp: 2025-06-23T13:06:15.335Z
Learning: Leverage defineComponent and PropType for strong typing in Vue 3 components.
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/vue-shadcn.mdc:0-0
Timestamp: 2025-06-23T13:06:15.335Z
Learning: Use VueUse for common composables and utility functions to promote code reuse.
🔇 Additional comments (7)
src/renderer/src/components/artifacts/HTMLArtifact.vue (2)
610-623
: Excellent event listener cleanup implementation.The cleanup logic properly handles:
- Removing all event listeners on unmount
- Clearing timers to prevent memory leaks
- Resetting body styles if unmounting during drag operation
15-21
: Smart solution for iframe interaction during resize.The iframe mask overlay elegantly prevents the iframe from capturing mouse events during drag operations. The implementation using Vue's reactivity system is clean and efficient.
Also applies to: 319-328
src/renderer/src/components/artifacts/ArtifactDialog.vue (5)
52-93
: Device viewport toggle implementation looks good with proper i18n usage.The device size toggle buttons are well-structured with conditional rendering, proper styling, and correct i18n key usage. The implementation follows Vue best practices with reactive state binding.
95-135
: Dimension input controls are well-implemented with appropriate constraints.The dimension input section provides good UX with:
- Proper min/max constraints for each device type
- Responsive design with conditional rendering
- Correct v-model bindings with number modifier
- Proper i18n usage for labels
The input ranges are appropriate:
- Tablet: 320-1200px width, 426-1400px height
- Mobile: 320-480px width, 426-1000px height
247-251
: Reactive state variables are properly typed and initialized.The viewport state management is well-designed with:
- Proper TypeScript typing for viewportSize
- Reasonable default dimensions for tablet and mobile
- Consistent naming conventions
The default dimensions follow common device standards:
- Tablet: 768x1024 (iPad-like dimensions)
- Mobile: 375x667 (iPhone-like dimensions)
322-324
: setViewportSize method is simple and correct.The method properly updates the viewport size state with appropriate typing.
204-208
: Props binding to HTMLArtifact component is correctly implemented.The component properly passes all viewport-related props and v-model bindings to the HTMLArtifact component:
- viewport-size as a prop
- v-model bindings for all dimension variables
This follows Vue 3 patterns correctly and enables two-way data binding for the dimension controls.
"copyImageFailedDesc": "이미지를 클립보드에 복사할 수 없습니다", | ||
"desktop": "데스크톱", | ||
"tablet": "태블릿", | ||
"mobile": "모바일", | ||
"width": "너비", | ||
"height": "높이" |
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.
💡 Verification agent
🧩 Analysis chain
Generic terms should live in common.json
and follow hierarchical keys
desktop
, tablet
, mobile
, width
, and height
are generic UI words, not artifact-specific.
Per i18n guidelines, shared strings must be placed under src/renderer/src/i18n/**/common.json
using dot-separated, lower-case keys (e.g., common.device.desktop
, common.dimension.width
). Keeping them here duplicates data and will drift across modules/languages.
Suggest moving these entries to common.json
(all languages) and updating components to reference the new keys.
🏁 Script executed:
#!/bin/bash
# Locate all common.json files in the i18n directory
find src/renderer/src/i18n -type f -name 'common.json'
# Check for existing definitions of the generic keys in those common.json files
rg '"desktop"' -g 'src/renderer/src/i18n/**/common.json' -A2 || echo "desktop not found in any common.json"
rg '"tablet"' -g 'src/renderer/src/i18n/**/common.json' -A2 || echo "tablet not found in any common.json"
rg '"mobile"' -g 'src/renderer/src/i18n/**/common.json' -A2 || echo "mobile not found in any common.json"
rg '"width"' -g 'src/renderer/src/i18n/**/common.json' -A2 || echo "width not found in any common.json"
rg '"height"' -g 'src/renderer/src/i18n/**/common.json' -A2 || echo "height not found in any common.json"
Length of output: 1129
Move shared UI terms into common.json
These generic keys—desktop
, tablet
, mobile
, width
, and height
—belong in your shared translations, not in the artifact-specific file. Please:
• Remove these entries from each src/renderer/src/i18n/*/artifacts.json
(e.g. lines 39–44 in ko-KR/artifacts.json
).
• Add them under logical, dot-separated keys in every src/renderer/src/i18n/*/common.json
, for example:
{
…,
+ "device": {
+ "desktop": "Desktop translation",
+ "tablet": "Tablet translation",
+ "mobile": "Mobile translation"
+ },
+ "dimension": {
+ "width": "Width translation",
+ "height": "Height translation"
+ }
}
• Update all component references:
- Change
$t('artifacts.desktop')
→$t('common.device.desktop')
- Similarly for
tablet
,mobile
,width
, andheight
This ensures consistency across modules and prevents drift.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/renderer/src/i18n/ko-KR/artifacts.json lines 39 to 44, remove the keys
desktop, tablet, mobile, width, and height as they are generic UI terms. Add
these keys instead to src/renderer/src/i18n/ko-KR/common.json under a logical
namespace like common.device for desktop, tablet, and mobile, and
common.dimension for width and height. Then update all component code to replace
references from $t('artifacts.desktop') to $t('common.device.desktop') and
similarly for the other keys to ensure consistent shared translations.
"copyImageFailedDesc": "Could not copy image to clipboard.", | ||
"desktop": "Desktop", | ||
"tablet": "Tablet", | ||
"mobile": "Mobile", | ||
"width": "Width", | ||
"height": "Height" |
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.
💡 Verification agent
🧩 Analysis chain
Move generic labels to common.json
& adopt hierarchical naming
Same concern as other locales: these five labels are application-wide and should be under common.json
using a dot-separated namespace (common.device.*
, common.dimension.*
) for consistency and re-use.
🏁 Script executed:
#!/bin/bash
# Locate common.json in the i18n directory
COMMON_JSON=$(fd --full-path 'common\.json' src/renderer/src/i18n | head -n1)
echo "common.json path: ${COMMON_JSON:-not found}"
# Check whether each generic key already lives in common.json
for KEY in desktop tablet mobile width height; do
if [[ -z "$COMMON_JSON" ]]; then
echo "Skipping check for '$KEY': common.json not found"
else
if grep -q "\"$KEY\"" "$COMMON_JSON"; then
echo "✔ '$KEY' found in common.json"
else
echo "✘ '$KEY' not present in common.json"
fi
fi
done
# Search for these keys in each locale's artifacts.json
echo -e "\nScanning locale-specific artifacts.json files for generic labels..."
for FILE in src/renderer/src/i18n/*/artifacts.json; do
echo "File: $FILE"
grep -En '"(desktop|tablet|mobile|width|height)"' "$FILE" || echo " – no generic labels here"
done
Length of output: 4813
Extract generic labels into common.json with hierarchical keys
These device and dimension labels are used application-wide and should live in each locale’s common.json
with a dot-separated namespace, not under artifacts.json
. Please:
• Add to src/renderer/src/i18n/<locale>/common.json
(creating the file if missing):
"common.device.desktop": "Desktop",
"common.device.tablet": "Tablet",
"common.device.mobile": "Mobile",
"common.dimension.width": "Width",
"common.dimension.height": "Height"
(adjust target translations in non-en locales)
• Remove from every artifacts.json
where they currently appear:
- src/renderer/src/i18n/en-US/artifacts.json (lines 39–44)
- src/renderer/src/i18n/ko-KR/artifacts.json (lines 40–44)
- src/renderer/src/i18n/ru-RU/artifacts.json (lines 40–44)
- src/renderer/src/i18n/zh-CN/artifacts.json (lines 40–44)
- src/renderer/src/i18n/zh-HK/artifacts.json (lines 40–44)
- src/renderer/src/i18n/zh-TW/artifacts.json (lines 40–44)
This keeps translation keys consistent, reusable, and aligned with our dot-hierarchy convention.
🤖 Prompt for AI Agents
In src/renderer/src/i18n/en-US/artifacts.json lines 39 to 44, the device and
dimension labels are incorrectly placed under artifacts.json. Move these keys to
src/renderer/src/i18n/en-US/common.json using a dot-separated namespace like
"common.device.desktop" and "common.dimension.width". Remove these keys from
artifacts.json and replicate this change for all other locale folders mentioned,
ensuring translations are updated accordingly. This will centralize common
labels and maintain consistency across locales.
"copyFailedDesc": "无法复制内容到剪贴板", | ||
"desktop": "桌面", | ||
"tablet": "平板", | ||
"mobile": "手机", | ||
"width": "宽度", | ||
"height": "高度" |
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.
💡 Verification agent
🧩 Analysis chain
将通用词条迁移至 common.json
并使用分层命名
desktop
、tablet
、mobile
、width
、height
属于全局共用词汇,应放入各语言的 common.json
,并采用 common.device.desktop
、common.dimension.width
等点分层级命名,避免多处重复。
Here’s a quick check to locate your shared common.json
and see if those keys already live there:
🏁 Script executed:
#!/bin/bash
# Find common.json under the i18n directory and verify global keys
common_paths=$(fd -HI common.json src/renderer/src/i18n)
if [ -z "$common_paths" ]; then
echo "No common.json found under src/renderer/src/i18n"
exit 0
fi
echo "common.json found at:"
echo "$common_paths"
for path in $common_paths; do
echo "Checking keys in $path"
for key in desktop tablet mobile width height; do
echo -n " $key: "
grep -n "\"$key\"" "$path" || echo "Not found"
done
done
Length of output: 10631
Move global translation keys into common.json
with hierarchical naming
The keys "desktop"
, "tablet"
, "mobile"
, "width"
and "height"
are shared across multiple contexts and should live in each language’s common.json
under dot-separated namespaces.
• Remove these entries from
src/renderer/src/i18n/zh-CN/artifacts.json (lines 39–44)
• In src/renderer/src/i18n/zh-CN/common.json, add:
+ "common.device.desktop": "桌面",
+ "common.device.tablet": "平板",
+ "common.device.mobile": "手机",
+ "common.dimension.width": "宽度",
+ "common.dimension.height": "高度"
• Repeat the same additions in every other language’s common.json
to keep keys consistent.
• Update any code or templates that referenced artifacts.desktop
/tablet
/… to use common.device.desktop
/common.dimension.width
, etc.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/renderer/src/i18n/zh-CN/artifacts.json lines 39 to 44, remove the keys
"desktop", "tablet", "mobile", "width", and "height" as they are global
translation keys. Add these keys with appropriate hierarchical namespaces (e.g.,
device.desktop, device.tablet, device.mobile, dimension.width, dimension.height)
into src/renderer/src/i18n/zh-CN/common.json. Repeat this addition in all other
language common.json files to maintain consistency. Finally, update all code and
templates referencing these keys from artifacts to use the new paths under
common, such as common.device.desktop or common.dimension.width.
"copyImageFailedDesc": "無法複製圖片到剪貼板", | ||
"desktop": "桌面", | ||
"tablet": "平板", | ||
"mobile": "手機", | ||
"width": "寬度", | ||
"height": "高度" |
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.
🛠️ Refactor suggestion
將共用字串移至 common.json
並使用階層式 key
同上:請把「desktop / tablet / mobile / width / height」移到 common.json
,並使用如 common.device.desktop
的點分命名,以維持多語系一致性。
🤖 Prompt for AI Agents
In src/renderer/src/i18n/zh-HK/artifacts.json lines 39 to 44, the keys
"desktop", "tablet", "mobile", "width", and "height" should be moved to
src/renderer/src/i18n/zh-HK/common.json to centralize shared strings. After
moving, update their keys to use hierarchical dot notation like
"common.device.desktop" to maintain consistency across languages. Then, replace
their usage in artifacts.json with references to these new keys.
"copyImageFailedDesc": "無法複製圖片到剪貼板", | ||
"desktop": "桌面", | ||
"tablet": "平板", | ||
"mobile": "手機", | ||
"width": "寬度", | ||
"height": "高度" |
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.
🛠️ Refactor suggestion
共用詞條應集中於 common.json
與其他語系一致,請將此處新增的五個通用詞條遷移至 common.json
,並採用點分層級命名。
🤖 Prompt for AI Agents
In src/renderer/src/i18n/zh-TW/artifacts.json lines 39 to 44, the five common
terms added should be moved to the common.json file to maintain consistency
across languages. Relocate these entries to common.json and rename them using
dot-separated hierarchical keys to reflect their shared usage properly.
"desktop": "Рабочий стол", | ||
"tablet": "Планшет", | ||
"mobile": "Мобильный", | ||
"width": "Ширина", | ||
"height": "Высота" |
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.
💡 Verification agent
🧩 Analysis chain
Verify translation consistency across all language files.
The new translation keys are properly formatted. However, according to the coding guidelines, we need to ensure these keys are added to all language files to maintain consistency.
🏁 Script executed:
#!/bin/bash
# Description: Verify that the new translation keys are present in all language files
# Find all artifacts.json files in different languages
echo "Checking for new keys in all language files..."
for file in $(fd -t f "artifacts.json" src/renderer/src/i18n/); do
echo -e "\n=== $file ==="
# Check for each new key
for key in "desktop" "tablet" "mobile" "width" "height"; do
if rg -q "\"$key\":" "$file"; then
echo "✓ Key '$key' found"
else
echo "✗ Key '$key' missing"
fi
done
done
# Also check if these keys might be better suited for common.json
echo -e "\n=== Checking if similar keys exist in common.json files ==="
fd -t f "common.json" src/renderer/src/i18n/ -x rg -l "\"(desktop|tablet|mobile|width|height)\":" {} \;
Length of output: 10099
Add missing translation keys in artifacts.json
for all languages
The new keys (desktop
, tablet
, mobile
, width
, height
) are present in en-US, ko-KR, ru-RU, zh-CN, zh-HK, and zh-TW but are missing in several language files. They should remain in artifacts.json
(no duplicates found in common.json
).
Please add the following keys (with appropriate translations) to each of these files:
- src/renderer/src/i18n/fa-IR/artifacts.json
- src/renderer/src/i18n/fr-FR/artifacts.json
- src/renderer/src/i18n/ja-JP/artifacts.json
Ensure the keys follow the existing structure and dot-separated naming (artifacts.desktop
, etc.) so that all language files remain consistent.
🤖 Prompt for AI Agents
In src/renderer/src/i18n/fa-IR/artifacts.json, fr-FR/artifacts.json, and
ja-JP/artifacts.json, add the missing translation keys "desktop", "tablet",
"mobile", "width", and "height" with appropriate translations. Follow the
existing JSON structure and ensure the keys use the same dot-separated naming
convention as in other language files to maintain consistency across all
artifacts.json files.
}" | ||
@mousedown="handleTopDragStart" | ||
:style="{ | ||
top: `calc(50% - ${(viewportSize === 'mobile' ? (mobileHeight || 844) : (tabletHeight || 800)) / 2}px - 1px)`, | ||
width: `${viewportSize === 'mobile' ? (mobileWidth || 390) : (tabletWidth || 680)}px` | ||
}" | ||
> | ||
<div class="absolute inset-x-0 top-1/2 transform -translate-y-1/2 h-0.5 bg-blue-500 opacity-0 group-hover:opacity-100 transition-opacity duration-200" | ||
:class="{ 'opacity-100': isDragging }"></div> | ||
</div> | ||
|
||
<!-- 下侧拖动手柄 --> | ||
<div | ||
v-if="viewportSize !== 'desktop'" | ||
class="absolute left-1/2 transform -translate-x-1/2 h-2 cursor-row-resize transition-all duration-200 group" | ||
:class="{ | ||
'bg-blue-500 bg-opacity-30': isDragging, | ||
'hover:bg-blue-500 hover:bg-opacity-20': !isDragging | ||
}" | ||
@mousedown="handleBottomDragStart" | ||
:style="{ | ||
bottom: `calc(50% - ${(viewportSize === 'mobile' ? (mobileHeight || 844) : (tabletHeight || 800)) / 2}px - 1px)`, | ||
width: `${viewportSize === 'mobile' ? (mobileWidth || 390) : (tabletWidth || 680)}px` | ||
}" | ||
> | ||
<div class="absolute inset-x-0 top-1/2 transform -translate-y-1/2 h-0.5 bg-blue-500 opacity-0 group-hover:opacity-100 transition-opacity duration-200" | ||
:class="{ 'opacity-100': isDragging }"></div> | ||
</div> | ||
|
||
<!-- 左上角拖动手柄 --> | ||
<div | ||
v-if="viewportSize !== 'desktop'" | ||
class="absolute w-3 h-3 cursor-nw-resize transition-all duration-200 group" | ||
:class="{ | ||
'bg-blue-500 bg-opacity-30': isDragging, | ||
'hover:bg-blue-500 hover:bg-opacity-20': !isDragging | ||
}" | ||
@mousedown="(e) => handleCornerDragStart(e, 'nw')" | ||
:style="{ | ||
left: `calc(50% - ${(viewportSize === 'mobile' ? (mobileWidth || 390) : (tabletWidth || 680)) / 2}px - 1px)`, | ||
top: `calc(50% - ${(viewportSize === 'mobile' ? (mobileHeight || 844) : (tabletHeight || 800)) / 2}px - 1px)` | ||
}" | ||
> | ||
<div class="absolute inset-0 border-l-2 border-t-2 border-blue-500 opacity-0 group-hover:opacity-100 transition-opacity duration-200" | ||
:class="{ 'opacity-100': isDragging }"></div> | ||
</div> | ||
|
||
<!-- 右上角拖动手柄 --> | ||
<div | ||
v-if="viewportSize !== 'desktop'" | ||
class="absolute w-3 h-3 cursor-ne-resize transition-all duration-200 group" | ||
:class="{ | ||
'bg-blue-500 bg-opacity-30': isDragging, | ||
'hover:bg-blue-500 hover:bg-opacity-20': !isDragging | ||
}" | ||
@mousedown="(e) => handleCornerDragStart(e, 'ne')" | ||
:style="{ | ||
right: `calc(50% - ${(viewportSize === 'mobile' ? (mobileWidth || 390) : (tabletWidth || 680)) / 2}px - 1px)`, | ||
top: `calc(50% - ${(viewportSize === 'mobile' ? (mobileHeight || 844) : (tabletHeight || 800)) / 2}px - 1px)` | ||
}" | ||
> | ||
<div class="absolute inset-0 border-r-2 border-t-2 border-blue-500 opacity-0 group-hover:opacity-100 transition-opacity duration-200" | ||
:class="{ 'opacity-100': isDragging }"></div> | ||
</div> | ||
|
||
<!-- 左下角拖动手柄 --> | ||
<div | ||
v-if="viewportSize !== 'desktop'" | ||
class="absolute w-3 h-3 cursor-sw-resize transition-all duration-200 group" | ||
:class="{ | ||
'bg-blue-500 bg-opacity-30': isDragging, | ||
'hover:bg-blue-500 hover:bg-opacity-20': !isDragging | ||
}" | ||
@mousedown="(e) => handleCornerDragStart(e, 'sw')" | ||
:style="{ | ||
left: `calc(50% - ${(viewportSize === 'mobile' ? (mobileWidth || 390) : (tabletWidth || 680)) / 2}px - 1px)`, | ||
bottom: `calc(50% - ${(viewportSize === 'mobile' ? (mobileHeight || 844) : (tabletHeight || 800)) / 2}px - 1px)` | ||
}" | ||
> | ||
<div class="absolute inset-0 border-l-2 border-b-2 border-blue-500 opacity-0 group-hover:opacity-100 transition-opacity duration-200" | ||
:class="{ 'opacity-100': isDragging }"></div> | ||
</div> | ||
|
||
<!-- 右下角拖动手柄 --> | ||
<div | ||
v-if="viewportSize !== 'desktop'" | ||
class="absolute w-3 h-3 cursor-se-resize transition-all duration-200 group" | ||
:class="{ | ||
'bg-blue-500 bg-opacity-30': isDragging, | ||
'hover:bg-blue-500 hover:bg-opacity-20': !isDragging | ||
}" | ||
@mousedown="(e) => handleCornerDragStart(e, 'se')" | ||
:style="{ | ||
right: `calc(50% - ${(viewportSize === 'mobile' ? (mobileWidth || 390) : (tabletWidth || 680)) / 2}px - 1px)`, | ||
bottom: `calc(50% - ${(viewportSize === 'mobile' ? (mobileHeight || 844) : (tabletHeight || 800)) / 2}px - 1px)` | ||
}" | ||
> | ||
<div class="absolute inset-0 border-r-2 border-b-2 border-blue-500 opacity-0 group-hover:opacity-100 transition-opacity duration-200" | ||
:class="{ 'opacity-100': isDragging }"></div> | ||
</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.
🛠️ Refactor suggestion
Add accessibility support for resize handles.
The resize handles lack keyboard support and ARIA attributes, making them inaccessible to users who rely on keyboards or screen readers.
Consider adding:
- ARIA labels for screen readers:
<div
v-if="viewportSize !== 'desktop'"
class="absolute top-1/2 transform -translate-y-1/2 w-2 cursor-col-resize transition-all duration-200 group"
+ role="separator"
+ :aria-label="`Resize ${viewportSize} preview width from left`"
+ tabindex="0"
:class="{
- Keyboard event handlers:
@mousedown="handleLeftDragStart"
+ @keydown="handleKeyboardResize"
- Add a keyboard resize handler:
const handleKeyboardResize = (e: KeyboardEvent) => {
if (props.viewportSize === 'desktop') return
const step = e.shiftKey ? 10 : 1
let currentWidth = props.viewportSize === 'mobile'
? props.mobileWidth || 390
: props.tabletWidth || 680
switch(e.key) {
case 'ArrowLeft':
currentWidth -= step
break
case 'ArrowRight':
currentWidth += step
break
default:
return
}
e.preventDefault()
// Apply constraints and emit updates
const { minWidth, maxWidth } = dragConstraints.value
currentWidth = Math.max(minWidth, Math.min(maxWidth, currentWidth))
if (props.viewportSize === 'mobile') {
emit('update:mobileWidth', currentWidth)
} else {
emit('update:tabletWidth', currentWidth)
}
}
🤖 Prompt for AI Agents
In src/renderer/src/components/artifacts/HTMLArtifact.vue between lines 24 and
166, the resize handles lack accessibility features such as keyboard support and
ARIA attributes. To fix this, add appropriate ARIA labels to each resize handle
for screen reader clarity, implement keyboard event handlers to capture key
presses, and integrate a keyboard resize handler function that adjusts the width
based on arrow key inputs with shift key support for larger steps. Ensure the
handler respects viewport constraints and emits the updated width values
accordingly.
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.
fix i18n
Run pnpm run i18n
pnpm run i18n
shell: /usr/bin/bash -e {0}
env:
PNPM_HOME: /home/runner/setup-pnpm/node_modules/.bin
[email protected] i18n /home/runner/work/deepchat/deepchat
i18n-check -s zh-CN -f i18next --locales src/renderer/src/i18n
i18n translations checker
Source: zh-CN
Selected format is: i18next
Found missing keys!
┌────────────────────────────────────────────┬─────────┐
│ file │ key │
├────────────────────────────────────────────┼─────────┤
│ src/renderer/src/i18n/fa-IR/artifacts.json │ desktop │
│ src/renderer/src/i18n/fa-IR/artifacts.json │ tablet │
│ src/renderer/src/i18n/fa-IR/artifacts.json │ mobile │
│ src/renderer/src/i18n/fa-IR/artifacts.json │ width │
│ src/renderer/src/i18n/fa-IR/artifacts.json │ height │
│ src/renderer/src/i18n/fr-FR/artifacts.json │ desktop │
│ src/renderer/src/i18n/fr-FR/artifacts.json │ tablet │
│ src/renderer/src/i18n/fr-FR/artifacts.json │ mobile │
│ src/renderer/src/i18n/fr-FR/artifacts.json │ width │
│ src/renderer/src/i18n/fr-FR/artifacts.json │ height │
│ src/renderer/src/i18n/ja-JP/artifacts.json │ desktop │
│ src/renderer/src/i18n/ja-JP/artifacts.json │ tablet │
│ src/renderer/src/i18n/ja-JP/artifacts.json │ mobile │
│ src/renderer/src/i18n/ja-JP/artifacts.json │ width │
│ src/renderer/src/i18n/ja-JP/artifacts.json │ height │
└────────────────────────────────────────────┴─────────┘
No invalid translations found!
Done in 0.06s.
ELIFECYCLE Command failed with exit code 1.
Checking formatting... |
新增了HTML预览的尺寸切换,尺寸边界可拖动。
测试平台:
界面如下:
桌面尺寸:



平板尺寸:
手机尺寸:
Summary by CodeRabbit