@tsparticles/template-portfolio 4.1.3 → 4.2.0
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/CHANGELOG.md +10 -0
- package/README.md +3 -0
- package/package.json +4 -3
- package/template/angular/package.json +35 -0
- package/template/angular/src/app/app.component.css +180 -0
- package/template/angular/src/app/app.component.html +53 -0
- package/template/angular/src/app/app.component.ts +47 -0
- package/template/angular-confetti/package.json +36 -0
- package/template/angular-confetti/src/app/app.component.css +180 -0
- package/template/angular-confetti/src/app/app.component.html +53 -0
- package/template/angular-confetti/src/app/app.component.ts +47 -0
- package/template/angular-fireworks/package.json +36 -0
- package/template/angular-fireworks/src/app/app.component.css +180 -0
- package/template/angular-fireworks/src/app/app.component.html +53 -0
- package/template/angular-fireworks/src/app/app.component.ts +47 -0
- package/template/astro/package.json +21 -0
- package/template/astro/src/pages/index.astro +131 -0
- package/template/ember/app/templates/application.hbs +61 -0
- package/template/ember/package.json +25 -0
- package/template/inferno/package.json +23 -0
- package/template/inferno/src/App.css +180 -0
- package/template/inferno/src/App.tsx +100 -0
- package/template/jquery/package.json +23 -0
- package/template/jquery/src/main.ts +33 -0
- package/template/jquery/src/style.css +180 -0
- package/template/lit/package.json +22 -0
- package/template/lit/src/my-app.ts +117 -0
- package/template/lit/src/style.css +180 -0
- package/template/nextjs/package.json +25 -0
- package/template/nextjs/src/app/page.tsx +94 -0
- package/template/nextjs/src/app/providers.tsx +20 -0
- package/template/nuxt2/package.json +21 -0
- package/template/nuxt2/pages/index.vue +124 -0
- package/template/nuxt3/app.vue +116 -0
- package/template/nuxt3/package.json +22 -0
- package/template/nuxt4/app.vue +116 -0
- package/template/nuxt4/package.json +22 -0
- package/template/preact/package.json +22 -0
- package/template/preact/src/App.css +180 -0
- package/template/preact/src/App.tsx +98 -0
- package/template/qwik/package.json +22 -0
- package/template/qwik/src/App.tsx +104 -0
- package/template/react/package.json +19 -0
- package/template/react/src/App.css +180 -0
- package/template/react/src/App.tsx +85 -0
- package/template/riot/package.json +23 -0
- package/template/riot/src/app.riot +121 -0
- package/template/solid/package.json +18 -0
- package/template/solid/src/App.tsx +99 -0
- package/template/solid/src/index.css +180 -0
- package/template/solid/src/main.tsx +9 -0
- package/template/stencil/package.json +21 -0
- package/template/stencil/src/components/app-home/app-home.tsx +109 -0
- package/template/svelte/package.json +20 -0
- package/template/svelte/src/App.svelte +289 -0
- package/template/svelte/src/main.ts +12 -0
- package/template/vanilla/LICENSE +21 -0
- package/template/vue2/package.json +22 -0
- package/template/vue2/src/App.vue +273 -0
- package/template/vue3/package.json +19 -0
- package/template/vue3/src/App.vue +264 -0
- package/template/vue3/src/main.ts +14 -0
- package/template/webcomponents/package.json +21 -0
- package/template/webcomponents/src/main.ts +38 -0
- package/template/webcomponents/src/style.css +180 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
* {
|
|
2
|
+
margin: 0;
|
|
3
|
+
padding: 0;
|
|
4
|
+
box-sizing: border-box;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
html {
|
|
8
|
+
scroll-behavior: smooth;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
body {
|
|
12
|
+
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
|
13
|
+
color: #fff;
|
|
14
|
+
background: #0a0a1a;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
#navbar {
|
|
18
|
+
position: fixed;
|
|
19
|
+
top: 0;
|
|
20
|
+
width: 100%;
|
|
21
|
+
z-index: 100;
|
|
22
|
+
display: flex;
|
|
23
|
+
justify-content: center;
|
|
24
|
+
gap: 2rem;
|
|
25
|
+
padding: 1rem;
|
|
26
|
+
background: rgba(10, 10, 26, 0.8);
|
|
27
|
+
backdrop-filter: blur(10px);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.nav-link {
|
|
31
|
+
color: rgba(255, 255, 255, 0.7);
|
|
32
|
+
text-decoration: none;
|
|
33
|
+
font-size: 0.9em;
|
|
34
|
+
transition: color 0.2s;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.nav-link:hover {
|
|
38
|
+
color: #6c5ce7;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.section {
|
|
42
|
+
min-height: 100vh;
|
|
43
|
+
display: flex;
|
|
44
|
+
align-items: center;
|
|
45
|
+
justify-content: center;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
#hero {
|
|
49
|
+
position: relative;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.hero-content {
|
|
53
|
+
text-align: center;
|
|
54
|
+
z-index: 10;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.hero-content h1 {
|
|
58
|
+
font-size: 3.5em;
|
|
59
|
+
margin-bottom: 0.5rem;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.highlight {
|
|
63
|
+
color: #6c5ce7;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.subtitle {
|
|
67
|
+
font-size: 1.3em;
|
|
68
|
+
opacity: 0.7;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.content-section {
|
|
72
|
+
padding: 6rem 1rem;
|
|
73
|
+
min-height: auto;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.container {
|
|
77
|
+
max-width: 900px;
|
|
78
|
+
width: 100%;
|
|
79
|
+
margin: 0 auto;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
h2 {
|
|
83
|
+
font-size: 2.2em;
|
|
84
|
+
margin-bottom: 2rem;
|
|
85
|
+
color: #6c5ce7;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
p {
|
|
89
|
+
line-height: 1.7;
|
|
90
|
+
opacity: 0.85;
|
|
91
|
+
font-size: 1.1em;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.project-grid {
|
|
95
|
+
display: grid;
|
|
96
|
+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
97
|
+
gap: 1.5rem;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.project-card {
|
|
101
|
+
background: rgba(255, 255, 255, 0.05);
|
|
102
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
103
|
+
border-radius: 12px;
|
|
104
|
+
padding: 1.5rem;
|
|
105
|
+
transition: transform 0.2s, border-color 0.2s;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.project-card:hover {
|
|
109
|
+
transform: translateY(-4px);
|
|
110
|
+
border-color: #6c5ce7;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.project-card h3 {
|
|
114
|
+
margin-bottom: 0.5rem;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.skill-bar {
|
|
118
|
+
margin-bottom: 1.2rem;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.skill-name {
|
|
122
|
+
display: block;
|
|
123
|
+
margin-bottom: 0.3em;
|
|
124
|
+
font-size: 0.95em;
|
|
125
|
+
opacity: 0.8;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.bar {
|
|
129
|
+
height: 10px;
|
|
130
|
+
background: rgba(255, 255, 255, 0.1);
|
|
131
|
+
border-radius: 5px;
|
|
132
|
+
overflow: hidden;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.fill {
|
|
136
|
+
height: 100%;
|
|
137
|
+
background: linear-gradient(90deg, #6c5ce7, #a29bfe);
|
|
138
|
+
border-radius: 5px;
|
|
139
|
+
transition: width 1s ease;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
#contactForm {
|
|
143
|
+
display: flex;
|
|
144
|
+
flex-direction: column;
|
|
145
|
+
gap: 1rem;
|
|
146
|
+
max-width: 500px;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
#contactForm input,
|
|
150
|
+
#contactForm textarea {
|
|
151
|
+
padding: 0.8em 1em;
|
|
152
|
+
font-size: 1em;
|
|
153
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
154
|
+
border-radius: 8px;
|
|
155
|
+
background: rgba(255, 255, 255, 0.05);
|
|
156
|
+
color: #fff;
|
|
157
|
+
outline: none;
|
|
158
|
+
font-family: inherit;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
#contactForm input:focus,
|
|
162
|
+
#contactForm textarea:focus {
|
|
163
|
+
border-color: #6c5ce7;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
#contactForm button {
|
|
167
|
+
padding: 0.8em;
|
|
168
|
+
font-size: 1em;
|
|
169
|
+
font-weight: 600;
|
|
170
|
+
border: none;
|
|
171
|
+
border-radius: 8px;
|
|
172
|
+
background: #6c5ce7;
|
|
173
|
+
color: #fff;
|
|
174
|
+
cursor: pointer;
|
|
175
|
+
transition: background 0.2s;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
#contactForm button:hover {
|
|
179
|
+
background: #a29bfe;
|
|
180
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectName}}",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "{{version}}",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "next dev",
|
|
8
|
+
"build": "next build",
|
|
9
|
+
"preview": "next start"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@tsparticles/nextjs": "^4.1.3",
|
|
13
|
+
"@tsparticles/engine": "^4.0.0",
|
|
14
|
+
"@tsparticles/slim": "^4.0.0",
|
|
15
|
+
"@tsparticles/configs": "^4.0.0",
|
|
16
|
+
"next": "^15.0.0",
|
|
17
|
+
"react": "^19.2.5",
|
|
18
|
+
"react-dom": "^19.2.5"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/react": "^19.0.0",
|
|
22
|
+
"@types/react-dom": "^19.0.0",
|
|
23
|
+
"typescript": "~5.8.0"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import Particles from "@tsparticles/nextjs";
|
|
4
|
+
import configs from "@tsparticles/configs";
|
|
5
|
+
import type { ISourceOptions } from "@tsparticles/engine";
|
|
6
|
+
import { ParticlesProvider } from "./providers";
|
|
7
|
+
|
|
8
|
+
const keys = Object.keys(configs);
|
|
9
|
+
const randomKey = keys[Math.floor(Math.random() * keys.length)] as keyof typeof configs;
|
|
10
|
+
const options: ISourceOptions = {
|
|
11
|
+
...configs[randomKey],
|
|
12
|
+
fullScreen: { enable: true, zIndex: -1 },
|
|
13
|
+
} as ISourceOptions;
|
|
14
|
+
|
|
15
|
+
const navItems = ["Home", "About", "Projects", "Skills", "Contact"];
|
|
16
|
+
|
|
17
|
+
const projects = [
|
|
18
|
+
{ title: "Project One", desc: "A web application built with Next.js and TypeScript." },
|
|
19
|
+
{ title: "Project Two", desc: "Real-time dashboard with data visualization." },
|
|
20
|
+
{ title: "Project Three", desc: "Mobile-first e-commerce platform." },
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const skills = [
|
|
24
|
+
{ name: "TypeScript", pct: 90 },
|
|
25
|
+
{ name: "React", pct: 85 },
|
|
26
|
+
{ name: "Node.js", pct: 80 },
|
|
27
|
+
{ name: "CSS", pct: 88 },
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
export default function Home() {
|
|
31
|
+
function handleSubmit(e: React.FormEvent) {
|
|
32
|
+
e.preventDefault();
|
|
33
|
+
alert("Message sent! (demo)");
|
|
34
|
+
(e.target as HTMLFormElement).reset();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<ParticlesProvider>
|
|
39
|
+
<Particles id="tsparticles" options={options} />
|
|
40
|
+
<nav id="navbar">
|
|
41
|
+
{navItems.map((item) => (
|
|
42
|
+
<a key={item} href={`#${item.toLowerCase()}`} className="nav-link">{item}</a>
|
|
43
|
+
))}
|
|
44
|
+
</nav>
|
|
45
|
+
<section id="hero" className="section">
|
|
46
|
+
<div className="hero-content">
|
|
47
|
+
<h1>Hello, I'm <span className="highlight">Your Name</span></h1>
|
|
48
|
+
<p className="subtitle">Full-Stack Developer & Designer</p>
|
|
49
|
+
</div>
|
|
50
|
+
</section>
|
|
51
|
+
<section id="about" className="section content-section">
|
|
52
|
+
<div className="container">
|
|
53
|
+
<h2>About Me</h2>
|
|
54
|
+
<p>A passionate developer who loves building beautiful and performant web applications. Experienced in modern JavaScript frameworks, cloud infrastructure, and UI/UX design.</p>
|
|
55
|
+
</div>
|
|
56
|
+
</section>
|
|
57
|
+
<section id="projects" className="section content-section">
|
|
58
|
+
<div className="container">
|
|
59
|
+
<h2>Projects</h2>
|
|
60
|
+
<div className="project-grid">
|
|
61
|
+
{projects.map((p) => (
|
|
62
|
+
<div key={p.title} className="project-card">
|
|
63
|
+
<h3>{p.title}</h3>
|
|
64
|
+
<p>{p.desc}</p>
|
|
65
|
+
</div>
|
|
66
|
+
))}
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
</section>
|
|
70
|
+
<section id="skills" className="section content-section">
|
|
71
|
+
<div className="container">
|
|
72
|
+
<h2>Skills</h2>
|
|
73
|
+
{skills.map((s) => (
|
|
74
|
+
<div key={s.name} className="skill-bar">
|
|
75
|
+
<span className="skill-name">{s.name}</span>
|
|
76
|
+
<div className="bar"><div className="fill" style={{ width: `${s.pct}%` }}></div></div>
|
|
77
|
+
</div>
|
|
78
|
+
))}
|
|
79
|
+
</div>
|
|
80
|
+
</section>
|
|
81
|
+
<section id="contact" className="section content-section">
|
|
82
|
+
<div className="container">
|
|
83
|
+
<h2>Contact</h2>
|
|
84
|
+
<form id="contactForm" onSubmit={handleSubmit}>
|
|
85
|
+
<input type="text" placeholder="Your Name" required />
|
|
86
|
+
<input type="email" placeholder="Your Email" required />
|
|
87
|
+
<textarea placeholder="Your Message" rows={5} required></textarea>
|
|
88
|
+
<button type="submit">Send Message</button>
|
|
89
|
+
</form>
|
|
90
|
+
</div>
|
|
91
|
+
</section>
|
|
92
|
+
</ParticlesProvider>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { initParticlesEngine } from "@tsparticles/nextjs";
|
|
4
|
+
import { loadSlim } from "@tsparticles/slim";
|
|
5
|
+
import { useEffect, useRef } from "react";
|
|
6
|
+
|
|
7
|
+
export function ParticlesProvider({ children }: { children: React.ReactNode }) {
|
|
8
|
+
const initialized = useRef(false);
|
|
9
|
+
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (!initialized.current) {
|
|
12
|
+
initialized.current = true;
|
|
13
|
+
void initParticlesEngine(async (engine) => {
|
|
14
|
+
await loadSlim(engine);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}, []);
|
|
18
|
+
|
|
19
|
+
return <>{children}</>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectName}}",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "{{version}}",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "nuxt",
|
|
7
|
+
"build": "nuxt build",
|
|
8
|
+
"preview": "nuxt start"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@tsparticles/nuxt2": "^4.1.3",
|
|
12
|
+
"@tsparticles/engine": "^4.0.0",
|
|
13
|
+
"@tsparticles/slim": "^4.0.0",
|
|
14
|
+
"@tsparticles/configs": "^4.0.0",
|
|
15
|
+
"nuxt": "^2.18.0",
|
|
16
|
+
"vue": "^2.7.16"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"typescript": "~5.8.0"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<vue-particles id="tsparticles" :options="options" />
|
|
4
|
+
<nav id="navbar">
|
|
5
|
+
<a v-for="item in navItems" :key="item" :href="'#' + item.toLowerCase()" class="nav-link">{{ item }}</a>
|
|
6
|
+
</nav>
|
|
7
|
+
<section id="hero" class="section">
|
|
8
|
+
<div class="hero-content">
|
|
9
|
+
<h1>Hello, I'm <span class="highlight">Your Name</span></h1>
|
|
10
|
+
<p class="subtitle">Full-Stack Developer & Designer</p>
|
|
11
|
+
</div>
|
|
12
|
+
</section>
|
|
13
|
+
<section id="about" class="section content-section">
|
|
14
|
+
<div class="container">
|
|
15
|
+
<h2>About Me</h2>
|
|
16
|
+
<p>A passionate developer who loves building beautiful and performant web applications. Experienced in modern JavaScript frameworks, cloud infrastructure, and UI/UX design.</p>
|
|
17
|
+
</div>
|
|
18
|
+
</section>
|
|
19
|
+
<section id="projects" class="section content-section">
|
|
20
|
+
<div class="container">
|
|
21
|
+
<h2>Projects</h2>
|
|
22
|
+
<div class="project-grid">
|
|
23
|
+
<div v-for="p in projects" :key="p.title" class="project-card">
|
|
24
|
+
<h3>{{ p.title }}</h3>
|
|
25
|
+
<p>{{ p.desc }}</p>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</section>
|
|
30
|
+
<section id="skills" class="section content-section">
|
|
31
|
+
<div class="container">
|
|
32
|
+
<h2>Skills</h2>
|
|
33
|
+
<div v-for="s in skills" :key="s.name" class="skill-bar">
|
|
34
|
+
<span class="skill-name">{{ s.name }}</span>
|
|
35
|
+
<div class="bar"><div class="fill" :style="{ width: s.pct + '%' }"></div></div>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
</section>
|
|
39
|
+
<section id="contact" class="section content-section">
|
|
40
|
+
<div class="container">
|
|
41
|
+
<h2>Contact</h2>
|
|
42
|
+
<form id="contactForm" @submit="handleSubmit">
|
|
43
|
+
<input type="text" placeholder="Your Name" required />
|
|
44
|
+
<input type="email" placeholder="Your Email" required />
|
|
45
|
+
<textarea placeholder="Your Message" rows="5" required></textarea>
|
|
46
|
+
<button type="submit">Send Message</button>
|
|
47
|
+
</form>
|
|
48
|
+
</div>
|
|
49
|
+
</section>
|
|
50
|
+
</div>
|
|
51
|
+
</template>
|
|
52
|
+
|
|
53
|
+
<script lang="ts">
|
|
54
|
+
import Vue from "vue";
|
|
55
|
+
import configs from "@tsparticles/configs";
|
|
56
|
+
import type { ISourceOptions } from "@tsparticles/engine";
|
|
57
|
+
|
|
58
|
+
const keys = Object.keys(configs);
|
|
59
|
+
const randomKey = keys[Math.floor(Math.random() * keys.length)] as keyof typeof configs;
|
|
60
|
+
const options: ISourceOptions = {
|
|
61
|
+
...(configs[randomKey] as ISourceOptions),
|
|
62
|
+
fullScreen: { enable: true, zIndex: -1 },
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export default Vue.extend({
|
|
66
|
+
name: "IndexPage",
|
|
67
|
+
data() {
|
|
68
|
+
return {
|
|
69
|
+
options,
|
|
70
|
+
navItems: ["Home", "About", "Projects", "Skills", "Contact"],
|
|
71
|
+
projects: [
|
|
72
|
+
{ title: "Project One", desc: "A web application built with Nuxt 2 and TypeScript." },
|
|
73
|
+
{ title: "Project Two", desc: "Real-time dashboard with data visualization." },
|
|
74
|
+
{ title: "Project Three", desc: "Mobile-first e-commerce platform." },
|
|
75
|
+
],
|
|
76
|
+
skills: [
|
|
77
|
+
{ name: "TypeScript", pct: 90 },
|
|
78
|
+
{ name: "Nuxt 2", pct: 85 },
|
|
79
|
+
{ name: "Node.js", pct: 80 },
|
|
80
|
+
{ name: "CSS", pct: 88 },
|
|
81
|
+
],
|
|
82
|
+
};
|
|
83
|
+
},
|
|
84
|
+
methods: {
|
|
85
|
+
handleSubmit(e: Event) {
|
|
86
|
+
e.preventDefault();
|
|
87
|
+
alert("Message sent! (demo)");
|
|
88
|
+
(e.target as HTMLFormElement).reset();
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
</script>
|
|
93
|
+
|
|
94
|
+
<style scoped>
|
|
95
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
96
|
+
html { scroll-behavior: smooth; }
|
|
97
|
+
body { font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; color: #fff; background: #0a0a1a; }
|
|
98
|
+
#navbar { position: fixed; top: 0; width: 100%; z-index: 100; display: flex; justify-content: center; gap: 2rem; padding: 1rem; background: rgba(10,10,26,0.8); backdrop-filter: blur(10px); }
|
|
99
|
+
.nav-link { color: rgba(255,255,255,0.7); text-decoration: none; font-size: 0.9em; transition: color 0.2s; }
|
|
100
|
+
.nav-link:hover { color: #6c5ce7; }
|
|
101
|
+
.section { min-height: 100vh; display: flex; align-items: center; justify-content: center; }
|
|
102
|
+
#hero { position: relative; }
|
|
103
|
+
.hero-content { text-align: center; z-index: 10; }
|
|
104
|
+
.hero-content h1 { font-size: 3.5em; margin-bottom: 0.5rem; }
|
|
105
|
+
.highlight { color: #6c5ce7; }
|
|
106
|
+
.subtitle { font-size: 1.3em; opacity: 0.7; }
|
|
107
|
+
.content-section { padding: 6rem 1rem; min-height: auto; }
|
|
108
|
+
.container { max-width: 900px; width: 100%; margin: 0 auto; }
|
|
109
|
+
h2 { font-size: 2.2em; margin-bottom: 2rem; color: #6c5ce7; }
|
|
110
|
+
p { line-height: 1.7; opacity: 0.85; font-size: 1.1em; }
|
|
111
|
+
.project-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1.5rem; }
|
|
112
|
+
.project-card { background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.1); border-radius: 12px; padding: 1.5rem; transition: transform 0.2s, border-color 0.2s; }
|
|
113
|
+
.project-card:hover { transform: translateY(-4px); border-color: #6c5ce7; }
|
|
114
|
+
.project-card h3 { margin-bottom: 0.5rem; }
|
|
115
|
+
.skill-bar { margin-bottom: 1.2rem; }
|
|
116
|
+
.skill-name { display: block; margin-bottom: 0.3em; font-size: 0.95em; opacity: 0.8; }
|
|
117
|
+
.bar { height: 10px; background: rgba(255,255,255,0.1); border-radius: 5px; overflow: hidden; }
|
|
118
|
+
.fill { height: 100%; background: linear-gradient(90deg,#6c5ce7,#a29bfe); border-radius: 5px; transition: width 1s ease; }
|
|
119
|
+
#contactForm { display: flex; flex-direction: column; gap: 1rem; max-width: 500px; }
|
|
120
|
+
#contactForm input, #contactForm textarea { padding: 0.8em 1em; font-size: 1em; border: 1px solid rgba(255,255,255,0.1); border-radius: 8px; background: rgba(255,255,255,0.05); color: #fff; outline: none; font-family: inherit; }
|
|
121
|
+
#contactForm input:focus, #contactForm textarea:focus { border-color: #6c5ce7; }
|
|
122
|
+
#contactForm button { padding: 0.8em; font-size: 1em; font-weight: 600; border: none; border-radius: 8px; background: #6c5ce7; color: #fff; cursor: pointer; transition: background 0.2s; }
|
|
123
|
+
#contactForm button:hover { background: #a29bfe; }
|
|
124
|
+
</style>
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import configs from "@tsparticles/configs";
|
|
3
|
+
import type { ISourceOptions } from "@tsparticles/engine";
|
|
4
|
+
|
|
5
|
+
const keys = Object.keys(configs);
|
|
6
|
+
const randomKey = keys[Math.floor(Math.random() * keys.length)] as keyof typeof configs;
|
|
7
|
+
const options: ISourceOptions = {
|
|
8
|
+
...(configs[randomKey] as ISourceOptions),
|
|
9
|
+
fullScreen: { enable: true, zIndex: -1 },
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const navItems = ["Home", "About", "Projects", "Skills", "Contact"];
|
|
13
|
+
|
|
14
|
+
const projects = [
|
|
15
|
+
{ title: "Project One", desc: "A web application built with Nuxt 3 and TypeScript." },
|
|
16
|
+
{ title: "Project Two", desc: "Real-time dashboard with data visualization." },
|
|
17
|
+
{ title: "Project Three", desc: "Mobile-first e-commerce platform." },
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const skills = [
|
|
21
|
+
{ name: "TypeScript", pct: 90 },
|
|
22
|
+
{ name: "Nuxt 3", pct: 85 },
|
|
23
|
+
{ name: "Node.js", pct: 80 },
|
|
24
|
+
{ name: "CSS", pct: 88 },
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
function handleSubmit(e: Event) {
|
|
28
|
+
e.preventDefault();
|
|
29
|
+
alert("Message sent! (demo)");
|
|
30
|
+
(e.target as HTMLFormElement).reset();
|
|
31
|
+
}
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<template>
|
|
35
|
+
<div>
|
|
36
|
+
<vue-particles id="tsparticles" :options="options" />
|
|
37
|
+
<nav id="navbar">
|
|
38
|
+
<a v-for="item in navItems" :key="item" :href="'#' + item.toLowerCase()" class="nav-link">{{ item }}</a>
|
|
39
|
+
</nav>
|
|
40
|
+
<section id="hero" class="section">
|
|
41
|
+
<div class="hero-content">
|
|
42
|
+
<h1>Hello, I'm <span class="highlight">Your Name</span></h1>
|
|
43
|
+
<p class="subtitle">Full-Stack Developer & Designer</p>
|
|
44
|
+
</div>
|
|
45
|
+
</section>
|
|
46
|
+
<section id="about" class="section content-section">
|
|
47
|
+
<div class="container">
|
|
48
|
+
<h2>About Me</h2>
|
|
49
|
+
<p>A passionate developer who loves building beautiful and performant web applications. Experienced in modern JavaScript frameworks, cloud infrastructure, and UI/UX design.</p>
|
|
50
|
+
</div>
|
|
51
|
+
</section>
|
|
52
|
+
<section id="projects" class="section content-section">
|
|
53
|
+
<div class="container">
|
|
54
|
+
<h2>Projects</h2>
|
|
55
|
+
<div class="project-grid">
|
|
56
|
+
<div v-for="p in projects" :key="p.title" class="project-card">
|
|
57
|
+
<h3>{{ p.title }}</h3>
|
|
58
|
+
<p>{{ p.desc }}</p>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</section>
|
|
63
|
+
<section id="skills" class="section content-section">
|
|
64
|
+
<div class="container">
|
|
65
|
+
<h2>Skills</h2>
|
|
66
|
+
<div v-for="s in skills" :key="s.name" class="skill-bar">
|
|
67
|
+
<span class="skill-name">{{ s.name }}</span>
|
|
68
|
+
<div class="bar"><div class="fill" :style="{ width: s.pct + '%' }"></div></div>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
</section>
|
|
72
|
+
<section id="contact" class="section content-section">
|
|
73
|
+
<div class="container">
|
|
74
|
+
<h2>Contact</h2>
|
|
75
|
+
<form id="contactForm" @submit="handleSubmit">
|
|
76
|
+
<input type="text" placeholder="Your Name" required />
|
|
77
|
+
<input type="email" placeholder="Your Email" required />
|
|
78
|
+
<textarea placeholder="Your Message" rows="5" required></textarea>
|
|
79
|
+
<button type="submit">Send Message</button>
|
|
80
|
+
</form>
|
|
81
|
+
</div>
|
|
82
|
+
</section>
|
|
83
|
+
</div>
|
|
84
|
+
</template>
|
|
85
|
+
|
|
86
|
+
<style>
|
|
87
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
88
|
+
html { scroll-behavior: smooth; }
|
|
89
|
+
body { font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; color: #fff; background: #0a0a1a; }
|
|
90
|
+
#navbar { position: fixed; top: 0; width: 100%; z-index: 100; display: flex; justify-content: center; gap: 2rem; padding: 1rem; background: rgba(10,10,26,0.8); backdrop-filter: blur(10px); }
|
|
91
|
+
.nav-link { color: rgba(255,255,255,0.7); text-decoration: none; font-size: 0.9em; transition: color 0.2s; }
|
|
92
|
+
.nav-link:hover { color: #6c5ce7; }
|
|
93
|
+
.section { min-height: 100vh; display: flex; align-items: center; justify-content: center; }
|
|
94
|
+
#hero { position: relative; }
|
|
95
|
+
.hero-content { text-align: center; z-index: 10; }
|
|
96
|
+
.hero-content h1 { font-size: 3.5em; margin-bottom: 0.5rem; }
|
|
97
|
+
.highlight { color: #6c5ce7; }
|
|
98
|
+
.subtitle { font-size: 1.3em; opacity: 0.7; }
|
|
99
|
+
.content-section { padding: 6rem 1rem; min-height: auto; }
|
|
100
|
+
.container { max-width: 900px; width: 100%; margin: 0 auto; }
|
|
101
|
+
h2 { font-size: 2.2em; margin-bottom: 2rem; color: #6c5ce7; }
|
|
102
|
+
p { line-height: 1.7; opacity: 0.85; font-size: 1.1em; }
|
|
103
|
+
.project-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1.5rem; }
|
|
104
|
+
.project-card { background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.1); border-radius: 12px; padding: 1.5rem; transition: transform 0.2s, border-color 0.2s; }
|
|
105
|
+
.project-card:hover { transform: translateY(-4px); border-color: #6c5ce7; }
|
|
106
|
+
.project-card h3 { margin-bottom: 0.5rem; }
|
|
107
|
+
.skill-bar { margin-bottom: 1.2rem; }
|
|
108
|
+
.skill-name { display: block; margin-bottom: 0.3em; font-size: 0.95em; opacity: 0.8; }
|
|
109
|
+
.bar { height: 10px; background: rgba(255,255,255,0.1); border-radius: 5px; overflow: hidden; }
|
|
110
|
+
.fill { height: 100%; background: linear-gradient(90deg,#6c5ce7,#a29bfe); border-radius: 5px; transition: width 1s ease; }
|
|
111
|
+
#contactForm { display: flex; flex-direction: column; gap: 1rem; max-width: 500px; }
|
|
112
|
+
#contactForm input, #contactForm textarea { padding: 0.8em 1em; font-size: 1em; border: 1px solid rgba(255,255,255,0.1); border-radius: 8px; background: rgba(255,255,255,0.05); color: #fff; outline: none; font-family: inherit; }
|
|
113
|
+
#contactForm input:focus, #contactForm textarea:focus { border-color: #6c5ce7; }
|
|
114
|
+
#contactForm button { padding: 0.8em; font-size: 1em; font-weight: 600; border: none; border-radius: 8px; background: #6c5ce7; color: #fff; cursor: pointer; transition: background 0.2s; }
|
|
115
|
+
#contactForm button:hover { background: #a29bfe; }
|
|
116
|
+
</style>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectName}}",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "{{version}}",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "nuxt dev",
|
|
8
|
+
"build": "nuxt build",
|
|
9
|
+
"preview": "nuxt preview"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@tsparticles/nuxt3": "^4.1.3",
|
|
13
|
+
"@tsparticles/engine": "^4.0.0",
|
|
14
|
+
"@tsparticles/slim": "^4.0.0",
|
|
15
|
+
"@tsparticles/configs": "^4.0.0",
|
|
16
|
+
"nuxt": "^3.16.0",
|
|
17
|
+
"vue": "^3.5.0"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"typescript": "~5.8.0"
|
|
21
|
+
}
|
|
22
|
+
}
|