Admin-driven front page with event calendar #7
3 changed files with 75 additions and 11 deletions
30
src/components/DoveMark.tsx
Normal file
30
src/components/DoveMark.tsx
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
/* ═══════════════════════════════════════════════════════════════
|
||||||
|
DOVE MARK
|
||||||
|
|
||||||
|
NGU's dove, lifted from the original home page. The path and its
|
||||||
|
two transforms are the drawing as exported, untouched; only the
|
||||||
|
wrapper changed — sized by the caller, coloured by currentColor,
|
||||||
|
and hidden from screen readers since it's decoration wherever
|
||||||
|
it appears.
|
||||||
|
|
||||||
|
Renders as an <svg> element, so it nests inside another SVG as
|
||||||
|
well as in HTML: pass x, y, width and height to place it in a
|
||||||
|
parent viewBox.
|
||||||
|
═══════════════════════════════════════════════════════════════ */
|
||||||
|
|
||||||
|
import type { SVGProps } from 'react'
|
||||||
|
|
||||||
|
const PATH =
|
||||||
|
'm 355.91146,-123.11955 c 3.13369,-1.59928 7.04147,-4.49077 10.29591,-6.33595 3.25443,-1.84519 6.30899,-3.58417 9.61426,-4.20523 2.65302,-0.4889 6.37319,-0.18817 9.07211,0.58357 2.69896,0.77175 5.57299,2.70484 7.16593,3.40762 1.59295,0.70275 2.24655,0.19006 2.82855,-0.77494 0.582,-0.96504 2.81839,-6.05064 3.84362,-8.9293 1.02519,-2.87864 2.26409,-5.72337 4.14553,-7.76121 1.88144,-2.03782 2.31893,-2.07776 4.06202,-3.15865 1.74307,-1.08086 10.24244,-3.71628 14.53403,-5.61581 4.29158,-1.89953 8.11957,-3.58996 12.24067,-5.48028 4.12109,-1.89033 6.08861,-2.79441 7.30709,-3.29554 0.273,0.73801 -0.2034,3.06663 -1.16031,5.22317 -0.95691,2.15654 -2.9569,5.04357 -4.86279,7.26365 -1.90589,2.22009 -4.28775,4.10342 -6.82223,5.66812 -2.53448,1.56467 -4.53981,2.45823 -7.60439,3.71266 -3.06457,1.25446 -11.88915,4.7102 -14.64698,7.12005 -2.75786,2.40984 -4.18313,6.63212 -3.64772,7.60115 0.5354,0.96902 2.51391,-1.48598 3.81084,-2.34867 1.29694,-0.8627 1.95172,-1.05814 3.14897,-1.09198 1.17765,-0.0172 2.77532,0.40067 3.29849,0.63293 1.48441,0.659 3.97438,2.00122 3.54176,3.36038 -0.16368,0.51434 -0.19462,0.56904 -3.05611,1.25841 -2.86151,0.68935 -3.48508,1.29579 -3.81533,3.74861 -0.22097,1.47094 -1.44719,3.88743 -3.13317,5.28015 -1.68596,1.39274 -4.55099,2.93627 -8.41717,3.35482 -3.86617,0.41855 -6.17544,3.97192 -6.93256,5.37259 -0.75713,1.40064 -2.66104,5.90506 -2.99685,6.15238 -0.3358,0.24732 -2.76998,-0.36582 -3.79458,-0.82517 -1.02463,-0.45935 -2.612,-1.39111 -3.63624,-2.16132 -1.02425,-0.7702 -3.457,-2.975 -3.0018,-3.64018 0.45519,-0.66516 1.56543,-1.35445 2.73515,-2.12254 1.16972,-0.76811 3.86984,-2.33631 5.3456,-3.59002 1.47576,-1.25372 2.7334,-2.47754 3.4042,-3.48323 0.67079,-1.00567 0.9358,-2.14286 -0.28206,-2.7388 -1.21786,-0.59597 -1.84092,-0.39835 -4.4486,0.0225 -2.60769,0.42097 -4.8218,1.10142 -8.46858,1.9005 -3.64678,0.79905 -7.82786,2.49393 -10.97221,3.07304 -3.14439,0.5791 -4.3363,0.83756 -8.5197,0.95691 -4.1834,0.11935 -7.15938,-0.35864 -8.95468,-0.91763 -1.7953,-0.55899 -2.64147,-1.55556 -2.60415,-2.17667 3.90737,-1.58574 7.9469,-3.2841 11.38348,-5.04009 z'
|
||||||
|
|
||||||
|
export default function DoveMark(props: SVGProps<SVGSVGElement>) {
|
||||||
|
return (
|
||||||
|
<svg viewBox="0 0 72.867699 48.568241" aria-hidden="true" focusable="false" {...props}>
|
||||||
|
<g transform="translate(-70.490069,-117.83965)">
|
||||||
|
<g transform="matrix(0.71532587,0,0,0.71532587,-173.91758,237.73112)">
|
||||||
|
<path d={PATH} fill="currentColor" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -4,7 +4,8 @@
|
||||||
The top of the front page, in whichever mode the admin set:
|
The top of the front page, in whichever mode the admin set:
|
||||||
|
|
||||||
brand drifting colour and slow concentric rings — many
|
brand drifting colour and slow concentric rings — many
|
||||||
circles, one centre — behind the words
|
circles, one centre — behind the words, with the
|
||||||
|
dove at that centre
|
||||||
photos the hero photos, crossfading with a slow zoom, a
|
photos the hero photos, crossfading with a slow zoom, a
|
||||||
progress bar per photo and a pause button (anything
|
progress bar per photo and a pause button (anything
|
||||||
that moves on its own for more than five seconds
|
that moves on its own for more than five seconds
|
||||||
|
|
@ -24,6 +25,7 @@
|
||||||
import { useEffect, useState, type CSSProperties } from 'react'
|
import { useEffect, useState, type CSSProperties } from 'react'
|
||||||
|
|
||||||
import HomeLink from './HomeLink.tsx'
|
import HomeLink from './HomeLink.tsx'
|
||||||
|
import DoveMark from '../../../components/DoveMark.tsx'
|
||||||
import { livestreamEmbedUrl } from '../../../lib/embeds.ts'
|
import { livestreamEmbedUrl } from '../../../lib/embeds.ts'
|
||||||
import { heroPhoto } from '../../../lib/media.ts'
|
import { heroPhoto } from '../../../lib/media.ts'
|
||||||
import type { Hero, HeroSlide } from '../../../lib/useFrontPage.ts'
|
import type { Hero, HeroSlide } from '../../../lib/useFrontPage.ts'
|
||||||
|
|
@ -157,19 +159,38 @@ function BrandBackdrop() {
|
||||||
<div className="hp-aurora hp-aurora--c" style={blob('#d8b64a', '30vw', '70%', '-5%')} />
|
<div className="hp-aurora hp-aurora--c" style={blob('#d8b64a', '30vw', '70%', '-5%')} />
|
||||||
|
|
||||||
<svg
|
<svg
|
||||||
className="absolute -right-[20vw] top-1/2 h-[120vw] w-[120vw] -translate-y-1/2 opacity-[0.16] md:-right-[10vw] md:h-[80vw] md:w-[80vw]"
|
className="absolute -right-[20vw] top-1/2 h-[120vw] w-[120vw] -translate-y-1/2 md:-right-[10vw] md:h-[80vw] md:w-[80vw]"
|
||||||
viewBox="0 0 400 400"
|
viewBox="0 0 400 400"
|
||||||
>
|
>
|
||||||
<g className="hp-rings" fill="none" stroke="#ffffff">
|
<defs>
|
||||||
{[40, 70, 100, 130, 160, 190].map((r, i) => (
|
<radialGradient id="hp-dove-glow">
|
||||||
<circle key={r} cx="200" cy="200" r={r} strokeWidth={i % 2 ? 0.6 : 1.2} strokeDasharray={i % 2 ? '2 6' : undefined} />
|
<stop offset="0%" stopColor="#9fe7d0" stopOpacity="0.35" />
|
||||||
))}
|
<stop offset="100%" stopColor="#9fe7d0" stopOpacity="0" />
|
||||||
<circle cx="390" cy="200" r="4" fill="#9fe7d0" stroke="none" />
|
</radialGradient>
|
||||||
<circle cx="200" cy="40" r="3" fill="#5ce7ff" stroke="none" />
|
</defs>
|
||||||
|
|
||||||
|
{/* The rings are faint; the dove at their centre is not, so
|
||||||
|
the opacity sits on the rings rather than the whole SVG. */}
|
||||||
|
<g opacity="0.16">
|
||||||
|
<g className="hp-rings" fill="none" stroke="#ffffff">
|
||||||
|
{[40, 70, 100, 130, 160, 190].map((r, i) => (
|
||||||
|
<circle key={r} cx="200" cy="200" r={r} strokeWidth={i % 2 ? 0.6 : 1.2} strokeDasharray={i % 2 ? '2 6' : undefined} />
|
||||||
|
))}
|
||||||
|
<circle cx="390" cy="200" r="4" fill="#9fe7d0" stroke="none" />
|
||||||
|
<circle cx="200" cy="40" r="3" fill="#5ce7ff" stroke="none" />
|
||||||
|
</g>
|
||||||
|
<g className="hp-rings hp-rings--reverse" fill="none" stroke="#9fe7d0">
|
||||||
|
<circle cx="200" cy="200" r="115" strokeWidth="0.8" strokeDasharray="1 10" />
|
||||||
|
<circle cx="85" cy="200" r="3.5" fill="#ffffff" stroke="none" />
|
||||||
|
</g>
|
||||||
</g>
|
</g>
|
||||||
<g className="hp-rings hp-rings--reverse" fill="none" stroke="#9fe7d0">
|
|
||||||
<circle cx="200" cy="200" r="115" strokeWidth="0.8" strokeDasharray="1 10" />
|
{/* Outside the rotating groups, so it stays upright while the
|
||||||
<circle cx="85" cy="200" r="3.5" fill="#ffffff" stroke="none" />
|
rings turn around it. 64 × 42.7 at the centre fits inside
|
||||||
|
the innermost ring (r 40) with room to float. */}
|
||||||
|
<circle cx="200" cy="200" r="46" fill="url(#hp-dove-glow)" />
|
||||||
|
<g className="hp-dove" style={{ color: '#ffffff' }} opacity="0.9">
|
||||||
|
<DoveMark x="168" y="178.65" width="64" height="42.7" />
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,18 @@
|
||||||
to { transform: rotate(360deg); }
|
to { transform: rotate(360deg); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The dove at the rings' centre bobs gently rather than turning. */
|
||||||
|
.hp-dove {
|
||||||
|
animation: hp-bob 6s ease-in-out infinite;
|
||||||
|
transform-box: fill-box;
|
||||||
|
transform-origin: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes hp-bob {
|
||||||
|
0%, 100% { transform: translateY(0); }
|
||||||
|
50% { transform: translateY(-4px); }
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Hero: headline words rise in ────────────────────────────── */
|
/* ── Hero: headline words rise in ────────────────────────────── */
|
||||||
|
|
||||||
.hp-rise {
|
.hp-rise {
|
||||||
|
|
@ -137,6 +149,7 @@
|
||||||
@media (prefers-reduced-motion: reduce) {
|
@media (prefers-reduced-motion: reduce) {
|
||||||
.hp-aurora,
|
.hp-aurora,
|
||||||
.hp-rings,
|
.hp-rings,
|
||||||
|
.hp-dove,
|
||||||
.hp-slide--on img,
|
.hp-slide--on img,
|
||||||
.hp-live-dot {
|
.hp-live-dot {
|
||||||
animation: none;
|
animation: none;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue