abhishek-portfolio-template 1.0.0 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/template/package.json +1 -0
- package/template/src/app/layout.tsx +7 -1
- package/template/src/app/works/[slug]/page.tsx +5 -22
- package/template/src/app/works/page.tsx +3 -10
- package/template/src/components/ui/social-stories.tsx +22 -24
- package/template/src/lib/data.ts +75 -8
- package/template/src/types/project.ts +28 -0
package/package.json
CHANGED
package/template/package.json
CHANGED
|
@@ -2,6 +2,8 @@ import type { Metadata, Viewport } from "next";
|
|
|
2
2
|
import { Outfit } from "next/font/google";
|
|
3
3
|
import { bolivia } from "@/lib/fonts";
|
|
4
4
|
import { NavBar } from "@/components/ui/navbar";
|
|
5
|
+
import { PreloaderWrapper } from "@/components/ui/preloader-wrapper";
|
|
6
|
+
import { SmoothScroll } from "@/components/ui/smooth-scroll";
|
|
5
7
|
import "./globals.css";
|
|
6
8
|
|
|
7
9
|
const outfit = Outfit({
|
|
@@ -32,7 +34,11 @@ export default function RootLayout({
|
|
|
32
34
|
<html lang="en">
|
|
33
35
|
<body className={`${outfit.variable} ${bolivia.variable} bg-[#050805] text-[#ededed] antialiased`}>
|
|
34
36
|
<NavBar />
|
|
35
|
-
<
|
|
37
|
+
<PreloaderWrapper>
|
|
38
|
+
<SmoothScroll>
|
|
39
|
+
{children}
|
|
40
|
+
</SmoothScroll>
|
|
41
|
+
</PreloaderWrapper>
|
|
36
42
|
</body>
|
|
37
43
|
</html>
|
|
38
44
|
);
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { createClient } from "@/utils/supabase/server";
|
|
2
1
|
import { notFound } from "next/navigation";
|
|
3
2
|
import { ProjectDetailsView } from "@/components/works/project-details-view";
|
|
4
3
|
import { Metadata } from "next";
|
|
5
|
-
|
|
6
|
-
export const revalidate = 0; // Dynamic rendering
|
|
4
|
+
import { FEATURED_PROJECTS, CONTRIBUTORS } from "@/lib/data";
|
|
7
5
|
|
|
8
6
|
interface WorksDetailProps {
|
|
9
7
|
params: Promise<{
|
|
@@ -11,20 +9,9 @@ interface WorksDetailProps {
|
|
|
11
9
|
}>;
|
|
12
10
|
}
|
|
13
11
|
|
|
14
|
-
async function getProject(slug: string) {
|
|
15
|
-
const supabase = await createClient();
|
|
16
|
-
const { data } = await supabase
|
|
17
|
-
.from("projects")
|
|
18
|
-
.select("*")
|
|
19
|
-
.eq("slug", slug)
|
|
20
|
-
.single();
|
|
21
|
-
|
|
22
|
-
return data;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
12
|
export async function generateMetadata({ params }: WorksDetailProps): Promise<Metadata> {
|
|
26
13
|
const { slug } = await params;
|
|
27
|
-
const project =
|
|
14
|
+
const project = FEATURED_PROJECTS.find(p => p.slug === slug);
|
|
28
15
|
if (!project) return { title: "Project Not Found" };
|
|
29
16
|
return {
|
|
30
17
|
title: `${project.title} - Case Study`,
|
|
@@ -34,17 +21,13 @@ export async function generateMetadata({ params }: WorksDetailProps): Promise<Me
|
|
|
34
21
|
|
|
35
22
|
export default async function ProjectDetailPage({ params }: WorksDetailProps) {
|
|
36
23
|
const { slug } = await params;
|
|
37
|
-
const project =
|
|
24
|
+
const project = FEATURED_PROJECTS.find(p => p.slug === slug);
|
|
38
25
|
|
|
39
26
|
if (!project) {
|
|
40
27
|
notFound();
|
|
41
28
|
}
|
|
42
29
|
|
|
43
|
-
const
|
|
44
|
-
.from("project_contributors")
|
|
45
|
-
.select("*")
|
|
46
|
-
.eq("project_id", project.id)
|
|
47
|
-
.order("created_at", { ascending: true });
|
|
30
|
+
const contributors = CONTRIBUTORS[project.id as keyof typeof CONTRIBUTORS] || [];
|
|
48
31
|
|
|
49
|
-
return <ProjectDetailsView project={project} contributors={contributors
|
|
32
|
+
return <ProjectDetailsView project={project as any} contributors={contributors} />;
|
|
50
33
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FEATURED_PROJECTS } from "@/lib/data";
|
|
2
2
|
import { WorksClient } from "./client";
|
|
3
3
|
import { NavBar } from "@/components/ui/navbar";
|
|
4
4
|
|
|
@@ -7,18 +7,11 @@ export const metadata = {
|
|
|
7
7
|
description: "A curated list of my projects and current work in progress.",
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
-
export default
|
|
11
|
-
const supabase = await createClient();
|
|
12
|
-
|
|
13
|
-
const { data: projects } = await supabase
|
|
14
|
-
.from("projects")
|
|
15
|
-
.select("*")
|
|
16
|
-
.order("display_order", { ascending: true });
|
|
17
|
-
|
|
10
|
+
export default function WorksPage() {
|
|
18
11
|
return (
|
|
19
12
|
<>
|
|
20
13
|
<NavBar />
|
|
21
|
-
<WorksClient projects={
|
|
14
|
+
<WorksClient projects={FEATURED_PROJECTS} />
|
|
22
15
|
</>
|
|
23
16
|
);
|
|
24
17
|
}
|
|
@@ -5,7 +5,6 @@ import { createPortal } from "react-dom"
|
|
|
5
5
|
import { motion, AnimatePresence } from "framer-motion"
|
|
6
6
|
import { ArrowUpRight, X, Loader2 } from "lucide-react"
|
|
7
7
|
import Image from "next/image"
|
|
8
|
-
import { supabase } from "@/lib/supabase"
|
|
9
8
|
import { cn } from "@/lib/utils"
|
|
10
9
|
|
|
11
10
|
export type SocialPlatform = "linkedin" | "instagram"
|
|
@@ -25,15 +24,34 @@ const PROFILE = {
|
|
|
25
24
|
avatarUrl: "https://res.cloudinary.com/dap0u41dz/image/upload/v1766771167/file_00000000d51472078b7e2f9d883a6674_majhmb.jpg",
|
|
26
25
|
}
|
|
27
26
|
|
|
27
|
+
const DUMMY_STORIES: Story[] = [
|
|
28
|
+
{
|
|
29
|
+
id: "1",
|
|
30
|
+
platform: "linkedin",
|
|
31
|
+
mediaUrl: "https://images.unsplash.com/photo-1633356122544-f134324a6cee?q=80&w=2670&auto=format&fit=crop",
|
|
32
|
+
linkUrl: "https://linkedin.com/in/AbhishekS04",
|
|
33
|
+
caption: "Just launched a new project! 🚀 #development #webdesign",
|
|
34
|
+
duration: 5
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: "2",
|
|
38
|
+
platform: "instagram",
|
|
39
|
+
mediaUrl: "https://images.unsplash.com/photo-1587620962725-abab7fe55159?q=80&w=2531&auto=format&fit=crop",
|
|
40
|
+
linkUrl: "https://github.com/AbhishekS04",
|
|
41
|
+
caption: "Late night coding sessions... ☕️💻",
|
|
42
|
+
duration: 5
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
|
|
28
46
|
export function SocialStories({ id = "default" }: { id?: string }) {
|
|
29
|
-
const [stories, setStories] = useState<Story[]>(
|
|
47
|
+
const [stories, setStories] = useState<Story[]>(DUMMY_STORIES)
|
|
30
48
|
const [isOpen, setIsOpen] = useState(false)
|
|
31
49
|
const [currentIndex, setCurrentIndex] = useState(0)
|
|
32
50
|
const [isPaused, setIsPaused] = useState(false)
|
|
33
51
|
const [isMediaLoaded, setIsMediaLoaded] = useState(false)
|
|
34
52
|
const [mounted, setMounted] = useState(false)
|
|
35
53
|
const [dynamicDuration, setDynamicDuration] = useState<number | null>(null)
|
|
36
|
-
const [isFetchLoading, setIsFetchLoading] = useState(
|
|
54
|
+
const [isFetchLoading, setIsFetchLoading] = useState(false)
|
|
37
55
|
|
|
38
56
|
// Timing refs for high-performance animation
|
|
39
57
|
const startTimeRef = useRef<number | null>(null)
|
|
@@ -47,30 +65,10 @@ export function SocialStories({ id = "default" }: { id?: string }) {
|
|
|
47
65
|
|
|
48
66
|
useEffect(() => {
|
|
49
67
|
setMounted(true)
|
|
50
|
-
fetchStories()
|
|
51
68
|
}, [])
|
|
52
69
|
|
|
53
70
|
const fetchStories = async () => {
|
|
54
|
-
|
|
55
|
-
try {
|
|
56
|
-
const { data } = await supabase
|
|
57
|
-
.from("social_stories")
|
|
58
|
-
.select("*")
|
|
59
|
-
.order("display_order", { ascending: true })
|
|
60
|
-
|
|
61
|
-
if (data) {
|
|
62
|
-
setStories(data.map(s => ({
|
|
63
|
-
id: s.id,
|
|
64
|
-
platform: s.platform as SocialPlatform,
|
|
65
|
-
mediaUrl: s.media_url,
|
|
66
|
-
linkUrl: s.link_url,
|
|
67
|
-
caption: s.caption,
|
|
68
|
-
duration: 5
|
|
69
|
-
})))
|
|
70
|
-
}
|
|
71
|
-
} finally {
|
|
72
|
-
setIsFetchLoading(false)
|
|
73
|
-
}
|
|
71
|
+
// No-op for template
|
|
74
72
|
}
|
|
75
73
|
|
|
76
74
|
const currentStory = stories[currentIndex]
|
package/template/src/lib/data.ts
CHANGED
|
@@ -1,11 +1,39 @@
|
|
|
1
1
|
|
|
2
|
+
export interface Contributor {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
role: string;
|
|
6
|
+
avatar_url: string;
|
|
7
|
+
social_url?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
2
10
|
export interface Project {
|
|
3
11
|
id: string;
|
|
4
12
|
title: string;
|
|
13
|
+
slug: string;
|
|
5
14
|
description: string;
|
|
6
|
-
|
|
7
|
-
|
|
15
|
+
long_description?: string;
|
|
16
|
+
overview?: string;
|
|
17
|
+
problem_statement?: string;
|
|
18
|
+
approach?: string;
|
|
19
|
+
outcome?: string;
|
|
20
|
+
tech_stack: string[];
|
|
21
|
+
image_url: string;
|
|
22
|
+
video_url?: string;
|
|
23
|
+
media_mode?: 'image_first' | 'video_first';
|
|
8
24
|
link: string;
|
|
25
|
+
is_currently_working?: boolean;
|
|
26
|
+
github_url?: string;
|
|
27
|
+
live_url?: string;
|
|
28
|
+
external_link_url?: string;
|
|
29
|
+
project_url?: string;
|
|
30
|
+
tags?: string[];
|
|
31
|
+
created_at?: string;
|
|
32
|
+
status: 'Not Started' | 'In Progress' | 'Near Completion' | 'Completed';
|
|
33
|
+
project_type?: 'Client' | 'Personal';
|
|
34
|
+
client_name?: string;
|
|
35
|
+
features?: string;
|
|
36
|
+
gallery_images?: string[];
|
|
9
37
|
}
|
|
10
38
|
|
|
11
39
|
export const USER_DATA = {
|
|
@@ -24,29 +52,68 @@ export const FEATURED_PROJECTS: Project[] = [
|
|
|
24
52
|
{
|
|
25
53
|
id: "1",
|
|
26
54
|
title: "Bento Portfolio Template",
|
|
55
|
+
slug: "bento-portfolio",
|
|
27
56
|
description: "A premium portfolio template featuring a responsive bento grid and smooth framer-motion animations.",
|
|
28
|
-
|
|
29
|
-
|
|
57
|
+
overview: "A comprehensive solution for developers wanting a high-end portfolio without spending weeks on design.",
|
|
58
|
+
problem_statement: "Most templates are either too generic or too complex to customize.",
|
|
59
|
+
approach: "Built with Next.js 15 and Framer Motion for a perfect balance of performance and aesthetics.",
|
|
60
|
+
outcome: "A 5-star rated template used by hundreds of developers.",
|
|
61
|
+
tech_stack: ["Next.js", "Framer Motion", "Tailwind CSS"],
|
|
62
|
+
image_url: "https://images.unsplash.com/photo-1550751827-4bd374c3f58b?q=80&w=2670&auto=format&fit=crop",
|
|
30
63
|
link: "#",
|
|
64
|
+
is_currently_working: true,
|
|
65
|
+
status: 'In Progress',
|
|
66
|
+
project_type: 'Personal',
|
|
67
|
+
created_at: new Date().toISOString(),
|
|
68
|
+
tags: ["Design System", "Next.js", "Animations"],
|
|
69
|
+
github_url: "https://github.com/AbhishekS04/abhishek-portfolio-template",
|
|
70
|
+
live_url: "#",
|
|
71
|
+
features: "Responsive Bento Grid\nPremium Framer Motion Animations\nNext.js 15 Optimized\nPWA Ready",
|
|
72
|
+
gallery_images: [
|
|
73
|
+
"https://images.unsplash.com/photo-1618005182384-a83a8bd57fbe?q=80&w=2564&auto=format&fit=crop",
|
|
74
|
+
"https://images.unsplash.com/photo-1550751827-4bd374c3f58b?q=80&w=2670&auto=format&fit=crop"
|
|
75
|
+
]
|
|
31
76
|
},
|
|
32
77
|
{
|
|
33
78
|
id: "2",
|
|
34
79
|
title: "Dynamic UI Components",
|
|
80
|
+
slug: "dynamic-ui",
|
|
35
81
|
description: "A collection of reusable, highly interactive components for modern web apps.",
|
|
36
|
-
|
|
37
|
-
|
|
82
|
+
overview: "A library focused on micro-interactions and tactile feedback.",
|
|
83
|
+
tech_stack: ["React", "TypeScript", "Lucide"],
|
|
84
|
+
image_url: "https://images.unsplash.com/photo-1611974765270-ca12586343bb?q=80&w=2576&auto=format&fit=crop",
|
|
38
85
|
link: "#",
|
|
86
|
+
status: 'Completed',
|
|
87
|
+
project_type: 'Personal',
|
|
88
|
+
created_at: new Date().toISOString(),
|
|
89
|
+
tags: ["UI/UX", "Open Source"],
|
|
90
|
+
github_url: "#",
|
|
91
|
+
live_url: "#",
|
|
39
92
|
},
|
|
40
93
|
{
|
|
41
94
|
id: "3",
|
|
42
95
|
title: "AI Project Scaffolder",
|
|
96
|
+
slug: "ai-scaffolder",
|
|
43
97
|
description: "CLI tool for generating optimized project structures with pre-configured tools.",
|
|
44
|
-
|
|
45
|
-
|
|
98
|
+
tech_stack: ["Node.js", "CLI", "Shell"],
|
|
99
|
+
image_url: "https://images.unsplash.com/photo-1677442136019-21780ecad995?q=80&w=2664&auto=format&fit=crop",
|
|
46
100
|
link: "#",
|
|
101
|
+
status: 'Near Completion',
|
|
102
|
+
project_type: 'Personal',
|
|
103
|
+
created_at: new Date().toISOString(),
|
|
104
|
+
tags: ["CLI", "DevTools"],
|
|
47
105
|
},
|
|
48
106
|
];
|
|
49
107
|
|
|
108
|
+
export const CONTRIBUTORS: Record<string, Contributor[]> = {
|
|
109
|
+
"1": [
|
|
110
|
+
{ id: "c1", name: "Abhishek Singh", role: "Lead Developer", avatar_url: "https://avatars.githubusercontent.com/u/74382583?v=4" }
|
|
111
|
+
],
|
|
112
|
+
"2": [
|
|
113
|
+
{ id: "c1", name: "Abhishek Singh", role: "Contributor", avatar_url: "https://avatars.githubusercontent.com/u/74382583?v=4" }
|
|
114
|
+
]
|
|
115
|
+
};
|
|
116
|
+
|
|
50
117
|
export const SKILLS = [
|
|
51
118
|
"Product Engineering",
|
|
52
119
|
"UI Systems & Animations",
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface Project {
|
|
2
|
+
id: string;
|
|
3
|
+
title: string;
|
|
4
|
+
slug: string;
|
|
5
|
+
description: string;
|
|
6
|
+
long_description?: string;
|
|
7
|
+
overview?: string;
|
|
8
|
+
problem_statement?: string;
|
|
9
|
+
approach?: string;
|
|
10
|
+
outcome?: string;
|
|
11
|
+
tech_stack: string[];
|
|
12
|
+
image_url: string;
|
|
13
|
+
video_url?: string;
|
|
14
|
+
media_mode?: 'image_first' | 'video_first';
|
|
15
|
+
link: string;
|
|
16
|
+
is_currently_working?: boolean;
|
|
17
|
+
github_url?: string;
|
|
18
|
+
live_url?: string;
|
|
19
|
+
external_link_url?: string;
|
|
20
|
+
project_url?: string;
|
|
21
|
+
tags?: string[];
|
|
22
|
+
created_at?: string;
|
|
23
|
+
status: 'Not Started' | 'In Progress' | 'Near Completion' | 'Completed';
|
|
24
|
+
project_type?: 'Client' | 'Personal';
|
|
25
|
+
client_name?: string;
|
|
26
|
+
features?: string;
|
|
27
|
+
gallery_images?: string[];
|
|
28
|
+
}
|