The interface was translated in en/it/es/fr via @nuxtjs/i18n. Drop the module, the locale files, and the language switcher: the UI is now static Italian text, with translation for foreign visitors left to the Google Translate browser extension instead of the app.
289 lines
6.1 KiB
Vue
289 lines
6.1 KiB
Vue
<script setup lang="ts">
|
|
import type { Category } from '#shared/types/blog'
|
|
|
|
const { data: categories } = await useFetch<Category[]>('/api/categories', {
|
|
key: 'nav-categories',
|
|
default: () => [],
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div class="page">
|
|
<a class="skip-link" href="#main">Vai al contenuto</a>
|
|
|
|
<header class="site-header">
|
|
<div class="container">
|
|
<p class="wordmark">
|
|
<NuxtLink to="/">
|
|
<img src="/logo.png" :alt="SITE_NAME" width="400" height="400">
|
|
</NuxtLink>
|
|
</p>
|
|
<p class="tagline kicker">Articoli, guide e analisi.</p>
|
|
</div>
|
|
|
|
<nav class="site-nav" aria-label="Navigazione principale">
|
|
<div class="container nav-inner">
|
|
<ul>
|
|
<li><NuxtLink to="/blog">Tutti gli articoli</NuxtLink></li>
|
|
<li v-for="category in categories" :key="category.slug">
|
|
<NuxtLink :to="`/category/${category.slug}`">
|
|
{{ category.name }}
|
|
</NuxtLink>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</nav>
|
|
</header>
|
|
|
|
<main id="main" class="container site-main">
|
|
<slot />
|
|
</main>
|
|
|
|
<footer class="site-footer">
|
|
<div class="container footer-inner">
|
|
<div class="footer-block">
|
|
<img class="footer-logo" src="/logo.png" :alt="SITE_NAME" width="400" height="400">
|
|
<p class="muted">Articoli, guide e analisi.</p>
|
|
<address class="contact">
|
|
Contatti:
|
|
<a :href="`mailto:${SITE_EMAIL}`">{{ SITE_EMAIL }}</a>
|
|
</address>
|
|
</div>
|
|
|
|
<nav class="footer-block" aria-label="Categorie">
|
|
<p class="kicker">Categorie</p>
|
|
<ul>
|
|
<li v-for="category in categories" :key="category.slug">
|
|
<NuxtLink :to="`/category/${category.slug}`">
|
|
{{ category.name }}
|
|
</NuxtLink>
|
|
</li>
|
|
<li v-if="!categories.length" class="muted">Ancora nessuna pubblicazione</li>
|
|
</ul>
|
|
</nav>
|
|
|
|
<nav class="footer-block" aria-label="Naviga">
|
|
<p class="kicker">Naviga</p>
|
|
<ul>
|
|
<li><NuxtLink to="/">Home</NuxtLink></li>
|
|
<li><NuxtLink to="/blog">Tutti gli articoli</NuxtLink></li>
|
|
</ul>
|
|
</nav>
|
|
|
|
<nav class="footer-block" aria-label="Seguici">
|
|
<p class="kicker">Seguici</p>
|
|
<ul>
|
|
<li v-for="social in SOCIAL_LINKS" :key="social.name">
|
|
<a class="social" :href="social.url" target="_blank" rel="noopener me">
|
|
<SocialIcon :name="social.name" />
|
|
<span>{{ social.name }}</span>
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
|
|
<p class="container copyright kicker">
|
|
© {{ new Date().getFullYear() }} {{ SITE_NAME }}. Tutti i diritti riservati.
|
|
</p>
|
|
</footer>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.page {
|
|
display: flex;
|
|
flex-direction: column;
|
|
min-height: 100vh;
|
|
}
|
|
|
|
/* Header: centred wordmark over a thin rule of links. */
|
|
.site-header {
|
|
padding-top: 1.5rem;
|
|
text-align: center;
|
|
border-bottom: 1px solid var(--color-border);
|
|
}
|
|
|
|
@media (min-width: 48rem) {
|
|
.site-header {
|
|
padding-top: 2.5rem;
|
|
}
|
|
}
|
|
|
|
.wordmark {
|
|
margin: 0;
|
|
}
|
|
|
|
.wordmark a {
|
|
display: inline-block;
|
|
text-decoration: none;
|
|
}
|
|
|
|
/* The seal carries the name itself, so it stands in for a text wordmark. */
|
|
.wordmark img {
|
|
width: clamp(6rem, 14vw, 8.5rem);
|
|
height: auto;
|
|
}
|
|
|
|
.tagline {
|
|
margin-top: 0.6rem;
|
|
}
|
|
|
|
.site-nav {
|
|
margin-top: 1.25rem;
|
|
border-top: 1px solid var(--color-border);
|
|
}
|
|
|
|
.nav-inner {
|
|
display: flex;
|
|
justify-content: center;
|
|
padding-block: 0.6rem;
|
|
}
|
|
|
|
.site-nav ul {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 0 1.25rem;
|
|
justify-content: center;
|
|
padding: 0;
|
|
margin: 0;
|
|
list-style: none;
|
|
font-size: 0.75rem;
|
|
font-weight: 600;
|
|
letter-spacing: 0.14em;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
@media (min-width: 48rem) {
|
|
.site-nav {
|
|
margin-top: 2rem;
|
|
}
|
|
|
|
.nav-inner {
|
|
padding-block: 0.9rem;
|
|
}
|
|
|
|
.site-nav ul {
|
|
gap: 0.25rem 2rem;
|
|
}
|
|
}
|
|
|
|
.site-nav a {
|
|
display: inline-block;
|
|
text-decoration: none;
|
|
color: var(--color-body);
|
|
/* Roomy enough to tap accurately on a phone. */
|
|
padding-block: 0.6rem;
|
|
border-bottom: 1px solid transparent;
|
|
}
|
|
|
|
.site-nav a:hover,
|
|
.site-nav a.router-link-active {
|
|
color: var(--color-ink);
|
|
border-bottom-color: var(--color-ink);
|
|
}
|
|
|
|
.site-main {
|
|
flex: 1;
|
|
padding-block: 2.25rem 3.5rem;
|
|
}
|
|
|
|
@media (min-width: 48rem) {
|
|
.site-main {
|
|
padding-block: 3.5rem 5rem;
|
|
}
|
|
}
|
|
|
|
/* Footer: columns, then a centred copyright line. */
|
|
.site-footer {
|
|
padding-block: 3.5rem 2rem;
|
|
background: var(--color-surface);
|
|
border-top: 1px solid var(--color-border);
|
|
}
|
|
|
|
/* One column on phones, two on tablets, four on desktop — auto-fit would
|
|
otherwise leave the fourth block stranded on its own row on a tablet. */
|
|
.footer-inner {
|
|
display: grid;
|
|
gap: 2rem;
|
|
grid-template-columns: 1fr;
|
|
padding-bottom: 2.5rem;
|
|
}
|
|
|
|
@media (min-width: 48rem) {
|
|
.footer-inner {
|
|
grid-template-columns: repeat(2, 1fr);
|
|
gap: 2.5rem;
|
|
}
|
|
}
|
|
|
|
@media (min-width: 64rem) {
|
|
.footer-inner {
|
|
grid-template-columns: repeat(4, 1fr);
|
|
}
|
|
}
|
|
|
|
.footer-block p:last-of-type {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.footer-logo {
|
|
width: 4.5rem;
|
|
height: auto;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.contact {
|
|
margin-top: 0.75rem;
|
|
font-size: 0.95rem;
|
|
font-style: normal;
|
|
}
|
|
|
|
.contact a {
|
|
text-decoration: underline;
|
|
text-underline-offset: 0.2em;
|
|
}
|
|
|
|
.footer-block ul {
|
|
padding: 0;
|
|
margin: 0.9rem 0 0;
|
|
list-style: none;
|
|
font-size: 0.95rem;
|
|
}
|
|
|
|
.footer-block li + li {
|
|
margin-top: 0.35rem;
|
|
}
|
|
|
|
.footer-block a {
|
|
text-decoration: none;
|
|
}
|
|
|
|
.footer-block a:hover {
|
|
text-decoration: underline;
|
|
text-underline-offset: 0.2em;
|
|
}
|
|
|
|
.social {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.55rem;
|
|
}
|
|
|
|
/* Keep the underline on the label, not stretched across the icon. */
|
|
.social:hover {
|
|
text-decoration: none;
|
|
}
|
|
|
|
.social:hover span {
|
|
text-decoration: underline;
|
|
text-underline-offset: 0.2em;
|
|
}
|
|
|
|
.copyright {
|
|
padding-top: 1.75rem;
|
|
text-align: center;
|
|
border-top: 1px solid var(--color-border);
|
|
}
|
|
</style>
|