mid light/dark coloured gradient/shadows that thus contrast on light and dark mode

This commit is contained in:
sam
2026-05-21 13:28:27 +07:00
committed by lemon
parent 9a5d3e56fe
commit a42522dda2
5 changed files with 49 additions and 19 deletions
+10 -4
View File
@@ -86,10 +86,16 @@ export function CampaignHeroBackground({ imageUrl, className }: CampaignHeroBack
);
})}
{/* Warm tint + dark gradient — keeps foreground text legible without
completely washing the photo out. */}
<div className="absolute inset-0 bg-gradient-to-t from-background/85 via-background/55 to-background/40" />
<div className="absolute inset-0 bg-gradient-to-br from-primary/25 via-transparent to-secondary/30" />
{/* Dark vertical scrim — strong at the bottom (spotlight card) and
lighter at the top so the photo still reads. Uses black instead of
background so the overlay is consistent across light/dark themes. */}
<div className="absolute inset-0 bg-gradient-to-t from-black/80 via-black/45 to-black/15" />
{/* Warm primary tint — gives the hero its brand feel. */}
<div className="absolute inset-0 bg-gradient-to-br from-primary/20 via-transparent to-primary/10" />
{/* Left wash — mobile only, where the globe arc crosses the headline.
Dark so white headline text has a reliable backdrop. */}
<div className="absolute inset-0 bg-gradient-to-r from-black/75 via-black/35 to-transparent sm:hidden" />
{/* Film grain — same trick as Treasures' HeroGallery. Helps the
composited globe + photo feel like one image. */}
+8 -9
View File
@@ -63,10 +63,9 @@ export function HeroCampaignSpotlight({
return (
<div
className={cn(
// Compact text block over the photo. Light text + subtle drop
// shadow for legibility, no card chrome — modeled after the
// Treasures hero overlay: tight, dense, low-key.
'space-y-1.5 text-foreground [text-shadow:0_1px_2px_rgb(0_0_0/0.4)]',
// Compact text block over the photo — always white regardless of
// theme since the hero is always a dark-scrimed photo.
'space-y-1.5 text-white hero-text-shadow-soft',
className,
)}
>
@@ -75,7 +74,7 @@ export function HeroCampaignSpotlight({
</p>
{campaign.summary && (
<p className="text-xs text-foreground/80 line-clamp-2 max-w-xs">
<p className="text-xs text-white/80 line-clamp-2 max-w-xs">
{campaign.summary}
</p>
)}
@@ -101,12 +100,12 @@ export function HeroCampaignSpotlight({
</div>
)}
<div className="flex items-baseline justify-between gap-2 text-[11px] [text-shadow:none]">
<span className="font-semibold text-foreground">
<span className="font-semibold text-white">
{formatCampaignAmount(raised, btcPrice)}
{!hasGoal && <span className="ml-1 font-normal text-foreground/70">raised</span>}
{!hasGoal && <span className="ml-1 font-normal text-white/70">raised</span>}
</span>
{hasGoal && (
<span className="text-foreground/70">
<span className="text-white/70">
of {formatCampaignAmount(goal!, btcPrice)} goal
</span>
)}
@@ -115,7 +114,7 @@ export function HeroCampaignSpotlight({
);
})()}
<div className="flex flex-wrap items-center gap-x-3 gap-y-1 text-[11px] text-foreground/75 pt-0.5">
<div className="flex flex-wrap items-center gap-x-3 gap-y-1 text-[11px] text-white/75 pt-0.5">
<span className="inline-flex items-center gap-1.5">
<Avatar className="size-4 ring-1 ring-white/40">
{authorPicture && <AvatarImage src={authorPicture} alt="" />}
+2 -2
View File
@@ -313,8 +313,8 @@ export function HeroGlobe({
<stop offset="100%" stopColor={hue.glow} stopOpacity="0" />
</radialGradient>
{/* Soft highlight in the upper-left to sell the sphere shape. */}
<radialGradient id="hero-globe-highlight" cx="28%" cy="22%" r="38%">
<stop offset="0%" stopColor="hsl(50 100% 98% / 0.85)" />
<radialGradient id="hero-globe-highlight" cx="30%" cy="25%" r="35%">
<stop offset="0%" stopColor="hsl(50 100% 98% / 0.58)" />
<stop offset="100%" stopColor="hsl(50 100% 98% / 0)" />
</radialGradient>
{/* Marker glow halo. Soft, warm, no pulsing. */}
+25
View File
@@ -753,3 +753,28 @@
.hero-pan-right, .hero-pan-left { animation: none; }
.hero-globe-halo-breath { animation: none; opacity: 0.42; }
}
/* Dark drop-shadow for hero copy — photo backgrounds are always colorful,
so we want a dark shadow regardless of light/dark theme. */
.hero-text-shadow {
text-shadow:
0 2px 8px rgba(0, 0, 0, 0.8),
0 0 20px rgba(0, 0, 0, 0.45);
}
.hero-text-shadow-soft {
text-shadow: 0 1px 6px rgba(0, 0, 0, 0.65);
}
/* On mobile the globe sits under the headline — soften its left edge. */
.hero-globe-mask {
-webkit-mask-image: linear-gradient(to right, transparent 0%, black 48%, black 100%);
mask-image: linear-gradient(to right, transparent 0%, black 48%, black 100%);
}
@media (min-width: 640px) {
.hero-globe-mask {
-webkit-mask-image: none;
mask-image: none;
}
}
+4 -4
View File
@@ -271,7 +271,7 @@ export function CampaignsPage() {
<div className="absolute inset-0 pointer-events-none">
<div className="relative max-w-7xl mx-auto h-full px-4 sm:px-6">
<div className="absolute inset-y-0 right-4 sm:right-6 flex items-center">
<div className="pointer-events-auto translate-x-[40%] sm:translate-x-[38%] lg:translate-x-[38%] opacity-90">
<div className="pointer-events-auto hero-globe-mask translate-x-[40%] sm:translate-x-[38%] lg:translate-x-[38%] opacity-90">
<HeroGlobe
markers={globeMarkers}
selectedKey={highlightedMarkerKey}
@@ -305,12 +305,12 @@ export function CampaignsPage() {
{/* Foreground content — headline + CTAs at the top, spotlight info
at the bottom. Shares the `max-w-7xl mx-auto` container with the
globe so everything aligns to the same left/right axis. */}
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 py-14 lg:py-20 min-h-[560px] sm:min-h-[600px] lg:min-h-[640px] flex flex-col">
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 py-14 lg:py-20 min-h-[560px] sm:min-h-[600px] lg:min-h-[640px] flex flex-col text-white">
<div className="relative space-y-5 max-w-2xl">
<h1 className="text-4xl sm:text-5xl lg:text-6xl font-bold tracking-tight leading-[1.1] drop-shadow-sm">
<h1 className="text-4xl sm:text-5xl lg:text-6xl font-bold tracking-tight leading-[1.1] hero-text-shadow">
Connecting activists to unstoppable funding.
</h1>
<p className="text-base sm:text-lg text-foreground/80 max-w-2xl">
<p className="text-base sm:text-lg text-white/85 max-w-2xl hero-text-shadow-soft">
Raise Bitcoin directly from supporters around the world. Every donation settles
straight to your campaign's beneficiaries, with no middlemen, no chargebacks, and no
platform holding your funds.