Skip to content

feat:ai-extension development and detail optimization#95

Closed
discreted66 wants to merge 1 commit intodevfrom
home0228
Closed

feat:ai-extension development and detail optimization#95
discreted66 wants to merge 1 commit intodevfrom
home0228

Conversation

@discreted66
Copy link
Collaborator

@discreted66 discreted66 commented Feb 28, 2026

feat:ai-extension开发以及细节优化

Summary by CodeRabbit

Release Notes

  • New Features

    • Added Agent Skills section with interactive feature cards and call-to-action elements to home page
    • Implemented viewport-triggered fade-in animations for improved visual experience
  • Style

    • Updated typography scale and spacing across home pages for better readability
    • Enhanced responsive design for mobile and tablet breakpoints
    • Refined button styling and visual layout consistency

@coderabbitai
Copy link

coderabbitai bot commented Feb 28, 2026

Walkthrough

Refactors and expands three home page views (AI Extension, Next SDKs, TinyVue) from monolithic templates to modular component-based architectures. Introduces new UI components (HeroSection, FeatureSection, HighlightsSection, McpSection), establishes shared styling patterns via common.less files, implements IntersectionObserver-based fade-in animations, and updates Vite configuration for optimized asset handling.

Changes

Cohort / File(s) Summary
AI Extension Home
packages/home/src/views/ai-extension-home/common.less, packages/home/src/views/ai-extension-home/components/HeroSection.vue, packages/home/src/views/ai-extension-home/components/FeatureSection.vue, packages/home/src/views/ai-extension-home/components/HighlightsSection.vue, packages/home/src/views/ai-extension-home/index.vue
New view structure with reusable components, shared design system stylesheet, viewport-triggered fade-in-up animations via IntersectionObserver, responsive layouts across multiple breakpoints, and data-driven feature rendering.
Next SDKs Home
packages/home/src/views/next-sdks-home/common.less, packages/home/src/views/next-sdks-home/components/HeroSection.vue, packages/home/src/views/next-sdks-home/components/FeatureSection.vue, packages/home/src/views/next-sdks-home/components/StepItem.vue, packages/home/src/views/next-sdks-home/index.vue, packages/home/src/views/next-sdks-home/next-sdk.md
Refactored to component-based architecture with extracted HeroSection, namespaced styling under root selector, enhanced code block parsing (multiple blocks per step with per-block copy state), updated typography and button styling, and markdown documentation adjustments.
TinyVue Home
packages/home/src/views/tiny-vue-home/common.less, packages/home/src/views/tiny-vue-home/components/HeroSection.vue, packages/home/src/views/tiny-vue-home/components/CrossPlatformFeature.vue, packages/home/src/views/tiny-vue-home/components/McpSection.vue, packages/home/src/views/tiny-vue-home/index.vue
New McpSection component for Agent Skills, improved HeroSection with computed-based image selection, CrossPlatformFeature icon additions, comprehensive typography and spacing updates, responsive refinements, and provided fade-in-up initialization for child components.
Build Configuration
packages/home/vite.config.js
Added asset handling configuration including assetsInclude for image formats, assetsInlineLimit capping at 4KB, and custom assetFileNames function to organize images into dedicated subdirectory with hash-based naming.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰✨ Components dance in modular grace,
Animations fade-in with intersection's embrace,
Responsive styles scale from device to place,
TinyVue, Next SDK, AI's gleaming face—
A rabbit hops through refactored space! 🌟

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat:ai-extension development and detail optimization' is partially related to the changeset. It highlights AI extension development, which is evident in the new AI-extension-home files, but it is overly broad and vague by mentioning 'detail optimization' without specifying what optimizations are included. The PR actually encompasses component-based refactoring, animation improvements, styling updates, and build configuration changes across multiple home views (AI extension, next-sdks, tiny-vue), making the title incomplete and not fully descriptive of the main scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch home0228

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/home/src/views/next-sdks-home/next-sdk.md (1)

84-97: ⚠️ Potential issue | 🟡 Minor

Use correct code block language for Vue SFC.

The code block uses ```typescript but contains Vue Single File Component syntax with <template> and <script setup> sections. Use ```vue for proper syntax highlighting.

📝 Suggested fix
-```typescript
+```vue
 // 在 Vue 中使用
 <template>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/home/src/views/next-sdks-home/next-sdk.md` around lines 84 - 97, The
fenced code block showing a Vue SFC currently uses ```typescript but contains
<template> and <script setup> sections; change the fence language to ```vue so
editors/previewers apply correct Vue SFC highlighting for the TinyRemoter
example (the block containing TinyRemoter, v-model:show and the show ref in the
<script setup>).
🧹 Nitpick comments (12)
packages/home/src/views/tiny-vue-home/components/HeroSection.vue (2)

12-15: Consider simplifying backgroundImageUrl to a constant.

This computed property returns a static value that never changes—heroBgWhite is a static import resolved at build time. A simple constant would be clearer and marginally more efficient:

-// 使用 computed 确保 Vite 在构建时能正确追踪图片资源
-const backgroundImageUrl = computed(() => {
-  return `url(${heroBgWhite})`;
-});
+// Vite tracks static imports at build time
+const backgroundImageUrl = `url(${heroBgWhite})`;

Note: Vite tracks the asset via the static import statement, not via computed. The computed wrapper adds no benefit here.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/home/src/views/tiny-vue-home/components/HeroSection.vue` around
lines 12 - 15, The computed wrapper around backgroundImageUrl is unnecessary
because heroBgWhite is a static import; replace the computed() usage by a plain
constant (e.g., const backgroundImageUrl = `url(${heroBgWhite})`) and remove the
computed import/usage so Vite still tracks the asset but without reactive
overhead; update any bindings that reference backgroundImageUrl accordingly and
remove unused computed-related imports if no longer used.

89-93: Verify fixed 1000px width doesn't cause overflow on medium viewports.

The fixed width: 1000px on the image applies between 1024px and larger viewports. If the container (with gap: 60px and hero-content padding) doesn't accommodate 1000px, horizontal overflow could occur on viewports around 1100-1200px.

The media query at 1024px correctly sets width: 100%, but consider using max-width: 1000px; width: 100%; for the base rule to gracefully handle intermediate sizes.

🛠️ Suggested adjustment
     img {
-      width: 1000px;
+      max-width: 1000px;
+      width: 100%;
       filter: drop-shadow(0 20px 40px rgba(0, 0, 0, 0.15));
       border-radius: 20px;
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/home/src/views/tiny-vue-home/components/HeroSection.vue` around
lines 89 - 93, The image rule in HeroSection.vue currently sets img { width:
1000px; ... } which can cause horizontal overflow on intermediate viewports;
change that rule to use responsive sizing by replacing the fixed width with
width: 100%; max-width: 1000px; (keep filter and border-radius), so the image
scales down inside its container while still capping at 1000px, and leave the
existing `@media` (min-width:1024px) behavior intact if present.
packages/home/src/views/tiny-vue-home/common.less (1)

372-376: Consider improving mobile button legibility/touch ergonomics.

line-height: 1 is tight for 14px text and can reduce readability. A slightly larger line-height plus minimum height is safer on small screens.

Proposed tweak
 .btn {
   padding: 12px 24px;
   font-size: 14px;
-  line-height: 1;
+  line-height: 1.2;
+  min-height: 44px;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/home/src/views/tiny-vue-home/common.less` around lines 372 - 376,
The .btn rule uses a tight line-height (line-height: 1) which harms readability
and touch ergonomics on mobile; update the .btn selector in common.less to
increase vertical rhythm (e.g., set line-height to ~1.2–1.4) and add a
min-height (e.g., 40–48px) or slightly larger vertical padding for a comfortable
touch target, while preserving existing horizontal padding and font-size; ensure
these changes apply responsively (mobile-first or via a small-screen media
query) so desktop styles remain unchanged.
packages/home/src/views/tiny-vue-home/components/CrossPlatformFeature.vue (1)

5-6: Consider more descriptive import names.

img1 and img2 are generic and don't convey meaning. Names like platformIcon and vueVersionIcon (or similar) would improve readability and maintainability.

♻️ Suggested improvement
-import img1 from "@/assets/images/home/tinyvue-home/web/img1.svg";
-import img2 from "@/assets/images/home/tinyvue-home/web/img2.svg";
+import platformIcon from "@/assets/images/home/tinyvue-home/web/img1.svg";
+import vueVersionIcon from "@/assets/images/home/tinyvue-home/web/img2.svg";

Then update the features array accordingly:

-    icon: img1,
+    icon: platformIcon,
-    icon: img2,
+    icon: vueVersionIcon,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/home/src/views/tiny-vue-home/components/CrossPlatformFeature.vue`
around lines 5 - 6, The imports img1 and img2 in CrossPlatformFeature.vue are
too generic; rename them to descriptive identifiers (e.g., platformIcon and
vueVersionIcon) at the top import statements and update every usage in this
component—notably the features array and any template, computed, or methods that
reference img1/img2—to use the new names so the intent is clear and
maintainable.
packages/home/src/views/next-sdks-home/components/FeatureSection.vue (2)

4-9: Consider marking feature prop as required.

The feature prop lacks a required: true constraint. If this component is rendered without the prop, it will fail silently when accessing feature.title, feature.description, etc. Adding validation improves developer experience and debugging.

♻️ Suggested fix
 const props = defineProps({
   // Feature 配置对象
   feature: {
     type: Object,
+    required: true,
   },
 });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/home/src/views/next-sdks-home/components/FeatureSection.vue` around
lines 4 - 9, The feature prop in FeatureSection.vue is not marked required which
can lead to silent failures when accessing feature.title/description; update the
defineProps call for "feature" to include required: true (i.e., change the
feature prop descriptor to include required: true while keeping the type:Object)
so Vue will validate presence at runtime and surface missing-prop errors for the
FeatureSection component.

2-2: Remove unnecessary defineProps import.

In Vue 3's <script setup>, defineProps is a compiler macro and does not need to be imported. The import is ignored at runtime but adds noise.

♻️ Suggested fix
 <script setup>
-import { defineProps, computed } from "vue";
+import { computed } from "vue";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/home/src/views/next-sdks-home/components/FeatureSection.vue` at line
2, The import unnecessarily includes the compiler macro defineProps; remove
defineProps from the import statement (leave computed if it's used) in
FeatureSection.vue so you only import actual runtime APIs from "vue" — i.e.,
drop defineProps from the import list and keep computed (or remove computed too
if unused).
packages/home/src/views/next-sdks-home/index.vue (2)

341-341: Update animation reference if keyframe is renamed.

If the fadeInUp keyframe in common.less is renamed to fade-in-up per the Stylelint kebab-case convention, update this reference accordingly.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/home/src/views/next-sdks-home/index.vue` at line 341, The CSS
animation reference in the component uses the old keyframe name "fadeInUp";
update the animation declaration (the line with animation: fadeInUp 1s
ease-out;) to use the renamed keyframe "fade-in-up" so it matches the keyframe
in common.less (and search for other occurrences of "fadeInUp" in this component
to update them as well).

247-252: Fragile timing-based initialization.

Using setTimeout with a fixed 800ms delay to ensure DOM readiness is fragile and may fail on slower devices or succeed too late on faster ones. Consider using MutationObserver or waiting for specific elements to exist before initializing observers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/home/src/views/next-sdks-home/index.vue` around lines 247 - 252, The
current setTimeout-based initialization is fragile; remove the fixed 800ms
timeout and instead wait for the target DOM to be ready before calling
initFadeInUp(null) and initStepObserver(): implement a small helper that polls
or uses a MutationObserver to watch the container for the presence of the
required elements (e.g., querySelectorAll('.fade-in-up') or the specific step
elements), call initFadeInUp and initStepObserver once the elements exist, then
disconnect the observer (or stop polling) and fall back to a short timeout only
as a safety net; update the code that currently calls setTimeout(...) so it uses
this helper and ensures initFadeInUp and initStepObserver are invoked exactly
once when the DOM is ready.
packages/home/src/views/ai-extension-home/components/HeroSection.vue (1)

39-106: Styles depend on parent .ai-extension-home wrapper.

All scoped styles are nested under .ai-extension-home, meaning this component's styles will only apply when rendered inside a parent element with that class. Ensure the consuming component (e.g., index.vue) wraps content appropriately, or consider moving component-specific styles outside the parent selector for better encapsulation.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/home/src/views/ai-extension-home/components/HeroSection.vue` around
lines 39 - 106, The styles are currently scoped under the parent selector
`.ai-extension-home`, so the rules for `.section.hero`, `.hero-content`,
`.hero-img`, and `.cta-group` will only apply when the component is wrapped by
an element with class `.ai-extension-home`; fix by either ensuring the consumer
(e.g., the parent index component) wraps this component with a container having
class `.ai-extension-home`, or remove the top-level `.ai-extension-home` prefix
in this file and promote the nested selectors (`.section.hero`, `.hero-content`,
`.hero-img`, `.cta-group`) to top-level component styles so they apply wherever
the component is used.
packages/home/src/views/next-sdks-home/components/HeroSection.vue (1)

61-62: Redundant padding declarations.

padding: 20px 0 0 40px sets padding-top: 20px, which is immediately overridden by padding-top: 0 on the next line. Simplify to a single declaration.

♻️ Suggested fix
 .hero-content {
   position: relative;
   z-index: 1;
   max-width: 1400px;
-  padding: 20px 0 0 40px;
-  padding-top: 0;
+  padding: 0 0 0 40px;
   animation: fadeInUp 1s ease-out;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/home/src/views/next-sdks-home/components/HeroSection.vue` around
lines 61 - 62, In the HeroSection.vue CSS block replace the two conflicting
rules ("padding: 20px 0 0 40px;" followed by "padding-top: 0;") with a single
padding declaration that expresses the intended result (e.g. "padding: 0 0 0
40px;"); remove the redundant padding-top line so only one padding rule remains.
packages/home/src/views/ai-extension-home/common.less (1)

156-166: Avoid using zoom on universal selector.

The zoom property is non-standard (only supported in some browsers) and applying it to * can cause performance issues and unexpected layout behavior. Consider using responsive typography/spacing adjustments or CSS transform: scale() on a container instead.

♻️ Alternative approach

Instead of scaling everything with zoom, adjust the root font size or use CSS custom properties for responsive sizing:

   /* 中等屏幕 (1024px - 1440px) - 小桌面 */
   `@media` (max-width: 1440px) {
-    * {
-      zoom: 0.9;
-    }
+    // Consider adjusting specific element sizes or using rem-based scaling
   }

   /* 平板横屏 (1024px - 1440px) */
   `@media` (max-width: 1024px) {
-    * {
-      zoom: 1;
-    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/home/src/views/ai-extension-home/common.less` around lines 156 -
166, Replace the non-standard use of zoom on the universal selector inside the
media queries (`@media` (max-width: 1440px) and `@media` (max-width: 1024px)) by
removing the "*" zoom rules and implement a standards-compliant responsive
approach: set a scaled root font-size on html or :root (or update CSS custom
properties used for spacing/typography) for those breakpoints, or apply
transform: scale(...) on a specific top-level container class instead of *.
Update any dependent spacing/typography variables to use rem units so layout
scales predictably across browsers; ensure you remove the zoom declarations from
the selectors to eliminate the non-standard property usage.
packages/home/src/views/ai-extension-home/index.vue (1)

77-85: Scope the .fade-in-up query to this page container.

Using a global document.querySelectorAll(".fade-in-up") can observe unrelated elements that reuse the same class.

♻️ Suggested refactor
-  if (elementsToObserve.size === 0) {
-    const targets = Array.from(document.querySelectorAll(".fade-in-up"));
+  if (elementsToObserve.size === 0) {
+    const root = document.querySelector(".ai-extension-home");
+    const targets = root ? Array.from(root.querySelectorAll(".fade-in-up")) : [];
     targets.forEach((el) => {
       if (el instanceof Element) {
         elementsToObserve.add(el);
       }
     });
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/home/src/views/ai-extension-home/index.vue` around lines 77 - 85,
The query for ".fade-in-up" is currently global (document.querySelectorAll) and
can catch elements outside this component; change it to scope to the component's
root container (e.g., use a local ref like rootContainerRef or this.$el) by
replacing document.querySelectorAll(".fade-in-up") with
container.querySelectorAll(".fade-in-up") (fall back to document only if the
container is null), keeping the same element instanceof Element checks and
adding those elements to elementsToObserve; reference elementsToObserve and the
local container ref (rootContainerRef / wrapperRef / this.$el) in the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/home/src/views/ai-extension-home/common.less`:
- Line 130: The keyframes declaration named fadeInUp violates the Stylelint
keyframes-name-pattern; rename the keyframe to fade-in-up and update every
reference that uses it (e.g., any animation: fadeInUp 1s ease-out or
animation-name: fadeInUp) to use animation: fade-in-up 1s ease-out (or
animation-name: fade-in-up) so selectors and animations continue to work with
the new kebab-case identifier.

In `@packages/home/src/views/ai-extension-home/components/HeroSection.vue`:
- Line 78: Replace the invalid CSS value "justify-content: left" in the
HeroSection.vue style block with the correct flexbox value "justify-content:
flex-start"; locate the rule in the component's style (the declaration currently
reading "justify-content: left") and update it to "flex-start" so the layout
uses a valid flexbox alignment.

In `@packages/home/src/views/ai-extension-home/index.vue`:
- Around line 123-135: The setTimeout created inside onMounted is not stored so
it may execute after unmount; store its handle (e.g. let fadeInitTimer) when
calling setTimeout for initFadeInUp(null) and in onUnmounted clear it via
clearTimeout(fadeInitTimer) and set fadeInitTimer = undefined, while leaving the
existing fadeObserver?.disconnect() and fadeObserver = undefined logic intact so
no delayed init runs after the component is destroyed.

In `@packages/home/src/views/next-sdks-home/components/StepItem.vue`:
- Around line 133-150: The fenced-code range tracking is inside the conditional
that only runs when `code` is non-empty, so empty fenced blocks are not recorded
and remain in `body`; move the `codeBlockRanges.push({ start: fenceStart, end:
fenceEnd + 3 })` call out of the `if (code)` block so it always executes
(regardless of whether `Prism.highlight` runs or the `catch` branch executes),
and apply the same change for the second occurrence mentioned (the block around
lines handling `code`, `langLineEnd`, `fenceEnd`, and `fenceStart`) so empty
fenced blocks are always removed from `body`.

In `@packages/home/src/views/tiny-vue-home/common.less`:
- Around line 117-119: The .title-us selector is hard-coded to 56px and not
adjusted in the tablet/media-query rules where .title is scaled, causing
overflow on 768–1024px; update the responsive blocks that modify .title (the
media-query rules around where .title is adjusted) to also include .title-us
with appropriate smaller font-sizes (matching the same ratios used for .title)
or add separate media-query entries for .title-us to reduce from 56px at tablet
and mobile breakpoints so headings scale consistently across viewports.

In `@packages/home/src/views/tiny-vue-home/components/CrossPlatformFeature.vue`:
- Line 37: The <img> in CrossPlatformFeature.vue is missing an alt attribute;
update the image element that uses :src="item.icon" to include an alt (use a
meaningful text like item.alt or item.title if provided) or alt="" if the icon
is purely decorative; ensure you reference the same binding (item) so no
behavior changes and add the alt attribute next to :src on the <img> element.

In `@packages/home/src/views/tiny-vue-home/components/McpSection.vue`:
- Line 2: Store the timer ID returned by setTimeout in a tracked variable (e.g.,
a ref or let named animationTimerId) when calling setTimeout inside the
component (the block currently using onMounted and setTimeout), and add an
onBeforeUnmount hook that calls clearTimeout(animationTimerId) to cancel the
pending callback if the component unmounts early; update any other delayed-init
calls (the same pattern around lines 54-64) to use the same tracked ID and
clearing logic.
- Around line 100-107: The external anchor elements (the <a> tags with class
"btn primary" and "btn secondary" in the McpSection.vue template) open links
with target="_blank" and must be hardened; add rel="noopener noreferrer" to each
external anchor (both the "即刻体验" link and the "阅读文档" link that contains
IconArrowRight) so the new tab cannot access window.opener and to prevent
potential reverse tabnabbing.

---

Outside diff comments:
In `@packages/home/src/views/next-sdks-home/next-sdk.md`:
- Around line 84-97: The fenced code block showing a Vue SFC currently uses
```typescript but contains <template> and <script setup> sections; change the
fence language to ```vue so editors/previewers apply correct Vue SFC
highlighting for the TinyRemoter example (the block containing TinyRemoter,
v-model:show and the show ref in the <script setup>).

---

Nitpick comments:
In `@packages/home/src/views/ai-extension-home/common.less`:
- Around line 156-166: Replace the non-standard use of zoom on the universal
selector inside the media queries (`@media` (max-width: 1440px) and `@media`
(max-width: 1024px)) by removing the "*" zoom rules and implement a
standards-compliant responsive approach: set a scaled root font-size on html or
:root (or update CSS custom properties used for spacing/typography) for those
breakpoints, or apply transform: scale(...) on a specific top-level container
class instead of *. Update any dependent spacing/typography variables to use rem
units so layout scales predictably across browsers; ensure you remove the zoom
declarations from the selectors to eliminate the non-standard property usage.

In `@packages/home/src/views/ai-extension-home/components/HeroSection.vue`:
- Around line 39-106: The styles are currently scoped under the parent selector
`.ai-extension-home`, so the rules for `.section.hero`, `.hero-content`,
`.hero-img`, and `.cta-group` will only apply when the component is wrapped by
an element with class `.ai-extension-home`; fix by either ensuring the consumer
(e.g., the parent index component) wraps this component with a container having
class `.ai-extension-home`, or remove the top-level `.ai-extension-home` prefix
in this file and promote the nested selectors (`.section.hero`, `.hero-content`,
`.hero-img`, `.cta-group`) to top-level component styles so they apply wherever
the component is used.

In `@packages/home/src/views/ai-extension-home/index.vue`:
- Around line 77-85: The query for ".fade-in-up" is currently global
(document.querySelectorAll) and can catch elements outside this component;
change it to scope to the component's root container (e.g., use a local ref like
rootContainerRef or this.$el) by replacing
document.querySelectorAll(".fade-in-up") with
container.querySelectorAll(".fade-in-up") (fall back to document only if the
container is null), keeping the same element instanceof Element checks and
adding those elements to elementsToObserve; reference elementsToObserve and the
local container ref (rootContainerRef / wrapperRef / this.$el) in the change.

In `@packages/home/src/views/next-sdks-home/components/FeatureSection.vue`:
- Around line 4-9: The feature prop in FeatureSection.vue is not marked required
which can lead to silent failures when accessing feature.title/description;
update the defineProps call for "feature" to include required: true (i.e.,
change the feature prop descriptor to include required: true while keeping the
type:Object) so Vue will validate presence at runtime and surface missing-prop
errors for the FeatureSection component.
- Line 2: The import unnecessarily includes the compiler macro defineProps;
remove defineProps from the import statement (leave computed if it's used) in
FeatureSection.vue so you only import actual runtime APIs from "vue" — i.e.,
drop defineProps from the import list and keep computed (or remove computed too
if unused).

In `@packages/home/src/views/next-sdks-home/components/HeroSection.vue`:
- Around line 61-62: In the HeroSection.vue CSS block replace the two
conflicting rules ("padding: 20px 0 0 40px;" followed by "padding-top: 0;") with
a single padding declaration that expresses the intended result (e.g. "padding:
0 0 0 40px;"); remove the redundant padding-top line so only one padding rule
remains.

In `@packages/home/src/views/next-sdks-home/index.vue`:
- Line 341: The CSS animation reference in the component uses the old keyframe
name "fadeInUp"; update the animation declaration (the line with animation:
fadeInUp 1s ease-out;) to use the renamed keyframe "fade-in-up" so it matches
the keyframe in common.less (and search for other occurrences of "fadeInUp" in
this component to update them as well).
- Around line 247-252: The current setTimeout-based initialization is fragile;
remove the fixed 800ms timeout and instead wait for the target DOM to be ready
before calling initFadeInUp(null) and initStepObserver(): implement a small
helper that polls or uses a MutationObserver to watch the container for the
presence of the required elements (e.g., querySelectorAll('.fade-in-up') or the
specific step elements), call initFadeInUp and initStepObserver once the
elements exist, then disconnect the observer (or stop polling) and fall back to
a short timeout only as a safety net; update the code that currently calls
setTimeout(...) so it uses this helper and ensures initFadeInUp and
initStepObserver are invoked exactly once when the DOM is ready.

In `@packages/home/src/views/tiny-vue-home/common.less`:
- Around line 372-376: The .btn rule uses a tight line-height (line-height: 1)
which harms readability and touch ergonomics on mobile; update the .btn selector
in common.less to increase vertical rhythm (e.g., set line-height to ~1.2–1.4)
and add a min-height (e.g., 40–48px) or slightly larger vertical padding for a
comfortable touch target, while preserving existing horizontal padding and
font-size; ensure these changes apply responsively (mobile-first or via a
small-screen media query) so desktop styles remain unchanged.

In `@packages/home/src/views/tiny-vue-home/components/CrossPlatformFeature.vue`:
- Around line 5-6: The imports img1 and img2 in CrossPlatformFeature.vue are too
generic; rename them to descriptive identifiers (e.g., platformIcon and
vueVersionIcon) at the top import statements and update every usage in this
component—notably the features array and any template, computed, or methods that
reference img1/img2—to use the new names so the intent is clear and
maintainable.

In `@packages/home/src/views/tiny-vue-home/components/HeroSection.vue`:
- Around line 12-15: The computed wrapper around backgroundImageUrl is
unnecessary because heroBgWhite is a static import; replace the computed() usage
by a plain constant (e.g., const backgroundImageUrl = `url(${heroBgWhite})`) and
remove the computed import/usage so Vite still tracks the asset but without
reactive overhead; update any bindings that reference backgroundImageUrl
accordingly and remove unused computed-related imports if no longer used.
- Around line 89-93: The image rule in HeroSection.vue currently sets img {
width: 1000px; ... } which can cause horizontal overflow on intermediate
viewports; change that rule to use responsive sizing by replacing the fixed
width with width: 100%; max-width: 1000px; (keep filter and border-radius), so
the image scales down inside its container while still capping at 1000px, and
leave the existing `@media` (min-width:1024px) behavior intact if present.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e298da6 and 4899b83.

⛔ Files ignored due to path filters (17)
  • packages/home/src/assets/images/home/ai-extension-home/banner-bg.svg is excluded by !**/*.svg
  • packages/home/src/assets/images/home/ai-extension-home/banner-img.svg is excluded by !**/*.svg
  • packages/home/src/assets/images/home/ai-extension-home/flow1.svg is excluded by !**/*.svg
  • packages/home/src/assets/images/home/ai-extension-home/flow2.svg is excluded by !**/*.svg
  • packages/home/src/assets/images/home/ai-extension-home/flow3.svg is excluded by !**/*.svg
  • packages/home/src/assets/images/home/ai-extension-home/flow4.svg is excluded by !**/*.svg
  • packages/home/src/assets/images/home/ai-extension-home/hxld-1.svg is excluded by !**/*.svg
  • packages/home/src/assets/images/home/ai-extension-home/hxld-2.svg is excluded by !**/*.svg
  • packages/home/src/assets/images/home/ai-extension-home/hxld-3.svg is excluded by !**/*.svg
  • packages/home/src/assets/images/home/ai-extension-home/hxld-4.svg is excluded by !**/*.svg
  • packages/home/src/assets/images/home/ai-extension-home/hxld-5.svg is excluded by !**/*.svg
  • packages/home/src/assets/images/home/ai-extension-home/hxld-6.svg is excluded by !**/*.svg
  • packages/home/src/assets/images/home/ai-extension-home/hxld-7.svg is excluded by !**/*.svg
  • packages/home/src/assets/images/home/ai-extension-home/hxld-8.svg is excluded by !**/*.svg
  • packages/home/src/assets/images/home/tinyvue-home/web/skill_1.png is excluded by !**/*.png
  • packages/home/src/assets/images/home/tinyvue-home/web/skill_2.png is excluded by !**/*.png
  • packages/home/src/assets/images/home/tinyvue-home/web/skill_3.png is excluded by !**/*.png
📒 Files selected for processing (17)
  • packages/home/src/views/ai-extension-home/common.less
  • packages/home/src/views/ai-extension-home/components/FeatureSection.vue
  • packages/home/src/views/ai-extension-home/components/HeroSection.vue
  • packages/home/src/views/ai-extension-home/components/HighlightsSection.vue
  • packages/home/src/views/ai-extension-home/index.vue
  • packages/home/src/views/next-sdks-home/common.less
  • packages/home/src/views/next-sdks-home/components/FeatureSection.vue
  • packages/home/src/views/next-sdks-home/components/HeroSection.vue
  • packages/home/src/views/next-sdks-home/components/StepItem.vue
  • packages/home/src/views/next-sdks-home/index.vue
  • packages/home/src/views/next-sdks-home/next-sdk.md
  • packages/home/src/views/tiny-vue-home/common.less
  • packages/home/src/views/tiny-vue-home/components/CrossPlatformFeature.vue
  • packages/home/src/views/tiny-vue-home/components/HeroSection.vue
  • packages/home/src/views/tiny-vue-home/components/McpSection.vue
  • packages/home/src/views/tiny-vue-home/index.vue
  • packages/home/vite.config.js

transform: translateY(0);
}

@keyframes fadeInUp {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Rename keyframe to kebab-case per Stylelint rule.

The keyframe name fadeInUp should be fade-in-up to comply with the keyframes-name-pattern lint rule.

🔧 Suggested fix
-  `@keyframes` fadeInUp {
+  `@keyframes` fade-in-up {
     from {
       opacity: 0;
       transform: translateY(40px);

Note: Update all references to fadeInUp (e.g., in animation: fadeInUp 1s ease-out) to use fade-in-up as well.

🧰 Tools
🪛 Stylelint (17.3.0)

[error] 130-130: Expected keyframe name "fadeInUp" to be kebab-case (keyframes-name-pattern)

(keyframes-name-pattern)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/home/src/views/ai-extension-home/common.less` at line 130, The
keyframes declaration named fadeInUp violates the Stylelint
keyframes-name-pattern; rename the keyframe to fade-in-up and update every
reference that uses it (e.g., any animation: fadeInUp 1s ease-out or
animation-name: fadeInUp) to use animation: fade-in-up 1s ease-out (or
animation-name: fade-in-up) so selectors and animations continue to work with
the new kebab-case identifier.

.cta-group {
display: flex;
gap: 30px;
justify-content: left;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Invalid justify-content value.

justify-content: left is not a valid flexbox value. Use flex-start instead.

🔧 Suggested fix
   .cta-group {
     display: flex;
     gap: 30px;
-    justify-content: left;
+    justify-content: flex-start;
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/home/src/views/ai-extension-home/components/HeroSection.vue` at line
78, Replace the invalid CSS value "justify-content: left" in the HeroSection.vue
style block with the correct flexbox value "justify-content: flex-start"; locate
the rule in the component's style (the declaration currently reading
"justify-content: left") and update it to "flex-start" so the layout uses a
valid flexbox alignment.

Comment on lines +123 to +135
onMounted(async () => {
// 延迟初始化,确保所有动态内容都已渲染
await nextTick();
setTimeout(() => {
// 从整个容器中查找所有 .fade-in-up 元素
initFadeInUp(null);
}, 800);
});

onUnmounted(() => {
fadeObserver?.disconnect();
fadeObserver = undefined;
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Clear delayed init timer during unmount.

The delayed setTimeout in onMounted is not tracked/cleared, so it can run after unmount.

🧹 Suggested fix
 let fadeObserver;
+let fadeInitTimer;

 onMounted(async () => {
   await nextTick();
-  setTimeout(() => {
+  fadeInitTimer = setTimeout(() => {
     initFadeInUp(null);
   }, 800);
 });

 onUnmounted(() => {
+  clearTimeout(fadeInitTimer);
   fadeObserver?.disconnect();
   fadeObserver = undefined;
 });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/home/src/views/ai-extension-home/index.vue` around lines 123 - 135,
The setTimeout created inside onMounted is not stored so it may execute after
unmount; store its handle (e.g. let fadeInitTimer) when calling setTimeout for
initFadeInUp(null) and in onUnmounted clear it via clearTimeout(fadeInitTimer)
and set fadeInitTimer = undefined, while leaving the existing
fadeObserver?.disconnect() and fadeObserver = undefined logic intact so no
delayed init runs after the component is destroyed.

Comment on lines +133 to 150
const code = body.slice(langLineEnd + 1, fenceEnd).trim();
if (code) {
try {
const language = Prism.languages[lang] || Prism.languages.markup || {};
const highlightedCode = Prism.highlight(code, language, lang);
codeBlocks.push({ lang, code, highlightedCode });
} catch {
const escapedCode = code
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#39;");
codeBlocks.push({ lang, code, highlightedCode: escapedCode });
}
// 去掉代码块部分,保留其余内容用于 markdown 渲染
body = body.slice(0, fenceStart) + body.slice(fenceEnd + 3);
// 记录代码块的位置范围
codeBlockRanges.push({ start: fenceStart, end: fenceEnd + 3 });
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Always remove fenced code blocks, even when content is empty.

Range tracking is currently inside if (code), so empty fenced blocks can remain in body and leak into rendered markdown.

🔧 Suggested fix
     const code = body.slice(langLineEnd + 1, fenceEnd).trim();
     if (code) {
       try {
         const language = Prism.languages[lang] || Prism.languages.markup || {};
         const highlightedCode = Prism.highlight(code, language, lang);
         codeBlocks.push({ lang, code, highlightedCode });
       } catch {
         const escapedCode = code
           .replace(/&/g, "&amp;")
           .replace(/</g, "&lt;")
           .replace(/>/g, "&gt;")
           .replace(/"/g, "&quot;")
           .replace(/'/g, "&#39;");
         codeBlocks.push({ lang, code, highlightedCode: escapedCode });
       }
-      // 记录代码块的位置范围
-      codeBlockRanges.push({ start: fenceStart, end: fenceEnd + 3 });
     }
+    // 记录代码块的位置范围(无论代码是否为空都应移除)
+    codeBlockRanges.push({ start: fenceStart, end: fenceEnd + 3 });

Also applies to: 157-160

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/home/src/views/next-sdks-home/components/StepItem.vue` around lines
133 - 150, The fenced-code range tracking is inside the conditional that only
runs when `code` is non-empty, so empty fenced blocks are not recorded and
remain in `body`; move the `codeBlockRanges.push({ start: fenceStart, end:
fenceEnd + 3 })` call out of the `if (code)` block so it always executes
(regardless of whether `Prism.highlight` runs or the `catch` branch executes),
and apply the same change for the second occurrence mentioned (the block around
lines handling `code`, `langLineEnd`, `fenceEnd`, and `fenceStart`) so empty
fenced blocks are always removed from `body`.

Comment on lines +117 to +119
.title-us {
font-size: 56px;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Responsive mismatch: .title-us stays oversized on tablet breakpoints.

Line 117 fixes .title-us at 56px, but Line 271 and Line 297 only scale .title, not .title-us. This can cause heading overflow/imbalance on 768–1024px layouts.

Proposed fix
 `@media` (max-width: 1024px) {
   .title {
     font-size: 28px;
     letter-spacing: 3px;
+    .title-us {
+      font-size: 30px;
+    }
   }
 }

 `@media` (max-width: 768px) {
   .title {
     font-size: 28px;
     letter-spacing: 2px;
     padding-bottom: 15px;
+    .title-us {
+      font-size: 28px;
+    }
   }
 }

Also applies to: 271-274, 296-300

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/home/src/views/tiny-vue-home/common.less` around lines 117 - 119,
The .title-us selector is hard-coded to 56px and not adjusted in the
tablet/media-query rules where .title is scaled, causing overflow on 768–1024px;
update the responsive blocks that modify .title (the media-query rules around
where .title is adjusted) to also include .title-us with appropriate smaller
font-sizes (matching the same ratios used for .title) or add separate
media-query entries for .title-us to reduce from 56px at tablet and mobile
breakpoints so headings scale consistently across viewports.

<div class="feature-content max-w1100 pad-t40 fade-in-up">
<div v-for="(item, index) in features" :key="index" class="feature-text">
<div class="title-logo">
<img :src="item.icon" class="feature-icon" />
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Missing alt attribute on feature icon image.

The <img> element lacks an alt attribute, which is an accessibility concern. If the icon is decorative, use alt="". Otherwise, provide meaningful alt text describing the icon's purpose.

🛠️ Proposed fix
-          <img :src="item.icon" class="feature-icon" />
+          <img :src="item.icon" :alt="item.title" class="feature-icon" />

Or if decorative:

-          <img :src="item.icon" class="feature-icon" />
+          <img :src="item.icon" alt="" class="feature-icon" />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<img :src="item.icon" class="feature-icon" />
<img :src="item.icon" :alt="item.title" class="feature-icon" />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/home/src/views/tiny-vue-home/components/CrossPlatformFeature.vue` at
line 37, The <img> in CrossPlatformFeature.vue is missing an alt attribute;
update the image element that uses :src="item.icon" to include an alt (use a
meaningful text like item.alt or item.title if provided) or alt="" if the icon
is purely decorative; ensure you reference the same binding (item) so no
behavior changes and add the alt attribute next to :src on the <img> element.

@@ -0,0 +1,366 @@
<script setup>
import { reactive, inject, ref, onMounted, computed } from "vue";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Cancel delayed animation init if the component unmounts early.

The setTimeout callback can execute after unmount because the timer ID is not tracked/cleared.

🧹 Suggested fix
-import { reactive, inject, ref, onMounted, computed } from "vue";
+import { reactive, inject, ref, onMounted, onUnmounted, computed } from "vue";
@@
-onMounted(() => {
+let fadeInitTimer;
+
+onMounted(() => {
   // 延迟初始化,确保 DOM 已完全渲染
-  setTimeout(() => {
+  fadeInitTimer = setTimeout(() => {
     if (initFadeInUp) {
       const refs = [featureHeaderRef.value, mcpContentRef.value].filter(Boolean);
       if (refs.length > 0) {
         initFadeInUp(refs);
       }
     }
   }, 200);
 });
+
+onUnmounted(() => {
+  clearTimeout(fadeInitTimer);
+});

Also applies to: 54-64

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/home/src/views/tiny-vue-home/components/McpSection.vue` at line 2,
Store the timer ID returned by setTimeout in a tracked variable (e.g., a ref or
let named animationTimerId) when calling setTimeout inside the component (the
block currently using onMounted and setTimeout), and add an onBeforeUnmount hook
that calls clearTimeout(animationTimerId) to cancel the pending callback if the
component unmounts early; update any other delayed-init calls (the same pattern
around lines 54-64) to use the same tracked ID and clearing logic.

Comment on lines +100 to +107
<a href="https://opentiny.design/tiny-vue" target="_blank" class="btn primary"
>即刻体验</a
>
<a
href="https://docs.opentiny.design/tiny-vue/guide/introduce.html"
target="_blank"
class="btn secondary"
>阅读文档 <IconArrowRight
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Harden external links opened with target="_blank".

Add rel="noopener noreferrer" to prevent opener access from the new tab.

🔐 Suggested fix
-        <a href="https://opentiny.design/tiny-vue" target="_blank" class="btn primary"
+        <a
+          href="https://opentiny.design/tiny-vue"
+          target="_blank"
+          rel="noopener noreferrer"
+          class="btn primary"
+        "
           >即刻体验</a
         >
         <a
           href="https://docs.opentiny.design/tiny-vue/guide/introduce.html"
           target="_blank"
+          rel="noopener noreferrer"
           class="btn secondary"
           >阅读文档 <IconArrowRight
         /></a>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/home/src/views/tiny-vue-home/components/McpSection.vue` around lines
100 - 107, The external anchor elements (the <a> tags with class "btn primary"
and "btn secondary" in the McpSection.vue template) open links with
target="_blank" and must be hardened; add rel="noopener noreferrer" to each
external anchor (both the "即刻体验" link and the "阅读文档" link that contains
IconArrowRight) so the new tab cannot access window.opener and to prevent
potential reverse tabnabbing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant