diff options
| author | Elizabeth Hunt <me@liz.coffee> | 2026-01-01 18:32:49 -0800 |
|---|---|---|
| committer | Elizabeth Hunt <me@liz.coffee> | 2026-01-01 18:32:49 -0800 |
| commit | 9af1854a7e35785a8e86426c4fb1edd465f164a3 (patch) | |
| tree | 8a070c6a9498d952c9ef4ba045f2ebfb25f7b335 /src/routes | |
| parent | 0248a3899ed910f005dccaeefc1d9dcb893e8154 (diff) | |
| download | mistymountainstherapy-9af1854a7e35785a8e86426c4fb1edd465f164a3.tar.gz mistymountainstherapy-9af1854a7e35785a8e86426c4fb1edd465f164a3.zip | |
Massive refactor courtesy of 5 dollars of AI tokens
Diffstat (limited to 'src/routes')
| -rw-r--r-- | src/routes/+layout.svelte | 40 | ||||
| -rw-r--r-- | src/routes/+page.svelte | 266 | ||||
| -rw-r--r-- | src/routes/__layout.svelte | 13 | ||||
| -rw-r--r-- | src/routes/approach/+page.svelte | 188 | ||||
| -rw-r--r-- | src/routes/approach/index.svelte | 45 | ||||
| -rw-r--r-- | src/routes/contact/+page.svelte | 325 | ||||
| -rw-r--r-- | src/routes/contact/index.svelte | 158 | ||||
| -rw-r--r-- | src/routes/contact/submit/+server.js (renamed from src/routes/contact/submit.js) | 31 | ||||
| -rw-r--r-- | src/routes/index.svelte | 84 | ||||
| -rw-r--r-- | src/routes/services/+page.svelte (renamed from src/routes/services/index.svelte) | 4 | ||||
| -rw-r--r-- | src/routes/team/+page.svelte (renamed from src/routes/team/index.svelte) | 8 |
11 files changed, 838 insertions, 324 deletions
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte new file mode 100644 index 0000000..651ef5f --- /dev/null +++ b/src/routes/+layout.svelte @@ -0,0 +1,40 @@ +<script> + import { page } from '$app/stores'; + import { fade } from 'svelte/transition'; + import NavBar from '../components/NavBar.svelte'; + import Footer from '../components/Footer.svelte'; + import '../app.css'; +</script> + +<svelte:head> + <meta + name="description" + content="Misty Mountains Therapy provides high quality therapy services for Rexburg and the surrounding area." + /> + <meta property="og:site_name" content="Misty Mountains Therapy" /> + <meta property="og:title" content="Misty Mountains Therapy" /> + <meta + property="og:description" + content="High quality therapy services for Rexburg and the surrounding area." + /> + <meta property="og:type" content="website" /> + <meta property="og:url" content="https://mistymountainstherapy.com/" /> + <meta property="og:image" content="https://mistymountainstherapy.com/logo.png" /> + <meta name="twitter:card" content="summary" /> + <meta name="twitter:title" content="Misty Mountains Therapy" /> + <meta + name="twitter:description" + content="High quality therapy services for Rexburg and the surrounding area." + /> +</svelte:head> + +<a class="skip-link" href="#main">Skip to content</a> +<NavBar /> +<main id="main" class="page" tabindex="-1"> + {#key $page.url.pathname} + <div class="container" in:fade={{ duration: 150, delay: 50 }}> + <slot /> + </div> + {/key} +</main> +<Footer /> diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte new file mode 100644 index 0000000..71b9920 --- /dev/null +++ b/src/routes/+page.svelte @@ -0,0 +1,266 @@ +<script> + import { resolveRoute } from '$app/paths'; + import { carouselImages } from '$lib/data/images'; + import { onMount } from 'svelte'; + + const images = [ + { src: carouselImages[0], alt: 'Glass office door with the Misty Mountains Therapy logo' }, + { src: carouselImages[1], alt: 'Entry hall with a bench for waiting patients' }, + { src: carouselImages[2], alt: 'Office room with a rustic lamp and comfortable couch' }, + { src: carouselImages[3], alt: 'Welcoming therapy office interior' }, + { src: carouselImages[4], alt: 'Misty mountain landscape' } + ]; + + let currentIndex = 0; + let intervalId; + + function nextSlide() { + currentIndex = (currentIndex + 1) % images.length; + } + + function prevSlide() { + currentIndex = (currentIndex - 1 + images.length) % images.length; + } + + function goToSlide(index) { + currentIndex = index; + } + + onMount(() => { + intervalId = setInterval(nextSlide, 5000); + return () => clearInterval(intervalId); + }); + + function pauseAutoplay() { + clearInterval(intervalId); + } + + function resumeAutoplay() { + clearInterval(intervalId); + intervalId = setInterval(nextSlide, 5000); + } +</script> + +<section class="hero"> + <div + class="carousel" + role="region" + aria-label="Office photos" + aria-roledescription="carousel" + on:mouseenter={pauseAutoplay} + on:mouseleave={resumeAutoplay} + on:focusin={pauseAutoplay} + on:focusout={resumeAutoplay} + > + <div class="carousel__track" style="transform: translateX(-{currentIndex * 100}%)"> + {#each images as image, i (image.src)} + <div + class="carousel__slide" + role="group" + aria-roledescription="slide" + aria-label="{i + 1} of {images.length}" + aria-hidden={i !== currentIndex} + > + <img + class="carousel__image" + src={image.src} + alt={image.alt} + loading={i === 0 ? 'eager' : 'lazy'} + decoding="async" + /> + </div> + {/each} + </div> + + <button + class="carousel__btn carousel__btn--prev" + type="button" + aria-label="Previous slide" + on:click={prevSlide} + > + <i class="bi bi-chevron-left" aria-hidden="true"></i> + </button> + <button + class="carousel__btn carousel__btn--next" + type="button" + aria-label="Next slide" + on:click={nextSlide} + > + <i class="bi bi-chevron-right" aria-hidden="true"></i> + </button> + + <div class="carousel__dots" role="tablist" aria-label="Slide controls"> + {#each images as _, i (i)} + <button + class="carousel__dot" + class:carousel__dot--active={i === currentIndex} + type="button" + role="tab" + aria-selected={i === currentIndex} + aria-label="Go to slide {i + 1}" + on:click={() => goToSlide(i)} + ></button> + {/each} + </div> + </div> + + <div class="hero__content"> + <h1>Helping you conquer Mount Doom.</h1> + <a href={resolveRoute('/contact')} class="button button--primary"> + Free 15 Minute Consultation + </a> + </div> +</section> + +<section class="card home-intro"> + <blockquote> + "Darkness must pass, a new day will come, and when the sun shines, it will shine out the clearer." + <footer>Samwise Gamgee</footer> + </blockquote> + + <p> + Misty Mountains Therapy is a privately owned, high quality, specialty therapy clinic, + founded in January 2020 by Jefferson Hunt. We are dedicated to providing comprehensive + therapy evaluation and treatment services to children and adults for a wide variety of + disorders in the most efficient and effective manner possible in the Rexburg area. We + believe that therapy should be fun, engaging, and most importantly, useful to our clients. + </p> + <p> + We are currently accepting new clients and offer a variety of services to <strong>help you live the + life you desire</strong>. To find the right fit for you, schedule a <a href={resolveRoute('/contact')} + >free 15-minute consultation</a + >. + </p> + + <aside class="notice notice--warn" aria-label="Crisis information"> + <p style="margin: 0"> + We do not have a crisis line. If you or someone you know is in danger please call 911, visit your + nearest emergency room, call the National Suicide Prevention Lifeline for free crisis counseling at + <a href="tel:18002738255">(800)273-TALK</a> (8255), or text HELLO to 741-741. + </p> + </aside> +</section> + +<style> + .hero { + display: grid; + gap: var(--space-5); + margin-bottom: var(--space-5); + } + + @media (min-width: 768px) { + .hero { + grid-template-columns: 1.4fr 1fr; + align-items: center; + } + } + + /* Carousel */ + .carousel { + position: relative; + border-radius: var(--radius-sm); + overflow: hidden; + box-shadow: var(--shadow-sm); + } + + .carousel__track { + display: flex; + transition: transform 400ms ease; + } + + .carousel__slide { + flex: 0 0 100%; + min-width: 0; + } + + .carousel__image { + display: block; + width: 100%; + height: auto; + aspect-ratio: 4 / 3; + object-fit: cover; + } + + .carousel__btn { + position: absolute; + top: 50%; + transform: translateY(-50%); + background: rgba(255, 255, 255, 0.85); + border: none; + border-radius: 50%; + width: 2.5rem; + height: 2.5rem; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + opacity: 0; + transition: opacity 150ms ease, background 150ms ease; + font-size: 1.1rem; + color: var(--color-ink); + } + + .carousel:hover .carousel__btn, + .carousel:focus-within .carousel__btn { + opacity: 1; + } + + .carousel__btn:hover { + background: white; + } + + .carousel__btn--prev { + left: var(--space-3); + } + + .carousel__btn--next { + right: var(--space-3); + } + + .carousel__dots { + position: absolute; + bottom: var(--space-3); + left: 50%; + transform: translateX(-50%); + display: flex; + gap: var(--space-2); + } + + .carousel__dot { + width: 0.5rem; + height: 0.5rem; + border-radius: 50%; + border: none; + background: rgba(255, 255, 255, 0.5); + cursor: pointer; + padding: 0; + transition: background 150ms ease, transform 150ms ease; + } + + .carousel__dot:hover { + background: rgba(255, 255, 255, 0.8); + } + + .carousel__dot--active { + background: white; + transform: scale(1.25); + } + + /* Hero content */ + .hero__content { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: var(--space-4); + } + + .hero__content h1 { + margin: 0; + } + + /* Intro card - removed max-width for wider feel */ + .home-intro .notice { + margin-top: var(--space-5); + margin-bottom: 0; + } +</style> diff --git a/src/routes/__layout.svelte b/src/routes/__layout.svelte deleted file mode 100644 index ccb2fd5..0000000 --- a/src/routes/__layout.svelte +++ /dev/null @@ -1,13 +0,0 @@ -<script> - import NavBar from '../components/NavBar.svelte'; - import Footer from '../components/Footer.svelte'; - import '../app.css'; - import { SvelteToast } from '@zerodevx/svelte-toast'; -</script> - -<SvelteToast /> -<NavBar /> -<div class="container my-2"> - <slot /> -</div> -<Footer /> diff --git a/src/routes/approach/+page.svelte b/src/routes/approach/+page.svelte new file mode 100644 index 0000000..75c9620 --- /dev/null +++ b/src/routes/approach/+page.svelte @@ -0,0 +1,188 @@ +<script> + import { slide } from 'svelte/transition'; + import { approachImage } from '$lib/data/images'; + + const approaches = [ + { + title: 'Cognitive Behavioral Therapy', + description: + 'CBT focuses on modifying dysfunctional behaviors, thoughts, and emotions. In session, we will identify these harmful processes and determine if they are an accurate depiction of reality. If they are not, we will help you use strategies to challenge and overcome them.' + }, + { + title: 'Solution Focused Therapy', + description: + "We believe the client is the expert of their own story. If you are coming to see us, it's possible that you're overwhelmed with your present situation. We will use the past to provide understanding and reflection, but we will mostly focus on the present and future. We will empower you to create new perspective, possibilities, and plans to actualize your new story." + }, + { + title: 'Narrative Therapy', + description: + 'Sometimes we become our problems. We start to identify as "a depressed person" or "an anxious person". We can help you learn to see your issues as something you have, but not something that defines you. We will teach you to put some distance between yourself and your issues and empower you to live your life so that you can work on finding out who you really are and what you are capable of.' + }, + { + title: 'Emotion Focused Therapy', + description: + 'We will work together as a team to find blocked vulnerabilities in your relationship. We will teach you to express your emotions to help you connect rather than disconnect. The goal is to create more trust and a secure bond with your partner.' + }, + { + title: 'Gottman Method', + description: + "Gottman's research has shown that negativity impacts the brain and can draw couples apart. We will help you take the steps necessary to maintain a positive orientation towards one another during difficult circumstances. Therapy is most effective when both partners are present so that each person can share their history, story, and goals." + }, + { + title: 'Family Systems Theory', + description: + 'It is true that profound joy can come from living in a family, but conversely many psychological issues stem from dysfunctional relationships with one another. For example, when one person is struggling with anxiety, pornography addiction, any form of abuse, faith crisis, depression, or health issues it affects the whole family unit. Effective mediation can help in the toughest situations and facilitate respect and resolution.' + }, + { + title: 'PPP - Positive Parenting Program', + description: + 'We use this method to teach families how to treat and prevent behavioral and emotional problems in children and teens. We use a holistic approach and address concerns in the family, school, and community. We will not tell you how to parent, rather we will give you tools and ideas to manage misbehavior, set rules, encourage behavior you like, and take care of yourself so you can feel good and be confident in your parenting skills.' + } + ]; + + let openIndex = -1; + + function toggle(index) { + openIndex = openIndex === index ? -1 : index; + } +</script> + +<div class="approach"> + <h1 class="text-center">Our Approach.</h1> + + <section class="card approach__intro"> + <div class="approach__hero"> + <img + class="shadow rounded" + src={approachImage} + alt="boats in water" + loading="lazy" + decoding="async" + /> + </div> + <p> + We meet each client where they are at and customize their therapeutic journey to best fit + their personality and issues. Some of the approaches we use most are listed below: + </p> + </section> + + <ul class="approach__list"> + {#each approaches as approach, i (approach.title)} + <li class="approach__item"> + <button + class="approach__trigger" + type="button" + aria-expanded={openIndex === i} + on:click={() => toggle(i)} + > + <span class="approach__title">{approach.title}</span> + <span class="approach__icon" aria-hidden="true"> + <i class={'bi ' + (openIndex === i ? 'bi-dash' : 'bi-plus')}></i> + </span> + </button> + {#if openIndex === i} + <div class="approach__content" transition:slide={{ duration: 200 }}> + <p>{approach.description}</p> + </div> + {/if} + </li> + {/each} + </ul> +</div> + +<style> + .approach { + display: grid; + gap: var(--space-5); + } + + .approach__intro { + display: grid; + gap: var(--space-4); + text-align: center; + } + + .approach__intro p { + max-width: 65ch; + margin-inline: auto; + } + + .approach__hero img { + max-width: min(100%, 420px); + height: auto; + } + + .approach__list { + list-style: none; + margin: 0; + padding: 0; + display: grid; + gap: var(--space-3); + } + + .approach__item { + background: var(--color-surface); + border: 1px solid var(--color-border); + border-radius: var(--radius-sm); + overflow: hidden; + } + + .approach__trigger { + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--space-3); + padding: var(--space-4); + background: transparent; + border: none; + cursor: pointer; + font: inherit; + text-align: left; + transition: background 150ms ease; + } + + .approach__trigger:hover { + background: rgba(0, 0, 0, 0.02); + } + + .approach__icon { + transition: transform 150ms ease; + } + + .approach__trigger[aria-expanded='true'] .approach__icon { + transform: rotate(180deg); + } + + .approach__title { + font-family: var(--font-serif); + font-size: 1.25rem; + font-weight: 600; + } + + .approach__icon { + flex-shrink: 0; + display: inline-flex; + align-items: center; + justify-content: center; + width: 2rem; + height: 2rem; + border-radius: 999px; + background: color-mix(in srgb, var(--color-accent) 12%, transparent); + color: var(--color-accent-strong); + } + + .approach__icon i { + font-size: 1.1rem; + } + + .approach__content { + padding: 0 var(--space-4) var(--space-4); + } + + .approach__content p { + margin: 0; + color: var(--color-muted); + line-height: 1.6; + } +</style> diff --git a/src/routes/approach/index.svelte b/src/routes/approach/index.svelte deleted file mode 100644 index 3a4e963..0000000 --- a/src/routes/approach/index.svelte +++ /dev/null @@ -1,45 +0,0 @@ -<script> - import { approachImage } from '$lib/data/images'; -</script> - -<main> - <h1 class="text-center">Our Approach.</h1> - <div class="bg-light rounded p-4 shadow"> - <div class="row justify-content-center"> - <div class="col-sm-10"> - <div style="text-align:center"> - <img class="shadow" src={approachImage} alt="boats in water" style="width:60%;border-radius: 0.25em;"> - </div> - <br> - <p>We meet each client where they are at and customize their therapeutic journey to best fit their personality and issues. Some of the approaches we use most are listed below:</p> - </div> - </div> - <br> - <h2>Cognitive Behavioral Therapy</h2> - - <p>CBT focuses on modifying dysfunctional behaviors, thoughts, and emotions. In session, we will identify these harmful processes and determine if they are an accurate depiction of reality. If they are not, we will help you use strategies to challenge and overcome them. </p> - <h2>Solution Focused Therapy</h2> - - <p>We believe the client is the expert of their own story. If you are coming to see us, it’s possible that you’re overwhelmed with your present situation. We will use the past to provide understanding and reflection, but we will mostly focus on the present and future. We will empower you to create new perspective, possibilities, and plans to actualize your new story.</p> - <h2>Narrative Therapy</h2> - - <p>Sometimes we become our problems. We start to identify as “a depressed person” or “an anxious person”. We can help you learn to see your issues as something you have, but not something that defines you. We will teach you to put some distance between yourself and your issues and empower you to live your life so that you can work on finding out who you really are and what you are capable of.</p> - <h2>Emotion Focused Therapy</h2> - - <p>We will work together as a team to find blocked vulnerabilities in your relationship. We will teach you to express your emotions to help you connect rather than disconnect. The goal is to create more trust and a secure bond with your partner. It is a three-step process: - </p><ol> - <li>De-escalate negative interactions</li> - <li>Re-structure interactions and state fears as well as insecurities</li> - <li>Continue productive conversations outside of therapy.</li> - </ol> - <h2>Gottman Method</h2> - - <p>Gottman’s research has shown that negativity impacts the brain and can draw couples apart. We will help you take the steps necessary to maintain a positive orientation towards one another during difficult circumstances. Therapy is most effective when both partners are present so that each person can share their history, story, and goals.</p> - <h2>Family Systems Theory</h2> - - <p>It is true that profound joy can come from living in a family, but conversely many psychological issues stem from dysfunctional relationships with one another. For example, when one person is struggling with anxiety, pornography addiction, any form of abuse, faith crisis, depression, or health issues it affects the whole family unit. Effective mediation can help in the toughest situations and facilitate respect and resolution.</p> - <h2>PPP - Positive Parenting Program</h2> - - <p>We use this method to teach families how to treat and prevent behavioral and emotional problems in children and teens. We use a holistic approach and address concerns in the family, school, and community. We will not tell you how to parent, rather we will give you tools and ideas to manage misbehavior, set rules, encourage behavior you like, and take care of yourself so you can feel good and be confident in your parenting skills.</p> - </div> -</main> diff --git a/src/routes/contact/+page.svelte b/src/routes/contact/+page.svelte new file mode 100644 index 0000000..c66d9df --- /dev/null +++ b/src/routes/contact/+page.svelte @@ -0,0 +1,325 @@ +<script> + import { browser } from '$app/environment'; + import HCaptcha from 'svelte-hcaptcha'; + + const mapsUrl = 'https://maps.app.goo.gl/s1AFqfKvUKgXDCrq5'; + + let submission = { + name: '', + email: '', + message: '', + phone: '', + captchaToken: '' + }; + + let captcha; + let noticeType = 'info'; + let noticeMessage = ''; + + function setNotice(type, message) { + noticeType = type; + noticeMessage = message; + } + + function handleSubmit(e) { + e.preventDefault(); + + if (!browser) return; + if (!submission.captchaToken) { + setNotice('error', 'Please complete the captcha first.'); + return; + } + + setNotice('info', 'Sending...'); + fetch('/contact/submit', { + method: 'POST', + body: JSON.stringify(submission) + }) + .then((x) => x.json()) + .then((x) => { + if (x.success) { + setNotice('success', 'Success! Reloading...'); + setTimeout(() => window.location.reload(), 1000); + } else { + setNotice('error', x.error ?? 'Something went wrong. Please try again.'); + } + }) + .catch((err) => { + console.log(err); + setNotice('error', 'Network error. Please try again.'); + }); + } + + function onCaptchaError() { + setNotice('error', 'Failed to verify captcha, try again.'); + captcha?.reset(); + submission.captchaToken = ''; + } + + function onCaptchaSuccess({ detail: { token } }) { + submission.captchaToken = token; + } +</script> + +<div class="contact"> + <header class="contact__header"> + <h1>Contact</h1> + </header> + + {#if noticeMessage} + <div + class={'notice notice--' + noticeType} + role={noticeType === 'error' ? 'alert' : 'status'} + aria-live={noticeType === 'error' ? 'assertive' : 'polite'} + > + {noticeMessage} + </div> + {/if} + + <div class="contact__grid"> + <div class="contact__sidebar"> + <section class="card" aria-label="Contact details"> + <h2>Details</h2> + + <div class="contact__methods"> + <a class="contact__method" href={mapsUrl} target="_blank" rel="noopener noreferrer"> + <span class="contact__icon" aria-hidden="true"><i class="bi bi-pin-map"></i></span> + <span class="contact__methodBody"> + <span class="contact__methodTitle">Office</span> + <span class="contact__methodText"> + 534 Trejo Street, Suite 200F<br />Rexburg, ID 83440 + </span> + </span> + </a> + + <a class="contact__method" href="tel:12084994517"> + <span class="contact__icon" aria-hidden="true"><i class="bi bi-telephone"></i></span> + <span class="contact__methodBody"> + <span class="contact__methodTitle">Phone</span> + <span class="contact__methodText">(208) 499 - 4517</span> + </span> + </a> + + <a class="contact__method" href="mailto:contact@mistymountainstherapy.com"> + <span class="contact__icon" aria-hidden="true"><i class="bi bi-envelope"></i></span> + <span class="contact__methodBody"> + <span class="contact__methodTitle">Email</span> + <span class="contact__methodText">contact@mistymountainstherapy.com</span> + </span> + </a> + </div> + </section> + + <section class="card card--warn" aria-label="Crisis resources"> + <h2>In a crisis?</h2> + <p style="margin: 0"> + We do not have a crisis line. If you or someone you know is in danger please call 911, visit your + nearest emergency room, call the National Suicide Prevention Lifeline at + <a href="tel:18002738255">(800)273-TALK</a> (8255), or text HELLO to 741-741. + </p> + </section> + </div> + + <section class="card" aria-label="Send a message"> + <h2>Send a message</h2> + <form class="contact__form" on:submit|preventDefault={handleSubmit}> + <div class="contact__fields"> + <label class="field"> + <span class="field__label">Email *</span> + <input + type="email" + class="form-control" + bind:value={submission.email} + placeholder="johnnyappleseed@example.com" + required + /> + </label> + + <label class="field"> + <span class="field__label">Name *</span> + <input + type="text" + class="form-control" + bind:value={submission.name} + placeholder="Johnny Appleseed" + required + /> + </label> + + <label class="field"> + <span class="field__label">Phone</span> + <input + type="text" + class="form-control" + bind:value={submission.phone} + placeholder="(208) 123-4567" + /> + </label> + + <label class="field"> + <span class="field__label">Message *</span> + <textarea + class="form-control" + bind:value={submission.message} + rows="6" + placeholder="Hello! I would like to schedule a free 15-minute consultation..." + required + ></textarea> + </label> + </div> + + <div class="contact__captcha"> + <HCaptcha + sitekey={import.meta.env.VITE_HCAPTCHA_KEY} + bind:this={captcha} + on:success={onCaptchaSuccess} + on:error={onCaptchaError} + /> + </div> + + <div class="contact__actions"> + <button type="submit" class="button button--primary" disabled={!submission.captchaToken}> + Submit + </button> + <p class="text-muted" style="margin: 0"> + Please watch spam for replies. + </p> + </div> + </form> + </section> + </div> +</div> + +<style> + .contact { + display: grid; + gap: var(--space-5); + } + + .contact__header { + display: grid; + gap: var(--space-2); + } + + .contact__lede { + margin: 0; + color: var(--color-muted); + } + + .contact__grid { + display: grid; + grid-template-columns: 1fr; + gap: var(--space-5); + align-items: start; + } + + @media (min-width: 900px) { + .contact__grid { + grid-template-columns: 1fr minmax(0, 320px); + } + + .contact__sidebar { + order: 2; + } + } + + .contact__sidebar { + display: grid; + gap: var(--space-5); + min-width: 0; + } + + .contact__methods { + display: grid; + grid-template-columns: 1fr; + gap: var(--space-3); + } + + .contact__method { + display: grid; + grid-template-columns: 2.25rem 1fr; + gap: var(--space-3); + align-items: start; + padding: var(--space-3); + border-radius: var(--radius-sm); + border: 1px solid var(--color-border); + text-decoration: none; + background: rgba(255, 255, 255, 0.55); + } + + .contact__method:hover { + border-color: var(--color-accent); + } + + .contact__icon { + display: inline-flex; + align-items: center; + justify-content: center; + width: 2.25rem; + height: 2.25rem; + border-radius: 999px; + background: color-mix(in srgb, var(--color-accent) 10%, transparent); + color: var(--color-accent-strong); + } + + .contact__icon i { + font-size: 1.1rem; + } + + .contact__methodBody { + display: grid; + gap: 0.15rem; + } + + .contact__methodTitle { + font-weight: 700; + } + + .contact__methodText { + color: var(--color-muted); + line-height: 1.35; + word-break: break-word; + } + + .contact__form { + display: grid; + gap: var(--space-4); + } + + .contact__fields { + display: grid; + grid-template-columns: 1fr; + gap: var(--space-3); + } + + @media (min-width: 700px) { + .contact__fields { + grid-template-columns: 1fr; + } + + .field--full { + grid-column: 1 / -1; + } + } + + .field { + display: grid; + gap: var(--space-2); + } + + .field__label { + font-weight: 650; + } + + .contact__captcha { + display: grid; + justify-content: start; + } + + .contact__actions { + display: flex; + flex-wrap: wrap; + gap: var(--space-3); + align-items: center; + } +</style> diff --git a/src/routes/contact/index.svelte b/src/routes/contact/index.svelte deleted file mode 100644 index 5bd68f1..0000000 --- a/src/routes/contact/index.svelte +++ /dev/null @@ -1,158 +0,0 @@ -<script context="module"> - import { browser } from '$app/env'; - import { toast } from '@zerodevx/svelte-toast' - import HCaptcha from 'svelte-hcaptcha'; - - let submission = { - name: '', - email: '', - message: '', - phone: '', - captchaToken: '', - }; - - let captcha; - - function handleSubmit (e) { - e.preventDefault(); - - if (browser) { - const sendToast = toast.push('Sending...', { - duration: 300, - initial: 0, - next: 0.2, - dismissable: false - }); - fetch('/contact/submit', { - method: "POST", - body: JSON.stringify(submission) - }) - .then((x) => x.json()) - .then((x) => { - toast.set(sendToast, { next: 1 }); - - if (x.success) { - toast.push('Success! Reloading...', { - theme: { - '--toastBackground': '#48BB78', - '--toastBarBackground': '#2F855A' - }, - duration: 1000, - onpop: () => { window.location.reload(); }, - }); - } else if (x.error) { - toast.push(x.error, { - theme: { - '--toastBackground': '#F56565', - '--toastBarBackground': '#C53030' - } - }); - } - }) - .catch((err) => console.log(err)); - } - } - - function onCaptchaError () { - toast.push('Failed to verify captcha, try again.', { - theme: { - '--toastBackground': '#F56565', - '--toastBarBackground': '#C53030' - } - }); - captcha.reset(); - } - - function onCaptchaSuccess ({ detail: { token } }) { - submission.captchaToken = token; - } -</script> - -<main> - <h1 class="text-center">Get in touch.</h1> - <div class="d-flex justify-content-center flex-row row"> - <div class="border shadow bg-light py-2 col-lg-3 d-flex align-items-center flex-column m-2"> - <h1><i class="bi bi-map-fill"></i></h1> - <p style="hyphens: auto;"> - <a href="https://maps.app.goo.gl/s1AFqfKvUKgXDCrq5">534 Trejo Street - <br> - Suite 200F - <br> - Rexburg, ID - <br> - 83440 - </a> - </p> - </div> - <div class="border shadow bg-light py-2 col-lg-3 d-flex align-items-center flex-column m-2"> - <div><h1><i class="bi bi-phone-fill"></i></h1></div> - <p style="hyphens: auto;"> - Scheduling and Other - <br> - <a href="tel:12084994517">(208) 499 - 4517</a> - </p> - </div> - <div class="border shadow bg-light py-2 col-lg-3 d-flex align-items-center flex-column m-2" style="word-break: break-all;"> - <h1><i class="bi bi-envelope-fill"></i></h1> - <div> - <p style="hyphens: auto;"> - Billing - <br> - <a href="mailto:billing@mistymountainstherapy.com">billing@mistymountainstherapy.com</a> - </p> - <p style="hyphens: auto;"> - Inquiries - <br> - <a href="mailto:contact@mistymountainsthreapy.com">contact@mistymountainstherapy.com</a> - </p> - <div><em>note: please watch spam for replies</em></div> - </div> - </div> - </div> - <br> - <hr> - <form class="bg-light border shadow p-4" on:submit|preventDefault={handleSubmit}> - <h2>Or send us a message.</h2> - <div class="row mb-2"> - <div class="form-group col-md-6"> - <label for="email">Email *</label> - <input id="email" type="email" class="form-control" bind:value={submission.email} placeholder="johnnyappleseed@example.com" required> - </div> - <div class="form-group col-md-6"> - <label for="name">Name *</label> - <input id="name" type="text" class="form-control" bind:value={submission.name} placeholder="Johnny Appleseed" required> - </div> - </div> - <div class="form-group"> - <label for="phone">Phone</label> - <input id="phone" type="text" class="form-control" bind:value={submission.phone} placeholder="(208) 123-4567"> - </div> - <div class="form-group"> - <label for="message">Message *</label> - <textarea id="message" class="form-control" bind:value={submission.message} rows="3" placeholder="Hello! I would like to schedule a free 15-minute consultation..." required></textarea> - </div> - <div class="pt-2"> - <HCaptcha - sitekey={import.meta.env.VITE_HCAPTCHA_KEY} - bind:this={captcha} - on:success={onCaptchaSuccess} - on:error={onCaptchaError} - /> - </div> - <button type="submit" class="btn btn-primary">Submit</button> - <div class="my-2"><em>note: please watch spam for any replies</em></div> - </form> - <br> - - <div class="bg-light border shadow p-4"> - <div class="d-flex justify-content-center"> - <div class="col-md-8 mt-2"> - <div> - We do not have a crisis line. If you or someone you know is in danger please call 911, visit - your nearest emergency room, call the National Suicide Prevention Lifeline for free crisis - counseling at <a href="tel:18002738255">(800)273-TALK</a> (8255), or text HELLO to 741-741. - </div> - </div> - </div> - </div> -</main> diff --git a/src/routes/contact/submit.js b/src/routes/contact/submit/+server.js index 0befd0e..eed95fe 100644 --- a/src/routes/contact/submit.js +++ b/src/routes/contact/submit/+server.js @@ -39,7 +39,7 @@ class MistyMountainsMailer { } } -export async function post({ request }) { +export async function POST({ request }) { const body = await request.json(); const { HCAPTCHA_SECRET, FORM_TO_EMAIL } = process.env; const mailer = new MistyMountainsMailer( @@ -61,12 +61,10 @@ export async function post({ request }) { .catch(() => false); if (!captchaVerified) { - return { - statusCode: 400, - body: { - error: 'Captcha verification failed' - } - }; + return new Response(JSON.stringify({ error: 'Captcha verification failed' }), { + status: 400, + headers: { 'Content-Type': 'application/json' } + }); } const text = `<p>New MMT Message</h1> @@ -86,17 +84,14 @@ export async function post({ request }) { }); if (!messageSent) { - return { - statusCode: 500, - body: { - error: 'Message could not be sent' - } - }; + return new Response(JSON.stringify({ error: 'Message could not be sent' }), { + status: 500, + headers: { 'Content-Type': 'application/json' } + }); } - return { - body: { - success: true - } - }; + return new Response(JSON.stringify({ success: true }), { + status: 200, + headers: { 'Content-Type': 'application/json' } + }); } diff --git a/src/routes/index.svelte b/src/routes/index.svelte deleted file mode 100644 index 1a701c7..0000000 --- a/src/routes/index.svelte +++ /dev/null @@ -1,84 +0,0 @@ -<script> - import { carouselImages } from '$lib/data/images'; - import { Navigation, Pagination, Scrollbar, A11y, Autoplay } from 'swiper'; - import { Swiper, SwiperSlide } from 'swiper/svelte'; - import 'swiper/css'; - import 'swiper/css/navigation'; - import 'swiper/css/pagination'; - import 'swiper/css/scrollbar'; - import 'swiper/css/autoplay'; - - const images = [ - { image: carouselImages[0], alt: 'Picture of the glass office door with the Misty Mountains Therapy logo in the center.' }, - { image: carouselImages[1], alt: 'The entry hall to the Misty Mountains Suite room, showing a bench for waiting patients to sit. The vibes are inviting.' }, - { image: carouselImages[2], alt: 'An office room with a rustic lamp and comfy looking couch.' }, - { image: carouselImages[3], alt: 'A second office room with good vibes.' }, - { image: carouselImages[4], alt: 'Cloudy mountains in a light sky' }, - ]; -</script> - -<div class="row align-items-center py-2"> - <div class="col-md-7"> - <Swiper - modules={[Navigation, Pagination, Scrollbar, A11y, Autoplay]} - class="rounded shadow" - spaceBetween={50} - slidesPerView={1} - autoHeight={true} - loop={true} - navigation - pagination={{ clickable: true }} - autoplay={true} - speed={1000} - on:slideChange={() => console.log('slide change')} - on:swiper={(e) => console.log(e.detail[0])} - > - {#each images as { image, alt } (image)} - <SwiperSlide> - <img class="image-fluid" style="width:100%" src={image} {alt} /> - </SwiperSlide> - {/each} - </Swiper> - </div> - <div class="col-md-5 my-2"> - <h2>Helping you conquer Mount Doom.</h2> - <p><a href="/contact" class="btn btn-success shadow">FREE 15 Minute Consultation</a></p> - </div> -</div> - -<div class="bg-light rounded p-3 shadow"> - <div class="d-flex justify-content-center"> - <div class="col-md-8 mt-2 border-bottom"> - <h3> - "Darkness must pass, a new day will come, and when the sun shines, it will shine out the - clearer." - </h3> - <div class="d-flex justify-content-end">- Samwise Gamgee</div> - <br /> - <p> - Misty Mountains Therapy is a privately owned, high quality, specialty therapy clinic, - founded in January 2020 by Jefferson Hunt. We are dedicated to providing comprehensive - therapy evaluation and treatment services to children and adults for a wide variety of - disorders in the most efficient and effective manner possible in the Rexburg area. We - believe that therapy should be fun, engaging, and most importantly, useful to our clients. - </p> - <p> - We are currently accepting new clients and offer a variety of services to <strong>help you live the - life you desire</strong>. To find the right fit for you, schedule a <a href="/contact" - >free 15-minute consultation</a - >. - </p> - </div> - </div> - - <div class="d-flex justify-content-center"> - <div class="col-md-8 mt-2"> - <div> - We do not have a crisis line. If you or someone you know is in danger please call 911, visit - your nearest emergency room, call the National Suicide Prevention Lifeline for free crisis - counseling at <a href="tel:18002738255">(800)273-TALK</a> (8255), or text HELLO to 741-741. - </div> - </div> - </div> - <br /> -</div> diff --git a/src/routes/services/index.svelte b/src/routes/services/+page.svelte index 1a02120..222e2ff 100644 --- a/src/routes/services/index.svelte +++ b/src/routes/services/+page.svelte @@ -3,7 +3,7 @@ import { servicesImages } from '$lib/data/images'; </script> -<main> +<div> <h1 class="text-center">Our Services.</h1> <DirectionCard direction="left" imageSpec={{image: servicesImages.girl, alt: "Girl looking at camera"}}> <h2>Therapy</h2> @@ -41,4 +41,4 @@ <li>Suicidal Ideation</li> </ul> </DirectionCard> -</main> +</div> diff --git a/src/routes/team/index.svelte b/src/routes/team/+page.svelte index 631645b..12e068f 100644 --- a/src/routes/team/index.svelte +++ b/src/routes/team/+page.svelte @@ -3,20 +3,20 @@ import { people } from '$lib/data/people'; </script> -<main> +<div> <h1 class="text-center">Our Team.</h1> {#if people.length} - {#each people as person, i} + {#each people as person, i (person.email)} <div class="row border-bottom"> <DirectionCard imageSpec={{ image: person.image, alt: person.name }} direction={i % 2 ? 'left' : 'right'} > <h2>{person.name}, {person.position}</h2> - <p style="white-space: pre-line">{person.bio}</p> <a href="mailto:{person.email}"><p>{person.email}</p></a> + <p style="white-space: pre-line">{person.bio}</p> </DirectionCard> </div> {/each} {/if} -</main> +</div> |
