Repository navigation
perf: style - #7868
perf: style#7868
Conversation
| ) | ||
|
|
||
| return { ...bundle, portalList } | ||
| } |
There was a problem hiding this comment.
No syntax errors are apparent, and the watcher generally implements the intended “same application: 0 → >0 conversations, auto-expand once” behavior. The previousCount !== 0 guard correctly prevents later message-count changes from overriding a manual collapse.
Potential issues / suggestions:
-
Missed auto-expand when app ID and count change in the same flush
- If
currentApplicationIdchanges and the new app already has conversations in the same tick, the guardapplicationId !== previousApplicationIdreturns early, so the group is not expanded. - This may be intentional, but if switching to an app with existing conversations should also expand it, the logic needs adjustment.
- If
-
No retry if the group is not found
- If
portalList.applicationGroups.valuehas not been updated/loaded yet,find(...)returnsundefined, and the expansion is permanently skipped because the count transition is already consumed. - Consider
{ flush: 'post' }ornextTick()if group availability can lag behind conversation changes.
- If
-
Manual collapse can be overridden after conversations become empty
- Scenario: user manually collapses a group with 1 conversation → all conversations are deleted (
count = 0) → a new conversation arrives (count = 1) → watcher expands again. - If manual collapse must survive this case, track an explicit per-group
userCollapsed/autoExpandDoneflag instead of relying only onpreviousCount === 0.
- Scenario: user manually collapses a group with 1 conversation → all conversations are deleted (
-
Direct mutation of
group.expandedgroup.expanded = trueassumes the group object is deeply reactive/mutable.- If
applicationGroupsis ashallowRef, readonly, frozen, or computed structure, this mutation may not trigger UI updates. Prefer a centralized action such asportalList.expandGroup(applicationId).
-
Watcher cleanup
- If
createPortalConversationcan be called outside a component setup scope, the watcher may not be automatically disposed. Verify lifecycle handling or dispose it explicitly.
- If
-
No
immediate- If an application is created with conversations already present, the group will not auto-expand. If that is desired, add
immediatewith explicit initialization logic.
- If an application is created with conversations already present, the group will not auto-expand. If that is desired, add
Optimization suggestion:
Use separate watch sources instead of constructing a new tuple array on each evaluation. This is slightly clearer and avoids unnecessary tuple allocation:
watch(
[currentApplicationId, () => bundle.list.conversations.value.length] as const,
([applicationId, count], [previousApplicationId, previousCount]) => {
if (applicationId !== previousApplicationId) return
if (previousCount !== 0 || count === 0) return
const group = portalList.applicationGroups.value.find(
(applicationGroup) => applicationGroup.id === applicationId,
)
if (group) group.expanded = true
},
{ flush: 'post' },
)Overall: the logic is acceptable for the stated narrow case, but it is fragile around group-loading timing and manual-collapse persistence. I’d recommend using a flush: 'post' watcher and, if manual collapse must be respected across empty/non-empty transitions, storing explicit expansion state per group.
| } | ||
| &.small { | ||
| .cell { | ||
| padding: calc(var(--spacing) * 2) calc(var(--spacing) * 3); |
There was a problem hiding this comment.
Here is the review of the provided CSS/SCSS code:
1. Irregularities & Potential Issues
A. Hardcoded Value (32px) in .mk-form-item-with-avatar
- Issue:
calc(32px + var(--spacing) * 3)mixes hardcoded pixel values with design tokens. If the avatar size or spacing token changes, this rule will break visually (misalignment). - Risk: Low maintainability. This specific padding likely relies on an external component structure (Element UI + Avatar component). Without a corresponding CSS variable for "avatar width" or "avatar container padding," this is brittle.
- Suggestion: Extract
32px(and potentially the extra spacing logic) into a CSS variable if possible, e.g.,--avatar-offset. If not possible, add a comment explaining why32pxis used (e.g., "Matches default el-avatar size").
B. :has() Selector Support (Critical)
- Issue: The rule
.el-table__row:has(> .el-table-column--selection .el-checkbox.is-checked)uses:has(). - Compatibility Check: As of current standards,
:has()has broad support in modern browsers (Chrome 105+, Safari 15.4+, Firefox 121+). However, if your project targets older browsers or enterprise environments without auto-updates, this rule will be totally ignored by those browsers, causing selection colors to disappear. - Suggestion: Verify your browser support requirements. If targeting broader compatibility, this approach is risky without polyfills (which are often heavy or unreliable for complex selectors like this). A JavaScript-free alternative is often difficult; usually, Vue/React state classes are added to the row instead.
C. Specificity & Element Plus Internal Class Names
- Issue: Reliance on specific internal class names like
.el-table-column--selection,.el-table__cell, and.el-form-item__content. - Risk: Element Plus (and other UI libraries) can change internal DOM structure or class naming conventions in patch updates. These selectors are fragile.
- Suggestion: Check if Element Plus provides official props or CSS variables for this behavior. For example, does
el-tablesupporthighlight-current-rowor similar props that achieve this visual effect natively? Native solutions are more stable.
D. Commented-Out Code
- Issue:
// --el-table-row-hover-bg-color: var(--el-color-primary-light-9); - Suggestion: Remove this line. Keep commit history clean. If you need this fallback later, rely on source control, not commented-out code in production styles.
2. Optimization Suggestions
A. Use var() for Avatar Offset (Refactor)
If this pattern appears elsewhere, create a variable:
:root {
--mk-avatar-width: 32px;
}
.mk-form-item-with-avatar > .el-form-item__content > .el-form-item__error {
padding-left: calc(var(--mk-avatar-width) + var(--spacing) * 3);
}B. Alternative to :has() for Row Selection Highlighting
If you must avoid :has(), inspect how Element Plus handles selection. Often, they add a class to the <tr> itself when selected (e.g., .el-table__selected-row). Check the rendered HTML:
- If there is a native class like
.is-selectedon thetr:This is significantly more performant and compatible than.el-table .el-table__row.el-table__selected-row > .el-table__cell { background-color: var(--el-color-primary-light-9); }
:has().
C. Variable Consistency
- You changed
color-mix(...)tovar(--mk-N200). Ensure--mk-N200is a light gray/neutral color. - Using
var(--el-table-row-hover-bg-color)consistently via variables is good. Just ensure--mk-N200contrasts enough against text color (WCAG compliance).
Summary of Recommendations
- Browser Compatibility: Confirm
:has()is acceptable for your target audience. If not, refactor to use JS-applied classes or native Element Plus props. - Fragility: Move away from deep nesting and specific internal EP class names where possible. Look for official customization props.
- Hardcoding: Mitigate the
32pxhardcode by adding a comment or variable. - Cleanliness: Delete the commented-out
row-hoverline.
| <el-form-item class="mk-form-item-with-avatar" label="名称" prop="name"> | ||
| <div class="flex-align-center w-full gap-3"> | ||
| <MkEditAvatar v-model="toolForm.icon" @change="handleIconChange"> | ||
| <template #default="{ icon }"> |
There was a problem hiding this comment.
Here is the review of the provided code diff:
1. Irregularities & Potential Issues
- None detected in functionality: The changes are purely stylistic (formatting for readability) and UI consistency (adding a CSS class). They do not alter logic or props definition, so no bugs are introduced.
2. Optimization Suggestions & Best Practices
A. Props Definition Type Safety (TypeScript/Vue)
Using typeof XxxApi directly for the api prop type can be fragile if the API objects have methods that aren't strictly needed here or if their structure changes.
- Suggestion: Consider defining a minimal interface that includes only the methods the component actually uses. This makes testing easier and decouples the component from specific API implementations.
// Example interface IToolApiClient { create: (data: any) => Promise<any> update: (id: string, data: any) => Promise<any> // ... other used methods } props: { api: IToolApiClient }
B. CSS Class Naming Convention
You added mk-form-item-with-avatar.
- Observation: Hardcoding layout-specific classes (
flex-align-center w-full gap-3) inside the template alongside a semantic class (mk-form-item-with-avatar) mixes styling concerns. - Suggestion: Ensure
mk-form-item-with-avatarhandles the avatar positioning internally via its scoped styles or global CSS. If it only provides spacing/alignment, consider using utility classes consistently, or moving all layout logic into the component's own CSS to keep the template clean.
C. Code Formatting (Prettier/ESLint)
- Good: Breaking down the
definePropsgeneric into multiple lines improves readability significantly, especially as prop count grows. This aligns with common Vue 3 style guides. - Check: Ensure your ESLint/Prettier configuration automatically enforces this multi-line format for complex types to prevent future reformatting noise in diffs.
Summary
The changes are safe and beneficial for readability. No functional issues found. Focus on long-term maintainability of the api prop type structure.
perf: style