feat: add contact component
- update css - update data.json - update types
This commit is contained in:
154
src/lib/components/Contact.svelte
Normal file
154
src/lib/components/Contact.svelte
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { Contact } from '$lib/types/data';
|
||||||
|
|
||||||
|
let { title, anchorId, subtitle, form }: Contact = $props();
|
||||||
|
|
||||||
|
let emailData = $state({
|
||||||
|
to: "frodo06@gmx.de",
|
||||||
|
subject: "",
|
||||||
|
message: ""
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleSubmit(event: SubmitEvent) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const subject = encodeURIComponent(emailData.subject);
|
||||||
|
const body = encodeURIComponent(emailData.message);
|
||||||
|
|
||||||
|
// Construct the mailto URL
|
||||||
|
const mailtoUrl = `mailto:${emailData.to}?subject=${subject}&body=${body}`;
|
||||||
|
|
||||||
|
// Open the user's email client
|
||||||
|
window.location.href = mailtoUrl;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<section id={anchorId}>
|
||||||
|
<h2>{title}</h2>
|
||||||
|
{#if (subtitle)}
|
||||||
|
<p>{subtitle}</p>
|
||||||
|
{/if}
|
||||||
|
<form onsubmit={handleSubmit} class="flex flex-col gap-4">
|
||||||
|
<p>{form.title}</p>
|
||||||
|
<input
|
||||||
|
bind:value={emailData.subject}
|
||||||
|
placeholder={form.subjectPlaceholder}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
|
||||||
|
<textarea
|
||||||
|
bind:value={emailData.message}
|
||||||
|
placeholder={form.messagePlaceholder}
|
||||||
|
rows="5"
|
||||||
|
></textarea>
|
||||||
|
|
||||||
|
<button type="submit">
|
||||||
|
{form.submit}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 1rem;
|
||||||
|
padding: 5rem 1rem;
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
padding: 6rem 2.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin: unset;
|
||||||
|
|
||||||
|
font-size: 1.875rem;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
color: transparent;
|
||||||
|
background-image: var(--color-headline-background-image);
|
||||||
|
background-clip: text;
|
||||||
|
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
font-size: 3rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: unset;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
|
||||||
|
font-size: 1.125rem;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 1rem;
|
||||||
|
|
||||||
|
max-width: 32rem;
|
||||||
|
width: 100%;
|
||||||
|
padding: 2rem;
|
||||||
|
background-color: var(--color-contact-background);
|
||||||
|
border: 1px solid var(--color-contact-background-border);
|
||||||
|
border-radius: 1rem;
|
||||||
|
color: var(--color-contact-text);
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
color: var(--color-contact-text);
|
||||||
|
font-size: 1.25rem;
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input, textarea {
|
||||||
|
padding: 1rem;
|
||||||
|
color: white;
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
background-color: var(--color-contact-background-input);
|
||||||
|
border: 1px solid var(--color-contact-background-border);
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
border: 1px solid var(--color-contact-background-input-border-focused);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
appearance: none;
|
||||||
|
padding: 1rem 1.5rem;
|
||||||
|
background-image: var(--color-contact-background-button);
|
||||||
|
border: unset;
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
color: var(--color-contact-text);
|
||||||
|
font-size: 1.125rem;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 1.5;
|
||||||
|
transition: translate ease-in-out 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-image: var(--color-contact-background-button-hover);
|
||||||
|
translate: 0 -0.25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -184,5 +184,16 @@
|
|||||||
"items": ["SEO", "Accessibility", "KI-basierte Tools"]
|
"items": ["SEO", "Accessibility", "KI-basierte Tools"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"contact": {
|
||||||
|
"title": "Kontakt",
|
||||||
|
"anchorId": "contact",
|
||||||
|
"subtitle": "Hinterlassen Sie mir eine Nachricht",
|
||||||
|
"form": {
|
||||||
|
"title": "Schneller Kontakt",
|
||||||
|
"subjectPlaceholder": "Dein Name",
|
||||||
|
"messagePlaceholder": "Deine Nachricht",
|
||||||
|
"submit": "Email öffnen"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,22 @@
|
|||||||
|
|
||||||
--color-card-box-shadow: 0 0 0 0 rgba(0, 0, 0, 0), oklab(0.623 -0.0378409 -0.210628 / 0.5) 0 25px 50px -12px;
|
--color-card-box-shadow: 0 0 0 0 rgba(0, 0, 0, 0), oklab(0.623 -0.0378409 -0.210628 / 0.5) 0 25px 50px -12px;
|
||||||
|
|
||||||
|
--color-contact-background: oklch(0.278 0.033 256.848);
|
||||||
|
--color-contact-background-border: oklab(0.623 -0.0378409 -0.210628 / 0.3);
|
||||||
|
--color-contact-text: oklch(0.967 0.003 264.542);
|
||||||
|
--color-contact-background-input: oklch(0.373 0.034 259.733);
|
||||||
|
--color-contact-background-input-border-focused: oklch(70.7% 0.165 254.624);
|
||||||
|
--color-contact-background-button: linear-gradient(
|
||||||
|
to right,
|
||||||
|
oklch(0.623 0.214 259.815) 0%,
|
||||||
|
oklch(0.511 0.262 276.966) 100%
|
||||||
|
);
|
||||||
|
--color-contact-background-button-hover: linear-gradient(
|
||||||
|
to right,
|
||||||
|
oklch(0.546 0.245 262.881) 0%,
|
||||||
|
oklch(0.457 0.24 277.023) 100%
|
||||||
|
);
|
||||||
|
|
||||||
--z-index-header: 50;
|
--z-index-header: 50;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export type Data = {
|
|||||||
profile: Profile;
|
profile: Profile;
|
||||||
projects: Projects;
|
projects: Projects;
|
||||||
skills: Skills;
|
skills: Skills;
|
||||||
|
contact: Contact;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Header = {
|
export type Header = {
|
||||||
@@ -60,8 +61,22 @@ export type Skills = {
|
|||||||
|
|
||||||
export type SkillEntry = {
|
export type SkillEntry = {
|
||||||
title: string;
|
title: string;
|
||||||
icon: LucideIconName;
|
icon: string;
|
||||||
items: string[];
|
items: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type LucideIconName = keyof typeof icons;
|
export type LucideIconName = keyof typeof icons;
|
||||||
|
|
||||||
|
export type Contact = {
|
||||||
|
title: string;
|
||||||
|
subtitle: string;
|
||||||
|
anchorId: string;
|
||||||
|
form: ContactForm;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ContactForm = {
|
||||||
|
title: string;
|
||||||
|
subjectPlaceholder: string;
|
||||||
|
messagePlaceholder: string;
|
||||||
|
submit: string;
|
||||||
|
};
|
||||||
@@ -4,10 +4,12 @@
|
|||||||
import Profile from '$lib/components/Profile.svelte';
|
import Profile from '$lib/components/Profile.svelte';
|
||||||
import Projects from '$lib/components/Projects.svelte';
|
import Projects from '$lib/components/Projects.svelte';
|
||||||
import Skills from '$lib/components/Skills.svelte';
|
import Skills from '$lib/components/Skills.svelte';
|
||||||
|
import Contact from '$lib/components/Contact.svelte';
|
||||||
|
|
||||||
let data: Data = content;
|
let data: Data = content;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Profile {...data.profile} />
|
<Profile {...data.profile} />
|
||||||
<Projects {...data.projects} />
|
<Projects {...data.projects} />
|
||||||
<Skills {...data.skills} />
|
<Skills {...data.skills} />
|
||||||
|
<Contact {...data.contact} />
|
||||||
Reference in New Issue
Block a user