mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-28 02:11:40 +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:
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>
|
||||
Reference in New Issue
Block a user