Add holiday wishlist banner

This commit is contained in:
Calum Muir 2025-12-22 15:21:10 +00:00
parent e6d4f3c7f3
commit c0cfa261a1
2 changed files with 255 additions and 112 deletions

View file

@ -41,6 +41,31 @@ function App() {
<QueryClientProvider client={queryClient}> <QueryClientProvider client={queryClient}>
<TooltipProvider> <TooltipProvider>
<Toaster /> <Toaster />
<div
className="snow-banner"
role="region"
aria-label="Holiday announcement"
>
<div className="snow-banner__snow" aria-hidden="true">
<span className="snowflake snowflake-1" />
<span className="snowflake snowflake-2" />
<span className="snowflake snowflake-3" />
<span className="snowflake snowflake-4" />
<span className="snowflake snowflake-5" />
<span className="snowflake snowflake-6" />
<span className="snowflake snowflake-7" />
<span className="snowflake snowflake-8" />
</div>
<a
className="snow-banner__link"
href="https://www.amazon.co.uk/hz/wishlist/ls/2B4R5YZQ8U4B2?ref_=wl_share"
target="_blank"
rel="noreferrer"
>
The ponies have had a chat and put together an Amazon
Wish-List for Christmas! Click here
</a>
</div>
<Router /> <Router />
</TooltipProvider> </TooltipProvider>
</QueryClientProvider> </QueryClientProvider>

View file

@ -2,116 +2,116 @@
@tailwind utilities; @tailwind utilities;
@layer components { @layer components {
.all-\[unset\] { .all-\[unset\] {
all: unset; all: unset;
} }
} }
:root { :root {
--animate-spin: spin 1s linear infinite; --animate-spin: spin 1s linear infinite;
} }
.animate-fade-in { .animate-fade-in {
animation: fade-in 1s var(--animation-delay, 0s) ease forwards; animation: fade-in 1s var(--animation-delay, 0s) ease forwards;
} }
.animate-fade-up { .animate-fade-up {
animation: fade-up 1s var(--animation-delay, 0s) ease forwards; animation: fade-up 1s var(--animation-delay, 0s) ease forwards;
} }
.animate-marquee { .animate-marquee {
animation: marquee var(--duration) infinite linear; animation: marquee var(--duration) infinite linear;
} }
.animate-marquee-vertical { .animate-marquee-vertical {
animation: marquee-vertical var(--duration) linear infinite; animation: marquee-vertical var(--duration) linear infinite;
} }
.animate-shimmer { .animate-shimmer {
animation: shimmer 8s infinite; animation: shimmer 8s infinite;
} }
.animate-spin { .animate-spin {
animation: var(--animate-spin); animation: var(--animate-spin);
} }
@keyframes spin { @keyframes spin {
to { to {
transform: rotate(1turn); transform: rotate(1turn);
} }
} }
@keyframes image-glow { @keyframes image-glow {
0% { 0% {
opacity: 0; opacity: 0;
animation-timing-function: cubic-bezier(0.74, 0.25, 0.76, 1); animation-timing-function: cubic-bezier(0.74, 0.25, 0.76, 1);
} }
10% { 10% {
opacity: 0.7; opacity: 0.7;
animation-timing-function: cubic-bezier(0.12, 0.01, 0.08, 0.99); animation-timing-function: cubic-bezier(0.12, 0.01, 0.08, 0.99);
} }
to { to {
opacity: 0.4; opacity: 0.4;
} }
} }
@keyframes fade-in { @keyframes fade-in {
0% { 0% {
opacity: 0; opacity: 0;
transform: translateY(-10px); transform: translateY(-10px);
} }
to { to {
opacity: 1; opacity: 1;
transform: none; transform: none;
} }
} }
@keyframes fade-up { @keyframes fade-up {
0% { 0% {
opacity: 0; opacity: 0;
transform: translateY(20px); transform: translateY(20px);
} }
to { to {
opacity: 1; opacity: 1;
transform: none; transform: none;
} }
} }
@keyframes shimmer { @keyframes shimmer {
0%, 0%,
90%, 90%,
to { to {
background-position: calc(-100% - var(--shimmer-width)) 0; background-position: calc(-100% - var(--shimmer-width)) 0;
} }
30%, 30%,
60% { 60% {
background-position: calc(100% + var(--shimmer-width)) 0; background-position: calc(100% + var(--shimmer-width)) 0;
} }
} }
@keyframes marquee { @keyframes marquee {
0% { 0% {
transform: translate(0); transform: translate(0);
} }
to { to {
transform: translateX(calc(-100% - var(--gap))); transform: translateX(calc(-100% - var(--gap)));
} }
} }
@keyframes marquee-vertical { @keyframes marquee-vertical {
0% { 0% {
transform: translateY(0); transform: translateY(0);
} }
to { to {
transform: translateY(calc(-100% - var(--gap))); transform: translateY(calc(-100% - var(--gap)));
} }
} }
@tailwind base; @tailwind base;
@ -119,80 +119,198 @@
@tailwind utilities; @tailwind utilities;
@layer base { @layer base {
:root { :root {
--background: 0 0% 100%; --background: 0 0% 100%;
--foreground: 222.2 47.4% 11.2%; --foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%; --muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%; --muted-foreground: 215.4 16.3% 46.9%;
--popover: 0 0% 100%; --popover: 0 0% 100%;
--popover-foreground: 222.2 47.4% 11.2%; --popover-foreground: 222.2 47.4% 11.2%;
--border: 214.3 31.8% 91.4%; --border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%; --input: 214.3 31.8% 91.4%;
--card: transparent; --card: transparent;
--card-foreground: 222.2 47.4% 11.2%; --card-foreground: 222.2 47.4% 11.2%;
--primary: 222.2 47.4% 11.2%; --primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%; --primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%; --secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%; --secondary-foreground: 222.2 47.4% 11.2%;
--accent: 210 40% 96.1%; --accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%; --accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 100% 50%; --destructive: 0 100% 50%;
--destructive-foreground: 210 40% 98%; --destructive-foreground: 210 40% 98%;
--ring: 215 20.2% 65.1%; --ring: 215 20.2% 65.1%;
--radius: 0.5rem; --radius: 0.5rem;
} }
.dark { .dark {
--background: 224 71% 4%; --background: 224 71% 4%;
--foreground: 213 31% 91%; --foreground: 213 31% 91%;
--muted: 223 47% 11%; --muted: 223 47% 11%;
--muted-foreground: 215.4 16.3% 56.9%; --muted-foreground: 215.4 16.3% 56.9%;
--accent: 216 34% 17%; --accent: 216 34% 17%;
--accent-foreground: 210 40% 98%; --accent-foreground: 210 40% 98%;
--popover: 224 71% 4%; --popover: 224 71% 4%;
--popover-foreground: 215 20.2% 65.1%; --popover-foreground: 215 20.2% 65.1%;
--border: 216 34% 17%; --border: 216 34% 17%;
--input: 216 34% 17%; --input: 216 34% 17%;
--card: transparent; --card: transparent;
--card-foreground: 213 31% 91%; --card-foreground: 213 31% 91%;
--primary: 210 40% 98%; --primary: 210 40% 98%;
--primary-foreground: 222.2 47.4% 1.2%; --primary-foreground: 222.2 47.4% 1.2%;
--secondary: 222.2 47.4% 11.2%; --secondary: 222.2 47.4% 11.2%;
--secondary-foreground: 210 40% 98%; --secondary-foreground: 210 40% 98%;
--destructive: 0 63% 31%; --destructive: 0 63% 31%;
--destructive-foreground: 210 40% 98%; --destructive-foreground: 210 40% 98%;
--ring: 216 34% 17%; --ring: 216 34% 17%;
--radius: 0.5rem; --radius: 0.5rem;
} }
} }
@layer base { @layer base {
* { * {
@apply border-border; @apply border-border;
} }
body { body {
@apply bg-background text-foreground; @apply bg-background text-foreground;
font-feature-settings: "rlig" 1, "calt" 1; font-feature-settings:
} "rlig" 1,
"calt" 1;
}
}
.snow-banner {
position: sticky;
top: 0;
z-index: 50;
overflow: hidden;
background: linear-gradient(120deg, #0a3b6a, #0f5b8f);
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
animation: banner-slide-down 0.6s ease-out;
}
.snow-banner__link {
display: block;
padding: 14px 20px;
text-align: center;
font-family: "Merriweather", Helvetica, serif;
font-weight: 700;
color: #ffffff;
text-decoration: none;
letter-spacing: 0.01em;
}
.snow-banner__link:hover,
.snow-banner__link:focus-visible {
text-decoration: underline;
}
.snow-banner__snow {
pointer-events: none;
position: absolute;
inset: 0;
}
.snowflake {
position: absolute;
top: -12px;
width: 6px;
height: 6px;
border-radius: 999px;
background: rgba(255, 255, 255, 0.8);
animation: snow-fall 6s linear infinite;
}
.snowflake-1 {
left: 8%;
animation-delay: 0s;
animation-duration: 5.5s;
}
.snowflake-2 {
left: 18%;
animation-delay: 1s;
animation-duration: 6.5s;
}
.snowflake-3 {
left: 32%;
animation-delay: 0.5s;
animation-duration: 5.8s;
}
.snowflake-4 {
left: 45%;
animation-delay: 1.4s;
animation-duration: 6.2s;
}
.snowflake-5 {
left: 58%;
animation-delay: 0.2s;
animation-duration: 5.9s;
}
.snowflake-6 {
left: 72%;
animation-delay: 1.1s;
animation-duration: 6.7s;
}
.snowflake-7 {
left: 84%;
animation-delay: 0.7s;
animation-duration: 5.6s;
}
.snowflake-8 {
left: 93%;
animation-delay: 1.6s;
animation-duration: 6.9s;
}
@keyframes banner-slide-down {
from {
transform: translateY(-100%);
}
to {
transform: translateY(0);
}
}
@keyframes snow-fall {
0% {
transform: translateY(-10px);
opacity: 0;
}
10% {
opacity: 0.9;
}
100% {
transform: translateY(60px);
opacity: 0;
}
} }