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
3 changes: 0 additions & 3 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ export const metadata: Metadata = {
description:
"Collect bug reports with screenshots in 30 seconds. Open source feedback widget that creates GitHub issues automatically.",
},
alternates: {
canonical: "https://bugdrop.dev",
},
};

export default function RootLayout({
Expand Down
105 changes: 105 additions & 0 deletions src/app/opengraph-image.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { ImageResponse } from "next/og";

export const runtime = "edge";
export const alt = "BugDrop - In-app feedback to GitHub Issues";
export const size = { width: 1200, height: 630 };
export const contentType = "image/png";

export default function OgImage() {
return new ImageResponse(
(
<div
style={{
background: "#1a1b26",
width: "100%",
height: "100%",
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
fontFamily: "system-ui, sans-serif",
position: "relative",
overflow: "hidden",
}}
>
{/* Background gradients */}
<div
style={{
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
background:
"radial-gradient(ellipse 80% 50% at 20% 40%, rgba(255,158,100,0.12) 0%, transparent 50%), radial-gradient(ellipse 60% 40% at 80% 20%, rgba(125,207,255,0.08) 0%, transparent 50%)",
}}
/>

{/* Bug emoji */}
<div style={{ fontSize: 72, marginBottom: 16, display: "flex" }}>
🐛
</div>

{/* Title */}
<div
style={{
fontSize: 64,
fontWeight: 700,
color: "#c0caf5",
marginBottom: 12,
display: "flex",
}}
>
BugDrop
</div>

{/* Tagline */}
<div
style={{
fontSize: 28,
color: "#787c99",
marginBottom: 32,
display: "flex",
}}
>
In-app feedback → GitHub Issues
</div>

{/* Feature pills */}
<div style={{ display: "flex", gap: 16 }}>
{["Screenshots", "Annotations", "System Info"].map((label) => (
<div
key={label}
style={{
background: "#24283b",
border: "1px solid #3b4261",
borderRadius: 24,
padding: "10px 24px",
color: "#ff9e64",
fontSize: 20,
fontWeight: 500,
display: "flex",
}}
>
{label}
</div>
))}
</div>

{/* Domain */}
<div
style={{
position: "absolute",
bottom: 32,
fontSize: 20,
color: "#565f89",
display: "flex",
}}
>
bugdrop.dev
</div>
</div>
),
{ ...size },
);
}
34 changes: 34 additions & 0 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,44 @@ import { StylingShowcase } from "@/components/landing/styling-showcase";
import { QuickStart } from "@/components/landing/quick-start";
import { ConfigTable } from "@/components/landing/config-table";
import { TryCallout } from "@/components/landing/try-callout";
import { JsonLd } from "@/components/json-ld";

const structuredData = {
"@context": "https://schema.org",
"@type": "SoftwareApplication",
name: "BugDrop",
description:
"Open-source in-app feedback widget that turns user bug reports into GitHub issues with screenshots, annotations, and system info.",
url: "https://bugdrop.dev",
applicationCategory: "DeveloperApplication",
operatingSystem: "Web",
offers: {
"@type": "Offer",
price: "0",
priceCurrency: "USD",
},
author: {
"@type": "Organization",
name: "mean-weasel",
url: "https://github.com/mean-weasel",
},
license: "https://opensource.org/licenses/MIT",
codeRepository: "https://github.com/mean-weasel/bugdrop",
featureList: [
"Screenshot capture",
"Annotation tools",
"Automatic system info",
"GitHub issue creation",
"Fully stylable widget",
"Shadow DOM isolation",
"Privacy-first design",
],
};

export default function Home() {
return (
<main>
<JsonLd data={structuredData} />
<Hero />
<HowItWorks />
<DemoVideo />
Expand Down
12 changes: 12 additions & 0 deletions src/components/json-ld.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Renders JSON-LD structured data as a script tag.
* Safe: data is a static object defined at build time, not user input.
*/
export function JsonLd({ data }: { data: Record<string, unknown> }) {
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(data) }}
/>
);
}
Loading