• Mutimedia Web la Web Agency Italiana. Contattateci per preventivi gratuiti e consulenze nello sviluppo del vostro sito web o app Ios e Android. Professinalità e assistenza garatite!
    Immagini dei quadri e opere di: Giuseppe Lattanzio

  • Social

    [easy-social-share buttons="facebook,twitter,pinterest,linkedin,digg,stumbleupon,vk,tumblr,print,mail,del,reddit,whatsapp" counters=0 hide_names="force" template="grey-blocks-retina"]
  • WEB AGENCY

  • Sede Principale

    Multimedia Web

    Blog Studio Web

    Studio Web

    Sede a Venezia

    Web Agency Venezia

    Sede a New York

    Nyc Web Design

    Sede International

    Web Designer International

    Sito Demo One Page

    Spaghetti Web

    Landing page

    Savinus

  • smartphone

    Trovaci sul tuo smartphone

  • web-designer-ancona
  • AGENZIA WEB ITALIA

Home / News / La struttura del sito web

La struttura del sito web


Nella lezione precedente abbiamo registrato la struttura di una collezione di contenuti Astro e creato una serie di post in formato Markdown.

In questa lezione vedremo come creare la pagina del sito web in cui visualizzare le anteprime dei post e le pagine dei singoli post. A questo scopo utilizzeremo delle potenti funzionalità di Astro: componenti e routing dinamico. Infine, utilizzeremo la libreria Alpine.js per impaginare i risultati del blog.

Iniziamo creando due componenti. Il primo per generare l’anteprima degli articoli del blog, il secondo per i singoli articoli.

La struttura del sito web: un blog in Astro

Cominciamo dal blog. Creiamo il file ArticleCard.astro nella cartella /src/components con il seguente codice:

---
import type { CollectionEntry } from 'astro:content';
interface Props {
	post: CollectionEntry<'blog'>;
}
const { post } = Astro.props;
---

Questo è il codice del frontmatter del componente. Ecco cosa fa:

  • import type { CollectionEntry } importa i tipi di TypeScript da Astro;
  • interface Props { ... } dichiara le proprietà che il componente si aspetta di ricevere; post: CollectionEntry<'blog'> significa che la proprietà deve essere un intero oggetto della collezione blog;
  • const { post } = Astro.props; accetta i dati che vengono passati al componente.

Subito sotto il frontmatter, aggiungiamo il codice HTML che genera la struttura del componente:

<a href={`/blog/${post.slug}/`} class="block group hover:no-underline focus:outline-none focus:ring-2 focus:ring-purple-500 rounded-lg">
	<article class="bg-white p-6 rounded-lg shadow-md hover:shadow-xl transition-shadow duration-300 h-full flex flex-col">
		<!-- Immagine (se presente) -->
		{post.data.heroImage && (
			<div class="mb-4">
				<img
					src={post.data.heroImage}
					alt={`Immagine per ${post.data.title}`}
					class="w-full h-48 object-cover rounded-md"
				/>
			</div>
		)}
		<div class="flex flex-col flex-grow">
			<!-- Data del post -->
			<p class="text-sm text-gray-500">
				{new Date(post.data.pubDate).toLocaleDateString('it-IT', { year: 'numeric', month: 'long', day: 'numeric' })}
			</p>
			<!-- Titolo del post -->
			<h2 class="text-2xl font-bold mt-2 text-gray-900 group-hover:text-purple-600 transition-colors duration-300">
				{post.data.title}
			</h2>
			<!-- Descrizione -->
			<p class="text-gray-700 mt-3 flex-grow">
				{post.data.description}
			</p>
		</div>
	</article>
</a>
  • L’intero componente è racchiuso in un tag <a>, che farà sì che l’intera card sia un’unica area cliccabile;
  • href={/blog/${post.slug}/`} genera dinamicamente l’URL della pagina di destinazione. Questo in quanto Astro genera automaticamente il campo slug per ogni post in base al nome del file Markdown (es. primo-post.md produce post.slug = 'primo-post').
  • {post.data.heroImage && (...) } è un rendering condizionale che verifica l’esistenza di post.data.heroImage e, se la condizione è vera, visualizza il codice tra parentesi.
  • post.data.pubDate, post.data.title e post.data.description generano data, titolo e descrizione del post.

La pagina del blog

Ora dobbiamo creare la pagina che usa questo componente. Spostiamoci nella cartella /src/pages e creiamo la cartella blog. Qui creiamo il file index.astro e aggiungiamo il seguente codice:

---
import { getCollection, type CollectionEntry } from 'astro:content';
import Layout from '../../layouts/Layout.astro';
import ArticleCard from '../../components/ArticleCard.astro';
// --- IMPOSTAZIONI ---
const POSTS_PER_PAGE = 3;
// Ordina in modo discendente i post per data
const sortedPosts = (await getCollection('blog')).sort(
		(a: CollectionEntry<'blog'>, b: CollectionEntry<'blog'>) =>
				b.data.pubDate.getTime() - a.data.pubDate.getTime()
);
const totalPosts = sortedPosts.length;
---
<Layout
	title="Il Mio Blog"
	description="Una raccolta dei miei pensieri e tutorial sullo sviluppo web."
>
	<h1 class="text-4xl font-extrabold text-gray-900 mb-8">Tutti gli Articoli</h1>
	<div
		x-data={`{ visibleItems: ${POSTS_PER_PAGE} }`}
		x-cloak
	>
		<div class="grid gap-10">
			{sortedPosts.length > 0 ? (
				sortedPosts.map((post, index) => (
					<div x-show={`${index} < visibleItems`}>
						<ArticleCard post={post} />
					</div>
				))
			) : (
				<p>Nessun articolo disponibile.</p>
			)}
		</div>
		<div class="mt-12 text-center">
			<button
				type="button"
				x-show={`visibleItems < ${totalPosts}`}
				@click={`visibleItems += ${POSTS_PER_PAGE}`}
				class="bg-purple-600 text-white font-bold py-3 px-6 rounded-lg hover:bg-purple-700 transition-colors duration-300"
			>
				Carica Altri Articoli
			</button>
		</div>
	</div>
</Layout>
<style is:global>
	[x-cloak] {
		display: none !important;
	}
</style>

Ecco cosa fa questo codice:

  • Importa la funzione asincrona getCollection, che permette di recuperare tutti gli elementi da una collezione definita nel file /src/content/config.ts.
  • type CollectionEntry è il tipo di TypeScript che descrive la struttura di un singolo articolo. Importandolo esplicitamente, rendiamo il codice più sicuro e conforme alle best practice.
  • Importa i componenti Layout e ArticleCard.
  • Imposta il limite di post per pagina.
  • Recupera tutti i post della collezione (getCollection('blog')), li ordina e li memorizza in sortedPosts.
  • Itera tra gli elementi dell’array visualizzando ogni post con l’elemento <ArticleCard>.

Abbiamo utilizzato Alpine.js per creare un sistema di paginazione “lato client” con un pulsante che permette di mostrare altri POSTS_PER_PAGE articoli ad ogni clic:

  • x-data definisce un componente Alpine in cui { visibleItems: ${POSTS_PER_PAGE} } rappresenta lo stato iniziale del componente (vedi Il local state di Alpine);
  • x-cloak nasconde gli elementi finché Alpine.js non è completamente inizializzato, grazie allo stile CSS definito con [x-cloak] { display: none !important; }.
  • x-show fa in modo che la div venga visualizzata solo se ci sono elementi visibili (${index} < visibleItems);
  • il pulsante viene visualizzato se ci sono altri visibleItems disponibili;
  • al clic sul pulsante, la proprietà visibleItems viene incrementata di POSTS_PER_PAGE.

Ed ecco la pagina iniziale del nostro blog:

La prima versione del blog Astro

La prima versione del blog Astro

Se vuoi aggiornamenti su La struttura del sito web inserisci la tua email nel box qui sotto:



Source link