Skip to content

Commit c03aa37

Browse files
authored
Merge pull request #64 from Ebyte-Lab/feat/vite-and-spa-for-portifolio
Add Vite and React SPA for Portfolio Template
2 parents 4f8c966 + 3f9ba1f commit c03aa37

18 files changed

Lines changed: 831 additions & 5 deletions

File tree

src/generate.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export async function generateProject(config) {
6666
// 🟢 DEVELOPMENT MODE: Local folder found
6767
const spinner = ora({
6868
text: 'DEV MODE: Copying local template...',
69-
spinner: 'squareCorners',
69+
spinner: 'dots',
7070
color: 'blue'
7171
}).start();
7272
fs.cpSync(localTemplatePath, projectPath, { recursive: true });
@@ -78,7 +78,7 @@ export async function generateProject(config) {
7878

7979
const spinner = ora({
8080
text: `Fetching template from GitHub (${repoURI})...`,
81-
spinner: 'squareCorners',
81+
spinner: 'dots',
8282
color: 'blue'
8383
}).start();
8484

@@ -109,7 +109,7 @@ export async function generateProject(config) {
109109
// 3. TRANSFORM PHASE: Process Handlebars Tags
110110
const compileSpinner = ora({
111111
text: 'Compiling template tags...',
112-
spinner: 'squareCorners',
112+
spinner: 'dots',
113113
color: 'cyan'
114114
}).start();
115115
const allFiles = getAllFiles(projectPath);
@@ -151,7 +151,7 @@ export async function generateProject(config) {
151151

152152
const installSpinner = ora({
153153
text: 'Installing dependencies (this might take a minute)...',
154-
spinner: 'squareCorners',
154+
spinner: 'dots',
155155
color: 'yellow'
156156
}).start();
157157
try {
@@ -168,7 +168,7 @@ export async function generateProject(config) {
168168
if (config.initGit) {
169169
const gitSpinner = ora({
170170
text: 'Initializing Git repository...',
171-
spinner: 'squareCorners',
171+
spinner: 'dots',
172172
color: 'magenta'
173173
}).start();
174174
try {
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
export default function SkillsPage() {
2+
const categories = [
3+
{
4+
title: 'Frontend',
5+
skills: [
6+
{ name: 'React', level: 95 },
7+
{ name: 'Next.js', level: 90 },
8+
{ name: 'TypeScript', level: 92 },
9+
{ name: 'Tailwind CSS', level: 95 },
10+
{ name: 'HTML/CSS', level: 98 },
11+
{ name: 'Vue.js', level: 70 },
12+
],
13+
},
14+
{
15+
title: 'Backend',
16+
skills: [
17+
{ name: 'Node.js', level: 88 },
18+
{ name: 'PostgreSQL', level: 82 },
19+
{ name: 'REST APIs', level: 90 },
20+
{ name: 'GraphQL', level: 75 },
21+
{ name: 'Prisma', level: 85 },
22+
{ name: 'Redis', level: 70 },
23+
],
24+
},
25+
{
26+
title: 'Tools & DevOps',
27+
skills: [
28+
{ name: 'Git', level: 92 },
29+
{ name: 'Docker', level: 78 },
30+
{ name: 'CI/CD', level: 80 },
31+
{ name: 'Vercel', level: 90 },
32+
{ name: 'AWS', level: 72 },
33+
{ name: 'Linux', level: 75 },
34+
],
35+
},
36+
{
37+
title: 'Design & Other',
38+
skills: [
39+
{ name: 'Figma', level: 85 },
40+
{ name: 'UI/UX Design', level: 78 },
41+
{ name: 'Accessibility', level: 82 },
42+
{ name: 'Performance', level: 88 },
43+
{ name: 'Testing', level: 80 },
44+
{ name: 'Agile/Scrum', level: 85 },
45+
],
46+
},
47+
];
48+
49+
const certifications = [
50+
{ name: 'AWS Certified Cloud Practitioner', issuer: 'Amazon Web Services', year: '2023' },
51+
{ name: 'Meta Frontend Developer Certificate', issuer: 'Meta / Coursera', year: '2022' },
52+
{ name: 'Google UX Design Certificate', issuer: 'Google / Coursera', year: '2021' },
53+
];
54+
55+
return (
56+
<div className="min-h-screen bg-background">
57+
<section className="max-w-5xl mx-auto px-6 py-16">
58+
<div className="mb-12">
59+
<h1 className="text-3xl sm:text-4xl font-bold text-foreground">Skills & Expertise</h1>
60+
<p className="mt-3 text-text-secondary text-lg">
61+
A breakdown of my technical skills, tools, and proficiency levels built over 5+ years of professional development.
62+
</p>
63+
</div>
64+
65+
{/* Skill Categories */}
66+
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 mb-20">
67+
{categories.map((category) => (
68+
<div key={category.title} className="border border-border rounded-theme p-6 bg-card">
69+
<h2 className="text-xl font-bold text-foreground mb-6">{category.title}</h2>
70+
<div className="space-y-4">
71+
{category.skills.map((skill) => (
72+
<div key={skill.name}>
73+
<div className="flex justify-between text-sm mb-1.5">
74+
<span className="font-medium text-foreground">{skill.name}</span>
75+
<span className="text-text-secondary">{skill.level}%</span>
76+
</div>
77+
<div className="w-full h-2 bg-bg-secondary rounded-full overflow-hidden">
78+
<div
79+
className="h-full rounded-full transition-all duration-500"
80+
style=\{{ width: `${skill.level}%`, backgroundColor: 'var(--primary)' }}
81+
/>
82+
</div>
83+
</div>
84+
))}
85+
</div>
86+
</div>
87+
))}
88+
</div>
89+
90+
{/* Certifications */}
91+
<div>
92+
<h2 className="text-2xl font-bold text-foreground mb-8 text-center">Certifications</h2>
93+
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
94+
{certifications.map((cert) => (
95+
<div key={cert.name} className="border border-border rounded-theme p-5 bg-card text-center">
96+
<div className="w-12 h-12 rounded-full bg-primary/10 mx-auto flex items-center justify-center mb-4">
97+
<svg className="w-6 h-6 text-primary" fill="none" stroke="currentColor" viewBox="0 0 24 24">
98+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4M7.835 4.697a3.42 3.42 0 001.946-.806 3.42 3.42 0 014.438 0 3.42 3.42 0 001.946.806 3.42 3.42 0 013.138 3.138 3.42 3.42 0 00.806 1.946 3.42 3.42 0 010 4.438 3.42 3.42 0 00-.806 1.946 3.42 3.42 0 01-3.138 3.138 3.42 3.42 0 00-1.946.806 3.42 3.42 0 01-4.438 0 3.42 3.42 0 00-1.946-.806 3.42 3.42 0 01-3.138-3.138 3.42 3.42 0 00-.806-1.946 3.42 3.42 0 010-4.438 3.42 3.42 0 00.806-1.946 3.42 3.42 0 013.138-3.138z" />
99+
</svg>
100+
</div>
101+
<h3 className="font-semibold text-foreground text-sm">{cert.name}</h3>
102+
<p className="text-xs text-text-secondary mt-1">{cert.issuer}</p>
103+
<p className="text-xs text-primary mt-1">{cert.year}</p>
104+
</div>
105+
))}
106+
</div>
107+
</div>
108+
</section>
109+
</div>
110+
);
111+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!DOCTYPE html>
2+
<html lang="en" data-theme="{{design}}">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>{{projectName}} - Portfolio</title>
8+
</head>
9+
<body>
10+
<div id="root"></div>
11+
<script type="module" src="/src/main.tsx"></script>
12+
</body>
13+
</html>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"name": "{{projectName}}",
3+
"version": "1.0.0",
4+
"private": true,
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite",
8+
"build": "tsc && vite build",
9+
"preview": "vite preview"
10+
},
11+
"dependencies": {
12+
"react": "^18.3.1",
13+
"react-dom": "^18.3.1",
14+
"react-router-dom": "^6.23.0"
15+
},
16+
"devDependencies": {
17+
"@types/react": "^18.3.0",
18+
"@types/react-dom": "^18.3.0",
19+
"@vitejs/plugin-react": "^4.2.1",
20+
"autoprefixer": "^10.4.19",
21+
"postcss": "^8.4.38",
22+
"tailwindcss": "^3.4.3",
23+
"typescript": "^5.4.5",
24+
"vite": "^5.2.11"
25+
}
26+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export default {
2+
plugins: {
3+
tailwindcss: {},
4+
autoprefixer: {},
5+
},
6+
};
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { BrowserRouter, Routes, Route } from 'react-router-dom';
2+
import Layout from './components/Layout';
3+
import Home from './pages/Home';
4+
import Projects from './pages/Projects';
5+
import About from './pages/About';
6+
import Contact from './pages/Contact';
7+
import Skills from './pages/Skills';
8+
9+
export default function App() {
10+
return (
11+
<BrowserRouter>
12+
<Routes>
13+
<Route element={<Layout />}>
14+
<Route path="/" element={<Home />} />
15+
<Route path="/projects" element={<Projects />} />
16+
<Route path="/about" element={<About />} />
17+
<Route path="/skills" element={<Skills />} />
18+
<Route path="/contact" element={<Contact />} />
19+
</Route>
20+
</Routes>
21+
</BrowserRouter>
22+
);
23+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { Link, Outlet } from 'react-router-dom';
2+
import { navLinks } from '../lib/nav';
3+
4+
function Navbar() {
5+
return (
6+
<header className="border-b border-border bg-card">
7+
<nav className="max-w-5xl mx-auto px-6 h-16 flex items-center justify-between">
8+
<Link to="/" className="text-xl font-bold text-primary">
9+
{{projectName}}
10+
</Link>
11+
<ul className="flex gap-6">
12+
{navLinks.map((link) => (
13+
<li key={link.href}>
14+
<Link
15+
to={link.href}
16+
className="text-text-secondary hover:text-foreground transition"
17+
>
18+
{link.label}
19+
</Link>
20+
</li>
21+
))}
22+
</ul>
23+
</nav>
24+
</header>
25+
);
26+
}
27+
28+
function Sidebar() {
29+
return (
30+
<aside className="w-64 border-r border-border bg-card min-h-screen p-6">
31+
<Link to="/" className="text-xl font-bold text-primary block mb-8">
32+
{{projectName}}
33+
</Link>
34+
<nav>
35+
<ul className="space-y-2">
36+
{navLinks.map((link) => (
37+
<li key={link.href}>
38+
<Link
39+
to={link.href}
40+
className="block px-4 py-2 rounded-theme text-text-secondary hover:bg-bg-secondary hover:text-foreground transition"
41+
>
42+
{link.label}
43+
</Link>
44+
</li>
45+
))}
46+
</ul>
47+
</nav>
48+
</aside>
49+
);
50+
}
51+
52+
export default function Layout() {
53+
const useSidebar = ('{{includeSidebar}}' as string) === 'true';
54+
55+
if (useSidebar) {
56+
return (
57+
<div className="flex">
58+
<Sidebar />
59+
<main className="flex-1">
60+
<Outlet />
61+
</main>
62+
</div>
63+
);
64+
}
65+
66+
return (
67+
<>
68+
<Navbar />
69+
<main>
70+
<Outlet />
71+
</main>
72+
</>
73+
);
74+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
@tailwind base;
2+
@tailwind components;
3+
@tailwind utilities;
4+
5+
:root {
6+
--bg-color: #ffffff;
7+
--bg-secondary: #f9fafb;
8+
--text-color: #111827;
9+
--text-secondary: #6b7280;
10+
--primary: #2563eb;
11+
--primary-hover: #1d4ed8;
12+
--border-color: #e5e7eb;
13+
--card-bg: #ffffff;
14+
--font-family: 'Inter', system-ui, sans-serif;
15+
--radius: 0.5rem;
16+
}
17+
18+
[data-theme="Glassmorphism"] {
19+
--bg-color: #0f172a;
20+
--bg-secondary: rgba(255, 255, 255, 0.05);
21+
--text-color: #f1f5f9;
22+
--text-secondary: #94a3b8;
23+
--primary: #8b5cf6;
24+
--primary-hover: #7c3aed;
25+
--border-color: rgba(255, 255, 255, 0.1);
26+
--card-bg: rgba(255, 255, 255, 0.08);
27+
--font-family: 'Inter', system-ui, sans-serif;
28+
--radius: 1rem;
29+
}
30+
31+
[data-theme="Dark Terminal"] {
32+
--bg-color: #000000;
33+
--bg-secondary: #0a0a0a;
34+
--text-color: #3fb950;
35+
--text-secondary: #8b949e;
36+
--primary: #3fb950;
37+
--primary-hover: #2ea043;
38+
--border-color: #21262d;
39+
--card-bg: #0d1117;
40+
--font-family: 'JetBrains Mono', 'Fira Code', monospace;
41+
--radius: 0.25rem;
42+
}
43+
44+
body {
45+
background-color: var(--bg-color);
46+
color: var(--text-color);
47+
font-family: var(--font-family);
48+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import React from 'react';
2+
import ReactDOM from 'react-dom/client';
3+
import App from './App';
4+
import './index.css';
5+
6+
ReactDOM.createRoot(document.getElementById('root')!).render(
7+
<React.StrictMode>
8+
<App />
9+
</React.StrictMode>,
10+
);

0 commit comments

Comments
 (0)