Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
272 changes: 272 additions & 0 deletions bun.lock

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
},
"dependencies": {
"@hookform/resolvers": "^5.1.1",
"@octokit/graphql": "^9.0.3",
"@opennextjs/cloudflare": "^1.16.5",
"@radix-ui/react-accordion": "^1.2.11",
"@radix-ui/react-alert-dialog": "^1.1.14",
Expand Down Expand Up @@ -47,11 +48,13 @@
"@radix-ui/react-toggle-group": "^1.1.10",
"@radix-ui/react-tooltip": "^1.2.7",
"@ridemountainpig/svgl-react": "^1.0.15",
"@shikijs/transformers": "^3.22.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"date-fns": "^4.1.0",
"embla-carousel-react": "^8.6.0",
"gray-matter": "^4.0.3",
"input-otp": "^1.4.2",
"lefthook": "^1.11.14",
"lucide-react": "^0.525.0",
Expand All @@ -62,9 +65,18 @@
"react-dom": "^19.2.1",
"react-hook-form": "^7.60.0",
"react-resizable-panels": "^3.0.3",
"reading-time": "^1.5.0",
"recharts": "2.15.4",
"rehype-autolink-headings": "^7.1.0",
"rehype-pretty-code": "^0.14.1",
"rehype-slug": "^6.0.0",
"rehype-stringify": "^10.0.1",
"remark-gfm": "^4.0.1",
"remark-parse": "^11.0.0",
"remark-rehype": "^11.1.2",
"sonner": "^2.0.6",
"tailwind-merge": "^3.3.1",
"unified": "^11.0.5",
"vaul": "^1.1.2",
"zod": "^4.0.5"
},
Expand Down
Binary file removed public/3.png
Binary file not shown.
Binary file added public/mint-trans.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/mint.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
228 changes: 228 additions & 0 deletions src/app/_components/AboutSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
"use client";

import Image from "next/image";
import { useEffect, useRef, useState } from "react";
import { ExternalLink, Github, Mail, Globe } from "lucide-react";
import { XLight } from "@ridemountainpig/svgl-react";

import { SkillsPanel } from "./_components/SkillsPanel";
import { CareerPanel } from "./_components/CareerPanel";
import { LearningPanel } from "./_components/LearningPanel";

function useInView(threshold = 0.05) {
const ref = useRef<HTMLDivElement>(null);
const [inView, setInView] = useState(false);
useEffect(() => {
const el = ref.current;
if (!el) return;
const obs = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setInView(true);
obs.disconnect();
}
},
{ threshold }
);
obs.observe(el);
return () => obs.disconnect();
}, [threshold]);
return { ref, inView };
}

const SOCIALS = [
{
label: "GitHub",
sub: "@mintani",
href: "https://github.com/mintani",
icon: Github,
color: "hover:text-neutral-900",
},
{
label: "Twitter / X",
sub: "@_mint76",
href: "https://twitter.com/_mint76",
icon: XLight,
color: "hover:text-sky-600",
},
{
label: "Runa.dev",
sub: "作品一覧",
href: "https://runa.dev",
icon: Globe,
color: "hover:text-violet-600",
},
{
label: "Email",
sub: "mi.2005.sub@gmail.com",
href: "mailto:mi.2005.sub@gmail.com",
icon: Mail,
color: "hover:text-amber-600",
},
];

// Thin card wrapper — no uniform height enforcement
function Panel({
children,
className = "",
delay = 0,
inView,
}: {
children: React.ReactNode;
className?: string;
delay?: number;
inView: boolean;
}) {
return (
<div
className={`rounded-2xl bg-white/30 backdrop-blur-xl border border-white/50 ring-1 ring-white/60 shadow-lg overflow-hidden transition-all duration-700 ${inView ? "opacity-100 translate-y-0" : "opacity-0 translate-y-6"} ${className}`}
style={{ transitionDelay: inView ? `${delay}ms` : "0ms" }}
>
{children}
</div>
);
}

export function AboutSection() {
const { ref, inView } = useInView(0.05);

return (
<section
id="about-section"
className="w-full relative z-30 overflow-hidden flex flex-col items-center justify-center"
>
<div
ref={ref}
className="container mx-auto w-full py-16 px-4 sm:px-6 lg:px-10 flex flex-col gap-10"
>
{/* ── Section header ── */}
<div
className={`flex flex-col gap-1 transition-all duration-700 ${inView ? "opacity-100 translate-y-0" : "opacity-0 translate-y-6"}`}
>
<span className="font-mono text-xs tracking-[0.3em] uppercase text-neutral-400">
自己紹介
</span>
<h2 className="text-5xl sm:text-6xl font-bold font-poppins italic text-neutral-800 leading-none">
About me
</h2>
</div>

{/* ── Row 1: Profile (wide) + Socials ── */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4">
{/* Profile — takes 2 cols */}
<Panel
className="lg:col-span-2 p-7 sm:p-8"
delay={60}
inView={inView}
>
<div className="flex flex-col sm:flex-row gap-6 h-full">
{/* Avatar */}
<div className="shrink-0">
<div className="relative w-20 h-20 rounded-2xl overflow-hidden ring-2 ring-cyan-400 shadow-md">
<Image
src="/mint.png"
alt="mintanaka"
fill
className="object-cover object-top"
sizes="80px"
/>
</div>
</div>

{/* Bio */}
<div className="flex flex-col gap-3 flex-1">
<div className="flex flex-col gap-0.5">
<span className="font-poppins font-bold text-xl text-neutral-900 leading-tight">
MinTani
</span>
<span className="font-mono text-xs text-neutral-400 tracking-wide">
mintanaka
</span>
</div>
<p className="text-sm text-neutral-600 leading-relaxed">
「いろいろやる」をモットーに活動する学生エンジニア。
日本工業大学先進工学部データサイエンス学科(28卒)。
WebサービスやAPIの設計・実装が得意で、ハッカソンにも積極的に参加しています。
</p>
<p className="text-sm text-neutral-600 leading-relaxed">
現在インターン・お仕事を探しています。
お気軽にXのDMやメールでご連絡ください。
</p>
<div className="mt-auto pt-1">
<span className="inline-flex items-center gap-1.5 text-xs font-mono px-2.5 py-1 rounded-full bg-yellow-50 border border-yellow-200 text-yellow-700">
<span className="w-1.5 h-1.5 rounded-full bg-yellow-400 animate-pulse" />
Open to work
</span>
</div>
</div>
</div>
</Panel>

{/* Social links — 1 col */}
<Panel className="p-6" delay={120} inView={inView}>
<div className="flex flex-col gap-2 h-full justify-center">
{SOCIALS.map((s) => {
const Icon = s.icon;
return (
<a
key={s.label}
href={s.href}
target={s.href.startsWith("mailto") ? undefined : "_blank"}
rel="noopener noreferrer"
className={`group flex items-center gap-3 px-3 py-2 rounded-xl hover:bg-white/60 transition-all duration-200 ${s.color}`}
>
<Icon
size={16}
width={16}
height={16}
className="shrink-0 text-neutral-500 group-hover:scale-110 transition-transform duration-200"
/>
<div className="flex-1 min-w-0">
<p className="text-sm font-semibold text-neutral-800 leading-none">
{s.label}
</p>
<p className="text-[11px] text-neutral-400 mt-0.5 truncate">
{s.sub}
</p>
</div>
<ExternalLink
size={11}
className="shrink-0 text-neutral-300 opacity-0 group-hover:opacity-100 transition-opacity"
/>
</a>
);
})}
</div>
</Panel>
</div>

{/* ── Row 2: Full-width skill grid ── */}
<Panel delay={180} inView={inView} className="p-7">
<h3 className="text-xs font-mono tracking-[0.2em] uppercase text-neutral-400 mb-5">
Skills
</h3>
<SkillsPanel />
</Panel>

{/* ── Row 3: Career (narrow) + Projects ── */}
<div className="grid grid-cols-1 lg:grid-cols-5 gap-4">
{/* Career — 2 cols */}
<Panel className="lg:col-span-2 p-7" delay={240} inView={inView}>
<h3 className="text-xs font-mono tracking-[0.2em] uppercase text-neutral-400 mb-5">
Career
</h3>
<CareerPanel />
</Panel>

{/* Projects — 3 cols */}
<Panel className="lg:col-span-3 p-7" delay={300} inView={inView}>
<h3 className="text-xs font-mono tracking-[0.2em] uppercase text-neutral-400 mb-5">
Projects
</h3>
<LearningPanel />
</Panel>
</div>
</div>
</section>
);
}
46 changes: 46 additions & 0 deletions src/app/_components/_components/CareerPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { CAREER } from "@/data/about";

export function CareerPanel({ compact = false }: { compact?: boolean }) {
return (
<div className="flex flex-col divide-y divide-white/40">
{CAREER.map((item) => (
<div
key={item.year}
className="group flex items-start gap-4 py-4 first:pt-0 last:pb-0"
>
{/* Year pill */}
<div className="shrink-0 mt-0.5">
<span className="inline-block font-mono text-[11px] font-bold tracking-widest text-yellow-600 bg-yellow-50 border border-yellow-200/80 px-2.5 py-1 rounded-md">
{item.year}
</span>
</div>

{/* Content */}
<div className="flex flex-col gap-1 flex-1 min-w-0">
<span className="font-semibold text-sm text-neutral-800 leading-snug">
{item.title}
</span>
<span className="text-[11px] text-neutral-400">{item.place}</span>
{item.desc && !compact && (
<p className="text-xs text-neutral-500 leading-relaxed mt-1">
{item.desc}
</p>
)}
{item.tags && item.tags.length > 0 && (
<div className="flex flex-wrap gap-1 mt-1.5">
{item.tags.map((tag) => (
<span
key={tag}
className="text-[10px] font-mono px-2 py-0.5 rounded-md bg-neutral-100/80 border border-neutral-200/60 text-neutral-500"
>
{tag}
</span>
))}
</div>
)}
</div>
</div>
))}
</div>
);
}
41 changes: 41 additions & 0 deletions src/app/_components/_components/LearningPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { ArrowUpRight } from "lucide-react";
import { PROJECTS } from "@/data/about";

export function LearningPanel() {
return (
<div className="flex flex-col gap-3 h-full">
{PROJECTS.map((project) => (
<a
key={project.name}
href={project.url ?? "#"}
target="_blank"
rel="noopener noreferrer"
className="group flex flex-col gap-2 p-4 rounded-xl bg-white/40 border border-white/60 hover:bg-white/60 hover:border-white/80 transition-all duration-200 hover:-translate-y-0.5"
>
<div className="flex items-start justify-between gap-2">
<span className="font-poppins font-bold text-sm text-neutral-800 leading-snug">
{project.name}
</span>
<ArrowUpRight
size={14}
className="shrink-0 text-neutral-400 opacity-0 group-hover:opacity-100 transition-opacity mt-0.5"
/>
</div>
<p className="text-xs text-neutral-500 leading-relaxed line-clamp-2">
{project.desc}
</p>
<div className="flex flex-wrap gap-1.5 mt-0.5">
{project.tags.map((tag) => (
<span
key={tag}
className="text-[10px] font-mono px-2 py-0.5 rounded-full bg-neutral-100/80 border border-neutral-200/60 text-neutral-500"
>
{tag}
</span>
))}
</div>
</a>
))}
</div>
);
}
Loading
Loading