@tsparticles/template-portfolio 4.1.3 → 4.2.1
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 +16 -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/vanilla/package.json +1 -1
- 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,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{packageName}}",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "{{version}}",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "stencil build --dev --watch",
|
|
8
|
+
"build": "stencil build",
|
|
9
|
+
"preview": "stencil build --dev --watch"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@tsparticles/stencil": "^4.1.3",
|
|
13
|
+
"@tsparticles/engine": "^4.0.0",
|
|
14
|
+
"@tsparticles/slim": "^4.0.0",
|
|
15
|
+
"@tsparticles/configs": "^4.0.0",
|
|
16
|
+
"@stencil/core": "^4.20.0"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"typescript": "~5.8.0"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { Component, State, h } from "@stencil/core";
|
|
2
|
+
import { ParticlesBase } from "@tsparticles/stencil";
|
|
3
|
+
import { loadSlim } from "@tsparticles/slim";
|
|
4
|
+
import configs from "@tsparticles/configs";
|
|
5
|
+
import type { ISourceOptions } from "@tsparticles/engine";
|
|
6
|
+
|
|
7
|
+
const keys = Object.keys(configs);
|
|
8
|
+
const randomKey = keys[Math.floor(Math.random() * keys.length)] as keyof typeof configs;
|
|
9
|
+
const options: ISourceOptions = {
|
|
10
|
+
...configs[randomKey],
|
|
11
|
+
fullScreen: { enable: true, zIndex: -1 },
|
|
12
|
+
} as ISourceOptions;
|
|
13
|
+
|
|
14
|
+
@Component({
|
|
15
|
+
tag: "app-home",
|
|
16
|
+
styleUrl: "app-home.css",
|
|
17
|
+
scoped: true,
|
|
18
|
+
})
|
|
19
|
+
export class AppHome {
|
|
20
|
+
@State()
|
|
21
|
+
private navItems = ["Home", "About", "Projects", "Skills", "Contact"];
|
|
22
|
+
|
|
23
|
+
@State()
|
|
24
|
+
private projects = [
|
|
25
|
+
{ title: "Project One", desc: "A web application built with Stencil and TypeScript." },
|
|
26
|
+
{ title: "Project Two", desc: "Real-time dashboard with data visualization." },
|
|
27
|
+
{ title: "Project Three", desc: "Mobile-first e-commerce platform." },
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
@State()
|
|
31
|
+
private skills = [
|
|
32
|
+
{ name: "TypeScript", pct: 90 },
|
|
33
|
+
{ name: "Stencil", pct: 85 },
|
|
34
|
+
{ name: "Node.js", pct: 80 },
|
|
35
|
+
{ name: "CSS", pct: 88 },
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
connectedCallback(): void {
|
|
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 (
|
|
52
|
+
<div>
|
|
53
|
+
<ts-particles id="tsparticles" options={options}></ts-particles>
|
|
54
|
+
<nav id="navbar">
|
|
55
|
+
{this.navItems.map((item) => (
|
|
56
|
+
<a href={`#${item.toLowerCase()}`} class="nav-link">{item}</a>
|
|
57
|
+
))}
|
|
58
|
+
</nav>
|
|
59
|
+
<section id="hero" class="section">
|
|
60
|
+
<div class="hero-content">
|
|
61
|
+
<h1>Hello, I'm <span class="highlight">Your Name</span></h1>
|
|
62
|
+
<p class="subtitle">Full-Stack Developer & Designer</p>
|
|
63
|
+
</div>
|
|
64
|
+
</section>
|
|
65
|
+
<section id="about" class="section content-section">
|
|
66
|
+
<div class="container">
|
|
67
|
+
<h2>About Me</h2>
|
|
68
|
+
<p>A passionate developer who loves building beautiful and performant web applications. Experienced in modern JavaScript frameworks, cloud infrastructure, and UI/UX design.</p>
|
|
69
|
+
</div>
|
|
70
|
+
</section>
|
|
71
|
+
<section id="projects" class="section content-section">
|
|
72
|
+
<div class="container">
|
|
73
|
+
<h2>Projects</h2>
|
|
74
|
+
<div class="project-grid">
|
|
75
|
+
{this.projects.map((p) => (
|
|
76
|
+
<div class="project-card">
|
|
77
|
+
<h3>{p.title}</h3>
|
|
78
|
+
<p>{p.desc}</p>
|
|
79
|
+
</div>
|
|
80
|
+
))}
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
</section>
|
|
84
|
+
<section id="skills" class="section content-section">
|
|
85
|
+
<div class="container">
|
|
86
|
+
<h2>Skills</h2>
|
|
87
|
+
{this.skills.map((s) => (
|
|
88
|
+
<div class="skill-bar">
|
|
89
|
+
<span class="skill-name">{s.name}</span>
|
|
90
|
+
<div class="bar"><div class="fill" style={{ width: `${s.pct}%` }}></div></div>
|
|
91
|
+
</div>
|
|
92
|
+
))}
|
|
93
|
+
</div>
|
|
94
|
+
</section>
|
|
95
|
+
<section id="contact" class="section content-section">
|
|
96
|
+
<div class="container">
|
|
97
|
+
<h2>Contact</h2>
|
|
98
|
+
<form id="contactForm" onSubmit={this.handleSubmit}>
|
|
99
|
+
<input type="text" placeholder="Your Name" required />
|
|
100
|
+
<input type="email" placeholder="Your Email" required />
|
|
101
|
+
<textarea placeholder="Your Message" rows={5} required></textarea>
|
|
102
|
+
<button type="submit">Send Message</button>
|
|
103
|
+
</form>
|
|
104
|
+
</div>
|
|
105
|
+
</section>
|
|
106
|
+
</div>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{packageName}}",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "vite build",
|
|
9
|
+
"preview": "vite preview"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@tsparticles/svelte": "^4.1.3"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
|
16
|
+
"svelte": "^5.55.7",
|
|
17
|
+
"svelte-check": "^3.7.1",
|
|
18
|
+
"tslib": "^2.8.1"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Particles from "@tsparticles/svelte";
|
|
3
|
+
import type { ISourceOptions } from "@tsparticles/engine";
|
|
4
|
+
import configs from "@tsparticles/configs";
|
|
5
|
+
|
|
6
|
+
const keys = Object.keys(configs);
|
|
7
|
+
const randomKey = keys[Math.floor(Math.random() * keys.length)] as keyof typeof configs;
|
|
8
|
+
|
|
9
|
+
const options: ISourceOptions = {
|
|
10
|
+
...configs[randomKey],
|
|
11
|
+
fullScreen: { enable: true, zIndex: -1 },
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
function handleSubmit(e: Event): void {
|
|
15
|
+
e.preventDefault();
|
|
16
|
+
alert("Message sent! (demo)");
|
|
17
|
+
const form = e.target as HTMLFormElement;
|
|
18
|
+
form.reset();
|
|
19
|
+
}
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<nav id="navbar">
|
|
23
|
+
<a class="nav-link" href="#hero">Home</a>
|
|
24
|
+
<a class="nav-link" href="#about">About</a>
|
|
25
|
+
<a class="nav-link" href="#projects">Projects</a>
|
|
26
|
+
<a class="nav-link" href="#skills">Skills</a>
|
|
27
|
+
<a class="nav-link" href="#contact">Contact</a>
|
|
28
|
+
</nav>
|
|
29
|
+
|
|
30
|
+
<section id="hero" class="section">
|
|
31
|
+
<div class="hero-content">
|
|
32
|
+
<h1>Hi, I'm <span class="highlight">Alex</span></h1>
|
|
33
|
+
<p class="subtitle">Full-Stack Developer & Designer</p>
|
|
34
|
+
</div>
|
|
35
|
+
</section>
|
|
36
|
+
|
|
37
|
+
<section id="about" class="section content-section">
|
|
38
|
+
<div class="container">
|
|
39
|
+
<h2>About Me</h2>
|
|
40
|
+
<p>
|
|
41
|
+
I'm a passionate developer with experience building modern web applications.
|
|
42
|
+
I love creating elegant solutions to complex problems, and I'm always
|
|
43
|
+
exploring new technologies to stay at the cutting edge.
|
|
44
|
+
</p>
|
|
45
|
+
</div>
|
|
46
|
+
</section>
|
|
47
|
+
|
|
48
|
+
<section id="projects" class="section content-section">
|
|
49
|
+
<div class="container">
|
|
50
|
+
<h2>Projects</h2>
|
|
51
|
+
<div class="project-grid">
|
|
52
|
+
<div class="project-card">
|
|
53
|
+
<h3>Project Alpha</h3>
|
|
54
|
+
<p>A real-time collaboration platform built with modern web technologies.</p>
|
|
55
|
+
</div>
|
|
56
|
+
<div class="project-card">
|
|
57
|
+
<h3>Project Beta</h3>
|
|
58
|
+
<p>An AI-powered analytics dashboard for data-driven decision making.</p>
|
|
59
|
+
</div>
|
|
60
|
+
<div class="project-card">
|
|
61
|
+
<h3>Project Gamma</h3>
|
|
62
|
+
<p>A cross-platform mobile app for tracking personal fitness goals.</p>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</section>
|
|
67
|
+
|
|
68
|
+
<section id="skills" class="section content-section">
|
|
69
|
+
<div class="container">
|
|
70
|
+
<h2>Skills</h2>
|
|
71
|
+
<div class="skill-bar">
|
|
72
|
+
<span class="skill-name">TypeScript</span>
|
|
73
|
+
<div class="bar"><div class="fill" style="width: 90%"></div></div>
|
|
74
|
+
</div>
|
|
75
|
+
<div class="skill-bar">
|
|
76
|
+
<span class="skill-name">React</span>
|
|
77
|
+
<div class="bar"><div class="fill" style="width: 85%"></div></div>
|
|
78
|
+
</div>
|
|
79
|
+
<div class="skill-bar">
|
|
80
|
+
<span class="skill-name">Node.js</span>
|
|
81
|
+
<div class="bar"><div class="fill" style="width: 80%"></div></div>
|
|
82
|
+
</div>
|
|
83
|
+
<div class="skill-bar">
|
|
84
|
+
<span class="skill-name">Python</span>
|
|
85
|
+
<div class="bar"><div class="fill" style="width: 75%"></div></div>
|
|
86
|
+
</div>
|
|
87
|
+
<div class="skill-bar">
|
|
88
|
+
<span class="skill-name">Svelte</span>
|
|
89
|
+
<div class="bar"><div class="fill" style="width: 70%"></div></div>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
</section>
|
|
93
|
+
|
|
94
|
+
<section id="contact" class="section content-section">
|
|
95
|
+
<div class="container">
|
|
96
|
+
<h2>Contact</h2>
|
|
97
|
+
<form id="contactForm" onsubmit={handleSubmit}>
|
|
98
|
+
<input type="text" placeholder="Your Name" required />
|
|
99
|
+
<input type="email" placeholder="Your Email" required />
|
|
100
|
+
<textarea placeholder="Your Message" rows="5" required></textarea>
|
|
101
|
+
<button type="submit">Send Message</button>
|
|
102
|
+
</form>
|
|
103
|
+
</div>
|
|
104
|
+
</section>
|
|
105
|
+
|
|
106
|
+
<Particles id="tsparticles" options={options} />
|
|
107
|
+
|
|
108
|
+
<style>
|
|
109
|
+
:global(*) {
|
|
110
|
+
margin: 0;
|
|
111
|
+
padding: 0;
|
|
112
|
+
box-sizing: border-box;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
:global(html) {
|
|
116
|
+
scroll-behavior: smooth;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
:global(body) {
|
|
120
|
+
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
|
121
|
+
color: #fff;
|
|
122
|
+
background: #0a0a1a;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
#navbar {
|
|
126
|
+
position: fixed;
|
|
127
|
+
top: 0;
|
|
128
|
+
width: 100%;
|
|
129
|
+
z-index: 100;
|
|
130
|
+
display: flex;
|
|
131
|
+
justify-content: center;
|
|
132
|
+
gap: 2rem;
|
|
133
|
+
padding: 1rem;
|
|
134
|
+
background: rgba(10, 10, 26, 0.8);
|
|
135
|
+
backdrop-filter: blur(10px);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.nav-link {
|
|
139
|
+
color: rgba(255, 255, 255, 0.7);
|
|
140
|
+
text-decoration: none;
|
|
141
|
+
font-size: 0.9em;
|
|
142
|
+
transition: color 0.2s;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.nav-link:hover {
|
|
146
|
+
color: #6c5ce7;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.section {
|
|
150
|
+
min-height: 100vh;
|
|
151
|
+
display: flex;
|
|
152
|
+
align-items: center;
|
|
153
|
+
justify-content: center;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
#hero {
|
|
157
|
+
position: relative;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.hero-content {
|
|
161
|
+
text-align: center;
|
|
162
|
+
z-index: 10;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.hero-content h1 {
|
|
166
|
+
font-size: 3.5em;
|
|
167
|
+
margin-bottom: 0.5rem;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.highlight {
|
|
171
|
+
color: #6c5ce7;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.subtitle {
|
|
175
|
+
font-size: 1.3em;
|
|
176
|
+
opacity: 0.7;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.content-section {
|
|
180
|
+
padding: 6rem 1rem;
|
|
181
|
+
min-height: auto;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.container {
|
|
185
|
+
max-width: 900px;
|
|
186
|
+
width: 100%;
|
|
187
|
+
margin: 0 auto;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
h2 {
|
|
191
|
+
font-size: 2.2em;
|
|
192
|
+
margin-bottom: 2rem;
|
|
193
|
+
color: #6c5ce7;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
p {
|
|
197
|
+
line-height: 1.7;
|
|
198
|
+
opacity: 0.85;
|
|
199
|
+
font-size: 1.1em;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.project-grid {
|
|
203
|
+
display: grid;
|
|
204
|
+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
205
|
+
gap: 1.5rem;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.project-card {
|
|
209
|
+
background: rgba(255, 255, 255, 0.05);
|
|
210
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
211
|
+
border-radius: 12px;
|
|
212
|
+
padding: 1.5rem;
|
|
213
|
+
transition: transform 0.2s, border-color 0.2s;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.project-card:hover {
|
|
217
|
+
transform: translateY(-4px);
|
|
218
|
+
border-color: #6c5ce7;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.project-card h3 {
|
|
222
|
+
margin-bottom: 0.5rem;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.skill-bar {
|
|
226
|
+
margin-bottom: 1.2rem;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.skill-name {
|
|
230
|
+
display: block;
|
|
231
|
+
margin-bottom: 0.3em;
|
|
232
|
+
font-size: 0.95em;
|
|
233
|
+
opacity: 0.8;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.bar {
|
|
237
|
+
height: 10px;
|
|
238
|
+
background: rgba(255, 255, 255, 0.1);
|
|
239
|
+
border-radius: 5px;
|
|
240
|
+
overflow: hidden;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.fill {
|
|
244
|
+
height: 100%;
|
|
245
|
+
background: linear-gradient(90deg, #6c5ce7, #a29bfe);
|
|
246
|
+
border-radius: 5px;
|
|
247
|
+
transition: width 1s ease;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
#contactForm {
|
|
251
|
+
display: flex;
|
|
252
|
+
flex-direction: column;
|
|
253
|
+
gap: 1rem;
|
|
254
|
+
max-width: 500px;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
#contactForm input,
|
|
258
|
+
#contactForm textarea {
|
|
259
|
+
padding: 0.8em 1em;
|
|
260
|
+
font-size: 1em;
|
|
261
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
262
|
+
border-radius: 8px;
|
|
263
|
+
background: rgba(255, 255, 255, 0.05);
|
|
264
|
+
color: #fff;
|
|
265
|
+
outline: none;
|
|
266
|
+
font-family: inherit;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
#contactForm input:focus,
|
|
270
|
+
#contactForm textarea:focus {
|
|
271
|
+
border-color: #6c5ce7;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
#contactForm button {
|
|
275
|
+
padding: 0.8em;
|
|
276
|
+
font-size: 1em;
|
|
277
|
+
font-weight: 600;
|
|
278
|
+
border: none;
|
|
279
|
+
border-radius: 8px;
|
|
280
|
+
background: #6c5ce7;
|
|
281
|
+
color: #fff;
|
|
282
|
+
cursor: pointer;
|
|
283
|
+
transition: background 0.2s;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
#contactForm button:hover {
|
|
287
|
+
background: #a29bfe;
|
|
288
|
+
}
|
|
289
|
+
</style>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { mount } from "svelte";
|
|
2
|
+
import { initParticlesEngine } from "@tsparticles/svelte";
|
|
3
|
+
import { loadSlim } from "@tsparticles/slim";
|
|
4
|
+
import App from "./App.svelte";
|
|
5
|
+
|
|
6
|
+
void initParticlesEngine(async (engine) => {
|
|
7
|
+
await loadSlim(engine);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const app = mount(App, { target: document.getElementById("app")! });
|
|
11
|
+
|
|
12
|
+
export default app;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020 Matteo Bruni
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{packageName}}",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "{{version}}",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "vite",
|
|
7
|
+
"build": "vite build",
|
|
8
|
+
"preview": "vite preview"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@tsparticles/vue2": "^4.1.3",
|
|
12
|
+
"@tsparticles/engine": "^4.0.0",
|
|
13
|
+
"@tsparticles/slim": "^4.0.0",
|
|
14
|
+
"@tsparticles/configs": "^4.0.0",
|
|
15
|
+
"vue": "^2.7.16"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@vitejs/plugin-vue2": "^2.3.0",
|
|
19
|
+
"typescript": "~5.8.0",
|
|
20
|
+
"vite": "^7.0.0"
|
|
21
|
+
}
|
|
22
|
+
}
|