fixed logo, fixed product details page image and api

This commit is contained in:
2025-12-09 06:11:50 -05:00
parent 6b0e0334b0
commit 7c2206ffc3
5 changed files with 57 additions and 38 deletions
@@ -17,7 +17,7 @@ type GunbuilderProductFromApi = {
platform: string;
partRole: string;
price: number | null;
mainImageUrl: string | null;
imageUrl: string | null;
buyUrl: string | null;
};
@@ -55,21 +55,20 @@ export default function PartDetailPage() {
// For now, pull the full AR-15 list and find by UUID.
// We can optimize with a dedicated /api/products/{uuid} later.
const url = `${API_BASE_URL}/api/products/gunbuilder?platform=AR-15`;
const url = `${API_BASE_URL}/api/products/gunbuilder/products/${partId}`;
const res = await fetch(url, { signal: controller.signal });
if (!res.ok) {
throw new Error(`Failed to load product (${res.status})`);
}
const data: GunbuilderProductFromApi[] = await res.json();
const found = data.find((p) => p.id === partId) ?? null;
const data: GunbuilderProductFromApi = await res.json();
if (!found) {
if (!data) {
setError("Product not found");
}
setProduct(found);
setProduct(data);
} catch (err: any) {
if (err.name === "AbortError") return;
setError(err.message ?? "Failed to load product");
@@ -77,7 +76,7 @@ export default function PartDetailPage() {
setLoading(false);
}
}
fetchProduct();
return () => controller.abort();
@@ -187,11 +186,11 @@ export default function PartDetailPage() {
<div className="grid gap-6 md:grid-cols-[minmax(0,2fr)_minmax(0,1.3fr)] items-start">
{/* Left: image + meta */}
<div className="space-y-4">
{product.mainImageUrl && (
{product.imageUrl && (
<div className="overflow-hidden rounded-lg border border-zinc-800 bg-zinc-950">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={product.mainImageUrl}
src={product.imageUrl}
alt={product.name}
className="w-full object-contain max-h-80 bg-zinc-950"
/>
+2 -5
View File
@@ -6,6 +6,7 @@ import { useParams, useRouter } from "next/navigation";
import { CATEGORIES } from "@/data/gunbuilderParts";
import type { CategoryId, Part } from "@/types/gunbuilder";
type ViewMode = "card" | "list";
type GunbuilderProductFromApi = {
@@ -134,11 +135,6 @@ export default function CategoryPage() {
}
}, [build]);
useEffect(() => {
// whenever the category or filters change, jump back to page 1
setCurrentPage(1);
}, [categoryId, brandFilter, sortBy, searchQuery]);
// handler to toggle Add / Remove for this category
const handleTogglePart = (categoryId: CategoryId, partId: string) => {
const isSelected = build[categoryId] === partId;
@@ -293,6 +289,7 @@ export default function CategoryPage() {
return { start, end };
}, [filteredParts.length, currentPage, paginatedParts.length, PAGE_SIZE]);
if (!category) {
return (
<main className="min-h-screen bg-black text-zinc-50">
+19 -24
View File
@@ -6,9 +6,9 @@ import Image from "next/image";
export default function HomePage() {
const [email, setEmail] = useState("");
const [useCase, setUseCase] = useState("");
const [status, setStatus] = useState<"idle" | "loading" | "success" | "error">(
"idle"
);
const [status, setStatus] = useState<
"idle" | "loading" | "success" | "error"
>("idle");
const [message, setMessage] = useState<string | null>(null);
async function handleSubmit(e: FormEvent) {
@@ -47,7 +47,7 @@ export default function HomePage() {
return (
<main className="min-h-screen bg-black text-zinc-50">
{/* Abstract Brand Background */}
<div className="pointer-events-none absolute inset-0 overflow-hidden opacity-[0.065]">
<div className="pointer-events-none absolute inset-0 overflow-hidden opacity-[0.55]">
<svg
width="100%"
height="100%"
@@ -97,20 +97,15 @@ export default function HomePage() {
<header className="flex items-center justify-between gap-4">
<div className="flex items-center gap-3">
{/* Logo slot replace src with your actual logo file */}
<div className="relative h-10 w-10 overflow-hidden rounded-md border border-zinc-800 bg-zinc-900">
<div className="flex items-center">
<Image
src="/battl-logo-mark.svg"
alt="Battl Builders logo"
fill
className="object-contain p-1.5"
src="/battl/battl-logo-mark-2.svg"
alt="Battl Builders Logo"
width={260} // adjust to taste
height={48} // adjust to taste
className="block"
/>
</div>
<div>
<p className="text-xs uppercase tracking-[0.18em] text-zinc-500">
Battl Builders
</p>
</div>
</div>
<span className="rounded-full border border-amber-500/40 bg-amber-500/10 px-3 py-1 text-xs font-medium text-amber-300">
@@ -122,14 +117,15 @@ export default function HomePage() {
<section className="mt-16 grid gap-10 md:grid-cols-[minmax(0,1.3fr)_minmax(0,1fr)] md:items-center">
<div>
<h1 className="text-balance text-3xl font-semibold tracking-tight sm:text-4xl md:text-5xl">
Stop Guessing.
Stop Guessing.
<span className="block text-amber-300 py-0.16em">
Start Building
Start Building.
</span>
</h1>
<p className="mt-4 max-w-xl text-sm text-zinc-400 sm:text-base">
From part comparisons to full-build matchups, Battl Builders helps you find the right components, catch compatibility issues, and score the best deals all without juggling tabs or spreadsheets.
From part comparisons to full-build matchups, Battl Builders helps
you find the right components, catch compatibility issues, and
score the best deals all without juggling tabs or spreadsheets.
</p>
<ul className="mt-6 space-y-2 text-sm text-zinc-300">
@@ -138,7 +134,6 @@ export default function HomePage() {
<li> Live pricing from vetted merchants</li>
<li> Save & share builds with your crew</li>
<li> Vote on the cleanest, meanest setups</li>
</ul>
</div>
@@ -212,8 +207,8 @@ export default function HomePage() {
)}
<p className="pt-1 text-[10px] leading-relaxed text-zinc-500">
You can one-click unsubscribe
any time with one-click. No data games, no surprise newsletters.
You can one-click unsubscribe any time with one-click. No data
games, no surprise newsletters.
</p>
</form>
</div>
@@ -222,7 +217,7 @@ export default function HomePage() {
{/* Footer strip */}
<footer className="mt-12 border-t border-zinc-900 pt-4 text-xs text-zinc-500">
<div className="flex flex-wrap items-center justify-between gap-3">
<span>© {new Date().getFullYear()} BATTL BUILDERS</span>
<span>© {new Date().getFullYear()} BATTL BUILDERS<span className="align-super text-[0.9em] ml-0.5"></span></span>
<span className="text-zinc-600">
v0.1 Import engine online Builder UI in progress
</span>
@@ -231,4 +226,4 @@ export default function HomePage() {
</div>
</main>
);
}
}
-36
View File
@@ -1,36 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_2" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1001.79 154.88">
<defs>
<style>
.cls-1 {
font-family: AgencyFB-Bold, AgencyFB;
font-size: 134.88px;
font-weight: 700;
}
.cls-1, .cls-2 {
fill: #f0efef;
}
.cls-3 {
letter-spacing: .06em;
}
.cls-4 {
letter-spacing: .05em;
}
.cls-5 {
letter-spacing: .05em;
}
.cls-6 {
letter-spacing: 0em;
}
</style>
</defs>
<g id="Layer_1-2" data-name="Layer 1">
<text class="cls-1" transform="translate(202.12 121.28)"><tspan class="cls-5" x="0" y="0">B</tspan><tspan class="cls-6" x="69.06" y="0">A</tspan><tspan class="cls-3" x="130.83" y="0">T</tspan><tspan class="cls-4" x="191.79" y="0">TLBUILDERS</tspan></text>
<path class="cls-2" d="M155.87,0v108.05l-46.85,46.84H0V46.84L46.85,0h109.02ZM128.96,14.84H62.16v31.53h35.72l31.08-31.53ZM46.39,46.37v-24.11l-24.12,24.11h24.12ZM140.1,92.75V25.97l-31.55,31.07v35.71h31.55ZM46.39,61.21H15.77v66.78l30.62-30.14v-36.63ZM93.71,61.21h-31.55v31.53h31.55v-31.53ZM93.71,108.51h-36.65c-8.09,9.81-21.24,18.92-28.77,28.74-.72.93-1.79,1.17-1.39,2.79h65.41l1.39-1.39v-30.14ZM133.6,108.51h-25.05v24.11c1.62.4,1.85-.67,2.79-1.39,7.57-5.8,15.12-16.08,22.26-22.73Z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB