refactor(media-gallery): redesign chrome to match native folds conventions
The Media Gallery panel worked but didn't look like a first-party Cinny
drawer. Redesign the chrome to match MembersDrawer / Saved Messages and the
PolicyListViewer tab precedent:
- panel + header: Surface -> Background variant; header uses Text size="H4"
and a plain close IconButton (dropped the bespoke tooltip-wrapped button)
- tabs: moved into a bordered toolbar strip; adopt the repo's
variant={active?'Primary':'Secondary'} fill={active?'Solid':'Soft'} pattern
and show per-tab counts (Images (N) / Videos (N) / Files (N))
- month grouping: replaced the centered "lines + label" divider with a
left-aligned group label (the Cinny group-label pattern)
- thumbnail tiles: hover/focus border + caption overlay are now CSS-driven
(:hover / :focus-visible) instead of React state, and live in
MediaGallery.css.ts; grid + file rows tokenized
- caption overlay also reveals on keyboard focus (a11y)
All styling consolidated into MediaGallery.css.ts; no inline grid/tile styles.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,7 @@ export const MediaGalleryDrawer = style({
|
||||
overflow: 'hidden',
|
||||
borderLeftWidth: config.borderWidth.B300,
|
||||
borderLeftStyle: 'solid',
|
||||
borderLeftColor: color.Surface.ContainerLine,
|
||||
borderLeftColor: color.Background.ContainerLine,
|
||||
'@media': {
|
||||
'(max-width: 750px)': {
|
||||
width: '100%',
|
||||
@@ -25,7 +25,102 @@ export const MediaGalleryDrawer = style({
|
||||
|
||||
export const MediaGalleryHeader = style({
|
||||
flexShrink: 0,
|
||||
paddingRight: config.space.S200,
|
||||
paddingLeft: config.space.S300,
|
||||
padding: `0 ${config.space.S200} 0 ${config.space.S300}`,
|
||||
borderBottomWidth: config.borderWidth.B300,
|
||||
});
|
||||
|
||||
export const MediaGalleryTabs = style({
|
||||
flexShrink: 0,
|
||||
padding: config.space.S200,
|
||||
gap: config.space.S100,
|
||||
borderBottomWidth: config.borderWidth.B300,
|
||||
borderBottomStyle: 'solid',
|
||||
borderBottomColor: color.Background.ContainerLine,
|
||||
});
|
||||
|
||||
export const MediaGalleryContent = style({
|
||||
padding: config.space.S200,
|
||||
});
|
||||
|
||||
export const MediaGalleryGroup = style({
|
||||
marginBottom: config.space.S300,
|
||||
});
|
||||
|
||||
export const MediaGalleryGroupLabel = style({
|
||||
padding: `${config.space.S200} ${config.space.S100}`,
|
||||
});
|
||||
|
||||
export const MediaGalleryGrid = style({
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(3, 1fr)',
|
||||
gap: config.space.S100,
|
||||
});
|
||||
|
||||
export const GalleryTile = style({
|
||||
position: 'relative',
|
||||
aspectRatio: '1',
|
||||
overflow: 'hidden',
|
||||
borderRadius: config.radii.R300,
|
||||
background: color.SurfaceVariant.Container,
|
||||
borderWidth: config.borderWidth.B300,
|
||||
borderStyle: 'solid',
|
||||
borderColor: color.SurfaceVariant.ContainerLine,
|
||||
cursor: 'pointer',
|
||||
padding: 0,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
transition: 'border-color 100ms ease-in-out',
|
||||
selectors: {
|
||||
'&:hover, &:focus-visible': {
|
||||
borderColor: color.Primary.Main,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const GalleryTileImg = style({
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
objectFit: 'cover',
|
||||
objectPosition: 'center top',
|
||||
display: 'block',
|
||||
});
|
||||
|
||||
// Dark scrim is intentional: it overlays arbitrary media, so a theme surface
|
||||
// token would not guarantee legibility of the sender/date caption.
|
||||
export const GalleryTileOverlay = style({
|
||||
position: 'absolute',
|
||||
inset: 0,
|
||||
background: 'linear-gradient(to top, rgba(0,0,0,0.72) 0%, transparent 55%)',
|
||||
opacity: 0,
|
||||
transition: 'opacity 100ms ease-in-out',
|
||||
pointerEvents: 'none',
|
||||
selectors: {
|
||||
[`${GalleryTile}:hover &, ${GalleryTile}:focus-visible &`]: {
|
||||
opacity: 1,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const GalleryTileCaption = style({
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
padding: `${config.space.S100} ${config.space.S200}`,
|
||||
});
|
||||
|
||||
export const GalleryVideoBadge = style({
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, -50%)',
|
||||
width: toRem(28),
|
||||
height: toRem(28),
|
||||
borderRadius: '50%',
|
||||
background: 'rgba(0,0,0,0.6)',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
pointerEvents: 'none',
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user