* Refactor Gemini model display: filter old versions, group low/high pro, and improve naming * Fix potential negative minutes and refine Gemini 3 Pro grouping logic based on PR feedback * The account change process has been sped up * Address PR review: enhance error message and parameterize polling interval in process handler * Address PR review: fix potential race condition in database backup logic * fix: prevent renderer white screen and harden sentry gating * feat: localize model labels * chore: enable hoisted node-linker * chore: ignore .agent/.claude/.codex in prettier --------- Co-authored-by: Draculabo <[email protected]>
95 lines
2.3 KiB
Markdown
95 lines
2.3 KiB
Markdown
---
|
|
title: Create Explicit Component Variants
|
|
impact: MEDIUM
|
|
impactDescription: self-documenting code, no hidden conditionals
|
|
tags: composition, variants, architecture
|
|
---
|
|
|
|
## Create Explicit Component Variants
|
|
|
|
Instead of one component with many boolean props, create explicit variant
|
|
components. Each variant composes the pieces it needs. The code documents
|
|
itself.
|
|
|
|
**Incorrect (one component, many modes):**
|
|
|
|
```tsx
|
|
// What does this component actually render?
|
|
<Composer isThread isEditing={false} channelId="abc" showAttachments showFormatting={false} />
|
|
```
|
|
|
|
**Correct (explicit variants):**
|
|
|
|
```tsx
|
|
// Immediately clear what this renders
|
|
<ThreadComposer channelId="abc" />
|
|
|
|
// Or
|
|
<EditMessageComposer messageId="xyz" />
|
|
|
|
// Or
|
|
<ForwardMessageComposer messageId="123" />
|
|
```
|
|
|
|
Each implementation is unique, explicit and self-contained. Yet they can each
|
|
use shared parts.
|
|
|
|
**Implementation:**
|
|
|
|
```tsx
|
|
function ThreadComposer({ channelId }: { channelId: string }) {
|
|
return (
|
|
<ThreadProvider channelId={channelId}>
|
|
<Composer.Frame>
|
|
<Composer.Input />
|
|
<AlsoSendToChannelField channelId={channelId} />
|
|
<Composer.Footer>
|
|
<Composer.Formatting />
|
|
<Composer.Emojis />
|
|
<Composer.Submit />
|
|
</Composer.Footer>
|
|
</Composer.Frame>
|
|
</ThreadProvider>
|
|
);
|
|
}
|
|
|
|
function EditMessageComposer({ messageId }: { messageId: string }) {
|
|
return (
|
|
<EditMessageProvider messageId={messageId}>
|
|
<Composer.Frame>
|
|
<Composer.Input />
|
|
<Composer.Footer>
|
|
<Composer.Formatting />
|
|
<Composer.Emojis />
|
|
<Composer.CancelEdit />
|
|
<Composer.SaveEdit />
|
|
</Composer.Footer>
|
|
</Composer.Frame>
|
|
</EditMessageProvider>
|
|
);
|
|
}
|
|
|
|
function ForwardMessageComposer({ messageId }: { messageId: string }) {
|
|
return (
|
|
<ForwardMessageProvider messageId={messageId}>
|
|
<Composer.Frame>
|
|
<Composer.Input placeholder="Add a message, if you'd like." />
|
|
<Composer.Footer>
|
|
<Composer.Formatting />
|
|
<Composer.Emojis />
|
|
<Composer.Mentions />
|
|
</Composer.Footer>
|
|
</Composer.Frame>
|
|
</ForwardMessageProvider>
|
|
);
|
|
}
|
|
```
|
|
|
|
Each variant is explicit about:
|
|
|
|
- What provider/state it uses
|
|
- What UI elements it includes
|
|
- What actions are available
|
|
|
|
No boolean prop combinations to reason about. No impossible states.
|