From bec00fc9ab8b137f8ea57f80cda331ece0cd80c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luukas=20P=C3=B6rtfors?= Date: Fri, 14 Nov 2025 14:08:55 +0100 Subject: [PATCH] feat: make system seven theme CMS toggleable --- apps/web/src/app/[locale]/(main)/layout.tsx | 14 +- apps/web/src/app/[locale]/(main)/page.tsx | 19 +- .../[locale]/(main)/system-seven/glitch.css | 226 ++++++------- .../(main)/system-seven/system-seven.css | 304 +++++++++--------- .../src/components/events-display/index.tsx | 9 +- apps/web/src/components/hero/index.tsx | 24 +- apps/web/src/components/main-nav/index.tsx | 3 +- .../web/src/components/main-nav/logo-link.tsx | 46 ++- apps/web/src/components/mobile-nav/index.tsx | 3 +- .../src/components/mobile-nav/logo-link.tsx | 37 ++- .../src/components/partner-logos/index.tsx | 6 +- apps/web/src/custom-pages/events-page.tsx | 6 +- apps/web/src/globals/main-navigation.ts | 6 + 13 files changed, 390 insertions(+), 313 deletions(-) diff --git a/apps/web/src/app/[locale]/(main)/layout.tsx b/apps/web/src/app/[locale]/(main)/layout.tsx index da470f95..40ef78ec 100644 --- a/apps/web/src/app/[locale]/(main)/layout.tsx +++ b/apps/web/src/app/[locale]/(main)/layout.tsx @@ -12,7 +12,7 @@ import "@tietokilta/ui/global.css"; import "../globals.css"; import { getScopedI18n, type Locale } from "@locales/server"; import { DigiCommitteeRecruitmentAlert } from "@components/digi-committee-recruitment-alert"; -// import "./globals.css"; +import { fetchMainNavigation } from "@lib/api/main-navigation"; import "./system-seven/system-seven.css"; import "./system-seven/glitch.css"; @@ -77,9 +77,19 @@ export default async function RootLayout( const { children } = props; + const mainNav = await fetchMainNavigation(locale)({}); + const systemSeven = mainNav?.enableSystemSevenTheme ?? false; + return ( - + diff --git a/apps/web/src/app/[locale]/(main)/page.tsx b/apps/web/src/app/[locale]/(main)/page.tsx index 9d432169..289675bb 100644 --- a/apps/web/src/app/[locale]/(main)/page.tsx +++ b/apps/web/src/app/[locale]/(main)/page.tsx @@ -8,7 +8,8 @@ import { fetchLandingPage } from "@lib/api/landing-page"; import { AnnouncementCard } from "@components/announcement-card"; import { getCurrentLocale } from "@locales/server"; import AprilFoolsAlert from "@components/april-fools/april-fools-alert"; -import { type NonNullableKeys } from "@lib/utils"; +import { type NonNullableKeys, cn } from "@lib/utils"; +import { fetchMainNavigation } from "@lib/api/main-navigation"; function Content({ content }: { content?: EditorState }) { if (!content) return null; @@ -39,6 +40,9 @@ export default async function Home(props: { throw new Error("Unable to fetch landing page data"); } + const mainNav = await fetchMainNavigation(locale)({}); + const systemSeven = mainNav?.enableSystemSevenTheme ?? false; + const body = landingPageData.body as unknown as EditorState | undefined; const announcement = landingPageData.announcement as News | undefined; const eventsListPage = landingPageData.eventsListPage as CMSPage | undefined; @@ -60,12 +64,16 @@ export default async function Home(props: { texts={landingPageData.heroTexts .map(({ text }) => (typeof text === "string" ? text : null)) .filter((url): url is string => Boolean(url))} + systemSeven={systemSeven} /> {/* Desktop view */}

Tietokilta @@ -77,6 +85,7 @@ export default async function Home(props: {

@@ -87,7 +96,10 @@ export default async function Home(props: {

Tietokilta @@ -97,6 +109,7 @@ export default async function Home(props: { diff --git a/apps/web/src/app/[locale]/(main)/system-seven/glitch.css b/apps/web/src/app/[locale]/(main)/system-seven/glitch.css index 5fea5ff9..7d5988ea 100644 --- a/apps/web/src/app/[locale]/(main)/system-seven/glitch.css +++ b/apps/web/src/app/[locale]/(main)/system-seven/glitch.css @@ -1,84 +1,3 @@ -.layers { - position: relative; -} - -.layers::before, -.layers::after { - content: attr(data-text); - position: absolute; - width: 110%; - z-index: -1; -} - -.layers::before { - top: 10px; - left: 15px; - color: #b31b1b; -} - -.layers::after { - top: 5px; - left: -10px; - color: #191ebd; -} - -.single-path { - clip-path: polygon( - 0% 12%, - 53% 12%, - 53% 26%, - 25% 26%, - 25% 86%, - 31% 86%, - 31% 0%, - 53% 0%, - 53% 84%, - 92% 84%, - 92% 82%, - 70% 82%, - 70% 29%, - 78% 29%, - 78% 65%, - 69% 65%, - 69% 66%, - 77% 66%, - 77% 45%, - 85% 45%, - 85% 26%, - 97% 26%, - 97% 28%, - 84% 28%, - 84% 34%, - 54% 34%, - 54% 89%, - 30% 89%, - 30% 58%, - 83% 58%, - 83% 5%, - 68% 5%, - 68% 36%, - 62% 36%, - 62% 1%, - 12% 1%, - 12% 34%, - 60% 34%, - 60% 57%, - 98% 57%, - 98% 83%, - 1% 83%, - 1% 53%, - 91% 53%, - 91% 84%, - 8% 84%, - 8% 83%, - 4% 83% - ); -} - -.paths { - animation: paths 5s step-end infinite; -} - @keyframes paths { 0% { clip-path: polygon( @@ -331,12 +250,6 @@ } } -.movement { - /* Normally this position would be absolute & on the layers, set to relative here so we can see it on the div */ - position: relative; - animation: movement 8s step-end infinite; -} - @keyframes movement { 0% { top: 0px; @@ -364,10 +277,6 @@ } } -.opacity { - animation: opacity 5s step-end infinite; -} - @keyframes opacity { 0% { opacity: 0.1; @@ -403,10 +312,6 @@ } } -.font { - animation: font 7s step-end infinite; -} - @keyframes font { 0% { font-weight: 100; @@ -439,22 +344,119 @@ } } -.glitch span { - animation: paths 5s step-end infinite; -} +.system-seven-theme { + .layers { + position: relative; + } -.glitch::before { - animation: - paths 5s step-end infinite, - opacity 5s step-end infinite, - font 8s step-end infinite, - movement 10s step-end infinite; -} + .layers::before, + .layers::after { + content: attr(data-text); + position: absolute; + width: 110%; + z-index: -1; + } -.glitch::after { - animation: - paths 5s step-end infinite, - opacity 5s step-end infinite, - font 7s step-end infinite, - movement 8s step-end infinite; -} + .layers::before { + top: 10px; + left: 15px; + color: #b31b1b; + } + + .layers::after { + top: 5px; + left: -10px; + color: #191ebd; + } + + .single-path { + clip-path: polygon( + 0% 12%, + 53% 12%, + 53% 26%, + 25% 26%, + 25% 86%, + 31% 86%, + 31% 0%, + 53% 0%, + 53% 84%, + 92% 84%, + 92% 82%, + 70% 82%, + 70% 29%, + 78% 29%, + 78% 65%, + 69% 65%, + 69% 66%, + 77% 66%, + 77% 45%, + 85% 45%, + 85% 26%, + 97% 26%, + 97% 28%, + 84% 28%, + 84% 34%, + 54% 34%, + 54% 89%, + 30% 89%, + 30% 58%, + 83% 58%, + 83% 5%, + 68% 5%, + 68% 36%, + 62% 36%, + 62% 1%, + 12% 1%, + 12% 34%, + 60% 34%, + 60% 57%, + 98% 57%, + 98% 83%, + 1% 83%, + 1% 53%, + 91% 53%, + 91% 84%, + 8% 84%, + 8% 83%, + 4% 83% + ); + } + + .paths { + animation: paths 5s step-end infinite; + } + + .movement { + /* Normally this position would be absolute & on the layers, set to relative here so we can see it on the div */ + position: relative; + animation: movement 8s step-end infinite; + } + + .opacity { + animation: opacity 5s step-end infinite; + } + + .font { + animation: font 7s step-end infinite; + } + + .glitch span { + animation: paths 5s step-end infinite; + } + + .glitch::before { + animation: + paths 5s step-end infinite, + opacity 5s step-end infinite, + font 8s step-end infinite, + movement 10s step-end infinite; + } + + .glitch::after { + animation: + paths 5s step-end infinite, + opacity 5s step-end infinite, + font 7s step-end infinite, + movement 8s step-end infinite; + } +} \ No newline at end of file diff --git a/apps/web/src/app/[locale]/(main)/system-seven/system-seven.css b/apps/web/src/app/[locale]/(main)/system-seven/system-seven.css index b2089c2b..a1c43cab 100644 --- a/apps/web/src/app/[locale]/(main)/system-seven/system-seven.css +++ b/apps/web/src/app/[locale]/(main)/system-seven/system-seven.css @@ -1,146 +1,3 @@ -.wrapper { - height: 70vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; -} - -.header { - font-size: 1.5rem; - color: #dc2626; - text-shadow: 0 0 1rem #dc2626; - text-align: center; - - @media (min-width: 640px) { - font-size: 3rem; - } - - @media (min-width: 1024px) { - font-size: 4rem; - } -} - -.time { - margin: 0rem; - font-size: 3rem; - color: #dc2626; - text-shadow: 0 0 1rem #dc2626; - - @media (min-width: 640px) { - font-size: 6rem; - } - - @media (min-width: 1024px) { - font-size: 8rem; - } -} - -.header-container { - display: flex; - padding: 2rem; - width: 40rem; - max-width: 100vw; - flex-direction: column; - align-items: center; -} - -.text-container { - display: flex; - padding: 2rem; - width: 60rem; - max-width: calc(100vw - 2rem); - flex-direction: column; - align-items: center; - margin-left: auto; - margin-right: auto; - text-align: center; -} - -.video-container { - padding-top: 10rem; - padding-bottom: 10rem; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; -} - -.video { - max-width: calc(100vw - 4rem); - box-shadow: 0 0 2rem 0.5rem #dc2626; -} - -a, -svg, -h1, -h2, -p, -li, -span { - color: #dc2626; -} - -img { - /* Filter that turns white to red */ - filter: invert(8%) sepia(96%) saturate(5343%) hue-rotate(354deg) - brightness(108%) contrast(103%) !important; -} - -/* Do NOT hue-shift partner logos */ -.partner-logos img { - filter: none !important; -} - -/* But keep footer partner logos white on dark background */ -footer .partner-logos img { - filter: grayscale(1) invert(1) !important; -} - -img[alt~="Tietokilta"] { - /* For some reason the above filter doesn't work on this image */ - filter: invert(92%) sepia(96%) saturate(5343%) hue-rotate(354deg) - brightness(108%) contrast(103%) !important; -} - -img[alt~="SystemSeven"] { - filter: none !important; -} - -section { - :hover { - p, - h1, - h2, - span, - a { - animation: skew-x-shakeng 4s infinite; - animation-delay: 1s; - animation-timing-function: steps(1, end); - } - } -} - -a:hover { - opacity: 0.9; - text-shadow: - 0px -4px #ec2225, - 0px 4px #00c2cb, - -4px 0px #ec2225, - 4px 0px #00c2cb; - animation: glitch 12ms ease-in-out infinite; - z-index: 1; -} - -a::before { - content: attr(data-text); - position: absolute; - top: 0; - left: 0; - color: #e0ffff; - z-index: -1; -} - @keyframes glitch { 0%, 100% { @@ -238,20 +95,165 @@ a::before { } } -section { - opacity: 1; +.system-seven-theme { + .wrapper { + height: 70vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + } - :hover { - opacity: 0; - transition: opacity 5s; - transition-delay: 5s; + .header { + font-size: 1.5rem; + color: #dc2626; + text-shadow: 0 0 1rem #dc2626; + text-align: center; + + @media (min-width: 640px) { + font-size: 3rem; + } + + @media (min-width: 1024px) { + font-size: 4rem; + } + } + + .time { + margin: 0rem; + font-size: 3rem; + color: #dc2626; + text-shadow: 0 0 1rem #dc2626; + + @media (min-width: 640px) { + font-size: 6rem; + } + + @media (min-width: 1024px) { + font-size: 8rem; + } + } + + .header-container { + display: flex; + padding: 2rem; + width: 40rem; + max-width: 100vw; + flex-direction: column; + align-items: center; + } + + .text-container { + display: flex; + padding: 2rem; + width: 60rem; + max-width: calc(100vw - 2rem); + flex-direction: column; + align-items: center; + margin-left: auto; + margin-right: auto; + text-align: center; + } + + .video-container { + padding-top: 10rem; + padding-bottom: 10rem; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + } + + .video { + max-width: calc(100vw - 4rem); + box-shadow: 0 0 2rem 0.5rem #dc2626; + } + + a, + svg, + h1, + h2, + p, + li, + span { + color: #dc2626; + } + + img { + /* Filter that turns white to red */ + filter: invert(8%) sepia(96%) saturate(5343%) hue-rotate(354deg) + brightness(108%) contrast(103%) !important; + } + + /* Do NOT hue-shift partner logos */ + .partner-logos img { + filter: none !important; + } + + /* But keep footer partner logos white on dark background */ + footer .partner-logos img { + filter: grayscale(1) invert(1) !important; + } + + img[alt~="Tietokilta"] { + /* For some reason the above filter doesn't work on this image */ + filter: invert(92%) sepia(96%) saturate(5343%) hue-rotate(354deg) + brightness(108%) contrast(103%) !important; + } + + img[alt~="SystemSeven"] { + filter: none !important; + } + + section { + :hover { + p, + h1, + h2, + span, + a { + animation: skew-x-shakeng 4s infinite; + animation-delay: 1s; + animation-timing-function: steps(1, end); + } + } + } + + a:hover { + opacity: 0.9; + text-shadow: + 0px -4px #ec2225, + 0px 4px #00c2cb, + -4px 0px #ec2225, + 4px 0px #00c2cb; + animation: glitch 12ms ease-in-out infinite; + z-index: 1; + } + + a::before { + content: attr(data-text); + position: absolute; + top: 0; + left: 0; + color: #e0ffff; + z-index: -1; + } + + section { + opacity: 1; + + :hover { + opacity: 0; + transition: opacity 5s; + transition-delay: 5s; + } } -} -/* This makes the site completely unusable + /* This makes the site completely unusable section { :hover { display: none; } } */ +} \ No newline at end of file diff --git a/apps/web/src/components/events-display/index.tsx b/apps/web/src/components/events-display/index.tsx index cd4af54f..219f9d77 100644 --- a/apps/web/src/components/events-display/index.tsx +++ b/apps/web/src/components/events-display/index.tsx @@ -14,7 +14,7 @@ import { } from "../pagination"; import { fetchUpcomingEvents } from "../../lib/api/external/ilmomasiina"; import { getCurrentLocale, getI18n } from "../../locales/server"; -import { formatDateTime, formatDateTimeOptions } from "../../lib/utils"; +import { formatDateTime, formatDateTimeOptions, cn } from "../../lib/utils"; import { DateTime } from "../datetime"; function EventListSkeleton() { @@ -166,9 +166,11 @@ async function EventList({ currentPage = 1 }: { currentPage?: number }) { export async function EventsDisplay({ eventsListPath, currentPage, + systemSeven, }: { eventsListPath?: string; currentPage?: number; + systemSeven?: boolean; }) { const locale = await getCurrentLocale(); const t = await getI18n(); @@ -179,7 +181,10 @@ export async function EventsDisplay({ href={eventsListPath ?? `/${locale}/${t("ilmomasiina.path.events")}`} >

{t("heading.Upcoming events")} diff --git a/apps/web/src/components/hero/index.tsx b/apps/web/src/components/hero/index.tsx index 1ede7f96..3519556b 100644 --- a/apps/web/src/components/hero/index.tsx +++ b/apps/web/src/components/hero/index.tsx @@ -66,24 +66,28 @@ function ImageWithCitation({ export function Hero({ images, texts, + systemSeven, }: { images: ImageWithPhotographer[]; texts: string[]; + systemSeven?: boolean; }) { const [currentImageIndex, setCurrentImageIndex] = useState( new Date().getUTCDate() % images.length, ); - // eslint-disable-next-line no-param-reassign -- Syse code go brr - texts = [ - "The destruction is near", - "Join System Seven today!", - "Maximize your potential", - "Productivity is the key to success", - "Stop the slack", - "Work hard, play hard", - "Down with the guild!", - ]; + if (systemSeven) { + // eslint-disable-next-line no-param-reassign -- Syse code go brr + texts = [ + "The destruction is near", + "Join System Seven today!", + "Maximize your potential", + "Productivity is the key to success", + "Stop the slack", + "Work hard, play hard", + "Down with the guild!", + ]; + } const [currentText, setCurrentText] = useState(texts[0]); // eslint-disable-next-line react/hook-use-state -- prev index used directly in the setter diff --git a/apps/web/src/components/main-nav/index.tsx b/apps/web/src/components/main-nav/index.tsx index d42e53be..a5ae3831 100644 --- a/apps/web/src/components/main-nav/index.tsx +++ b/apps/web/src/components/main-nav/index.tsx @@ -21,6 +21,7 @@ export async function MainNav({ const rightLinks = links.slice(middleIndex); const logo = mainNav.logo as Media; + const systemSeven = mainNav.enableSystemSevenTheme ?? false; return ( - + diff --git a/apps/web/src/components/main-nav/logo-link.tsx b/apps/web/src/components/main-nav/logo-link.tsx index 74b6ff66..65f6fa7b 100644 --- a/apps/web/src/components/main-nav/logo-link.tsx +++ b/apps/web/src/components/main-nav/logo-link.tsx @@ -6,20 +6,47 @@ import Image from "next/image"; import { usePathname } from "next/navigation"; import type { Media } from "@payload-types"; import { useCurrentLocale } from "../../locales/client"; -// import TiKLogo from "../../assets/TiK-logo-white.png"; +import TiKLogo from "../../assets/TiK-logo-white.png"; import SyseLogo from "../../assets/syse/syse.png"; -export function LogoLink({ image }: { image: Media | undefined }) { +export function LogoLink({ + image, + systemSeven, +}: { + image: Media | undefined; + systemSeven?: boolean; +}) { const locale = useCurrentLocale(); - const href = `/${locale}`; const pathname = usePathname(); - const isActive = pathname === href; + const isActive = pathname === `/${locale}`; + const href = `/${locale}`; + + if (systemSeven) { + return ( + + + + SystemSeven + + + + ); + } return ( - {/* Tietokilta - */} - SystemSeven diff --git a/apps/web/src/components/mobile-nav/index.tsx b/apps/web/src/components/mobile-nav/index.tsx index 73c1030d..488c145c 100644 --- a/apps/web/src/components/mobile-nav/index.tsx +++ b/apps/web/src/components/mobile-nav/index.tsx @@ -45,6 +45,7 @@ export async function MobileNav({ block.blockType === "partners-row", ); const navLogo = mainNav.logo as Media; + const systemSeven = mainNav.enableSystemSevenTheme ?? false; return (
- + Tietokilta diff --git a/apps/web/src/components/mobile-nav/logo-link.tsx b/apps/web/src/components/mobile-nav/logo-link.tsx index 80d29f33..cbb7fea7 100644 --- a/apps/web/src/components/mobile-nav/logo-link.tsx +++ b/apps/web/src/components/mobile-nav/logo-link.tsx @@ -4,19 +4,40 @@ import { usePathname } from "next/navigation"; import Link from "next/link"; import Image from "next/image"; import type { Media } from "@payload-types"; -// import TiKLogo from "../../assets/TiK-logo-white.png"; +import TiKLogo from "../../assets/TiK-logo-white.png"; import SyseLogo from "../../assets/syse/syse.png"; export function LogoLink({ locale, image, + systemSeven, }: { locale: string; image: Media | undefined; + systemSeven?: boolean; }) { - const href = `/${locale}`; const pathname = usePathname(); - const isActive = pathname === href; + const isActive = pathname === `/${locale}`; + const href = `/${locale}`; + + if (systemSeven) { + return ( + + SystemSeven + + ); + } return ( - {/* Tietokilta - */} - SystemSeven ); } diff --git a/apps/web/src/components/partner-logos/index.tsx b/apps/web/src/components/partner-logos/index.tsx index dc814d23..786dac84 100644 --- a/apps/web/src/components/partner-logos/index.tsx +++ b/apps/web/src/components/partner-logos/index.tsx @@ -31,7 +31,7 @@ export async function PartnerLogos({ if (type === "row" || type === "infoscreen") { return ( -
    +
      {logos.map((logo) => (
    • +
        {logos.map((logo) => (
      • @@ -76,7 +76,7 @@ export async function PartnerLogos({ } return ( -
        +
        ); diff --git a/apps/web/src/custom-pages/events-page.tsx b/apps/web/src/custom-pages/events-page.tsx index 9c0a785f..52180f07 100644 --- a/apps/web/src/custom-pages/events-page.tsx +++ b/apps/web/src/custom-pages/events-page.tsx @@ -10,6 +10,8 @@ import { getCurrentLocale, getScopedI18n } from "../locales/server"; import { CalendarSubButton } from "../components/calendar-sub-button"; import EventCard from "../components/event-card"; import EventCalendar from "./event-calendar"; +import { fetchMainNavigation } from "../lib/api/main-navigation"; +import { cn } from "../lib/utils"; async function Calendar({ events }: { events: UserEventListResponse }) { const t = await getScopedI18n("ilmomasiina"); @@ -36,6 +38,8 @@ export default async function Page() { const locale = await getCurrentLocale(); const events = await fetchEvents(locale); const upcomingEvents = await fetchUpcomingEvents(locale); + const mainNav = await fetchMainNavigation(locale)({}); + const systemSeven = mainNav?.enableSystemSevenTheme ?? false; if (!events.ok || !upcomingEvents.ok) { // eslint-disable-next-line no-console -- nice to know @@ -52,7 +56,7 @@ export default async function Page() {
        {ta("Back")}

        {t("Tapahtumat")} diff --git a/apps/web/src/globals/main-navigation.ts b/apps/web/src/globals/main-navigation.ts index eac4a2d5..fad63f81 100644 --- a/apps/web/src/globals/main-navigation.ts +++ b/apps/web/src/globals/main-navigation.ts @@ -46,6 +46,12 @@ export const MainNavigation: GlobalConfig = { required: true, filterOptions: filterLogos, }, + { + name: "enableSystemSevenTheme", + type: "checkbox", + label: "Enable System Seven Theme", + defaultValue: false, + }, { name: "items", type: "array",