feat: add detailed character page
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable @next/next/no-img-element */
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
@ -5,8 +6,8 @@ import { IconWithText } from "../components/IconWithText";
|
||||||
import { Section } from "../components/Section";
|
import { Section } from "../components/Section";
|
||||||
import { CharacterImage } from "../components/CharacterImage";
|
import { CharacterImage } from "../components/CharacterImage";
|
||||||
|
|
||||||
import { useInView } from "motion/react"
|
import { useInView } from "motion/react";
|
||||||
import { useEffect, useRef } from "react";
|
import { useRef } from "react";
|
||||||
|
|
||||||
const links = [
|
const links = [
|
||||||
{
|
{
|
||||||
|
@ -24,19 +25,24 @@ const links = [
|
||||||
];
|
];
|
||||||
|
|
||||||
export const Characters = () => {
|
export const Characters = () => {
|
||||||
|
const imagesRedPandaRef = useRef(null);
|
||||||
const imagesRedPandaRef = useRef(null)
|
const imagesRedPandaIsInView = useInView(imagesRedPandaRef, { once: true });
|
||||||
const imagesRedPandaIsInView = useInView(imagesRedPandaRef, { once: true })
|
const imagesProtogenRef = useRef(null);
|
||||||
const imagesProtogenRef = useRef(null)
|
const imagesProtogenIsInView = useInView(imagesProtogenRef, { once: true });
|
||||||
const imagesProtogenIsInView = useInView(imagesProtogenRef, { once: true })
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Section>
|
<Section>
|
||||||
<div className="flex flex-col gap-2 mt-2 md:flex-row md:justify-between md:items-center">
|
<div className="flex flex-col gap-2 mt-2 md:flex-row md:justify-between md:items-center">
|
||||||
<h2 className="text-4xl md:text-5xl border-1 px-3 py-2 rounded-xl border-white/5 bg-[#ffb1cd]/5 flex-1">Characters</h2>
|
<h2 className="text-4xl md:text-5xl border-1 px-3 py-2 rounded-xl border-white/5 bg-[#ffb1cd]/5 flex-1">
|
||||||
|
Characters
|
||||||
|
</h2>
|
||||||
<div className="flex items-center gap-2 flex-1">
|
<div className="flex items-center gap-2 flex-1">
|
||||||
{links.map((item) => (
|
{links.map((item) => (
|
||||||
<Link href={item.url} key={`characters.link.${item.text}`} className="flex-1">
|
<Link
|
||||||
|
href={item.url}
|
||||||
|
key={`characters.link.${item.text}`}
|
||||||
|
className="flex-1"
|
||||||
|
>
|
||||||
<IconWithText
|
<IconWithText
|
||||||
icon={item.icon}
|
icon={item.icon}
|
||||||
text={item.text}
|
text={item.text}
|
||||||
|
@ -49,12 +55,14 @@ export const Characters = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-4 mt-2 md:hidden">
|
<div className="flex flex-col gap-4 mt-2 md:hidden">
|
||||||
<CharacterImage
|
<Link href="/character/kentai">
|
||||||
name="Kentai"
|
<CharacterImage
|
||||||
species="Red Panda"
|
name="Kentai"
|
||||||
gender="Male"
|
species="Red Panda"
|
||||||
image="/images/red_panda.png"
|
gender="Male"
|
||||||
/>
|
image="/images/red_panda.png"
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
<CharacterImage
|
<CharacterImage
|
||||||
name=""
|
name=""
|
||||||
species="Protogen"
|
species="Protogen"
|
||||||
|
@ -72,14 +80,26 @@ export const Characters = () => {
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<p className="text-5xl">Kentai</p>
|
<p className="text-5xl">Kentai</p>
|
||||||
<p className="mt-2 text-3xl" ref={imagesRedPandaRef}>Red Panda</p>
|
<p className="mt-2 text-3xl" ref={imagesRedPandaRef}>
|
||||||
|
Red Panda
|
||||||
|
</p>
|
||||||
<p className="text-3xl">Male</p>
|
<p className="text-3xl">Male</p>
|
||||||
<div className="flex-1"></div>
|
<div className="flex-1"></div>
|
||||||
<button className="rounded-full bg-[#491f1f] px-4 py-2 text-3xl">
|
<Link
|
||||||
|
href="/character/kentai"
|
||||||
|
className="rounded-full bg-[#491f1f] hover:bg-[#601f1f] transition-colors px-4 py-2 text-3xl text-center"
|
||||||
|
>
|
||||||
about
|
about
|
||||||
</button>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="top-0 left-[488px] absolute hidden xl:flex gap-4 transition-transform duration-1000 ease-out" style={{ transform: !imagesRedPandaIsInView ? "translateX(100vw)" : "translateX(0)" }}>
|
<div
|
||||||
|
className="top-0 left-[488px] absolute hidden xl:flex gap-4 transition-transform duration-1000 ease-out"
|
||||||
|
style={{
|
||||||
|
transform: !imagesRedPandaIsInView
|
||||||
|
? "translateX(100vw)"
|
||||||
|
: "translateX(0)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
<img
|
<img
|
||||||
className="rounded-4xl w-[372px] h-[288px] object-cover flex-shrink-0"
|
className="rounded-4xl w-[372px] h-[288px] object-cover flex-shrink-0"
|
||||||
src="/images/red_panda2.png"
|
src="/images/red_panda2.png"
|
||||||
|
@ -101,9 +121,18 @@ export const Characters = () => {
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-col xl:text-right">
|
<div className="flex flex-col xl:text-right">
|
||||||
<p className="mt-2 text-3xl">Protogen</p>
|
<p className="mt-2 text-3xl">Protogen</p>
|
||||||
<p className="text-3xl" ref={imagesProtogenRef}>Male</p>
|
<p className="text-3xl" ref={imagesProtogenRef}>
|
||||||
|
Male
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="bottom-0 right-[488px] absolute hidden xl:flex gap-4 transition-transform duration-1000 ease-out" style={{ transform: !imagesProtogenIsInView ? "translateX(-100vw)" : "translateX(0)" }}>
|
<div
|
||||||
|
className="bottom-0 right-[488px] absolute hidden xl:flex gap-4 transition-transform duration-1000 ease-out"
|
||||||
|
style={{
|
||||||
|
transform: !imagesProtogenIsInView
|
||||||
|
? "translateX(-100vw)"
|
||||||
|
: "translateX(0)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
<img
|
<img
|
||||||
className="rounded-4xl w-[372px] h-[288px] object-cover flex-shrink-0"
|
className="rounded-4xl w-[372px] h-[288px] object-cover flex-shrink-0"
|
||||||
src="/images/protogen3.png"
|
src="/images/protogen3.png"
|
||||||
|
|
|
@ -13,7 +13,7 @@ export const Intro = () => {
|
||||||
<div>
|
<div>
|
||||||
<div className="flex flex-col mx-auto max-w-fit md:items-center justify-center h-fit py-16 gap-4">
|
<div className="flex flex-col mx-auto max-w-fit md:items-center justify-center h-fit py-16 gap-4">
|
||||||
<h1 className="text-4xl md:text-8xl font-medium">Hi, I'm <span className="bg-clip-text bg-gradient-to-br from-[#FFB1CD] via-[#C8E8FE] to-white text-transparent font-bold">Radiquum</span></h1>
|
<h1 className="text-4xl md:text-8xl font-medium">Hi, I'm <span className="bg-clip-text bg-gradient-to-br from-[#FFB1CD] via-[#C8E8FE] to-white text-transparent font-bold">Radiquum</span></h1>
|
||||||
<div className="flex flex-col md:flex-row md:gap-8 overflow-hidden">
|
<div className="flex flex-col lg:flex-row lg:gap-8 overflow-hidden">
|
||||||
<p className={`text-2xl md:text-4xl text-[#C8E8FE] ${isAnimated ? "translate-y-0 opacity-100" : "translate-y-full opacity-0"} transition-[transform_opacity] duration-1000 ease-out`}>Developer</p>
|
<p className={`text-2xl md:text-4xl text-[#C8E8FE] ${isAnimated ? "translate-y-0 opacity-100" : "translate-y-full opacity-0"} transition-[transform_opacity] duration-1000 ease-out`}>Developer</p>
|
||||||
<p className={`text-2xl md:text-4xl text-[#FF8686] ${isAnimated ? "translate-y-0 opacity-100" : "translate-y-full opacity-0"} transition-[transform_opacity] duration-1000 ease-out delay-150`}>Amateur Photographer</p>
|
<p className={`text-2xl md:text-4xl text-[#FF8686] ${isAnimated ? "translate-y-0 opacity-100" : "translate-y-full opacity-0"} transition-[transform_opacity] duration-1000 ease-out delay-150`}>Amateur Photographer</p>
|
||||||
<p className={`text-2xl md:text-4xl text-[#FF851A] ${isAnimated ? "translate-y-0 opacity-100" : "translate-y-full opacity-0"} transition-[transform_opacity] duration-1000 ease-out delay-300`}>Self-Hosting Admirer</p>
|
<p className={`text-2xl md:text-4xl text-[#FF851A] ${isAnimated ? "translate-y-0 opacity-100" : "translate-y-full opacity-0"} transition-[transform_opacity] duration-1000 ease-out delay-300`}>Self-Hosting Admirer</p>
|
||||||
|
|
150
app/character/kentai/page.tsx
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
/* eslint-disable @next/next/no-img-element */
|
||||||
|
import { CharacterColor } from "@/app/components/CharacterColor";
|
||||||
|
import Link from "next/link";
|
||||||
|
const CharacterColors = {
|
||||||
|
Body: ["#ffb1ce", "#91d1fd", "#ffffff"],
|
||||||
|
Clothes: ["#492020", "#1c1a1d", "#39373b", "#494749", "#69676a", "#98959a"],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function CharacterKentai() {
|
||||||
|
return (
|
||||||
|
<main className="pb-16 overflow-hidden">
|
||||||
|
<div className="bg-[#131314] rounded-b-4xl md:rounded-b-[128px]">
|
||||||
|
<div className="container mx-auto py-8 px-4">
|
||||||
|
<div>
|
||||||
|
<div className="grid grid-cols-1 xl:grid-cols-2 gap-4">
|
||||||
|
<img
|
||||||
|
alt="Reference"
|
||||||
|
src="/characters/kentai_redpanda_thumb.jpg"
|
||||||
|
className="rounded-xl"
|
||||||
|
/>
|
||||||
|
<div className="flex flex-col gap-4">
|
||||||
|
<div>
|
||||||
|
<h2 className="text-5xl">Info</h2>
|
||||||
|
<div>
|
||||||
|
<p className="text-2xl">Name: Kentai Radiquum</p>
|
||||||
|
<p className="text-2xl">Species: Red Panda</p>
|
||||||
|
<p className="text-2xl">Male, average height, slim build</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col gap-4">
|
||||||
|
<h2 className="text-5xl -mb-4">Colors</h2>
|
||||||
|
{Object.entries(CharacterColors).map(([category, colors]) => (
|
||||||
|
<div key={`color.${category}`}>
|
||||||
|
<h2 className="text-2xl">{category}</h2>
|
||||||
|
<div className="mt-2 grid grid-cols-3 gap-2">
|
||||||
|
{colors.map((color) => (
|
||||||
|
<CharacterColor
|
||||||
|
color={color}
|
||||||
|
key={`color.${category}.${color}`}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="container mx-auto py-8 px-4">
|
||||||
|
<p className="text-2xl">
|
||||||
|
Kentai is a friendly yet introverted red panda who values his quiet
|
||||||
|
space and prefers meaningful interactions over large crowds. Curious
|
||||||
|
by nature and sharp-minded, he has a deep love for technology and is
|
||||||
|
always eager to explore something new. While he keeps a low profile,
|
||||||
|
those close to him know him as thoughtful, creative, and quietly
|
||||||
|
expressive.
|
||||||
|
</p>
|
||||||
|
<div className="grid grid-cols-1 xl:grid-cols-2 gap-4 mt-4">
|
||||||
|
<div className="border-1 border-white/5 bg-[#161224]/5 rounded-xl px-8 py-4">
|
||||||
|
<h2 className="text-5xl text-center">Hobbies</h2>
|
||||||
|
<ul className="list-disc mt-2">
|
||||||
|
<li>
|
||||||
|
<p className="text-2xl">
|
||||||
|
Programming — not just a skill, but a form of self-expression
|
||||||
|
and problem-solving he deeply enjoys.
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p className="text-2xl">
|
||||||
|
Photography — capturing small details and cozy moments from
|
||||||
|
his world.
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p className="text-2xl">
|
||||||
|
Plush Toy Collecting — he has a soft spot for plushies,
|
||||||
|
especially red pandas. His collection brings him comfort and
|
||||||
|
emotional grounding.
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div className="border-1 border-white/5 bg-[#132416]/5 rounded-xl px-8 py-4">
|
||||||
|
<h2 className="text-5xl text-center">Habits</h2>
|
||||||
|
<ul className="list-disc mt-2">
|
||||||
|
<li>
|
||||||
|
<p className="text-2xl">
|
||||||
|
His tail gently wags when he's fully absorbed in
|
||||||
|
something.
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p className="text-2xl">
|
||||||
|
Tugs or adjusts his collar when thinking through a tricky
|
||||||
|
problem.
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p className="text-2xl">
|
||||||
|
Always has music playing while he works, and sometimes hums
|
||||||
|
along without noticing.
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p className="text-2xl">
|
||||||
|
Loves curling up in a blanket with a plush toy and relaxing to
|
||||||
|
music — his version of peace.
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<nav className="fixed left-4 bottom-4">
|
||||||
|
<Link href="/" className="min-w-fit min-h-fit group">
|
||||||
|
<div className="p-4 border-1 rounded-full backdrop-blur-md border-white/5 bg-[#161213]/25 flex gap-2 w-[66px] hover:w-[128px] relative transition-[width] duration-150 ease-in-out overflow-hidden">
|
||||||
|
<img
|
||||||
|
alt=""
|
||||||
|
src="/icons/mdi_arrow-left.svg"
|
||||||
|
className="w-8 h-8 invert"
|
||||||
|
/>
|
||||||
|
<div className="relative w-0 opacity-0 group-hover:opacity-100 transition-[opacity]">
|
||||||
|
<span className="text-2xl absolute">Back</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
</nav>
|
||||||
|
<nav className="fixed right-4 bottom-4">
|
||||||
|
<a
|
||||||
|
className="min-w-fit min-h-fit group"
|
||||||
|
href="/characters/Kentai_Radiquum_RedPanda/Kentai_Radiquum_RedPanda.zip"
|
||||||
|
download={true}
|
||||||
|
>
|
||||||
|
<div className="p-4 border-1 rounded-full backdrop-blur-md border-white/5 bg-[#161213]/25 flex gap-2 w-[66px] hover:w-[180px] relative transition-[width] duration-150 ease-in-out overflow-hidden">
|
||||||
|
<img
|
||||||
|
alt=""
|
||||||
|
src="/icons/mdi_download.svg"
|
||||||
|
className="ml-[2px] w-8 h-8 invert"
|
||||||
|
/>
|
||||||
|
<div className="relative w-0 opacity-0 group-hover:opacity-100 transition-[opacity]">
|
||||||
|
<span className="text-2xl absolute">Download</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</nav>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
10
app/components/CharacterColor.tsx
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
export const CharacterColor = ({ color }: { color: string }) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="bg-[var(--bg-color)] px-8 py-4 text-2xl rounded-xl border-1 border-white/5"
|
||||||
|
style={{ "--bg-color": color } as React.CSSProperties}
|
||||||
|
>
|
||||||
|
<p className="text-transparent">{color}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
BIN
app/favicon.ico
Before Width: | Height: | Size: 25 KiB |
BIN
app/icon.png
Normal file
After Width: | Height: | Size: 34 KiB |
|
@ -2,8 +2,17 @@ import type { Metadata } from "next";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Create Next App",
|
title: "Kentai Radiquum",
|
||||||
description: "Generated by create next app",
|
description: "Developer, Amateur Photographer, Self-Hosting Admirer",
|
||||||
|
openGraph: {
|
||||||
|
images: [
|
||||||
|
{
|
||||||
|
url: "https://radiquum.wah.su/images/opengraph.png",
|
||||||
|
width: 1200,
|
||||||
|
height: 675,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function RootLayout({
|
export default function RootLayout({
|
||||||
|
|
After Width: | Height: | Size: 1.5 MiB |
BIN
public/characters/Kentai_Radiquum_RedPanda/Color Palette.png
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
public/characters/kentai_redpanda_thumb.jpg
Normal file
After Width: | Height: | Size: 400 KiB |
BIN
public/characters/protogen.jpg
Normal file
After Width: | Height: | Size: 279 KiB |
1
public/icons/mdi_arrow-left.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20,11V13H8L13.5,18.5L12.08,19.92L4.16,12L12.08,4.08L13.5,5.5L8,11H20Z" /></svg>
|
After Width: | Height: | Size: 149 B |
1
public/icons/mdi_download.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12,4V16.25L17.25,11L18,11.66L11.5,18.16L5,11.66L5.75,11L11,16.25V4H12M3,19H4V21H19V19H20V22H3V19Z" /></svg>
|
After Width: | Height: | Size: 177 B |
BIN
public/images/opengraph.png
Normal file
After Width: | Height: | Size: 628 KiB |