fix(ui): mention color picker, send-animation conflict, DM virtualizer (N69,N10,N22)
- N69: @mention highlight color now uses HexColorPickerPopOut + react-colorful HexColorPicker behind a folds Button (color swatch); built-in onRemove replaces the separate Reset, dropping the OS-native <input type="color"> - N10: mentionPulseKeyframes animates only box-shadow (dropped the imperceptible scale(1.003)) so it no longer fights MsgAppearClass over `transform` on self-sent @mention messages - N22: Direct.tsx virtualizer estimateSize 38 -> 52 (two-line DM row height) to avoid the initial-render jump before measureElement corrects each row Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -110,10 +110,15 @@ export type MessageBaseVariants = RecipeVariants<typeof MessageBase>;
|
||||
|
||||
// ── Mention pulse animation ───────────────────────────────────────────────────
|
||||
|
||||
// Animates only `box-shadow` — NOT `transform`. A self-sent @mention message
|
||||
// carries both this class and `MsgAppearClass` (which animates a scale), and two
|
||||
// animations on the same element cannot share the `transform` property: the
|
||||
// later one wins and the other is silently dropped. Pulsing the glow alone keeps
|
||||
// both effects working. (The previous scale(1.003) was imperceptible anyway.)
|
||||
const mentionPulseKeyframes = keyframes({
|
||||
'0%': { transform: 'scale(1)', boxShadow: 'none' },
|
||||
'30%': { transform: 'scale(1.003)', boxShadow: `0 0 8px ${color.Warning.Main}` },
|
||||
'100%': { transform: 'scale(1)', boxShadow: 'none' },
|
||||
'0%': { boxShadow: 'none' },
|
||||
'30%': { boxShadow: `0 0 8px ${color.Warning.Main}` },
|
||||
'100%': { boxShadow: 'none' },
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,7 +32,9 @@ import {
|
||||
toRem,
|
||||
} from 'folds';
|
||||
import { isKeyHotkey } from 'is-hotkey';
|
||||
import { HexColorPicker } from 'react-colorful';
|
||||
import FocusTrap from 'focus-trap-react';
|
||||
import { HexColorPickerPopOut } from '../../../components/HexColorPickerPopOut';
|
||||
import { Page, PageContent, PageHeader } from '../../../components/page';
|
||||
import { SequenceCard } from '../../../components/sequence-card';
|
||||
import {
|
||||
@@ -640,33 +642,42 @@ function Appearance() {
|
||||
title="@Mention Highlight Color"
|
||||
description="Color used to highlight messages that mention you. Leave empty to use the theme default."
|
||||
after={
|
||||
<Box alignItems="Center" gap="200">
|
||||
<input
|
||||
type="color"
|
||||
value={mentionHighlightColor || '#4caf50'}
|
||||
onChange={(e) => setMentionHighlightColor(e.target.value)}
|
||||
style={{
|
||||
width: '36px',
|
||||
height: '28px',
|
||||
cursor: 'pointer',
|
||||
borderRadius: '4px',
|
||||
border: 'none',
|
||||
padding: '2px',
|
||||
}}
|
||||
/>
|
||||
{mentionHighlightColor && (
|
||||
<HexColorPickerPopOut
|
||||
picker={
|
||||
<HexColorPicker
|
||||
color={mentionHighlightColor || '#4caf50'}
|
||||
onChange={setMentionHighlightColor}
|
||||
/>
|
||||
}
|
||||
onRemove={mentionHighlightColor ? () => setMentionHighlightColor('') : undefined}
|
||||
>
|
||||
{(openPicker, opened) => (
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => setMentionHighlightColor('')}
|
||||
aria-pressed={opened}
|
||||
onClick={openPicker}
|
||||
size="300"
|
||||
variant="Secondary"
|
||||
fill="Soft"
|
||||
radii="300"
|
||||
before={
|
||||
<span
|
||||
style={{
|
||||
width: toRem(16),
|
||||
height: toRem(16),
|
||||
borderRadius: config.radii.R300,
|
||||
background: mentionHighlightColor || color.Primary.Main,
|
||||
border: `${config.borderWidth.B300} solid ${color.SurfaceVariant.ContainerLine}`,
|
||||
display: 'inline-block',
|
||||
flexShrink: 0,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Text size="B300">Reset</Text>
|
||||
<Text size="B300">{mentionHighlightColor ? 'Change' : 'Pick'}</Text>
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
</HexColorPickerPopOut>
|
||||
}
|
||||
/>
|
||||
</SequenceCard>
|
||||
|
||||
@@ -227,7 +227,11 @@ export function Direct() {
|
||||
const virtualizer = useVirtualizer({
|
||||
count: filteredDirects.length,
|
||||
getScrollElement: () => scrollRef.current,
|
||||
estimateSize: () => 38,
|
||||
// DM rows render a two-line layout (name + message preview), so they are
|
||||
// taller than the 38px single-line rooms elsewhere. Estimating the common
|
||||
// two-line height avoids the initial-render jump/overlap before
|
||||
// `measureElement` corrects each row to its exact size.
|
||||
estimateSize: () => 52,
|
||||
overscan: 10,
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user