feat: add smooth site-wide animations with framer-motion
Local Build and Deploy / deploy (push) Successful in 53s

- Add framer-motion and tailwindcss-animate for transitions
- Add page transitions via AnimatePresence in the site layout
- Convert nav dropdown and mobile menu to animated motion components
- Add entry animation to the radio player widget
- Add reveal/stagger animations to the home page views
- Add shared motion utilities and reusable animated components
This commit is contained in:
openhands committed 2026-07-16 20:58:18 +02:00
1 parent ac1b412756
commit a3b077c488
13 files changed
+624 -142

No files matched your search

+92 -24
View File
@@ -1,6 +1,7 @@
@import "tailwindcss";
@plugin "@tailwindcss/forms";
@plugin "@tailwindcss/typography";
@plugin "tailwindcss-animate";
@custom-variant dark (&:where(.dark, .dark *));
@theme {
@@ -270,7 +271,6 @@ html.dark body.site-bg:has([data-admin]) {
background-blend-mode: normal;
}
.article-body {
line-height: 1.7;
}
@@ -382,7 +382,11 @@ a:hover {
font-size: 14px;
cursor: pointer;
transition: all 0.18s ease;
background: color-mix(in srgb, var(--color-text-muted) 14%, var(--color-surface));
background: color-mix(
in srgb,
var(--color-text-muted) 14%,
var(--color-surface)
);
color: var(--color-text-readable, var(--color-text));
text-decoration: none;
}
@@ -642,8 +646,16 @@ tbody tr:hover {
flex-direction: column;
width: 100%;
background: var(--color-surface);
color: var(--color-surface-text-readable, var(--color-text-readable, var(--color-text)));
border: 1px solid color-mix(in srgb, var(--color-text-muted-readable, var(--color-text-muted)) 12%, transparent);
color: var(
--color-surface-text-readable,
var(--color-text-readable, var(--color-text))
);
border: 1px solid
color-mix(
in srgb,
var(--color-text-muted-readable, var(--color-text-muted)) 12%,
transparent
);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-card);
overflow: hidden;
@@ -663,7 +675,11 @@ tbody tr:hover {
color-mix(in srgb, var(--color-primary) 5%, var(--color-surface))
);
border-bottom: 1px solid
color-mix(in srgb, var(--color-text-muted-readable, var(--color-text-muted)) 8%, transparent);
color-mix(
in srgb,
var(--color-text-muted-readable, var(--color-text-muted)) 8%,
transparent
);
}
.content-card-icon {
flex: none;
@@ -690,7 +706,10 @@ tbody tr:hover {
font-weight: 700;
font-size: 1rem;
line-height: 1.3;
color: var(--color-surface-text-readable, var(--color-text-readable, var(--color-text)));
color: var(
--color-surface-text-readable,
var(--color-text-readable, var(--color-text))
);
}
.content-card-subtitle {
margin: 0.15rem 0 0;
@@ -740,7 +759,12 @@ tbody tr:hover {
}
.stat-block {
background: var(--color-background);
border: 1px solid color-mix(in srgb, var(--color-text-muted-readable, var(--color-text-muted)) 12%, transparent);
border: 1px solid
color-mix(
in srgb,
var(--color-text-muted-readable, var(--color-text-muted)) 12%,
transparent
);
border-radius: 12px;
padding: 0.85rem 1rem;
text-align: center;
@@ -776,7 +800,11 @@ tbody tr:hover {
font-weight: 700;
padding: 0.1rem 0.55rem 0.1rem 0.45rem;
border-radius: 999px;
background: color-mix(in srgb, var(--color-text-muted-readable, var(--color-text-muted)) 14%, transparent);
background: color-mix(
in srgb,
var(--color-text-muted-readable, var(--color-text-muted)) 14%,
transparent
);
color: var(--color-text-muted-readable, var(--color-text-muted));
}
.online-badge.online {
@@ -806,7 +834,12 @@ tbody tr:hover {
font-weight: 800;
font-size: 0.95rem;
background: var(--color-background);
border: 1px solid color-mix(in srgb, var(--color-text-muted-readable, var(--color-text-muted)) 18%, transparent);
border: 1px solid
color-mix(
in srgb,
var(--color-text-muted-readable, var(--color-text-muted)) 18%,
transparent
);
}
.rank-badge.rank-1 {
background: color-mix(in srgb, var(--color-warning) 20%, transparent);
@@ -852,7 +885,11 @@ tbody tr:hover {
gap: 0.25rem;
padding-bottom: 0.5rem;
border-bottom: 1px solid
color-mix(in srgb, var(--color-text-muted-readable, var(--color-text-muted)) 14%, transparent);
color-mix(
in srgb,
var(--color-text-muted-readable, var(--color-text-muted)) 14%,
transparent
);
overflow-x: auto;
}
.radio-sidebar-head {
@@ -917,7 +954,11 @@ tbody tr:hover {
position: relative;
width: min(440px, 100%);
border: 1px solid
color-mix(in srgb, var(--color-primary) 30%, color-mix(in srgb, var(--color-text-muted) 22%, transparent));
color-mix(
in srgb,
var(--color-primary) 30%,
color-mix(in srgb, var(--color-text-muted) 22%, transparent)
);
border-radius: 8px;
background:
linear-gradient(
@@ -927,7 +968,10 @@ tbody tr:hover {
),
var(--color-surface);
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.34);
color: var(--color-surface-text-readable, var(--color-text-readable, var(--color-text)));
color: var(
--color-surface-text-readable,
var(--color-text-readable, var(--color-text))
);
padding: 1.25rem;
}
.cms-info-close {
@@ -938,7 +982,12 @@ tbody tr:hover {
width: 2rem;
height: 2rem;
place-items: center;
border: 1px solid color-mix(in srgb, var(--color-text-muted-readable, var(--color-text-muted)) 18%, transparent);
border: 1px solid
color-mix(
in srgb,
var(--color-text-muted-readable, var(--color-text-muted)) 18%,
transparent
);
border-radius: 999px;
background: color-mix(in srgb, var(--color-surface) 84%, transparent);
color: var(--color-text-muted-readable, var(--color-text-muted));
@@ -947,7 +996,10 @@ tbody tr:hover {
line-height: 1;
}
.cms-info-close:hover {
color: var(--color-surface-text-readable, var(--color-text-readable, var(--color-text)));
color: var(
--color-surface-text-readable,
var(--color-text-readable, var(--color-text))
);
border-color: color-mix(in srgb, var(--color-primary) 40%, transparent);
}
.cms-info-kicker {
@@ -970,7 +1022,10 @@ tbody tr:hover {
border: 1px solid color-mix(in srgb, var(--color-primary) 34%, transparent);
border-radius: 999px;
background: color-mix(in srgb, var(--color-primary) 14%, transparent);
color: var(--color-surface-text-readable, var(--color-text-readable, var(--color-text)));
color: var(
--color-surface-text-readable,
var(--color-text-readable, var(--color-text))
);
font-size: 0.75rem;
font-weight: 900;
padding: 0.3rem 0.6rem;
@@ -988,7 +1043,12 @@ tbody tr:hover {
margin: 1rem 0 0;
}
.cms-info-grid div {
border: 1px solid color-mix(in srgb, var(--color-text-muted-readable, var(--color-text-muted)) 14%, transparent);
border: 1px solid
color-mix(
in srgb,
var(--color-text-muted-readable, var(--color-text-muted)) 14%,
transparent
);
border-radius: 8px;
background: color-mix(in srgb, var(--color-background) 68%, transparent);
padding: 0.7rem;
@@ -1001,7 +1061,10 @@ tbody tr:hover {
}
.cms-info-grid dd {
margin: 0.18rem 0 0;
color: var(--color-surface-text-readable, var(--color-text-readable, var(--color-text)));
color: var(
--color-surface-text-readable,
var(--color-text-readable, var(--color-text))
);
font-size: 0.8rem;
font-weight: 900;
line-height: 1.25;
@@ -1022,7 +1085,10 @@ tbody tr:hover {
padding: 0.65rem 0.75rem;
}
.cms-info-credit span {
color: var(--color-surface-text-readable, var(--color-text-readable, var(--color-text)));
color: var(
--color-surface-text-readable,
var(--color-text-readable, var(--color-text))
);
font-weight: 900;
}
.cms-info-credit small {
@@ -1174,9 +1240,10 @@ body:has([data-admin]) {
}
/* Admin forms / boxes follow admin tokens in both light and dark. */
body:has([data-admin]) input:not([type="checkbox"]):not([type="radio"]):not(
[type="range"]
):not([type="file"]):not([type="color"]),
body:has([data-admin])
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not(
[type="file"]
):not([type="color"]),
body:has([data-admin]) select,
body:has([data-admin]) textarea {
background-color: var(--admin-surface-elevated);
@@ -1210,9 +1277,10 @@ body:has([data-admin]) .btn-outline:hover {
color: var(--admin-text);
}
/* Override public html.dark input hardcodes inside admin. */
html.dark body:has([data-admin]) input:not([type="checkbox"]):not(
[type="radio"]
):not([type="range"]):not([type="file"]):not([type="color"]),
html.dark body:has([data-admin])
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not(
[type="file"]
):not([type="color"]),
html.dark body:has([data-admin]) select,
html.dark body:has([data-admin]) textarea {
background: var(--admin-surface-elevated);