Migrate to sveltekit #26

Merged
leomurca merged 36 commits from migrate-to-sveltekit into development 2025-06-04 21:41:44 +00:00
10 changed files with 99 additions and 76 deletions
Showing only changes of commit b4df137211 - Show all commits

View file

@ -1,15 +1,20 @@
{ {
"/": [ "/": [
"src/routes/+layout.js",
"src/routes/+layout.server.js", "src/routes/+layout.server.js",
"src/routes/+layout.js",
"src/routes/+layout.server.js" "src/routes/+layout.server.js"
], ],
"/about": [ "/about": [
"src/routes/+layout.js",
"src/routes/+layout.server.js" "src/routes/+layout.server.js"
], ],
"/donate": [ "/donate": [
"src/routes/+layout.js",
"src/routes/+layout.server.js" "src/routes/+layout.server.js"
], ],
"/viewer": [ "/viewer": [
"src/routes/+layout.js",
"src/routes/+layout.server.js" "src/routes/+layout.server.js"
] ]
} }

View file

@ -20,9 +20,11 @@ type LayoutParentData = EnsureDefined<{}>;
export type PageServerData = null; export type PageServerData = null;
export type PageData = Expand<PageParentData>; export type PageData = Expand<PageParentData>;
export type PageProps = { data: PageData } export type PageProps = { data: PageData }
export type LayoutServerLoad<OutputData extends OutputDataShape<LayoutServerParentData> = OutputDataShape<LayoutServerParentData>> = Kit.ServerLoad<LayoutParams, LayoutServerParentData, OutputData, LayoutRouteId>; export type LayoutServerLoad<OutputData extends Partial<App.PageData> & Record<string, any> | void = Partial<App.PageData> & Record<string, any> | void> = Kit.ServerLoad<LayoutParams, LayoutServerParentData, OutputData, LayoutRouteId>;
export type LayoutServerLoadEvent = Parameters<LayoutServerLoad>[0]; export type LayoutServerLoadEvent = Parameters<LayoutServerLoad>[0];
export type LayoutServerData = Expand<OptionalUnion<EnsureDefined<Kit.LoadProperties<Awaited<ReturnType<typeof import('./proxy+layout.server.js').load>>>>>>; export type LayoutServerData = Expand<OptionalUnion<EnsureDefined<Kit.LoadProperties<Awaited<ReturnType<typeof import('./proxy+layout.server.js').load>>>>>>;
export type LayoutData = Expand<Omit<LayoutParentData, keyof LayoutServerData> & EnsureDefined<LayoutServerData>>; export type LayoutLoad<OutputData extends OutputDataShape<LayoutParentData> = OutputDataShape<LayoutParentData>> = Kit.Load<LayoutParams, LayoutServerData, LayoutParentData, OutputData, LayoutRouteId>;
export type LayoutLoadEvent = Parameters<LayoutLoad>[0];
export type LayoutData = Expand<Omit<LayoutParentData, keyof Kit.LoadProperties<Awaited<ReturnType<typeof import('./proxy+layout.js').load>>>> & OptionalUnion<EnsureDefined<Kit.LoadProperties<Awaited<ReturnType<typeof import('./proxy+layout.js').load>>>>>>;
export type LayoutProps = { data: LayoutData; children: import("svelte").Snippet } export type LayoutProps = { data: LayoutData; children: import("svelte").Snippet }
export type RequestEvent = Kit.RequestEvent<RouteParams, RouteId>; export type RequestEvent = Kit.RequestEvent<RouteParams, RouteId>;

View file

@ -1,49 +0,0 @@
<div class="loading-container" role="alert" aria-live="polite" aria-busy="true">
Loading translations
<span class="dot"></span>
<span class="dot"></span>
<span class="dot"></span>
</div>
<style>
.loading-container {
display: inline-flex;
align-items: center;
gap: 0.5rem;
font-family: 'Inter', system-ui, sans-serif;
font-weight: bold;
font-size: 1rem;
color: #06345f; /* match your green */
user-select: none;
margin: 0 auto;
}
.dot {
width: 8px;
height: 8px;
background-color: #06345f;
border-radius: 50%;
animation: pulse 1.2s ease-in-out infinite;
}
.dot:nth-child(2) {
animation-delay: 0.2s;
}
.dot:nth-child(3) {
animation-delay: 0.4s;
}
@keyframes pulse {
0%,
80%,
100% {
opacity: 0.3;
transform: scale(1);
}
40% {
opacity: 1;
transform: scale(1.4);
}
}
</style>

View file

@ -0,0 +1,4 @@
{
"title": " About Embroidery Viewer",
"content": "<p>Hi there! 👋</p><p><strong>⭐️ Embroidery Viewer</strong> was born out of a simple need — helping someone I care about. 💖</p><p>My girlfriend loves embroidery, but she often struggled to find an easy and free way to preview her embroidery design files before stitching them. Most tools she tried were either paid, overly complex, or required technical knowledge — and shes not a techie.</p><p>So, to make things easier for her (and others like her), I decided to build this web application.</p><p>Over the course of a few weeks, I created <strong>Embroidery Viewer</strong> — a lightweight, fast, and free tool that lets you view embroidery files directly in your browser. No installation, no setup, and no tech hurdles. Just upload your file and see your design.</p><p>Its not a super sophisticated tool, but it solves the problem it was meant to solve: making embroidery file previews accessible to everyone.</p><p>If this tool has helped you too, that makes me really happy! I plan to continue improving it based on feedback from users like you.</p><p>Thanks for stopping by — and happy stitching! 🧵✨</p>"
}

View file

@ -17,7 +17,7 @@ export const SUPPORTED_LOCALES = Object.freeze({
/** @type {import('sveltekit-i18n').Config} */ /** @type {import('sveltekit-i18n').Config} */
const config = { const config = {
initLocale: navigator.language, initLocale: navigator.language,
fallbackLocale: SUPPORTED_LOCALES.PT_BR, fallbackLocale: SUPPORTED_LOCALES.EN_US,
loaders: [ loaders: [
{ {
locale: SUPPORTED_LOCALES.EN_US, locale: SUPPORTED_LOCALES.EN_US,
@ -32,9 +32,15 @@ const config = {
{ {
locale: SUPPORTED_LOCALES.EN_US, locale: SUPPORTED_LOCALES.EN_US,
key: 'home', key: 'home',
routes: [''], routes: ['/'],
loader: async () => (await import('./en-US/home.json')).default, loader: async () => (await import('./en-US/home.json')).default,
}, },
{
locale: SUPPORTED_LOCALES.EN_US,
key: 'about',
routes: ['/about'],
loader: async () => (await import('./en-US/about.json')).default,
},
{ {
locale: SUPPORTED_LOCALES.PT_BR, locale: SUPPORTED_LOCALES.PT_BR,
key: 'header', key: 'header',
@ -48,15 +54,27 @@ const config = {
{ {
locale: SUPPORTED_LOCALES.PT_BR, locale: SUPPORTED_LOCALES.PT_BR,
key: 'home', key: 'home',
routes: [''], routes: ['/'],
loader: async () => (await import('./pt-BR/home.json')).default, loader: async () => (await import('./pt-BR/home.json')).default,
}, },
{
locale: SUPPORTED_LOCALES.PT_BR,
key: 'about',
routes: ['/about'],
loader: async () => (await import('./pt-BR/about.json')).default,
},
], ],
}; };
export const { t, locale, locales, loading, loadTranslations } = new i18n( export const {
config, t,
); locale,
locales,
loading,
loadTranslations,
setRoute,
setLocale,
} = new i18n(config);
locale.subscribe(($locale) => { locale.subscribe(($locale) => {
if (typeof document !== 'undefined') { if (typeof document !== 'undefined') {

View file

@ -0,0 +1,4 @@
{
"title": " Sobre o Embroidery Viewer",
"content": "<p>Oi! 👋</p><p><strong>⭐️ Embroidery Viewer</strong> nasceu de uma necessidade simples — ajudar alguém que eu amo. 💖</p><p>Minha namorada adora bordado, mas ela sempre teve dificuldades para encontrar uma maneira fácil e gratuita de visualizar os arquivos de design de bordado antes de começar a costurar. A maioria das ferramentas que ela tentou eram pagas, muito complexas ou exigiam conhecimento técnico — e ela não é da área de tecnologia.</p><p>Então, para facilitar a vida dela (e de outras pessoas como ela), decidi criar este aplicativo web.</p><p>Ao longo de algumas semanas, criei o <strong>Embroidery Viewer</strong> — uma ferramenta leve, rápida e gratuita que permite visualizar arquivos de bordado diretamente no navegador. Sem instalação, sem configuração e sem obstáculos técnicos. Basta enviar o arquivo e ver o design.</p><p>Não é uma ferramenta super sofisticada, mas resolve o problema para o qual foi criada: tornar a visualização de arquivos de bordado acessível para todos.</p><p>Se essa ferramenta também te ajudou, isso me deixa muito feliz! Pretendo continuar melhorando com base no feedback de usuários como você.</p><p>Obrigado por visitar — e bons bordados! 🧵✨</p>"
}

17
src/routes/+layout.js Normal file
View file

@ -0,0 +1,17 @@
import { setLocale, setRoute } from '$lib/translations';
/**
* @typedef {Object} LayoutData
* @property {string} route
* @property {string} language
*/
/** @type {import('@sveltejs/kit').Load<LayoutData>} */
export const load = async ({ data }) => {
const { route, language } = data ?? {};
if (route) await setRoute(route);
if (language) await setLocale(language);
return data ?? {};
};

View file

@ -1,5 +1,5 @@
import { parse } from 'accept-language-parser'; import { parse } from 'accept-language-parser';
import { loadTranslations } from '$lib/translations'; import { loadTranslations, setLocale, setRoute } from '$lib/translations';
import { SUPPORTED_LOCALES } from '$lib/translations'; import { SUPPORTED_LOCALES } from '$lib/translations';
/** /**
@ -40,12 +40,15 @@ function localeFromHeader(header) {
} }
/** @type {import('@sveltejs/kit').ServerLoad}*/ /** @type {import('@sveltejs/kit').ServerLoad}*/
export async function load({ request, cookies }) { export async function load({ url, request, cookies }) {
const cookieLocale = localeFromCookies(cookies); const cookieLocale = localeFromCookies(cookies);
const headerLocale = localeFromHeader(request.headers.get('accept-language')); const headerLocale = localeFromHeader(request.headers.get('accept-language'));
const language = cookieLocale || headerLocale || SUPPORTED_LOCALES.EN_US; const language = cookieLocale || headerLocale || SUPPORTED_LOCALES.EN_US;
const route = url.pathname;
await loadTranslations(language); await loadTranslations(language, route);
setLocale(language);
setRoute(route);
return { language }; return { language, route };
} }

View file

@ -1,22 +1,13 @@
<script> <script>
import { locale, loading } from '$lib/translations';
import Header from '$lib/components/Header.svelte'; import Header from '$lib/components/Header.svelte';
import LoadingTranslations from '$lib/components/LoadingTranslations.svelte';
import Footer from '$lib/components/Footer.svelte'; import Footer from '$lib/components/Footer.svelte';
export let data;
$: locale.set(data.language);
</script> </script>
{#if !$loading && $locale !== undefined} <Header />
<Header /> <main>
<main> <slot />
<slot /> </main>
</main> <Footer />
<Footer />
{:else}
<LoadingTranslations />
{/if}
<style> <style>
main { main {

View file

@ -1 +1,29 @@
<h1>About</h1> <script>
import { t, locale } from '$lib/translations';
console.log($locale);
</script>
<section aria-labelledby="about-heading">
<h1 id="about-heading">{$t('about.title')}</h1>
{@html $t('about.content')}
</section>
<style>
section {
width: 70%;
margin: 0 auto;
}
h1 {
padding: 0;
margin-bottom: 7px;
}
@media (max-width: 768px) {
section {
width: 100%;
}
}
</style>