Documentation Index Fetch the complete documentation index at: https://mintlify.com/abisai7/diccionario-chapin/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Chapinismos uses Astro components (.astro files) for building the UI. Components are highly reusable, support props, and can include scoped styles and client-side scripts.
Component Architecture
Component Categories
components/
├── Layout Components # Header, Footer, Navigation
├── Feature Components # SearchBox, WordCard, Ticker
├── Home Components # Homepage sections
├── Icon Components # SVG icons
└── Schema Components # JSON-LD structured data
Core Components
Main site header with logo, navigation, language switcher, and theme toggle.
src/components/Header.astro
---
import { getLangFromUrl } from "../utils/i18n" ;
import Logo from "./icons/Logo.astro" ;
import LanguageSwitcher from "./LanguageSwitcher.astro" ;
import Navigation from "./Navigation.astro" ;
import MobileMenu from "./MobileMenu.astro" ;
import ThemeToggle from "./ThemeToggle.astro" ;
const lang = getLangFromUrl ( Astro . url );
const prefix = lang === "en" ? "/en" : "/es" ;
---
< header class = "relative mx-auto max-w-[1100px] px-4 py-4" transition:persist >
< div class = "flex items-center justify-between gap-4" >
< a href = { ` ${ prefix } /` } class = "flex items-center gap-2" >
< Logo height = { 75 } />
</ a >
<!-- Desktop navigation -->
< nav class = "hidden items-center gap-2 md:flex" >
< Navigation />
< LanguageSwitcher />
< ThemeToggle />
</ nav >
<!-- Mobile navigation -->
< div class = "flex items-center gap-2 md:hidden" >
< LanguageSwitcher />
< ThemeToggle isMobile = { true } />
< MobileMenu />
</ div >
</ div >
</ header >
None - Uses Astro.url to detect language
Auto-detects language from URL
Responsive (desktop/mobile layouts)
Persistent across page transitions
import Header from "../components/Header.astro";
< Header />
WordCard Component
Displays a word preview card with category badge.
src/components/WordCard.astro
---
import type { CollectionEntry } from "astro:content" ;
import { getCategoryColor } from "../utils/categoryColors" ;
import { useTranslations } from "../utils/i18n" ;
import { ArrowRight } from "@lucide/astro" ;
interface Props {
entry : CollectionEntry < "words-es" | "words-en" >;
lang : string ;
titleLevel ?: "h3" | "h4" ;
}
const { entry , lang , titleLevel = "h4" } = Astro . props ;
const t = useTranslations ( lang );
---
< a
href = { `/ ${ lang } /palabras/ ${ entry . slug } /` }
class = "word-related-card rounded-lg border p-4 transition-all hover:-translate-y-1"
>
{ entry . data . category && (
< span
class = "absolute top-3 right-3 rounded-full px-2 py-0.5 text-xs"
style = { `background-color: ${ getCategoryColor ( entry . data . category ) } ;` }
>
{ entry . data . category }
</ span >
) }
{ titleLevel === "h3" ? (
< h3 class = "m-0 mb-2 font-semibold" > { entry . data . word } </ h3 >
) : (
< h4 class = "m-0 mb-2 font-semibold" > { entry . data . word } </ h4 >
) }
< p class = "m-0 line-clamp-2 text-sm" > { entry . data . meaning } </ p >
< span class = "mt-2 inline-flex items-center gap-1 text-xs" >
{ t ( "word.learn_more" ) }
< ArrowRight size = { 12 } />
</ span >
</ a >
Prop Type Required Default Description entryCollectionEntry Yes - Word data from content collection langstring Yes - Current language (es/en) titleLevel”h3” | “h4” No ”h4” Heading level for SEO
TypeScript props with validation
Dynamic category colors
Hover animations
Line clamping for long text
import WordCard from "../components/WordCard.astro";
{ words . map (( entry ) => (
< WordCard entry = { entry } lang = { lang } titleLevel = "h3" />
)) }
SearchBox Component
Search input with keyboard shortcut support.
src/components/SearchBox.astro
---
interface Props {
placeholder ?: string ;
}
const { placeholder = "Search..." } = Astro . props ;
---
< form role = "search" class = "search-form" >
< input
type = "search"
name = "q"
placeholder = { placeholder }
class = "search-input"
autocomplete = "off"
aria-label = "Search words"
/>
</ form >
< style >
.search-input {
width : 100 % ;
padding : 0.75 rem 1 rem ;
border-radius : 0.5 rem ;
border : 1 px solid var ( --border );
background : var ( --card );
color : var ( --text );
font-size : 1 rem ;
}
.search-input:focus {
outline : 2 px solid var ( --primary );
border-color : var ( --primary );
}
</ style >
Homepage Components
HeroSection Component
Homepage hero with title, subtitle, and search.
src/components/home/HeroSection.astro
---
import { Info } from "@lucide/astro" ;
import SearchBox from "../SearchBox.astro" ;
import { useTranslations } from "../../utils/i18n" ;
interface Props {
lang : string ;
}
const { lang } = Astro . props ;
const t = useTranslations ( lang );
---
< section class = "mx-auto max-w-[1100px]" >
< div class = "card-with-gradient m-6 grid gap-3.5" >
< h1 class = "gradient-text mx-4 mt-4 text-[clamp(1.8rem,2.4vw,2.6rem)]" >
{ t ( "home.title" ) }
</ h1 >
< p class = "text-muted mx-4 text-base" >
{ t ( "home.subtitle" ) }
</ p >
< div class = "mx-4 mb-4" >
< SearchBox placeholder = { t ( "home.search.placeholder" ) } />
</ div >
< div class = "text-muted mx-4 mb-4 hidden md:block" >
< span class = "inline-flex items-center gap-2" >
< Info size = { 16 } />
{ t ( "home.search.tip" ) }
< kbd class = "rounded border px-2 py-0.5" > / </ kbd >
{ t ( "home.search.tip2" ) }
</ span >
</ div >
</ div >
</ section >
FeaturedWords Component
Grid of featured word cards.
src/components/home/FeaturedWords.astro
---
import WordCard from "../WordCard.astro" ;
import { useTranslations } from "../../utils/i18n" ;
interface Props {
words : any [];
lang : string ;
}
const { words , lang } = Astro . props ;
const t = useTranslations ( lang );
---
< section class = "mx-auto max-w-[1100px] px-6" >
< h2 class = "mb-6 text-2xl font-bold" > { t ( "home.featured.title" ) } </ h2 >
< div class = "grid grid-cols-[repeat(auto-fill,minmax(260px,1fr))] gap-3.5" >
{ words . map (( entry ) => (
< WordCard entry = { entry } lang = { lang } titleLevel = "h3" />
)) }
</ div >
</ section >
Schema Components
JSON-LD structured data components for SEO.
WordSchema Component
src/components/schemas/WordSchema.astro
---
interface Props {
lang : string ;
siteUrl : string ;
word : any ;
slug : string ;
}
const { lang , siteUrl , word , slug } = Astro . props ;
const schema = {
"@context" : "https://schema.org" ,
"@type" : "DefinedTerm" ,
"name" : word . word ,
"description" : word . meaning ,
"inDefinedTermSet" : ` ${ siteUrl } / ${ lang } /indice/` ,
"url" : ` ${ siteUrl } / ${ lang } /palabras/ ${ slug } /` ,
};
---
< script type = "application/ld+json" set:html = { JSON . stringify ( schema ) } />
Creating New Components
Basic Component Template
Create the file
Create a new .astro file in src/components/: touch src/components/MyComponent.astro
Define the component
---
// TypeScript props interface
interface Props {
title : string ;
description ?: string ;
}
const { title , description } = Astro . props ;
---
< div class = "my-component" >
< h2 > { title } </ h2 >
{ description && < p > { description } </ p > }
</ div >
< style >
.my-component {
padding : 1 rem ;
border-radius : 0.5 rem ;
}
</ style >
Use the component
---
import MyComponent from "../components/MyComponent.astro" ;
---
< MyComponent title = "Hello" description = "World" />
Component with Client Script
For interactive components, add a <script> tag:
---
interface Props {
buttonText : string ;
}
const { buttonText } = Astro . props ;
---
< button id = "my-button" class = "btn" > { buttonText } </ button >
< script >
document . addEventListener ( "astro:page-load" , () => {
const button = document . getElementById ( "my-button" );
button ?. addEventListener ( "click" , () => {
alert ( "Clicked!" );
});
});
</ script >
Use astro:page-load event for scripts that should work with View Transitions.
Component with Slots
Use slots for flexible content:
---
interface Props {
title : string ;
}
const { title } = Astro . props ;
---
< section class = "card" >
< h2 > { title } </ h2 >
< div class = "content" >
< slot /> <!-- Default slot -->
</ div >
< footer >
< slot name = "footer" /> <!-- Named slot -->
</ footer >
</ section >
Usage:
< MyCard title = "Title" >
< p > This goes in the default slot </ p >
< div slot = "footer" > Footer content </ div >
</ MyCard >
Best Practices
Use TypeScript interfaces for props
interface Props {
title : string ;
count ?: number ; // Optional prop
}
const { title , count = 0 } = Astro.props; // Default value
Each component should have a single, clear purpose. Break large components into smaller, reusable pieces.
Styles in <style> tags are automatically scoped to the component: < style >
.my-class {
color : red ; /* Only affects this component */
}
</ style >
Use CSS custom properties for theming
< style >
.card {
background : var ( --card );
color : var ( --text );
border : 1 px solid var ( --border );
}
</ style >
For components that need translations: ---
import { useTranslations } from "../utils/i18n" ;
interface Props {
lang : string ;
}
const { lang } = Astro . props ;
const t = useTranslations ( lang );
---
Component Utilities
Category Colors
import { getCategoryColor } from "../utils/categoryColors" ;
const color = getCategoryColor ( "sustantivo" ); // Returns hex color
Translations
import { useTranslations } from "../utils/i18n" ;
const t = useTranslations ( "es" );
const title = t ( "home.title" );
Next Steps
Layouts Learn about layout components
Styling Deep dive into styling
Internationalization Work with translations