fix: rewrite decoration grid to contain images within cells
The INSET overflow approach (position:absolute images extending beyond 52×52 buttons) was fundamentally broken: absolutely positioned children don't contribute to flex row height, so rowGap controlled button-to-button spacing but image pixels still painted into the gap, causing visual overlap regardless of how large rowGap was set. New approach: 72×72 circle cells, overflow:hidden, image fills the cell via inset:0 with objectFit:contain. Gap of 16px is actual clear space between cell edges — no math needed. Also bumped maxHeight 420→480. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -12,7 +12,7 @@ import {
|
||||
import { invalidateDecorationCache } from '../../../hooks/useAvatarDecoration';
|
||||
|
||||
const PROFILE_FIELD = 'io.lotus.avatar_decoration';
|
||||
const INSET = 8;
|
||||
const CELL_SIZE = 72;
|
||||
|
||||
function DecorationPreviewCell({
|
||||
slug,
|
||||
@@ -34,29 +34,19 @@ function DecorationPreviewCell({
|
||||
onClick={() => onSelect(slug)}
|
||||
style={{
|
||||
position: 'relative',
|
||||
width: 52,
|
||||
height: 52,
|
||||
width: CELL_SIZE,
|
||||
height: CELL_SIZE,
|
||||
flexShrink: 0,
|
||||
border: `2px solid ${selected ? 'var(--accent-cyan)' : 'transparent'}`,
|
||||
borderRadius: '0.75rem',
|
||||
borderRadius: '50%',
|
||||
background: 'var(--bg-surface-variant)',
|
||||
cursor: 'pointer',
|
||||
padding: 0,
|
||||
boxShadow: selected ? '0 0 0 1px var(--accent-cyan)' : 'none',
|
||||
overflow: 'visible',
|
||||
overflow: 'hidden',
|
||||
outline: 'none',
|
||||
}}
|
||||
>
|
||||
{/* Avatar placeholder tint */}
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
inset: 0,
|
||||
borderRadius: '0.75rem',
|
||||
background: 'var(--bg-surface-variant)',
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
/>
|
||||
<img
|
||||
src={`${DECORATION_CDN}/${slug}.png`}
|
||||
alt={name}
|
||||
@@ -64,10 +54,9 @@ function DecorationPreviewCell({
|
||||
decoding="async"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: -INSET,
|
||||
left: -INSET,
|
||||
width: `calc(100% + ${INSET * 2}px)`,
|
||||
height: `calc(100% + ${INSET * 2}px)`,
|
||||
inset: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
objectFit: 'contain',
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
@@ -149,12 +138,12 @@ export function ProfileDecoration() {
|
||||
<div
|
||||
style={{
|
||||
position: 'relative',
|
||||
width: 52,
|
||||
height: 52,
|
||||
width: CELL_SIZE,
|
||||
height: CELL_SIZE,
|
||||
flexShrink: 0,
|
||||
borderRadius: '0.75rem',
|
||||
borderRadius: '50%',
|
||||
background: 'var(--bg-surface-variant)',
|
||||
overflow: 'visible',
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
{selected && (
|
||||
@@ -163,10 +152,9 @@ export function ProfileDecoration() {
|
||||
alt="Selected decoration preview"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: -INSET,
|
||||
left: -INSET,
|
||||
width: `calc(100% + ${INSET * 2}px)`,
|
||||
height: `calc(100% + ${INSET * 2}px)`,
|
||||
inset: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
objectFit: 'contain',
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
@@ -236,7 +224,7 @@ export function ProfileDecoration() {
|
||||
direction="Column"
|
||||
gap="300"
|
||||
style={{
|
||||
maxHeight: 420,
|
||||
maxHeight: 480,
|
||||
overflowY: 'auto',
|
||||
paddingRight: 4,
|
||||
}}
|
||||
@@ -250,12 +238,8 @@ export function ProfileDecoration() {
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
columnGap: 28,
|
||||
rowGap: 52,
|
||||
paddingBottom: INSET,
|
||||
paddingLeft: INSET,
|
||||
paddingRight: INSET,
|
||||
paddingTop: INSET,
|
||||
gap: 16,
|
||||
padding: 4,
|
||||
}}
|
||||
>
|
||||
{category.decorations.map((d) => (
|
||||
|
||||
Reference in New Issue
Block a user