Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions src/components/content/LandingHero.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
---
/*
Import the visual sub-components so the landing hero
only handles layout + text content.
*/
import HeroRibbon from "../hero/HeroRibbon.astro";
import HeroDashboard from "../hero/HeroDashboard.astro";

/*
Props allow this component to be reused with different text
without modifying the layout or styling.
*/
const {
eyebrow = "UBC Agrobot",
title = "Robotics for agriculture",
subtitle = "We design and build field-ready systems. For perception, autonomy, and real-world deployment.",
primaryCta = { label: "Get involved", href: "/recruitment" },
secondaryCta = { label: "Explore projects", href: "/projects" },
} = Astro.props;
---

<!--
Hero section container.

relative + isolate:
Creates a local stacking context so the background, ribbon,
and content layer in a predictable way.
-->
<section class="relative isolate">
<!-- Subtle page background -->
<div class="pointer-events-none absolute inset-0 -z-20">
<div
class="absolute inset-0 bg-gradient-to-b from-white via-white to-slate-50"
>
</div>
</div>

<!-- Animated Stripe-style ribbon -->
<HeroRibbon />

<!-- Main content wrapper -->
<div class="mx-auto max-w-6xl px-6">
<!--
12-column responsive hero layout.

Left = text content
Right = product/dashboard mock
-->
<div
class="grid min-h-[calc(100vh-var(--header-height,5rem))] items-center gap-12 py-16 lg:grid-cols-12"
>
<!-- Left: hero messaging -->
<div class="lg:col-span-6">
<p class="text-sm font-semibold tracking-wide text-emerald-700">
{eyebrow}
</p>

<h1
class="mt-4 text-4xl leading-[1.05] font-semibold tracking-tight text-slate-900 sm:text-5xl md:text-6xl"
>
{title}
</h1>

<p class="mt-5 text-lg leading-relaxed text-slate-700 sm:text-xl">
{subtitle}
</p>

<!-- CTA buttons -->
<div class="mt-8 flex flex-col gap-3 sm:flex-row sm:items-center">
<a
href={primaryCta.href}
class="inline-flex items-center justify-center rounded-full bg-emerald-600 px-6 py-3 text-base font-semibold text-white transition hover:bg-emerald-700"
>
{primaryCta.label}
</a>

<a
href={secondaryCta.href}
class="inline-flex items-center justify-center rounded-full bg-white px-6 py-3 text-base font-semibold text-slate-900 ring-1 ring-slate-200 transition hover:bg-slate-50 hover:ring-slate-300"
>
{secondaryCta.label}
</a>
</div>

<!-- Small supporting tagline -->
<p class="mt-6 text-sm text-slate-500">
Build • Test • Deploy • Iterate
</p>
</div>

<!-- Right: dashboard visual -->
<div class="lg:col-span-6">
<HeroDashboard />
</div>
</div>
</div>
</section>
133 changes: 133 additions & 0 deletions src/components/hero/HeroDashboard.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
---
/*
Dashboard mock shown on the right side of the landing hero.

This simulates a robotics/computer vision interface so the page
feels like a real product/engineering site instead of just text.
*/
---

<div class="relative mx-auto max-w-xl">
<!-- Soft blurred glow behind the dashboard card -->
<div
class="absolute -inset-6 -z-10 rounded-[28px] bg-white/70 ring-1 ring-slate-200/70 blur-xl"
>
</div>

<!-- Main dashboard card -->
<div
class="overflow-hidden rounded-[28px] bg-white shadow-[0_24px_70px_-40px_rgba(2,6,23,0.45)] ring-1 ring-slate-200"
>
<!-- Fake window bar -->
<div class="flex items-center gap-2 border-b border-slate-100 px-5 py-4">
<span class="h-2.5 w-2.5 rounded-full bg-slate-200"></span>
<span class="h-2.5 w-2.5 rounded-full bg-slate-200"></span>
<span class="h-2.5 w-2.5 rounded-full bg-slate-200"></span>
<span class="ml-2 text-xs font-medium text-slate-500">
Agrobot Dashboard
</span>
</div>

<div class="p-5">
<!-- Mock camera / computer vision feed -->
<div class="relative overflow-hidden rounded-2xl bg-slate-900">
<!-- Fake field background -->
<div
class="aspect-[16/10] w-full"
style="background: linear-gradient(180deg, #c7f9cc 0%, #95d5b2 38%, #40916c 38%, #2d6a4f 100%);"
>
</div>

<!-- Crop rows -->
<div
class="absolute inset-x-0 top-[42%] bottom-0 flex justify-evenly opacity-70"
>
<div class="h-full w-1 bg-emerald-200/40"></div>
<div class="h-full w-1 bg-emerald-200/40"></div>
<div class="h-full w-1 bg-emerald-200/40"></div>
<div class="h-full w-1 bg-emerald-200/40"></div>
</div>

<!-- Detection box: crop -->
<div
class="absolute top-[48%] left-[18%] h-16 w-14 rounded-md border-2 border-lime-300"
>
<span
class="absolute -top-6 left-0 rounded bg-lime-300 px-2 py-0.5 text-[10px] font-semibold text-slate-900"
>
crop
</span>
</div>

<!-- Detection box: weed -->
<div
class="absolute top-[58%] left-[46%] h-12 w-12 rounded-md border-2 border-emerald-300"
>
<span
class="absolute -top-6 left-0 rounded bg-emerald-300 px-2 py-0.5 text-[10px] font-semibold text-slate-900"
>
weed
</span>
</div>

<!-- Detection box: row -->
<div
class="absolute top-[52%] right-[18%] h-14 w-12 rounded-md border-2 border-sky-300"
>
<span
class="absolute -top-6 left-0 rounded bg-sky-300 px-2 py-0.5 text-[10px] font-semibold text-slate-900"
>
row
</span>
</div>

<!-- Small status chip -->
<div
class="absolute top-4 left-4 rounded-full bg-white/90 px-3 py-1 text-xs font-medium text-slate-700 shadow-sm"
>
Live vision
</div>
</div>

<!-- Robot status cards -->
<div class="mt-4 grid grid-cols-2 gap-3">
<div class="rounded-2xl bg-slate-50 p-4 ring-1 ring-slate-200">
<p class="text-xs font-medium text-slate-500">Mode</p>
<p class="mt-1 text-sm font-semibold text-slate-900">Autonomous</p>
</div>

<div class="rounded-2xl bg-slate-50 p-4 ring-1 ring-slate-200">
<p class="text-xs font-medium text-slate-500">Battery</p>
<p class="mt-1 text-sm font-semibold text-slate-900">92%</p>
</div>

<div class="rounded-2xl bg-slate-50 p-4 ring-1 ring-slate-200">
<p class="text-xs font-medium text-slate-500">Detected crops</p>
<p class="mt-1 text-sm font-semibold text-slate-900">67</p>
</div>

<div class="rounded-2xl bg-slate-50 p-4 ring-1 ring-slate-200">
<p class="text-xs font-medium text-slate-500">Path status</p>
<p class="mt-1 text-sm font-semibold text-emerald-700">On track</p>
</div>
</div>

<!-- Bottom health/status row -->
<div
class="mt-4 flex items-center justify-between rounded-2xl bg-white px-4 py-3 ring-1 ring-slate-200"
>
<div>
<p class="text-xs font-medium text-slate-500">System health</p>
<p class="text-sm font-semibold text-slate-900">Nominal</p>
</div>

<div
class="flex items-center gap-2 rounded-full bg-emerald-50 px-3 py-1 text-xs font-semibold text-emerald-700"
>
<span class="h-2 w-2 rounded-full bg-emerald-500"></span>
Online
</div>
</div>
</div>
</div>
</div>
62 changes: 62 additions & 0 deletions src/components/hero/HeroRibbon.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
/*
Animated gradient ribbon background.
*/
---

<div class="pointer-events-none absolute inset-x-[-25%] top-[62%] -z-10">
<div class="agrobot-ribbon agrobot-ribbon--blur"></div>
<div class="agrobot-ribbon"></div>
</div>

<style>
.agrobot-ribbon {
height: 220px;
width: 140%;
margin: 0 auto;
transform: rotate(-8deg);
border-radius: 999px;
opacity: 0.95;
background-size: 240% 240%;
background-position: 0% 50%;
animation: agrobotGradientMove 10s ease-in-out infinite;
background-image: linear-gradient(
115deg,
#22c55e 0%,
#10b981 18%,
#06b6d4 40%,
#60a5fa 60%,
#a3e635 78%,
#22c55e 100%
);
}

.agrobot-ribbon--blur {
position: absolute;
inset: 0;
transform: rotate(-8deg);
filter: blur(36px);
opacity: 0.6;
mix-blend-mode: multiply;
animation-duration: 12s;
}

@keyframes agrobotGradientMove {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}

@media (prefers-reduced-motion: reduce) {
.agrobot-ribbon,
.agrobot-ribbon--blur {
animation: none;
}
}
</style>
5 changes: 4 additions & 1 deletion src/pages/index.astro
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
---
import Welcome from "../components/Welcome.astro";
import Layout from "../layouts/Layout.astro";
import LandingHero from "../components/content/LandingHero.astro";

// Welcome to Astro! Wondering what to do next? Check out the Astro documentation at https://docs.astro.build
// Don't want to use any of this? Delete everything in this file, the `assets`, `components`, and `layouts` directories, and start fresh.
---

<Layout>
<Welcome />
<main class="pb-64">
<LandingHero />
</main>
</Layout>