Skip to content

Commit

Permalink
Merge pull request #67 from ruru-m07/feat/blocks
Browse files Browse the repository at this point in the history
feat(www): Add Blocks and Improve CLI and UI Components
  • Loading branch information
ruru-m07 authored Sep 8, 2024
2 parents e7ed86b + d5d2a3b commit def17a2
Show file tree
Hide file tree
Showing 77 changed files with 4,281 additions and 362 deletions.
26 changes: 25 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,25 @@
# ruru-UI
# Ruru-UI

Welcome to ruru UI, a comprehensive UI library and a set of reusable components designed to help you build beautiful and consistent user interfaces with ease.

![banner-modified](https://github.com/user-attachments/assets/0dcd8002-daff-4b89-854f-f899a94ecaff)

## Join the Community

Become a part of the **ruru UI** community! Share your experiences, ask questions, and collaborate with other developers. Together, we can make **ruru UI** even better. [Provide feedback](https://github.com/ruru-m07/ruru-ui/discussions/3).

## License

**ruru UI** is licensed under the MIT License. You are free to use, modify, and distribute the library as you see fit. For more information, please refer to the [LICENSE](https://github.com/ruru-m07/ruru-ui/blob/main/LICENSE)

## Contributing

Contributions to Next.js are welcome and highly appreciated. However, before you jump right into it, we would like you to review our [Contribution Guidelines](https://github.com/ruru-m07/ruru-ui/blob/main/CONTRIBUTING.md) to make sure you have a smooth experience contributing to Next.js.

### Good First Issues:

We have a list of **[good first issues](https://github.com/ruru-m07/ruru-ui/labels/good%20first%20issue)** that contain bugs that have a relatively limited scope. This is a great place for newcomers and beginners alike to get started, gain experience, and get familiar with our contribution process.

## Thank You

Thank you for choosing **ruru UI**. We appreciate your support and look forward to seeing the amazing applications you build with our library. We hope you enjoy using **ruru UI** to build your applications. Our goal is to provide you with a robust and flexible set of tools to create stunning user interfaces.
Empty file added apps/www/__registry__/.gitkeep
Empty file.
43 changes: 43 additions & 0 deletions apps/www/__registry__/blocks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// ! THIS FILE IS GENERATED AUTOMATICALLY. DO NOT MODIFY IT MANUALLY.

import { Blocks_registry } from "@/registry/blocks";

import Login1 from "@/components/blocks/login-1";
import Register1 from "@/components/blocks/register-1";
import Forgot1 from "@/components/blocks/forgot-1";

export const blocks_registry: Blocks_registry[] = [
{
name: "login-1",
files: ["login-1.tsx"],
dependencies: ["react-hook-form", "@hookform/resolvers", "zod"],
components: ["button", "input", "form"],
type: "block:component",
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/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/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',
],
default_export: Login1,
},
{
name: "register-1",
files: ["register-1.tsx"],
dependencies: ["react-hook-form", "@hookform/resolvers", "zod"],
components: ["button", "input", "form"],
type: "block:component",
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 Register1 = () => {\n const registerSchema = z.object({\n firstName: z\n .string()\n .min(3, { message: "First name must be at least 3 characters long." }),\n lastName: z\n .string()\n .min(3, { message: "Last name must be at least 3 characters long." }),\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 registerSchema>>({\n resolver: zodResolver(registerSchema),\n defaultValues: {\n firstName: "",\n lastName: "",\n email: "",\n password: "",\n },\n });\n\n function onSubmit(values: z.infer<typeof registerSchema>) {\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/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/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 Create an account\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 <div className="flex gap-2">\n <FormField\n control={form.control}\n name="firstName"\n render={({ field }) => (\n <FormItem>\n <FormLabel>First Name</FormLabel>\n <FormControl>\n <Input placeholder="John" {...field} />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={form.control}\n name="lastName"\n render={({ field }) => (\n <FormItem>\n <FormLabel>Last Name</FormLabel>\n <FormControl>\n <Input placeholder="doe" {...field} />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n </div>\n\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 <div className="py-4 w-full space-y-3">\n <Button type="submit" className="w-full">\n Register\n </Button>\n <Button\n className="w-full"\n variant={"secondary"}\n onClick={() => console.log("Login with Github")}\n >\n Register with Github\n </Button>\n </div>\n\n <Link\n href={"#"}\n className="hover:underline text-xs flex justify-center"\n >\n Already have an account?\n </Link>\n </form>\n </Form>\n </div>\n </div>\n );\n};\n\nexport default Register1;\n',
],
default_export: Register1,
},
{
name: "forgot-1",
files: ["forgot-1.tsx"],
dependencies: ["react-hook-form", "@hookform/resolvers", "zod"],
components: ["button", "input", "form"],
type: "block:component",
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/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/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',
],
default_export: Forgot1,
},
];
29 changes: 29 additions & 0 deletions apps/www/app/(block)/blocks/[name]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { notFound } from "next/navigation";
import { blocks } from "@/registry/blocks";
import { blocks_registry } from "@/__registry__/blocks";

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

// Find the block by name in blocks
const block = blocks.find((block) => block.name === name);
if (!block) {
return notFound();
}

// Load block from blocks_registry and render it
const block_registry = blocks_registry.find((block) => block.name === name);
if (!block_registry) {
return notFound();
}

// Render the component as JSX
const BlockComponent = block_registry.default_export;
return <BlockComponent />;
}
5 changes: 5 additions & 0 deletions apps/www/app/(home)/blocks/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { ReactNode } from "react";

export default function BlocksLayout({ children }: { children: ReactNode }) {
return <div className="mx-4 md:mx-24 lg:mx-36 py-4">{children}</div>;
}
65 changes: 65 additions & 0 deletions apps/www/app/(home)/blocks/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { blocks_registry } from "@/__registry__/blocks";
import React from "react";
import { Button } from "ruru-ui/components/button";
import { Block } from "@/registry/blocks";
import Link from "next/link";
import BlockWrapper from "@/components/ui/block-wrapper";

const BlocksPage = (): React.ReactNode => {
return (
<>
<div>
<div className="w-full my-4 py-4">
<h2 className="scroll-m-20 text-3xl font-semibold tracking-tight first:mt-0">
The Blocks To Build Your App Faster
</h2>
<p className="leading-7 [&:not(:first-child)]:mt-4 text-muted-foreground max-w-[70%]">
Choose from a variety of pre-built components to build your app
faster and easier. Customize the components to fit your brand and
style.
</p>

<div className="flex items-center mt-3 gap-4">
<Link href="/docs">
<Button>Get Started</Button>
</Link>
<Link
href={"https://github.com/ruru-m07/ruru-ui/discussions/new"}
target="_blank"
>
<Button variant={"secondary"}>
<svg
xmlns="http://www.w3.org/2000/svg"
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="lucide lucide-layout-template"
>
<rect width="18" height="7" x="3" y="3" rx="1" />
<rect width="9" height="7" x="3" y="14" rx="1" />
<rect width="5" height="7" x="16" y="14" rx="1" />
</svg>
<span className="ml-2">Request a block</span>
</Button>
</Link>
</div>
</div>
{blocks_registry.map((block, index) => {
return (
<BlockWrapper
key={index}
block={block as unknown as Block & { content: string }}
/>
);
})}
</div>
</>
);
};

export default BlocksPage;
39 changes: 39 additions & 0 deletions apps/www/app/(home)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { ReactNode } from "react";
import { HomeLayout } from "fumadocs-ui/home-layout";
import { baseOptions } from "@/app/layout.config";

export default function Layout({
children,
}: {
children: ReactNode;
}): React.ReactElement {
return (
<HomeLayout {...baseOptions}>
{children}
<Footer />
</HomeLayout>
);
}

function Footer(): React.ReactElement {
return (
<footer className="mt-auto border-t bg-fd-card py-12 text-fd-secondary-foreground">
<div className="container flex flex-col gap-4 ">
<div>
<p className="mb-1 text-sm font-semibold">Ruru UI</p>
<p className="text-xs">
Built with ❤️ by{" "}
<a
href="https://github.com/ruru-m07"
rel="noreferrer noopener"
target="_blank"
className="font-medium"
>
Ruru
</a>
</p>
</div>
</div>
</footer>
);
}
Loading

0 comments on commit def17a2

Please sign in to comment.