Skip to content

new conf design — footer #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
164 changes: 164 additions & 0 deletions src/app/conf/2025/components/footer/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import NextLink from "next/link"
import { ReactNode } from "react"
import { clsx } from "clsx"

import { SocialIcons } from "../../../_components/social-icons"

import blurBean from "./blur-bean.webp"

interface FooterLink {
href: string
children: ReactNode
disabled?: boolean
}

export function Footer({
links,
logo,
}: {
links: (FooterLink | FooterLink[])[]
logo: ReactNode
}) {
return (
<footer className="gql-all-anchors-focusable relative !bg-neu-100 text-neu-900 typography-menu dark:!bg-neu-0 max-md:px-0 max-md:pt-0">
<Stripes />
<div className="flex flex-wrap justify-between gap-4 px-6 py-4 max-md:w-full lg:py-10">
{logo}
<div className="flex gap-x-4 gap-y-2 typography-body-lg">
<p className="flex items-center gap-2">
<time dateTime="2025-09-08">September 08</time>
<span>-</span>
<time dateTime="2025-09-10">10, 2025</time>
</p>
<address className="not-italic">Amsterdam, Netherlands</address>
</div>
</div>
<ul className="grid grid-cols-2 gap-px bg-neu-400 py-px dark:bg-neu-100 lg:grid-cols-4">
{links.map((box, i) => (
<li className="bg-neu-100 dark:bg-neu-0 lg:h-32" key={i}>
<FooterBox box={box} />
</li>
))}
</ul>
<div className="relative flex justify-between gap-10 px-6 py-4 text-sm max-lg:flex-col">
<div className="flex flex-col font-light max-md:gap-5">
<p>
Copyright © {new Date().getFullYear()} The GraphQL Foundation. All
rights reserved.
</p>
<p>
For web site terms of use, trademark policy and general project
policies please see{" "}
<a
href="https://lfprojects.org"
target="_blank"
rel="noreferrer"
className="typography-link"
>
https://lfprojects.org
</a>
.
</p>
</div>
<SocialIcons className="[&>a:focus]:text-current [&>a:focus]:ring-transparent [&>a:hover]:bg-neu-900/10 [&>a:hover]:text-current" />
</div>
</footer>
)
}

const maskEven =
"repeating-linear-gradient(to right, transparent, transparent 12px, black 12px, black 24px)"
const maskOdd =
"repeating-linear-gradient(to right, black, black 12px, transparent 12px, transparent 24px)"

function Stripes() {
return (
<div
role="presentation"
// prettier-ignore
// false positive
// eslint-disable-next-line tailwindcss/no-contradicting-classname
className="pointer-events-none absolute inset-0
[--start-1:rgba(255,204,239,.05)]
[--end-1:hsl(var(--color-pri-base)/.8)]
dark:[--start-1:hsl(var(--color-pri-darker))]
dark:[--end-1:hsl(var(--color-pri-base)/.9)]

[--start-2:transparent]
[--end-2:hsl(var(--color-pri-base)/.6)]
dark:[--start-2:rgba(255,204,239,.1)]
dark:[--end-2:hsl(var(--color-pri-base)/.8)]

mix-blend-darken
dark:mix-blend-lighten
"
style={{
maskImage: `url(${blurBean.src})`,
WebkitMaskImage: `url(${blurBean.src})`,
maskPosition: "center 260px",
WebkitMaskPosition: "center 260px",
maskSize: "200% 100%",
WebkitMaskSize: "200% 100%",
maskRepeat: "no-repeat",
WebkitMaskRepeat: "no-repeat",
maskOrigin: "top",
}}
>
<div
className="absolute inset-0 bg-[linear-gradient(180deg,var(--start-1)_0%,var(--end-1)_200%)]"
style={{
maskImage: maskEven,
WebkitMaskImage: maskEven,
}}
/>
<div
className="absolute inset-0 bg-[linear-gradient(180deg,var(--start-2)_0%,var(--end-2)_200%)]"
style={{
maskImage: maskOdd,
WebkitMaskImage: maskOdd,
}}
/>
</div>
)
}

function FooterBox({ box }: { box: FooterLink | FooterLink[] }) {
if (Array.isArray(box)) {
return (
<div className="relative flex flex-col p-3">
{box.map(link => (
<NextLink
key={link.href}
href={link.href}
title={link.disabled ? "Coming soon" : undefined}
className={clsx(
"gql-focus-visible block h-full p-3 first:font-bold",
link.disabled
? "pointer-events-none"
: "underline-offset-4 hover:underline",
)}
tabIndex={link.disabled ? -1 : undefined}
>
{link.children}
</NextLink>
))}
</div>
)
}

const { href, children, disabled } = box

return (
<NextLink
href={href}
title={disabled ? "Coming soon" : undefined}
className={clsx(
"gql-focus-visible relative block h-full p-6",
disabled ? "pointer-events-none" : "underline-offset-4 hover:underline",
)}
tabIndex={disabled ? -1 : undefined}
>
{children}
</NextLink>
)
}
52 changes: 52 additions & 0 deletions src/app/conf/2025/components/graphql-conf-logo-link.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import NextLink from "next/link"
import { clsx } from "clsx"

export interface GraphQLConfLogoLinkProps
extends React.HTMLAttributes<HTMLDivElement> {
year: number
}

export function GraphQLConfLogoLink({
className,
year,
...rest
}: GraphQLConfLogoLinkProps) {
return (
<div
className={clsx(
"flex items-center gap-2 text-xl/none uppercase",
className,
)}
{...rest}
>
<NextLink href="/" className="-m-1 p-1 hover:bg-neu-900/10">
<GraphQLLogo className="h-6" />
</NextLink>
<span>/</span>
<NextLink
href={`/conf/${year}`}
className="-m-2 p-2 underline-offset-4 hover:underline"
>
GraphQLConf {year}
</NextLink>
</div>
)
}

function GraphQLLogo(props: React.SVGProps<SVGSVGElement>) {
return (
<svg viewBox="0 0 100 100" fill="currentColor" {...props}>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M50 6.90308L87.323 28.4515V71.5484L50 93.0968L12.677 71.5484V28.4515L50 6.90308ZM16.8647 30.8693V62.5251L44.2795 15.0414L16.8647 30.8693ZM50 13.5086L18.3975 68.2457H81.6025L50 13.5086ZM77.4148 72.4334H22.5852L50 88.2613L77.4148 72.4334ZM83.1353 62.5251L55.7205 15.0414L83.1353 30.8693V62.5251Z"
/>
<circle cx="50" cy="9.3209" r="8.82" />
<circle cx="85.2292" cy="29.6605" r="8.82" />
<circle cx="85.2292" cy="70.3396" r="8.82" />
<circle cx="50" cy="90.6791" r="8.82" />
<circle cx="14.7659" cy="70.3396" r="8.82" />
<circle cx="14.7659" cy="29.6605" r="8.82" />
</svg>
)
}
32 changes: 2 additions & 30 deletions src/app/conf/2025/components/navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Badge } from "../../_components/badge"

import MenuIcon from "../pixelarticons/menu.svg?svgr"
import CloseIcon from "../pixelarticons/close.svg?svgr"
import { GraphQLConfLogoLink } from "./graphql-conf-logo-link"

export interface NavbarProps {
links: { href: string; children: React.ReactNode; "aria-disabled"?: true }[]
Expand Down Expand Up @@ -49,18 +50,7 @@ export function Navbar({ links, year }: NavbarProps): ReactElement {
>
<BackdropBlur />
<div className="flex h-[var(--navbar-h)] items-center justify-between gap-5 px-4 lg:px-10">
<div className="flex items-center gap-2 text-xl/none uppercase">
<NextLink href="/" className="-m-1 p-1 hover:bg-neu-900/10">
<GraphQLLogo className="h-6" />
</NextLink>
<span>/</span>
<NextLink
href={`/conf/${year}`}
className="-m-2 p-2 underline-offset-4 hover:underline"
>
GraphQLConf {year}
</NextLink>
</div>
<GraphQLConfLogoLink year={year} />

<div className="mr-auto flex h-full flex-col justify-center whitespace-pre border-x border-black/60 px-4 typography-menu dark:border-white/80 max-xl:hidden">
<p className="flex items-center gap-2 text-sm">
Expand Down Expand Up @@ -127,24 +117,6 @@ export function Navbar({ links, year }: NavbarProps): ReactElement {
)
}

function GraphQLLogo(props: React.SVGProps<SVGSVGElement>) {
return (
<svg viewBox="0 0 100 100" fill="currentColor" {...props}>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M50 6.90308L87.323 28.4515V71.5484L50 93.0968L12.677 71.5484V28.4515L50 6.90308ZM16.8647 30.8693V62.5251L44.2795 15.0414L16.8647 30.8693ZM50 13.5086L18.3975 68.2457H81.6025L50 13.5086ZM77.4148 72.4334H22.5852L50 88.2613L77.4148 72.4334ZM83.1353 62.5251L55.7205 15.0414L83.1353 30.8693V62.5251Z"
/>
<circle cx="50" cy="9.3209" r="8.82" />
<circle cx="85.2292" cy="29.6605" r="8.82" />
<circle cx="85.2292" cy="70.3396" r="8.82" />
<circle cx="50" cy="90.6791" r="8.82" />
<circle cx="14.7659" cy="70.3396" r="8.82" />
<circle cx="14.7659" cy="29.6605" r="8.82" />
</svg>
)
}

function BackdropBlur() {
const mask = "linear-gradient(to bottom,#000 0% 50%, transparent 50% 100%)"
return (
Expand Down
35 changes: 12 additions & 23 deletions src/app/conf/2025/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { ReactElement, ReactNode } from "react"
import { Metadata } from "next"
import { Footer } from "../_components/footer"
import { GraphQLConf, HostedByGraphQLFoundation } from "@/icons"
import NextLink from "next/link"

import { NewFontsStyleTag } from "../../fonts"
import "../../colors.css"

import { Navbar } from "./components/navbar"
import { Footer } from "./components/footer"

// @ts-expect-error: we want to import the same version as Nextra for the main page
import { ThemeProvider } from "next-themes"
import { GraphQLConfLogoLink } from "./components/graphql-conf-logo-link"

export const metadata = {
description:
Expand Down Expand Up @@ -51,28 +52,16 @@ export default function Layout({
<div className="bg-neu-0 text-neu-900 antialiased">{children}</div>
</ThemeProvider>
<Footer
logo={
<NextLink href="/conf/2025" className="nextra-logo text-white">
<div className="flex items-center gap-2">
<GraphQLConf className="h-6" />
<span className="select-none text-xl/none">2025</span>
</div>
<HostedByGraphQLFoundation className="mt-2 h-5" />
</NextLink>
}
logo={<GraphQLConfLogoLink year={2025} />}
links={[
{ children: "Sponsor", href: "/conf/2025/#sponsors" },
{ children: "Speakers", href: "/#speakers" },
{ children: "GraphQLConf 2024", href: "/conf/2024" },
{ children: "FAQ", href: "#faq" },
{ children: "Contact Us", href: "/conf/2025/faq/#contact" },
{ children: "GraphQL", href: "/" },
{ children: "GraphQL Foundation", href: "/foundation" },
[
{ children: "Sponsor", href: "/conf/2025/#sponsors" },
{ children: "Speakers", href: "/#speakers" },
{ children: "GraphQLConf 2024", href: "/conf/2024" },
],
[
{ children: "FAQ", href: "#faq" },
{ children: "Contact Us", href: "/conf/2025/faq/#contact" },
],
[
{ children: "GraphQL", href: "/" },
{ children: "GraphQL Foundation", href: "/foundation" },
{
children: "Code of Conduct",
href: "/conf/2025/resources/#code-of-conduct",
Expand Down
14 changes: 12 additions & 2 deletions src/app/conf/_components/social-icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,25 @@ import {
YouTubeIcon,
FacebookIcon,
} from "@/icons"
import clsx from "clsx"

const anchorProps = {
target: "_blank",
rel: "noreferrer",
}

export function SocialIcons() {
export function SocialIcons({
className,
...rest
}: React.HTMLAttributes<HTMLDivElement>) {
return (
<div className="flex items-center gap-5 *:outline-none *:transition-colors hover:*:text-primary focus:*:text-primary focus:*:ring focus:*:ring-primary [&_svg]:h-5">
<div
className={clsx(
"flex items-center gap-1 *:p-2 *:outline-none *:transition-colors hover:*:text-primary focus:*:text-primary focus:*:ring focus:*:ring-primary [&_svg]:h-5",
className,
)}
{...rest}
>
<a href="https://github.com/graphql" {...anchorProps}>
<GitHubIcon />
</a>
Expand Down
Loading