Use typed links to detect broken links (#2750)

- Fixes firezone/gtm#220
- Add @jefferenced and @ReactorScram to team page and simplify it

@conectado Interesting use of strong typing to enforce no broken links
in NextJS
This commit is contained in:
Jamil
2023-11-30 15:54:41 -08:00
committed by GitHub
parent 04d4371b93
commit e3e2baf87d
10 changed files with 98 additions and 82 deletions

View File

@@ -31,6 +31,9 @@ const highlightLanguages = {
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
typedRoutes: true,
},
// Proxy GitHub requests to avoid CORS issues
async rewrites() {
return [

View File

@@ -319,7 +319,7 @@ export default function Page() {
</div>
</div>
<div className="mx-auto gap-8 max-w-screen-xl grid justify-items-center sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-6 px-16 pt-8">
<Link href="/docs/authenticate/oidc/keycloak/">
<Link href="/docs/authenticate/oidc/keycloak">
<Image
width={150}
height={75}
@@ -327,7 +327,7 @@ export default function Page() {
src="/images/keycloak-logo.png"
/>
</Link>
<Link href="/docs/authenticate/oidc/google/">
<Link href="/docs/authenticate/oidc/google">
<Image
width={150}
height={75}
@@ -335,7 +335,7 @@ export default function Page() {
src="/images/google-logo.png"
/>
</Link>
<Link href="/docs/authenticate/oidc/okta/">
<Link href="/docs/authenticate/oidc/okta">
<Image
width={150}
height={75}
@@ -343,7 +343,7 @@ export default function Page() {
src="/images/okta-logo.png"
/>
</Link>
<Link href="/docs/authenticate/oidc/onelogin/">
<Link href="/docs/authenticate/oidc/onelogin">
<Image
width={150}
height={75}
@@ -351,7 +351,7 @@ export default function Page() {
src="/images/onelogin-logo.png"
/>
</Link>
<Link href="/docs/authenticate/oidc/azuread/">
<Link href="/docs/authenticate/oidc/azuread">
<Image
width={150}
height={75}
@@ -359,7 +359,7 @@ export default function Page() {
src="/images/azure-logo.png"
/>
</Link>
<Link href="/docs/authenticate/saml/jumpcloud/">
<Link href="/docs/authenticate/saml/jumpcloud">
<Image
width={150}
height={75}

View File

@@ -14,9 +14,9 @@ function renderTeamMember({
name: string;
title: string;
imgSrc: string;
twitterUrl?: string;
githubUrl?: string;
linkedinUrl?: string;
twitterUrl?: URL;
githubUrl?: URL;
linkedinUrl?: URL;
}) {
return (
<div className="text-center">
@@ -31,7 +31,7 @@ function renderTeamMember({
<h3 className="justify-center text-xl font-bold tracking-tight text-neutral-900 ">
{name}
</h3>
<span className="text-neutral-800 ">{title}</span>
<span className="text-neutral-800 text-sm">{title}</span>
<ul className="flex justify-center space-x-4 mt-4">
{twitterUrl && (
<li>
@@ -55,61 +55,73 @@ function renderTeamMember({
}
export default function Page() {
const coreTeam = [
const team = [
{
name: "Jamil Bou Kheir",
title: "CEO/Founder",
imgSrc: gravatar("jamil@firezone.dev", 200),
twitterUrl: "https://twitter.com/jamilbk",
githubUrl: "https://github.com/jamilbk",
linkedinUrl: "https://linkedin.com/in/jamilbk",
twitterUrl: new URL("https://twitter.com/jamilbk"),
githubUrl: new URL("https://github.com/jamilbk"),
linkedinUrl: new URL("https://linkedin.com/in/jamilbk"),
},
{
name: "Gabriel Steinberg",
title: "Senior Backend Engineer",
imgSrc: "/images/avatars/gabriel.png",
twitterUrl: "https://twitter.com/tapingmemory",
githubUrl: "https://github.com/conectado",
twitterUrl: new URL("https://twitter.com/tapingmemory"),
githubUrl: new URL("https://github.com/conectado"),
},
{
name: "Andrew Dryga",
title: "Founding Engineer",
imgSrc: "/images/avatars/andrew.jpg",
twitterUrl: "https://twitter.com/andrew_dryga",
githubUrl: "https://github.com/andrewdryga",
linkedinUrl: "https://linkedin.com/in/andrew-dryga-bb382557",
twitterUrl: new URL("https://twitter.com/andrew_dryga"),
githubUrl: new URL("https://github.com/andrewdryga"),
linkedinUrl: new URL("https://linkedin.com/in/andrew-dryga-bb382557"),
},
{
name: "Blake Hitchcock",
title: "Technical Advisor",
imgSrc: "/images/avatars/blake.jpeg",
githubUrl: new URL("https://github.com/rbhitchcock"),
linkedinUrl: new URL("https://www.linkedin.com/in/rblakehitchcock"),
},
{
name: "Thomas Eizinger",
title: "Distributed Systems Engineer",
imgSrc: "/images/avatars/thomas.jpeg",
twitterUrl: new URL("https://twitter.com/oetzn"),
githubUrl: new URL("https://github.com/thomaseizinger"),
linkedinUrl: new URL("https://www.linkedin.com/in/thomas-eizinger"),
},
{
name: "Roopesh Chander",
title: "Apple Platform Engineer",
imgSrc: gravatar("roop@roopc.net", 200),
twitterUrl: new URL("https://twitter.com/roopcnet"),
githubUrl: new URL("https://github.com/roop"),
},
{
name: "Brian Manifold",
title: "Senior Full-stack Engineer",
imgSrc: "/images/avatars/brian.png",
githubUrl: "https://github.com/bmanifold",
linkedinUrl: "https://www.linkedin.com/in/brian-manifold-536a0a3a/",
},
];
const advisors = [
{
name: "Blake Hitchcock",
title: "Technical Advisor",
imgSrc: "/images/avatars/blake.jpeg",
githubUrl: "https://github.com/rbhitchcock",
linkedinUrl: "https://www.linkedin.com/in/rblakehitchcock",
githubUrl: new URL("https://github.com/bmanifold"),
linkedinUrl: new URL(
"https://www.linkedin.com/in/brian-manifold-536a0a3a/"
),
},
{
name: "Thomas Eizinger",
title: "Technical Consultant",
imgSrc: "/images/avatars/thomas.jpeg",
twitterUrl: "https://twitter.com/oetzn",
githubUrl: "https://github.com/thomaseizinger",
linkedinUrl: "https://www.linkedin.com/in/thomas-eizinger",
name: "Jeff Spencer",
title: "Head of Marketing",
imgSrc: gravatar("jeff@firezone.dev", 200),
githubUrl: new URL("https://github.com/jefferenced"),
linkedinUrl: new URL("https://www.linkedin.com/in/jeff393/"),
},
{
name: "Roopesh Chander",
title: "Technical Consultant",
imgSrc: gravatar("roop@roopc.net", 200),
twitterUrl: "https://twitter.com/roopcnet",
githubUrl: "https://github.com/roop",
name: "Trisha",
title: "Windows Platform Engineer",
imgSrc: gravatar("trish@firezone.dev", 200),
githubUrl: new URL("https://github.com/ReactorScram"),
},
];
@@ -118,31 +130,25 @@ export default function Page() {
<div className="py-8 px-4 mx-auto max-w-screen-lg text-center lg:py-16 lg:px-6">
<div className="text-neutral-800 sm:text-lg ">
<h1 className="mb-14 justify-center md:text-6xl text-5xl tracking-tight font-extrabold text-neutral-900 leading-none">
People are everything.
Meet the Firezone team.
</h1>
<h2 className="mb-8 text-xl tracking-tight text-neutral-800 sm:px-16 xl:px-48">
We know that it's people who make all the difference. We strive to
hire the best and brightest and give them the tools they need to
succeed.
{/* FIXME: Make this less fluffy */}
See the driving force behind Firezone -- a team dedicated to
crafting secure and accessible software for a connected world.
Committed to transparency and innovation, our diverse group of
experts collaborates seamlessly to empower users with reliable and
security-focused technology, redefining the way we connect in the
digital landscape.
</h2>
</div>
<div className="text-neutral-800 sm:text-lg ">
<h3 className="justify-center pb-4 pt-14 text-2xl tracking-tight font-bold text-neutral-900 border-b border-neutral-300">
CORE TEAM
THE FIREZONE TEAM
</h3>
</div>
<div className="mt-16 grid sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 md:gap-8 lg:gap-16">
{coreTeam.map((person) => {
return renderTeamMember(person);
})}
</div>
<div className="text-neutral-800 sm:text-lg ">
<h3 className="justify-center pb-4 pt-14 text-2xl tracking-tight font-bold text-neutral-900 border-b border-neutral-300">
ADVISORS & CONSULTANTS
</h3>
</div>
<div className="mt-16 grid sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-8 lg:gap-16">
{advisors.map((person) => {
{team.map((person) => {
return renderTeamMember(person);
})}
</div>

View File

@@ -1,4 +1,5 @@
import Link from "next/link";
import { Route } from "next";
import { HiArrowLongRight } from "react-icons/hi2";
export default function ActionLink({
@@ -7,7 +8,7 @@ export default function ActionLink({
className,
}: {
children: React.ReactNode;
href: string;
href: Route<string>;
className?: string;
}) {
return (

View File

@@ -1,5 +1,6 @@
import ActionLink from "@/components/ActionLink";
import Link from "next/link";
import { Route } from "next";
import Image from "next/image";
@@ -14,7 +15,7 @@ export default function SummaryCard({
}: {
children: React.ReactNode;
date: string;
href: string;
href: Route<string>;
title: string;
authorName: string;
authorAvatarSrc: string;

View File

@@ -1,7 +1,14 @@
import Link from "next/link";
import { Route } from "next";
import { usePathname } from "next/navigation";
export default function Item({ href, label }: { href: string; label: string }) {
export default function Item({
href,
label,
}: {
href: Route<string>;
label: string;
}) {
const p = usePathname();
function active(path: string) {

View File

@@ -196,9 +196,11 @@ export default function Footer() {
</Link>
</span>
<div className="flex mt-4 space-x-6 sm:justify-center sm:mt-0">
<TwitterIcon url="https://twitter.com/firezonehq" />
<GitHubIcon url="https://github.com/firezone" />
<LinkedInIcon url="https://linkedin.com/company/firezonehq" />
<TwitterIcon url={new URL("https://twitter.com/firezonehq")} />
<GitHubIcon url={new URL("https://github.com/firezone")} />
<LinkedInIcon
url={new URL("https://linkedin.com/company/firezonehq")}
/>
</div>
</div>
</div>

View File

@@ -1,11 +1,8 @@
import Link from "next/link";
export function LinkedInIcon({ url }: { url: string }) {
export function LinkedInIcon({ url }: { url: URL }) {
return (
<Link
href={url}
className="text-neutral-800 hover:text-neutral-900 "
>
<Link href={url} className="text-neutral-800 hover:text-neutral-900 ">
<svg
aria-hidden="true"
fill="currentColor"
@@ -23,12 +20,9 @@ export function LinkedInIcon({ url }: { url: string }) {
);
}
export function GitHubIcon({ url }: { url: string }) {
export function GitHubIcon({ url }: { url: URL }) {
return (
<Link
href={url}
className="text-neutral-800 hover:text-neutral-900 "
>
<Link href={url} className="text-neutral-800 hover:text-neutral-900 ">
<svg
className="w-5 h-5"
fill="currentColor"
@@ -46,12 +40,9 @@ export function GitHubIcon({ url }: { url: string }) {
);
}
export function TwitterIcon({ url }: { url: string }) {
export function TwitterIcon({ url }: { url: URL }) {
return (
<Link
href={url}
className="text-neutral-800 hover:text-neutral-900 "
>
<Link href={url} className="text-neutral-800 hover:text-neutral-900 ">
<svg
className="w-5 h-5"
fill="currentColor"

View File

@@ -1,7 +1,14 @@
import Link from "next/link";
import { Route } from "next";
import { usePathname } from "next/navigation";
export default function Item({ href, label }: { href: string; label: string }) {
export default function Item({
href,
label,
}: {
href: Route<string>;
label: string;
}) {
const p = usePathname();
function active(path: string) {

View File

@@ -14,8 +14,6 @@ export default function KbSidebar() {
initFlowbite();
}, []);
console.log(p);
return (
<aside
id="kb-sidebar"