119 lines
3.5 KiB
TypeScript
119 lines
3.5 KiB
TypeScript
import type { Metadata } from "next";
|
|
import "./globals.css";
|
|
import SmoothScroll from "./components/SmoothScroll";
|
|
import Cursor from "./components/Cursor";
|
|
import { SITE, services, faqs } from "./content";
|
|
|
|
export const metadata: Metadata = {
|
|
title: "Results-driven digital marketing agency | Feedback Studios",
|
|
description: SITE.description,
|
|
// Test environment — keep everything out of search engines.
|
|
// Remove these robots directives (here + app/robots.ts + next.config.mjs
|
|
// X-Robots-Tag header) to flip the site to index when it goes live.
|
|
robots: {
|
|
index: false,
|
|
follow: false,
|
|
nocache: true,
|
|
googleBot: { index: false, follow: false },
|
|
},
|
|
};
|
|
|
|
/* JSON-LD: Organization + WebSite (+SearchAction) + Service (per core
|
|
service) + FAQPage. Structure is launch-ready; the page stays noindex
|
|
in this test env via the robots directives above. */
|
|
function StructuredData() {
|
|
const graph = [
|
|
{
|
|
"@type": "Organization",
|
|
"@id": `${SITE.url}/#organization`,
|
|
name: SITE.name,
|
|
url: SITE.url,
|
|
description: SITE.description,
|
|
email: SITE.email,
|
|
slogan: SITE.tagline,
|
|
knowsAbout: [
|
|
"digital marketing",
|
|
"search engine optimization",
|
|
"paid advertising",
|
|
"content marketing",
|
|
"social media marketing",
|
|
"conversion rate optimization",
|
|
],
|
|
},
|
|
{
|
|
"@type": "WebSite",
|
|
"@id": `${SITE.url}/#website`,
|
|
url: SITE.url,
|
|
name: SITE.name,
|
|
publisher: { "@id": `${SITE.url}/#organization` },
|
|
potentialAction: {
|
|
"@type": "SearchAction",
|
|
target: {
|
|
"@type": "EntryPoint",
|
|
urlTemplate: `${SITE.url}/?s={search_term_string}`,
|
|
},
|
|
"query-input": "required name=search_term_string",
|
|
},
|
|
},
|
|
...services.map((s) => ({
|
|
"@type": "Service",
|
|
name: s.name,
|
|
description: s.desc,
|
|
serviceType: s.name,
|
|
provider: { "@id": `${SITE.url}/#organization` },
|
|
areaServed: "Worldwide",
|
|
})),
|
|
{
|
|
"@type": "FAQPage",
|
|
"@id": `${SITE.url}/#faq`,
|
|
mainEntity: faqs.map((f) => ({
|
|
"@type": "Question",
|
|
name: f.q,
|
|
acceptedAnswer: { "@type": "Answer", text: f.a },
|
|
})),
|
|
},
|
|
];
|
|
|
|
return (
|
|
<script
|
|
type="application/ld+json"
|
|
dangerouslySetInnerHTML={{
|
|
__html: JSON.stringify({ "@context": "https://schema.org", "@graph": graph }),
|
|
}}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export default function RootLayout({
|
|
children,
|
|
}: {
|
|
children: React.ReactNode;
|
|
}) {
|
|
return (
|
|
<html lang="en">
|
|
<head>
|
|
{/* Satoshi (workhorse sans) + Newsreader (editorial display, in
|
|
globals via @import) + Spline Sans Mono (data/labels). */}
|
|
<link rel="preconnect" href="https://api.fontshare.com" crossOrigin="" />
|
|
<link
|
|
rel="stylesheet"
|
|
href="https://api.fontshare.com/v2/css?f[]=satoshi@300,400,500,700,900&display=swap"
|
|
/>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="" />
|
|
<meta name="robots" content="noindex, nofollow, noarchive, nosnippet" />
|
|
<meta name="theme-color" content="#07070b" />
|
|
</head>
|
|
<body>
|
|
<StructuredData />
|
|
<a href="#main" className="skip-link">
|
|
Skip to content
|
|
</a>
|
|
<div className="grain" aria-hidden="true" />
|
|
<SmoothScroll />
|
|
<Cursor />
|
|
{children}
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|