parent
011c55f61c
commit
55022e5ed2
@ -1,26 +1,122 @@
|
||||
@import "tailwindcss";
|
||||
@import "tw-animate-css";
|
||||
|
||||
:root {
|
||||
--background: #ffffff;
|
||||
--foreground: #171717;
|
||||
}
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
@theme inline {
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--font-sans: var(--font-geist-sans);
|
||||
--font-mono: var(--font-geist-mono);
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
--color-sidebar-accent: var(--sidebar-accent);
|
||||
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||
--color-sidebar-primary: var(--sidebar-primary);
|
||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||
--color-sidebar: var(--sidebar);
|
||||
--color-chart-5: var(--chart-5);
|
||||
--color-chart-4: var(--chart-4);
|
||||
--color-chart-3: var(--chart-3);
|
||||
--color-chart-2: var(--chart-2);
|
||||
--color-chart-1: var(--chart-1);
|
||||
--color-ring: var(--ring);
|
||||
--color-input: var(--input);
|
||||
--color-border: var(--border);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-card: var(--card);
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--background: #0a0a0a;
|
||||
--foreground: #ededed;
|
||||
}
|
||||
:root {
|
||||
--radius: 0.625rem;
|
||||
--background: oklch(1 0 0);
|
||||
--foreground: oklch(0.145 0 0);
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.145 0 0);
|
||||
--popover: oklch(1 0 0);
|
||||
--popover-foreground: oklch(0.145 0 0);
|
||||
--primary: oklch(0.205 0 0);
|
||||
--primary-foreground: oklch(0.985 0 0);
|
||||
--secondary: oklch(0.97 0 0);
|
||||
--secondary-foreground: oklch(0.205 0 0);
|
||||
--muted: oklch(0.97 0 0);
|
||||
--muted-foreground: oklch(0.556 0 0);
|
||||
--accent: oklch(0.97 0 0);
|
||||
--accent-foreground: oklch(0.205 0 0);
|
||||
--destructive: oklch(0.577 0.245 27.325);
|
||||
--border: oklch(0.922 0 0);
|
||||
--input: oklch(0.922 0 0);
|
||||
--ring: oklch(0.708 0 0);
|
||||
--chart-1: oklch(0.646 0.222 41.116);
|
||||
--chart-2: oklch(0.6 0.118 184.704);
|
||||
--chart-3: oklch(0.398 0.07 227.392);
|
||||
--chart-4: oklch(0.828 0.189 84.429);
|
||||
--chart-5: oklch(0.769 0.188 70.08);
|
||||
--sidebar: oklch(0.985 0 0);
|
||||
--sidebar-foreground: oklch(0.145 0 0);
|
||||
--sidebar-primary: oklch(0.205 0 0);
|
||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||
--sidebar-accent: oklch(0.97 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.205 0 0);
|
||||
--sidebar-border: oklch(0.922 0 0);
|
||||
--sidebar-ring: oklch(0.708 0 0);
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--background);
|
||||
color: var(--foreground);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
.dark {
|
||||
--background: oklch(0.145 0 0);
|
||||
--foreground: oklch(0.985 0 0);
|
||||
--card: oklch(0.205 0 0);
|
||||
--card-foreground: oklch(0.985 0 0);
|
||||
--popover: oklch(0.205 0 0);
|
||||
--popover-foreground: oklch(0.985 0 0);
|
||||
--primary: oklch(0.922 0 0);
|
||||
--primary-foreground: oklch(0.205 0 0);
|
||||
--secondary: oklch(0.269 0 0);
|
||||
--secondary-foreground: oklch(0.985 0 0);
|
||||
--muted: oklch(0.269 0 0);
|
||||
--muted-foreground: oklch(0.708 0 0);
|
||||
--accent: oklch(0.269 0 0);
|
||||
--accent-foreground: oklch(0.985 0 0);
|
||||
--destructive: oklch(0.704 0.191 22.216);
|
||||
--border: oklch(1 0 0 / 10%);
|
||||
--input: oklch(1 0 0 / 15%);
|
||||
--ring: oklch(0.556 0 0);
|
||||
--chart-1: oklch(0.488 0.243 264.376);
|
||||
--chart-2: oklch(0.696 0.17 162.48);
|
||||
--chart-3: oklch(0.769 0.188 70.08);
|
||||
--chart-4: oklch(0.627 0.265 303.9);
|
||||
--chart-5: oklch(0.645 0.246 16.439);
|
||||
--sidebar: oklch(0.205 0 0);
|
||||
--sidebar-foreground: oklch(0.985 0 0);
|
||||
--sidebar-primary: oklch(0.488 0.243 264.376);
|
||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||
--sidebar-accent: oklch(0.269 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.985 0 0);
|
||||
--sidebar-border: oklch(1 0 0 / 10%);
|
||||
--sidebar-ring: oklch(0.556 0 0);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border outline-ring/50;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,65 +1,264 @@
|
||||
import Image from "next/image";
|
||||
import UploadArea from "@/components/UploadArea";
|
||||
import {
|
||||
NavigationMenu,
|
||||
NavigationMenuList,
|
||||
NavigationMenuItem,
|
||||
NavigationMenuLink,
|
||||
} from "@/components/ui/navigation-menu";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center bg-zinc-50 font-sans dark:bg-black">
|
||||
<main className="flex min-h-screen w-full max-w-3xl flex-col items-center justify-between py-32 px-16 bg-white dark:bg-black sm:items-start">
|
||||
<Image
|
||||
className="dark:invert"
|
||||
src="/next.svg"
|
||||
alt="Next.js logo"
|
||||
width={100}
|
||||
height={20}
|
||||
priority
|
||||
/>
|
||||
<div className="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
|
||||
<h1 className="max-w-xs text-3xl font-semibold leading-10 tracking-tight text-black dark:text-zinc-50">
|
||||
To get started, edit the page.tsx file.
|
||||
</h1>
|
||||
<p className="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400">
|
||||
Looking for a starting point or more instructions? Head over to{" "}
|
||||
<a
|
||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
className="font-medium text-zinc-950 dark:text-zinc-50"
|
||||
<div className="min-h-screen" style={{ backgroundColor: "#FFFFFF" }}>
|
||||
{/* Sticky Navigation */}
|
||||
<nav className="sticky top-0 z-50 bg-white/95 backdrop-blur-sm border-b border-gray-200">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="flex justify-between items-center h-16">
|
||||
{/* Logo */}
|
||||
<div className="flex-shrink-0">
|
||||
<Image src="/reya2.svg" alt="Reya Logo" width={120} height={40} />
|
||||
</div>
|
||||
|
||||
{/* Navigation Menu */}
|
||||
<NavigationMenu className="hidden md:flex">
|
||||
<NavigationMenuList>
|
||||
<NavigationMenuItem>
|
||||
<NavigationMenuLink
|
||||
href="/contact"
|
||||
className="px-4 py-2 text-gray-700 hover:text-gray-900"
|
||||
>
|
||||
Contact
|
||||
</NavigationMenuLink>
|
||||
</NavigationMenuItem>
|
||||
<NavigationMenuItem>
|
||||
<NavigationMenuLink
|
||||
href="/pricing"
|
||||
className="px-4 py-2 text-gray-700 hover:text-gray-900"
|
||||
>
|
||||
Pricing
|
||||
</NavigationMenuLink>
|
||||
</NavigationMenuItem>
|
||||
</NavigationMenuList>
|
||||
</NavigationMenu>
|
||||
|
||||
{/* Auth Buttons */}
|
||||
<div className="flex items-center space-x-4">
|
||||
<button className="text-gray-700 hover:text-gray-900 px-4 py-2 border border-gray-300 hover:border-gray-400 rounded-md cursor-pointer transition-colors">
|
||||
Log In
|
||||
</button>
|
||||
<button className="bg-orange-500 hover:bg-orange-600 text-white px-6 py-2 rounded-md font-medium cursor-pointer transition-colors">
|
||||
Sign Up
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{/* Main Content */}
|
||||
<div className="flex items-center justify-center min-h-screen">
|
||||
<div
|
||||
className="w-[90%] h-[600px] rounded-2xl flex justify-between items-start relative"
|
||||
style={{
|
||||
backgroundColor: "#FF580F",
|
||||
margin: "20px",
|
||||
marginTop: "5px",
|
||||
}}
|
||||
>
|
||||
<div className="ml-8 mt-16">
|
||||
<h1
|
||||
className="text-white text-6xl font-bold mb-4"
|
||||
style={{ fontFamily: "Inter, sans-serif" }}
|
||||
>
|
||||
Templates
|
||||
</a>{" "}
|
||||
or the{" "}
|
||||
<a
|
||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
className="font-medium text-zinc-950 dark:text-zinc-50"
|
||||
Welcome to reYa Render
|
||||
</h1>
|
||||
<p
|
||||
className="text-white text-2xl"
|
||||
style={{ width: "600px", fontFamily: "Inter, sans-serif" }}
|
||||
>
|
||||
Learning
|
||||
</a>{" "}
|
||||
center.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4 text-base font-medium sm:flex-row">
|
||||
<a
|
||||
className="flex h-12 w-full items-center justify-center gap-2 rounded-full bg-foreground px-5 text-background transition-colors hover:bg-[#383838] dark:hover:bg-[#ccc] md:w-[158px]"
|
||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
className="dark:invert"
|
||||
src="/vercel.svg"
|
||||
alt="Vercel logomark"
|
||||
width={16}
|
||||
height={16}
|
||||
Whether you're working on animations, visualizations, or still
|
||||
images, our render farm is optimized to deliver high-quality
|
||||
results efficiently. Simply upload your files, and our system will
|
||||
take care of the rendering process, saving you time and computing
|
||||
power so you can focus on the creative side of your work.
|
||||
</p>
|
||||
<div className="flex gap-4 mt-6">
|
||||
<button className="bg-white text-orange-500 px-6 py-3 rounded-md font-medium hover:bg-gray-100 cursor-pointer transition-colors">
|
||||
Contact Us
|
||||
</button>
|
||||
<button className="bg-transparent border-2 border-white text-white px-6 py-3 rounded-md font-medium hover:bg-white hover:text-orange-500 cursor-pointer transition-colors">
|
||||
Get Started
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="absolute bottom-4 right-4">
|
||||
<img
|
||||
src="/3d-model.png"
|
||||
alt="3D Model"
|
||||
width={500}
|
||||
height={500}
|
||||
style={{ display: "block" }}
|
||||
/>
|
||||
Deploy Now
|
||||
</a>
|
||||
<a
|
||||
className="flex h-12 w-full items-center justify-center rounded-full border border-solid border-black/[.08] px-5 transition-colors hover:border-transparent hover:bg-black/[.04] dark:border-white/[.145] dark:hover:bg-[#1a1a1a] md:w-[158px]"
|
||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Documentation
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Pricing Section */}
|
||||
<div className="flex justify-center mt-16 mb-16">
|
||||
<div className="w-[90%]">
|
||||
<h2 className="text-4xl font-bold text-center mb-12 text-gray-800">
|
||||
Available Plans
|
||||
</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||
{/* Basic Plan */}
|
||||
<div className="bg-white border-2 border-gray-200 rounded-xl p-8 text-center transition-all hover:transform hover:-translate-y-2 hover:shadow-xl hover:border-orange-500 cursor-pointer">
|
||||
<div className="text-2xl font-bold text-orange-500 mb-2">
|
||||
Basic
|
||||
</div>
|
||||
<div className="text-4xl font-bold text-orange-500 mb-8">
|
||||
€9.99{" "}
|
||||
<span className="text-lg font-normal text-gray-500">
|
||||
/month
|
||||
</span>
|
||||
</div>
|
||||
<button className="w-full bg-orange-500 text-white py-3 px-6 rounded-lg font-medium mb-6 hover:bg-orange-600 transition-colors hover:cursor-pointer">
|
||||
Choose Basic
|
||||
</button>
|
||||
<ul className="text-left space-y-3">
|
||||
<li className="flex items-center">
|
||||
<span className="text-green-500 font-bold mr-3">✓</span>
|
||||
250 GB storage
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<span className="text-green-500 font-bold mr-3">✓</span>
|
||||
Custom subdomain
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<span className="text-green-500 font-bold mr-3">✓</span>
|
||||
Unlimited downloads
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<span className="text-green-500 font-bold mr-3">✓</span>
|
||||
Password protected links
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<span className="text-green-500 font-bold mr-3">✓</span>
|
||||
Basic analytics
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Standard Plan */}
|
||||
<div className="bg-white border-2 border-gray-200 rounded-xl p-8 text-center transition-all hover:transform hover:-translate-y-2 hover:shadow-xl hover:border-orange-500 cursor-pointer">
|
||||
<div className="text-2xl font-bold text-orange-500 mb-2">
|
||||
Standard
|
||||
</div>
|
||||
<div className="text-4xl font-bold text-orange-500 mb-8">
|
||||
€19.99{" "}
|
||||
<span className="text-lg font-normal text-gray-500">
|
||||
/month
|
||||
</span>
|
||||
</div>
|
||||
<button className="w-full bg-orange-500 text-white py-3 px-6 rounded-lg font-medium mb-6 hover:bg-orange-600 transition-colors hover:cursor-pointer">
|
||||
Choose Standard
|
||||
</button>
|
||||
<ul className="text-left space-y-3">
|
||||
<li className="flex items-center">
|
||||
<span className="text-green-500 font-bold mr-3">✓</span>
|
||||
500 GB storage
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<span className="text-green-500 font-bold mr-3">✓</span>
|
||||
Custom subdomain
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<span className="text-green-500 font-bold mr-3">✓</span>
|
||||
Unlimited downloads
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<span className="text-green-500 font-bold mr-3">✓</span>
|
||||
Password protected links
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<span className="text-green-500 font-bold mr-3">✓</span>
|
||||
Basic analytics
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<span className="text-green-500 font-bold mr-3">✓</span>
|
||||
Custom branding & logo
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<span className="text-green-500 font-bold mr-3">✓</span>
|
||||
Priority support
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Premium Plan */}
|
||||
<div className="bg-white border-2 border-gray-200 rounded-xl p-8 text-center transition-all hover:transform hover:-translate-y-2 hover:shadow-xl hover:border-orange-500 cursor-pointer">
|
||||
<div className="text-2xl font-bold text-orange-500 mb-2">
|
||||
Premium
|
||||
</div>
|
||||
<div className="text-4xl font-bold text-orange-500 mb-8">
|
||||
€39.99{" "}
|
||||
<span className="text-lg font-normal text-gray-500">
|
||||
/month
|
||||
</span>
|
||||
</div>
|
||||
<button className="w-full bg-orange-500 text-white py-3 px-6 rounded-lg font-medium mb-6 hover:bg-orange-600 transition-colors hover:cursor-pointer">
|
||||
Choose Premium
|
||||
</button>
|
||||
<ul className="text-left space-y-3">
|
||||
<li className="flex items-center">
|
||||
<span className="text-green-500 font-bold mr-3">✓</span>1 TB
|
||||
storage
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<span className="text-green-500 font-bold mr-3">✓</span>
|
||||
Custom subdomain
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<span className="text-green-500 font-bold mr-3">✓</span>
|
||||
Unlimited downloads
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<span className="text-green-500 font-bold mr-3">✓</span>
|
||||
Password protected links
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<span className="text-green-500 font-bold mr-3">✓</span>
|
||||
Basic analytics
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<span className="text-green-500 font-bold mr-3">✓</span>
|
||||
Custom branding & logo
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<span className="text-green-500 font-bold mr-3">✓</span>
|
||||
Priority support
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<span className="text-green-500 font-bold mr-3">✓</span>
|
||||
Multiple user accounts
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<span className="text-green-500 font-bold mr-3">✓</span>
|
||||
Team management
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Upload area below hero, same width as orange container */}
|
||||
<div className="flex justify-center">
|
||||
<div className="w-[90%] mt-6 mb-12">
|
||||
<h2 className="text-4xl font-bold text-left mb-8 text-gray-800">
|
||||
Start by uploading at least one .blend file
|
||||
</h2>
|
||||
<UploadArea className="w-full shadow-sm" />
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "new-york",
|
||||
"rsc": true,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "",
|
||||
"css": "app/globals.css",
|
||||
"baseColor": "neutral",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
"iconLibrary": "lucide",
|
||||
"aliases": {
|
||||
"components": "@/components",
|
||||
"utils": "@/lib/utils",
|
||||
"ui": "@/components/ui",
|
||||
"lib": "@/lib",
|
||||
"hooks": "@/hooks"
|
||||
},
|
||||
"registries": {}
|
||||
}
|
||||
@ -0,0 +1,89 @@
|
||||
"use client";
|
||||
|
||||
import React, { useRef, useState } from "react";
|
||||
|
||||
type UploadAreaProps = {
|
||||
onFilesSelected?: (files: FileList) => void;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export default function UploadArea({
|
||||
onFilesSelected,
|
||||
className,
|
||||
}: UploadAreaProps) {
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
|
||||
const handleClick = () => fileInputRef.current?.click();
|
||||
|
||||
const handleDragOver: React.DragEventHandler<HTMLDivElement> = (e) => {
|
||||
e.preventDefault();
|
||||
setIsDragging(true);
|
||||
};
|
||||
|
||||
const handleDragLeave: React.DragEventHandler<HTMLDivElement> = () => {
|
||||
setIsDragging(false);
|
||||
};
|
||||
|
||||
const handleDrop: React.DragEventHandler<HTMLDivElement> = (e) => {
|
||||
e.preventDefault();
|
||||
setIsDragging(false);
|
||||
if (e.dataTransfer?.files?.length) {
|
||||
onFilesSelected?.(e.dataTransfer.files);
|
||||
}
|
||||
};
|
||||
|
||||
const handleChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
|
||||
if (e.target.files?.length) {
|
||||
onFilesSelected?.(e.target.files);
|
||||
// reset input to allow re-selecting the same file
|
||||
e.currentTarget.value = "";
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
role="button"
|
||||
aria-label="Upload files"
|
||||
onClick={handleClick}
|
||||
onDragOver={handleDragOver}
|
||||
onDragLeave={handleDragLeave}
|
||||
onDrop={handleDrop}
|
||||
className={`rounded-xl border-2 border-dashed bg-white text-gray-700 cursor-pointer transition-colors ${
|
||||
isDragging
|
||||
? "border-gray-400 bg-gray-50"
|
||||
: "border-gray-300 hover:border-gray-400"
|
||||
} ${
|
||||
// striped background (grey interrupted)
|
||||
"[background-image:repeating-linear-gradient(135deg,rgba(0,0,0,0.06)_0_10px,transparent_10px_20px)]"
|
||||
} p-10 min-h-56 text-center select-none ${className ?? ""}`}
|
||||
>
|
||||
<div className="mx-auto mb-3 flex h-12 w-12 items-center justify-center rounded-lg border border-gray-300 bg-white/60">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
className="h-6 w-6 text-gray-700"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="text-lg font-medium text-gray-700">Upload files here</div>
|
||||
<div className="mt-1 text-sm text-gray-500">or click to browse files</div>
|
||||
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
multiple
|
||||
className="hidden"
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,168 @@
|
||||
import * as React from "react"
|
||||
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu"
|
||||
import { cva } from "class-variance-authority"
|
||||
import { ChevronDownIcon } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function NavigationMenu({
|
||||
className,
|
||||
children,
|
||||
viewport = true,
|
||||
...props
|
||||
}: React.ComponentProps<typeof NavigationMenuPrimitive.Root> & {
|
||||
viewport?: boolean
|
||||
}) {
|
||||
return (
|
||||
<NavigationMenuPrimitive.Root
|
||||
data-slot="navigation-menu"
|
||||
data-viewport={viewport}
|
||||
className={cn(
|
||||
"group/navigation-menu relative flex max-w-max flex-1 items-center justify-center",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
{viewport && <NavigationMenuViewport />}
|
||||
</NavigationMenuPrimitive.Root>
|
||||
)
|
||||
}
|
||||
|
||||
function NavigationMenuList({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof NavigationMenuPrimitive.List>) {
|
||||
return (
|
||||
<NavigationMenuPrimitive.List
|
||||
data-slot="navigation-menu-list"
|
||||
className={cn(
|
||||
"group flex flex-1 list-none items-center justify-center gap-1",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function NavigationMenuItem({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof NavigationMenuPrimitive.Item>) {
|
||||
return (
|
||||
<NavigationMenuPrimitive.Item
|
||||
data-slot="navigation-menu-item"
|
||||
className={cn("relative", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const navigationMenuTriggerStyle = cva(
|
||||
"group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:hover:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent data-[state=open]:bg-accent/50 focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1"
|
||||
)
|
||||
|
||||
function NavigationMenuTrigger({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof NavigationMenuPrimitive.Trigger>) {
|
||||
return (
|
||||
<NavigationMenuPrimitive.Trigger
|
||||
data-slot="navigation-menu-trigger"
|
||||
className={cn(navigationMenuTriggerStyle(), "group", className)}
|
||||
{...props}
|
||||
>
|
||||
{children}{" "}
|
||||
<ChevronDownIcon
|
||||
className="relative top-[1px] ml-1 size-3 transition duration-300 group-data-[state=open]:rotate-180"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</NavigationMenuPrimitive.Trigger>
|
||||
)
|
||||
}
|
||||
|
||||
function NavigationMenuContent({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof NavigationMenuPrimitive.Content>) {
|
||||
return (
|
||||
<NavigationMenuPrimitive.Content
|
||||
data-slot="navigation-menu-content"
|
||||
className={cn(
|
||||
"data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 top-0 left-0 w-full p-2 pr-2.5 md:absolute md:w-auto",
|
||||
"group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:data-[state=open]:animate-in group-data-[viewport=false]/navigation-menu:data-[state=closed]:animate-out group-data-[viewport=false]/navigation-menu:data-[state=closed]:zoom-out-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:fade-in-0 group-data-[viewport=false]/navigation-menu:data-[state=closed]:fade-out-0 group-data-[viewport=false]/navigation-menu:top-full group-data-[viewport=false]/navigation-menu:mt-1.5 group-data-[viewport=false]/navigation-menu:overflow-hidden group-data-[viewport=false]/navigation-menu:rounded-md group-data-[viewport=false]/navigation-menu:border group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:duration-200 **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function NavigationMenuViewport({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof NavigationMenuPrimitive.Viewport>) {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"absolute top-full left-0 isolate z-50 flex justify-center"
|
||||
)}
|
||||
>
|
||||
<NavigationMenuPrimitive.Viewport
|
||||
data-slot="navigation-menu-viewport"
|
||||
className={cn(
|
||||
"origin-top-center bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border shadow md:w-[var(--radix-navigation-menu-viewport-width)]",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function NavigationMenuLink({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof NavigationMenuPrimitive.Link>) {
|
||||
return (
|
||||
<NavigationMenuPrimitive.Link
|
||||
data-slot="navigation-menu-link"
|
||||
className={cn(
|
||||
"data-[active=true]:focus:bg-accent data-[active=true]:hover:bg-accent data-[active=true]:bg-accent/50 data-[active=true]:text-accent-foreground hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus-visible:ring-ring/50 [&_svg:not([class*='text-'])]:text-muted-foreground flex flex-col gap-1 rounded-sm p-2 text-sm transition-all outline-none focus-visible:ring-[3px] focus-visible:outline-1 [&_svg:not([class*='size-'])]:size-4",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function NavigationMenuIndicator({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof NavigationMenuPrimitive.Indicator>) {
|
||||
return (
|
||||
<NavigationMenuPrimitive.Indicator
|
||||
data-slot="navigation-menu-indicator"
|
||||
className={cn(
|
||||
"data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<div className="bg-border relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm shadow-md" />
|
||||
</NavigationMenuPrimitive.Indicator>
|
||||
)
|
||||
}
|
||||
|
||||
export {
|
||||
NavigationMenu,
|
||||
NavigationMenuList,
|
||||
NavigationMenuItem,
|
||||
NavigationMenuContent,
|
||||
NavigationMenuTrigger,
|
||||
NavigationMenuLink,
|
||||
NavigationMenuIndicator,
|
||||
NavigationMenuViewport,
|
||||
navigationMenuTriggerStyle,
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
import { clsx, type ClassValue } from "clsx"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
Loading…
Reference in new issue