diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index d62bbb6..dd7da6d 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -24,8 +24,8 @@ jobs: - name: Build and push to DockerHub run: | - docker build -t devarifhossain/retroui:1.0.12 ./ - docker push devarifhossain/retroui:1.0.12 + docker build -t devarifhossain/retroui:1.0.13 ./ + docker push devarifhossain/retroui:1.0.13 # - name: Set up SSH # uses: webfactory/ssh-agent@v0.9.0 diff --git a/app/(marketing)/blogs/[slug]/page.tsx b/app/(marketing)/blogs/[slug]/page.tsx new file mode 100644 index 0000000..e9c1dd9 --- /dev/null +++ b/app/(marketing)/blogs/[slug]/page.tsx @@ -0,0 +1,107 @@ +import React from "react"; +import { allBlogs } from "contentlayer/generated"; +import { notFound } from "next/navigation"; +import { format } from "date-fns"; +import MDX from "@/components/MDX"; +import { Avatar, Badge, Button, Text } from "@/packages/ui"; +import { Metadata } from "next"; +import { MoveRightIcon, MoveUpRightIcon } from "lucide-react"; +import Image from "next/image"; +import Link from "next/link"; + +interface IProps { + params: { slug: string[] }; +} + +function getBlogParams({ params }: IProps) { + const url = `/blogs/${params.slug}`; + const blog = allBlogs.find((blog) => blog.url === url); + + if (!blog) { + return null; + } + + return blog; +} + +export async function generateMetadata({ params }: IProps): Promise { + const blog = getBlogParams({ params }); + + if (!blog) { + return { + title: "Not Found | Retro UI", + }; + } + + return { + title: `${blog.title} | RetroUI Blogs`, + description: blog.description, + openGraph: { + images: blog.coverImage, + title: `${blog.title} | RetroUI Blogs`, + }, + }; +} + +export default function page({ params }: IProps) { + const blog = getBlogParams({ params }); + + if (!blog) { + return notFound(); + } + + if (!blog.publishedAt || blog.status !== "published") { + return notFound(); + } + + return ( +
+
+ + {format(new Date(blog.publishedAt), "dd, MMMM yyyy")} + + + {blog.title} + +

{blog.description}

+ {blog.title} +
+
+ + + {blog.author.name} + +
+ {blog.author.name} + + @{blog.author.x} + +
+
+ + + + +
+
+ +
+ ); +} diff --git a/app/(marketing)/blogs/layout.tsx b/app/(marketing)/blogs/layout.tsx new file mode 100644 index 0000000..9eab00f --- /dev/null +++ b/app/(marketing)/blogs/layout.tsx @@ -0,0 +1,13 @@ +import { Metadata } from "next"; + +export const metadata: Metadata = { + title: "RetroUI Blogs", +}; + +export default function BlogsLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return
{children}
; +} diff --git a/app/(marketing)/blogs/page.tsx b/app/(marketing)/blogs/page.tsx new file mode 100644 index 0000000..a6236fc --- /dev/null +++ b/app/(marketing)/blogs/page.tsx @@ -0,0 +1,38 @@ +import { allBlogs } from "@/.contentlayer/generated"; +import { Card, Text } from "@/packages/ui"; +import Image from "next/image"; +import Link from "next/link"; +import React from "react"; + +function page() { + const blogs = allBlogs.filter((blog) => blog.status === "published"); + + return ( +
+ + All RetroUI Blogs + +
+ {blogs.map((blog) => ( + + + + {blog.title} + {blog.title} + {blog.description} + + + + ))} +
+
+ ); +} + +export default page; diff --git a/app/(marketing)/page.tsx b/app/(marketing)/page.tsx index 05902cb..162ffc2 100644 --- a/app/(marketing)/page.tsx +++ b/app/(marketing)/page.tsx @@ -63,7 +63,7 @@ export default async function Home() { @@ -311,7 +311,7 @@ export default async function Home() { diff --git a/app/layout.tsx b/app/layout.tsx index 87e2031..f78e64b 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -25,9 +25,13 @@ const shareTechMono = Share_Tech_Mono({ }); export const metadata: Metadata = { - title: "Retro Styled Tailwind UI Library | Retro UI", + title: "Retro Styled React UI Library | Retro UI", description: - "RetroUI - Retro styled TailwindCSS component library for modern web apps.", + "RetroUI - Retro styled component library built with React and TailwindCSS for modern web apps.", + openGraph: { + images: "/banner.png", + title: "Retro Styled React UI Library | Retro UI", + }, }; export default function RootLayout({ @@ -47,7 +51,7 @@ export default function RootLayout({ -
+
{children} diff --git a/app/open-graph.png b/app/open-graph.png deleted file mode 100644 index 503405f..0000000 Binary files a/app/open-graph.png and /dev/null differ diff --git a/app/twitter-image.png b/app/twitter-image.png deleted file mode 100644 index 503405f..0000000 Binary files a/app/twitter-image.png and /dev/null differ diff --git a/components/MDX.tsx b/components/MDX.tsx index ee5374f..edac61a 100644 --- a/components/MDX.tsx +++ b/components/MDX.tsx @@ -2,19 +2,23 @@ import { Text } from "@/packages/ui"; import { useMDXComponent } from "next-contentlayer/hooks"; -import React, { HTMLAttributes } from "react"; +import React, { AnchorHTMLAttributes, HTMLAttributes } from "react"; import { ComponentShowcase } from "./ComponentShowcase"; import { cn } from "@/lib/utils"; import { ComponentSource } from "./ComponentSource"; import { CodeBlock } from "./CodeBlock"; +import Link from "next/link"; -const components = { +const components = (type: "doc" | "blog") => ({ h1: (props: HTMLAttributes) => ( ), - h2: (props: HTMLAttributes) => ( - - ), + h2: (props: HTMLAttributes) => + type === "blog" ? ( + + ) : ( + + ), h3: (props: HTMLAttributes) => ( ), @@ -23,6 +27,50 @@ const components = { ), h5: (props: HTMLAttributes) => , h6: (props: HTMLAttributes) => , + p: (props: HTMLAttributes) => + type === "blog" ? ( + + ) : ( + + ), + li: (props: HTMLAttributes) => + type === "blog" ? ( + + ) : ( + + ), + img: (props: HTMLAttributes) => ( + + ), + a: (props: AnchorHTMLAttributes) => { + const { href, target, rel, ...rest } = props; + + if (!href) { + return ; + } + + const isExternal = href.startsWith("http"); + + return isExternal ? ( + + ) : ( + + ); + }, pre: CodeBlock, code: ({ className, @@ -41,10 +89,16 @@ const components = { ), ComponentShowcase, ComponentSource, -}; +}); -export default function MDX({ code }: { code: string }) { +export default function MDX({ + code, + type = "doc", +}: { + code: string; + type?: "doc" | "blog"; +}) { const Content = useMDXComponent(code); - return ; + return ; } diff --git a/components/TopNav.tsx b/components/TopNav.tsx index bba3aa5..ddc4645 100644 --- a/components/TopNav.tsx +++ b/components/TopNav.tsx @@ -29,12 +29,12 @@ export default function TopNav() {
{/* Navigation Links */} -
+
{navConfig.topNavItems.map((item) => ( {item.title} @@ -47,13 +47,13 @@ export default function TopNav() { target="_blank" rel="noopener noreferrer" > - +
- {/* Star on GitHub - */} - -
diff --git a/config/navigation.ts b/config/navigation.ts index c3e9425..452599b 100644 --- a/config/navigation.ts +++ b/config/navigation.ts @@ -7,6 +7,7 @@ export const navConfig: INavigationConfig = { topNavItems: [ { title: "Documentation", href: "/docs" }, { title: "Components", href: `${componentsRoute}/button` }, + { title: "Blogs", href: "/blogs" }, ], sideNavItems: [ { diff --git a/content/blogs/top-5-react-ui-library.mdx b/content/blogs/top-5-react-ui-library.mdx new file mode 100644 index 0000000..fe62324 --- /dev/null +++ b/content/blogs/top-5-react-ui-library.mdx @@ -0,0 +1,204 @@ +--- +title: Top 5 React UI Libraries in 2025 +coverImage: https://pub-5f7cbdfd9ffa4c838e386788f395f0c4.r2.dev/blogs/top-5-react-ui-library/cover.png +description: Using UI libraries can significantly speed up your development. In this article, we will explore the top 5 for your next React project. +tags: + - react + - ui library + - top 5 +author: + name: Arif Hossain + avatar: https://pub-5f7cbdfd9ffa4c838e386788f395f0c4.r2.dev/arif.jpg + x: ariflogs +status: published +publishedAt: 12 Feb, 2024 +--- + +React remains one of the most popular JavaScript frameworks for building web applications, and UI libraries play a important role in speeding up development. Using UI libraries can significantly speed up your development process and help you create consistent, high-quality user interfaces. + +
+Fortunately, there are many React great UI libraries available that can help you +achieve this. Here are the top 5 React UI libraries in 2025 that you should consider +using in your next project. + +
+
+ +## [1. RetroUI](https://retroui.dev) + +![RetroUI cover](https://pub-5f7cbdfd9ffa4c838e386788f395f0c4.r2.dev/retroui_landing_w_frame.png) + +If you are bored with generic looking UI libraries, you should check out [RetroUI](https://retroui.dev). It brings a combination of retro and modern design elements to create a unique and memorable user experience. +The library is built with React and Tailwind CSS, making it easy to integrate into your existing projects. + +
+ +RetroUI comes with 100+ utility components, including `buttons`, `cards`, `modals`, and more that you can just copy-paste into your projects. + +
+ +#### Why use RetroUI in 2025? + +- **Unique Design:** RetroUI's unique design elements make it stand out from other UI libraries. +- **Easy to Use:** RetroUI's components are easy to use and can be customized with Tailwind CSS. +- **Bold Design System:** For websites that aims to look bold, RetroUI can be a perfect fit. + +
+ +#### Drawbacks + +- **Bold Design System:** RetroUI's biggest benefit can also be it's biggest drawback, If you are looking for a more subtle design, RetroUI might not be the best fit. +- **Smaller Community Size:** As a new UI library, RetroUI doesn't have a large community yet compared to other mainstream libraries. + +
+ +#### Use Case + +Perfect for someone looking to combine old school and modern design! + +
+
+ +## [2. Chakra UI](https://chakra-ui.com) + +![ChakraUI cover](https://pub-5f7cbdfd9ffa4c838e386788f395f0c4.r2.dev/chakraui_landing_w_frame.png) +Chakra UI has gained popularity for its simplicity and flexibility. It offers a modern, accessible, and easy-to-use components that can fit any React applications. + +
+ +#### Why Chakra UI in 2025? + +- Large Selection of Components: Chakra UI offers a wide range of components, including `dialogs`, `forms`, `icons`, `stats`, and more. +- Ease of Styling: Chakra UI Uses a prop-based styling approach that allows for easily customize the components. +- Theming Support: Chakra UI allows deep customization along with a playground where you can try and test your themes. +- Utilities: Chakra UI also provides a bunch of helper components that can handle some common functionalities. + +```js +import { FormatNumber } from "@chakra-ui/react"; + +; +``` + +
+ +#### Drawbacks + +- Heavy: The unpacked size of Chakra UI is over 2MB, and combining that with it's core dependencies, can make Chakra UI a heavy library to use. + +
+ +#### Use Case + +Developers who don't wanna spend a lot of time on building/styling UIs, as ChakraUI has almost all the common components you can think of. + +
+
+ +## [3. Shadcn/UI](https://ui.shadcn.com/) + +![Shadcn cover](https://pub-5f7cbdfd9ffa4c838e386788f395f0c4.r2.dev/shadcn_landing_w_frame.png) + +Shadcn is not necessarily a UI library, but a collection of UI components that you can use to build your own UI library. It's a great starting point for building your own UI library, as it provides a lot of components that you can use and customize. + +
+ +#### Why Use ShadCN in 2025? + +- Fully Customizable: Unlike traditional UI kits, it doesn't have a specific design language. You can fully customize it to match your brand's design. +- Minimalistic Design: If you like clean and minimalistic design, you'll love ShadCN. +- Backed by Vercel: Shadcn is now managed by Vercel and integrates well with other Vercel products like NextJS, v0 and AI SDK. +- Developer-Friendly: No lock-in—just import and customize as needed. + +
+ +#### Drawbacks of ShadCN + +- **Learning Curve:** If you're new to component libraries, it might take some time to get used to. +- **Looks Generic:** ShadCN components look generic, as it's meant to be. So you might have to put some effort into making them look unique. + +
+
+ +## [4. Hero UI](https://www.heroui.com/) + +![HeroUI cover](https://pub-5f7cbdfd9ffa4c838e386788f395f0c4.r2.dev/heroui_landing_w_frame.png) + +Hero UI is a relatively newer UI library that offers a wide range of base and animated components for Next.js and React applications. + +
+ +#### Why use Hero UI in 2025? + +- Modern Design: Hero UI offers a modern and sleek design that is perfect for building responsive and accessible applications. +- Animation Support: Most of it's components supports animations out of the box. +- Developer-Friendly: Hero UI is easy to use and integrate with existing React projects. +- CLI Support: Hero UI comes with a CLI that makes it easy to initialize new projects and install components. + +#### Drawbacks + +- **Limited Customization:** Hero UI has a opinionated design, so you might not be able to customize it as much as you want. + +
+ +#### Use Case: + +If you want to make your website look and feel like Apple's, Hero UI is the go-to choice. + +
+
+ +## [5. Mantine](https://mantine.dev/) + +![Mentine info](https://pub-5f7cbdfd9ffa4c838e386788f395f0c4.r2.dev/mentine_landing_w_frame.png) + +Mentine is a fully featured React UI library that offers a wide range of components, hooks, and utilities for building modern web applications. + +**Why Mantine in 2025?** + +- Rich Component Library: Mantine offers a wide range of components, from basic `buttons` to complex `data tables`. +- Hooks-Based: Mantine's hooks-based architecture makes it easy to integrate with existing React projects. +- Extensions: Mentine offers some free extensions like `Code Highlight`, `Rich text editor` that can come in handy. + +```jsx +import { CodeHighlight } from "@mantine/code-highlight"; + +const exampleCode = ` +function Button() { + return ; +} +`; + +function Demo() { + return ( + + ); +} +``` + +- Focus on DX: Mantine prioritizes developer experience with excellent documentation and TypeScript support. + +#### Drawbacks: + +- Large Size: Mantine's extensive feature set comes at the cost of a larger bundle size! +- Learning Curve: Mentine as so many features like `@mentine/hooks`, `@mentine/charts`, `extensions` and much more which can be overwhelming for beginners. + +#### Use Case: + +Mentine is a great choice for data intensive applications, dashboards, and admin panels. + +
+
+ +### **Conclusion** + +In 2025, the React ecosystem is more vibrant than ever, with UI libraries catering to a wide range of needs. Whether you're looking for a minimal design system like [Shadcn](https://ui.shadcn.com), or an bold design system like [RetroUI](https://retroui.dev), there's a React UI library for almost every project. + +When choosing a library, consider factors like customization, performance, accessibility, and community support. Each of these top 5 libraries has its strengths, so pick the one that aligns best with your project requirements and development style. + +
+
diff --git a/contentlayer.config.ts b/contentlayer.config.ts index a0fc1e5..1781a6f 100644 --- a/contentlayer.config.ts +++ b/contentlayer.config.ts @@ -44,6 +44,36 @@ export const Doc = defineDocumentType(() => ({ }, })); +const Author = defineNestedType(() => ({ + name: "Author", + fields: { + name: { type: "string", required: true }, + avatar: { type: "string", required: true }, + x: { type: "string", required: false }, + }, +})); + +export const Blog = defineDocumentType(() => ({ + name: "Blog", + filePathPattern: `blogs/**/*.mdx`, + contentType: "mdx", + fields: { + title: { type: "string", required: true }, + description: { type: "string", required: true }, + coverImage: { type: "string", required: true }, + publishedAt: { type: "date" }, + author: { type: "nested", required: true, of: Author }, + tags: { type: "list", required: true, of: { type: "string" } }, + status: { type: "enum", options: ["draft", "published"], default: "draft" }, + }, + computedFields: { + url: { + type: "string", + resolve: (doc) => `/${doc._raw.flattenedPath}`, + }, + }, +})); + export default makeSource({ mdx: { remarkPlugins: [], @@ -139,7 +169,7 @@ export default makeSource({ ], }, contentDirPath: "./content", - documentTypes: [Doc], + documentTypes: [Doc, Blog], }); const getNodeAttributeByName = (node: UnistNode, name: string) => { diff --git a/next.config.mjs b/next.config.mjs index dbab98b..bce917b 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,6 +1,17 @@ -import { withContentlayer } from 'next-contentlayer' +import { withContentlayer } from "next-contentlayer"; /** @type {import('next').NextConfig} */ -const nextConfig = { reactStrictMode: true, swcMinify: true } +const nextConfig = { + reactStrictMode: true, + swcMinify: true, + images: { + remotePatterns: [ + { + protocol: "https", + hostname: "pub-5f7cbdfd9ffa4c838e386788f395f0c4.r2.dev", + }, + ], + }, +}; -export default withContentlayer(nextConfig) \ No newline at end of file +export default withContentlayer(nextConfig); diff --git a/packages/ui/Text/Text.tsx b/packages/ui/Text/Text.tsx index f7d609f..1461068 100644 --- a/packages/ui/Text/Text.tsx +++ b/packages/ui/Text/Text.tsx @@ -6,12 +6,14 @@ const textVariants = cva("font-head", { variants: { as: { p: "font-sans text-base", + li: "font-sans text-base", + a: "font-sans text-base hover:underline underline-offset-2 decoration-primary-500", h1: "text-5xl lg:text-6xl font-bold", - h2: "text-3xl lg:text-5xl font-semibold", - h3: "text-2xl lg:text-3xl font-medium", - h4: "text-xl font-medium", - h5: "text-lg font-medium", - h6: "", + h2: "text-3xl lg:text-4xl font-semibold", + h3: "text-2xl font-medium", + h4: "text-xl font-normal", + h5: "text-lg font-normal", + h6: "text-base font-normal", }, }, defaultVariants: { diff --git a/public/banner.png b/public/banner.png index 55267ec..4b710a5 100644 Binary files a/public/banner.png and b/public/banner.png differ diff --git a/public/images/blogs/top-5-react-ui-library/cover.png b/public/images/blogs/top-5-react-ui-library/cover.png new file mode 100644 index 0000000..393bd6f Binary files /dev/null and b/public/images/blogs/top-5-react-ui-library/cover.png differ