enzostvs HF Staff commited on
Commit
8bce833
·
1 Parent(s): 813f0e0

improve SEO

Browse files
app/[namespace]/[repoId]/page.tsx CHANGED
@@ -1,4 +1,22 @@
1
  import { AppEditor } from "@/components/editor";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  export default async function ProjectNamespacePage({
4
  params,
 
1
  import { AppEditor } from "@/components/editor";
2
+ import { generateSEO } from "@/lib/seo";
3
+ import { Metadata } from "next";
4
+
5
+ export async function generateMetadata({
6
+ params,
7
+ }: {
8
+ params: Promise<{ namespace: string; repoId: string }>;
9
+ }): Promise<Metadata> {
10
+ const { namespace, repoId } = await params;
11
+
12
+ return generateSEO({
13
+ title: `${namespace}/${repoId} - DeepSite Editor`,
14
+ description: `Edit and build ${namespace}/${repoId} with AI-powered tools on DeepSite. Create stunning websites with no code required.`,
15
+ path: `/${namespace}/${repoId}`,
16
+ // Prevent indexing of individual project editor pages if they contain sensitive content
17
+ noIndex: false, // Set to true if you want to keep project pages private
18
+ });
19
+ }
20
 
21
  export default async function ProjectNamespacePage({
22
  params,
app/layout.tsx CHANGED
@@ -13,6 +13,7 @@ import AppContext from "@/components/contexts/app-context";
13
  import TanstackContext from "@/components/contexts/tanstack-query-context";
14
  import { LoginProvider } from "@/components/contexts/login-context";
15
  import { ProProvider } from "@/components/contexts/pro-context";
 
16
 
17
  const inter = Inter({
18
  variable: "--font-inter-sans",
@@ -26,31 +27,12 @@ const ptSans = PT_Sans({
26
  });
27
 
28
  export const metadata: Metadata = {
29
- title: "DeepSite | Build with AI ✨",
30
- description:
31
- "DeepSite is a web development tool that helps you build websites with AI, no code required. Let's deploy your website with DeepSite and enjoy the magic of AI.",
32
- openGraph: {
33
  title: "DeepSite | Build with AI ✨",
34
  description:
35
  "DeepSite is a web development tool that helps you build websites with AI, no code required. Let's deploy your website with DeepSite and enjoy the magic of AI.",
36
- url: "https://deepsite.hf.co",
37
- siteName: "DeepSite",
38
- images: [
39
- {
40
- url: "https://deepsite.hf.co/banner.png",
41
- width: 1200,
42
- height: 630,
43
- alt: "DeepSite Open Graph Image",
44
- },
45
- ],
46
- },
47
- twitter: {
48
- card: "summary_large_image",
49
- title: "DeepSite | Build with AI ✨",
50
- description:
51
- "DeepSite is a web development tool that helps you build websites with AI, no code required. Let's deploy your website with DeepSite and enjoy the magic of AI.",
52
- images: ["https://deepsite.hf.co/banner.png"],
53
- },
54
  appleWebApp: {
55
  capable: true,
56
  title: "DeepSite",
@@ -61,6 +43,9 @@ export const metadata: Metadata = {
61
  shortcut: "/logo.svg",
62
  apple: "/logo.svg",
63
  },
 
 
 
64
  };
65
 
66
  export const viewport: Viewport = {
@@ -91,8 +76,35 @@ export default async function RootLayout({
91
  children: React.ReactNode;
92
  }>) {
93
  const data = await getMe();
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  return (
95
  <html lang="en">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  <Script
97
  defer
98
  data-domain="deepsite.hf.co"
 
13
  import TanstackContext from "@/components/contexts/tanstack-query-context";
14
  import { LoginProvider } from "@/components/contexts/login-context";
15
  import { ProProvider } from "@/components/contexts/pro-context";
16
+ import { generateSEO, generateStructuredData } from "@/lib/seo";
17
 
18
  const inter = Inter({
19
  variable: "--font-inter-sans",
 
27
  });
28
 
29
  export const metadata: Metadata = {
30
+ ...generateSEO({
 
 
 
31
  title: "DeepSite | Build with AI ✨",
32
  description:
33
  "DeepSite is a web development tool that helps you build websites with AI, no code required. Let's deploy your website with DeepSite and enjoy the magic of AI.",
34
+ path: "/",
35
+ }),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  appleWebApp: {
37
  capable: true,
38
  title: "DeepSite",
 
43
  shortcut: "/logo.svg",
44
  apple: "/logo.svg",
45
  },
46
+ verification: {
47
+ google: process.env.GOOGLE_SITE_VERIFICATION,
48
+ },
49
  };
50
 
51
  export const viewport: Viewport = {
 
76
  children: React.ReactNode;
77
  }>) {
78
  const data = await getMe();
79
+
80
+ // Generate structured data
81
+ const structuredData = generateStructuredData("WebApplication", {
82
+ name: "DeepSite",
83
+ description: "Build websites with AI, no code required",
84
+ url: "https://deepsite.hf.co",
85
+ });
86
+
87
+ const organizationData = generateStructuredData("Organization", {
88
+ name: "DeepSite",
89
+ url: "https://deepsite.hf.co",
90
+ });
91
+
92
  return (
93
  <html lang="en">
94
+ <head>
95
+ <script
96
+ type="application/ld+json"
97
+ dangerouslySetInnerHTML={{
98
+ __html: JSON.stringify(structuredData),
99
+ }}
100
+ />
101
+ <script
102
+ type="application/ld+json"
103
+ dangerouslySetInnerHTML={{
104
+ __html: JSON.stringify(organizationData),
105
+ }}
106
+ />
107
+ </head>
108
  <Script
109
  defer
110
  data-domain="deepsite.hf.co"
app/new/page.tsx CHANGED
@@ -1,4 +1,13 @@
1
  import { AppEditor } from "@/components/editor";
 
 
 
 
 
 
 
 
 
2
 
3
  export default function NewProjectPage() {
4
  return <AppEditor isNew />;
 
1
  import { AppEditor } from "@/components/editor";
2
+ import { Metadata } from "next";
3
+ import { generateSEO } from "@/lib/seo";
4
+
5
+ export const metadata: Metadata = generateSEO({
6
+ title: "Create New Project - DeepSite",
7
+ description:
8
+ "Start building your next website with AI. Create a new project on DeepSite and experience the power of AI-driven web development.",
9
+ path: "/new",
10
+ });
11
 
12
  export default function NewProjectPage() {
13
  return <AppEditor isNew />;
app/sitemap.ts ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { MetadataRoute } from 'next';
2
+
3
+ export default function sitemap(): MetadataRoute.Sitemap {
4
+ const baseUrl = 'https://deepsite.hf.co';
5
+
6
+ return [
7
+ {
8
+ url: baseUrl,
9
+ lastModified: new Date(),
10
+ changeFrequency: 'daily',
11
+ priority: 1,
12
+ },
13
+ {
14
+ url: `${baseUrl}/new`,
15
+ lastModified: new Date(),
16
+ changeFrequency: 'weekly',
17
+ priority: 0.8,
18
+ },
19
+ {
20
+ url: `${baseUrl}/auth`,
21
+ lastModified: new Date(),
22
+ changeFrequency: 'monthly',
23
+ priority: 0.5,
24
+ },
25
+ // Note: Dynamic project routes will be handled by Next.js automatically
26
+ // but you can add specific high-priority project pages here if needed
27
+ ];
28
+ }
components/iframe-detector/index.tsx CHANGED
@@ -41,6 +41,42 @@ export default function IframeDetector() {
41
  }
42
  };
43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  // Check if we're in an iframe from a non-allowed domain
45
  const shouldShowWarning = () => {
46
  if (!isInIframe() && !isEmbedded()) {
@@ -65,6 +101,9 @@ export default function IframeDetector() {
65
  }
66
  };
67
 
 
 
 
68
  if (shouldShowWarning()) {
69
  // Show warning modal instead of redirecting immediately
70
  setShowWarning(true);
 
41
  }
42
  };
43
 
44
+ // SEO: Add canonical URL meta tag when in iframe
45
+ const addCanonicalUrl = () => {
46
+ // Remove existing canonical link if present
47
+ const existingCanonical = document.querySelector('link[rel="canonical"]');
48
+ if (existingCanonical) {
49
+ existingCanonical.remove();
50
+ }
51
+
52
+ // Add canonical URL pointing to the standalone version
53
+ const canonical = document.createElement("link");
54
+ canonical.rel = "canonical";
55
+ canonical.href = window.location.href;
56
+ document.head.appendChild(canonical);
57
+
58
+ // Add meta tag to indicate this page should not be indexed when in iframe from unauthorized domains
59
+ if (isInIframe() || isEmbedded()) {
60
+ try {
61
+ const parentHostname = document.referrer
62
+ ? new URL(document.referrer).hostname
63
+ : null;
64
+ if (parentHostname && !isAllowedDomain(parentHostname)) {
65
+ // Add noindex meta tag when embedded in unauthorized domains
66
+ const noIndexMeta = document.createElement("meta");
67
+ noIndexMeta.name = "robots";
68
+ noIndexMeta.content = "noindex, nofollow";
69
+ document.head.appendChild(noIndexMeta);
70
+ }
71
+ } catch (error) {
72
+ // Silently handle cross-origin errors
73
+ console.debug(
74
+ "SEO: Could not determine parent domain for iframe indexing rules"
75
+ );
76
+ }
77
+ }
78
+ };
79
+
80
  // Check if we're in an iframe from a non-allowed domain
81
  const shouldShowWarning = () => {
82
  if (!isInIframe() && !isEmbedded()) {
 
101
  }
102
  };
103
 
104
+ // Always add canonical URL for SEO, regardless of iframe status
105
+ addCanonicalUrl();
106
+
107
  if (shouldShowWarning()) {
108
  // Show warning modal instead of redirecting immediately
109
  setShowWarning(true);
lib/seo.ts ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Metadata } from "next";
2
+
3
+ interface SEOParams {
4
+ title?: string;
5
+ description?: string;
6
+ path?: string;
7
+ image?: string;
8
+ noIndex?: boolean;
9
+ canonical?: string;
10
+ }
11
+
12
+ export function generateSEO({
13
+ title = "DeepSite | Build with AI ✨",
14
+ description = "DeepSite is a web development tool that helps you build websites with AI, no code required. Let's deploy your website with DeepSite and enjoy the magic of AI.",
15
+ path = "",
16
+ image = "/banner.png",
17
+ noIndex = false,
18
+ canonical,
19
+ }: SEOParams = {}): Metadata {
20
+ const baseUrl = "https://deepsite.hf.co";
21
+ const fullUrl = `${baseUrl}${path}`;
22
+ const canonicalUrl = canonical || fullUrl;
23
+
24
+ return {
25
+ title,
26
+ description,
27
+ alternates: {
28
+ canonical: canonicalUrl,
29
+ },
30
+ robots: noIndex
31
+ ? {
32
+ index: false,
33
+ follow: false,
34
+ googleBot: {
35
+ index: false,
36
+ follow: false,
37
+ 'max-video-preview': -1,
38
+ 'max-image-preview': 'large',
39
+ 'max-snippet': -1,
40
+ }
41
+ }
42
+ : {
43
+ index: true,
44
+ follow: true,
45
+ googleBot: {
46
+ index: true,
47
+ follow: true,
48
+ 'max-video-preview': -1,
49
+ 'max-image-preview': 'large',
50
+ 'max-snippet': -1,
51
+ }
52
+ },
53
+ openGraph: {
54
+ title,
55
+ description,
56
+ url: canonicalUrl,
57
+ siteName: "DeepSite",
58
+ images: [
59
+ {
60
+ url: `${baseUrl}${image}`,
61
+ width: 1200,
62
+ height: 630,
63
+ alt: `${title} - DeepSite`,
64
+ },
65
+ ],
66
+ locale: "en_US",
67
+ type: "website",
68
+ },
69
+ twitter: {
70
+ card: "summary_large_image",
71
+ title,
72
+ description,
73
+ images: [`${baseUrl}${image}`],
74
+ creator: "@deepsite",
75
+ },
76
+ other: {
77
+ // Prevent iframe embedding from unauthorized domains
78
+ 'X-Frame-Options': 'SAMEORIGIN',
79
+ // Control how the page appears when shared
80
+ 'og:image:secure_url': `${baseUrl}${image}`,
81
+ // Help search engines understand the primary URL
82
+ 'rel': 'canonical',
83
+ },
84
+ };
85
+ }
86
+
87
+ export function generateStructuredData(type: 'WebApplication' | 'Organization' | 'Article', data: any) {
88
+ const baseStructuredData = {
89
+ '@context': 'https://schema.org',
90
+ '@type': type,
91
+ };
92
+
93
+ switch (type) {
94
+ case 'WebApplication':
95
+ return {
96
+ ...baseStructuredData,
97
+ name: 'DeepSite',
98
+ description: 'Build websites with AI, no code required',
99
+ url: 'https://deepsite.hf.co',
100
+ applicationCategory: 'DeveloperApplication',
101
+ operatingSystem: 'Web',
102
+ offers: {
103
+ '@type': 'Offer',
104
+ price: '0',
105
+ priceCurrency: 'USD',
106
+ },
107
+ creator: {
108
+ '@type': 'Organization',
109
+ name: 'DeepSite',
110
+ url: 'https://deepsite.hf.co',
111
+ },
112
+ ...data,
113
+ };
114
+
115
+ case 'Organization':
116
+ return {
117
+ ...baseStructuredData,
118
+ name: 'DeepSite',
119
+ url: 'https://deepsite.hf.co',
120
+ logo: 'https://deepsite.hf.co/logo.svg',
121
+ description: 'AI-powered web development platform',
122
+ sameAs: [
123
+ // Add social media links here if available
124
+ ],
125
+ ...data,
126
+ };
127
+
128
+ default:
129
+ return { ...baseStructuredData, ...data };
130
+ }
131
+ }
middleware.ts CHANGED
@@ -4,7 +4,24 @@ import type { NextRequest } from "next/server";
4
  export function middleware(request: NextRequest) {
5
  const headers = new Headers(request.headers);
6
  headers.set("x-current-host", request.nextUrl.host);
7
- return NextResponse.next({ headers });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  }
9
 
10
  export const config = {
 
4
  export function middleware(request: NextRequest) {
5
  const headers = new Headers(request.headers);
6
  headers.set("x-current-host", request.nextUrl.host);
7
+
8
+ // Create response with headers
9
+ const response = NextResponse.next({ headers });
10
+
11
+ // Add SEO and security headers
12
+ response.headers.set('X-Frame-Options', 'SAMEORIGIN');
13
+ response.headers.set('X-Content-Type-Options', 'nosniff');
14
+ response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
15
+
16
+ // Add cache control for better performance
17
+ if (request.nextUrl.pathname.startsWith('/_next/static')) {
18
+ response.headers.set('Cache-Control', 'public, max-age=31536000, immutable');
19
+ }
20
+
21
+ // Add canonical URL headers for programmatic access
22
+ response.headers.set('X-Canonical-URL', `https://deepsite.hf.co${request.nextUrl.pathname}`);
23
+
24
+ return response;
25
  }
26
 
27
  export const config = {
public/robots.txt ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ User-agent: *
2
+ Allow: /
3
+
4
+ # Block access to API routes and private areas
5
+ Disallow: /api/
6
+ Disallow: /auth/
7
+ Disallow: /_next/
8
+ Disallow: /assets/
9
+
10
+ # Allow specific public API endpoints if needed
11
+ Allow: /api/public/
12
+
13
+ # Sitemap location
14
+ Sitemap: https://deepsite.hf.co/sitemap.xml
15
+
16
+ # Crawl-delay for respectful crawling
17
+ Crawl-delay: 1