From 4f978d142d6b0ce27c0ca2a4367c5c197253c27d Mon Sep 17 00:00:00 2001 From: GiFTED! Date: Sun, 12 Jul 2026 19:44:31 +0100 Subject: [PATCH] =?UTF-8?q?feat(website):=20add=20full=20technical=20SEO?= =?UTF-8?q?=20=E2=80=94=20metadata,=20JSON-LD,=20sitemap,=20favicon,=20OG?= =?UTF-8?q?=20images?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/website/app/apple-icon.tsx | 37 +++++++++ apps/website/app/icon.svg | 17 ++++ apps/website/app/layout.tsx | 113 +++++++++++++++++++++++++-- apps/website/app/opengraph-image.tsx | 103 ++++++++++++++++++++++++ apps/website/app/robots.ts | 13 +++ apps/website/app/sitemap.ts | 13 +++ apps/website/app/twitter-image.tsx | 1 + apps/website/lib/site.ts | 2 + apps/website/next.config.mjs | 8 ++ 9 files changed, 299 insertions(+), 8 deletions(-) create mode 100644 apps/website/app/apple-icon.tsx create mode 100644 apps/website/app/icon.svg create mode 100644 apps/website/app/opengraph-image.tsx create mode 100644 apps/website/app/robots.ts create mode 100644 apps/website/app/sitemap.ts create mode 100644 apps/website/app/twitter-image.tsx diff --git a/apps/website/app/apple-icon.tsx b/apps/website/app/apple-icon.tsx new file mode 100644 index 0000000..522b00a --- /dev/null +++ b/apps/website/app/apple-icon.tsx @@ -0,0 +1,37 @@ +import { ImageResponse } from "next/og"; + +export const size = { width: 180, height: 180 }; +export const contentType = "image/png"; + +export default function AppleIcon() { + return new ImageResponse( + ( +
+ + + + + + + + +
+ ), + { ...size } + ); +} diff --git a/apps/website/app/icon.svg b/apps/website/app/icon.svg new file mode 100644 index 0000000..9437aee --- /dev/null +++ b/apps/website/app/icon.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/apps/website/app/layout.tsx b/apps/website/app/layout.tsx index cf17419..63e5e4e 100644 --- a/apps/website/app/layout.tsx +++ b/apps/website/app/layout.tsx @@ -1,5 +1,6 @@ import type { Metadata } from "next"; import { Archivo, JetBrains_Mono } from "next/font/google"; +import { SITE_URL, GITHUB_URL, GITHUB_ORG_URL } from "@/lib/site"; import "./globals.css"; const archivo = Archivo({ @@ -14,25 +15,121 @@ const jetbrainsMono = JetBrains_Mono({ display: "swap" }); +const OG_IMAGE = `${SITE_URL}/opengraph-image`; +const ICON_URL = `${SITE_URL}/icon.svg`; + +const DESCRIPTION = + "Pontoon is a local-first desktop tool for @ton/sandbox. Deploy contracts, send messages, and watch the whole async transaction tree: phase-level fees, TVM traces, and state, without reading raw VM logs."; + export const metadata: Metadata = { - metadataBase: new URL("https://pontoon.entrypointlabs.xyz"), - title: "Pontoon: the desktop inspector for @ton/sandbox", - description: - "Pontoon is a local-first desktop tool for @ton/sandbox. Deploy contracts, send messages, and watch the whole async transaction tree: phase-level fees, TVM traces, and state, without reading raw VM logs.", - keywords: ["TON", "@ton/sandbox", "Blueprint", "TVM", "smart contracts", "debugger", "desktop"], + metadataBase: new URL(SITE_URL), + title: { + template: "%s | Pontoon", + default: "Pontoon: the desktop inspector for @ton/sandbox" + }, + description: DESCRIPTION, + keywords: [ + "debug ton smart contracts locally", + "ton sandbox transaction inspector", + "visualize async ton transactions", + "step through tvm bytecode", + "ton gas fee breakdown per transaction", + "func tact test coverage and gas benchmarks", + "local ton blockchain sandbox debugger", + "blueprint ton smart contract testing tool" + ], + alternates: { + canonical: "/" + }, + robots: { + index: true, + follow: true, + googleBot: { + index: true, + follow: true, + "max-image-preview": "large", + "max-snippet": -1, + "max-video-preview": -1 + } + }, openGraph: { + type: "website", + locale: "en_US", + url: SITE_URL, + siteName: "Pontoon", + title: "Pontoon: the desktop inspector for @ton/sandbox", + description: "Make TON's async execution visible. A local-first desktop debugger for @ton/sandbox." + }, + twitter: { + card: "summary_large_image", title: "Pontoon: the desktop inspector for @ton/sandbox", - description: - "Make TON's async execution visible. A local-first desktop debugger for @ton/sandbox.", - type: "website" + description: "Make TON's async execution visible. A local-first desktop debugger for @ton/sandbox." + }, + formatDetection: { + telephone: false, + email: false, + address: false } }; +const jsonLd = { + "@context": "https://schema.org", + "@graph": [ + { + "@type": "Organization", + "@id": `${SITE_URL}#org`, + name: "Entrypoint Labs", + url: "https://entrypointlabs.xyz", + logo: ICON_URL, + sameAs: [GITHUB_ORG_URL] + }, + { + "@type": "WebSite", + "@id": `${SITE_URL}#website`, + url: SITE_URL, + name: "Pontoon", + description: DESCRIPTION, + publisher: { "@id": `${SITE_URL}#org` } + }, + { + "@type": "SoftwareApplication", + "@id": `${SITE_URL}#app`, + name: "Pontoon", + url: SITE_URL, + image: OG_IMAGE, + description: DESCRIPTION, + applicationCategory: "DeveloperApplication", + operatingSystem: "macOS", + featureList: [ + "Transaction-tree inspector", + "Phase-level fee breakdown", + "TVM step debugger", + "Cell & TL-B viewer", + "Snapshots & time control", + "Coverage & benchmarks" + ], + offers: { + "@type": "Offer", + price: "0", + priceCurrency: "USD" + }, + publisher: { "@id": `${SITE_URL}#org` }, + sameAs: [GITHUB_URL] + } + ] +}; + export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) { return ( + +