@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,85 @@
|
|
|
1
|
+
import Particles, { ParticlesProvider } from "@tsparticles/react";
|
|
2
|
+
import { loadSlim } from "@tsparticles/slim";
|
|
3
|
+
import configs from "@tsparticles/configs";
|
|
4
|
+
import type { Engine, ISourceOptions } from "@tsparticles/engine";
|
|
5
|
+
import "./App.css";
|
|
6
|
+
|
|
7
|
+
async function init(engine: Engine): Promise<void> {
|
|
8
|
+
await loadSlim(engine);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const keys = Object.keys(configs);
|
|
12
|
+
const randomKey = keys[Math.floor(Math.random() * keys.length)] as keyof typeof configs;
|
|
13
|
+
const options: ISourceOptions = {
|
|
14
|
+
...configs[randomKey],
|
|
15
|
+
fullScreen: { enable: true, zIndex: -1 },
|
|
16
|
+
} as ISourceOptions;
|
|
17
|
+
|
|
18
|
+
export default function App() {
|
|
19
|
+
function handleSubmit(e: React.FormEvent) {
|
|
20
|
+
e.preventDefault();
|
|
21
|
+
alert("Message sent! (demo)");
|
|
22
|
+
(e.target as HTMLFormElement).reset();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<ParticlesProvider init={init}>
|
|
27
|
+
<Particles id="tsparticles" options={options} />
|
|
28
|
+
<nav id="navbar">
|
|
29
|
+
{["Home", "About", "Projects", "Skills", "Contact"].map((item) => (
|
|
30
|
+
<a key={item} href={`#${item.toLowerCase()}`} className="nav-link">{item}</a>
|
|
31
|
+
))}
|
|
32
|
+
</nav>
|
|
33
|
+
<section id="hero" className="section">
|
|
34
|
+
<div className="hero-content">
|
|
35
|
+
<h1>Hello, I'm <span className="highlight">Your Name</span></h1>
|
|
36
|
+
<p className="subtitle">Full-Stack Developer & Designer</p>
|
|
37
|
+
</div>
|
|
38
|
+
</section>
|
|
39
|
+
<section id="about" className="section content-section">
|
|
40
|
+
<div className="container">
|
|
41
|
+
<h2>About Me</h2>
|
|
42
|
+
<p>A passionate developer who loves building beautiful and performant web applications. Experienced in modern JavaScript frameworks, cloud infrastructure, and UI/UX design.</p>
|
|
43
|
+
</div>
|
|
44
|
+
</section>
|
|
45
|
+
<section id="projects" className="section content-section">
|
|
46
|
+
<div className="container">
|
|
47
|
+
<h2>Projects</h2>
|
|
48
|
+
<div className="project-grid">
|
|
49
|
+
{[{ title: "Project One", desc: "A web application built with React and TypeScript." },
|
|
50
|
+
{ title: "Project Two", desc: "Real-time dashboard with data visualization." },
|
|
51
|
+
{ title: "Project Three", desc: "Mobile-first e-commerce platform." }
|
|
52
|
+
].map((p, i) => (
|
|
53
|
+
<div key={i} className="project-card">
|
|
54
|
+
<h3>{p.title}</h3>
|
|
55
|
+
<p>{p.desc}</p>
|
|
56
|
+
</div>
|
|
57
|
+
))}
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
</section>
|
|
61
|
+
<section id="skills" className="section content-section">
|
|
62
|
+
<div className="container">
|
|
63
|
+
<h2>Skills</h2>
|
|
64
|
+
{[{ name: "TypeScript", pct: 90 }, { name: "React", pct: 85 }, { name: "Node.js", pct: 80 }, { name: "CSS", pct: 88 }].map((s, i) => (
|
|
65
|
+
<div key={i} className="skill-bar">
|
|
66
|
+
<span className="skill-name">{s.name}</span>
|
|
67
|
+
<div className="bar"><div className="fill" style={{ width: `${s.pct}%` }}></div></div>
|
|
68
|
+
</div>
|
|
69
|
+
))}
|
|
70
|
+
</div>
|
|
71
|
+
</section>
|
|
72
|
+
<section id="contact" className="section content-section">
|
|
73
|
+
<div className="container">
|
|
74
|
+
<h2>Contact</h2>
|
|
75
|
+
<form id="contactForm" onSubmit={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
|
+
</ParticlesProvider>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectName}}",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "{{version}}",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "vite build",
|
|
9
|
+
"preview": "vite preview"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@tsparticles/riot": "^4.1.3",
|
|
13
|
+
"@tsparticles/engine": "^4.0.0",
|
|
14
|
+
"@tsparticles/slim": "^4.0.0",
|
|
15
|
+
"@tsparticles/configs": "^4.0.0",
|
|
16
|
+
"riot": "^9.5.0"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@riotjs/vite": "^9.2.0",
|
|
20
|
+
"typescript": "~5.8.0",
|
|
21
|
+
"vite": "^7.0.0"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
<app>
|
|
2
|
+
<vue-particles id="tsparticles" :options="state.options" />
|
|
3
|
+
|
|
4
|
+
<nav id="navbar">
|
|
5
|
+
<a each="{ item in state.navItems }" href="#{ item.toLowerCase() }" class="nav-link">{ item }</a>
|
|
6
|
+
</nav>
|
|
7
|
+
|
|
8
|
+
<section id="hero" class="section">
|
|
9
|
+
<div class="hero-content">
|
|
10
|
+
<h1>Hello, I'm <span class="highlight">Your Name</span></h1>
|
|
11
|
+
<p class="subtitle">Full-Stack Developer & Designer</p>
|
|
12
|
+
</div>
|
|
13
|
+
</section>
|
|
14
|
+
|
|
15
|
+
<section id="about" class="section content-section">
|
|
16
|
+
<div class="container">
|
|
17
|
+
<h2>About Me</h2>
|
|
18
|
+
<p>A passionate developer who loves building beautiful and performant web applications. Experienced in modern JavaScript frameworks, cloud infrastructure, and UI/UX design.</p>
|
|
19
|
+
</div>
|
|
20
|
+
</section>
|
|
21
|
+
|
|
22
|
+
<section id="projects" class="section content-section">
|
|
23
|
+
<div class="container">
|
|
24
|
+
<h2>Projects</h2>
|
|
25
|
+
<div class="project-grid">
|
|
26
|
+
<div each="{ p in state.projects }" class="project-card">
|
|
27
|
+
<h3>{ p.title }</h3>
|
|
28
|
+
<p>{ p.desc }</p>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
</section>
|
|
33
|
+
|
|
34
|
+
<section id="skills" class="section content-section">
|
|
35
|
+
<div class="container">
|
|
36
|
+
<h2>Skills</h2>
|
|
37
|
+
<div each="{ s in state.skills }" class="skill-bar">
|
|
38
|
+
<span class="skill-name">{ s.name }</span>
|
|
39
|
+
<div class="bar"><div class="fill" style="width: { s.pct }%"></div></div>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</section>
|
|
43
|
+
|
|
44
|
+
<section id="contact" class="section content-section">
|
|
45
|
+
<div class="container">
|
|
46
|
+
<h2>Contact</h2>
|
|
47
|
+
<form id="contactForm" onsubmit="{ handleSubmit }">
|
|
48
|
+
<input type="text" placeholder="Your Name" required />
|
|
49
|
+
<input type="email" placeholder="Your Email" required />
|
|
50
|
+
<textarea placeholder="Your Message" rows="5" required></textarea>
|
|
51
|
+
<button type="submit">Send Message</button>
|
|
52
|
+
</form>
|
|
53
|
+
</div>
|
|
54
|
+
</section>
|
|
55
|
+
|
|
56
|
+
<script>
|
|
57
|
+
import configs from "@tsparticles/configs";
|
|
58
|
+
import type { ISourceOptions } from "@tsparticles/engine";
|
|
59
|
+
|
|
60
|
+
const keys = Object.keys(configs);
|
|
61
|
+
const randomKey = keys[Math.floor(Math.random() * keys.length)];
|
|
62
|
+
|
|
63
|
+
export default {
|
|
64
|
+
state: {
|
|
65
|
+
options: {
|
|
66
|
+
...configs[randomKey],
|
|
67
|
+
fullScreen: { enable: true, zIndex: -1 },
|
|
68
|
+
},
|
|
69
|
+
navItems: ["Home", "About", "Projects", "Skills", "Contact"],
|
|
70
|
+
projects: [
|
|
71
|
+
{ title: "Project One", desc: "A web application built with Riot and TypeScript." },
|
|
72
|
+
{ title: "Project Two", desc: "Real-time dashboard with data visualization." },
|
|
73
|
+
{ title: "Project Three", desc: "Mobile-first e-commerce platform." },
|
|
74
|
+
],
|
|
75
|
+
skills: [
|
|
76
|
+
{ name: "TypeScript", pct: 90 },
|
|
77
|
+
{ name: "Riot", pct: 85 },
|
|
78
|
+
{ name: "Node.js", pct: 80 },
|
|
79
|
+
{ name: "CSS", pct: 88 },
|
|
80
|
+
],
|
|
81
|
+
},
|
|
82
|
+
handleSubmit(e) {
|
|
83
|
+
e.preventDefault();
|
|
84
|
+
alert("Message sent! (demo)");
|
|
85
|
+
e.target.reset();
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
</script>
|
|
89
|
+
|
|
90
|
+
<style>
|
|
91
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
92
|
+
html { scroll-behavior: smooth; }
|
|
93
|
+
body { font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; color: #fff; background: #0a0a1a; }
|
|
94
|
+
#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); }
|
|
95
|
+
.nav-link { color: rgba(255, 255, 255, 0.7); text-decoration: none; font-size: 0.9em; transition: color 0.2s; }
|
|
96
|
+
.nav-link:hover { color: #6c5ce7; }
|
|
97
|
+
.section { min-height: 100vh; display: flex; align-items: center; justify-content: center; }
|
|
98
|
+
#hero { position: relative; }
|
|
99
|
+
.hero-content { text-align: center; z-index: 10; }
|
|
100
|
+
.hero-content h1 { font-size: 3.5em; margin-bottom: 0.5rem; }
|
|
101
|
+
.highlight { color: #6c5ce7; }
|
|
102
|
+
.subtitle { font-size: 1.3em; opacity: 0.7; }
|
|
103
|
+
.content-section { padding: 6rem 1rem; min-height: auto; }
|
|
104
|
+
.container { max-width: 900px; width: 100%; margin: 0 auto; }
|
|
105
|
+
h2 { font-size: 2.2em; margin-bottom: 2rem; color: #6c5ce7; }
|
|
106
|
+
p { line-height: 1.7; opacity: 0.85; font-size: 1.1em; }
|
|
107
|
+
.project-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1.5rem; }
|
|
108
|
+
.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; }
|
|
109
|
+
.project-card:hover { transform: translateY(-4px); border-color: #6c5ce7; }
|
|
110
|
+
.project-card h3 { margin-bottom: 0.5rem; }
|
|
111
|
+
.skill-bar { margin-bottom: 1.2rem; }
|
|
112
|
+
.skill-name { display: block; margin-bottom: 0.3em; font-size: 0.95em; opacity: 0.8; }
|
|
113
|
+
.bar { height: 10px; background: rgba(255, 255, 255, 0.1); border-radius: 5px; overflow: hidden; }
|
|
114
|
+
.fill { height: 100%; background: linear-gradient(90deg, #6c5ce7, #a29bfe); border-radius: 5px; transition: width 1s ease; }
|
|
115
|
+
#contactForm { display: flex; flex-direction: column; gap: 1rem; max-width: 500px; }
|
|
116
|
+
#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; }
|
|
117
|
+
#contactForm input:focus, #contactForm textarea:focus { border-color: #6c5ce7; }
|
|
118
|
+
#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; }
|
|
119
|
+
#contactForm button:hover { background: #a29bfe; }
|
|
120
|
+
</style>
|
|
121
|
+
</app>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectName}}",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "tsc && vite build",
|
|
9
|
+
"preview": "vite preview"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"solid-js": "^1.8.11",
|
|
13
|
+
"@tsparticles/solid": "^4.1.3"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"vite-plugin-solid": "^2.8.2"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { onMount } from "solid-js";
|
|
2
|
+
import Particles, { initParticlesEngine } from "@tsparticles/solid";
|
|
3
|
+
import { loadSlim } from "@tsparticles/slim";
|
|
4
|
+
import configs from "@tsparticles/configs";
|
|
5
|
+
import type { ISourceOptions } from "@tsparticles/engine";
|
|
6
|
+
|
|
7
|
+
export default function App() {
|
|
8
|
+
onMount(() => {
|
|
9
|
+
void initParticlesEngine(async (engine) => {
|
|
10
|
+
await loadSlim(engine);
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const keys = Object.keys(configs);
|
|
15
|
+
const randomKey = keys[Math.floor(Math.random() * keys.length)] as keyof typeof configs;
|
|
16
|
+
const presetConfig = configs[randomKey] as Record<string, unknown>;
|
|
17
|
+
|
|
18
|
+
const options: ISourceOptions = {
|
|
19
|
+
...presetConfig,
|
|
20
|
+
fullScreen: { enable: true, zIndex: -1 },
|
|
21
|
+
} as ISourceOptions;
|
|
22
|
+
|
|
23
|
+
function handleSubmit(e: Event) {
|
|
24
|
+
e.preventDefault();
|
|
25
|
+
alert("Message sent! (demo)");
|
|
26
|
+
const form = e.target as HTMLFormElement;
|
|
27
|
+
form.reset();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<>
|
|
32
|
+
<nav id="navbar">
|
|
33
|
+
<a href="#hero" class="nav-link">Home</a>
|
|
34
|
+
<a href="#about" class="nav-link">About</a>
|
|
35
|
+
<a href="#projects" class="nav-link">Projects</a>
|
|
36
|
+
<a href="#skills" class="nav-link">Skills</a>
|
|
37
|
+
<a href="#contact" class="nav-link">Contact</a>
|
|
38
|
+
</nav>
|
|
39
|
+
|
|
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
|
+
|
|
47
|
+
<section id="about" class="section content-section">
|
|
48
|
+
<div class="container">
|
|
49
|
+
<h2>About Me</h2>
|
|
50
|
+
<p>A passionate developer who loves building beautiful and performant web applications. Experienced in modern JavaScript frameworks, cloud infrastructure, and UI/UX design.</p>
|
|
51
|
+
</div>
|
|
52
|
+
</section>
|
|
53
|
+
|
|
54
|
+
<section id="projects" class="section content-section">
|
|
55
|
+
<div class="container">
|
|
56
|
+
<h2>Projects</h2>
|
|
57
|
+
<div class="project-grid">
|
|
58
|
+
<div class="project-card">
|
|
59
|
+
<h3>Project One</h3>
|
|
60
|
+
<p>A web application built with React and TypeScript.</p>
|
|
61
|
+
</div>
|
|
62
|
+
<div class="project-card">
|
|
63
|
+
<h3>Project Two</h3>
|
|
64
|
+
<p>Real-time dashboard with data visualization.</p>
|
|
65
|
+
</div>
|
|
66
|
+
<div class="project-card">
|
|
67
|
+
<h3>Project Three</h3>
|
|
68
|
+
<p>Mobile-first e-commerce platform.</p>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
</section>
|
|
73
|
+
|
|
74
|
+
<section id="skills" class="section content-section">
|
|
75
|
+
<div class="container">
|
|
76
|
+
<h2>Skills</h2>
|
|
77
|
+
<div class="skill-bar"><span class="skill-name">TypeScript</span><div class="bar"><div class="fill" style="width: 90%"></div></div></div>
|
|
78
|
+
<div class="skill-bar"><span class="skill-name">React</span><div class="bar"><div class="fill" style="width: 85%"></div></div></div>
|
|
79
|
+
<div class="skill-bar"><span class="skill-name">Node.js</span><div class="bar"><div class="fill" style="width: 80%"></div></div></div>
|
|
80
|
+
<div class="skill-bar"><span class="skill-name">CSS</span><div class="bar"><div class="fill" style="width: 88%"></div></div></div>
|
|
81
|
+
</div>
|
|
82
|
+
</section>
|
|
83
|
+
|
|
84
|
+
<section id="contact" class="section content-section">
|
|
85
|
+
<div class="container">
|
|
86
|
+
<h2>Contact</h2>
|
|
87
|
+
<form id="contactForm" onSubmit={handleSubmit}>
|
|
88
|
+
<input type="text" placeholder="Your Name" required />
|
|
89
|
+
<input type="email" placeholder="Your Email" required />
|
|
90
|
+
<textarea placeholder="Your Message" rows={5} required></textarea>
|
|
91
|
+
<button type="submit">Send Message</button>
|
|
92
|
+
</form>
|
|
93
|
+
</div>
|
|
94
|
+
</section>
|
|
95
|
+
|
|
96
|
+
<Particles id="tsparticles" options={options} />
|
|
97
|
+
</>
|
|
98
|
+
);
|
|
99
|
+
}
|