Skip to content

Commit

Permalink
feat(seo): add sitemaps for improved SEO
Browse files Browse the repository at this point in the history
  • Loading branch information
ruru-m07 committed Sep 19, 2024
1 parent e582a8d commit 1e140fe
Show file tree
Hide file tree
Showing 15 changed files with 115 additions and 11,626 deletions.
6 changes: 3 additions & 3 deletions apps/www/__registry__/blocks/index.ts

Large diffs are not rendered by default.

31 changes: 25 additions & 6 deletions apps/www/app/(block)/blocks/[name]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,33 @@
import { notFound } from "next/navigation";
import { blocks } from "@/registry/blocks";
import { blocks_registry } from "@/__registry__/blocks";
import { Metadata } from "next";

export default async function BlockPage({
params,
}: {
params: {
name: string;
type Params = {
name: string;
};

type Props = {
params: Params;
};

export async function generateStaticParams(): Promise<Params[]> {
return blocks.map((block) => ({
name: block.name,
}));
}

export async function generateMetadata({ params }: Props): Promise<Metadata> {
const block = blocks.find((block) => block.name === params.name);
if (!block) return {};

return {
title: `${block.name} Block`,
description: `View details for the ${block.name} block`,
};
}) {
}

export default async function BlockPage({ params }: Props) {
const { name } = params;

// Find the block by name in blocks
Expand Down
1 change: 0 additions & 1 deletion apps/www/app/theme__/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { Button } from "ruru-ui/components/button";
import { PaintbrushVertical } from "lucide-react";

import "react-color-palette/css";
import Login1 from "@/components/blocks/login-1";
import Playground from "../playground/page";
import { Tab, Tabs } from "ruru-ui/components/tabs";
import Colors from "@/components/colors";
Expand Down
30 changes: 30 additions & 0 deletions apps/www/next-sitemap.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const { execSync } = require("child_process");

/** @type {import('next-sitemap').IConfig} */
module.exports = {
siteUrl: process.env.SITE_URL || "https://ruru-ui.vercel.app",
generateRobotsTxt: true,
exclude: ["/api/*"],
transform: async (config, path) => {
const lastmod = await getLastModifiedDate(path);
return {
loc: path,
changefreq: config.changefreq,
priority: config.priority,
lastmod,
alternateRefs: config.alternateRefs ?? [],
};
},
};

async function getLastModifiedDate(path) {
try {
const timestamp = execSync(`git log -1 --format=%ct ${path}`)
.toString()
.trim();
return new Date(parseInt(timestamp, 10) * 1000).toISOString();
} catch (error) {
console.error(`Error getting last modified date for ${path}:`, error);
return new Date().toISOString(); // Fallback to current date
}
}
2 changes: 2 additions & 0 deletions apps/www/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"dev": "next dev",
"start": "next start",
"lint": "next lint",
"postbuild": "next-sitemap",
"build:registry": "tsx --tsconfig ./tsconfig.scripts.json ./scripts/build-registry.mts && prettier --loglevel silent --ignore-path .gitignore --ignore-path .prettierignore --write \"**/*.{ts,tsx,mdx,json}\" --cache"
},
"dependencies": {
Expand All @@ -31,6 +32,7 @@
"hast-util-to-jsx-runtime": "^2.3.0",
"lucide-react": "^0.437.0",
"next": "^14.2.4",
"next-sitemap": "^4.2.3",
"os": "^0.1.2",
"path": "^0.12.7",
"posthog-js": "^1.161.3",
Expand Down
2 changes: 1 addition & 1 deletion apps/www/public/registry/blocks/forgot-1.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"files": [
{
"name": "forgot-1.tsx",
"content": "\"use client\";\n\n/* eslint-disable @next/next/no-img-element */\nimport Image from \"next/image\";\n\nimport Link from \"next/link\";\nimport React from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport { z } from \"zod\";\nimport { Button } from \"ruru-ui/components/button\";\nimport { Input } from \"ruru-ui/components/input\";\nimport {\n Form,\n FormControl,\n FormField,\n FormLabel,\n FormItem,\n FormMessage,\n} from \"ruru-ui/components/form\";\n\nconst Forgot1 = (): React.ReactNode => {\n const formSchema = z.object({\n email: z.string().email({ message: \"Please enter a valid email address.\" }),\n });\n\n const form = useForm<z.infer<typeof formSchema>>({\n resolver: zodResolver(formSchema),\n defaultValues: {\n email: \"\",\n },\n });\n\n function onSubmit(values: z.infer<typeof formSchema>) {\n // Do something with the form values.\n console.log(values);\n }\n\n return (\n <div className=\"flex items-center justify-center h-screen\">\n <div className=\"flex flex-col items-center w-96 border rounded-md bg-card p-4\">\n <div className=\"grid place-items-center\">\n <div className=\"flex items-center gap-4\">\n <img\n className=\"dark:block hidden\"\n src={\"https://ruru-ui.vercel.app/assets/logo-white.png\"}\n alt=\"logo\"\n height={40}\n width={40}\n />\n <img\n className=\"dark:hidden block\"\n src={\"https://ruru-ui.vercel.app/assets/logo-black.png\"}\n alt=\"logo\"\n height={40}\n width={40}\n />\n <span className=\"text-xl\">Ruru UI</span>\n </div>\n <span className=\"text-sm text-muted-foreground mt-4\">\n Forgot your password?\n </span>\n </div>\n\n <Form {...form}>\n <form\n onSubmit={form.handleSubmit(onSubmit)}\n className=\"w-full space-y-2\"\n >\n <div className=\"my-3\">\n <FormField\n control={form.control}\n name=\"email\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>Email</FormLabel>\n <FormControl>\n <Input placeholder=\"[email protected]\" {...field} />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n </div>\n\n <div className=\"py-4 w-full space-y-3\">\n <Button type=\"submit\" className=\"w-full\">\n Send reset link\n </Button>\n </div>\n\n <Link\n href={\"#\"}\n className=\"hover:underline text-xs flex justify-center\"\n >\n Back to login\n </Link>\n </form>\n </Form>\n </div>\n </div>\n );\n};\n\nexport default Forgot1;\n"
"content": "\"use client\";\r\n\r\n/* eslint-disable @next/next/no-img-element */\r\nimport Image from \"next/image\";\r\n\r\nimport Link from \"next/link\";\r\nimport React from \"react\";\r\nimport { useForm } from \"react-hook-form\";\r\nimport { zodResolver } from \"@hookform/resolvers/zod\";\r\nimport { z } from \"zod\";\r\nimport { Button } from \"ruru-ui/components/button\";\r\nimport { Input } from \"ruru-ui/components/input\";\r\nimport {\r\n Form,\r\n FormControl,\r\n FormField,\r\n FormLabel,\r\n FormItem,\r\n FormMessage,\r\n} from \"ruru-ui/components/form\";\r\n\r\nconst Forgot1 = (): React.ReactNode => {\r\n const formSchema = z.object({\r\n email: z.string().email({ message: \"Please enter a valid email address.\" }),\r\n });\r\n\r\n const form = useForm<z.infer<typeof formSchema>>({\r\n resolver: zodResolver(formSchema),\r\n defaultValues: {\r\n email: \"\",\r\n },\r\n });\r\n\r\n function onSubmit(values: z.infer<typeof formSchema>) {\r\n // Do something with the form values.\r\n console.log(values);\r\n }\r\n\r\n return (\r\n <div className=\"flex items-center justify-center h-screen\">\r\n <div className=\"flex flex-col items-center w-96 border rounded-md bg-card p-4\">\r\n <div className=\"grid place-items-center\">\r\n <div className=\"flex items-center gap-4\">\r\n <img\r\n className=\"dark:block hidden\"\r\n src={\"https://ruru-ui.vercel.app/assets/logo-white.png\"}\r\n alt=\"logo\"\r\n height={40}\r\n width={40}\r\n />\r\n <img\r\n className=\"dark:hidden block\"\r\n src={\"https://ruru-ui.vercel.app/assets/logo-black.png\"}\r\n alt=\"logo\"\r\n height={40}\r\n width={40}\r\n />\r\n <span className=\"text-xl\">Ruru UI</span>\r\n </div>\r\n <span className=\"text-sm text-muted-foreground mt-4\">\r\n Forgot your password?\r\n </span>\r\n </div>\r\n\r\n <Form {...form}>\r\n <form\r\n onSubmit={form.handleSubmit(onSubmit)}\r\n className=\"w-full space-y-2\"\r\n >\r\n <div className=\"my-3\">\r\n <FormField\r\n control={form.control}\r\n name=\"email\"\r\n render={({ field }) => (\r\n <FormItem>\r\n <FormLabel>Email</FormLabel>\r\n <FormControl>\r\n <Input placeholder=\"[email protected]\" {...field} />\r\n </FormControl>\r\n <FormMessage />\r\n </FormItem>\r\n )}\r\n />\r\n </div>\r\n\r\n <div className=\"py-4 w-full space-y-3\">\r\n <Button type=\"submit\" className=\"w-full\">\r\n Send reset link\r\n </Button>\r\n </div>\r\n\r\n <Link\r\n href={\"#\"}\r\n className=\"hover:underline text-xs flex justify-center\"\r\n >\r\n Back to login\r\n </Link>\r\n </form>\r\n </Form>\r\n </div>\r\n </div>\r\n );\r\n};\r\n\r\nexport default Forgot1;\r\n"
}
],
"dependencies": ["react-hook-form", "@hookform/resolvers", "zod"],
Expand Down
2 changes: 1 addition & 1 deletion apps/www/public/registry/blocks/login-1.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"files": [
{
"name": "login-1.tsx",
"content": "\"use client\";\n\n/* eslint-disable @next/next/no-img-element */\nimport Image from \"next/image\";\n\nimport Link from \"next/link\";\nimport React from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport { z } from \"zod\";\nimport { Button } from \"ruru-ui/components/button\";\nimport { Input, PasswordInput } from \"ruru-ui/components/input\";\nimport {\n Form,\n FormControl,\n FormField,\n FormLabel,\n FormItem,\n FormMessage,\n} from \"ruru-ui/components/form\";\n\nconst Login1 = (): React.ReactNode => {\n const loginSchema = z.object({\n email: z.string().email({ message: \"Please enter a valid email address.\" }),\n password: z\n .string()\n .min(8, { message: \"Password must be at least 8 characters long.\" }),\n });\n\n const form = useForm<z.infer<typeof loginSchema>>({\n resolver: zodResolver(loginSchema),\n defaultValues: {\n email: \"\",\n password: \"\",\n },\n });\n\n function onSubmit(values: z.infer<typeof loginSchema>) {\n // Do something with the form values.\n console.log(values);\n }\n\n return (\n <div className=\"flex items-center justify-center h-screen\">\n <div className=\"flex flex-col items-center w-96 border rounded-md bg-card p-4\">\n <div className=\"grid place-items-center\">\n <div className=\"flex items-center gap-4\">\n <img\n className=\"dark:block hidden\"\n src={\"https://ruru-ui.vercel.app/assets/logo-white.png\"}\n alt=\"logo\"\n height={40}\n width={40}\n />\n <img\n className=\"dark:hidden block\"\n src={\"https://ruru-ui.vercel.app/assets/logo-black.png\"}\n alt=\"logo\"\n height={40}\n width={40}\n />\n <span className=\"text-xl\">Ruru UI</span>\n </div>\n <span className=\"text-sm text-muted-foreground mt-4\">\n Welcome back\n </span>\n </div>\n\n <Form {...form}>\n <form\n onSubmit={form.handleSubmit(onSubmit)}\n className=\"w-full space-y-2\"\n >\n <div className=\"my-3\">\n <FormField\n control={form.control}\n name=\"email\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>Email</FormLabel>\n <FormControl>\n <Input placeholder=\"[email protected]\" {...field} />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={form.control}\n name=\"password\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>Password</FormLabel>\n <FormControl>\n <PasswordInput placeholder=\"••••••••\" {...field} />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n </div>\n\n <Link href={\"#\"} className=\"hover:underline text-xs\">\n Forgot password?\n </Link>\n\n <div className=\"py-4 w-full space-y-3\">\n <Button type=\"submit\" className=\"w-full\">\n Login\n </Button>\n <Button\n className=\"w-full\"\n variant={\"secondary\"}\n onClick={() => console.log(\"Login with Github\")}\n >\n Login with Github\n </Button>\n </div>\n\n <Link\n href={\"#\"}\n className=\"hover:underline text-xs flex justify-center\"\n >\n Don&apos;t have an account?\n </Link>\n </form>\n </Form>\n </div>\n </div>\n );\n};\n\nexport default Login1;\n"
"content": "\"use client\";\r\n\r\n/* eslint-disable @next/next/no-img-element */\r\nimport Image from \"next/image\";\r\n\r\nimport Link from \"next/link\";\r\nimport React from \"react\";\r\nimport { useForm } from \"react-hook-form\";\r\nimport { zodResolver } from \"@hookform/resolvers/zod\";\r\nimport { z } from \"zod\";\r\nimport { Button } from \"ruru-ui/components/button\";\r\nimport { Input, PasswordInput } from \"ruru-ui/components/input\";\r\nimport {\r\n Form,\r\n FormControl,\r\n FormField,\r\n FormLabel,\r\n FormItem,\r\n FormMessage,\r\n} from \"ruru-ui/components/form\";\r\n\r\nconst Login1 = (): React.ReactNode => {\r\n const loginSchema = z.object({\r\n email: z.string().email({ message: \"Please enter a valid email address.\" }),\r\n password: z\r\n .string()\r\n .min(8, { message: \"Password must be at least 8 characters long.\" }),\r\n });\r\n\r\n const form = useForm<z.infer<typeof loginSchema>>({\r\n resolver: zodResolver(loginSchema),\r\n defaultValues: {\r\n email: \"\",\r\n password: \"\",\r\n },\r\n });\r\n\r\n function onSubmit(values: z.infer<typeof loginSchema>) {\r\n // Do something with the form values.\r\n console.log(values);\r\n }\r\n\r\n return (\r\n <div className=\"flex items-center justify-center h-screen\">\r\n <div className=\"flex flex-col items-center w-96 border rounded-md bg-card p-4\">\r\n <div className=\"grid place-items-center\">\r\n <div className=\"flex items-center gap-4\">\r\n <img\r\n className=\"dark:block hidden\"\r\n src={\"https://ruru-ui.vercel.app/assets/logo-white.png\"}\r\n alt=\"logo\"\r\n height={40}\r\n width={40}\r\n />\r\n <img\r\n className=\"dark:hidden block\"\r\n src={\"https://ruru-ui.vercel.app/assets/logo-black.png\"}\r\n alt=\"logo\"\r\n height={40}\r\n width={40}\r\n />\r\n <span className=\"text-xl\">Ruru UI</span>\r\n </div>\r\n <span className=\"text-sm text-muted-foreground mt-4\">\r\n Welcome back\r\n </span>\r\n </div>\r\n\r\n <Form {...form}>\r\n <form\r\n onSubmit={form.handleSubmit(onSubmit)}\r\n className=\"w-full space-y-2\"\r\n >\r\n <div className=\"my-3\">\r\n <FormField\r\n control={form.control}\r\n name=\"email\"\r\n render={({ field }) => (\r\n <FormItem>\r\n <FormLabel>Email</FormLabel>\r\n <FormControl>\r\n <Input placeholder=\"[email protected]\" {...field} />\r\n </FormControl>\r\n <FormMessage />\r\n </FormItem>\r\n )}\r\n />\r\n\r\n <FormField\r\n control={form.control}\r\n name=\"password\"\r\n render={({ field }) => (\r\n <FormItem>\r\n <FormLabel>Password</FormLabel>\r\n <FormControl>\r\n <PasswordInput placeholder=\"••••••••\" {...field} />\r\n </FormControl>\r\n <FormMessage />\r\n </FormItem>\r\n )}\r\n />\r\n </div>\r\n\r\n <Link href={\"#\"} className=\"hover:underline text-xs\">\r\n Forgot password?\r\n </Link>\r\n\r\n <div className=\"py-4 w-full space-y-3\">\r\n <Button type=\"submit\" className=\"w-full\">\r\n Login\r\n </Button>\r\n <Button\r\n className=\"w-full\"\r\n variant={\"secondary\"}\r\n onClick={() => console.log(\"Login with Github\")}\r\n >\r\n Login with Github\r\n </Button>\r\n </div>\r\n\r\n <Link\r\n href={\"#\"}\r\n className=\"hover:underline text-xs flex justify-center\"\r\n >\r\n Don&apos;t have an account?\r\n </Link>\r\n </form>\r\n </Form>\r\n </div>\r\n </div>\r\n );\r\n};\r\n\r\nexport default Login1;\r\n"
}
],
"dependencies": ["react-hook-form", "@hookform/resolvers", "zod"],
Expand Down
Loading

0 comments on commit 1e140fe

Please sign in to comment.