mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-19 00:41:41 +00:00
Refactor website (#2243)
## Description Switches to Vue for easier maintenance (pre-built in CI). Changes UI to look a little nicer <img width="1920" height="1080" alt="image" src="https://github.com/user-attachments/assets/c5933326-c391-4d5c-8b3c-d3eeaa11a2f9" /> <img width="1920" height="1080" alt="image" src="https://github.com/user-attachments/assets/d933c8d0-e5a0-40c0-bc80-0c4c8a4cc4f0" /> <img width="1920" height="1080" alt="image" src="https://github.com/user-attachments/assets/3d8a652b-bd49-4147-a269-140e79fd4164" /> <img width="1021" height="1352" alt="image" src="https://github.com/user-attachments/assets/545a9c02-541c-4a34-b81f-587f21bc682f" /> <img width="957" height="1196" alt="image" src="https://github.com/user-attachments/assets/0dfd8080-0ffe-48c5-8fe0-11177f95dfc9" /> ## Meta Merge checklist: - [x] Pull Request title is [short, imperative summary](https://cbea.ms/git-commit/) of proposed changes - [x] The description documents the _what_ and _why_ - [ ] If this PR changes behavior or adds a feature, user documentation is updated - [ ] If this PR touches photon-serde, all messages have been regenerated and hashes have not changed unexpectedly - [ ] If this PR touches configuration, this is backwards compatible with settings back to v2025.3.2 - [ ] If this PR touches pipeline settings or anything related to data exchange, the frontend typing is updated - [ ] If this PR addresses a bug, a regression test for it is added --------- Co-authored-by: Gold856 <117957790+Gold856@users.noreply.github.com>
This commit is contained in:
@@ -1,15 +1,19 @@
|
||||
<!doctype html>
|
||||
<html lang="en-US">
|
||||
<!-- TODO: We need more images and videos to improve quality of the site- if you can see this and have PhotonVision, take a screenshot of yourself using it and send it to the #media channel in Discord!-->
|
||||
<head>
|
||||
<title>PhotonVision</title>
|
||||
<link rel="icon" href="favicon.svg" type="image/svg+xml" />
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="stylesheet" href="src/css/main.css" />
|
||||
<link rel="stylesheet" href="src/css/fontawesome.min.css" />
|
||||
<link rel="stylesheet" href="src/css/brands.min.css" />
|
||||
<link rel="stylesheet" href="src/css/solid.min.css" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&family=Prompt:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<meta name="title" content="PhotonVision" />
|
||||
<meta
|
||||
@@ -31,308 +35,7 @@
|
||||
/>
|
||||
</head>
|
||||
<body class="home bg-zinc-900 font-light text-white w-screen">
|
||||
<div id="page-wrapper" class="h-screen overflow-y-auto scroll-smooth">
|
||||
<!-- Header -->
|
||||
<header
|
||||
id="header"
|
||||
class="bg-zinc-800 flex md:justify-end sticky top-0 w-full z-10"
|
||||
>
|
||||
<button
|
||||
class="header-btn hover:bg-zinc-700 cursor-pointer flex md:!hidden"
|
||||
popovertarget="mobile-nav"
|
||||
aria-label="Open mobile navigation menu"
|
||||
>
|
||||
<i class="fa-solid fa-bars !leading-[24px]"></i>
|
||||
</button>
|
||||
<div class="relative">
|
||||
<div
|
||||
popover
|
||||
id="mobile-nav"
|
||||
class="h-screen starting:open:-translate-x-50 open:translate-0 transition-transform -translate-x-50 relative duration-400 transition-discrete bg-zinc-700 open:flex open:flex-col md:open:hidden"
|
||||
>
|
||||
<a
|
||||
href="https://docs.photonvision.org/en/latest/"
|
||||
class="header-btn"
|
||||
>Documentation</a
|
||||
>
|
||||
<a href="https://discord.gg/wYxTwym" class="header-btn">Discord</a>
|
||||
<a
|
||||
href="https://github.com/PhotonVision/photonvision/"
|
||||
class="header-btn"
|
||||
>GitHub</a
|
||||
>
|
||||
<a
|
||||
href="https://www.redbubble.com/people/PhotonVision/shop?asc=u"
|
||||
class="header-btn"
|
||||
>Merch</a
|
||||
>
|
||||
<a
|
||||
href="https://demo.photonvision.org"
|
||||
class="header-btn bg-primary"
|
||||
>Demo</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<nav id="nav" class="hidden md:flex">
|
||||
<a href="https://docs.photonvision.org/en/latest/" class="header-btn"
|
||||
>Documentation</a
|
||||
>
|
||||
<a href="https://discord.gg/wYxTwym" class="header-btn">Discord</a>
|
||||
<a
|
||||
href="https://github.com/PhotonVision/photonvision/"
|
||||
class="header-btn"
|
||||
>GitHub</a
|
||||
>
|
||||
<a
|
||||
href="https://www.redbubble.com/people/PhotonVision/shop?asc=u"
|
||||
class="header-btn"
|
||||
>Merch</a
|
||||
>
|
||||
<a href="https://demo.photonvision.org" class="header-btn bg-primary"
|
||||
>Demo</a
|
||||
>
|
||||
</nav>
|
||||
</header>
|
||||
<!-- One -->
|
||||
<section
|
||||
class="flex flex-col h-[calc(100vh_-_56px)] justify-center items-center p-8 md:p-0 relative"
|
||||
>
|
||||
<div class="flex justify-center md:justify-end flex-col md:flex-row">
|
||||
<header
|
||||
class="flex flex-col gap-4 items-center md:items-end justify-center text-center md:text-end"
|
||||
>
|
||||
<h2 class="text-4xl">PhotonVision</h2>
|
||||
<div class="text-xl max-w-128">
|
||||
PhotonVision is the free, fast, and easy-to-use computer vision
|
||||
solution for the FIRST® Robotics Competition. Teams can download
|
||||
a PhotonVision image for select coprocessors and start tracking
|
||||
targets in minutes.
|
||||
</div>
|
||||
<a
|
||||
href="https://docs.photonvision.org/en/latest/docs/quick-start/quick-install.html"
|
||||
class="bg-primary py-4 px-8 rounded grow-0 self-center md:self-end"
|
||||
>Get Started</a
|
||||
>
|
||||
</header>
|
||||
<span class="self-center md:self-initial mt-8 md:ms-8 shrink"
|
||||
><img
|
||||
src="images/PhotonVision-Icon-BG.png"
|
||||
alt="PhotonVision Logo"
|
||||
class="max-w-64"
|
||||
/></span>
|
||||
</div>
|
||||
<a href="#two" class="absolute bottom-0 p-4">
|
||||
<i class="fa-solid fa-chevron-down"></i>
|
||||
</a>
|
||||
</section>
|
||||
|
||||
<!-- Two -->
|
||||
<section
|
||||
id="two"
|
||||
class="h-[calc(100vh_-_56px)] relative justify-center flex items-center"
|
||||
>
|
||||
<span class="image fit"
|
||||
><img
|
||||
src="images/demo.png"
|
||||
alt="Demo of PhotonVision UI"
|
||||
loading="lazy"
|
||||
/></span>
|
||||
<a href="#three" class="absolute bottom-0 p-4"
|
||||
><i class="fa-solid fa-chevron-down"></i
|
||||
></a>
|
||||
</section>
|
||||
|
||||
<!-- Three -->
|
||||
<section
|
||||
id="three"
|
||||
class="min-h-[calc(100vh_-_56px)] flex flex-col gap-4 items-center justify-center px-4 md:px-14 lg:px-28 relative"
|
||||
>
|
||||
<header
|
||||
class="flex flex-col gap-4 justify-center items-center text-center"
|
||||
>
|
||||
<h2 class="text-3xl">The Future is in Sight</h2>
|
||||
<p class="text-2xl">
|
||||
PhotonVision is a powerful, open-source vision system for FRC. It's
|
||||
designed to be fast and easy to use, regardless of your team's
|
||||
financial or technical resources.
|
||||
</p>
|
||||
<hr class="border-brand-yellow border-2 w-64 mb-4" />
|
||||
</header>
|
||||
<div class="mb-8 lg:mb-0">
|
||||
<div
|
||||
class="grid max-w-xl grid-cols-1 gap-x-8 gap-y-10 lg:max-w-none lg:grid-cols-2 lg:gap-y-16"
|
||||
>
|
||||
<section class="relative pl-16">
|
||||
<div class="features-icon">
|
||||
<i class="fa-solid fa-location-arrow"></i>
|
||||
</div>
|
||||
<h3 class="text-lg mb-2">First-Class AprilTag Support</h3>
|
||||
<p>FRC Target tracking, out of the box.</p>
|
||||
</section>
|
||||
<section class="relative pl-16">
|
||||
<div class="features-icon">
|
||||
<i class="icon alt major fa-solid fa-chess-board"></i>
|
||||
</div>
|
||||
<h3 class="text-lg mb-2">Built-In Camera Calibration</h3>
|
||||
<p>
|
||||
Per-camera intrinsics calibration maximizes accuracy of
|
||||
homography
|
||||
</p>
|
||||
</section>
|
||||
<section class="relative pl-16">
|
||||
<div class="features-icon">
|
||||
<i class="icon alt major fa-solid fa-brain"></i>
|
||||
</div>
|
||||
<h3 class="text-lg mb-2">Machine Learning</h3>
|
||||
<p>Hardware-accelerated inferencing for gamepiece detection</p>
|
||||
</section>
|
||||
<section class="relative pl-16">
|
||||
<div class="features-icon">
|
||||
<i class="icon alt major fa-solid fa-eye"></i>
|
||||
</div>
|
||||
<h3 class="text-lg mb-2">Driver Mode Integration</h3>
|
||||
<p>You can use the same camera for driving and robot vision</p>
|
||||
</section>
|
||||
<section class="relative pl-16">
|
||||
<div class="features-icon">
|
||||
<i class="icon alt major fa-solid fa-camera"></i>
|
||||
</div>
|
||||
<h3 class="text-lg mb-2">Simultaneous Multi-Camera Operation</h3>
|
||||
<p>
|
||||
PhotonVision can run as many cameras as your hardware can handle
|
||||
</p>
|
||||
</section>
|
||||
<section class="relative pl-16">
|
||||
<div class="features-icon">
|
||||
<i class="icon alt major fa-solid fa-layer-group"></i>
|
||||
</div>
|
||||
<h3 class="text-lg mb-2">Multi-Tag Pose Estimation</h3>
|
||||
<p>Fuse all your available data for peak robot performance</p>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<a href="#four" class="absolute bottom-0 p-4"
|
||||
><i class="fa-solid fa-chevron-down"></i
|
||||
></a>
|
||||
</section>
|
||||
|
||||
<!-- Four -->
|
||||
<section id="four">
|
||||
<div class="">
|
||||
<video
|
||||
src="images/in-action.mp4"
|
||||
playsinline
|
||||
autoplay
|
||||
loop
|
||||
muted
|
||||
loading="lazy"
|
||||
class="w-full h-[calc(100vh_-_56px)] object-cover bottom-0 relative"
|
||||
></video>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section
|
||||
id="five"
|
||||
class="flex flex-col md:flex-row items-center justify-between relative mt-8 py-8 px-28 gap-8 bg-primary"
|
||||
>
|
||||
<header
|
||||
class="flex flex-col gap-4 justify-center items-center text-center"
|
||||
>
|
||||
<h2 class="text-3xl">Champs 2024 Talk</h2>
|
||||
<div class="flex gap-2 mb-4">
|
||||
<a
|
||||
href="https://docs.google.com/presentation/d/1Gh5InslM5p7aDxjzK8DHoEorpATOl-MQWWixY5GjGgs/edit#slide=id.p"
|
||||
class="bg-brand-blue py-4 px-8 rounded grow-0 text-nowrap"
|
||||
>Slide Deck</a
|
||||
>
|
||||
<a
|
||||
href="https://github.com/PhotonVision/champs_2024"
|
||||
class="bg-brand-blue py-4 px-8 rounded grow-0 text-nowrap"
|
||||
>Code</a
|
||||
>
|
||||
</div>
|
||||
</header>
|
||||
<div class="self-stretch contents">
|
||||
<iframe
|
||||
src="https://www.youtube-nocookie.com/embed/iV2v7F_9GwE?si=4wgaT1IrZBpA71dF"
|
||||
title="YouTube video player"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||
referrerpolicy="strict-origin-when-cross-origin"
|
||||
allowfullscreen
|
||||
class="max-w-256 aspect-video"
|
||||
></iframe>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Eight -->
|
||||
<section
|
||||
id="six"
|
||||
class="min-h-[calc(100vh_-_56px)] flex flex-col gap-4 items-center justify-center px-14 lg:px-28"
|
||||
>
|
||||
<header
|
||||
class="flex flex-col gap-4 justify-center items-center text-center"
|
||||
>
|
||||
<h2 class="text-3xl">FOSS</h2>
|
||||
<p class="text-2xl">
|
||||
PhotonVision is an open-source, community based vision system
|
||||
designed for use within the FIRST® Robotics Competition that aims
|
||||
to provide easy and inexpensive vision tracking to teams.
|
||||
</p>
|
||||
<hr class="border-brand-yellow border-2 w-64 mb-4" />
|
||||
</header>
|
||||
<div>
|
||||
<div
|
||||
class="grid max-w-xl grid-cols-1 gap-x-8 gap-y-10 lg:max-w-none lg:grid-cols-2 lg:gap-y-16"
|
||||
>
|
||||
<section class="relative pl-16">
|
||||
<div class="features-icon">
|
||||
<i class="icon alt major fa-solid fa-check"></i>
|
||||
</div>
|
||||
<h3 class="text-lg mb-2">Open Source</h3>
|
||||
<p>
|
||||
PhotonVision is the largest FOSS FRC Vision project to date,
|
||||
constantly being updated with new features and bug fixes.
|
||||
</p>
|
||||
</section>
|
||||
<section class="relative pl-16">
|
||||
<div class="features-icon">
|
||||
<i class="icon alt major fa-solid fa-balance-scale"></i>
|
||||
</div>
|
||||
<h3 class="text-lg mb-2">GNU GPL v3</h3>
|
||||
<p>
|
||||
The GNU GPL v3 license allows you to download, modify and share
|
||||
source code.
|
||||
</p>
|
||||
</section>
|
||||
<section class="relative pl-16">
|
||||
<div class="features-icon">
|
||||
<i class="icon alt major fab fa-github"></i>
|
||||
</div>
|
||||
<h3 class="text-lg mb-2">We're on GitHub</h3>
|
||||
<p>
|
||||
We do all of our development openly on GitHub. Transparency is
|
||||
key for every contributor of PhotonVision.
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Footer -->
|
||||
<footer
|
||||
id="footer"
|
||||
class="p-14 bg-zinc-700 flex flex-col items-center gap-8"
|
||||
>
|
||||
<img
|
||||
src="images/PhotonVision-Icon-BG.png"
|
||||
style="width: 50px; height: 50px"
|
||||
alt="PhotonVision logo"
|
||||
/>
|
||||
<ul class="text-sm">
|
||||
<li>©2025 PhotonVision. All rights reserved.</li>
|
||||
</ul>
|
||||
</footer>
|
||||
</div>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -5,16 +5,20 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"build": "tsc && vite-ssg build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@toolwind/anchors": "^1.0.10",
|
||||
"prettier": "^3.5.3",
|
||||
"typescript": "~5.7.2",
|
||||
"vite": "^7.1.2"
|
||||
"vite": "^7.1.2",
|
||||
"vite-ssg": "^28.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tailwindcss/vite": "^4.1.12",
|
||||
"tailwindcss": "^4.1.12"
|
||||
"@vitejs/plugin-vue": "^6.0.2",
|
||||
"tailwindcss": "^4.1.12",
|
||||
"vue": "^3.5.25"
|
||||
}
|
||||
}
|
||||
|
||||
813
website/pnpm-lock.yaml
generated
813
website/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
365
website/src/App.vue
Normal file
365
website/src/App.vue
Normal file
@@ -0,0 +1,365 @@
|
||||
<script setup lang="ts">
|
||||
import Button from "./components/Button.vue";
|
||||
import GridSection from "./components/GridSection.vue";
|
||||
|
||||
const navLinks = [
|
||||
{
|
||||
href: "https://docs.photonvision.org/en/latest/",
|
||||
label: "Documentation",
|
||||
icon: "fa-solid fa-book",
|
||||
},
|
||||
{
|
||||
href: "https://discord.gg/wYxTwym",
|
||||
label: "Discord",
|
||||
icon: "fab fa-discord",
|
||||
},
|
||||
{
|
||||
href: "https://github.com/PhotonVision/photonvision/",
|
||||
label: "GitHub",
|
||||
icon: "fab fa-github",
|
||||
},
|
||||
{
|
||||
href: "https://www.redbubble.com/people/PhotonVision/shop?asc=u",
|
||||
label: "Merch",
|
||||
icon: "fa-solid fa-shirt",
|
||||
},
|
||||
];
|
||||
|
||||
const features = [
|
||||
{
|
||||
icon: "fa-solid fa-location-arrow",
|
||||
title: "First-Class AprilTag Support",
|
||||
description: "FRC Target tracking, out of the box.",
|
||||
},
|
||||
{
|
||||
icon: "fa-solid fa-chess-board",
|
||||
title: "Built-In Camera Calibration",
|
||||
description:
|
||||
"Per-camera intrinsics calibration maximizes accuracy of homography",
|
||||
},
|
||||
{
|
||||
icon: "fa-solid fa-brain",
|
||||
title: "Machine Learning",
|
||||
description: "Hardware-accelerated inferencing for gamepiece detection",
|
||||
},
|
||||
{
|
||||
icon: "fa-solid fa-eye",
|
||||
title: "Driver Mode Integration",
|
||||
description: "Use the same camera for driving and robot vision",
|
||||
},
|
||||
{
|
||||
icon: "fa-solid fa-camera",
|
||||
title: "Simultaneous Multi-Camera Operation",
|
||||
description:
|
||||
"PhotonVision can run as many cameras as your hardware can handle",
|
||||
},
|
||||
{
|
||||
icon: "fa-solid fa-layer-group",
|
||||
title: "Multi-Tag Pose Estimation",
|
||||
description: "Fuse all your available data for peak robot performance",
|
||||
},
|
||||
];
|
||||
|
||||
const fossFeatures = [
|
||||
{
|
||||
icon: "fa-solid fa-check",
|
||||
title: "Open Source",
|
||||
description:
|
||||
"PhotonVision is the largest FOSS FRC Vision project to date, constantly being updated with new features and bug fixes.",
|
||||
},
|
||||
{
|
||||
icon: "fa-solid fa-balance-scale",
|
||||
title: "GNU GPL v3",
|
||||
description:
|
||||
"The GNU GPL v3 license allows you to download, modify and share source code.",
|
||||
},
|
||||
{
|
||||
icon: "fab fa-github",
|
||||
title: "We're on GitHub",
|
||||
description:
|
||||
"We do all of our development openly on GitHub. Transparency is key for every contributor of PhotonVision.",
|
||||
},
|
||||
];
|
||||
|
||||
const socialLinks = [
|
||||
{
|
||||
href: "https://github.com/PhotonVision/photonvision/",
|
||||
icon: "fab fa-github",
|
||||
label: "GitHub",
|
||||
},
|
||||
{
|
||||
href: "https://discord.gg/wYxTwym",
|
||||
icon: "fab fa-discord",
|
||||
label: "Discord",
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="page-wrapper" class="h-screen overflow-y-auto scroll-smooth">
|
||||
<header
|
||||
id="header"
|
||||
class="bg-zinc-900/80 backdrop-blur-md flex items-center justify-between sticky top-0 w-full z-50 border-b border-zinc-700/50 px-4 md:px-8"
|
||||
>
|
||||
<a href="#" class="flex items-center gap-3 py-2 group">
|
||||
<img
|
||||
src="/images/PhotonVision-Icon-BG.png"
|
||||
alt="PhotonVision"
|
||||
class="w-10 h-10 group-hover:scale-110 transition-transform duration-300"
|
||||
/>
|
||||
<span class="font-bold text-xl hidden sm:block text-white">
|
||||
PhotonVision
|
||||
</span>
|
||||
</a>
|
||||
<div>
|
||||
<!-- Mobile menu button -->
|
||||
<button
|
||||
class="p-3 hover:bg-zinc-700/50 rounded-lg cursor-pointer flex md:!hidden transition-colors anchor/my-anchor"
|
||||
popovertarget="mobile-nav"
|
||||
aria-label="Open mobile navigation menu"
|
||||
>
|
||||
<i class="fa-solid fa-bars text-xl"></i>
|
||||
</button>
|
||||
|
||||
<div class="relative">
|
||||
<div
|
||||
popover
|
||||
id="mobile-nav"
|
||||
class="bg-zinc-900/95 backdrop-blur-lg transition-opacity starting:open:opacity-0 open:opacity-100 opacity-0 duration-300 transition-discrete open:flex open:flex-col md:open:hidden items-center justify-center gap-2 anchored/my-anchor anchored-bottom-span-left overflow-clip p-2 rounded-b-2xl"
|
||||
>
|
||||
<a
|
||||
v-for="link in navLinks"
|
||||
:key="link.href"
|
||||
:href="link.href"
|
||||
class="flex items-center gap-3 px-6 py-4 text-xl text-white hover:text-brand-yellow transition-colors"
|
||||
>
|
||||
<i :class="link.icon"></i>
|
||||
{{ link.label }}
|
||||
</a>
|
||||
<Button
|
||||
href="https://demo.photonvision.org"
|
||||
variant="primary"
|
||||
size="sm"
|
||||
>
|
||||
Demo
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Desktop nav -->
|
||||
<nav id="nav" class="hidden md:flex items-center gap-1">
|
||||
<a
|
||||
v-for="link in navLinks"
|
||||
:key="link.href"
|
||||
:href="link.href"
|
||||
class="flex items-center gap-2 px-4 py-2 rounded-lg hover:bg-zinc-700/50 hover:text-brand-yellow transition-all duration-200"
|
||||
>
|
||||
<i :class="[link.icon, 'text-sm opacity-70']"></i>
|
||||
{{ link.label }}
|
||||
</a>
|
||||
<Button
|
||||
href="https://demo.photonvision.org"
|
||||
variant="primary"
|
||||
size="sm"
|
||||
class="ml-2"
|
||||
>
|
||||
Demo
|
||||
</Button>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<section
|
||||
class="flex flex-col min-h-[calc(100vh_-_56px)] md:justify-center items-center p-8 md:p-16 relative overflow-hidden"
|
||||
>
|
||||
<div
|
||||
class="flex justify-center md:justify-start flex-col md:flex-row items-start"
|
||||
>
|
||||
<span class="self-center md:self-initial mb-8 md:mb-0 md:me-12 shrink">
|
||||
<img
|
||||
src="/images/PhotonVision-Icon-BG.png"
|
||||
alt="PhotonVision Logo"
|
||||
class="max-w-20 md:max-w-80 drop-shadow-2xl md:p-0 transition-transform duration-500"
|
||||
/>
|
||||
</span>
|
||||
<header
|
||||
class="flex flex-col gap-6 items-center md:items-start justify-center text-center md:text-start"
|
||||
>
|
||||
<h2
|
||||
class="text-5xl md:text-6xl font-bold drop-shadow-lg font-heading"
|
||||
>
|
||||
PhotonVision
|
||||
</h2>
|
||||
<div
|
||||
class="text-xl md:text-2xl max-w-128 text-zinc-300 leading-relaxed"
|
||||
>
|
||||
PhotonVision is the free, fast, and easy-to-use computer vision
|
||||
solution for the FIRST® Robotics Competition. Teams can download a
|
||||
PhotonVision image for select coprocessors and start tracking
|
||||
targets in minutes.
|
||||
</div>
|
||||
<Button
|
||||
href="https://docs.photonvision.org/en/latest/docs/quick-start/quick-install.html"
|
||||
variant="primary"
|
||||
size="lg"
|
||||
class="self-center md:self-start rounded-xl"
|
||||
>
|
||||
Get Started
|
||||
</Button>
|
||||
</header>
|
||||
</div>
|
||||
<a
|
||||
href="#demo"
|
||||
class="absolute bottom-8 p-4 text-brand-yellow/70 hover:text-brand-yellow hover:translate-y-1 transition-all duration-300 animate-bounce"
|
||||
>
|
||||
<i class="fa-solid fa-chevron-down text-2xl"></i>
|
||||
</a>
|
||||
</section>
|
||||
|
||||
<section
|
||||
id="demo"
|
||||
class="min-h-[calc(100vh_-_56px)] relative justify-center flex items-center py-16 bg-zinc-950"
|
||||
>
|
||||
<div class="relative mx-4 md:mx-16 lg:mx-32">
|
||||
<div
|
||||
class="absolute -inset-4 bg-gradient-to-r from-primary via-brand-blue to-brand-yellow rounded-2xl blur-xl opacity-30"
|
||||
></div>
|
||||
<img
|
||||
src="/images/demo.png"
|
||||
alt="Demo of PhotonVision UI"
|
||||
loading="lazy"
|
||||
class="relative rounded-xl shadow-2xl border border-zinc-700/50"
|
||||
/>
|
||||
</div>
|
||||
<a
|
||||
href="#features"
|
||||
class="absolute bottom-8 p-4 text-brand-yellow/70 hover:text-brand-yellow hover:translate-y-1 transition-all duration-300"
|
||||
>
|
||||
<i class="fa-solid fa-chevron-down text-2xl"></i>
|
||||
</a>
|
||||
</section>
|
||||
|
||||
<GridSection
|
||||
id="features"
|
||||
description="PhotonVision is a powerful, open-source vision system for FRC. It's designed to be fast and easy to use, regardless of your team's financial or technical resources."
|
||||
:features="features"
|
||||
:columns="2"
|
||||
show-scroll-indicator
|
||||
scroll-target="#video"
|
||||
>
|
||||
<template #title>
|
||||
The Future is in <span class="text-brand-yellow">Sight</span>
|
||||
</template>
|
||||
</GridSection>
|
||||
|
||||
<section id="video" class="relative">
|
||||
<div class="relative">
|
||||
<video
|
||||
src="/images/in-action.mp4"
|
||||
playsinline
|
||||
autoplay
|
||||
loop
|
||||
muted
|
||||
class="w-full h-[calc(100vh_-_56px)] object-cover"
|
||||
></video>
|
||||
<div
|
||||
class="absolute inset-0 bg-gradient-to-t from-zinc-900/60 via-transparent to-zinc-900/30 pointer-events-none"
|
||||
></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section
|
||||
id="champs"
|
||||
class="flex flex-col lg:flex-row items-center justify-center relative py-16 px-8 md:px-16 lg:px-28 gap-12 bg-primary"
|
||||
>
|
||||
<header
|
||||
class="flex flex-col gap-6 justify-center items-center lg:items-start text-center lg:text-left"
|
||||
>
|
||||
<h2 class="text-4xl font-bold font-heading">Champs 2024 Talk</h2>
|
||||
<p class="text-zinc-200 text-lg max-w-md">
|
||||
Watch our presentation from the 2024 FIRST Championship and learn how
|
||||
to get the most out of PhotonVision.
|
||||
</p>
|
||||
<div class="flex gap-4">
|
||||
<Button
|
||||
href="https://docs.google.com/presentation/d/1Gh5InslM5p7aDxjzK8DHoEorpATOl-MQWWixY5GjGgs/edit#slide=id.p"
|
||||
variant="secondary"
|
||||
>
|
||||
Slide Deck
|
||||
</Button>
|
||||
<Button
|
||||
href="https://github.com/PhotonVision/champs_2024"
|
||||
variant="outline"
|
||||
>
|
||||
View Code
|
||||
</Button>
|
||||
</div>
|
||||
</header>
|
||||
<div class="flex-1 max-w-3xl w-full">
|
||||
<div
|
||||
class="relative rounded-xl overflow-hidden shadow-2xl border border-white/10"
|
||||
>
|
||||
<iframe
|
||||
src="https://www.youtube-nocookie.com/embed/iV2v7F_9GwE?si=4wgaT1IrZBpA71dF"
|
||||
title="YouTube video player"
|
||||
frameborder="0"
|
||||
allow="
|
||||
accelerometer;
|
||||
autoplay;
|
||||
clipboard-write;
|
||||
encrypted-media;
|
||||
gyroscope;
|
||||
picture-in-picture;
|
||||
web-share;
|
||||
"
|
||||
referrerpolicy="strict-origin-when-cross-origin"
|
||||
allowfullscreen
|
||||
class="w-full aspect-video"
|
||||
></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<GridSection
|
||||
id="foss"
|
||||
description="PhotonVision is an open-source, community based vision system designed for use within the FIRST® Robotics Competition that aims to provide easy and inexpensive vision tracking to teams."
|
||||
:features="fossFeatures"
|
||||
:columns="3"
|
||||
reverse-cards
|
||||
>
|
||||
<template #title>
|
||||
Built by the <span class="text-brand-yellow">Community</span>
|
||||
</template>
|
||||
</GridSection>
|
||||
|
||||
<footer id="footer" class="py-12 px-8 bg-zinc-800 border-t border-zinc-700">
|
||||
<div
|
||||
class="max-w-6xl mx-auto flex flex-col md:flex-row items-center justify-between gap-8"
|
||||
>
|
||||
<div class="flex items-center gap-4">
|
||||
<img
|
||||
src="/images/PhotonVision-Icon-BG.png"
|
||||
class="w-12 h-12 hover:scale-110 transition-transform duration-300"
|
||||
alt="PhotonVision logo"
|
||||
/>
|
||||
<span class="font-semibold text-lg">PhotonVision</span>
|
||||
</div>
|
||||
<div class="flex gap-6">
|
||||
<a
|
||||
v-for="link in socialLinks"
|
||||
:key="link.href"
|
||||
:href="link.href"
|
||||
class="text-zinc-400 hover:text-brand-yellow transition-colors"
|
||||
:aria-label="link.label"
|
||||
>
|
||||
<i :class="[link.icon, 'text-2xl']"></i>
|
||||
</a>
|
||||
</div>
|
||||
<p class="text-sm text-zinc-400">
|
||||
©{{ new Date().getFullYear() }} PhotonVision. All rights
|
||||
reserved.
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
33
website/src/components/Button.vue
Normal file
33
website/src/components/Button.vue
Normal file
@@ -0,0 +1,33 @@
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
href: string;
|
||||
variant?: "primary" | "secondary" | "outline";
|
||||
size?: "sm" | "md" | "lg";
|
||||
}>();
|
||||
|
||||
const variantClasses = {
|
||||
primary:
|
||||
"bg-primary shadow-lg shadow-primary/30 hover:shadow-xl hover:shadow-primary/40 hover:scale-105",
|
||||
secondary: "bg-brand-blue hover:bg-brand-blue/80 shadow-lg",
|
||||
outline: "bg-zinc-800 hover:bg-zinc-700 shadow-lg border border-zinc-600",
|
||||
};
|
||||
|
||||
const sizeClasses = {
|
||||
sm: "py-2 px-4 text-sm",
|
||||
md: "py-3 px-6",
|
||||
lg: "py-4 px-10 text-lg",
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<a
|
||||
:href="href"
|
||||
:class="[
|
||||
'rounded-lg font-medium text-nowrap transition-all duration-300 inline-block text-center',
|
||||
variantClasses[variant ?? 'primary'],
|
||||
sizeClasses[size ?? 'md'],
|
||||
]"
|
||||
>
|
||||
<slot />
|
||||
</a>
|
||||
</template>
|
||||
35
website/src/components/FeatureCard.vue
Normal file
35
website/src/components/FeatureCard.vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
icon: string;
|
||||
title: string;
|
||||
description: string;
|
||||
reverse?: boolean;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section
|
||||
:class="[
|
||||
'relative rounded-xl bg-zinc-800/50 border border-zinc-700/50 flex flex-col',
|
||||
reverse ? 'p-8' : 'p-6',
|
||||
]"
|
||||
>
|
||||
<div
|
||||
:class="[
|
||||
'flex items-center justify-center rounded-xl bg-linear-to-br from-brand-blue to-primary shadow-lg',
|
||||
'size-12 rounded-2xl mb-4',
|
||||
]"
|
||||
>
|
||||
<i :class="[icon, reverse ? 'text-2xl' : '']"></i>
|
||||
</div>
|
||||
<h3
|
||||
:class="[
|
||||
'font-semibold text-brand-yellow',
|
||||
reverse ? 'text-xl mb-3' : 'text-xl mb-2',
|
||||
]"
|
||||
>
|
||||
{{ title }}
|
||||
</h3>
|
||||
<p class="text-zinc-300">{{ description }}</p>
|
||||
</section>
|
||||
</template>
|
||||
77
website/src/components/GridSection.vue
Normal file
77
website/src/components/GridSection.vue
Normal file
@@ -0,0 +1,77 @@
|
||||
<script setup lang="ts">
|
||||
import FeatureCard from "./FeatureCard.vue";
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
id: string;
|
||||
label?: string;
|
||||
title?: string;
|
||||
description: string;
|
||||
features: {
|
||||
icon: string;
|
||||
title: string;
|
||||
description: string;
|
||||
}[];
|
||||
columns?: 2 | 3;
|
||||
reverseCards?: boolean;
|
||||
showScrollIndicator?: boolean;
|
||||
scrollTarget?: string;
|
||||
}>(),
|
||||
{
|
||||
columns: 2,
|
||||
reverseCards: false,
|
||||
showScrollIndicator: false,
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section
|
||||
:id="id"
|
||||
class="min-h-[calc(100vh_-_56px)] flex flex-col gap-8 items-center justify-center px-4 md:px-14 lg:px-28 py-20 relative overflow-hidden"
|
||||
>
|
||||
<header
|
||||
class="flex flex-col gap-6 justify-center items-center text-center max-w-4xl relative z-10"
|
||||
>
|
||||
<span
|
||||
v-if="label"
|
||||
class="text-brand-blue font-semibold tracking-wider uppercase text-sm"
|
||||
>
|
||||
{{ label }}
|
||||
</span>
|
||||
<h2 class="text-4xl md:text-5xl font-bold font-heading">
|
||||
<slot name="title">
|
||||
{{ title }}
|
||||
</slot>
|
||||
</h2>
|
||||
<p class="text-xl md:text-2xl text-zinc-300 leading-relaxed">
|
||||
{{ description }}
|
||||
</p>
|
||||
<div class="w-24 h-1 bg-brand-blue rounded-full"></div>
|
||||
</header>
|
||||
|
||||
<div :class="label ? 'relative z-10' : 'mb-8 lg:mb-0'">
|
||||
<div
|
||||
class="grid max-w-5xl grid-cols-1 gap-6"
|
||||
:class="columns === 3 ? 'lg:grid-cols-3' : 'lg:grid-cols-2'"
|
||||
>
|
||||
<FeatureCard
|
||||
v-for="feature in features"
|
||||
:key="feature.title"
|
||||
:icon="feature.icon"
|
||||
:title="feature.title"
|
||||
:description="feature.description"
|
||||
:reverse="reverseCards"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a
|
||||
v-if="showScrollIndicator && scrollTarget"
|
||||
:href="scrollTarget"
|
||||
class="absolute bottom-8 p-4 text-brand-yellow/70 hover:text-brand-yellow hover:translate-y-1 transition-all duration-300"
|
||||
>
|
||||
<i class="fa-solid fa-chevron-down text-2xl"></i>
|
||||
</a>
|
||||
</section>
|
||||
</template>
|
||||
@@ -1,15 +1,12 @@
|
||||
@import "tailwindcss";
|
||||
@import "@toolwind/anchors";
|
||||
|
||||
@theme {
|
||||
--color-primary: #006492;
|
||||
--color-brand-yellow: #ffd842;
|
||||
--color-brand-blue: #39a4d6;
|
||||
}
|
||||
|
||||
.header-btn {
|
||||
@apply hover:text-brand-yellow text-white flex p-4 transition-colors;
|
||||
}
|
||||
.features-icon {
|
||||
@apply absolute top-0 left-0 flex size-10 items-center justify-center rounded-lg bg-brand-blue;
|
||||
--font-sans: "Lato", sans-serif;
|
||||
--font-heading: "Prompt", sans-serif;
|
||||
}
|
||||
|
||||
.fas::before,
|
||||
|
||||
7
website/src/env.d.ts
vendored
Normal file
7
website/src/env.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
declare module "*.vue" {
|
||||
import type { DefineComponent } from "vue";
|
||||
const component: DefineComponent<{}, {}, any>;
|
||||
export default component;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { ViteSSG } from "vite-ssg/single-page";
|
||||
import App from "./App.vue";
|
||||
import "./css/main.css";
|
||||
|
||||
export const createApp = ViteSSG(App);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { defineConfig } from "vite";
|
||||
import tailwindcss from "@tailwindcss/vite";
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [tailwindcss()],
|
||||
plugins: [vue(), tailwindcss()],
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user