development #27
@ -39,7 +39,7 @@
|
|||||||
.card .card-content :global(div) {
|
.card .card-content :global(div) {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: center;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,47 @@
|
|||||||
import Loading from "$lib/components/Loading.svelte";
|
import Loading from "$lib/components/Loading.svelte";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
{#await getJson('/json/me.json')}
|
||||||
|
<Loading />
|
||||||
|
{:then info}
|
||||||
|
<div class="main-card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h1>{info.name}</h1>
|
||||||
|
<h3 class="not-required">{info.job_title}</h3>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<div class="flex-container">
|
||||||
|
<img class="profile not-required" src={info.profile_photo} alt="{info.name}'s Profile Photo">
|
||||||
|
<p class="about">{@html info.about}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<h1>Skills</h1>
|
||||||
|
<hr />
|
||||||
|
<div class="cards">
|
||||||
|
<Skills skills="{info.skills}"></Skills>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<h1>Experience</h1>
|
||||||
|
<hr />
|
||||||
|
<!-- https://github.com/K-Sato1995/svelte-vertical-timeline -->
|
||||||
|
<Timeline timelineData="{info.timeline}"></Timeline>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="display: none;">{addToast(new Toast("Click on a skill to open a prompt", ToastType.Info, true, 8_000))}</div>
|
||||||
|
<div style="display: none;">{addToast(new Toast("Welcome!", ToastType.Success, true, 7_000))}</div>
|
||||||
|
{:catch}
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h1>Unable to load portfolio overview data</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="display: none;">{addToast(new Toast("Unable to load me.json", ToastType.Error, true, 3000))}</div>
|
||||||
|
{/await}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.main-card {
|
.main-card {
|
||||||
background-color: var(--bg-secondary);
|
background-color: var(--bg-secondary);
|
||||||
@ -63,45 +104,4 @@
|
|||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
{#await getJson('/json/me.json')}
|
|
||||||
<Loading />
|
|
||||||
{:then info}
|
|
||||||
<div class="main-card">
|
|
||||||
<div class="card-header">
|
|
||||||
<h1>{info.name}</h1>
|
|
||||||
<h3 class="not-required">{info.job_title}</h3>
|
|
||||||
</div>
|
|
||||||
<hr />
|
|
||||||
<div class="flex-container">
|
|
||||||
<img class="profile not-required" src={info.profile_photo} alt="{info.name}'s Profile Photo">
|
|
||||||
<p class="about">{@html info.about}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
<h1>Skills</h1>
|
|
||||||
<hr />
|
|
||||||
<div class="cards">
|
|
||||||
<Skills skills="{info.skills}"></Skills>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
<h1>Experience</h1>
|
|
||||||
<hr />
|
|
||||||
<!-- https://github.com/K-Sato1995/svelte-vertical-timeline -->
|
|
||||||
<Timeline timelineData="{info.timeline}"></Timeline>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="display: none;">{addToast(new Toast("Click on a skill to open a prompt", ToastType.Info, true, 8_000))}</div>
|
|
||||||
<div style="display: none;">{addToast(new Toast("Welcome!", ToastType.Success, true, 7_000))}</div>
|
|
||||||
{:catch}
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-header">
|
|
||||||
<h1>Unable to load portfolio overview data</h1>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div style="display: none;">{addToast(new Toast("Unable to load me.json", ToastType.Error, true, 3000))}</div>
|
|
||||||
{/await}
|
|
@ -3,6 +3,18 @@
|
|||||||
import ThemeSwitcher from "$lib/components/ThemeSwitcher.svelte";
|
import ThemeSwitcher from "$lib/components/ThemeSwitcher.svelte";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<nav>
|
||||||
|
<a href = "/">//Profile</a>
|
||||||
|
<a href = "/repos">//Repos</a>
|
||||||
|
<a href = "/contact">//Contact</a>
|
||||||
|
<ThemeSwitcher />
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="main-container fade">
|
||||||
|
<Toasts />
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.main-container {
|
.main-container {
|
||||||
margin-left: 10%;
|
margin-left: 10%;
|
||||||
@ -45,16 +57,4 @@
|
|||||||
0% { opacity: 0; }
|
0% { opacity: 0; }
|
||||||
100% { opacity: 1; }
|
100% { opacity: 1; }
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<nav>
|
|
||||||
<a href = "/">//Profile</a>
|
|
||||||
<a href = "/repos">//Repos</a>
|
|
||||||
<a href = "/contact">//Contact</a>
|
|
||||||
<ThemeSwitcher />
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div class="main-container fade">
|
|
||||||
<Toasts />
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
@ -1,90 +1,149 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Card from '$lib/components/Cards/Card.svelte';
|
import Card from '$lib/components/Cards/Card.svelte';
|
||||||
import { Toast, ToastType } from "$lib/toast";
|
import { Toast, ToastType } from '$lib/toast';
|
||||||
import { addToast } from "$lib/stores";
|
import { addToast } from '$lib/stores';
|
||||||
|
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
const sent = $page.url.searchParams.get('sent');
|
const sent = $page.url.searchParams.get('sent');
|
||||||
|
|
||||||
if (sent == "true") {
|
if (sent == 'true') {
|
||||||
addToast(new Toast("Thank you! Your E-Mail has been sent. I will reply as soon as possible!", ToastType.Success, true, 5000));
|
addToast(
|
||||||
|
new Toast(
|
||||||
|
'Thank you! Your E-Mail has been sent. I will reply as soon as possible!',
|
||||||
|
ToastType.Success,
|
||||||
|
true,
|
||||||
|
5000
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// Can't use else otherwise the warning will display on load
|
// Can't use else otherwise the warning will display on load
|
||||||
if (sent == "false") {
|
if (sent == 'false') {
|
||||||
addToast(new Toast("Sorry, your E-Mail could not be sent... Please try again later!", ToastType.Error, true, 5000));
|
addToast(
|
||||||
|
new Toast(
|
||||||
|
'Sorry, your E-Mail could not be sent... Please try again later!',
|
||||||
|
ToastType.Error,
|
||||||
|
true,
|
||||||
|
5000
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
|
||||||
form {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
flex: 2 1;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
margin: 1em;
|
|
||||||
gap: 1em 3em;
|
|
||||||
}
|
|
||||||
|
|
||||||
input, textarea {
|
|
||||||
padding: 1em 0em 1em 1em;
|
|
||||||
background-color: var(--input);
|
|
||||||
color: var(--fg);
|
|
||||||
border: 1px solid var(--fg);
|
|
||||||
outline: 0;
|
|
||||||
border-radius: 8px;
|
|
||||||
resize: none;
|
|
||||||
min-width: 100%;
|
|
||||||
transition: all 0.15s;
|
|
||||||
font-size: .8em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
background-color: var(--fg);
|
|
||||||
color: var(--bg);
|
|
||||||
transition: all 0.2s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button:hover {
|
|
||||||
transform: scale(1.01);
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
min-height: 12em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
display: flex;
|
|
||||||
flex: 2 1 5rem;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 1em 1em;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<div slot="header">
|
<div slot="header">
|
||||||
<h2>Contact</h2>
|
<h2>Contact</h2>
|
||||||
</div>
|
</div>
|
||||||
<div slot="content">
|
<div slot="content">
|
||||||
<form action="https://api.staticforms.xyz/submit" method="post">
|
<form action="https://api.staticforms.xyz/submit" method="post" class="contact-form">
|
||||||
<div class="container">
|
<input type="hidden" name="accessKey" value="fbb5ec04-506b-448a-a445-a2e47579a966">
|
||||||
<input type="hidden" name="accessKey" value="fbb5ec04-506b-448a-a445-a2e47579a966">
|
|
||||||
<input type="text" name="name" placeholder="Name" required>
|
<!-- Form Items-->
|
||||||
<input type="text" name="email" placeholder="Email address" required>
|
<div class="input-group">
|
||||||
<input type="hidden" name="replyTo" value="@">
|
<input type="text" id="name" name="name" required placeholder="Your Name" />
|
||||||
|
<input type="email" id="email" name="email" required placeholder="Your Email" />
|
||||||
|
</div>
|
||||||
|
<div class="input-group">
|
||||||
<input type="text" name="subject" placeholder="Subject" required>
|
<input type="text" name="subject" placeholder="Subject" required>
|
||||||
<input type="text" name="honeypot" style="display: none;">
|
|
||||||
</div>
|
</div>
|
||||||
<div class="container">
|
<div class="input-group">
|
||||||
<textarea name="message" id="message" placeholder="Message" required></textarea>
|
<textarea id="message" name="message" rows="4" required placeholder="Your Message" />
|
||||||
</div>
|
</div>
|
||||||
<input class="button" type="submit" value="Send" />
|
|
||||||
|
<!-- Hidden Attributes-->
|
||||||
|
<input type="hidden" name="replyTo" value="@">
|
||||||
|
<input type="text" name="honeypot" style="display: none;">
|
||||||
<input type="hidden" name="redirectTo" value="https://luke-else.co.uk/contact?sent=true">
|
<input type="hidden" name="redirectTo" value="https://luke-else.co.uk/contact?sent=true">
|
||||||
|
|
||||||
|
<!-- reCAPTCHA integration -->
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="g-recaptcha" data-sitekey="6LfjQAwrAAAAAIF57u8Wt4w5L5vBEWi5DfXXBuGy"></div>
|
||||||
|
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group">
|
||||||
|
<button type="submit" class="submit-button">Send Message</button>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div slot="footer">
|
<div slot="footer">
|
||||||
<a href="/Luke Else - CV.pdf" target="_blank" rel="noopener noreferrer">Curriculum Vitae</a>
|
<a href="/Luke Else - CV.pdf" target="_blank" rel="noopener noreferrer">Curriculum Vitae</a>
|
||||||
<a href="mailto:contact@luke-else.co.uk">E-Mail</a>
|
<a href="mailto:contact@luke-else.co.uk">E-Mail</a>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
/* Contact form styling */
|
||||||
|
.contact-form {
|
||||||
|
background: none;
|
||||||
|
padding: 1rem;
|
||||||
|
width: 80%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Input groups */
|
||||||
|
.input-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 1rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Input fields and textarea */
|
||||||
|
.contact-form input,
|
||||||
|
.contact-form textarea {
|
||||||
|
padding: 0.8rem 1rem;
|
||||||
|
border: 1px solid var(--fg);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
background: var(--input);
|
||||||
|
color: var(--fg);
|
||||||
|
font-size: 1rem;
|
||||||
|
transition: border-color 0.3s ease, background 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-form button {
|
||||||
|
border: 1px solid var(--fg);
|
||||||
|
width: 60%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-form textarea {
|
||||||
|
width: 100%;
|
||||||
|
min-width: none;
|
||||||
|
resize: vertical;
|
||||||
|
min-height: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-form input:focus,
|
||||||
|
.contact-form textarea:focus {
|
||||||
|
border-color: var(--glow);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Submit button */
|
||||||
|
.submit-button {
|
||||||
|
padding: 0.8rem 1rem;
|
||||||
|
background: var(--accent);
|
||||||
|
color: var(--fg);
|
||||||
|
border: none;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-button:hover {
|
||||||
|
background: var(--link);
|
||||||
|
color: var(--input);
|
||||||
|
}
|
||||||
|
|
||||||
|
.g-recaptcha {
|
||||||
|
width: fit-content;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -8,20 +8,6 @@
|
|||||||
let activeModal: any = null;
|
let activeModal: any = null;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
|
||||||
.card-footer {
|
|
||||||
margin-bottom: 1em;
|
|
||||||
display: flex;
|
|
||||||
gap: 1.5em;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
color: var(--fg);
|
|
||||||
font-size: 3em;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
{#each skills as skill}
|
{#each skills as skill}
|
||||||
<Card on:click={() => {showModal = true; activeModal = skill}}>
|
<Card on:click={() => {showModal = true; activeModal = skill}}>
|
||||||
<div slot="header">
|
<div slot="header">
|
||||||
@ -56,4 +42,18 @@
|
|||||||
<a href="/repos">Repos</a>
|
<a href="/repos">Repos</a>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.card-footer {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
display: flex;
|
||||||
|
gap: 1.5em;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
color: var(--fg);
|
||||||
|
font-size: 3em;
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
x
Reference in New Issue
Block a user