-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
341 lines (313 loc) · 23 KB
/
index.html
File metadata and controls
341 lines (313 loc) · 23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>James Horton - Portfolio</title>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- React and ReactDOM -->
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<!-- Babel for JSX -->
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body class="bg-slate-50 text-slate-800 font-sans selection:bg-blue-200">
<div id="root"></div>
<script type="text/babel">
const { useState, useEffect } = React;
// --- Icons Components (Inline SVGs) ---
const Github = ({ size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg>
);
const Linkedin = ({ size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z"></path><rect x="2" y="9" width="4" height="12"></rect><circle cx="4" cy="4" r="2"></circle></svg>
);
const XIcon = ({ size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"></path></svg>
);
const Mail = ({ size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path><polyline points="22,6 12,13 2,6"></polyline></svg>
);
const Server = ({ size = 24, className }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}><rect x="2" y="2" width="20" height="8" rx="2" ry="2"></rect><rect x="2" y="14" width="20" height="8" rx="2" ry="2"></rect><line x1="6" y1="6" x2="6.01" y2="6"></line><line x1="6" y1="18" x2="6.01" y2="18"></line></svg>
);
const Cloud = ({ size = 24, className }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}><path d="M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z"></path></svg>
);
const Terminal = ({ size = 24, className }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}><polyline points="4 17 10 11 4 5"></polyline><line x1="12" y1="19" x2="20" y2="19"></line></svg>
);
const Award = ({ size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="8" r="7"></circle><polyline points="8.21 13.89 7 23 12 20 17 23 15.79 13.88"></polyline></svg>
);
const ExternalLink = ({ size = 14 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>
);
const MapPin = ({ size = 24, className }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path><circle cx="12" cy="10" r="3"></circle></svg>
);
const Download = ({ size = 20 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>
);
// --- Main Portfolio Component ---
const Portfolio = () => {
const [activeSection, setActiveSection] = useState('about');
const [isScrolled, setIsScrolled] = useState(false);
// Handle scroll for navbar styling
useEffect(() => {
const handleScroll = () => {
setIsScrolled(window.scrollY > 50);
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
const experience = [
{
company: "Layer5",
role: "Senior Solutions Consultant",
period: "July 2020 - Present",
location: "Remote",
description: "Using Kanvas and Meshery to help organizations overcome engineering silos and collaborate in managing their apps and infra. Driving collaborative configuration management for Kubernetes, Docker, and Cloud environments.",
link: "https://layer5.io"
},
{
company: "Horton Consulting",
role: "Consultant",
period: "Feb 2020 - Present",
location: "New York City Metropolitan Area",
description: "Freelance consulting with startups and Fortune 2,000s, focusing on infrastructure design and cloud strategies."
},
{
company: "Hewlett Packard Enterprise",
role: "Senior Solutions Architect",
period: "Nov 2017 - Feb 2020",
location: "Greater New York City Area",
description: "Designed solutions with Greenlake and third-party infrastructure in different public clouds. Pushed customers toward public marketplace solutions and modern design patterns."
},
{
company: "VertX Solutions",
role: "Software Engineer",
period: "Feb 2013 - Jan 2016",
location: "New York",
description: "Worked on product design and coding product features. Participated in scrum teams practicing SAFe agile methodologies."
},
{
company: "ADP",
role: "Database Application Developer",
period: "Apr 2009 - Jan 2013",
location: "New Jersey",
description: "Managed major migration projects for branch servers and cashier applications. Handled International Bank Transaction projects."
}
];
const skills = [
"Kubernetes", "Amazon EKS", "Azure AKS", "Google GKE",
"Docker", "Infrastructure as Design", "Kanvas", "Solutions Architecture",
"Meshery", "Network Engineering", "ITIL & ITSM"
];
return (
<div className="min-h-screen bg-slate-50 text-slate-800 font-sans selection:bg-blue-200">
{/* Navigation */}
<nav className={`fixed w-full z-50 transition-all duration-300 ${isScrolled ? 'bg-white/90 backdrop-blur-md shadow-sm py-4' : 'bg-transparent py-6'}`}>
<div className="max-w-6xl mx-auto px-6 flex justify-between items-center">
<h1 className="text-xl font-bold tracking-tight text-slate-900">James Horton<span className="text-blue-600">.</span></h1>
<div className="hidden md:flex gap-8 text-sm font-medium text-slate-600">
<a href="#about" className="hover:text-blue-600 transition-colors">About</a>
<a href="#experience" className="hover:text-blue-600 transition-colors">Experience</a>
<a href="#skills" className="hover:text-blue-600 transition-colors">Skills</a>
<a href="mailto:james.horton@layer5.io" className="px-4 py-2 bg-slate-900 text-white rounded-full hover:bg-slate-800 transition-colors">Contact Me</a>
</div>
</div>
</nav>
{/* Hero Section */}
<header id="about" className="pt-32 pb-20 px-6 lg:pt-48 lg:pb-32 overflow-hidden">
<div className="max-w-6xl mx-auto grid md:grid-cols-2 gap-16 items-center">
{/* Left Side: Text */}
<div className="order-2 md:order-1 space-y-6 text-center md:text-left">
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-blue-100 text-blue-700 text-xs font-bold uppercase tracking-wide">
<span className="w-2 h-2 rounded-full bg-blue-600 animate-pulse"></span>
Open Networker (LION)
</div>
<h1 className="text-5xl md:text-6xl font-extrabold text-slate-900 leading-tight">
Solutions <br/>
<span className="text-transparent bg-clip-text bg-gradient-to-r from-blue-600 to-indigo-600">Architecture</span>
</h1>
<p className="text-lg text-slate-600 max-w-lg leading-relaxed mx-auto md:mx-0">
I bring together internal technologies with external Cloud and on-premise systems to engineer robust solutions. Specializing in the internal customer experience.
</p>
<div className="pt-4 flex justify-center md:justify-start">
<a href="profile.pdf" target="_blank" className="flex items-center gap-2 px-8 py-3 bg-slate-900 text-white rounded-lg hover:bg-slate-800 transition-all hover:-translate-y-1 shadow-lg hover:shadow-xl font-medium">
<Download size={20} />
<span>Download Resume</span>
</a>
</div>
</div>
{/* Right Side: Dual Personas */}
<div className="order-1 md:order-2 flex justify-center md:justify-end gap-6">
{/* Professional Persona */}
<div className="flex flex-col items-center space-y-4 group">
<div className="w-36 h-36 md:w-44 md:h-44 rounded-2xl overflow-hidden shadow-xl border-4 border-white bg-slate-100 transform rotate-2 group-hover:rotate-0 transition-all duration-300">
<img
src="james horton.jpeg"
alt="James Horton"
className="w-full h-full object-cover"
onError={(e) => {e.target.src='https://ui-avatars.com/api/?name=James+Horton&background=0D8ABC&color=fff&size=500'}}
/>
</div>
<a href="https://www.linkedin.com/in/james-horton-7a7b57139/" target="_blank" rel="noreferrer" className="flex items-center gap-2 px-5 py-2 bg-white border border-blue-100 text-blue-700 rounded-full hover:bg-blue-50 hover:border-blue-300 transition-all shadow-sm hover:shadow font-medium text-sm">
<Linkedin size={16} />
<span>Connect</span>
</a>
</div>
{/* Developer Persona (Staggered) */}
<div className="flex flex-col items-center space-y-4 mt-12 group">
<div className="w-36 h-36 md:w-44 md:h-44 rounded-2xl overflow-hidden shadow-xl border-4 border-slate-800 bg-yellow-400 transform -rotate-2 group-hover:rotate-0 transition-all duration-300">
<img
src="hortison.jpeg"
alt="Hortison Avatar"
className="w-full h-full object-cover"
onError={(e) => {e.target.src='https://ui-avatars.com/api/?name=Hortison&background=random&size=500'}}
/>
</div>
<div className="flex gap-2">
<a href="https://github.com/hortison" target="_blank" rel="noreferrer" className="flex items-center gap-2 px-4 py-2 bg-slate-900 text-white rounded-full hover:bg-slate-800 transition-all shadow-sm hover:shadow font-medium text-sm">
<Github size={16} />
<span>GitHub</span>
</a>
<a href="https://x.com/hortison2337" target="_blank" rel="noreferrer" className="flex items-center gap-2 px-4 py-2 bg-slate-900 text-white rounded-full hover:bg-slate-800 transition-all shadow-sm hover:shadow font-medium text-sm">
<XIcon size={14} />
<span>X</span>
</a>
</div>
</div>
</div>
</div>
</header>
{/* Skills Section */}
<section id="skills" className="py-20 bg-white border-y border-slate-100">
<div className="max-w-6xl mx-auto px-6">
<div className="flex flex-col md:flex-row md:items-start gap-12">
<div className="md:w-1/3">
<h2 className="text-3xl font-bold text-slate-900 mb-4">Technical Proficiency</h2>
<p className="text-slate-600 mb-6">
From on-premise legacy systems to cutting-edge cloud native architectures, I've spent time in almost every IT role.
</p>
<div className="flex items-center gap-2 text-blue-600 font-semibold">
<Award size={20} />
<span>National Merit Finalist</span>
</div>
</div>
<div className="md:w-2/3">
<div className="flex flex-wrap gap-3">
{skills.map((skill, index) => (
<span key={index} className="px-5 py-3 bg-slate-50 border border-slate-200 rounded-lg text-slate-700 font-medium hover:border-blue-400 hover:text-blue-600 hover:shadow-md transition-all cursor-default">
{skill}
</span>
))}
</div>
<div className="mt-8 grid grid-cols-2 md:grid-cols-4 gap-4">
<div className="p-4 bg-slate-50 rounded-lg text-center">
<Cloud className="mx-auto text-blue-500 mb-2" />
<span className="text-sm font-bold text-slate-700">Cloud Native</span>
</div>
<div className="p-4 bg-slate-50 rounded-lg text-center">
<Server className="mx-auto text-indigo-500 mb-2" />
<span className="text-sm font-bold text-slate-700">Infrastructure</span>
</div>
<div className="p-4 bg-slate-50 rounded-lg text-center">
<Terminal className="mx-auto text-emerald-500 mb-2" />
<span className="text-sm font-bold text-slate-700">DevOps</span>
</div>
<div className="p-4 bg-slate-50 rounded-lg text-center">
<MapPin className="mx-auto text-red-500 mb-2" />
<span className="text-sm font-bold text-slate-700">NYC Metro</span>
</div>
</div>
</div>
</div>
</div>
</section>
{/* Experience Section */}
<section id="experience" className="py-24 max-w-4xl mx-auto px-6">
<div className="text-center mb-16">
<h2 className="text-3xl font-bold text-slate-900">Professional Experience</h2>
<p className="text-slate-500 mt-2">A timeline of my journey in technology</p>
</div>
<div className="space-y-12 relative before:absolute before:inset-0 before:ml-5 before:-translate-x-px md:before:mx-auto md:before:translate-x-0 before:h-full before:w-0.5 before:bg-gradient-to-b before:from-transparent before:via-slate-300 before:to-transparent">
{experience.map((job, index) => (
<div key={index} className="relative flex items-center justify-between md:justify-normal md:odd:flex-row-reverse group is-active">
{/* Timeline Dot */}
<div className="flex items-center justify-center w-10 h-10 rounded-full border-4 border-white bg-slate-200 group-hover:bg-blue-600 transition-colors shadow shrink-0 md:order-1 md:group-odd:-translate-x-1/2 md:group-even:translate-x-1/2">
<div className="w-2.5 h-2.5 rounded-full bg-slate-400 group-hover:bg-white transition-colors"></div>
</div>
{/* Content Card */}
<div className="w-[calc(100%-4rem)] md:w-[calc(50%-2.5rem)] p-6 bg-white rounded-xl shadow-sm border border-slate-100 hover:shadow-md transition-shadow">
<div className="flex flex-col sm:flex-row justify-between items-start sm:items-center mb-2">
<h3 className="font-bold text-lg text-slate-900">{job.role}</h3>
<span className="text-xs font-semibold px-2 py-1 bg-blue-50 text-blue-700 rounded-md whitespace-nowrap">{job.period}</span>
</div>
<div className="flex items-center gap-2 mb-4 text-slate-500 text-sm font-medium">
<span>{job.company}</span>
<span>•</span>
<span>{job.location}</span>
</div>
<p className="text-slate-600 text-sm leading-relaxed">
{job.description}
</p>
{job.link && (
<a href={job.link} target="_blank" rel="noreferrer" className="inline-flex items-center gap-1 text-blue-600 text-sm font-medium mt-3 hover:underline">
Visit Layer5 <ExternalLink size={14} />
</a>
)}
</div>
</div>
))}
</div>
</section>
{/* Education */}
<section className="py-20 bg-slate-900 text-slate-300">
<div className="max-w-6xl mx-auto px-6">
<h2 className="text-2xl font-bold text-white mb-8">Education & Certifications</h2>
<div className="grid md:grid-cols-2 gap-8">
<div className="bg-slate-800 p-6 rounded-lg border border-slate-700">
<h3 className="text-white font-bold text-lg mb-1">University of California, Los Angeles</h3>
<p className="text-blue-400 text-sm mb-4">Bachelor's degree, Information Technology (1998-2001)</p>
</div>
<div className="bg-slate-800 p-6 rounded-lg border border-slate-700">
<h3 className="text-white font-bold text-lg mb-1">Microsoft Certified Systems Administrator</h3>
<p className="text-blue-400 text-sm mb-4">MCSA Certification</p>
</div>
</div>
</div>
</section>
{/* Footer */}
<footer className="bg-slate-950 py-12 border-t border-slate-900">
<div className="max-w-6xl mx-auto px-6 flex flex-col md:flex-row justify-between items-center gap-6">
<div className="text-center md:text-left">
<h2 className="text-xl font-bold text-white">James Horton</h2>
<p className="text-slate-500 text-sm mt-1">Senior Solutions Consultant</p>
</div>
<div className="flex gap-6">
<a href="mailto:james.horton@layer5.io" className="text-slate-400 hover:text-white transition-colors">
<Mail size={24} />
</a>
<a href="https://github.com/hortison" className="text-slate-400 hover:text-white transition-colors">
<Github size={24} />
</a>
<a href="https://www.linkedin.com/in/james-horton-7a7b57139/" className="text-slate-400 hover:text-white transition-colors">
<Linkedin size={24} />
</a>
</div>
<div className="text-slate-600 text-sm">
© {new Date().getFullYear()} James Horton. All rights reserved.
</div>
</div>
</footer>
</div>
);
};
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Portfolio />);
</script>
</body>
</html>