ratkit 0.2.16

A comprehensive collection of reusable TUI components for ratatui including resizable splits, tree views, markdown rendering, toast notifications, dialogs, and terminal embedding
Documentation
"use client";
import { DynamicCodeBlock } from "fumadocs-ui/components/dynamic-codeblock";
import {
	Tabs,
	TabsContent,
	TabsList,
	TabsTrigger,
} from "fumadocs-ui/components/tabs";
import { Check, Copy, Layout, MousePointer, PanelLeft, SquareArrowOutUpRight, Type } from "lucide-react";
import Link from "next/link";
import { useTheme } from "next-themes";
import { useEffect, useMemo, useState } from "react";
import { useServerTheme } from "@/components/theme-provider";
import { Button } from "@/components/ui/button";

export function Hero() {
	const [copied, setCopied] = useState(false);
	const { resolvedTheme } = useTheme();
	const { serverTheme } = useServerTheme();
	const theme = resolvedTheme || serverTheme;
	const isDark = theme === "dark";

	useEffect(() => {
		if (copied) {
			const timer = setTimeout(() => setCopied(false), 2000);
			return () => clearTimeout(timer);
		}
	}, [copied]);

	const gridColor = isDark ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.08)";
	const overlayBackground = isDark
		? "radial-gradient(ellipse 120% 100% at 50% 0%, transparent 0%, rgba(0,0,0,0.3) 60%, rgba(0,0,0,0.7) 100%)"
		: "radial-gradient(ellipse 120% 100% at 50% 0%, transparent 0%, rgba(255,255,255,0.3) 60%, rgba(255,255,255,0.7) 100%)";

	return (
		<div className="hero-component relative flex flex-col items-center justify-center min-h-screen w-full overflow-hidden pt-24 p-0 sm:p-4 md:pt-32 lg:p-8">
			{/* Background Grid with Gradient Overlay */}
			<div className="absolute inset-0 pointer-events-none">
				{/* Grid Pattern */}
				<div
					className="absolute inset-0"
					style={{
						backgroundImage: `
              linear-gradient(to right, ${gridColor} 1px, transparent 1px),
              linear-gradient(to bottom, ${gridColor} 1px, transparent 1px)
            `,
						backgroundSize: "80px 80px",
					}}
				/>

				{/* Gradient Overlay - subtle fade */}
				<div
					className="absolute inset-0"
					style={{
						background: overlayBackground,
					}}
				/>
			</div>

			<div className="relative z-10 grid grid-cols-1 lg:grid-cols-2 gap-6 md:gap-12 max-w-7xl w-full items-center mt-8">
				{/* Left Column */}
				<div className="flex flex-col items-center text-center space-y-4 sm:space-y-6 lg:items-start lg:text-left">

					<h1 className="text-3xl sm:text-5xl xl:text-[3.5rem] font-bold tracking-tight text-black dark:text-white leading-tight">
						TUI Toolkit for <span className="text-[#ef4444]">Rust</span>
					</h1>

					<p className="text-xs sm:text-base text-gray-600 dark:text-gray-400 max-w-sm sm:max-w-xl md:max-w-lg">
						A comprehensive collection of reusable TUI components for ratatui.
						Build beautiful terminal interfaces with ease.
					</p>

					{/* Command Snippet */}
					<div className="w-full mt-4 rounded max-w-xs sm:mt-0 sm:max-w-md bg-white border border-black/10 dark:bg-[#111111] dark:border-[#ef4444]/30 p-2.5 flex items-center gap-2.5 font-mono text-xs">
						<span className="text-[#ef4444] mr-1">$</span>
						<span className="text-black dark:text-white font-semibold">
							<span className="text-[#06b6d4] dark:text-[#06b6d4]">cargo</span> add{" "}
							<span className="text-[#ef4444]">ratkit</span>
						</span>
						<div className="flex-1" />
						{copied ? (
							<Check className="w-3.5 h-3.5 text-black dark:text-white" />
						) : (
							<Copy
								className="w-3.5 h-3.5 text-gray-500 cursor-pointer hover:text-black dark:hover:text-white transition-colors"
								onClick={() => {
									navigator.clipboard.writeText("cargo add ratkit");
									setCopied(true);
								}}
							/>
						)}
					</div>
					<div className="flex flex-wrap gap-3">
						<Button
							asChild
							size="sm"
							className="bg-[#ef4444] dark:bg-[#ef4444] rounded font-semibold text-white text-xs sm:text-sm hover:bg-[#dc2626] dark:hover:bg-[#dc2626] px-2 sm:px-6 border-0"
						>
							<Link href="/docs">GET STARTED</Link>
						</Button>
						<Button
							variant="outline"
							size="sm"
							asChild
							className="px-2 sm:px-6 rounded text-xs sm:text-sm border-[#ef4444]/50 dark:border-[#ef4444]/50 bg-transparent text-black dark:text-white hover:bg-[#ef4444]/10 dark:hover:bg-[#ef4444]/10 hover:text-[#ef4444] dark:hover:text-[#ef4444]"
						>
							<Link href="https://github.com/Alpha-Innovation-Labs/ratkit" target="_blank">
								<SquareArrowOutUpRight className="mr-1 h-4 w-4" />
								View on GitHub
							</Link>
						</Button>
					</div>
				</div>

				{/* Right Column - Code Window */}
				<div className="relative w-full mt-8 md:mt-0 p-1 sm:p-0">
					<ComponentExampleCodeTabs />
				</div>
			</div>
		</div>
	);
}

const ComponentExampleCodeTabs = () => {
	const [activeCategory, setActiveCategory] = useState<Category>("button");

	/* ------------------------------------------------------------------ */
	/* Types */
	/* ------------------------------------------------------------------ */

	type Category = "button" | "dialog" | "scroll" | "grid";

	const CATEGORIES: Record<Category, { label: string; icon: React.ReactNode }> = {
		button: { label: "Button", icon: <MousePointer className="w-4 h-4 mr-2" /> },
		dialog: { label: "Dialog", icon: <PanelLeft className="w-4 h-4 mr-2" /> },
		scroll: { label: "Scroll", icon: <Layout className="w-4 h-4 mr-4" /> },
		grid: { label: "Grid", icon: <Layout className="w-4 h-4 mr-2" /> },
	};

	const TEMPLATES: Record<Category, string> = {
		button: `use ratkit::primitives::button::{Button, ButtonState};
use ratatui::Frame;

fn render_button(frame: &mut Frame) {
    let button = Button::new("Click Me")
        .style(Style::default().fg(Color::White))
        .highlight_style(Style::default().fg(Color::Yellow));
    
    frame.render_widget(button, frame.area());
}`,

		dialog: `use ratkit::primitives::dialog::Dialog;
use ratatui::Frame;

fn show_dialog(frame: &mut Frame) {
    let dialog = Dialog::new()
        .title("Confirm Action")
        .content("Are you sure you want to continue?")
        .button("Yes", DialogAction::Confirm)
        .button("No", DialogAction::Cancel);
    
    frame.render_widget(dialog, frame.area());
}`,

		scroll: `use ratkit::primitives::scroll::{ScrollArea, ScrollState};
use ratatui::Frame;

fn render_scrollable(frame: &mut Frame) {
    let mut state = ScrollState::default();
    
    let scroll = ScrollArea::vertical()
        .content(&long_content)
        .scroll_state(&mut state);
    
    frame.render_stateful_widget(
        scroll, 
        frame.area(), 
        &mut state
    );
}`,

		grid: `use ratkit::primitives::resizable_grid::ResizableGrid;
use ratatui::Frame;

fn render_grid(frame: &mut Frame) {
    let grid = ResizableGrid::new(3, 3)
        .column_constraints(vec![
            Constraint::Percentage(33),
            Constraint::Percentage(33),
            Constraint::Percentage(33),
        ])
        .resizable(true);
    
    frame.render_widget(grid, frame.area());
}`,
	};

	const codes = useMemo(() => TEMPLATES, []);

	return (
		<div className="flex flex-col space-y-4 w-full max-w-2xl mx-auto">
			{/* Category Switch */}
			<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between w-full gap-4">
				<div className="flex p-1 bg-black/5 dark:bg-white/5 rounded-xs w-fit">
					{(Object.keys(CATEGORIES) as Category[]).map((cat) => (
						<button
							key={cat}
							type="button"
							onClick={() => setActiveCategory(cat)}
							className={`px-2 py-1.5 text-xs lg:text-[10px] xl:text-xs sm:px-4 font-medium rounded-xs transition-all cursor-pointer flex items-center ${
								activeCategory === cat
									? "bg-white dark:bg-zinc-800 text-black dark:text-white shadow-sm"
									: "text-gray-500 hover:text-black dark:hover:text-white"
							}`}
						>
							{CATEGORIES[cat].icon}
							{CATEGORIES[cat].label}
						</button>
					))}
				</div>
			</div>

			{/* Code Display */}
			<div className="custom-code-block rounded-xs">
				<DynamicCodeBlock
					lang="rust"
					code={codes[activeCategory]}
				/>
			</div>
		</div>
	);
};