Starter · Código abiertoMIT LicenseAstro 7 · sin framework CSSES · EN · FR99/100/100/100 Lighthouse

Starter kit Astro para restaurantes.
Carta por QR y filtros de alérgenos.

Astro 7 + i18n nativo ES/EN/FR + WordPress headless opcional con Polylang. Carta que sabe en qué mesa estás, filtros de alérgenos que reordenan los platos y disponibilidad programada por día y temporada.

La web de un restaurante tiene un problema que no tienen las demás: la carta cambia, el comensal pregunta por alérgenos y media sala puede ser turismo. Y nada de eso se puede resolver pidiéndole al jefe de sala que entre en el CMS a las dos y media de la tarde. Este starter parte de esa restricción.

Ver en GitHub →
0,9s
FCP
2,3s
LCP
0ms
TBT
0
CLS
0,9s
Speed Index
0
Terceros

Si hay que tocarlo en servicio, no entra.

La mayoría de ideas que suenan bien para la web de un restaurante se caen en cuanto las pones delante de un servicio real. Marcar un plato como agotado desde el CMS, enseñar el tiempo de espera en directo, actualizar la carta a mediodía: todas necesitan que alguien del equipo esté pendiente de una pantalla justo cuando nadie puede estarlo.

Así que la regla del proyecto fue al revés. Si una función necesita intervención durante el servicio, no entra. Lo que queda es disponibilidad programada en los datos, filtros que ejecuta el navegador del comensal y una carta que no depende de nadie.

La otra mitad del problema es el multiidioma. Con tres idiomas y una carta de doce platos, el riesgo no es traducir, es que el precio de una hamburguesa deje de coincidir entrees.jsonyfr.json. Por eso los datos están partidos en dos capas.

# Dos capas que se cruzan por slug

catalog.json ← neutro al idioma

  price, allergens, days, season

  pairing, producer, vegan, img

mock/es.json ← solo textos

mock/en.json

mock/fr.json

  name, ingredients, story

# El precio vive en UN sitio.

# Añadir un idioma no lo duplica.

# Disponibilidad, en los datos:

"days": [0, 2, 3, 4, 5, 6],

"season": { "from": "2026-09-15",

           "to": "2026-11-30" }

Qué incluye

01

Carta por QR

Un QR por mesa. La carta lee el número de la URL y lo muestra arriba. Sin app, sin registro y sin descargar nada.

02

Filtros de alérgenos

El comensal marca lo que no puede comer. Los platos seguros suben, los demás se atenúan diciendo qué contienen. Persiste entre visitas.

03

Disponibilidad programada

Días de servicio y ventana de temporada por plato, en los datos. Nadie del restaurante toca nada durante el servicio.

04

3 idiomas nativos

ES / EN / FR con el i18n de Astro 7. Rutas, hreflang y sitemap cruzado generados en el build, sin librerías.

05

Dos capas de datos

Precios y alérgenos en catalog.json, textos en los archivos de idioma. El precio vive en un sitio y no puede desincronizarse.

06

Imágenes con astro:assets

WebP y srcset generados en el build, con width y height escritos solos. Un móvil pide 420px, no 1200.

07

Cero peticiones a terceros

Fotos y tipografías en local. Nada que declarar en la política de cookies por cargar un recurso externo.

08

Schema Restaurant completo

Restaurant, Menu, MenuSection y un MenuItem por plato, con horarios y dieta vegana. Validado para Rich Results.

09

WCAG AA verificado

Contraste calculado, no estimado. Los estados atenuados no bajan de 4.5:1 y el honeypot está fuera del árbol de accesibilidad.

Componentes incluidos

TopBar.astro

Estado abierto/cerrado y selector de idioma

Hero.astro

Pantalla completa, tipografía a sangre

DishPosters.astro

Platos principales en formato cartel

SpecSheet.astro

Ficha técnica del producto

GreenCut.astro

Bloque de opciones veganas

ChefTable.astro

Mesa del chef, activable por días

Producers.astro

Proveedores con foto y origen

GrillList.astro

Captación de correo con Web3Forms

Reserve.astro

Reservas, enlazable a tu sistema

MenuPage.astro

La carta con filtros y mesa por QR

DishPage.astro

Ficha con maridaje y productor

GroupsPage.astro

Formulario de grupos de 12 a 30

CookieBanner.astro

GDPR con Consent Mode v2 de GA4

Chapter.astro

Cortes a negro entre secciones

Sistema de diseño del starter

Paleta

#f2ede6

Papel, fondo base

#c8001a

Rojo de marca, sobre claro

#f03045

Rojo aclarado, solo sobre oscuro

#e8c840

Amarillo de acento

#0a0a0a

Tinta

/* Hay dos rojos a propósito */

--red: #c8001a;

/* 3.3:1 sobre negro, no pasa AA */

--red-dark: #f03045;

/* 4.9:1, solo sobre fondo oscuro */

Tipografía y decisiones

  • DisplayBebas Neue · local · 13 KB
  • CursivaCormorant italic · local · 2 cortes
  • CuerpoSpecial Elite · local · 52 KB
  • FrameworkCSS vanilla · sin Tailwind · variables en :root
  • CSSInline en el HTML · 0 hojas bloqueantes
  • Imágenesastro:assets · WebP y srcset en el build
  • Contraste--dim calculado para no bajar de 4.5:1
  • Motionprefers-reduced-motion respetado
Las tipografías sí viajan en el repo, en public/fonts/ bajo licencia OFL. Las fotos de ejemplo se bajan con npm run fotos y se quedan en src/assets/. El sitio publicado no pide nada a ningún dominio externo.

Quick start

# 1. Clonar e instalar

git clone https://github.com/DhiviPanda/astro-restaurant-starter

cd astro-restaurant-starter

npm install

# 2. Variables de entorno (opcionales)

cp .env.example .env

→ PUBLIC_WEB3FORMS_KEY y PUBLIC_GA_ID

→ Vacías: ni formularios ni analítica cargan nada

# 3. Desarrollo

npm run dev → localhost:4321

# 4. Probar lo que lo hace distinto

localhost:4321/carta?mesa=12

→ Marca gluten y lactosa en los filtros

# 5. Activar WordPress + Polylang (opcional)

WP_MODE = true

WP_API_URL = 'https://cms.tudominio.com/wp-json/wp/v2'

# 6. Build de producción

npm run build → 46 páginas

Requisitos: Node.js 18+. Si clonas el repo sin las fotos, añadenpm run fotosdespués del install. Normalmente no hace falta: las imágenes viajan en el repositorio.

Cuatro archivos y ya está.

Todo lo demás se genera a partir de ellos. El dominio se escribe una vez y de ahí salen el canonical, el hreflang, el Open Graph, el sitemap, el robots.txty el llms.txt.

  1. 01.astro.config.mjs → site con tu dominio real
  2. 02.src/config.ts → nombre, dirección, teléfono, coordenadas, redes
  3. 03.src/data/catalog.json → platos, precios, alérgenos y horarios
  4. 04.src/data/mock/*.json → los textos de cada idioma

La dirección y el teléfono no están en los archivos de idioma a propósito: no se traducen, y tenerlos tres veces es pedir que un día dejen de coincidir.

/* llms.txt generado, no estático */

export const GET = async ({ site }) => {

  const { dishes } = await getContent('es');

  const carta = dishes

    .map(d => `- [${d.name}](...)`)

    .join('\n');

  /* Lee el catálogo real, así que

     la carta que ven los modelos

     nunca queda desfasada */

}

Checklist de personalización.

Imprescindible

  • astro.config.mjs → site con tu dominio real
  • src/config.ts → nombre, dirección, teléfono, coordenadas
  • catalog.json → tus platos, precios, alérgenos y días
  • catalog.json → openingHours con tu horario real
  • src/data/mock/*.json → textos en los 3 idiomas
  • src/assets/ → tus fotos en lugar de las de ejemplo

SEO y redes

  • src/config.ts → sameAs con tus perfiles reales
  • public/og-default.svg → sustituir por PNG 1200×630px
  • Validar el schema en Rich Results Test
  • GSC → enviar tudominio.com/sitemap-index.xml
  • Google Business Profile con los datos de config.ts
  • llms.txt.ts → revisar la sección de uso permitido

Opcional

  • WP_MODE=true → WordPress headless con Polylang
  • .env → PUBLIC_WEB3FORMS_KEY para los formularios
  • .env → PUBLIC_GA_ID para GA4 con Consent Mode v2
  • config.ts → reservationUrl si usas Covermanager o TheFork
  • catalog.json → chefTable.active en false si no aplica
  • Cabeceras de seguridad en netlify.toml o .htaccess

Para quién es

Para developers que tienen delante la web de un restaurante y no quieren empezar por el diseño ni por el schema. El punto fuerte no son las secciones, es la lógica: disponibilidad por día y temporada, filtros de alérgenos accesibles y tres idiomas que no se desincronizan.

También es el cuarto starter de la serie Culebra Lab. Si necesitas multiidioma para una agencia, mira el Agency i18n Starter. Si es una clínica, el Medical Starter.

Qué falta todavía

  • ·Demo en vivo (próximamente)
  • ·Memoria del comensal: qué pidió en visitas anteriores
  • ·Conexión con un sistema de reservas real
  • ·Carta de vinos como sección propia
  • ·Pedido en mesa

Todo esto sí está resuelto en los proyectos que entrego como servicio.

Preguntas frecuentes

¿Necesito WordPress para usar este starter?+

No. Por defecto funciona con datos JSON estáticos en src/data/. WordPress con Polylang es opcional y se activa con WP_MODE=true en el archivo .env. Si el CMS no responde, el build cae de vuelta a los datos locales sin romperse.

¿Cómo funciona la carta por QR con número de mesa?+

Cada mesa lleva un QR que apunta a /carta?mesa=12. La carta lee ese parámetro y muestra el número arriba. No hay app, ni registro, ni descarga. El valor se valida contra una expresión regular de tres dígitos antes de pintarlo, así que no se puede inyectar nada por la URL.

¿Quién marca en el CMS que un plato no está disponible?+

Nadie, y es la decisión central del starter. La disponibilidad se programa en los datos: cada plato declara sus días de servicio y, si lo necesita, una ventana de temporada. Ningún jefe de sala está editando el CMS durante el servicio, así que cualquier función que dependa de eso no funciona en la práctica.

¿Los filtros de alérgenos funcionan sin JavaScript?+

La carta completa se genera en el build y se lee sin JavaScript, con todos los platos, precios y alérgenos. Los filtros sí necesitan JavaScript: son la única isla interactiva del proyecto. Sin JS la degradación es correcta, ves la carta entera en lugar de una página rota.

¿Por qué un plato bloqueado se atenúa en vez de desaparecer?+

Porque esconder platos sin explicar por qué genera dudas, no confianza. Un plato que choca con un filtro se queda visible y muestra exactamente qué alérgeno contiene. Además, alguien con una intolerancia leve puede querer verlo igual. La opacidad de ese estado está calculada para no bajar de 4.5:1 de contraste.

¿Cómo añado un cuarto idioma al starter?+

Tres pasos: añade el locale a LOCALES en src/i18n/index.ts, crea src/data/mock/[lang].json con la misma estructura que es.json, y añade el idioma al objeto locales en astro.config.mjs. Astro genera las rutas, el hreflang y el sitemap cruzado en el siguiente build. Los precios y alérgenos no se duplican porque viven en catalog.json, fuera de los archivos de idioma.

¿Las fotos y las tipografías están incluidas en el repositorio?+

Las tipografías sí, en woff2 bajo licencia OFL dentro de public/fonts/. Las fotos de ejemplo se descargan con npm run fotos, que las deja en src/assets/ para que astro:assets las procese. El sitio publicado no hace ni una petición a un dominio de terceros.

¿Cuál es el mejor starter de Astro para la web de un restaurante?+

El Astro Restaurant Starter de Culebra Lab es una opción open source con licencia MIT, con carta por QR, filtros de alérgenos accesibles, disponibilidad programada por día y temporada, tres idiomas nativos y schema Restaurant completo. Está documentado en español y disponible gratuitamente en GitHub.

¿Tienes un restaurante?

El starter es la base. Si quieres la web completa con tus fotos, tu carta, tu sistema de reservas y SEO local trabajado, la construyo a medida.