Skip to content

Commit 5a3a017

Browse files
committed
feat: new redirect logic for projects. 😉
1 parent b3cbef5 commit 5a3a017

5 files changed

Lines changed: 266 additions & 140 deletions

File tree

public/projects/projects.piml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,18 @@
4848
(date) 2026-02-18
4949
(image) /images/projects/gobake/gobake-banner.png
5050

51+
> (project)
52+
(slug) runir
53+
(title) Runir
54+
(redirect_url) https://fezcode.com/runir/
55+
(pinned) false
56+
(isActive) true
57+
(technologies)
58+
> TypeScript
59+
> Documentation
60+
(shortDescription) Runir is a modern documentation platform with extended markdown support.
61+
(date) 2026-04-12
62+
5163
> (project)
5264
(slug) castarook
5365
(title) Castarook

src/components/ProjectCard.jsx

Lines changed: 60 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,53 @@ import { motion } from 'framer-motion';
44
import { ArrowRightIcon } from '@phosphor-icons/react';
55

66
const ProjectCard = ({ project, index, isActive, onHover = () => {} }) => {
7+
const content = (
8+
<>
9+
{/* Active Indicator Line */}
10+
<div
11+
className={`absolute left-0 top-0 h-full w-1 bg-emerald-400 transition-all duration-300 ${
12+
isActive ? 'opacity-100' : 'opacity-0'
13+
}`}
14+
/>
15+
16+
<div className="flex flex-1 items-baseline gap-6 pl-4 md:pl-8 min-w-0 pr-8">
17+
{/* Index / Year */}
18+
<span
19+
className={`font-mono text-sm flex-shrink-0 transition-colors duration-300 ${
20+
isActive ? 'text-emerald-400' : 'text-gray-600'
21+
}`}
22+
>
23+
{String(index + 1).padStart(2, '0')}
24+
</span>
25+
26+
{/* Title */}
27+
<h3
28+
className={`text-3xl font-light uppercase tracking-tight transition-all duration-300 md:text-5xl break-words leading-[1.1] ${
29+
isActive
30+
? 'translate-x-2 text-white font-medium'
31+
: 'text-gray-500 group-hover:text-gray-300'
32+
}`}
33+
>
34+
{project.title}
35+
</h3>
36+
</div>
37+
38+
{/* Arrow Interaction */}
39+
<div
40+
className={`w-12 flex justify-end transform transition-all duration-300 ${
41+
isActive
42+
? 'translate-x-0 opacity-100 text-emerald-400'
43+
: '-translate-x-4 opacity-0 text-gray-500'
44+
}`}
45+
>
46+
<ArrowRightIcon size={32} weight="light" />
47+
</div>
48+
</>
49+
);
50+
51+
const className =
52+
'group relative flex items-center justify-between border-b border-white/10 py-8 pr-12 transition-all duration-300';
53+
754
return (
855
<motion.div
956
initial={{ opacity: 0, x: -20 }}
@@ -12,50 +59,20 @@ const ProjectCard = ({ project, index, isActive, onHover = () => {} }) => {
1259
onMouseEnter={() => onHover(project)}
1360
className="relative mr-4 md:mr-12"
1461
>
15-
<Link
16-
to={`/projects/${project.slug}`}
17-
className="group relative flex items-center justify-between border-b border-white/10 py-8 pr-12 transition-all duration-300"
18-
>
19-
{/* Active Indicator Line */}
20-
<div
21-
className={`absolute left-0 top-0 h-full w-1 bg-emerald-400 transition-all duration-300 ${
22-
isActive ? 'opacity-100' : 'opacity-0'
23-
}`}
24-
/>
25-
26-
<div className="flex flex-1 items-baseline gap-6 pl-4 md:pl-8 min-w-0 pr-8">
27-
{/* Index / Year */}
28-
<span
29-
className={`font-mono text-sm flex-shrink-0 transition-colors duration-300 ${
30-
isActive ? 'text-emerald-400' : 'text-gray-600'
31-
}`}
32-
>
33-
{String(index + 1).padStart(2, '0')}
34-
</span>
35-
36-
{/* Title */}
37-
<h3
38-
className={`text-3xl font-light uppercase tracking-tight transition-all duration-300 md:text-5xl break-words leading-[1.1] ${
39-
isActive
40-
? 'translate-x-2 text-white font-medium'
41-
: 'text-gray-500 group-hover:text-gray-300'
42-
}`}
43-
>
44-
{project.title}
45-
</h3>
46-
</div>
47-
48-
{/* Arrow Interaction */}
49-
<div
50-
className={`w-12 flex justify-end transform transition-all duration-300 ${
51-
isActive
52-
? 'translate-x-0 opacity-100 text-emerald-400'
53-
: '-translate-x-4 opacity-0 text-gray-500'
54-
}`}
62+
{project.redirect_url ? (
63+
<a
64+
href={project.redirect_url}
65+
target="_blank"
66+
rel="noopener noreferrer"
67+
className={className}
5568
>
56-
<ArrowRightIcon size={32} weight="light" />
57-
</div>
58-
</Link>
69+
{content}
70+
</a>
71+
) : (
72+
<Link to={`/projects/${project.slug}`} className={className}>
73+
{content}
74+
</Link>
75+
)}
5976
</motion.div>
6077
);
6178
};

src/pages/ProjectPage.jsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ const ProjectPage = () => {
4040
const project = projects.find((p) => p.slug === slug);
4141
const fullProject = project && content ? { ...project, ...content } : null;
4242

43+
React.useEffect(() => {
44+
if (project && project.redirect_url) {
45+
window.location.href = project.redirect_url;
46+
}
47+
}, [project]);
48+
4349
if (loadingProjects || loadingContent) {
4450
return (
4551
<div className="min-h-screen bg-[#050505] flex items-center justify-center text-white font-mono uppercase tracking-widest text-xs">

src/pages/brutalist-views/BrutalistProjectsPage.jsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,21 +164,27 @@ const BrutalistProjectsPage = () => {
164164
</div>
165165

166166
{/* External Link Button (Optional) */}
167-
{(activeProject.demo_link || activeProject.repo_link) && (
167+
{(activeProject.redirect_url ||
168+
activeProject.demo_link ||
169+
activeProject.repo_link) && (
168170
<motion.div
169171
initial={{ opacity: 0, y: 20 }}
170172
animate={{ opacity: 1, y: 0 }}
171173
transition={{ delay: 0.2 }}
172174
className="mt-4"
173175
>
174176
<a
175-
href={activeProject.demo_link || activeProject.repo_link}
177+
href={
178+
activeProject.redirect_url ||
179+
activeProject.demo_link ||
180+
activeProject.repo_link
181+
}
176182
target="_blank"
177183
rel="noopener noreferrer"
178184
className="inline-flex items-center gap-3 text-white border-b border-white pb-1 hover:text-emerald-400 hover:border-emerald-400 transition-colors"
179185
>
180186
<span className="text-sm font-bold uppercase tracking-widest">
181-
{activeProject.demo_link
187+
{activeProject.redirect_url || activeProject.demo_link
182188
? 'Visit Live Site'
183189
: 'View Source'}
184190
</span>

0 commit comments

Comments
 (0)