@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,100 @@
|
|
|
1
|
+
import { Component } from "inferno";
|
|
2
|
+
import Particles, { initParticlesEngine } from "@tsparticles/inferno";
|
|
3
|
+
import { loadSlim } from "@tsparticles/slim";
|
|
4
|
+
import configs from "@tsparticles/configs";
|
|
5
|
+
import type { ISourceOptions } from "@tsparticles/engine";
|
|
6
|
+
import "./App.css";
|
|
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
|
+
initParticlesEngine(async (engine) => {
|
|
16
|
+
await loadSlim(engine);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const navItems = ["Home", "About", "Projects", "Skills", "Contact"];
|
|
20
|
+
|
|
21
|
+
const projects = [
|
|
22
|
+
{ title: "Project One", desc: "A web application built with Inferno and TypeScript." },
|
|
23
|
+
{ title: "Project Two", desc: "Real-time dashboard with data visualization." },
|
|
24
|
+
{ title: "Project Three", desc: "Mobile-first e-commerce platform." },
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
const skills = [
|
|
28
|
+
{ name: "TypeScript", pct: 90 },
|
|
29
|
+
{ name: "Inferno", pct: 85 },
|
|
30
|
+
{ name: "Node.js", pct: 80 },
|
|
31
|
+
{ name: "CSS", pct: 88 },
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
export default class App extends Component {
|
|
35
|
+
handleSubmit(e: Event) {
|
|
36
|
+
e.preventDefault();
|
|
37
|
+
alert("Message sent! (demo)");
|
|
38
|
+
(e.target as HTMLFormElement).reset();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
render() {
|
|
42
|
+
return (
|
|
43
|
+
<div>
|
|
44
|
+
<Particles id="tsparticles" options={options} />
|
|
45
|
+
<nav id="navbar">
|
|
46
|
+
{navItems.map((item) => (
|
|
47
|
+
<a href={`#${item.toLowerCase()}`} className="nav-link">{item}</a>
|
|
48
|
+
))}
|
|
49
|
+
</nav>
|
|
50
|
+
<section id="hero" className="section">
|
|
51
|
+
<div className="hero-content">
|
|
52
|
+
<h1>Hello, I'm <span className="highlight">Your Name</span></h1>
|
|
53
|
+
<p className="subtitle">Full-Stack Developer & Designer</p>
|
|
54
|
+
</div>
|
|
55
|
+
</section>
|
|
56
|
+
<section id="about" className="section content-section">
|
|
57
|
+
<div className="container">
|
|
58
|
+
<h2>About Me</h2>
|
|
59
|
+
<p>A passionate developer who loves building beautiful and performant web applications. Experienced in modern JavaScript frameworks, cloud infrastructure, and UI/UX design.</p>
|
|
60
|
+
</div>
|
|
61
|
+
</section>
|
|
62
|
+
<section id="projects" className="section content-section">
|
|
63
|
+
<div className="container">
|
|
64
|
+
<h2>Projects</h2>
|
|
65
|
+
<div className="project-grid">
|
|
66
|
+
{projects.map((p) => (
|
|
67
|
+
<div className="project-card">
|
|
68
|
+
<h3>{p.title}</h3>
|
|
69
|
+
<p>{p.desc}</p>
|
|
70
|
+
</div>
|
|
71
|
+
))}
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</section>
|
|
75
|
+
<section id="skills" className="section content-section">
|
|
76
|
+
<div className="container">
|
|
77
|
+
<h2>Skills</h2>
|
|
78
|
+
{skills.map((s) => (
|
|
79
|
+
<div className="skill-bar">
|
|
80
|
+
<span className="skill-name">{s.name}</span>
|
|
81
|
+
<div className="bar"><div className="fill" style={{ width: `${s.pct}%` }}></div></div>
|
|
82
|
+
</div>
|
|
83
|
+
))}
|
|
84
|
+
</div>
|
|
85
|
+
</section>
|
|
86
|
+
<section id="contact" className="section content-section">
|
|
87
|
+
<div className="container">
|
|
88
|
+
<h2>Contact</h2>
|
|
89
|
+
<form id="contactForm" onSubmit={this.handleSubmit}>
|
|
90
|
+
<input type="text" placeholder="Your Name" required />
|
|
91
|
+
<input type="email" placeholder="Your Email" required />
|
|
92
|
+
<textarea placeholder="Your Message" rows={5} required></textarea>
|
|
93
|
+
<button type="submit">Send Message</button>
|
|
94
|
+
</form>
|
|
95
|
+
</div>
|
|
96
|
+
</section>
|
|
97
|
+
</div>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectName}}",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "{{version}}",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "tsc && vite build",
|
|
9
|
+
"preview": "vite preview"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@tsparticles/jquery": "^4.1.3",
|
|
13
|
+
"@tsparticles/engine": "^4.0.0",
|
|
14
|
+
"@tsparticles/slim": "^4.0.0",
|
|
15
|
+
"@tsparticles/configs": "^4.0.0",
|
|
16
|
+
"jquery": "^3.7.1"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@types/jquery": "^3.5.30",
|
|
20
|
+
"typescript": "~5.8.0",
|
|
21
|
+
"vite": "^7.0.0"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import "./style.css";
|
|
2
|
+
import $ from "jquery";
|
|
3
|
+
import "jquery-particles";
|
|
4
|
+
import { loadSlim } from "@tsparticles/slim";
|
|
5
|
+
import configs from "@tsparticles/configs";
|
|
6
|
+
import { tsParticles } from "@tsparticles/engine";
|
|
7
|
+
|
|
8
|
+
(async () => {
|
|
9
|
+
await loadSlim(tsParticles);
|
|
10
|
+
|
|
11
|
+
const keys = Object.keys(configs);
|
|
12
|
+
const randomKey = keys[Math.floor(Math.random() * keys.length)] as keyof typeof configs;
|
|
13
|
+
|
|
14
|
+
$("#tsparticles").particles().ajax({
|
|
15
|
+
...configs[randomKey],
|
|
16
|
+
fullScreen: { enable: true, zIndex: -1 },
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
$(".nav-link").on("click", function (e) {
|
|
20
|
+
e.preventDefault();
|
|
21
|
+
const target = $($(this).attr("href")!);
|
|
22
|
+
if (target.length) {
|
|
23
|
+
$("html, body").animate({ scrollTop: target.offset()!.top }, 500);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const contactForm = document.getElementById("contactForm") as HTMLFormElement;
|
|
28
|
+
contactForm.addEventListener("submit", (e) => {
|
|
29
|
+
e.preventDefault();
|
|
30
|
+
alert("Message sent! (demo)");
|
|
31
|
+
contactForm.reset();
|
|
32
|
+
});
|
|
33
|
+
})();
|
|
@@ -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,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectName}}",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "{{version}}",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "tsc && vite build",
|
|
9
|
+
"preview": "vite preview"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@tsparticles/lit": "^4.1.3",
|
|
13
|
+
"@tsparticles/engine": "^4.0.0",
|
|
14
|
+
"@tsparticles/slim": "^4.0.0",
|
|
15
|
+
"@tsparticles/configs": "^4.0.0",
|
|
16
|
+
"lit": "^3.4.0"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"typescript": "~5.8.0",
|
|
20
|
+
"vite": "^7.0.0"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { LitElement, html } from "lit";
|
|
2
|
+
import { customElement, state } from "lit/decorators.js";
|
|
3
|
+
import { ParticlesBase } from "@tsparticles/lit";
|
|
4
|
+
import { loadSlim } from "@tsparticles/slim";
|
|
5
|
+
import configs from "@tsparticles/configs";
|
|
6
|
+
import type { ISourceOptions } from "@tsparticles/engine";
|
|
7
|
+
import style from "./style.css" with { type: "css" };
|
|
8
|
+
|
|
9
|
+
const keys = Object.keys(configs);
|
|
10
|
+
const randomKey = keys[Math.floor(Math.random() * keys.length)] as keyof typeof configs;
|
|
11
|
+
const options: ISourceOptions = {
|
|
12
|
+
...configs[randomKey],
|
|
13
|
+
fullScreen: { enable: true, zIndex: -1 },
|
|
14
|
+
} as ISourceOptions;
|
|
15
|
+
|
|
16
|
+
@customElement("my-app")
|
|
17
|
+
export class MyApp extends LitElement {
|
|
18
|
+
static styles = [style];
|
|
19
|
+
|
|
20
|
+
@state()
|
|
21
|
+
private projects = [
|
|
22
|
+
{ title: "Project One", desc: "A web application built with Lit and TypeScript." },
|
|
23
|
+
{ title: "Project Two", desc: "Real-time dashboard with data visualization." },
|
|
24
|
+
{ title: "Project Three", desc: "Mobile-first e-commerce platform." },
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
@state()
|
|
28
|
+
private skills = [
|
|
29
|
+
{ name: "TypeScript", pct: 90 },
|
|
30
|
+
{ name: "Lit", pct: 85 },
|
|
31
|
+
{ name: "Node.js", pct: 80 },
|
|
32
|
+
{ name: "CSS", pct: 88 },
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
private navItems = ["Home", "About", "Projects", "Skills", "Contact"];
|
|
36
|
+
|
|
37
|
+
connectedCallback(): void {
|
|
38
|
+
super.connectedCallback();
|
|
39
|
+
void ParticlesBase.init(async (engine) => {
|
|
40
|
+
await loadSlim(engine);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private handleSubmit(e: Event): void {
|
|
45
|
+
e.preventDefault();
|
|
46
|
+
alert("Message sent! (demo)");
|
|
47
|
+
(e.target as HTMLFormElement).reset();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
render() {
|
|
51
|
+
return html`
|
|
52
|
+
<lit-particles id="tsparticles" .options=${options}></lit-particles>
|
|
53
|
+
|
|
54
|
+
<nav id="navbar">
|
|
55
|
+
${this.navItems.map(
|
|
56
|
+
(item) => html`<a href="#${item.toLowerCase()}" class="nav-link">${item}</a>`
|
|
57
|
+
)}
|
|
58
|
+
</nav>
|
|
59
|
+
|
|
60
|
+
<section id="hero" class="section">
|
|
61
|
+
<div class="hero-content">
|
|
62
|
+
<h1>Hello, I'm <span class="highlight">Your Name</span></h1>
|
|
63
|
+
<p class="subtitle">Full-Stack Developer & Designer</p>
|
|
64
|
+
</div>
|
|
65
|
+
</section>
|
|
66
|
+
|
|
67
|
+
<section id="about" class="section content-section">
|
|
68
|
+
<div class="container">
|
|
69
|
+
<h2>About Me</h2>
|
|
70
|
+
<p>A passionate developer who loves building beautiful and performant web applications. Experienced in modern JavaScript frameworks, cloud infrastructure, and UI/UX design.</p>
|
|
71
|
+
</div>
|
|
72
|
+
</section>
|
|
73
|
+
|
|
74
|
+
<section id="projects" class="section content-section">
|
|
75
|
+
<div class="container">
|
|
76
|
+
<h2>Projects</h2>
|
|
77
|
+
<div class="project-grid">
|
|
78
|
+
${this.projects.map(
|
|
79
|
+
(p) => html`
|
|
80
|
+
<div class="project-card">
|
|
81
|
+
<h3>${p.title}</h3>
|
|
82
|
+
<p>${p.desc}</p>
|
|
83
|
+
</div>
|
|
84
|
+
`
|
|
85
|
+
)}
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
</section>
|
|
89
|
+
|
|
90
|
+
<section id="skills" class="section content-section">
|
|
91
|
+
<div class="container">
|
|
92
|
+
<h2>Skills</h2>
|
|
93
|
+
${this.skills.map(
|
|
94
|
+
(s) => html`
|
|
95
|
+
<div class="skill-bar">
|
|
96
|
+
<span class="skill-name">${s.name}</span>
|
|
97
|
+
<div class="bar"><div class="fill" style="width: ${s.pct}%"></div></div>
|
|
98
|
+
</div>
|
|
99
|
+
`
|
|
100
|
+
)}
|
|
101
|
+
</div>
|
|
102
|
+
</section>
|
|
103
|
+
|
|
104
|
+
<section id="contact" class="section content-section">
|
|
105
|
+
<div class="container">
|
|
106
|
+
<h2>Contact</h2>
|
|
107
|
+
<form id="contactForm" @submit=${this.handleSubmit}>
|
|
108
|
+
<input type="text" placeholder="Your Name" required />
|
|
109
|
+
<input type="email" placeholder="Your Email" required />
|
|
110
|
+
<textarea placeholder="Your Message" rows="5" required></textarea>
|
|
111
|
+
<button type="submit">Send Message</button>
|
|
112
|
+
</form>
|
|
113
|
+
</div>
|
|
114
|
+
</section>
|
|
115
|
+
`;
|
|
116
|
+
}
|
|
117
|
+
}
|