diff --git a/public-website/.env.template b/public-website/.env.template new file mode 100644 index 0000000..3589193 --- /dev/null +++ b/public-website/.env.template @@ -0,0 +1 @@ +FONTAWESOME_AUTH_TOKEN= \ No newline at end of file diff --git a/public-website/.gitignore b/public-website/.gitignore index d08ad59..014cfce 100644 --- a/public-website/.gitignore +++ b/public-website/.gitignore @@ -32,6 +32,7 @@ yarn-error.log* # env files (can opt-in for committing if needed) .env* +!.env.template # vercel .vercel diff --git a/public-website/.npmrc b/public-website/.npmrc new file mode 100644 index 0000000..a25bc60 --- /dev/null +++ b/public-website/.npmrc @@ -0,0 +1,3 @@ +@awesome.me:registry=https://npm.fontawesome.com/ +@fortawesome:registry=https://npm.fontawesome.com/ +//npm.fontawesome.com/:_authToken=${FONTAWESOME_AUTH_TOKEN} \ No newline at end of file diff --git a/public-website/README.md b/public-website/README.md index 0c1de6a..194cce6 100644 --- a/public-website/README.md +++ b/public-website/README.md @@ -3,8 +3,9 @@ This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next- ## Getting Started 1. Ensure you're authenticated with NPM, and have at least "read" access to the `@bayareametro` NPM organization's packages -2. Install dependencies (preferably with `bun`) -3. Run the development server: `bun dev` +2. Create a `.env` file from the `.env.template` file, and complete the values within the `.env` file. +3. Install dependencies (preferably with `bun`) +4. Run the development server: `bun dev` Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. diff --git a/public-website/app/(public)/about.png b/public-website/app/(public)/about.png new file mode 100644 index 0000000..7cc27e3 Binary files /dev/null and b/public-website/app/(public)/about.png differ diff --git a/public-website/app/(public)/background.png b/public-website/app/(public)/background.png new file mode 100644 index 0000000..71a72c0 Binary files /dev/null and b/public-website/app/(public)/background.png differ diff --git a/public-website/app/(public)/layout.module.css b/public-website/app/(public)/layout.module.css new file mode 100644 index 0000000..069b5fd --- /dev/null +++ b/public-website/app/(public)/layout.module.css @@ -0,0 +1,3 @@ +.extraFooterLine { + color: #80979F; +} \ No newline at end of file diff --git a/public-website/app/(public)/layout.tsx b/public-website/app/(public)/layout.tsx new file mode 100644 index 0000000..8b2efc4 --- /dev/null +++ b/public-website/app/(public)/layout.tsx @@ -0,0 +1,38 @@ +import { LegalFooter as LegalFooterPrimitives } from "@bayareametro/mtc-ui"; +import { LegalFooter } from "@/components/legal-footer"; +import { StandardFooter } from "@/components/standard-footer"; +import { Header } from "@/components/header"; +import { version } from "@/components/legal-footer/version"; +import styles from "./layout.module.css"; + +export default function PublicLayout({ children }: { children: React.ReactNode }) { + return ( + <> + +
+ {children} + + + + Version {version.code} ({version.date}) + + + + + ); +} diff --git a/public-website/app/(public)/page.module.css b/public-website/app/(public)/page.module.css new file mode 100644 index 0000000..3e7ddd3 --- /dev/null +++ b/public-website/app/(public)/page.module.css @@ -0,0 +1,86 @@ +.heroSection { + position: relative; + align-items: center; + justify-content: center; + row-gap: 32px; + height: calc(100vh - var(--utility-header-height)); + padding: 56px 142px; +} + +.arrowDown { + position: absolute; + bottom: 56px; + color: #009EDD; +} +.backgroundImage { + z-index: -1; + object-fit: cover; +} + +.logos { + column-gap: 24px; +} + +.text { + row-gap: 16px; +} + +.title { + text-align: center; + color: var(--dv-medium-blue); + margin-bottom: 0; +} + +.subtitle { + text-align: center; + color: var(--dv-midnight-blue); + margin-top: 0; + margin-bottom: 0; +} + +.aboutSection { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + scroll-margin-top: var(--utility-header-height); +} + +.aboutSectionContent { + max-width: 1440px; + align-items: flex-start; + justify-content: center; + padding: 72px 142px; + column-gap: 72px; +} + +.aboutSectionLeftContent { + gap: 16px; + max-width: 1440px; +} + +.aboutSectionLearnMoreLinkIcon { + transition: transform 0.3s ease-in-out; +} + +.aboutSectionLearnMoreLink { + &:hover { + .aboutSectionLearnMoreLinkIcon { + transform: translateX(4px); + } + } +} + +.poweredBySection { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + background-color: var(--dv-white); +} + +.poweredBySectionContent { + max-width: 1440px; + padding: 64px 142px; + row-gap: 40px; +} \ No newline at end of file diff --git a/public-website/app/(public)/page.tsx b/public-website/app/(public)/page.tsx new file mode 100644 index 0000000..0555c43 --- /dev/null +++ b/public-website/app/(public)/page.tsx @@ -0,0 +1,203 @@ +import { + AbagIcon, + createHashLink, + ExternalLink, + HStack, + Link, + MtcIcon, + Typography, + VStack, +} from "@bayareametro/mtc-ui"; +import NextLink from "next/link"; +import Image from "next/image"; +import styles from "./page.module.css"; +import backgroundImage from "./background.png"; +import aboutImage from "./about.png"; +import { SpecialFeatureCard } from "@/components/special-feature-card"; +import vitalSignsImage from "./vital-signs.png"; +import { CSSProperties } from "react"; +import { AnimatedArrow } from "@/components/animated-arrow"; + +const [AboutSection, ScrollToAboutSectionLink] = createHashLink("about"); + +export default function Home() { + return ( + + + Bay Area Spatial Information System + + + + + + + Bay Area Spatial Information System + + + Building a Digital Landscape for Regional Planning in the Bay Area + + + + + + + + + + + About BASIS + + + About BASIS + + The Bay Area Spatial Information System (BASIS) was created to give public agencies + and planning professionals a reliable foundation for data-informed decision-making. + Developed by the Association of Bay Area Governments (ABAG) and the Metropolitan + Transportation Commission (MTC), BASIS reflects a regional effort to improve access + to critical spatial information. + + + As a centralized platform, BASIS is built to reduce duplication, promote + transparency and help jurisdictions work together toward shared goals. It offers + curated datasets submitted by local governments and standardized by ABAG and MTC to + support coordinated planning at every scale. + + + BASIS is part of a larger commitment to modernize how we share data, build tools and + respond to regional challenges in housing, transportation, environmental resilience + and equity. + + + Learn more + + + + + + Learn more + + + + +
+ + + Powered by BASIS + +
+ + + toc.mtcanalytics.org + + + + + rtci.bayareametro.gov + + + + + housing.abag.ca.gov + + + + + toc.mtcanalytics.org + + + + + ipsumcentralstrategy.org + + + + + lorem.ipsumlegacy.org + + +
+
+
+
+ ); +} diff --git a/public-website/app/(public)/vital-signs.png b/public-website/app/(public)/vital-signs.png new file mode 100644 index 0000000..315bb57 Binary files /dev/null and b/public-website/app/(public)/vital-signs.png differ diff --git a/public-website/app/[...fallback]/route.ts b/public-website/app/[...fallback]/route.ts new file mode 100644 index 0000000..e0102a2 --- /dev/null +++ b/public-website/app/[...fallback]/route.ts @@ -0,0 +1,3 @@ +import { redirect } from "next/navigation"; + +export const GET = () => redirect("/"); diff --git a/public-website/app/fontawesome.ts b/public-website/app/fontawesome.ts new file mode 100644 index 0000000..23f4ecf --- /dev/null +++ b/public-website/app/fontawesome.ts @@ -0,0 +1,11 @@ +import "@fortawesome/fontawesome-svg-core/styles.css"; + +import { fab } from "@fortawesome/free-brands-svg-icons"; +import { fas } from "@fortawesome/free-solid-svg-icons"; +import { fal } from "@fortawesome/pro-light-svg-icons"; +import { library } from "@fortawesome/fontawesome-svg-core"; +import { config } from "@fortawesome/fontawesome-svg-core"; + +config.autoAddCss = false; + +library.add(fab, fas, fal); diff --git a/public-website/app/layout.module.css b/public-website/app/layout.module.css new file mode 100644 index 0000000..d3adca2 --- /dev/null +++ b/public-website/app/layout.module.css @@ -0,0 +1,4 @@ +.body { + --utility-header-height: 80px; + --dv-body-bg: var(--dv-midnight-blue-10); +} \ No newline at end of file diff --git a/public-website/app/layout.tsx b/public-website/app/layout.tsx index 291fb81..5f297ae 100644 --- a/public-website/app/layout.tsx +++ b/public-website/app/layout.tsx @@ -6,6 +6,8 @@ import "@fontsource/nunito-sans/700.css"; import "@fontsource/nunito-sans/800.css"; import "@fontsource/nunito"; import "@fontsource/nunito/300.css"; +import "./fontawesome"; +import styles from "./layout.module.css"; import type { Metadata } from "next"; @@ -21,7 +23,7 @@ export default function RootLayout({ }>) { return ( - {children} + {children} ); } diff --git a/public-website/app/page.tsx b/public-website/app/page.tsx deleted file mode 100644 index b36f027..0000000 --- a/public-website/app/page.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function Home() { - return "Hello World"; -} diff --git a/public-website/bun.lock b/public-website/bun.lock index 859f157..c4d134c 100644 --- a/public-website/bun.lock +++ b/public-website/bun.lock @@ -5,28 +5,30 @@ "name": "public-website", "dependencies": { "@bayareametro/mtc-ui": "latest", + "@fortawesome/pro-light-svg-icons": "^6.7.2", "next": "15.3.3", - "react": "^19.0.0", - "react-dom": "^19.0.0", + "react": "^19.1.0", + "react-dom": "^19.1.0", + "sass": "^1.89.1", }, "devDependencies": { - "@eslint/eslintrc": "^3", - "@types/node": "^20", - "@types/react": "^19", - "@types/react-dom": "^19", - "eslint": "^9", + "@eslint/eslintrc": "^3.3.1", + "@types/node": "^20.19.0", + "@types/react": "^19.1.6", + "@types/react-dom": "^19.1.6", + "eslint": "^9.28.0", "eslint-config-next": "15.3.3", "eslint-config-prettier": "^10.1.5", "eslint-plugin-prettier": "^5.4.1", "prettier": "^3.5.3", - "typescript": "^5", + "typescript": "^5.8.3", }, }, }, "packages": { "@babel/runtime": ["@babel/runtime@7.27.6", "", {}, "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q=="], - "@bayareametro/mtc-ui": ["@bayareametro/mtc-ui@1.0.0-alpha.4", "", { "peerDependencies": { "@fontsource/nunito": "*", "@fontsource/nunito-sans": "*", "@fortawesome/fontawesome-svg-core": "6.x", "@fortawesome/free-brands-svg-icons": "6.x", "@fortawesome/free-regular-svg-icons": "6.x", "@fortawesome/free-solid-svg-icons": "6.x", "@fortawesome/react-fontawesome": "^0.2.2", "@tanstack/react-table": "8.x", "@types/react": "*", "@types/react-dom": "*", "bootstrap": "5.x", "react": ">=18.2.0", "react-bootstrap": "2.x", "react-dom": ">=18.2.0" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-uh0Lcu9kW+0ZEjuPyYAeTWUDxWBRDM/gCC0kwPnpJw0uCGP3WH1SFYOuR9t7j6UsPSlbvFOaeNGU1o3AoXiS4w=="], + "@bayareametro/mtc-ui": ["@bayareametro/mtc-ui@1.0.0-alpha.6", "", { "peerDependencies": { "@fontsource/nunito": "*", "@fontsource/nunito-sans": "*", "@fortawesome/fontawesome-svg-core": "6.x", "@fortawesome/free-brands-svg-icons": "6.x", "@fortawesome/free-regular-svg-icons": "6.x", "@fortawesome/free-solid-svg-icons": "6.x", "@fortawesome/react-fontawesome": "^0.2.2", "@tanstack/react-table": "8.x", "@types/react": "*", "@types/react-dom": "*", "bootstrap": "5.x", "react": ">=18.2.0", "react-bootstrap": "2.x", "react-dom": ">=18.2.0" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-FJQJm6lAwjt/Wyx1PjAm/KEAFT3XoMSAJ6MArZj1NOYkeogOaOamSWLKuswxH+nKWNvyvs3TmccvACdVDzWplA=="], "@emnapi/core": ["@emnapi/core@1.4.3", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.2", "tslib": "^2.4.0" } }, "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g=="], @@ -66,6 +68,8 @@ "@fortawesome/free-solid-svg-icons": ["@fortawesome/free-solid-svg-icons@6.7.2", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "6.7.2" } }, "sha512-GsBrnOzU8uj0LECDfD5zomZJIjrPhIlWU82AHwa2s40FKH+kcxQaBvBo3Z4TxyZHIyX8XTDxsyA33/Vx9eFuQA=="], + "@fortawesome/pro-light-svg-icons": ["@fortawesome/pro-light-svg-icons@6.7.2", "https://npm.fontawesome.com/@fortawesome/pro-light-svg-icons/-/pro-light-svg-icons-6.7.2.tgz", { "dependencies": { "@fortawesome/fontawesome-common-types": "6.7.2" } }, "sha512-LeUnJCKlVG0oQwTW3oADJq3rkmnSDTg95RWdP46dCQ8pXOaw/8wzhN0XzZ2s/MqE48FNAX7E/XEqs0qMnrTZDA=="], + "@fortawesome/react-fontawesome": ["@fortawesome/react-fontawesome@0.2.2", "", { "dependencies": { "prop-types": "^15.8.1" }, "peerDependencies": { "@fortawesome/fontawesome-svg-core": "~1 || ~6", "react": ">=16.3" } }, "sha512-EnkrprPNqI6SXJl//m29hpaNzOp1bruISWaOiRtkMi/xSvHJlzc2j2JAYS7egxt/EbjSNV/k6Xy0AQI6vB2+1g=="], "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], @@ -148,6 +152,34 @@ "@nolyfill/is-core-module": ["@nolyfill/is-core-module@1.0.39", "", {}, "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA=="], + "@parcel/watcher": ["@parcel/watcher@2.5.1", "", { "dependencies": { "detect-libc": "^1.0.3", "is-glob": "^4.0.3", "micromatch": "^4.0.5", "node-addon-api": "^7.0.0" }, "optionalDependencies": { "@parcel/watcher-android-arm64": "2.5.1", "@parcel/watcher-darwin-arm64": "2.5.1", "@parcel/watcher-darwin-x64": "2.5.1", "@parcel/watcher-freebsd-x64": "2.5.1", "@parcel/watcher-linux-arm-glibc": "2.5.1", "@parcel/watcher-linux-arm-musl": "2.5.1", "@parcel/watcher-linux-arm64-glibc": "2.5.1", "@parcel/watcher-linux-arm64-musl": "2.5.1", "@parcel/watcher-linux-x64-glibc": "2.5.1", "@parcel/watcher-linux-x64-musl": "2.5.1", "@parcel/watcher-win32-arm64": "2.5.1", "@parcel/watcher-win32-ia32": "2.5.1", "@parcel/watcher-win32-x64": "2.5.1" } }, "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg=="], + + "@parcel/watcher-android-arm64": ["@parcel/watcher-android-arm64@2.5.1", "", { "os": "android", "cpu": "arm64" }, "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA=="], + + "@parcel/watcher-darwin-arm64": ["@parcel/watcher-darwin-arm64@2.5.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw=="], + + "@parcel/watcher-darwin-x64": ["@parcel/watcher-darwin-x64@2.5.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg=="], + + "@parcel/watcher-freebsd-x64": ["@parcel/watcher-freebsd-x64@2.5.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ=="], + + "@parcel/watcher-linux-arm-glibc": ["@parcel/watcher-linux-arm-glibc@2.5.1", "", { "os": "linux", "cpu": "arm" }, "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA=="], + + "@parcel/watcher-linux-arm-musl": ["@parcel/watcher-linux-arm-musl@2.5.1", "", { "os": "linux", "cpu": "arm" }, "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q=="], + + "@parcel/watcher-linux-arm64-glibc": ["@parcel/watcher-linux-arm64-glibc@2.5.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w=="], + + "@parcel/watcher-linux-arm64-musl": ["@parcel/watcher-linux-arm64-musl@2.5.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg=="], + + "@parcel/watcher-linux-x64-glibc": ["@parcel/watcher-linux-x64-glibc@2.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A=="], + + "@parcel/watcher-linux-x64-musl": ["@parcel/watcher-linux-x64-musl@2.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg=="], + + "@parcel/watcher-win32-arm64": ["@parcel/watcher-win32-arm64@2.5.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw=="], + + "@parcel/watcher-win32-ia32": ["@parcel/watcher-win32-ia32@2.5.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ=="], + + "@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.1", "", { "os": "win32", "cpu": "x64" }, "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA=="], + "@pkgr/core": ["@pkgr/core@0.2.7", "", {}, "sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg=="], "@popperjs/core": ["@popperjs/core@2.11.8", "", {}, "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="], @@ -178,7 +210,7 @@ "@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="], - "@types/node": ["@types/node@20.17.57", "", { "dependencies": { "undici-types": "~6.19.2" } }, "sha512-f3T4y6VU4fVQDKVqJV4Uppy8c1p/sVvS3peyqxyWnzkqXFJLRU7Y1Bl7rMS1Qe9z0v4M6McY0Fp9yBsgHJUsWQ=="], + "@types/node": ["@types/node@20.19.0", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-hfrc+1tud1xcdVTABC2JiomZJEklMcXYNTVtZLAeqTVWD+qL5jkHKT+1lOtqDdGxt+mB53DTtiz673vfjU8D1Q=="], "@types/prop-types": ["@types/prop-types@15.7.14", "", {}, "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ=="], @@ -304,6 +336,8 @@ "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], + "classnames": ["classnames@2.5.1", "", {}, "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow=="], "client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="], @@ -470,6 +504,8 @@ "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], + "immutable": ["immutable@5.1.2", "", {}, "sha512-qHKXW1q6liAk1Oys6umoaZbDRqjcjgSrbnrifHsfsttza7zcvRAsL7mMV6xWcyhwQy7Xj5v4hhbr6b+iDYwlmQ=="], + "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], @@ -586,6 +622,8 @@ "next": ["next@15.3.3", "", { "dependencies": { "@next/env": "15.3.3", "@swc/counter": "0.1.3", "@swc/helpers": "0.5.15", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "15.3.3", "@next/swc-darwin-x64": "15.3.3", "@next/swc-linux-arm64-gnu": "15.3.3", "@next/swc-linux-arm64-musl": "15.3.3", "@next/swc-linux-x64-gnu": "15.3.3", "@next/swc-linux-x64-musl": "15.3.3", "@next/swc-win32-arm64-msvc": "15.3.3", "@next/swc-win32-x64-msvc": "15.3.3", "sharp": "^0.34.1" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.41.2", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-JqNj29hHNmCLtNvd090SyRbXJiivQ+58XjCcrC50Crb5g5u2zi7Y2YivbsEfzk6AtVI80akdOQbaMZwWB1Hthw=="], + "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], + "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], @@ -652,6 +690,8 @@ "react-transition-group": ["react-transition-group@4.4.5", "", { "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", "loose-envify": "^1.4.0", "prop-types": "^15.6.2" }, "peerDependencies": { "react": ">=16.6.0", "react-dom": ">=16.6.0" } }, "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g=="], + "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], + "reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="], "regexp.prototype.flags": ["regexp.prototype.flags@1.5.4", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-errors": "^1.3.0", "get-proto": "^1.0.1", "gopd": "^1.2.0", "set-function-name": "^2.0.2" } }, "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA=="], @@ -672,6 +712,8 @@ "safe-regex-test": ["safe-regex-test@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-regex": "^1.2.1" } }, "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw=="], + "sass": ["sass@1.89.1", "", { "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": { "sass": "sass.js" } }, "sha512-eMLLkl+qz7tx/0cJ9wI+w09GQ2zodTkcE/aVfywwdlRcI3EO19xGnbmJwg/JMIm+5MxVJ6outddLZ4Von4E++Q=="], + "scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="], "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], @@ -756,7 +798,7 @@ "uncontrollable": ["uncontrollable@7.2.1", "", { "dependencies": { "@babel/runtime": "^7.6.3", "@types/react": ">=16.9.11", "invariant": "^2.2.4", "react-lifecycles-compat": "^3.0.4" }, "peerDependencies": { "react": ">=15.0.0" } }, "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ=="], - "undici-types": ["undici-types@6.19.8", "", {}, "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="], + "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], "unrs-resolver": ["unrs-resolver@1.7.10", "", { "dependencies": { "napi-postinstall": "^0.2.2" }, "optionalDependencies": { "@unrs/resolver-binding-darwin-arm64": "1.7.10", "@unrs/resolver-binding-darwin-x64": "1.7.10", "@unrs/resolver-binding-freebsd-x64": "1.7.10", "@unrs/resolver-binding-linux-arm-gnueabihf": "1.7.10", "@unrs/resolver-binding-linux-arm-musleabihf": "1.7.10", "@unrs/resolver-binding-linux-arm64-gnu": "1.7.10", "@unrs/resolver-binding-linux-arm64-musl": "1.7.10", "@unrs/resolver-binding-linux-ppc64-gnu": "1.7.10", "@unrs/resolver-binding-linux-riscv64-gnu": "1.7.10", "@unrs/resolver-binding-linux-riscv64-musl": "1.7.10", "@unrs/resolver-binding-linux-s390x-gnu": "1.7.10", "@unrs/resolver-binding-linux-x64-gnu": "1.7.10", "@unrs/resolver-binding-linux-x64-musl": "1.7.10", "@unrs/resolver-binding-wasm32-wasi": "1.7.10", "@unrs/resolver-binding-win32-arm64-msvc": "1.7.10", "@unrs/resolver-binding-win32-ia32-msvc": "1.7.10", "@unrs/resolver-binding-win32-x64-msvc": "1.7.10" } }, "sha512-CJEMJcz6vuwRK6xxWc+uf8AGi0OyfoVtHs5mExtNecS0HZq3a3Br1JC/InwwTn6uy+qkAdAdK+nJUYO9FPtgZw=="], @@ -782,6 +824,8 @@ "@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="], + "@parcel/watcher/detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="], + "@restart/ui/@restart/hooks": ["@restart/hooks@0.5.1", "", { "dependencies": { "dequal": "^2.0.3" }, "peerDependencies": { "react": ">=16.8.0" } }, "sha512-EMoH04NHS1pbn07iLTjIjgttuqb7qu4+/EyhAx27MHpoENcB2ZdSsLTNxmKD+WEPnZigo62Qc8zjGnNxoSE/5Q=="], "@restart/ui/uncontrollable": ["uncontrollable@8.0.4", "", { "peerDependencies": { "react": ">=16.14.0" } }, "sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ=="], diff --git a/public-website/components/animated-arrow/index.module.css b/public-website/components/animated-arrow/index.module.css new file mode 100644 index 0000000..f14f0b7 --- /dev/null +++ b/public-website/components/animated-arrow/index.module.css @@ -0,0 +1,47 @@ +.container { + position: relative; + width: 30px; + height: 68px; +} + +.line { + position: absolute; + left: 13px; + top: 12px; + width: 4px; + height: 26px; + background-color: #009EDD; + border-radius: 8px; + animation: lineExtend 2.5s cubic-bezier(0.68, -0.55, 0.265, 1.55) infinite; +} + +.arrow { + position: absolute; + left: 1.01171875px; + top: 22px; + animation: arrowDrop 2.5s cubic-bezier(0.68, -0.55, 0.265, 1.55) infinite; +} + +@keyframes lineExtend { + 0% { + height: 26px; + } + 15% { + height: 42px; + } + 100% { + height: 26px; + } +} + +@keyframes arrowDrop { + 0% { + transform: translateY(0); + } + 15% { + transform: translateY(16px); + } + 100% { + transform: translateY(0); + } +} \ No newline at end of file diff --git a/public-website/components/animated-arrow/index.tsx b/public-website/components/animated-arrow/index.tsx new file mode 100644 index 0000000..e473c11 --- /dev/null +++ b/public-website/components/animated-arrow/index.tsx @@ -0,0 +1,24 @@ +import { clsx } from "@bayareametro/mtc-ui"; +import styles from "./index.module.css"; +import { HTMLAttributes } from "react"; + +export type AnimatedArrowProps = HTMLAttributes; + +export const AnimatedArrow = ({ className, ...props }: AnimatedArrowProps) => ( +
+
+ + + +
+); diff --git a/public-website/components/header/index.module.scss b/public-website/components/header/index.module.scss new file mode 100644 index 0000000..2ed2362 --- /dev/null +++ b/public-website/components/header/index.module.scss @@ -0,0 +1,108 @@ +@use "@bayareametro/mtc-ui/config.bootstrap.scss" as *; + +.standardHeaderRoot { + --xs-top-content-height: 72px; + + grid-column: 1 / -1; + grid-row: 1; + position: sticky; + top: var(--ribbon-height); + z-index: $zindex-dropdown + 2; +} + +.headerLogo { + margin-right: 16px; +} + +.headerTitleLink { + display: flex; + align-items: center; + margin: 10px 0; + text-decoration: none; +} + +.headerTitle { + font-weight: 300; + font-size: 24px !important; + line-height: 32px !important; +} + +.topContent { + height: var(--xs-top-content-height); + padding-left: var(--page-padding); + padding-right: var(--page-padding); + background-color: var(--dv-white); +} + +.standardHeaderNavigation { + padding-top: 24px; + background-color: var(--dv-white) !important; + + @include media-breakpoint-down(md) { + max-height: calc(100vh - (var(--xs-top-content-height) + var(--ribbon-height))); + overflow: auto; + } +} + +.rightContent { + flex: 1; + justify-content: flex-end; + height: 100%; +} + +.rightContentNavbar { + --dv-navbar-color: var(--dv-white); + --dv-navbar-hover-color: var(--dv-mtc-gold); + --dv-navbar-padding-y: 0; +} + +.rightContentNavbarCollapse { + height: 100%; +} + +.rightContentNav { + --dv-nav-pills-link-active-bg: var(--dv-mtc-gold); + --dv-nav-pills-link-active-color: var(--dv-midnight-blue); + --dv-nav-pills-border-radius: 0; + + gap: 16px; + height: 100%; +} + +.rightContentNavLink { + display: flex; + align-items: center; + height: 100%; +} + +.utilityHeaderRoot { + grid-column: 2; + grid-row: 1; + + position: sticky; + top: 0; + height: var(--utility-header-height); + + z-index: $zindex-dropdown + 2; +} + +.input { + padding: 16px 4px; +} + +.collapsibleSearchPanel { + background-color: var(--dv-medium-blue); +} + +.collapsibleSearchPanelSearchField { + padding: 8px; +} + +.utilityHeaderContainer { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + max-width: var(--max-content-width); + height: 100%; +} diff --git a/public-website/components/header/index.tsx b/public-website/components/header/index.tsx new file mode 100644 index 0000000..3117edb --- /dev/null +++ b/public-website/components/header/index.tsx @@ -0,0 +1,57 @@ +import { Button, HStack, Link, StandardHeader, UtilityHeader, VStack } from "@bayareametro/mtc-ui"; +import BootstrapNavbar from "react-bootstrap/Navbar"; +import BootstrapNavbarCollapse from "react-bootstrap/NavbarCollapse"; +import BootstrapNavItem from "react-bootstrap/NavItem"; +import BootstrapNavLink from "react-bootstrap/NavLink"; +import styles from "./index.module.scss"; +import { PathnameAwareNav } from "@/components/pathname-aware-nav"; +import { faArrowRight } from "@fortawesome/pro-light-svg-icons"; +import NextLink from "next/link"; + +const items = [ + { href: "/data-inventory", text: "Data Inventory" }, + { href: "/about-us", text: "About Us" }, + { href: "/contact-us", text: "Contact Us" }, +]; + +export const Header = () => ( + + + + + + + Bay Area Spatial Information System + + + + + + + {items.map(({ href, text }) => ( + + + {text} + + + ))} + + + Log In + + + + + + + + +); diff --git a/public-website/components/legal-footer/index.tsx b/public-website/components/legal-footer/index.tsx new file mode 100644 index 0000000..fe91b76 --- /dev/null +++ b/public-website/components/legal-footer/index.tsx @@ -0,0 +1,32 @@ +import { ExternalLink, LegalFooter as LegalFooterPrimitives } from "@bayareametro/mtc-ui"; +import { Fragment } from "react"; +import Link from "next/link"; + +export interface LegalFooterProps { + links: { href: string; text: string }[]; + children?: React.ReactNode; +} + +export const LegalFooter = ({ links, children }: LegalFooterProps) => ( + + + {links.length ? ( + + {links.map(({ text, href, ...rest }, index) => { + const Component = href.startsWith("/") || href.startsWith("#") ? Link : ExternalLink; + return ( + + {index !== 0 && links.length > 1 ? "|" : null} + + {text} + + + ); + })} + + ) : null} + {children} + + + +); diff --git a/public-website/components/legal-footer/version.ts b/public-website/components/legal-footer/version.ts new file mode 100644 index 0000000..9b6b096 --- /dev/null +++ b/public-website/components/legal-footer/version.ts @@ -0,0 +1,4 @@ +export const version = { + code: "2.0", + date: "June 25, 2025", +}; diff --git a/public-website/components/pathname-aware-nav.tsx b/public-website/components/pathname-aware-nav.tsx new file mode 100644 index 0000000..57f45ef --- /dev/null +++ b/public-website/components/pathname-aware-nav.tsx @@ -0,0 +1,12 @@ +"use client"; + +import { usePathname } from "next/navigation"; +import BootstrapNav, { NavProps as BootstrapNavProps } from "react-bootstrap/Nav"; + +export type PathnameAwareNavProps = Omit; + +export const PathnameAwareNav = ({ ...rest }: PathnameAwareNavProps) => { + const pathname = usePathname(); + + return ; +}; diff --git a/public-website/components/special-feature-card/index.module.css b/public-website/components/special-feature-card/index.module.css new file mode 100644 index 0000000..5b47051 --- /dev/null +++ b/public-website/components/special-feature-card/index.module.css @@ -0,0 +1,24 @@ +.root { + --dv-card-border-color: var(--dv-midnight-blue); + --dv-card-border-radius: 4px; + --dv-card-bg: var(--dv-white); +} + +.image { + height: auto; +} + +.body { + gap: 16px; +} + +.textContent { + flex: 1; + gap: 12px; +} + +.ctaContainer { + justify-content: space-between; + align-items: center; + gap: 16px; +} \ No newline at end of file diff --git a/public-website/components/special-feature-card/index.tsx b/public-website/components/special-feature-card/index.tsx new file mode 100644 index 0000000..8267dca --- /dev/null +++ b/public-website/components/special-feature-card/index.tsx @@ -0,0 +1,44 @@ +import { VStack, Card, Typography, HStack, clsx } from "@bayareametro/mtc-ui"; +import Image, { StaticImageData } from "next/image"; +import styles from "./index.module.css"; + +export interface SpecialFeatureCardProps extends Omit { + image: { + src: string | StaticImageData; + alt: string; + }; + heading: string; + body: string; + children?: React.ReactNode; +} + +export const SpecialFeatureCard = ({ + image, + heading, + body, + children, + className, + ...rest +}: SpecialFeatureCardProps) => ( + + + + + + {heading} + + + {body} + + + {children ? {children} : null} + + +); diff --git a/public-website/components/standard-footer/index.tsx b/public-website/components/standard-footer/index.tsx new file mode 100644 index 0000000..b3cb092 --- /dev/null +++ b/public-website/components/standard-footer/index.tsx @@ -0,0 +1,110 @@ +import { + AbagLogo, + ExternalLink, + MtcLogo, + StandardFooter as StandardFooterPrimitives, +} from "@bayareametro/mtc-ui"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import Col from "react-bootstrap/Col"; + +export interface StandardFooterProps { + children?: React.ReactNode; +} + +export const StandardFooter = ({ children }: StandardFooterProps) => ( + + + + + + + + +

Metropolitan Transportation Commission

+

+ MTC is responsible for planning, financing and coordinating transportation for the + nine-county San Francisco Bay Area. +

+ + + mtc.ca.gov + + + + + + + + + + + + + + + + + + + +
+ + + + + +

Association of Bay Area Governments

+

+ ABAG supports regional planning and cooperation among the cities and counties of the San + Francisco Bay Area. +

+ + abag.ca.gov + +
+ + +

Contact Us

+

+ Bay Area Metro Center +
+ 375 Beale Street +
+ San Francisco, CA 94105 +

+

+ Main Phone Number: (415) 778-6700 +
+ Public Information Line: (415) 778-6757 +
+ Main Fax Number: (415) 536-9800 +

+

+ info@bayareametro.gov +

+
+ +
+ {children} +
+
+); diff --git a/public-website/package.json b/public-website/package.json index 317aace..f21b496 100644 --- a/public-website/package.json +++ b/public-website/package.json @@ -13,20 +13,22 @@ }, "dependencies": { "@bayareametro/mtc-ui": "latest", + "@fortawesome/pro-light-svg-icons": "^6.7.2", "next": "15.3.3", - "react": "^19.0.0", - "react-dom": "^19.0.0" + "react": "^19.1.0", + "react-dom": "^19.1.0", + "sass": "^1.89.1" }, "devDependencies": { - "@eslint/eslintrc": "^3", - "@types/node": "^20", - "@types/react": "^19", - "@types/react-dom": "^19", - "eslint": "^9", + "@eslint/eslintrc": "^3.3.1", + "@types/node": "^20.19.0", + "@types/react": "^19.1.6", + "@types/react-dom": "^19.1.6", + "eslint": "^9.28.0", "eslint-config-next": "15.3.3", "eslint-config-prettier": "^10.1.5", "eslint-plugin-prettier": "^5.4.1", "prettier": "^3.5.3", - "typescript": "^5" + "typescript": "^5.8.3" } }