feat: better metadata, robots, and sitemap; simplify layout w/ AnimatedTitle and I18nProvider components
This commit is contained in:
parent
a37938e8c7
commit
5dc930bcbb
5 changed files with 136 additions and 57 deletions
111
app/layout.tsx
111
app/layout.tsx
|
@ -1,70 +1,67 @@
|
||||||
"use client"
|
import React from 'react'
|
||||||
|
import { Metadata } from 'next'
|
||||||
import React, { useEffect } from 'react'
|
import Head from 'next/head'
|
||||||
import './globals.css'
|
import './globals.css'
|
||||||
import { GeistSans } from 'geist/font/sans'
|
import { GeistSans } from 'geist/font/sans'
|
||||||
import '../i18n'
|
import AnimatedTitle from '../components/AnimatedTitle'
|
||||||
|
import I18nProvider from '../components/I18nProvider'
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
description: "The Internet home of Aidan. Come on in!",
|
||||||
|
openGraph: {
|
||||||
|
type: "website",
|
||||||
|
url: "https://aidxn.cc",
|
||||||
|
title: "aidxn.cc",
|
||||||
|
description: "The Internet home of Aidan. Come on in!",
|
||||||
|
siteName: "aidxn.cc",
|
||||||
|
images: [
|
||||||
|
{
|
||||||
|
url: "https://aidxn.cc/android-icon-192x192.png",
|
||||||
|
width: 192,
|
||||||
|
height: 192,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
export default function RootLayout({
|
export default function RootLayout({
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
}) {
|
}) {
|
||||||
useEffect(() => {
|
|
||||||
const title = 'aidxn.cc';
|
|
||||||
let index = 1;
|
|
||||||
let forward = true;
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
document.title = title.substring(0, index);
|
|
||||||
if (forward) {
|
|
||||||
index++;
|
|
||||||
if (index > title.length) {
|
|
||||||
forward = false;
|
|
||||||
index = title.length - 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
index--;
|
|
||||||
if (index < 1) {
|
|
||||||
forward = true;
|
|
||||||
index = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 500);
|
|
||||||
return () => clearInterval(interval);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html lang="en" className="dark">
|
<html lang="en" className="dark">
|
||||||
<head>
|
<Head>
|
||||||
<link rel="apple-touch-icon" sizes="57x57" href="/apple-icon-57x57.png" />
|
<link rel="apple-touch-icon" sizes="57x57" href="/apple-icon-57x57.png" />
|
||||||
<link rel="apple-touch-icon" sizes="60x60" href="/apple-icon-60x60.png" />
|
<link rel="apple-touch-icon" sizes="60x60" href="/apple-icon-60x60.png" />
|
||||||
<link rel="apple-touch-icon" sizes="72x72" href="/apple-icon-72x72.png" />
|
<link rel="apple-touch-icon" sizes="72x72" href="/apple-icon-72x72.png" />
|
||||||
<link rel="apple-touch-icon" sizes="76x76" href="/apple-icon-76x76.png" />
|
<link rel="apple-touch-icon" sizes="76x76" href="/apple-icon-76x76.png" />
|
||||||
<link rel="apple-touch-icon" sizes="114x114" href="/apple-icon-114x114.png" />
|
<link rel="apple-touch-icon" sizes="114x114" href="/apple-icon-114x114.png" />
|
||||||
<link rel="apple-touch-icon" sizes="120x120" href="/apple-icon-120x120.png" />
|
<link rel="apple-touch-icon" sizes="120x120" href="/apple-icon-120x120.png" />
|
||||||
<link rel="apple-touch-icon" sizes="144x144" href="/apple-icon-144x144.png" />
|
<link rel="apple-touch-icon" sizes="144x144" href="/apple-icon-144x144.png" />
|
||||||
<link rel="apple-touch-icon" sizes="152x152" href="/apple-icon-152x152.png" />
|
<link rel="apple-touch-icon" sizes="152x152" href="/apple-icon-152x152.png" />
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png" />
|
<link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png" />
|
||||||
<link rel="icon" type="image/png" sizes="192x192" href="/android-icon-192x192.png" />
|
<link rel="icon" type="image/png" sizes="192x192" href="/android-icon-192x192.png" />
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
||||||
<link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png" />
|
<link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png" />
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
||||||
<link rel="manifest" href="/manifest.json" />
|
<link rel="manifest" href="/manifest.json" />
|
||||||
<meta name="msapplication-TileColor" content="#ffffff" />
|
<meta name="msapplication-TileColor" content="#ffffff" />
|
||||||
<meta name="msapplication-TileImage" content="/ms-icon-144x144.png" />
|
<meta name="msapplication-TileImage" content="/ms-icon-144x144.png" />
|
||||||
<meta name="theme-color" content="#ffffff" />
|
<meta name="theme-color" content="#ffffff" />
|
||||||
<meta charSet="utf-8" />
|
<meta charSet="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="description" content="The Internet home of Aidan. Come on in!" />
|
<meta name="robots" content="index, follow" />
|
||||||
<meta name="keywords" content="blog, android, developer" />
|
<meta name="language" content="English" />
|
||||||
<meta name="robots" content="index, follow" />
|
<meta name="author" content="aidxn.cc" />
|
||||||
<meta name="language" content="English" />
|
</Head>
|
||||||
<meta name="author" content="aidxn.cc" />
|
<body className={`${GeistSans.className} bg-gray-900 text-gray-100`}>
|
||||||
</head>
|
<AnimatedTitle />
|
||||||
<body className={`${GeistSans.className} bg-gray-900 text-gray-100`}>
|
<I18nProvider>
|
||||||
{children}
|
{children}
|
||||||
</body>
|
</I18nProvider>
|
||||||
</html>
|
</body>
|
||||||
|
</html>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
9
app/robots.ts
Normal file
9
app/robots.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import type { MetadataRoute } from 'next'
|
||||||
|
|
||||||
|
export const robots: MetadataRoute.Robots = {
|
||||||
|
rules: {
|
||||||
|
userAgent: '*',
|
||||||
|
allow: '/',
|
||||||
|
},
|
||||||
|
sitemap: 'https://aidxn.cc/sitemap.xml',
|
||||||
|
}
|
36
app/sitemap.ts
Normal file
36
app/sitemap.ts
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import type { MetadataRoute } from 'next'
|
||||||
|
|
||||||
|
export default function sitemap(): MetadataRoute.Sitemap {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
url: 'https://aidxn.cc',
|
||||||
|
lastModified: new Date(),
|
||||||
|
changeFrequency: 'weekly',
|
||||||
|
priority: 1.0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: 'https://aidxn.cc/about',
|
||||||
|
lastModified: new Date(),
|
||||||
|
changeFrequency: 'weekly',
|
||||||
|
priority: 0.8,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: 'https://aidxn.cc/contact',
|
||||||
|
lastModified: new Date(),
|
||||||
|
changeFrequency: 'monthly',
|
||||||
|
priority: 0.8,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: 'https://aidxn.cc/domains',
|
||||||
|
lastModified: new Date(),
|
||||||
|
changeFrequency: 'monthly',
|
||||||
|
priority: 0.8,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: 'https://aidxn.cc/manifesto',
|
||||||
|
lastModified: new Date(),
|
||||||
|
changeFrequency: 'yearly',
|
||||||
|
priority: 0.7,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
29
components/AnimatedTitle.tsx
Normal file
29
components/AnimatedTitle.tsx
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
|
export default function AnimatedTitle() {
|
||||||
|
useEffect(() => {
|
||||||
|
const title = 'aidxn.cc';
|
||||||
|
let index = 1;
|
||||||
|
let forward = true;
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
document.title = title.substring(0, index);
|
||||||
|
if (forward) {
|
||||||
|
index++;
|
||||||
|
if (index > title.length) {
|
||||||
|
forward = false;
|
||||||
|
index = title.length - 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
index--;
|
||||||
|
if (index < 1) {
|
||||||
|
forward = true;
|
||||||
|
index = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
return () => clearInterval(interval);
|
||||||
|
}, []);
|
||||||
|
return null;
|
||||||
|
}
|
8
components/I18nProvider.tsx
Normal file
8
components/I18nProvider.tsx
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { ReactNode } from "react";
|
||||||
|
import "../i18n";
|
||||||
|
|
||||||
|
export default function I18nProvider({ children }: { children: ReactNode }) {
|
||||||
|
return <>{children}</>;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue