UI updates
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
---
|
||||
// Contact Form Component
|
||||
---
|
||||
<div id="form-message" class="hidden mb-4"></div>
|
||||
|
||||
<form id="contact-form" class="space-y-6 contact-form-wrapper">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div class="space-y-2">
|
||||
<label for="name" class="block text-sm text-black/70 dark:text-white/60">
|
||||
Name
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="name"
|
||||
name="name"
|
||||
required
|
||||
class="w-full px-4 py-3 rounded-md border border-black/5 dark:border-white/5 bg-transparent text-black dark:text-white placeholder-black/30 dark:placeholder-white/30 focus:outline-none focus:border-black/20 dark:focus:border-white/20 transition-all duration-300"
|
||||
placeholder="Your name"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<label for="email" class="block text-sm text-black/70 dark:text-white/60">
|
||||
Email
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
name="email"
|
||||
required
|
||||
class="w-full px-4 py-3 rounded-md border border-black/5 dark:border-white/5 bg-transparent text-black dark:text-white placeholder-black/30 dark:placeholder-white/30 focus:outline-none focus:border-black/20 dark:focus:border-white/20 transition-all duration-300"
|
||||
placeholder="your.email@example.com"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<label for="message" class="block text-sm text-black/70 dark:text-white/60">
|
||||
Message
|
||||
</label>
|
||||
<textarea
|
||||
id="message"
|
||||
name="message"
|
||||
required
|
||||
rows="5"
|
||||
class="w-full px-4 py-3 rounded-md border border-black/5 dark:border-white/5 bg-transparent text-black dark:text-white placeholder-black/30 dark:placeholder-white/30 focus:outline-none focus:border-black/20 dark:focus:border-white/20 transition-all duration-300 resize-none"
|
||||
placeholder="Your message..."
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button
|
||||
type="submit"
|
||||
class="px-8 py-3 rounded-md bg-black/90 dark:bg-white/90 text-white dark:text-black font-medium hover:bg-black dark:hover:bg-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black/50 dark:focus:ring-white/50 transition-all duration-300 disabled:opacity-40 disabled:cursor-not-allowed"
|
||||
>
|
||||
<span id="button-text">Send Message</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const form = document.getElementById('contact-form') as HTMLFormElement;
|
||||
const buttonText = document.getElementById('button-text') as HTMLSpanElement;
|
||||
const formMessage = document.getElementById('form-message') as HTMLDivElement;
|
||||
|
||||
if (form) {
|
||||
form.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
// Get form data
|
||||
const formData = new FormData(form);
|
||||
const name = formData.get('name') as string;
|
||||
const email = formData.get('email') as string;
|
||||
const message = formData.get('message') as string;
|
||||
|
||||
// Disable button and show loading state
|
||||
const submitButton = form.querySelector('button[type="submit"]') as HTMLButtonElement;
|
||||
submitButton.disabled = true;
|
||||
buttonText.textContent = 'Sending...';
|
||||
formMessage.className = 'hidden';
|
||||
|
||||
try {
|
||||
// Send to API
|
||||
const response = await fetch('https://notify.api.standard.nz/', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name,
|
||||
email,
|
||||
message,
|
||||
destination: 'michael'
|
||||
}),
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
// Success
|
||||
formMessage.textContent = 'Message sent successfully! I\'ll get back to you soon.';
|
||||
formMessage.className = 'text-sm px-4 py-2.5 rounded-md bg-green-50 dark:bg-green-900/20 text-green-700 dark:text-green-300 border border-green-200 dark:border-green-800/30';
|
||||
form.style.display = 'none';
|
||||
} else {
|
||||
// Error response
|
||||
throw new Error('Failed to send message');
|
||||
}
|
||||
} catch (error) {
|
||||
// Network or other error
|
||||
formMessage.textContent = 'Failed to send message. Please try again or email me directly.';
|
||||
formMessage.className = 'text-sm px-4 py-2.5 rounded-md bg-red-50 dark:bg-red-900/20 text-red-700 dark:text-red-300 border border-red-200 dark:border-red-800/30';
|
||||
} finally {
|
||||
// Re-enable button
|
||||
submitButton.disabled = false;
|
||||
buttonText.textContent = 'Send Message';
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -18,12 +18,6 @@ const isHomepage = Astro.url.pathname === '/';
|
||||
</Link>
|
||||
)}
|
||||
<nav class="flex gap-1">
|
||||
<Link href="/blog">
|
||||
blog
|
||||
</Link>
|
||||
<span>
|
||||
{`/`}
|
||||
</span>
|
||||
<Link href="/work">
|
||||
work
|
||||
</Link>
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ import type { Site, Metadata, Socials } from "@types";
|
||||
|
||||
export const SITE: Site = {
|
||||
NAME: "Michael Rausch",
|
||||
EMAIL: "michael@rausch.nz",
|
||||
EMAIL: "m@michaelraus.ch",
|
||||
NUM_POSTS_ON_HOMEPAGE: 3,
|
||||
NUM_WORKS_ON_HOMEPAGE: 2,
|
||||
NUM_PROJECTS_ON_HOMEPAGE: 3,
|
||||
|
||||
+30
-28
@@ -5,6 +5,7 @@ import PageLayout from "@layouts/PageLayout.astro";
|
||||
import ArrowCard from "@components/ArrowCard.astro";
|
||||
import WorkCard from "@components/WorkCard.astro";
|
||||
import Link from "@components/Link.astro";
|
||||
import ContactForm from "@components/ContactForm.astro";
|
||||
import { dateRange } from "@lib/utils";
|
||||
import { SITE, HOME, SOCIALS } from "@consts";
|
||||
import EmojiScroller from "@components/EmojiScroller.astro";
|
||||
@@ -35,13 +36,13 @@ const work = await Promise.all(
|
||||
|
||||
<PageLayout title={HOME.TITLE} description={HOME.DESCRIPTION}>
|
||||
<Container>
|
||||
<h1 class="animate font-bold text-black dark:text-white text-4xl md:text-5xl font-serif leading-tight">
|
||||
<h1 class="animate font-bold text-black dark:text-white text-4xl md:text-5xl font-serif leading-tight mb-5">
|
||||
Hi, I'm Michael <EmojiScroller/>
|
||||
</h1>
|
||||
<div class="space-y-16">
|
||||
<section>
|
||||
<article class="space-y-4">
|
||||
<p class="animate">
|
||||
<p class="animate text-lg">
|
||||
I'm a software engineer at the University of Canterbury, working on <Link href="https://uconline.ac.nz" external class="text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300">Tuihono UC | UC Online</Link>.
|
||||
|
||||
I specialize in full-stack development. While my primary expertise is in software engineering, I also have a strong interest in cloud infrastructure and DevOps. Based in Christchurch, New Zealand
|
||||
@@ -108,32 +109,33 @@ const work = await Promise.all(
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="animate space-y-4">
|
||||
<h4 class="font-semibold text-black dark:text-white text-xl">
|
||||
Let's Connect
|
||||
</h4>
|
||||
<article>
|
||||
<p>
|
||||
If you want to get in touch with me about something or just to say hi,
|
||||
reach out on social media or send me an email.
|
||||
</p>
|
||||
</article>
|
||||
<ul class="flex flex-wrap gap-2">
|
||||
{SOCIALS.map(SOCIAL => (
|
||||
<li class="flex gap-x-2 text-nowrap">
|
||||
<Link href={SOCIAL.HREF} external aria-label={`${SITE.NAME} on ${SOCIAL.NAME}`}>
|
||||
{SOCIAL.NAME}
|
||||
</Link>
|
||||
{"/"}
|
||||
</li>
|
||||
))}
|
||||
<li class="line-clamp-1">
|
||||
<Link href={`mailto:${SITE.EMAIL}`} aria-label={`Email ${SITE.NAME}`} confetti>
|
||||
{SITE.EMAIL}
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="animate space-y-4">
|
||||
<h4 class="font-semibold text-black dark:text-white text-xl">
|
||||
Let's Connect
|
||||
</h4>
|
||||
<article>
|
||||
<p>
|
||||
If you want to get in touch with me about something or just to say hi,
|
||||
reach out on social media or send me an email.
|
||||
</p>
|
||||
</article>
|
||||
<ContactForm />
|
||||
<ul class="flex flex-wrap gap-2 pt-5">
|
||||
{SOCIALS.map(SOCIAL => (
|
||||
<li class="flex gap-x-2 text-nowrap">
|
||||
<Link href={SOCIAL.HREF} external aria-label={`${SITE.NAME} on ${SOCIAL.NAME}`}>
|
||||
{SOCIAL.NAME}
|
||||
</Link>
|
||||
{"/"}
|
||||
</li>
|
||||
))}
|
||||
<li class="line-clamp-1">
|
||||
<Link href={`mailto:${SITE.EMAIL}`} aria-label={`Email ${SITE.NAME}`} confetti>
|
||||
{SITE.EMAIL}
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</Container>
|
||||
</PageLayout>
|
||||
|
||||
Reference in New Issue
Block a user