EmDash fornisce funzioni di query per recuperare contenuti nelle tue pagine e componenti Astro. Queste funzioni seguono il pattern delle live content collections di Astro, restituendo risultati strutturati con gestione degli errori.
Funzioni di query
| Funzione | Scopo | Restituisce |
|---|---|---|
getEmDashCollection | Recuperare tutte le entry di un tipo di contenuto | { entries, error } |
getEmDashEntry | Recuperare una singola entry per ID o slug | { entry, error, isPreview } |
import { getEmDashCollection, getEmDashEntry } from "emdash";
Ottenere tutte le entry
---
import { getEmDashCollection } from "emdash";
const { entries: posts, error } = await getEmDashCollection("posts");
if (error) {
console.error("Impossibile caricare i post:", error);
}
---
<ul>
{posts.map((post) => (
<li>{post.data.title}</li>
))}
</ul>
Filtrare per locale
Quando l’i18n è abilitato, filtra per locale per recuperare contenuti in una lingua specifica:
const { entries: frenchPosts } = await getEmDashCollection("posts", {
locale: "fr",
status: "published",
});
const { entries: localizedPosts } = await getEmDashCollection("posts", {
locale: Astro.currentLocale,
status: "published",
});
Per entry singole, passa locale come terzo argomento:
const { entry: post } = await getEmDashEntry("posts", "my-post", {
locale: Astro.currentLocale,
});
Quando locale viene omesso, viene usato per default il locale della richiesta corrente. Se non esiste una traduzione per il locale richiesto, viene seguita la catena di fallback.
Filtrare per stato
const { entries: published } = await getEmDashCollection("posts", {
status: "published",
});
const { entries: drafts } = await getEmDashCollection("posts", {
status: "draft",
});
Limitare i risultati
const { entries: recentPosts } = await getEmDashCollection("posts", {
status: "published",
limit: 5,
});
Filtrare per tassonomia
const { entries: newsPosts } = await getEmDashCollection("posts", {
status: "published",
where: { category: "news" },
});
const { entries: jsPosts } = await getEmDashCollection("posts", {
status: "published",
where: { tag: "javascript" },
});
const { entries: featuredNews } = await getEmDashCollection("posts", {
status: "published",
where: { category: ["news", "featured"] },
});
Il filtro where usa la logica OR quando vengono forniti più valori per una singola tassonomia.
Gestione degli errori
const { entries: posts, error } = await getEmDashCollection("posts");
if (error) {
console.error("Impossibile caricare i post:", error);
return new Response("Errore del server", { status: 500 });
}
Ottenere una singola entry
---
import { getEmDashEntry } from "emdash";
import { PortableText } from "emdash/ui";
const { slug } = Astro.params;
const { entry: post, error } = await getEmDashEntry("posts", slug);
if (error) {
return new Response("Errore del server", { status: 500 });
}
if (!post) {
return Astro.redirect("/404");
}
---
<article>
<h1>{post.data.title}</h1>
<PortableText value={post.data.content} />
</article>
Tipo di ritorno dell’entry
interface EntryResult<T> {
entry: ContentEntry<T> | null;
error?: Error;
isPreview: boolean;
}
interface ContentEntry<T> {
id: string;
data: T;
edit: EditProxy;
}
Rendere i dati del pannello SEO
Per le collezioni con supports: ["seo"], gli editor possono impostare un titolo SEO, meta description, immagine OG, URL canonico e un toggle “nascondi dai motori di ricerca” (noindex) nel pannello SEO dell’admin. Quei dati vengono forniti come entry.data.seo. Usa getSeoMeta per risolvere i campi del pannello in meta tag pronti per il rendering:
---
import { getEmDashEntry, getSeoMeta } from "emdash";
const { entry, error } = await getEmDashEntry("posts", Astro.params.slug);
if (error) {
return new Response("Errore del server", { status: 500 });
}
if (!entry) return Astro.redirect("/404");
const seo = getSeoMeta(entry, {
siteTitle: "Il Mio Sito",
siteUrl: "https://example.com",
path: Astro.url.pathname,
});
---
<head>
<title>{seo.title}</title>
{seo.description && <meta name="description" content={seo.description} />}
{seo.ogImage && <meta property="og:image" content={seo.ogImage} />}
{seo.canonical && <link rel="canonical" href={seo.canonical} />}
{seo.robots && <meta name="robots" content={seo.robots} />}
</head>
Modalità anteprima
EmDash gestisce l’anteprima automaticamente tramite middleware. Quando un URL contiene un token _preview valido, il middleware lo verifica e configura il contesto della richiesta:
---
import { getEmDashEntry } from "emdash";
const { slug } = Astro.params;
const { entry, isPreview, error } = await getEmDashEntry("posts", slug);
if (error) {
return new Response("Errore del server", { status: 500 });
}
if (!entry) {
return Astro.redirect("/404");
}
---
{isPreview && (
<div class="preview-banner">
Visualizzazione anteprima. Questo contenuto non è pubblicato.
</div>
)}
<article>
<h1>{entry.data.title}</h1>
<PortableText value={entry.data.content} />
</article>
Editing visuale
Ogni entry restituita include un proxy edit per annotare i tuoi template:
<article {...entry.edit}>
<h1 {...entry.edit.title}>{entry.data.title}</h1>
<div {...entry.edit.content}>
<PortableText value={entry.data.content} />
</div>
</article>
In modalità modifica, {...entry.edit.title} produce un attributo data-emdash-ref. In produzione, gli spread del proxy non producono output.
Stilizzare blocchi di codice inline
| Proprietà | Scopo |
|---|---|
--emdash-inline-code-background | Sfondo del blocco di codice |
--emdash-inline-code-foreground | Testo di codice semplice |
--emdash-inline-code-muted | Commenti e testo citato |
--emdash-inline-code-keyword | Parole chiave, letterali, selettori e testo eliminato |
--emdash-inline-code-string | Stringhe, attributi, simboli e testo aggiunto |
--emdash-inline-code-number | Numeri e metadati |
--emdash-inline-code-title | Titoli, nomi, tipi e built-in |
--emdash-inline-code-border | Bordo del selettore lingua |
--emdash-inline-code-control-background | Sfondo del selettore lingua |
--emdash-inline-code-control-foreground | Testo e icone del selettore lingua |
--emdash-inline-code-focus | Indicatore di focus tastiera |
:root {
--emdash-inline-code-background: #f7f7f5;
--emdash-inline-code-foreground: #24292f;
--emdash-inline-code-muted: #57606a;
--emdash-inline-code-keyword: #b8172a;
--emdash-inline-code-string: #0a3069;
--emdash-inline-code-number: #0550ae;
--emdash-inline-code-title: #7545c7;
--emdash-inline-code-border: #7d8590;
--emdash-inline-code-control-background: #fff;
--emdash-inline-code-control-foreground: #24292f;
--emdash-inline-code-focus: #0550ae;
}
:root.dark {
--emdash-inline-code-background: #202020;
--emdash-inline-code-foreground: #f0f3f6;
--emdash-inline-code-muted: #c9d1d9;
--emdash-inline-code-keyword: #ffc1bb;
--emdash-inline-code-string: #b9ddff;
--emdash-inline-code-number: #a8d5ff;
--emdash-inline-code-title: #e5ccff;
--emdash-inline-code-border: #6e7681;
--emdash-inline-code-control-background: #161b22;
--emdash-inline-code-control-foreground: #f0f3f6;
--emdash-inline-code-focus: #a8d5ff;
}
Ordinare i risultati
const { entries: posts } = await getEmDashCollection("posts", { status: "published" });
const sorted = posts.sort(
(a, b) => (b.data.publishedAt?.getTime() ?? 0) - (a.data.publishedAt?.getTime() ?? 0),
);
Pattern di ordinamento comuni
posts.sort((a, b) => a.data.title.localeCompare(b.data.title));
posts.sort((a, b) => (a.data.order ?? 0) - (b.data.order ?? 0));
posts.sort(() => Math.random() - 0.5);
Tipi TypeScript
npx emdash types
import { getEmDashCollection, getEmDashEntry } from "emdash";
import type { Post } from "../.emdash/types";
const { entries: posts } = await getEmDashCollection<Post>("posts");
const { entry: post } = await getEmDashEntry<Post>("posts", "my-post");
Rendering statico vs. server
Statico (Pre-renderizzato)
---
import { getEmDashCollection, getEmDashEntry } from "emdash";
export async function getStaticPaths() {
const { entries: posts } = await getEmDashCollection("posts", {
status: "published",
});
return posts.map((post) => ({ params: { slug: post.data.slug } }));
}
const { slug } = Astro.params;
const { entry: post } = await getEmDashEntry("posts", slug);
---
Rendering server
---
export const prerender = false;
import { getEmDashEntry } from "emdash";
const { slug } = Astro.params;
const { entry: post, error } = await getEmDashEntry("posts", slug);
if (error) return new Response("Errore del server", { status: 500 });
if (!post) return new Response(null, { status: 404 });
---
Considerazioni sulle prestazioni
Caching
---
const { entries: posts } = await getEmDashCollection("posts", { status: "published" });
Astro.response.headers.set("Cache-Control", "public, max-age=300");
---
Evitare query ridondanti
---
import { getEmDashCollection } from "emdash";
import PostList from "../components/PostList.astro";
import Sidebar from "../components/Sidebar.astro";
const { entries: posts } = await getEmDashCollection("posts", { status: "published" });
const featured = posts.filter((p) => p.data.featured);
const recent = posts.slice(0, 5);
---
<PostList posts={featured} />
<Sidebar posts={recent} />
Prossimi passi
- Creare un blog - Costruire un blog completo
- Tassonomie - Filtrare per categorie e tag
- Lavorare con i contenuti - Operazioni CRUD admin
- Internazionalizzazione - Contenuti multilingue e traduzioni