Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/constanza101/borrissol/llms.txt

Use this file to discover all available pages before exploring further.

The Borrissol codebase follows the standard Astro project layout with a few deliberate structural choices: all business and SEO configuration is centralised in src/config/ (split across site.ts, reviews.ts, and seasonal.ts), all translated copy lives in src/i18n/ui.ts, all design tokens live in src/styles/theme.css, and per-language routing is handled by a single [lang]/ dynamic route rather than duplicated per-language directories. Configuration files at the root (astro.config.mjs, keystatic.config.ts, netlify.toml) govern the build, CMS schema, and deployment respectively.

Directory tree

keystatic.config.ts         # CMS schema (collections, fields)
astro.config.mjs            # i18n, redirects, sitemap, integrations
netlify.toml                # Node version + bot-trap redirects

src/
├── assets/images/          # processed by Astro (AVIF/WebP output)
├── components/
│   ├── Seo.astro           # all meta, JSON-LD, hreflang
│   ├── Navbar.astro        # incl. language switcher + hash preservation
│   ├── HeroSection.astro
│   ├── OfferSection.astro
│   ├── ProcessSection.astro
│   ├── WorkshopsSection.astro
│   ├── TestimonialsSection.astro
│   ├── AboutSection.astro
│   ├── FAQSection.astro
│   ├── CTASection.astro
│   ├── Footer.astro
│   ├── Gallery.astro       # honeycomb tap-to-reveal photo grid
│   ├── PressGrid.astro     # press page grid
│   ├── PressStrip.astro    # press strip on home
│   ├── Button.astro        # design-system button primitive
│   ├── WhatsAppFab.astro
│   ├── CookieBanner.astro
│   └── PrivacySection.astro
├── config/
│   ├── site.ts             # SEO + business config (SITE object)
│   ├── reviews.ts          # Google review data + aggregate rating
│   └── seasonal.ts         # time-limited event visibility flags
├── content/
│   └── blog/               # Keystatic-authored MDX posts
├── i18n/
│   ├── ui.ts               # all copy, 4 languages
│   └── utils.ts            # getLangFromUrl, useTranslations, getAlternatePath
├── layouts/
│   └── Layout.astro        # GA + Consent Mode, skip link, favicons, scroll reveal
├── pages/
│   ├── 404.astro           # custom 404 page
│   ├── index.astro         # / (CA, default locale)
│   ├── gallery.astro       # /gallery (CA)
│   ├── press.astro         # /press (CA)
│   ├── tufting.astro       # /tufting (CA)
│   ├── punch-needle.astro  # /punch-needle (CA)
│   ├── felting.astro       # /felting (CA)
│   ├── loom.astro          # /loom (CA)
│   ├── borla.astro         # /borla (CA)
│   ├── summer-lab.astro    # /summer-lab (CA)
│   ├── team-building.astro # /team-building (CA)
│   ├── pelussetes.astro    # /pelussetes (CA)
│   ├── [lang]/             # dynamic routes — /es, /en, /fr variants
│   │   ├── index.astro
│   │   ├── gallery.astro
│   │   ├── press.astro
│   │   ├── tufting.astro
│   │   ├── punch-needle.astro
│   │   ├── felting.astro
│   │   ├── loom.astro
│   │   ├── borla.astro
│   │   ├── summer-lab.astro
│   │   ├── team-building.astro
│   │   └── pelussetes.astro
│   └── blog/
│       ├── index.astro     # /blog
│       └── [slug].astro    # /blog/post-slug
└── styles/
    └── theme.css           # design system tokens

Directory and file reference

src/assets/images/

All content images are stored here and run through the Astro asset pipeline at build time. Astro’s <Picture> component converts sources to AVIF + WebP with a responsive srcset, and automatically generates the correct width/height attributes to prevent Cumulative Layout Shift (CLS = 0). Source files should be no larger than approximately 2× the widest responsive variant that will be served.
The hero image uses loading="eager" and fetchpriority="high" to optimise LCP (1.8 s on mobile). All other images use loading="lazy".

src/components/

Components are organised into four informal categories:
CategoryDirectory / FilesPurpose
Page sectionsHeroSection.astro, OfferSection.astro, WorkshopsSection.astro, etc.Full-width bands that compose the single-page landing layout
Shared primitivesButton.astro, Seo.astro, Navbar.astro, Footer.astro, CookieBanner.astroReusable UI building blocks used across multiple pages
Gallery & pressGallery.astro, PressGrid.astro, PressStrip.astroFeature-specific display components
UtilitiesWhatsAppFab.astro, PrivacySection.astroSingle-purpose functional components
Seo.astro is the single place for all <meta> tags, JSON-LD structured data blocks (LocalBusiness, FAQPage, ImageObject, AggregateRating), Open Graph/Twitter Card tags, hreflang links, and canonical URL. It accepts per-page overrides as props and falls back to the values in src/config/site.ts.

src/config/

The config directory holds three separate modules — not one. Each is a single-purpose export:
FileExportsDescription
site.tsSITE: SiteConfigEvery SEO token and business detail: name, URL, locale, logo path, OG image path, and the full BusinessConfig (type, address, geo coordinates, telephone, email, opening hours, price range, social links). Seo.astro and the JSON-LD generators consume this object directly.
reviews.tsREVIEWS: Review[], REVIEW_AGGREGATEReal Google review data (reviewer names + i18n keys for review text) and aggregate rating totals (ratingValue, reviewCount). Shared by both TestimonialsSection.astro and the AggregateRating JSON-LD node in Seo.astro. Update REVIEW_AGGREGATE whenever the Google Business Profile totals change.
seasonal.tssummerLab: SeasonalEvent, isSummerLabVisible()Controls whether time-limited promotional cards are shown. Visibility is evaluated at build time (not per request), so a card hides on the first deploy after endDate. Bump the dates each year to re-enable the card.
Update site.ts rather than touching individual components when business details change. Never hardcode review counts or aggregate ratings inline — always edit reviews.ts.

src/content/blog/

MDX files authored via the Keystatic CMS panel at /keystatic. Posts are processed through Astro Content Collections (getCollection('blog')). The blog is intentionally Catalan-only to keep the editorial workload sustainable — /es/blog, /en/blog, and /fr/blog all 301-redirect to /blog.

src/i18n/

FileExportsDescription
ui.tsTranslation map objectAll visible copy for every UI string in all four languages (Catalan, Spanish, English, French). Zero hardcoded strings are allowed in components — every user-facing string references a key from this file.
utils.tsgetLangFromUrl, useTranslations, getAlternatePath (also called localizedPath)Helper functions for extracting the active locale from the current URL, retrieving the correct translation map, and generating localised hrefs for the language switcher.

src/layouts/

Layout.astro is the single shared shell for every page. It injects:
  • Google Analytics 4 (gtag.js) with Consent Mode v2 Advanced — GA loads on every visit in cookieless mode by default; cookies are only granted after the user accepts the cookie banner.
  • A skip-to-content link as the first child of <body> for keyboard accessibility.
  • Preconnect hints for third-party domains.
  • The scroll-reveal IntersectionObserver script (respects prefers-reduced-motion).
  • Self-hosted Roboto WOFF2 font declarations with font-display: swap.

src/pages/

Astro’s file-based router maps files to URLs directly. The routing strategy for Borrissol:
  • Catalan defaultindex.astro, gallery.astro, press.astro, and all workshop pages (tufting.astro, punch-needle.astro, felting.astro, loom.astro, borla.astro, summer-lab.astro, team-building.astro, pelussetes.astro) sit at the top level and are served at their respective root paths. There is no /ca/ prefix.
  • Other languages — mirrored files inside [lang]/ use getStaticPaths to generate the /es, /en, and /fr variants at build time.
  • Blogblog/index.astro and blog/[slug].astro are Catalan-only. Non-Catalan blog URLs 301-redirect to the Catalan equivalents in astro.config.mjs.
  • Seasonal pagessummer-lab.astro is always built and served; the home-page promotional card that links to it is conditionally rendered based on isSummerLabVisible() from src/config/seasonal.ts.

src/styles/theme.css

The single source of truth for the entire design system. Contains all CSS custom properties on :root:
  • Colors--color-white, --color-light, --color-mid, --color-muted, --color-black, plus semantic aliases (--bg, --fg, --fg-muted, --border-hairline).
  • Typography--font-size-h1 through --font-size-h4, --font-size-p1 through --font-size-p3, --font-size-ui, weight, line-height, and letter-spacing tokens.
  • Spacing--space-xs (8 px) through --space-xl (80 px).
  • Border radius--radius-pill, --radius-md, --radius-sm, --radius-xs.
  • Icons — stroke width, color, and size tokens for each context (inline, button, nav, feature, hero).
  • Utility classes.text-h1.text-h4, .text-p1.text-p3, .text-ui, .text-muted, .eyebrow, .card, .media, .btn, .btn-primary, .btn-secondary, .btn-tertiary, .btn-sm, .badge, .badge-light, .input, .checkbox.
Never hardcode a color, spacing value, font size, or border radius anywhere in the codebase. Always reference a token from theme.css. If a value isn’t tokenized yet, add it to theme.css first, then use it.

keystatic.config.ts

Defines the Keystatic CMS schema — the blog collection, its fields (title, publish date, description, body MDX), and the storage strategy (local Git-backed files in src/content/blog/). In production, Keystatic authenticates via Keystatic Cloud; serverless function invocations only occur when the editor uses the /keystatic UI — regular visitors load fully static pages at zero function cost.

astro.config.mjs

The Astro build configuration. Key settings:
  • site — set to https://borrissol.com for correct sitemap and canonical URL generation.
  • adapter@astrojs/netlify for hybrid rendering (static pages + Netlify functions for the Keystatic panel).
  • i18ndefaultLocale: 'ca', locales ['ca', 'es', 'en', 'fr'], prefixDefaultLocale: false (Catalan served at root without /ca/ prefix).
  • redirects — 301 rules for legacy /ca/* URLs and cross-language blog redirects (all /<lang>/blog/blog).
  • integrations@astrojs/sitemap (with hreflang cross-references between language variants), @astrojs/react (required by Keystatic), @astrojs/markdoc, @keystatic/astro.

netlify.toml

Controls the Netlify build and edge behaviour:
  • [build] — build command npm run build, publish directory dist.
  • [build.environment] — pins NODE_VERSION = "22.12.0" to match the Astro 6 requirement.
  • Bot-trap redirects — a series of forced-404 [[redirects]] rules that short-circuit common WordPress/PHP/admin-tool scanner probes (/wp-admin/*, /wp-login.php, /.env, /.git/*, etc.) at the Netlify edge layer. This prevents bot requests from invoking Astro SSR and consuming function credits.

URL routing reference

URL patternFileNotes
/src/pages/index.astroCatalan home (default locale, no prefix)
/es, /en, /frsrc/pages/[lang]/index.astroNon-Catalan home pages via getStaticPaths
/gallerysrc/pages/gallery.astroCatalan gallery
/es/gallery, /en/gallery, /fr/gallerysrc/pages/[lang]/gallery.astroLocalized gallery pages
/presssrc/pages/press.astroCatalan press page
/es/press, /en/press, /fr/presssrc/pages/[lang]/press.astroLocalized press pages
/blogsrc/pages/blog/index.astroBlog index (Catalan only)
/blog/[slug]src/pages/blog/[slug].astroIndividual blog posts (Catalan only)
/tuftingsrc/pages/tufting.astro + src/pages/[lang]/tufting.astroTufting workshop landing (CA root + ES/EN/FR via [lang])
/punch-needlesrc/pages/punch-needle.astro + src/pages/[lang]/punch-needle.astroPunch needle workshop landing
/feltingsrc/pages/felting.astro + src/pages/[lang]/felting.astroFelting workshop landing
/loomsrc/pages/loom.astro + src/pages/[lang]/loom.astroLoom weaving workshop landing
/borlasrc/pages/borla.astro + src/pages/[lang]/borla.astroBorla workshop landing
/summer-labsrc/pages/summer-lab.astro + src/pages/[lang]/summer-lab.astroSummer Lab seasonal offering (visibility controlled by src/config/seasonal.ts)
/team-buildingsrc/pages/team-building.astro + src/pages/[lang]/team-building.astroTeam building group format landing
/pelussetessrc/pages/pelussetes.astro + src/pages/[lang]/pelussetes.astroPelussetes workshop landing
/keystaticKeystatic integrationCMS panel (auth-gated in production, open in dev)
/ca, /ca/*301 → equivalent root URL (legacy redirect)
/es/blog, /en/blog, /fr/blog301 → /blog (blog is intentionally CA-only)

Build docs developers (and LLMs) love