Migrate the footer component.

pull/2/head
Joshua Potter 2023-12-02 07:21:05 -07:00
parent 794b3bcbdd
commit 57eeeafb7a
11 changed files with 224 additions and 6 deletions

View File

@ -3,3 +3,48 @@
@import "tailwindcss/utilities";
/* This file is for your main application CSS */
*,
*:before,
*:after {
box-sizing: inherit;
}
html {
height: 100%;
box-sizing: border-box;
touch-action: manipulation;
font-feature-settings: 'case' 1, 'rlig' 1, 'calt' 0;
}
html,
body {
font-family: -apple-system, system-ui, BlinkMacSystemFont, 'Helvetica Neue',
'Helvetica', sans-serif;
text-rendering: optimizeLegibility;
-moz-osx-font-smoothing: grayscale;
@apply text-white bg-white antialiased;
}
body {
position: relative;
min-height: 100%;
margin: 0;
}
a {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
.animated {
-webkit-animation-duration: 1s;
animation-duration: 1s;
-webkit-animation-duration: 1s;
animation-duration: 1s;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
.height-screen-helper {
height: calc(100vh - 80px);
}

View File

@ -1,9 +1,10 @@
import * as React from 'react'
import * as React from "react";
import { Footer } from "./components/Footer";
export default function App() {
return (
<div>
Hello React!
<Footer />
</div>
)
);
}

View File

@ -0,0 +1,23 @@
import * as React from "react";
import clsx from "clsx";
type ContainerProps<T extends React.ElementType> = {
as?: T;
className?: string;
children: React.ReactNode;
};
export function Container<T extends React.ElementType = "div">({
as,
className,
children,
}: Omit<React.ComponentPropsWithoutRef<T>, keyof ContainerProps<T>> &
ContainerProps<T>) {
let Component = as ?? "div";
return (
<Component className={clsx("mx-auto max-w-7xl px-6 lg:px-8", className)}>
<div className="mx-auto max-w-2xl lg:max-w-none">{children}</div>
</Component>
);
}

View File

@ -0,0 +1,64 @@
import * as React from "react";
import { Container } from "./Container";
import { Logo } from "./Logo";
const navigation = [
{
title: "Students",
links: [{ title: "Find a Coach", href: "/c/" }],
},
{
title: "Company",
links: [
{ title: "About Us", href: "/about/" },
{ title: "Contact Us", href: "/contact/" },
],
},
];
function Navigation() {
return (
<nav>
<ul role="list" className="grid grid-cols-2 gap-8 sm:grid-cols-3">
{navigation.map((section, sectionIndex) => (
<li key={sectionIndex}>
<div className="font-display text-sm font-semibold tracking-wider text-neutral-950">
{section.title}
</div>
<ul role="list" className="mt-4 text-sm text-neutral-700">
{section.links.map((link, linkIndex) => (
<li key={linkIndex} className="mt-4">
<a
href={link.href}
className="transition hover:text-neutral-950"
>
{link.title}
</a>
</li>
))}
</ul>
</li>
))}
</ul>
</nav>
);
}
export function Footer() {
return (
<Container as="footer" className="mt-16 w-full sm:mt-24 lg:mt-28">
<div className="grid grid-cols-1 gap-x-8 gap-y-16 lg:grid-cols-2">
<Navigation />
</div>
<div className="mb-12 mt-16 flex flex-wrap items-end justify-between gap-x-6 gap-y-4 border-t border-neutral-950/10 pt-12">
<a href="/" aria-label="Home">
<Logo className="h-8" />
</a>
<p className="text-sm text-neutral-700">
© BoardWise LLC {new Date().getFullYear()}
</p>
</div>
</Container>
);
}

View File

@ -0,0 +1,25 @@
import * as React from "react";
import clsx from "clsx";
import LogoMark from "../icons/Logomark";
export function Logo({
invert = false,
}: React.ComponentPropsWithoutRef<"svg"> & { invert?: boolean }) {
return (
<div className="mr-4 flex flex-nowrap items-center justify-start">
<LogoMark
className="mr-4 duration-500 ease-in-out hover:rotate-180"
invert={invert}
/>
<p
className={clsx(
"font-display text-xl font-bold tracking-tight",
invert ? "text-white" : "text-neutral-950",
)}
>
BoardWise
</p>
</div>
);
}

View File

@ -0,0 +1,33 @@
import * as React from "react";
const SvgComponent = ({ invert = false, size = 25, ...props }) => {
const color = invert ? "rgb(255, 255, 255)" : "rgb(10 10 10)";
const radius = 5;
const roundedTopRightPath = `
M ${size / 2} 0
H ${size - radius}
Q ${size} 0, ${size} ${radius}
V ${size / 2}
H ${size / 2}
Z`;
const roundedBottomLeftPath = `
M 0 ${size - radius}
Q 0 ${size}, ${radius} ${size}
H ${size / 2}
V ${size / 2}
H 0
Z`;
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width={size}
height={size}
{...props}
>
<path d={roundedTopRightPath} fill={color} />
<path d={roundedBottomLeftPath} fill={color} />
</svg>
);
};
export default SvgComponent;

View File

@ -4,6 +4,15 @@
let
sources = {
"clsx-2.0.0" = {
name = "clsx";
packageName = "clsx";
version = "2.0.0";
src = fetchurl {
url = "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz";
sha512 = "rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==";
};
};
"js-tokens-4.0.0" = {
name = "js-tokens";
packageName = "js-tokens";
@ -56,6 +65,7 @@ let
version = "0.1.0";
src = ./.;
dependencies = [
sources."clsx-2.0.0"
sources."js-tokens-4.0.0"
sources."loose-envify-1.4.0"
sources."react-18.2.0"

View File

@ -8,6 +8,7 @@
"name": "boardwise",
"version": "0.1.0",
"dependencies": {
"clsx": "^2.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
@ -72,6 +73,14 @@
"integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==",
"dev": true
},
"node_modules/clsx": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz",
"integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==",
"engines": {
"node": ">=6"
}
},
"node_modules/csstype": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
@ -172,6 +181,11 @@
"integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==",
"dev": true
},
"clsx": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz",
"integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q=="
},
"csstype": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",

View File

@ -2,6 +2,7 @@
"name": "boardwise",
"version": "0.1.0",
"dependencies": {
"clsx": "^2.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},

View File

@ -3,6 +3,8 @@
"compilerOptions": {
// Keep in mind that ES6+ syntax to ES5 is not supported in esbuild yet.
"target": "es2016",
// https://www.typescriptlang.org/docs/handbook/modules/theory.html
"module": "nodenext",
// Even when transpiling a single module, the TypeScript compiler actually
// parses imported files so it can tell whether an imported name is a type
// or a value. However, tools like esbuild compile each file in isolation so
@ -25,6 +27,6 @@
// calls. It seems like the "react" value mirrors esbuild's native
// "transform" option, but it isn't obvious how these two relate from the
// documentation: https://esbuild.github.io/api/#jsx.
"jsx": "react"
"jsx": "react",
}
}

View File

@ -47,7 +47,7 @@ config :boardwise, BoardWise.Mailer, adapter: Swoosh.Adapters.Local
# specified in this command (e.g. `useDefineForClassFields` as explained in
# https://esbuild.github.io/content-types/#tsconfig-json).
config :esbuild,
version: "0.17.11",
version: "0.19.7",
default: [
args: ~w(
./js/app.js
@ -65,7 +65,7 @@ config :esbuild,
# Configure tailwind (the version is required)
config :tailwind,
version: "3.3.2",
version: "3.3.5",
default: [
args: ~w(
--config=tailwind.config.js