// layout.tsx
export const viewport: Viewport = {
width: "device-width",
initialScale: 1,
themeColor: [
{ media: "(prefers-color-scheme: light)", color: "white" },
{ media: "(prefers-color-scheme: dark)", color: "#0f172a" },
],
};
export const metadata: Metadata = {
metadataBase: new URL(env.NEXT_PUBLIC_APP_URL),
title: {
default: siteConfig.name,
template: `%s | ${siteConfig.name}`,
},
description: siteConfig.description,
keywords: [
"Web Development Agency",
"Professional Services",
"Responsive Design",
"E-commerce Solutions",
"SEO Optimization",
"Brand Identity",
"Custom Design",
"Digital Solutions",
"User Experience",
],
authors: [{ name: "Sun Sreng", url: "https://service.gmana.co" }],
creator: "Sun Sreng",
openGraph: {
title: siteConfig.name,
description: siteConfig.description,
url: env.NEXT_PUBLIC_APP_URL,
siteName: siteConfig.name,
locale: "en_US",
type: "website",
images: [
{
url: siteConfig.ogImage,
width: 1200,
height: 600,
alt: siteConfig.name,
},
],
},
robots: {
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
"max-video-preview": -1,
"max-image-preview": "large",
"max-snippet": -1,
},
},
twitter: {
title: siteConfig.name,
card: "summary_large_image",
},
other: {
"google-adsense-account": "ca-pub-xxxx",
},
};
export default function RootLayout({ children }: PropsWithChildren) {
return (
<html lang="en" suppressHydrationWarning className={cn(fontGmana.variable, fontSans.variable, fontMono.variable)}>
<body className="min-h-scree font-sans text-base">
{children}
<Script
async
src={`https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=${process.env.NEXT_PUBLIC_GOOGLE_ADS_CLIENT_ID}`}
strategy="lazyOnload"
crossOrigin="anonymous"
></Script>
</body>
</html>
);
}
// ads-banner.tsx
"use client";
import { useEffect, useRef } from "react";
declare global {
interface Window {
adsbygoogle: unknown[];
}
}
interface AdsBannerProps {
"data-ad-slot": string;
"data-ad-format": string;
"data-full-width-responsive": string;
"data-ad-layout"?: string;
}
const AdBanner = (props: AdsBannerProps) => {
const adRef = useRef<HTMLModElement | null>(null);
useEffect(() => {
try {
if (adRef.current && !adRef.current.dataset.adInitialized) {
window.adsbygoogle = window.adsbygoogle || [];
window.adsbygoogle.push({});
adRef.current.dataset.adInitialized = "true";
}
} catch (err) {
console.error("Error initializing ads: ", err);
}
}, []);
return (
<ins
ref={adRef}
className="adsbygoogle adbanner-customize mt-2"
style={{
display: "block",
overflow: "hidden",
border: process.env.NODE_ENV === "development" ? "1px solid red" : "none",
}}
data-adtest="on"
data-ad-client={process.env.NEXT_PUBLIC_GOOGLE_ADS_CLIENT_ID}
{...props}
/>
);
};
export default AdBanner;
// ads-blogs
"use client";
import dynamic from "next/dynamic";
export const AdBlog = dynamic(() => import("@/components/ads/google-ads-unit"), {
ssr: false,
loading: () => null, // Optional: add a loading state if needed
});
// blog.tsx
<AdBlog data-ad-slot="xxxxx" data-full-width-responsive="true" data-ad-layout="in-article" data-ad-format="fluid" />
192 views