feat(P2-7): expand link previews to 13 domain-specific card types
YouTube, Vimeo (shared VideoCard with thumbnail + play overlay), GitHub (repo name/description parse), Twitter/X (tweet text parse), Reddit (subreddit + post title), Spotify (artwork + track/artist), Twitch (thumbnail + LIVE badge), Steam (game header image), Wikipedia (clean text card), Discord (server icon + member count), npm (package name/description), Stack Overflow (question excerpt), IMDb (portrait poster + title/rating) Generic fallback gains favicon from google/s2/favicons; empty cards (no title or description) are suppressed. Shared SiteBadge component with brand-colour CSS classes per domain in UrlPreview.css.tsx. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -138,3 +138,209 @@ export const GenericFaviconImg = style([
|
||||
flexShrink: 0,
|
||||
},
|
||||
]);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Shared media-card thumbnail (VideoCard, Steam, etc.)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export const MediaThumbnailWrapper = style([
|
||||
DefaultReset,
|
||||
{
|
||||
position: 'relative',
|
||||
flexShrink: 0,
|
||||
width: toRem(160),
|
||||
height: toRem(90),
|
||||
overflow: 'hidden',
|
||||
cursor: 'pointer',
|
||||
backgroundColor: color.Surface.Container,
|
||||
|
||||
':hover': {
|
||||
filter: 'brightness(0.85)',
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
export const MediaThumbnailImg = style([
|
||||
DefaultReset,
|
||||
{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
objectFit: 'cover',
|
||||
objectPosition: 'center',
|
||||
display: 'block',
|
||||
},
|
||||
]);
|
||||
|
||||
export const MediaPlayOverlay = style([
|
||||
DefaultReset,
|
||||
{
|
||||
position: 'absolute',
|
||||
inset: 0,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
]);
|
||||
|
||||
export const MediaPlayButton = style([
|
||||
DefaultReset,
|
||||
{
|
||||
width: toRem(44),
|
||||
height: toRem(44),
|
||||
borderRadius: '50%',
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.75)',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
color: '#ffffff',
|
||||
},
|
||||
]);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Shared square artwork thumbnail (Spotify, IMDb poster, Discord icon)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export const ArtworkThumbnail = style([
|
||||
DefaultReset,
|
||||
{
|
||||
flexShrink: 0,
|
||||
width: toRem(72),
|
||||
height: toRem(72),
|
||||
objectFit: 'cover',
|
||||
objectPosition: 'center',
|
||||
display: 'block',
|
||||
},
|
||||
]);
|
||||
|
||||
// IMDb portrait poster (60 × 90)
|
||||
export const PosterThumbnail = style([
|
||||
DefaultReset,
|
||||
{
|
||||
flexShrink: 0,
|
||||
width: toRem(60),
|
||||
height: toRem(90),
|
||||
objectFit: 'cover',
|
||||
objectPosition: 'center',
|
||||
display: 'block',
|
||||
},
|
||||
]);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Site-badge shared base
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export const SiteBadge = style([
|
||||
DefaultReset,
|
||||
{
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
gap: config.space.S100,
|
||||
paddingLeft: config.space.S100,
|
||||
paddingRight: config.space.S100,
|
||||
paddingTop: '2px',
|
||||
paddingBottom: '2px',
|
||||
borderRadius: config.radii.R300,
|
||||
fontSize: toRem(11),
|
||||
fontWeight: 700,
|
||||
lineHeight: '1.4',
|
||||
letterSpacing: '0.03em',
|
||||
flexShrink: 0,
|
||||
},
|
||||
]);
|
||||
|
||||
// Individual badge colour overrides (background / foreground)
|
||||
export const BadgeVimeo = style({
|
||||
backgroundColor: '#1ab7ea',
|
||||
color: '#ffffff',
|
||||
});
|
||||
|
||||
export const BadgeTwitter = style({
|
||||
backgroundColor: '#000000',
|
||||
color: '#ffffff',
|
||||
});
|
||||
|
||||
export const BadgeReddit = style({
|
||||
backgroundColor: '#ff4500',
|
||||
color: '#ffffff',
|
||||
});
|
||||
|
||||
export const BadgeSpotify = style({
|
||||
backgroundColor: '#1db954',
|
||||
color: '#ffffff',
|
||||
});
|
||||
|
||||
export const BadgeTwitch = style({
|
||||
backgroundColor: '#9146ff',
|
||||
color: '#ffffff',
|
||||
});
|
||||
|
||||
export const BadgeSteam = style({
|
||||
backgroundColor: '#1b2838',
|
||||
color: '#c7d5e0',
|
||||
});
|
||||
|
||||
export const BadgeWikipedia = style({
|
||||
backgroundColor: color.SurfaceVariant.ContainerLine,
|
||||
color: color.SurfaceVariant.OnContainer,
|
||||
});
|
||||
|
||||
export const BadgeDiscord = style({
|
||||
backgroundColor: '#5865f2',
|
||||
color: '#ffffff',
|
||||
});
|
||||
|
||||
export const BadgeNpm = style({
|
||||
backgroundColor: '#cb3837',
|
||||
color: '#ffffff',
|
||||
});
|
||||
|
||||
export const BadgeStackOverflow = style({
|
||||
backgroundColor: '#f48024',
|
||||
color: '#ffffff',
|
||||
});
|
||||
|
||||
export const BadgeImdb = style({
|
||||
backgroundColor: '#f5c518',
|
||||
color: '#000000',
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Twitch LIVE badge
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export const TwitchLiveBadge = style([
|
||||
DefaultReset,
|
||||
{
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
paddingLeft: config.space.S100,
|
||||
paddingRight: config.space.S100,
|
||||
paddingTop: '2px',
|
||||
paddingBottom: '2px',
|
||||
borderRadius: config.radii.R300,
|
||||
fontSize: toRem(11),
|
||||
fontWeight: 700,
|
||||
lineHeight: '1.4',
|
||||
backgroundColor: '#e91916',
|
||||
color: '#ffffff',
|
||||
letterSpacing: '0.04em',
|
||||
},
|
||||
]);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Icon-wrapper (generic left-side icon block — Twitter, Reddit, Wikipedia…)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export const IconWrapper = style([
|
||||
DefaultReset,
|
||||
{
|
||||
flexShrink: 0,
|
||||
width: toRem(72),
|
||||
minHeight: toRem(72),
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: color.Surface.ContainerHover,
|
||||
},
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user