File size: 3,930 Bytes
743dad3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65ef364
743dad3
65ef364
743dad3
 
 
 
65ef364
743dad3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65ef364
743dad3
65ef364
 
 
743dad3
 
 
65ef364
 
743dad3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65ef364
 
 
 
 
 
 
 
 
743dad3
 
 
0283cd2
 
 
743dad3
 
 
 
 
 
 
 
 
 
 
 
65ef364
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { Metadata, Viewport } from "next";
import { Inter, PT_Sans } from "next/font/google";
import { cookies } from "next/headers";
import Script from "next/script";

import "@/assets/globals.css";
import { Toaster } from "@/components/ui/sonner";
import MY_TOKEN_KEY from "@/lib/get-cookie-name";
import { apiServer } from "@/lib/api";
import IframeDetector from "@/components/iframe-detector";
import AppContext from "@/components/contexts/app-context";
import TanstackContext from "@/components/contexts/tanstack-query-context";
import { LoginProvider } from "@/components/contexts/login-context";
import { ProProvider } from "@/components/contexts/pro-context";
import { generateSEO, generateStructuredData } from "@/lib/seo";

const inter = Inter({
  variable: "--font-inter-sans",
  subsets: ["latin"],
});

const ptSans = PT_Sans({
  variable: "--font-ptSans-mono",
  subsets: ["latin"],
  weight: ["400", "700"],
});

export const metadata: Metadata = {
  ...generateSEO({
    title: "OmniDev | AI Project Builder",
    description:
      "OmniDev is an AI engineering environment that builds complete web projects (frontend + backend) from natural language.",
    path: "/",
  }),
  appleWebApp: {
    capable: true,
    title: "OmniDev",
    statusBarStyle: "black-translucent",
  },
  icons: {
    icon: "/logo.svg",
    shortcut: "/logo.svg",
    apple: "/logo.svg",
  },
  verification: {
    google: process.env.GOOGLE_SITE_VERIFICATION,
  },
};

export const viewport: Viewport = {
  initialScale: 1,
  maximumScale: 1,
  themeColor: "#000000",
};

async function getMe() {
  const cookieStore = await cookies();
  const token = cookieStore.get(MY_TOKEN_KEY())?.value;
  if (!token) return { user: null, projects: [], errCode: null };
  try {
    const res = await apiServer.get("/me", {
      headers: {
        Authorization: `Bearer ${token}`,
      },
    });
    return { user: res.data.user, projects: res.data.projects, errCode: null };
  } catch (err: any) {
    return { user: null, projects: [], errCode: err.status };
  }
}

export default async function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  const data = await getMe();

  // Structured data with OmniDev
  const structuredData = generateStructuredData("WebApplication", {
    name: "OmniDev",
    description: "AI-powered full-stack project builder",
    url: process.env.PUBLIC_BASE_URL || "https://omnidev.hf.co",
  });

  const organizationData = generateStructuredData("Organization", {
    name: "OmniDev",
    url: process.env.PUBLIC_BASE_URL || "https://omnidev.hf.co",
  });

  return (
    <html lang="en">
      <head>
        <script
          type="application/ld+json"
          dangerouslySetInnerHTML={{
            __html: JSON.stringify(structuredData),
          }}
        />
        <script
          type="application/ld+json"
          dangerouslySetInnerHTML={{
            __html: JSON.stringify(organizationData),
          }}
        />
      </head>
      {process.env.PUBLIC_BASE_URL && (
        <Script
          defer
          data-domain={(process.env.PUBLIC_BASE_URL as string)
            .replace("https://", "")
            .replace("http://", "")}
          src="https://plausible.io/js/script.js"
        />
      )}
      <body
        className={`${inter.variable} ${ptSans.variable} antialiased bg-black dark h-[100dvh] overflow-hidden`}
      >
        {((process.env.DISABLE_IFRAME_WARNING || process.env.NEXT_PUBLIC_DISABLE_IFRAME_WARNING) !== 'true') && (
          <IframeDetector />
        )}
        <Toaster richColors position="bottom-center" />
        <TanstackContext>
          <AppContext me={data}>
            <LoginProvider>
              <ProProvider>{children}</ProProvider>
            </LoginProvider>
          </AppContext>
        </TanstackContext>
      </body>
    </html>
  );
}