personal website
1import type { RefObject } from "react"
2import { CurrentlyPlaying, LastPlayed, type AtProtoStyles } from "atproto-ui"
3import { personalInfo, currentRole, skills } from "../../data/portfolio"
4
5interface HeaderProps {
6 sectionRef: (el: HTMLElement | null) => void
7}
8
9export function Header({ sectionRef }: HeaderProps) {
10 const scrollToWork = () => {
11 document.getElementById('work')?.scrollIntoView({ behavior: 'smooth' })
12 }
13
14 return (
15 <header id="intro" ref={sectionRef} className="min-h-screen flex items-center opacity-0 relative">
16 {/* Background Image - Full Width */}
17 <div
18 className="absolute top-0 bottom-0 left-1/2 right-1/2 -ml-[50vw] -mr-[50vw] w-screen z-0"
19 style={{
20 backgroundImage: 'url(https://cdn.donmai.us/original/31/2f/__kazusa_blue_archive_drawn_by_astelia__312fc11a21c5d4ce06dc3aa8bfbb7221.jpg)',
21 backgroundSize: 'cover',
22 backgroundPosition: 'center',
23 backgroundRepeat: 'no-repeat',
24 }}
25 >
26 {/* Overlay for better text readability */}
27 <div className="absolute inset-0 bg-background/70"></div>
28 </div>
29
30 <div className="grid lg:grid-cols-5 gap-12 sm:gap-16 w-full relative z-10 items-center">
31 <div className="lg:col-span-3 space-y-6 sm:space-y-8">
32 <div className="space-y-3 sm:space-y-2">
33 <div className="text-sm text-gray-300 font-mono tracking-wider">PORTFOLIO / 2025</div>
34 <h1 className="text-md sm:text-md lg:text-4xl font-light tracking-tight text-cyan-400">
35 {personalInfo.name.first}
36 <br />
37 <span className=" text-gray-400">{personalInfo.name.last}</span>
38 </h1>
39 </div>
40
41 <div className="space-y-6 max-w-md ">
42 <p className="text-lg sm:text-xl text-stone-200 leading-relaxed">
43 {personalInfo.description.map((part, i) => {
44 if (part.url) {
45 return (
46 <a
47 key={i}
48 href={part.url}
49 target="_blank"
50 rel="noopener noreferrer"
51 className="text-cyan-400/70 hover:text-cyan-300 font-medium transition-colors duration-300 underline decoration-cyan-400/30 hover:decoration-cyan-300/50"
52 >
53 {part.text}
54 </a>
55 )
56 }
57
58 if (part.bold) {
59 return (
60 <span key={i} className="text-white font-medium">
61 {part.text}
62 </span>
63 )
64 }
65
66 return part.text
67 })}
68 </p>
69
70 <div className="space-y-4">
71 <div className="flex items-center gap-2 text-sm text-gray-300">
72 <div className="w-2 h-2 bg-green-500 rounded-full animate-pulse"></div>
73 {personalInfo.availability.status}
74 </div>
75 <div className="flex items-center gap-4">
76 <a
77 href={`mailto:${personalInfo.contact.email}`}
78 className="glass glass-hover px-6 py-3 rounded-lg transition-all duration-300 inline-flex items-center justify-center gap-2 text-sm text-gray-300 hover:text-white flex-1"
79 >
80 <svg
81 className="w-4 h-4"
82 fill="none"
83 stroke="currentColor"
84 viewBox="0 0 24 24"
85 strokeWidth={2}
86 >
87 <path
88 strokeLinecap="round"
89 strokeLinejoin="round"
90 d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"
91 />
92 </svg>
93 Email me
94 </a>
95 <a
96 href="https://nekomimi.leaflet.pub"
97 target="_blank"
98 rel="noopener noreferrer"
99 className="glass glass-hover px-6 py-3 rounded-lg transition-all duration-300 inline-flex items-center justify-center gap-2 text-sm text-gray-300 hover:text-white flex-1"
100 >
101 <svg
102 className="w-4 h-4"
103 fill="none"
104 stroke="currentColor"
105 viewBox="0 0 24 24"
106 strokeWidth={2}
107 >
108 <path
109 strokeLinecap="round"
110 strokeLinejoin="round"
111 d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"
112 />
113 </svg>
114 Read my blog
115 </a>
116 </div>
117 </div>
118 </div>
119 </div>
120
121 <div className="lg:col-span-2 flex flex-col justify-end space-y-6 sm:space-y-8 mt-8 lg:mt-0">
122 <div className="space-y-4">
123 <p className="text-sm text-gray-300 font-mono">IM LISTENING TO:</p>
124 <div className="glass rounded-2xl" style={{
125 '--atproto-color-bg': 'transparent',
126 '--atproto-color-border': 'transparent',
127 '--atproto-color-bg-elevated': 'rgba(255, 255, 255, 0.20)',
128 '--atproto-color-text': 'white',
129 '--atproto-color-text-secondary': 'rgba(255, 255, 255, 0.80)',
130 } as AtProtoStyles }>
131 <CurrentlyPlaying did="nekomimi.pet"/>
132 </div>
133 </div>
134 </div>
135 </div>
136
137 {/* Image Source Link */}
138 <a
139 href="https://danbooru.donmai.us/posts/9959832"
140 target="_blank"
141 rel="noopener noreferrer"
142 className="absolute bottom-8 right-8 glass glass-hover p-2 rounded-lg transition-all duration-300 z-20 text-xs dark:text-gray-400 text-gray-600 hover:dark:text-gray-200 hover:text-gray-800"
143 aria-label="View image source"
144 >
145 <svg
146 className="w-4 h-4 inline-block mr-1"
147 fill="none"
148 stroke="currentColor"
149 viewBox="0 0 24 24"
150 strokeWidth={2}
151 >
152 <path
153 strokeLinecap="round"
154 strokeLinejoin="round"
155 d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"
156 />
157 </svg>
158 Source
159 </a>
160
161 {/* Scroll Down Arrow */}
162 <button
163 onClick={scrollToWork}
164 className="absolute bottom-8 left-1/2 -translate-x-1/2 glass glass-hover p-3 rounded-full animate-bounce-slow transition-all duration-300 z-20"
165 aria-label="Scroll to work section"
166 >
167 <svg
168 className="w-5 h-5 text-gray-300"
169 fill="none"
170 stroke="currentColor"
171 viewBox="0 0 24 24"
172 strokeWidth={2}
173 >
174 <path
175 strokeLinecap="round"
176 strokeLinejoin="round"
177 d="M19 14l-7 7m0 0l-7-7m7 7V3"
178 />
179 </svg>
180 </button>
181 </header>
182 )
183}