add treasures (artworks)

This commit is contained in:
2024-01-10 22:24:12 +07:00
parent 205f92001c
commit 2cbaca844e
22 changed files with 717 additions and 55 deletions
+9 -5
View File
@@ -9,7 +9,7 @@ import { cn } from "@/utility/utils";
const AppBar = () => {
return (
<header className="w-full bg-[#111a21] shadow">
<div className="container py-8 md:py-4 flex flex-col md:flex-row items-center gap-4">
<div className="mx-auto max-w-5xl md:px-4 pt-6 md:py-4 flex flex-col md:flex-row items-center gap-4">
<Link
to="/"
className="flex flex-col md:flex-row items-center gap-2 md:gap-4"
@@ -24,6 +24,7 @@ const AppBar = () => {
<Navbar>
<NavbarItem path="/" title="Pet the Furina" />
<NavbarItem path="/treasures" title="Treasures‧₊˚" />
<NavbarItem path="/toodle" title="Toodle-oo~" />
</Navbar>
</div>
@@ -33,7 +34,7 @@ const AppBar = () => {
const Navbar = ({ children }: ComponentProps<"div">) => {
return (
<nav className="flex-1 flex items-center justify-end gap-3 md:gap-5 overflow-x-auto md:overflow-x-hidden">
<nav className="md:flex-1 self-stretch md:self-center flex items-center px-2 md:px-0 md:justify-end md:gap-5 overflow-x-auto md:overflow-x-hidden">
{children}
</nav>
);
@@ -50,7 +51,10 @@ const NavbarItem = ({ path, title, isExact = true }: NavbarItemProps) => {
const isActive = isExact ? pathname === path : pathname.startsWith(path);
return (
<Link to={path} className="group flex items-center md:py-4">
<Link
to={path}
className="group flex flex-shrink-0 items-center px-2 md:px-0 md:py-4 first:ml-auto last:mr-auto"
>
<img
src={ahogeImg}
alt="ahoge"
@@ -62,8 +66,8 @@ const NavbarItem = ({ path, title, isExact = true }: NavbarItemProps) => {
<p
className={cn(
"text-white ml-2 md:ml-4 md:text-xl border-b-2 border-dotted group-hover:border-white/80 border-transparent transition-all",
isActive ? "border-white" : ""
"text-white ml-2 md:ml-4 md:text-xl py-2 md:py-0 border-b-2 md:border-dotted group-hover:border-primary-500 border-transparent transition-all",
isActive ? "border-primary-500 md:border-white" : ""
)}
>
{title}
+1 -4
View File
@@ -17,11 +17,8 @@ const MainLayout = ({ children }: ComponentProps<"div">) => {
</Suspense>
)}
<footer className="bg-primary-700 px-4 py-8 text-center">
<footer className="bg-primary-700 shadow relative z-10 px-4 py-8 text-center">
<p className="text-sm text-white">
<a href="http://rul.sh/">
Made with <span className="text-red-300"></span> by Khairul.
</a>{" "}
Artworks displayed belong to respective owners.
</p>
</footer>
+36
View File
@@ -0,0 +1,36 @@
import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/utility/utils";
const badgeVariants = cva(
"inline-flex items-center rounded border border-primary-200 px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-primary-950 focus:ring-offset-2 dark:border-primary-800 dark:focus:ring-primary-300",
{
variants: {
variant: {
default:
"border-transparent bg-primary-600 text-primary-50 hover:bg-primary-600/80 dark:bg-primary-50 dark:text-primary-900 dark:hover:bg-primary-50/80",
secondary:
"border-transparent bg-primary-100 text-primary-900 hover:bg-primary-100/80 dark:bg-primary-800 dark:text-primary-50 dark:hover:bg-primary-800/80",
destructive:
"border-transparent bg-red-500 text-primary-50 hover:bg-red-500/80 dark:bg-red-900 dark:text-primary-50 dark:hover:bg-red-900/80",
outline: "text-primary-950 dark:text-primary-50",
},
},
defaultVariants: {
variant: "default",
},
}
);
export interface BadgeProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof badgeVariants> {}
function Badge({ className, variant, ...props }: BadgeProps) {
return (
<div className={cn(badgeVariants({ variant }), className)} {...props} />
);
}
export default Badge;
+42
View File
@@ -0,0 +1,42 @@
import { cn } from "@/utility/utils";
import React, { useState } from "react";
type Props = React.ComponentProps<"img"> & {
lazySrc: string;
containerClassName?: string;
};
const LazyImage = ({
lazySrc,
src,
containerClassName,
className,
...props
}: Props) => {
const [isLoaded, setLoaded] = useState(false);
return (
<div
className={cn(
"bg-no-repeat bg-cover",
!isLoaded ? "blur-md" : "",
containerClassName
)}
style={{ backgroundImage: `url('${lazySrc}')` }}
>
<img
src={src}
loading="lazy"
onLoad={() => setLoaded(true)}
className={cn(
"transition-all",
isLoaded ? "opacity-100" : "opacity-0",
className
)}
{...props}
/>
</div>
);
};
export default LazyImage;
+156
View File
@@ -0,0 +1,156 @@
import * as React from "react";
import * as SheetPrimitive from "@radix-ui/react-dialog";
import { cva, type VariantProps } from "class-variance-authority";
import { X } from "lucide-react";
import { cn } from "@/utility/utils";
const SheetRoot = SheetPrimitive.Root;
const SheetPortal = SheetPrimitive.Portal;
const SheetOverlay = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Overlay
className={cn(
"fixed inset-0 z-50 bg-black/20 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className
)}
{...props}
ref={ref}
/>
));
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
const sheetVariants = cva(
"fixed z-50 gap-4 bg-white shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500 dark:bg-slate-950",
{
variants: {
side: {
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
bottom:
"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
right:
"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
},
},
defaultVariants: {
side: "right",
},
}
);
interface SheetContentProps
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
VariantProps<typeof sheetVariants> {}
const SheetContent = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Content>,
SheetContentProps
>(({ side = "right", className, children, ...props }, ref) => (
<SheetPortal>
<SheetOverlay />
<SheetPrimitive.Content
ref={ref}
className={cn(sheetVariants({ side }), className)}
{...props}
>
{children}
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-white transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-slate-950 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-slate-100 dark:ring-offset-slate-950 dark:focus:ring-slate-300 dark:data-[state=open]:bg-slate-800">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</SheetPrimitive.Close>
</SheetPrimitive.Content>
</SheetPortal>
));
SheetContent.displayName = SheetPrimitive.Content.displayName;
const SheetHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col p-4 space-y-2 text-center sm:text-left",
className
)}
{...props}
/>
);
SheetHeader.displayName = "SheetHeader";
const SheetFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className
)}
{...props}
/>
);
SheetFooter.displayName = "SheetFooter";
const SheetTitle = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Title
ref={ref}
className={cn(
"text-lg font-semibold text-slate-950 dark:text-slate-50",
className
)}
{...props}
/>
));
SheetTitle.displayName = SheetPrimitive.Title.displayName;
const SheetDescription = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Description
ref={ref}
className={cn("text-sm text-slate-500 dark:text-slate-400", className)}
{...props}
/>
));
SheetDescription.displayName = SheetPrimitive.Description.displayName;
type SheetProps = React.ComponentProps<typeof SheetRoot> & {
isOpen?: boolean;
title?: string;
description?: string;
position?: SheetContentProps["side"];
};
const Sheet = ({
isOpen,
title,
description,
children,
position,
...props
}: SheetProps) => {
return (
<SheetRoot open={isOpen} {...props}>
<SheetContent side={position} className="rounded-t-2xl">
<SheetHeader>
{title ? <SheetTitle>{title}</SheetTitle> : null}
{description ? (
<SheetDescription>{description}</SheetDescription>
) : null}
</SheetHeader>
<div className="max-h-[90vh] overflow-y-auto">{children}</div>
</SheetContent>
</SheetRoot>
);
};
export default Sheet;