diff --git a/assets/css/app.css b/assets/css/app.css
index 378c8f9..a3c19bb 100644
--- a/assets/css/app.css
+++ b/assets/css/app.css
@@ -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);
+}
diff --git a/assets/js/react/App.tsx b/assets/js/react/App.tsx
index 4a050bc..c9f6b81 100644
--- a/assets/js/react/App.tsx
+++ b/assets/js/react/App.tsx
@@ -1,9 +1,10 @@
-import * as React from 'react'
+import * as React from "react";
+import { Footer } from "./components/Footer";
export default function App() {
return (
- Hello React!
+
- )
+ );
}
diff --git a/assets/js/react/components/Container.tsx b/assets/js/react/components/Container.tsx
new file mode 100644
index 0000000..cd06fd2
--- /dev/null
+++ b/assets/js/react/components/Container.tsx
@@ -0,0 +1,23 @@
+import * as React from "react";
+import clsx from "clsx";
+
+type ContainerProps = {
+ as?: T;
+ className?: string;
+ children: React.ReactNode;
+};
+
+export function Container({
+ as,
+ className,
+ children,
+}: Omit, keyof ContainerProps> &
+ ContainerProps) {
+ let Component = as ?? "div";
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/assets/js/react/components/Footer.tsx b/assets/js/react/components/Footer.tsx
new file mode 100644
index 0000000..0e3a438
--- /dev/null
+++ b/assets/js/react/components/Footer.tsx
@@ -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 (
+
+ );
+}
+
+export function Footer() {
+ return (
+
+
+
+
+
+
+
+
+
+ © BoardWise LLC {new Date().getFullYear()}
+
+
+
+ );
+}
diff --git a/assets/js/react/components/Logo.tsx b/assets/js/react/components/Logo.tsx
new file mode 100644
index 0000000..9cb752e
--- /dev/null
+++ b/assets/js/react/components/Logo.tsx
@@ -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 (
+
+ );
+}
diff --git a/assets/js/react/icons/Logomark.tsx b/assets/js/react/icons/Logomark.tsx
new file mode 100644
index 0000000..c7c1202
--- /dev/null
+++ b/assets/js/react/icons/Logomark.tsx
@@ -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 (
+
+ );
+};
+export default SvgComponent;
diff --git a/assets/node-packages.nix b/assets/node-packages.nix
index 506e303..4b9959a 100644
--- a/assets/node-packages.nix
+++ b/assets/node-packages.nix
@@ -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"
diff --git a/assets/package-lock.json b/assets/package-lock.json
index e96b46b..36cdd96 100644
--- a/assets/package-lock.json
+++ b/assets/package-lock.json
@@ -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",
diff --git a/assets/package.json b/assets/package.json
index ebf7433..e3535c6 100644
--- a/assets/package.json
+++ b/assets/package.json
@@ -2,6 +2,7 @@
"name": "boardwise",
"version": "0.1.0",
"dependencies": {
+ "clsx": "^2.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
diff --git a/assets/tsconfig.json b/assets/tsconfig.json
index 0b48eff..fab4f2c 100644
--- a/assets/tsconfig.json
+++ b/assets/tsconfig.json
@@ -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",
}
}
diff --git a/config/config.exs b/config/config.exs
index 4a6111e..2356abd 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -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