# Unified Site Configuration — Single Source of Truth # # Replaces: # site/config/routes/en.ncl + es.ncl (per-language routes) # site/ui/menus/menu.ncl (multilingual menus) # site/content/content-kinds.toml (content type definitions) # site/ui/footer/footer.ncl (footer metadata) # # Consumed by build_config::site_config::load_unified_site_config() in all # build.rs scripts (shared, client, server). # # NICKEL_IMPORT_PATH must point to rustelo/nickel/ (auto-detected by nickel.rs). # # Adding a new language: add the lang code to site.languages, add a paths # entry to every route record, and create the corresponding FTL file. # No other files need changing. let site_d = import "site/defaults.ncl" in let site_c = import "site/contracts.ncl" in let { make_route, make_content_route, make_external, priorities, orders, no_menu } = site_d in { site = { name = "Website", languages = ["en", "es"], default_language = "en", }, paths = { i18n = "site/i18n/locales", content = "site/content", themes = "site/config/themes", assets = "site/public", migrations = "rustelo/migrations", email_templates = "site/templates/email", work = "works-pv", }, themes = { default = "default", available = ["default", "dark", "corporate"], }, logo = { light_src = "/logos/site-logo-b.png", dark_src = "/logos/site-logo-w.png", alt = "Site logo", show_in_nav = true, show_in_footer = true, width = null, height = null, }, content_types = [ { name = "blog", directory = "blog", enabled = true, features = { style_mode = "row", style_css = "blog-content", use_feature = true, use_categories = true, use_tags = true, use_emojis = true, cta_view = "BlogCTAView", default_page_size = 8, page_size_options = [5, 8, 12, 20], show_page_info = true, pagination_style = "numbered", }, }, { name = "recipes", directory = "recipes", enabled = true, features = { style_mode = "grid", style_css = "recipe-content", use_feature = false, use_categories = true, use_tags = true, use_emojis = true, cta_view = "RecipesCTAView", default_page_size = 12, page_size_options = [6, 12, 18, 24], show_page_info = true, pagination_style = "numbered", }, }, ], database = { url = "sqlite:works-pv/data/dev_database.db", create_if_missing = true, max_connections = 5, min_connections = 1, connect_timeout = 30, idle_timeout = 600, max_lifetime = 1800, }, footer = { title = "Jesús Pérez", company_desc = { en = "Rust Developer & Infrastructure Consultant", es = "Desarrollador Rust y Consultor de Infraestructura", }, copyright_text = { en = "© 2024 Jesús Pérez. All rights reserved.", es = "© 2024 Jesús Pérez. Todos los derechos reservados.", }, social_links = [ { name = "LinkedIn", url = "https://linkedin.com/in/example-org", icon = "fab fa-linkedin" }, { name = "GitHub", url = "https://github.com/example-org", icon = "fab fa-github" }, ], }, routes = [ # ── Home ──────────────────────────────────────────────────────────────── make_route "HomePage" { en = "/", es = "/inicio" } & { priority = priorities.critical, menu = { enabled = true, order = orders.home, icon = "home", label_key = "nav-home", labels = { en = "Home", es = "Inicio" }, use_in = ["header"], }, }, # Alternate Spanish home path (/es) — no menu entry make_route "HomePage" { es = "/es" } & { priority = priorities.critical, menu = no_menu, }, # ── About ──────────────────────────────────────────────────────────────── make_route "AboutPage" { en = "/about", es = "/acerca-de" } & { priority = priorities.high, menu = { enabled = true, order = orders.about, icon = "fas fa-user", label_key = "nav-about", labels = { en = "About", es = "Acerca de" }, use_in = ["header"], }, }, # ── Services ───────────────────────────────────────────────────────────── make_route "ServicesPage" { en = "/services", es = "/servicios" } & { priority = priorities.high, menu = { enabled = true, order = orders.services, icon = "briefcase", label_key = "nav-services", labels = { en = "Services", es = "Servicios" }, use_in = ["header"], }, }, # ── Blog article viewer ─────────────────────────────────────────────────── make_content_route "PostViewer" "blog" { en = "/blog/{category}/{slug}", es = "/blog/{category}/{slug}" } & { priority = priorities.minimal, menu = no_menu, }, # ── Recipes article viewer ──────────────────────────────────────────────── make_content_route "PostViewer" "recipes" { en = "/recipes/{category}/{slug}", es = "/recetas/{category}/{slug}" } & { priority = priorities.minimal, menu = no_menu, }, # ── Blog category filter ────────────────────────────────────────────────── make_content_route "ContentIndex" "blog" { en = "/blog/{category}", es = "/blog/{category}" } & { priority = priorities.low, menu = no_menu, }, # ── Recipes category filter ─────────────────────────────────────────────── make_content_route "ContentIndex" "recipes" { en = "/recipes/{category}", es = "/recetas/{category}" } & { priority = priorities.low, menu = no_menu, }, # ── Blog (content index) ────────────────────────────────────────────────── make_content_route "ContentIndex" "blog" { en = "/blog", es = "/blog" } & { priority = priorities.normal, menu = { enabled = true, order = orders.blog, icon = "book", label_key = "nav-blog", labels = { en = "Blog", es = "Blog" }, use_in = ["header"], }, props = { content_type = "blog", cta_view = "BlogCTAView", style_css = "blog-content", style_mode = "row", use_categories = true, use_emojis = true, use_feature = true, use_links = [ ["archive", "/blog/archive"], ["rss", "/blog/rss.xml"], ["categories", "/blog/categories"], ], use_tags = true, }, }, # ── Recipes (content index) ─────────────────────────────────────────────── make_content_route "ContentIndex" "recipes" { en = "/recipes", es = "/recetas" } & { priority = priorities.normal, menu = { enabled = true, order = orders.recipes, icon = "lightbulb", label_key = "nav-recipes", labels = { en = "Recipes", es = "Recetas" }, use_in = ["header"], }, props = { content_type = "recipes", cta_view = "RecipesCTAView", style_css = "recipes-content", style_mode = "row", use_categories = true, use_feature = true, }, }, # ── Work Request ────────────────────────────────────────────────────────── make_route "WorkRequestPage" { en = "/work-request", es = "/solicitud-trabajo" } & { priority = priorities.normal, menu = no_menu, }, # ── Contact ─────────────────────────────────────────────────────────────── make_route "ContactPage" { en = "/contact", es = "/contacto" } & { priority = priorities.normal, menu = { enabled = true, order = orders.contact, icon = "fas fa-envelope", label_key = "nav-contact", labels = { en = "Contact", es = "Contacto" }, use_in = ["header"], }, }, # ── Legal / footer routes ───────────────────────────────────────────────── make_route "LegalPage" { en = "/legal", es = "/legal" } & { priority = priorities.low, menu = { enabled = true, order = 2, icon = "fas fa-gavel", label_key = "nav-legal", labels = { en = "Legal Notice", es = "Aviso Legal" }, use_in = ["footer"], }, }, make_route "PrivacyPage" { en = "/privacy", es = "/privacidad" } & { priority = priorities.low, menu = { enabled = true, order = 1, icon = "fas fa-shield-alt", label_key = "nav-privacy", labels = { en = "Privacy Policy", es = "Política de Privacidad" }, use_in = ["footer"], }, }, # ── User (not in sitemap) ───────────────────────────────────────────────── make_route "UserPage" { en = "/user", es = "/usuario" } & { priority = priorities.minimal, menu = no_menu, }, # ── Login (passwordless OTP) ────────────────────────────────────────────── make_route "LoginPage" { en = "/login", es = "/iniciar-sesion" } & { priority = priorities.minimal, menu = no_menu, }, # ── External links ──────────────────────────────────────────────────────── make_external "Kit-Digital" "/kitdigital.html" & { menu = { enabled = true, order = orders.external, label_key = "nav-kit-digital", labels = { en = "Kit-Digital", es = "Kit-Digital" }, visible_in = ["es"], use_in = ["header"], }, }, ], } | site_c.SiteConfig