Attiva il form footer, API subscribe/confirm/unsubscribe e endpoint admin protetti, riusando Resend per le email. Co-authored-by: Cursor <cursoragent@cursor.com>
234 lines
8.5 KiB
Plaintext
234 lines
8.5 KiB
Plaintext
---
|
|
import { getFooter } from '../data/home';
|
|
|
|
const path = Astro.url.pathname;
|
|
const localeMatch = path.match(/^\/(en|th)(\/|$)/);
|
|
const currentLocale = (localeMatch?.[1] ?? 'it') as 'it' | 'en' | 'th';
|
|
const footer = getFooter(currentLocale);
|
|
|
|
const hasNewsletterAction =
|
|
typeof footer.newsletter.actionUrl === 'string' &&
|
|
footer.newsletter.actionUrl.length > 0;
|
|
|
|
const nl = footer.newsletter;
|
|
const nextUrl =
|
|
typeof nl.successRedirect === 'string' && nl.successRedirect.length > 0
|
|
? nl.successRedirect
|
|
: '';
|
|
const notifySubject =
|
|
typeof nl.notifySubject === 'string' && nl.notifySubject.length > 0
|
|
? nl.notifySubject
|
|
: '';
|
|
|
|
const linkClass =
|
|
'text-sm text-sky-400/90 transition-colors hover:text-sky-300';
|
|
const withLocale = (href: string) => {
|
|
if (currentLocale === 'it') return href;
|
|
if (href.startsWith(`/${currentLocale}`)) return href;
|
|
if (href.startsWith('/#')) return `/${currentLocale}${href}`;
|
|
if (href.startsWith('/')) return `/${currentLocale}${href}`;
|
|
return href;
|
|
};
|
|
---
|
|
|
|
<footer id="site-footer" class="relative z-[1] border-t border-nx-border px-4 py-12 sm:px-6">
|
|
<div class="mx-auto max-w-6xl">
|
|
<!-- Griglia link; brand + slogan spostati in fondo a fianco al copyright -->
|
|
<div class="border-b border-nx-border py-10">
|
|
<div
|
|
class="grid grid-cols-1 gap-10 sm:grid-cols-2 lg:grid-cols-4 lg:items-start lg:gap-x-10 xl:gap-x-12"
|
|
>
|
|
<div class="min-w-0">
|
|
<p
|
|
class="mb-4 text-xs font-semibold uppercase tracking-wider text-nx-fg"
|
|
>
|
|
{footer.columnTitles.sections}
|
|
</p>
|
|
<ul class="space-y-2.5">
|
|
{footer.homeNav.map((link) => (
|
|
<li>
|
|
<a class={linkClass} href={withLocale(link.href)}>
|
|
{link.label}
|
|
</a>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="min-w-0">
|
|
<p
|
|
class="mb-4 text-xs font-semibold uppercase tracking-wider text-nx-fg"
|
|
>
|
|
{footer.columnTitles.legal}
|
|
</p>
|
|
<ul class="space-y-2.5">
|
|
{footer.legalColumnNav.map((link) => (
|
|
<li>
|
|
<a class={linkClass} href={withLocale(link.href)}>
|
|
{link.label}
|
|
</a>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="min-w-0">
|
|
<p
|
|
class="mb-4 text-xs font-semibold uppercase tracking-wider text-nx-fg"
|
|
>
|
|
{footer.columnTitles.social}
|
|
</p>
|
|
<ul class="space-y-2.5 text-sm">
|
|
{footer.socialLinks.map((item) => (
|
|
<li>
|
|
{item.href ? (
|
|
<a
|
|
class={linkClass}
|
|
href={item.href}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
>
|
|
{item.label}
|
|
</a>
|
|
) : (
|
|
<span
|
|
class="cursor-not-allowed text-nx-muted opacity-50"
|
|
title={footer.labels.socialPlaceholderTitle}
|
|
>
|
|
{item.label}
|
|
</span>
|
|
)}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="min-w-0">
|
|
<p
|
|
class="mb-4 text-xs font-semibold uppercase tracking-wider text-nx-fg"
|
|
>
|
|
{footer.columnTitles.company}
|
|
</p>
|
|
<ul class="space-y-2.5">
|
|
{footer.companyNav.map((link) => (
|
|
<li>
|
|
{link.href ? (
|
|
<a class={linkClass} href={withLocale(link.href)}>
|
|
{link.label}
|
|
</a>
|
|
) : (
|
|
<span class="text-sm text-nx-muted" title={footer.labels.companyPlaceholderTitle}>
|
|
{link.label}
|
|
</span>
|
|
)}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
class="relative mt-10 grid gap-8 pt-8 before:pointer-events-none before:absolute before:left-1/2 before:top-0 before:h-px before:w-screen before:-translate-x-1/2 before:bg-nx-border/70 lg:grid-cols-[minmax(0,1fr)_minmax(0,1.2fr)] lg:items-start lg:gap-10"
|
|
data-nx-footer-print-collapsible
|
|
>
|
|
<div class="min-w-0">
|
|
<p class="text-xs font-semibold uppercase tracking-wider text-nx-fg">
|
|
{footer.labels.cookieTitle}
|
|
</p>
|
|
<p class="mt-1.5 max-w-xl text-xs leading-relaxed text-nx-muted">
|
|
{footer.cookiePreferences.hint}
|
|
</p>
|
|
<button
|
|
type="button"
|
|
class="mt-3 inline-flex h-10 shrink-0 items-center justify-center self-start rounded-lg border border-nx-border bg-nx-bg/50 px-4 text-sm font-medium text-sky-400/90 transition-colors hover:border-sky-500/35 hover:bg-sky-500/5 hover:text-sky-300"
|
|
data-nx-cc-open
|
|
>
|
|
{footer.cookiePreferences.label}
|
|
</button>
|
|
</div>
|
|
|
|
<div class="min-w-0">
|
|
<p class="text-xs font-semibold uppercase tracking-wider text-nx-fg">
|
|
{footer.newsletter.title}
|
|
</p>
|
|
<p class="mt-1.5 text-xs leading-relaxed text-nx-muted">
|
|
{footer.newsletter.description}
|
|
</p>
|
|
{
|
|
hasNewsletterAction ? (
|
|
<form
|
|
class="relative mt-3 flex flex-col gap-2 sm:flex-row sm:items-stretch"
|
|
action={nl.actionUrl}
|
|
method="post"
|
|
accept-charset="UTF-8"
|
|
>
|
|
{nextUrl ? <input type="hidden" name="_next" value={nextUrl} /> : null}
|
|
{notifySubject ? (
|
|
<input type="hidden" name="_subject" value={notifySubject} />
|
|
) : null}
|
|
<input type="hidden" name="locale" value={currentLocale} />
|
|
<input type="hidden" name="source" value="footer" />
|
|
<input
|
|
type="text"
|
|
name="_gotcha"
|
|
tabindex="-1"
|
|
autocomplete="off"
|
|
aria-hidden="true"
|
|
class="pointer-events-none absolute -left-[9999px] h-0 w-0 opacity-0"
|
|
/>
|
|
<input
|
|
type="email"
|
|
name={nl.fieldName}
|
|
required
|
|
autocomplete="email"
|
|
placeholder={nl.placeholder}
|
|
class="min-h-10 w-full rounded-lg border border-nx-border bg-nx-bg/80 px-3 text-sm text-nx-fg placeholder:text-nx-muted/70 outline-none ring-sky-500/30 focus:border-sky-500/40 focus:ring-2"
|
|
/>
|
|
<button
|
|
type="submit"
|
|
class="inline-flex h-10 shrink-0 items-center justify-center rounded-lg bg-nx-fg px-4 text-sm font-semibold text-nx-bg hover:bg-white sm:px-5"
|
|
>
|
|
{nl.buttonLabel}
|
|
</button>
|
|
</form>
|
|
) : (
|
|
<div class="mt-3 space-y-2">
|
|
<input
|
|
type="email"
|
|
disabled
|
|
placeholder={nl.placeholder}
|
|
class="min-h-10 w-full cursor-not-allowed rounded-lg border border-nx-border bg-nx-bg/40 px-3 text-sm text-nx-muted opacity-60"
|
|
aria-describedby="nx-newsletter-hint"
|
|
/>
|
|
<button
|
|
type="button"
|
|
disabled
|
|
class="inline-flex h-10 w-full cursor-not-allowed items-center justify-center rounded-lg border border-nx-border bg-nx-elevated/50 text-sm font-medium text-nx-muted opacity-70 sm:w-auto sm:px-5"
|
|
>
|
|
{nl.buttonLabel}
|
|
</button>
|
|
<p id="nx-newsletter-hint" class="text-xs leading-relaxed text-nx-muted">
|
|
{footer.labels.newsletterComingSoon}
|
|
</p>
|
|
</div>
|
|
)
|
|
}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
class="relative mt-0 flex flex-col gap-3 pt-8 before:pointer-events-none before:absolute before:left-1/2 before:top-0 before:h-px before:w-screen before:-translate-x-1/2 before:bg-nx-border sm:flex-row sm:items-end sm:justify-between sm:gap-6"
|
|
>
|
|
<p class="min-w-0 text-xs leading-relaxed text-nx-muted sm:text-sm">
|
|
© {new Date().getFullYear()} NexStudio. {footer.legalLine}
|
|
</p>
|
|
<p
|
|
class="max-w-md shrink-0 text-xs leading-relaxed text-nx-muted sm:max-w-lg sm:text-right sm:text-sm"
|
|
>
|
|
{footer.tagline}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</footer>
|