Files
oki-foundation/src/lib/components/sections/Contact.svelte
T

184 lines
4.1 KiB
Svelte
Raw Normal View History

<script lang="ts">
// {@html} sur contenu first-party (JSON i18n du dépôt), aucune donnée utilisateur.
import BrandIcon from '$lib/components/icons/BrandIcon.svelte';
import KineticText from '$lib/components/motion/KineticText.svelte';
import type { Bundle, Locale } from '$lib/i18n';
import { splitLeadingEmoji } from './pictos';
let { t }: { t: Bundle; locale?: Locale } = $props();
type BrandName =
| 'email'
| 'whatsapp'
| 'discord'
| 'telegram'
| 'mastodon'
| 'peertube'
| 'nextcloud'
| 'gitea'
| 'castopod'
| 'stoat'
| 'tiktok'
| 'x';
/** Reprend la logique du partial legacy : icône déduite du libellé du lien. */
function iconFor(text: string): BrandName | null {
const lname = text.toLowerCase();
if (lname.includes('kontak') || lname.includes('mail')) return 'email';
if (lname.includes('whatsapp')) return 'whatsapp';
if (lname.includes('telegram')) return 'telegram';
if (lname.includes('discord')) return 'discord';
if (lname.includes('labola') || lname.includes('gitea')) return 'gitea';
return null;
}
</script>
<section class="section contact" id="contact">
<div class="container">
<h2 class="section-title">
<KineticText as="span" text={t.contact.title} />
</h2>
<!-- Contenu éditorial du bundle i18n (lien mailto balisé). -->
<p class="contact-lede">{@html t.contact.lede}</p>
</div>
<div class="contact-socials container">
{#each t.contact.sections as group (group.title)}
{@const title = splitLeadingEmoji(group.title)}
<div class="contact-socials-group">
<h3 class="contact-socials-title">
{#if title.icon}
<svg class="icon" aria-hidden="true"><use href="/icons.svg#{title.icon}" /></svg>
{/if}
{title.text}
</h3>
<div class="contact-socials-row">
{#each group.links as link (link.url)}
{@const icon = iconFor(link.text)}
<a
href={link.url}
target={link.url.startsWith('http') ? '_blank' : undefined}
rel={link.url.startsWith('http') ? 'noopener noreferrer' : undefined}
class="contact-social-link"
aria-label={link.text}
>
{#if icon}
<BrandIcon name={icon} />
{:else}
<span class="contact-social-text">{link.text}</span>
{/if}
</a>
{/each}
</div>
</div>
{/each}
</div>
</section>
<style>
.contact {
background: var(--card-bg);
}
.section-title {
text-align: center;
color: var(--or-oki);
}
.contact-lede {
text-align: center;
max-width: 800px;
margin: 0 auto 3rem;
font-size: 1.1rem;
line-height: 1.6;
}
.contact-lede :global(a) {
font-weight: 600;
}
.contact-socials {
display: flex;
flex-direction: column;
align-items: center;
gap: 2rem;
}
.contact-socials-group {
text-align: center;
}
.contact-socials-title {
font-size: 0.85rem;
font-weight: 600;
color: var(--or-oki);
margin-bottom: 0.75rem;
opacity: 0.9;
display: flex;
align-items: center;
justify-content: center;
gap: 0.4rem;
}
.contact-socials-title .icon {
width: 1.1em;
height: 1.1em;
}
.contact-socials-row {
display: flex;
justify-content: center;
align-items: center;
gap: 1.5rem;
flex-wrap: wrap;
}
.contact-social-link {
display: inline-flex;
align-items: center;
justify-content: center;
width: 3rem;
height: 3rem;
color: var(--or-oki);
border-radius: var(--radius-md);
background: color-mix(in srgb, var(--or-oki) 8%, transparent);
transition:
transform var(--dur-tanbou) var(--ease-ka),
background var(--dur-tanbou) var(--ease-ka);
}
.contact-social-link:hover {
transform: scale(1.15);
background: color-mix(in srgb, var(--or-oki) 15%, transparent);
}
.contact-social-link :global(svg) {
width: 60%;
height: 60%;
}
.contact-social-text {
font-size: 0.7rem;
font-weight: 700;
padding: 0 0.25rem;
text-align: center;
}
@media (min-width: 768px) {
.contact-socials {
flex-direction: row;
align-items: flex-start;
justify-content: center;
gap: 3rem;
}
.contact-socials-row {
gap: 2rem;
}
.contact-social-link {
width: 3.5rem;
height: 3.5rem;
}
}
</style>