feat: add redesigned hero section and change fonts

This commit is contained in:
Leonardo Murça 2026-04-16 17:36:00 -03:00
parent 142b19ae75
commit 6354336610
18 changed files with 278 additions and 289 deletions

View file

@ -1,86 +1,17 @@
<!doctype html>
<html lang="en">
<head>
<style>
:root {
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
font-size: 16px;
line-height: 24px;
font-weight: 400;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}
* {
box-sizing: border-box;
}
body {
display: flex;
justify-content: center;
flex-direction: column;
margin: 0;
width: 100%;
height: 100%;
}
#app {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
background-color: #f2f6f5;
z-index: 10;
}
input[type='submit'] {
width: 100%;
font-size: 20px;
margin-top: 20px;
background-color: #05345f;
font-weight: 700;
color: white;
padding: 10px;
-webkit-appearance: none;
border-radius: 0;
}
input[type='submit']:hover {
cursor: pointer;
background-color: black;
color: white;
}
body a {
text-decoration: none;
color: #06345f;
border-bottom: 3px solid #06345f;
}
body a:hover {
background-color: #06345f;
color: #ffffff;
}
:is(h1, h2, h3, h4, h5, h6) {
color: #06345f;
}
strong {
color: #06345f;
}
ul li::marker {
color: #06345f;
}
</style>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Caveat:wght@400..700&display=swap"
rel="stylesheet"
/>
<link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="shortcut icon" href="/favicon.ico" />

View file

@ -96,12 +96,13 @@
<style>
header {
position: absolute;
top: 0;
z-index: 2;
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 100px;
background-color: #f8f9fa;
border-bottom: 1px solid #ddd;
padding: 10px 300px 10px 100px;
width: 100%;
}

View file

@ -0,0 +1,115 @@
<script>
import { resolve } from '$app/paths';
import { PUBLIC_IMAGE_BASE_URL } from '$env/static/public';
import { isMobile } from '$lib/utils/isMobile';
const backgroundImage = isMobile()
? `${PUBLIC_IMAGE_BASE_URL}/t/f_webp/embroidery-viewer/hero-mobile.webp`
: `${PUBLIC_IMAGE_BASE_URL}/t/f_webp,w_1920,h_1080/embroidery-viewer/hero.webp`;
</script>
<section
id="hero"
style={`background: url(${backgroundImage}) center/cover no-repeat`}
>
<div class="overlay">
<h1>Preview your embroidery designs instantly — no software needed</h1>
<p>Fast, private & no signup required</p>
<a class="organic-btn" href={resolve('/viewer')}>Try Your Design</a>
</div>
</section>
<style>
#hero {
position: relative;
z-index: 0;
min-height: 100vh;
display: flex;
}
.overlay {
display: flex;
flex-direction: column;
max-width: 800px;
z-index: 1;
padding-left: 100px;
padding-top: 130px;
}
h1 {
font-size: clamp(3.5rem, 4vw, 3.5rem);
font-weight: 700;
margin-bottom: 1rem;
line-height: 1.2;
}
p {
font-size: 1.5rem;
margin-bottom: 2rem;
}
.organic-btn {
background: var(--color-primary);
width: fit-content;
color: white;
border: none;
padding: 20px 60px;
font-size: 16px;
cursor: pointer;
border-radius: 58% 42% 65% 27% / 40% 60% 60% 70%;
border: 1px solid var(--color-primary);
transition: all 0.3s ease;
}
.organic-btn:hover {
color: var(--color-primary);
background-color: #ffffff;
border: 1px solid var(--color-primary);
}
@media (max-width: 1350px) {
h1 {
font-size: clamp(3.3rem, 4vw, 3.3rem);
}
}
@media (max-width: 1280px) {
h1 {
font-size: clamp(3rem, 4vw, 3rem);
}
p {
font-size: 1.1rem;
}
}
@media (max-width: 1180px) {
h1 {
font-size: clamp(3rem, 4vw, 3rem);
}
}
@media (max-width: 768px) {
h1 {
font-size: clamp(2rem, 4vw, 2rem);
}
p {
margin-top: 0;
}
#hero {
background-size: contain !important;
background-position: bottom !important;
}
.overlay {
width: 100%;
padding-top: 100px;
padding-left: 0;
height: 100vh;
padding-left: 20px;
padding-right: 20px;
}
}
</style>

47
src/lib/styles/fonts.css Normal file
View file

@ -0,0 +1,47 @@
@font-face {
font-family: 'Merienda';
font-display: swap;
src:
url('/fonts/merienda.regular.woff2') format('woff2'),
url('/fonts/merienda.regular.woff') format('woff');
font-weight: 400;
font-style: normal;
font-display: swap;
font-optical-sizing: auto;
}
@font-face {
font-family: 'Merienda';
font-display: swap;
src:
url('/fonts/merienda.medium.woff2') format('woff2'),
url('/fonts/merienda.medium.woff') format('woff');
font-weight: 500;
font-style: normal;
font-display: swap;
font-optical-sizing: auto;
}
@font-face {
font-family: 'Merienda';
font-display: swap;
src:
url('/fonts/merienda.semi-bold.woff2') format('woff2'),
url('/fonts/merienda.semi-bold.woff') format('woff');
font-weight: 600;
font-style: normal;
font-display: swap;
font-optical-sizing: auto;
}
@font-face {
font-family: 'Merienda';
font-display: swap;
src:
url('/fonts/merienda.bold.woff2') format('woff2'),
url('/fonts/merienda.bold.woff') format('woff');
font-weight: 700;
font-style: normal;
font-display: swap;
font-optical-sizing: auto;
}

74
src/lib/styles/global.css Normal file
View file

@ -0,0 +1,74 @@
:root {
font-family: 'Merienda', cursive;
font-size: 16px;
line-height: 24px;
font-weight: 400;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}
* {
box-sizing: border-box;
}
body {
display: flex;
justify-content: center;
flex-direction: column;
margin: 0;
width: 100%;
height: 100%;
}
#app {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
background-color: #f2f6f5;
z-index: 10;
}
input[type='submit'] {
width: 100%;
font-size: 20px;
margin-top: 20px;
background-color: #05345f;
font-weight: 700;
color: white;
padding: 10px;
-webkit-appearance: none;
border-radius: 0;
}
input[type='submit']:hover {
cursor: pointer;
background-color: black;
color: white;
}
body a {
text-decoration: none;
color: #06345f;
border-bottom: 3px solid #06345f;
}
body a:hover {
background-color: #06345f;
color: #ffffff;
}
:is(h1, h2, h3, h4, h5, h6) {
color: #06345f;
}
strong {
color: #06345f;
}
ul li::marker {
color: #06345f;
}

View file

@ -0,0 +1,5 @@
:root {
--color-primary: #06345f;
--font-base: 'Merienda';
}

View file

@ -0,0 +1,9 @@
import { browser } from '$app/environment';
export const isMobile = () => {
if (browser) {
return window.matchMedia('only screen and (max-width: 768px)').matches;
} else {
return null;
}
};

View file

@ -1,4 +1,8 @@
<script>
import '$lib/styles/fonts.css';
import '$lib/styles/variables.css';
import '$lib/styles/global.css';
import { browser } from '$app/environment';
import { onMount } from 'svelte';
@ -6,9 +10,9 @@
import Footer from '$lib/components/Footer.svelte';
import Analytics from '$lib/components/Analytics.svelte';
let { children } = $props();
let { children } = $props();
let mounted = $state(false);
let mounted = $state(false);
if (browser) {
onMount(() => {
@ -22,7 +26,7 @@
{#if mounted}
<Header />
<main>
{@render children()}
{@render children()}
</main>
<Footer />
{/if}

View file

@ -1,85 +1,22 @@
<script>
// @ts-nocheck
// @ts-nocheck
import { applyAction, enhance } from '$app/forms';
import { invalidateAll } from '$app/navigation';
import { t, locale, SUPPORTED_LOCALES } from '$lib/translations';
import { t } from '$lib/translations';
import { resolve } from '$app/paths';
import Seo from '$lib/components/Seo.svelte';
import appScreenshot from '$lib/assets/app-with-frame.png';
import appScreenshotPt from '$lib/assets/app-with-frame-pt.png';
import Hero from '$lib/sections/Hero.svelte';
let { data } = $props();
/**
* @type {{ textColor: String; message: String; } | null}
*/
let feedbackMessage = $state(null);
/**
* @type {boolean}
*/
let loading = $state(false);
// svelte-ignore state_referenced_locally
const metadata = data.metadata;
const resetFeedback = () => {
if (feedbackMessage) feedbackMessage = null
}
const metadata = data.metadata;
</script>
<Seo {...metadata} />
<!-- eslint-disable svelte/no-at-html-tags -->
<div class="beta-section">
<div class="beta-content">
<div class="beta-image">
<img src={$locale === SUPPORTED_LOCALES.EN_US ? appScreenshot : appScreenshotPt} alt="Embroidery Viewer App Screenshot" />
</div>
<div class="beta-text">
<h1>{$t("home.banner.title")}</h1>
<p class="lead">
{@html $t('home.banner.subtitle')}
</p>
<p>
{$t('home.banner.description')}
</p>
<form
action="/"
method="POST"
class="beta-form"
use:enhance={() => {
loading = true;
return async ({ result }) => {
loading = false;
feedbackMessage = result.data;
if (result.type === 'success') await invalidateAll();
applyAction(result);
};
}}>
<label for="name">{$t("home.banner.name")}</label>
<input type="text" name="name" id="name" oninput={resetFeedback} required />
<label for="email">{$t("home.banner.email")}</label>
<input type="email" name="email" id="email" oninput={resetFeedback} required />
<button type="submit">{$t(loading ? 'home.banner.cta.loading' : 'home.banner.cta') }</button>
{#if feedbackMessage !== null}
<p style="margin-top: 1rem; color: {feedbackMessage.textColor}">
{$t(feedbackMessage.message)}
</p>
{/if}
</form>
</div>
</div>
</div>
<Hero />
<div class="home-container">
<section aria-labelledby="main-title">
@ -106,7 +43,7 @@
<h2 id="donation-title">{$t('home.donation.title')}</h2>
{@html $t('home.donation.description')}
<p>
<a href={resolve("/donate")} class="button">{$t('home.donation.cta')}</a>
<a href={resolve('/donate')} class="button">{$t('home.donation.cta')}</a>
{$t('home.donation.cta.description')}
</p>
</section>
@ -115,57 +52,13 @@
<section aria-labelledby="cta-title">
<h2 id="cta-title">{$t('home.cta.title')}</h2>
<p>
<a href={resolve("/viewer")} class="button">{$t('home.cta.cta')}</a>
<a href={resolve('/viewer')} class="button">{$t('home.cta.cta')}</a>
{@html $t('home.cta.cta.description')}
</p>
</section>
</div>
<style>
.beta-form {
background: white;
color: #000;
padding: 1.5rem;
border-radius: 10px;
max-width: 400px;
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
}
.beta-form label {
display: block;
margin-top: 1rem;
font-weight: bold;
}
.beta-form input {
width: 100%;
padding: 0.6rem;
margin-top: 0.3rem;
border: 1px solid #ccc;
border-radius: 6px;
}
.beta-form button {
margin-top: 1.5rem;
width: 100%;
background-color: #05345f;
color: white;
border: none;
padding: 0.8rem;
font-size: 1rem;
border-radius: 6px;
cursor: pointer;
}
.beta-form button:disabled {
background-color: #7aa3c1;
cursor: wait;
}
.beta-form button:hover:enabled {
background-color: #042b4f;
}
.home-container {
margin: 0 auto;
width: 70%;
@ -177,97 +70,4 @@
width: 90%;
}
}
.beta-section {
background-color: #05345f;
color: white;
padding: 3rem 1rem;
display: flex;
justify-content: center;
}
.beta-content {
display: flex;
flex-wrap: wrap;
gap: 2rem;
max-width: 1000px;
align-items: center;
width: 100%;
}
.beta-image img {
max-width: 300px;
border-radius: 1rem;
}
.beta-text {
flex: 1;
min-width: 280px;
}
.beta-text h1 {
font-size: 2rem;
margin-bottom: 0.5rem;
color: white;
}
.beta-text .lead {
font-size: 1.2rem;
margin-bottom: 1rem;
font-weight: 500;
}
.beta-text p {
margin-bottom: 1rem;
line-height: 1.5;
}
.beta-form {
background: white;
color: #000;
padding: 1.5rem;
border-radius: 10px;
max-width: 400px;
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
}
.beta-form label {
display: block;
margin-top: 1rem;
font-weight: bold;
}
.beta-form input {
width: 100%;
padding: 0.6rem;
margin-top: 0.3rem;
border: 1px solid #ccc;
border-radius: 6px;
}
.beta-form button {
margin-top: 1.5rem;
width: 100%;
background-color: #05345f;
color: white;
border: none;
padding: 0.8rem;
font-size: 1rem;
border-radius: 6px;
cursor: pointer;
}
.beta-form button:hover {
background-color: #042b4f;
}
@media (max-width: 768px) {
.beta-content {
flex-direction: column;
align-items: center;
}
.beta-form {
margin: 0 auto;
}
}
</style>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -17,6 +17,9 @@ const config = {
prerender: {
origin: 'https://embroideryviewer.xyz',
},
env: {
publicPrefix: 'PUBLIC_',
},
};
export default config;