Create pages to increase organic traffic #43

Merged
leomurca merged 6 commits from increase-traffic into main 2026-05-17 18:05:07 +00:00
11 changed files with 640 additions and 3187 deletions
Showing only changes of commit 7b58f43bb1 - Show all commits

3174
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -36,6 +36,7 @@
<h1>{$t('footer.resources')}</h1>
<nav class="social-container" aria-label="Social media">
<a href={resolve('/about')}>{$t('footer.about')}</a>
<a href={resolve('/pes-file-viewer')}>{$t('footer.pesViewer')}</a>
<a href={resolve('/privacy-policy')}>{$t('footer.privacy.policy')}</a>
<a href={resolve('/terms-of-service')}
>{$t('footer.terms.of.service')}</a

View file

@ -28,6 +28,9 @@
/** @type {string} Optional override for Open Graph description */
export let ogDescription = description;
/** @type {string | undefined} Optional Open Graph image URL (translation key or absolute URL) */
export let ogImage = undefined;
/** @type {string} Twitter card type */
export let twitterCard = 'summary_large_image';
@ -40,7 +43,7 @@
* =========================
*/
let image = `${PUBLIC_IMAGE_BASE_URL}/t/f_webp/embroidery-viewer/logo-icon.webp`;
let defaultImage = `${PUBLIC_IMAGE_BASE_URL}/t/f_webp/embroidery-viewer/logo-icon.webp`;
// Translations (avoid repeating $t everywhere)
$: translatedTitle = title ? $t(title) : '';
@ -52,6 +55,18 @@
? $t(ogDescription)
: translatedDescription;
$: ogImageUrl = ogImage
? ogImage.startsWith('http')
? ogImage
: $t(ogImage)
: defaultImage;
$: canonicalUrl = url
? url.startsWith('http')
? url
: $t(url)
: '';
// Locale formatting (e.g., en-US -> en_US)
$: ogLocale = normalizeLocaleUnderscore($locale);
@ -64,6 +79,9 @@
<title>{translatedTitle}</title>
<meta name="description" content={translatedDescription} />
<meta name="keywords" content={translatedKeywords} />
{#if canonicalUrl}
<link rel="canonical" href={canonicalUrl} />
{/if}
<!-- Robots -->
<meta name="robots" content={robotsContent} />
@ -73,8 +91,8 @@
<meta property="og:type" content={ogType} />
<meta property="og:title" content={translatedTitle} />
<meta property="og:description" content={finalOgDescription} />
<meta property="og:image" content={image} />
<meta property="og:url" content={url} />
<meta property="og:image" content={ogImageUrl} />
<meta property="og:url" content={canonicalUrl} />
<meta property="og:locale" content={ogLocale} />
<meta property="og:site_name" content="Embroidery Viewer" />
@ -82,7 +100,7 @@
<meta name="twitter:card" content={twitterCard} />
<meta name="twitter:title" content={translatedTitle} />
<meta name="twitter:description" content={finalOgDescription} />
<meta name="twitter:image" content={image} />
<meta name="twitter:image" content={ogImageUrl} />
<!-- Optional: improves link previews in some platforms -->
<meta property="og:image:alt" content={translatedTitle} />

View file

@ -0,0 +1,11 @@
<script>
/**
* JSON-LD structured data for SEO (FAQPage, WebApplication).
* @type {Record<string, unknown> | Record<string, unknown>[]}
*/
export let data;
</script>
<svelte:head>
{@html `<script type="application/ld+json">${JSON.stringify(data)}</script>`}
</svelte:head>

View file

@ -8,6 +8,7 @@
"aria-label": "Back to top of the page"
},
"about": "About",
"pesViewer": "PES File Viewer",
"privacy.policy": "Privacy Policy",
"terms.of.service": "Terms of Service",
"copyright": "Copyright © {{year}} <a href=\"{{website}}\" target=\"_blank\" rel=\"noreferrer\">Leonardo Murça</a>. All rights reserved.",

View file

@ -0,0 +1,90 @@
{
"seo.title": "Free PES File Viewer Online — Open Embroidery Files Instantly",
"seo.description": "Open PES files online for free. Preview Brother embroidery designs in your browser — no install, no upload to servers. Also supports DST, JEF, EXP & PEC.",
"seo.keywords": "open PES file online, PES viewer, PES file viewer, free PES viewer, embroidery file viewer, how to view embroidery files, DST viewer, convert PES to DST, what is a JEF file, Brother embroidery file, online embroidery preview",
"seo.url": "https://embroideryviewer.xyz/pes-file-viewer",
"seo.image": "https://embroideryviewer.xyz/og/pes-viewer.png",
"hero.tagline": "Free · Private · No signup",
"hero.title": "Free PES File Viewer Online — Open Embroidery Files Instantly",
"hero.subtitle": "Preview stitch paths, colors, and dimensions in your browser — free, private, and no signup. Works with Brother machines and most home embroidery software.",
"hero.cta": "Try Your Design",
"whatIs.title": "What is a PES file?",
"whatIs.p1": "A <strong>PES file</strong> (.pes) is a proprietary embroidery format created by <strong>Brother</strong> and used by many home embroidery machines — including Brother, Babylock, Bernina (with conversion), and others that accept PES.",
"whatIs.p2": "Inside a PES file you will find stitch coordinates, color-change commands, jump/trim instructions, and a color palette. PES is one of the most common formats for downloadable embroidery designs on Etsy, Creative Fabrica, and embroidery forums.",
"whatIs.p3": "PES files often travel with a companion <strong>.pec</strong> file (older palette/stitch container). Embroidery Viewer reads both so you can preview designs without installing Wilcom, PE-Design, or Embrilliance.",
"howTo.title": "How to view embroidery files online",
"howTo.step1": "Open the <strong>free embroidery viewer</strong> in your browser.",
"howTo.step2": "Click <strong>Choose files</strong> or drag your .pes, .dst, .jef, .exp, or .pec file into the drop zone.",
"howTo.step3": "Click <strong>Render files</strong> to generate a stitch preview on screen.",
"howTo.step4": "Review colors, stitch count, and dimensions — then download a PNG if you need a reference image.",
"formats.title": "Embroidery file formats we support",
"formats.intro": "Looking for a DST viewer or wondering what a JEF file is? Here is a quick comparison of the formats Embroidery Viewer opens in your browser:",
"formats.table.headers": {
"format": "Format",
"extension": "Extension",
"machines": "Common machines",
"notes": "Notes"
},
"formats.rows.pes.format": "PES / PEC",
"formats.rows.pes.extension": ".pes, .pec",
"formats.rows.pes.machines": "Brother, Babylock",
"formats.rows.pes.notes": "Most popular for home embroidery downloads",
"formats.rows.dst.format": "DST",
"formats.rows.dst.extension": ".dst",
"formats.rows.dst.machines": "Commercial & many home brands",
"formats.rows.dst.notes": "Industry-standard; limited colors in file",
"formats.rows.jef.format": "JEF",
"formats.rows.jef.extension": ".jef",
"formats.rows.jef.machines": "Janome, Elna, Kenmore",
"formats.rows.jef.notes": "Janome's native format",
"formats.rows.exp.format": "EXP",
"formats.rows.exp.extension": ".exp",
"formats.rows.exp.machines": "Melco, Bernina (export)",
"formats.rows.exp.notes": "Simple stitch list, widely supported",
"convert.title": "Can I convert PES to DST online?",
"convert.p1": "Embroidery Viewer is a <strong>preview tool</strong>, not a file converter. It lets you open a PES file online and see exactly how the design stitches out — stitch paths, color stops, and size — before you load it on your machine.",
"convert.p2": "To convert PES to DST you will need dedicated embroidery software (Wilcom, Hatch, Embrilliance, Ink/Stitch, etc.) or your machine's included editor. After converting, you can return here to preview the DST file for free.",
"screenshots.title": "See your embroidery design before you stitch",
"screenshots.intro": "Preview stitch paths, color layers, and dimensions without installing desktop software.",
"screenshots.viewer.alt": "Embroidery Viewer showing a PES file preview with stitch paths and colors",
"screenshots.hero.alt": "Drag and drop interface for opening PES embroidery files online",
"faq.title": "Frequently asked questions about PES & embroidery files",
"faq.intro": "Answers to the questions embroiderers search for most — from opening PES online to understanding JEF and DST files.",
"faq.items": {
"openPesOnline": {
"summary": "How can I open a PES file online?",
"description": "Use the free viewer on this page: drag your .pes file into the drop zone and click Render files. Embroidery Viewer runs entirely in your browser — no Brother software or Windows-only tools required."
},
"dstViewer": {
"summary": "Is there a free DST viewer online?",
"description": "Yes. Embroidery Viewer opens DST files the same way as PES — upload or drag the file, then preview stitches and dimensions. DST is common for commercial machines and many home brands that accept universal formats."
},
"howToView": {
"summary": "How do I view embroidery files without software?",
"description": "Open embroideryviewer.xyz in any modern browser (Chrome, Safari, Firefox, Edge). Supported formats include PES, DST, JEF, EXP, and PEC. Your files are processed locally and never sent to a server."
},
"convertPesDst": {
"summary": "How do I convert PES to DST?",
"description": "Conversion requires embroidery editing software — for example Embrilliance, Hatch, or Ink/Stitch (free). Export or save as DST, then use Embroidery Viewer to preview the result online before stitching."
},
"whatIsJef": {
"summary": "What is a JEF file?",
"description": "JEF (.jef) is Janome's native embroidery format. It stores stitches and thread colors for Janome, Elna, and compatible machines. You can open and preview JEF files here alongside PES and DST."
},
"embroideryViewer": {
"summary": "What is the best free embroidery file viewer?",
"description": "Embroidery Viewer is built for quick, private previews: no account, no install, no upload. It supports the formats most home embroiderers use daily and works on desktop and mobile browsers."
},
"isSafe": {
"summary": "Is it safe to open my embroidery files here?",
"description": "Yes. Files are read and rendered inside your browser using JavaScript. They are not uploaded, stored, or shared with any server."
},
"mobile": {
"summary": "Can I open PES files on my phone?",
"description": "Yes, on modern mobile browsers. Tap Choose files, select your .pes from Files or cloud storage, and tap Render files to preview."
}
},
"cta.title": "Ready to preview your design?",
"cta.subtitle": "Open PES, DST, JEF, EXP, or PEC files in seconds — free and private.",
"cta.button": "Try Your Design"
}

View file

@ -73,6 +73,13 @@ const config = {
routes: ['/viewer'],
loader: async () => (await import('./en-US/viewer.json')).default,
},
{
locale: SUPPORTED_LOCALES.EN_US,
key: 'pes-file-viewer',
routes: ['/pes-file-viewer'],
loader: async () =>
(await import('./en-US/pes-file-viewer.json')).default,
},
{
locale: SUPPORTED_LOCALES.PT_BR,
key: 'header',
@ -127,6 +134,13 @@ const config = {
routes: ['/viewer'],
loader: async () => (await import('./pt-BR/viewer.json')).default,
},
{
locale: SUPPORTED_LOCALES.PT_BR,
key: 'pes-file-viewer',
routes: ['/pes-file-viewer'],
loader: async () =>
(await import('./pt-BR/pes-file-viewer.json')).default,
},
{
locale: SUPPORTED_LOCALES.PT_BR,
key: 'hero',

View file

@ -8,6 +8,7 @@
"aria-label": "Voltar ao topo da página"
},
"about": "Sobre",
"pesViewer": "Visualizador PES",
"privacy.policy": "Política de Privacidade",
"terms.of.service": "Termos de Serviço",
"copyright": "Copyright © {{year}} <a href=\"{{website}}/pt-br\" target=\"_blank\" rel=\"noreferrer\">Leonardo Murça</a>. Todos os direitos reservados.",

View file

@ -0,0 +1,90 @@
{
"seo.title": "Visualizador de Arquivos PES Online Grátis — Abra Bordados na Hora",
"seo.description": "Abra arquivos PES online gratuitamente. Visualize bordados Brother no navegador — sem instalar, sem enviar para servidores. Também suporta DST, JEF, EXP e PEC.",
"seo.keywords": "abrir arquivo PES online, visualizador PES, visualizador de bordado, como ver arquivo de bordado, visualizador DST, converter PES para DST, o que é arquivo JEF, arquivo Brother bordado, preview bordado online",
"seo.url": "https://embroideryviewer.xyz/pes-file-viewer",
"seo.image": "https://embroideryviewer.xyz/og/pes-viewer.png",
"hero.tagline": "Grátis · Privado · Sem cadastro",
"hero.title": "Visualizador de Arquivos PES Online Grátis — Abra Bordados na Hora",
"hero.subtitle": "Veja caminhos de pontos, cores e dimensões no navegador — grátis, privado e sem cadastro. Funciona com máquinas Brother e a maioria dos softwares domésticos.",
"hero.cta": "Experimente seu desenho",
"whatIs.title": "O que é um arquivo PES?",
"whatIs.p1": "Um <strong>arquivo PES</strong> (.pes) é um formato de bordado proprietário criado pela <strong>Brother</strong> e usado por muitas máquinas domésticas — incluindo Brother, Babylock, Bernina (com conversão) e outras que aceitam PES.",
"whatIs.p2": "Dentro de um PES há coordenadas de pontos, comandos de troca de cor, saltos/aparos e uma paleta de cores. É um dos formatos mais comuns em downloads do Etsy, Creative Fabrica e fóruns de bordado.",
"whatIs.p3": "Arquivos PES costumam vir com um <strong>.pec</strong> complementar (container mais antigo). O Embroidery Viewer lê ambos para você visualizar sem instalar Wilcom, PE-Design ou Embrilliance.",
"howTo.title": "Como visualizar arquivos de bordado online",
"howTo.step1": "Abra o <strong>visualizador de bordado gratuito</strong> no navegador.",
"howTo.step2": "Clique em <strong>Escolher arquivos</strong> ou arraste .pes, .dst, .jef, .exp ou .pec para a área de soltar.",
"howTo.step3": "Clique em <strong>Renderizar arquivos</strong> para gerar a prévia na tela.",
"howTo.step4": "Revise cores, contagem de pontos e dimensões — e baixe um PNG se precisar de referência.",
"formats.title": "Formatos de bordado suportados",
"formats.intro": "Procura um visualizador DST ou quer saber o que é um JEF? Comparação rápida dos formatos que o Embroidery Viewer abre no navegador:",
"formats.table.headers": {
"format": "Formato",
"extension": "Extensão",
"machines": "Máquinas comuns",
"notes": "Observações"
},
"formats.rows.pes.format": "PES / PEC",
"formats.rows.pes.extension": ".pes, .pec",
"formats.rows.pes.machines": "Brother, Babylock",
"formats.rows.pes.notes": "Mais popular em downloads domésticos",
"formats.rows.dst.format": "DST",
"formats.rows.dst.extension": ".dst",
"formats.rows.dst.machines": "Comercial e várias domésticas",
"formats.rows.dst.notes": "Padrão da indústria; cores limitadas no arquivo",
"formats.rows.jef.format": "JEF",
"formats.rows.jef.extension": ".jef",
"formats.rows.jef.machines": "Janome, Elna, Kenmore",
"formats.rows.jef.notes": "Formato nativo Janome",
"formats.rows.exp.format": "EXP",
"formats.rows.exp.extension": ".exp",
"formats.rows.exp.machines": "Melco, Bernina (exportação)",
"formats.rows.exp.notes": "Lista simples de pontos, amplamente suportado",
"convert.title": "Posso converter PES para DST online?",
"convert.p1": "O Embroidery Viewer é uma <strong>ferramenta de prévia</strong>, não um conversor. Ele permite abrir PES online e ver como o desenho será bordado — pontos, paradas de cor e tamanho — antes de carregar na máquina.",
"convert.p2": "Para converter PES em DST use software de bordado (Wilcom, Hatch, Embrilliance, Ink/Stitch, etc.) ou o editor da sua máquina. Depois volte aqui para visualizar o DST gratuitamente.",
"screenshots.title": "Veja o bordado antes de costurar",
"screenshots.intro": "Visualize pontos, cores e dimensões sem instalar software no computador.",
"screenshots.viewer.alt": "Embroidery Viewer exibindo prévia de arquivo PES com pontos e cores",
"screenshots.hero.alt": "Interface de arrastar e soltar para abrir arquivos PES de bordado online",
"faq.title": "Perguntas frequentes sobre PES e arquivos de bordado",
"faq.intro": "Respostas às dúvidas mais buscadas — de abrir PES online a entender JEF e DST.",
"faq.items": {
"openPesOnline": {
"summary": "Como abrir um arquivo PES online?",
"description": "Use o visualizador gratuito nesta página: arraste o .pes para a área e clique em Renderizar arquivos. Tudo roda no navegador — sem software Brother ou ferramentas só para Windows."
},
"dstViewer": {
"summary": "Existe visualizador DST online grátis?",
"description": "Sim. O Embroidery Viewer abre DST como PES — envie ou arraste o arquivo e veja pontos e dimensões. DST é comum em máquinas comerciais e muitas domésticas."
},
"howToView": {
"summary": "Como ver arquivos de bordado sem software?",
"description": "Abra embroideryviewer.xyz em qualquer navegador moderno. Formatos: PES, DST, JEF, EXP e PEC. Os arquivos são processados localmente e nunca enviados a um servidor."
},
"convertPesDst": {
"summary": "Como converter PES para DST?",
"description": "A conversão exige software de edição — Embrilliance, Hatch ou Ink/Stitch (grátis). Exporte como DST e use o Embroidery Viewer para prévia online antes de bordar."
},
"whatIsJef": {
"summary": "O que é um arquivo JEF?",
"description": "JEF (.jef) é o formato nativo da Janome. Armazena pontos e cores para Janome, Elna e compatíveis. Você pode abrir e visualizar JEF aqui junto com PES e DST."
},
"embroideryViewer": {
"summary": "Qual o melhor visualizador gratuito de bordado?",
"description": "O Embroidery Viewer foi feito para prévias rápidas e privadas: sem conta, sem instalação, sem upload. Suporta os formatos mais usados e funciona no celular e no desktop."
},
"isSafe": {
"summary": "É seguro abrir meus arquivos aqui?",
"description": "Sim. Os arquivos são lidos e renderizados no navegador com JavaScript. Não são enviados, armazenados nem compartilhados com servidores."
},
"mobile": {
"summary": "Posso abrir PES no celular?",
"description": "Sim, em navegadores móveis modernos. Toque em Escolher arquivos, selecione o .pes e toque em Renderizar arquivos."
}
},
"cta.title": "Pronto para ver seu desenho?",
"cta.subtitle": "Abra PES, DST, JEF, EXP ou PEC em segundos — grátis e privado.",
"cta.button": "Experimente seu desenho"
}

View file

@ -0,0 +1,400 @@
<script>
import { resolve } from '$app/paths';
import { PUBLIC_IMAGE_BASE_URL } from '$env/static/public';
import { t, locale } from '$lib/translations';
import Head from '$lib/components/Head.svelte';
import StructuredData from '$lib/components/StructuredData.svelte';
const NS = 'pes-file-viewer';
const baseUrl = 'https://embroideryviewer.xyz/pes-file-viewer';
const pesFilePreview = `${PUBLIC_IMAGE_BASE_URL}/t/f_webp,w_800/embroidery-viewer/${$locale}/pes-file-preview.webp`;
const viewerInterface = `${PUBLIC_IMAGE_BASE_URL}/t/f_webp,w_800/embroidery-viewer/${$locale}/viewer-interface.webp`;
const faqKeys = [
'openPesOnline',
'dstViewer',
'howToView',
'convertPesDst',
'whatIsJef',
'embroideryViewer',
'isSafe',
'mobile',
];
$: faqStructuredData = {
'@context': 'https://schema.org',
'@type': 'FAQPage',
mainEntity: faqKeys.map((key) => ({
'@type': 'Question',
name: $t(`${NS}.faq.items.${key}.summary`),
acceptedAnswer: {
'@type': 'Answer',
text: $t(`${NS}.faq.items.${key}.description`),
},
})),
};
$: webAppStructuredData = {
'@context': 'https://schema.org',
'@type': 'WebApplication',
name: 'Embroidery Viewer — PES File Viewer',
url: baseUrl,
applicationCategory: 'DesignApplication',
operatingSystem: 'Any',
offers: {
'@type': 'Offer',
price: '0',
priceCurrency: 'USD',
},
description: $t(`${NS}.seo.description`),
featureList: 'PES, DST, JEF, EXP, PEC embroidery file preview',
};
$: howToStructuredData = {
'@context': 'https://schema.org',
'@type': 'HowTo',
name: $t(`${NS}.howTo.title`),
step: ['step1', 'step2', 'step3', 'step4'].map((step, i) => ({
'@type': 'HowToStep',
position: i + 1,
text: $t(`${NS}.howTo.${step}`),
})),
};
</script>
<Head
title={`${NS}.seo.title`}
description={`${NS}.seo.description`}
keywords={`${NS}.seo.keywords`}
url={`${NS}.seo.url`}
ogImage={`${NS}.seo.image`}
/>
<StructuredData
data={[faqStructuredData, webAppStructuredData, howToStructuredData]}
/>
<section class="hero" aria-labelledby="pes-hero-heading">
<p class="tagline">{$t(`${NS}.hero.tagline`)}</p>
<h1 id="pes-hero-heading">{$t(`${NS}.hero.title`)}</h1>
<p class="hero-subtitle">{$t(`${NS}.hero.subtitle`)}</p>
<a class="organic-btn" href={resolve('/viewer')}>{$t(`${NS}.hero.cta`)}</a>
</section>
<article id="what-is-pes" class="content-section">
<h2>{$t(`${NS}.whatIs.title`)}</h2>
<!-- eslint-disable svelte/no-at-html-tags -->
<p>{@html $t(`${NS}.whatIs.p1`)}</p>
<p>{@html $t(`${NS}.whatIs.p2`)}</p>
<p>{@html $t(`${NS}.whatIs.p3`)}</p>
</article>
<article id="how-to-view" class="content-section alt">
<h2>{$t(`${NS}.howTo.title`)}</h2>
<ol class="steps">
{#each ['step1', 'step2', 'step3', 'step4'] as step (step)}
<li>{@html $t(`${NS}.howTo.${step}`)}</li>
{/each}
</ol>
</article>
<article id="formats" class="content-section">
<h2>{$t(`${NS}.formats.title`)}</h2>
<p>{$t(`${NS}.formats.intro`)}</p>
<div class="table-wrap">
<table>
<thead>
<tr>
<th>{$t(`${NS}.formats.table.headers.format`)}</th>
<th>{$t(`${NS}.formats.table.headers.extension`)}</th>
<th>{$t(`${NS}.formats.table.headers.machines`)}</th>
<th>{$t(`${NS}.formats.table.headers.notes`)}</th>
</tr>
</thead>
<tbody>
{#each ['pes', 'dst', 'jef', 'exp'] as row (row)}
<tr>
<td>{$t(`${NS}.formats.rows.${row}.format`)}</td>
<td>{$t(`${NS}.formats.rows.${row}.extension`)}</td>
<td>{$t(`${NS}.formats.rows.${row}.machines`)}</td>
<td>{$t(`${NS}.formats.rows.${row}.notes`)}</td>
</tr>
{/each}
</tbody>
</table>
</div>
</article>
<article id="convert-pes-dst" class="content-section alt">
<h2>{$t(`${NS}.convert.title`)}</h2>
<p>{@html $t(`${NS}.convert.p1`)}</p>
<p>{@html $t(`${NS}.convert.p2`)}</p>
</article>
<section
id="screenshots"
class="screenshots-section"
aria-labelledby="screenshots-heading"
>
<h2 id="screenshots-heading">{$t(`${NS}.screenshots.title`)}</h2>
<p class="screenshots-intro">{$t(`${NS}.screenshots.intro`)}</p>
<div class="screenshot-grid">
<figure>
<img
src={pesFilePreview}
width="800"
height="600"
loading="lazy"
alt={$t(`${NS}.screenshots.viewer.alt`)}
/>
<figcaption>{$t(`${NS}.screenshots.viewer.alt`)}</figcaption>
</figure>
<figure>
<img
src={viewerInterface}
width="800"
height="533"
loading="lazy"
alt={$t(`${NS}.screenshots.hero.alt`)}
/>
<figcaption>{$t(`${NS}.screenshots.hero.alt`)}</figcaption>
</figure>
</div>
</section>
<section id="faq" class="faq-section" aria-labelledby="faq-heading">
<h2 id="faq-heading">{$t(`${NS}.faq.title`)}</h2>
<p class="faq-intro">{$t(`${NS}.faq.intro`)}</p>
<div class="faq-list">
{#each faqKeys as key (key)}
<details>
<summary>{$t(`${NS}.faq.items.${key}.summary`)}</summary>
<p>{$t(`${NS}.faq.items.${key}.description`)}</p>
</details>
{/each}
</div>
</section>
<section class="cta-section" aria-labelledby="cta-heading">
<h2 id="cta-heading">{$t(`${NS}.cta.title`)}</h2>
<p>{$t(`${NS}.cta.subtitle`)}</p>
<a class="organic-btn-secondary" href={resolve('/viewer')}>
{$t(`${NS}.cta.button`)}
</a>
</section>
<style>
.hero {
padding: 140px 24px 80px;
text-align: center;
max-width: 900px;
margin: 0 auto;
}
.tagline {
text-transform: uppercase;
letter-spacing: 0.12em;
font-size: 0.85rem;
color: var(--color-primary);
margin-bottom: 12px;
}
.hero h1 {
font-size: clamp(1.75rem, 4vw, 2.5rem);
line-height: 1.25;
margin: 0 0 1rem;
}
.hero-subtitle {
font-size: 1.1rem;
line-height: 1.6;
max-width: 720px;
margin: 0 auto 1.5rem;
color: #333;
}
.hero .organic-btn {
display: block;
margin: 0 auto;
margin-top: 40px;
}
.content-section {
max-width: 800px;
margin: 0 auto;
padding: 48px 24px;
line-height: 1.7;
}
.content-section.alt {
background: rgba(6, 52, 95, 0.04);
max-width: none;
padding-left: max(24px, calc((100% - 800px) / 2));
padding-right: max(24px, calc((100% - 800px) / 2));
}
.content-section h2 {
margin-top: 0;
font-size: 1.75rem;
}
.steps {
padding-left: 1.25rem;
}
.steps li {
margin-bottom: 12px;
}
.table-wrap {
overflow-x: auto;
margin-top: 24px;
}
table {
width: 100%;
border-collapse: collapse;
font-size: 0.95rem;
}
th,
td {
border: 1px solid #d3dce6;
padding: 12px 14px;
text-align: left;
}
th {
background: var(--color-primary);
color: white;
}
tr:nth-child(even) {
background: #f8fafb;
}
.screenshots-section {
padding: 64px 24px;
max-width: 960px;
margin: 0 auto;
text-align: center;
}
.screenshots-intro {
margin-bottom: 32px;
line-height: 1.6;
}
.screenshot-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 32px;
}
.screenshot-grid img {
width: 100%;
height: auto;
border-radius: 12px;
border: 3px solid var(--color-primary);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
}
figcaption {
margin-top: 10px;
font-size: 0.9rem;
color: #444;
line-height: 1.4;
}
.faq-section {
padding: 64px 24px;
max-width: 800px;
margin: 0 auto;
}
.faq-section h2 {
text-align: center;
font-size: 1.75rem;
}
.faq-intro {
text-align: center;
margin-bottom: 32px;
line-height: 1.6;
}
.faq-list details {
border-bottom: 1px solid #eee;
padding: 20px 0;
}
.faq-list summary {
cursor: pointer;
font-weight: 600;
font-size: 1.1rem;
list-style: none;
position: relative;
color: var(--color-primary);
padding-right: 28px;
}
.faq-list summary::after {
content: '+';
position: absolute;
right: 0;
font-size: 1.5rem;
transition: transform 0.3s ease;
}
.faq-list details[open] summary::after {
transform: rotate(45deg);
}
.faq-list p {
margin-top: 10px;
line-height: 1.6;
}
.cta-section {
text-align: center;
padding: 64px 24px 100px;
background: var(--color-primary);
color: white;
}
.cta-section h2 {
color: white;
margin-top: 0;
}
.cta-section p {
margin-bottom: 24px;
opacity: 0.95;
}
.cta-section .organic-btn-secondary {
display: inline-block;
margin: 0 auto;
}
@media (max-width: 768px) {
.hero {
padding-top: 120px;
}
.screenshot-grid {
grid-template-columns: 1fr;
}
table {
font-size: 0.85rem;
}
th,
td {
padding: 8px;
}
}
</style>

View file

@ -2,21 +2,22 @@ export async function GET() {
const baseUrl = 'https://embroideryviewer.xyz';
const pages = [
'',
'about',
'donate',
'terms-of-service',
'privacy-policy',
'viewer',
{ path: '', priority: '0.8' },
{ path: 'pes-file-viewer', priority: '0.9' },
{ path: 'viewer', priority: '0.85' },
{ path: 'about', priority: '0.8' },
{ path: 'donate', priority: '0.8' },
{ path: 'terms-of-service', priority: '0.8' },
{ path: 'privacy-policy', priority: '0.8' },
];
const urls = pages
.map(
(page) => `
({ path, priority }) => `
<url>
<loc>${baseUrl}/${page}</loc>
<loc>${baseUrl}/${path}</loc>
<changefreq>weekly</changefreq>
<priority>0.8</priority>
<priority>${priority}</priority>
</url>`,
)
.join('');