Rustelo/resources/nickel/site/contracts.ncl
Jesús Pérez f1010e9d07
chore: update
2026-07-18 20:16:16 +01:00

308 lines
6.5 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Unified Site Configuration Contracts
#
# Type contracts for site.ncl — validates the complete site configuration
# including site metadata, paths, themes, content types, and routes with
# embedded multilingual menu data.
#
# JSON output of site.ncl is deserialized by build_config::site_config::UnifiedSiteConfig.
{
SiteMetadata = {
name
| String
| doc "Site display name",
languages
| Array String
| doc "Supported language codes (ISO 639-1, e.g. ['en', 'es'])",
default_language
| String
| doc "Default language code when none is specified in URL",
},
SitePaths = {
i18n
| String
| doc "Path to i18n/FTL locales directory",
content
| String
| doc "Path to content directory",
themes
| String
| doc "Path to themes configuration directory",
assets
| String
| doc "Path to public assets directory",
migrations
| String
| doc "Path to SQL migration files directory (server-only)"
| optional,
email_templates
| String
| doc "Path to email template files directory (server-only)"
| optional,
work
| String
| doc "Path to work-in-progress / staging assets directory (implementation-specific)"
| optional,
},
ThemeConfig = {
default
| String
| doc "Default theme name",
available
| Array String
| doc "List of available theme names",
},
ContentTypeFeatures = {
style_mode
| String
| doc "Display style: 'row' or 'grid'",
use_feature
| Bool
| doc "Enable featured content at top of index",
use_categories
| Bool
| default = true,
use_tags
| Bool
| default = true,
use_emojis
| Bool
| default = false,
cta_view
| String
| doc "CTA component name (e.g. 'BlogCTAView')",
default_page_size
| Number
| default = 10,
# Allow additional feature fields without breaking the contract
..
},
ContentType = {
name
| String
| doc "Content type identifier (e.g. 'blog', 'recipes')",
directory
| String
| doc "Directory name under content path",
enabled
| Bool
| default = true,
features
| ContentTypeFeatures
| doc "Content display and pagination settings",
},
# Database connection configuration.
# Structural settings (type, path, pool sizing) belong here.
# Credentials and full overrides go in .env via DATABASE_URL.
DatabaseConfig = {
url
| String
| doc "Database connection URL (e.g. 'sqlite:data/dev.db' or 'postgres://...')",
create_if_missing
| Bool
| doc "Create the SQLite database file if it does not exist"
| default = true,
max_connections
| Number
| doc "Maximum number of connections in the pool"
| default = 5,
min_connections
| Number
| doc "Minimum number of idle connections in the pool"
| default = 1,
connect_timeout
| Number
| doc "Connection acquisition timeout in seconds"
| default = 30,
idle_timeout
| Number
| doc "Maximum idle connection duration in seconds"
| default = 600,
max_lifetime
| Number
| doc "Maximum connection lifetime in seconds"
| default = 1800,
},
# Footer metadata — absorbed inline into SiteConfig.
FooterMetadata = {
title
| String
| doc "Footer title (language-neutral, e.g. author name)",
company_desc
| { _ : String }
| doc "Company description keyed by language code",
copyright_text
| { _ : String }
| doc "Copyright notice keyed by language code",
social_links
| Array {
name | String,
url | String,
icon | String,
}
| default = [],
},
# Menu configuration embedded directly in Route.
# At least one of label_key or labels must be present (validated by Nickel contracts
# plus runtime assertion in Rust loader).
MenuEntry = {
enabled
| Bool
| doc "Whether this route appears in navigation"
| default = false,
order
| Number
| doc "Display order (lower = first)"
| optional,
icon
| String
| doc "Icon identifier (e.g. 'home', 'fas fa-user')"
| optional,
label_key
| String
| doc "Primary: FTL i18n key for label (e.g. 'nav-home')"
| optional,
labels
| { _ : String }
| doc "Fallback inline labels keyed by language code"
| optional,
visible_in
| Array String
| doc "Language codes this item is visible in. Empty = all languages."
| default = [],
use_in
| Array String
| doc "Navigation zones: ['header'], ['footer'], or ['header','footer']"
| default = ["header"],
},
# A unified route entry covering all languages in a single record.
# paths maps language code → URL path (e.g. { en = '/', es = '/inicio' }).
Route = {
component
| String
| doc "Page component name (e.g. 'HomePage', 'ContentIndex')",
paths
| { _ : String }
| doc "URL paths keyed by language code",
priority
| Number
| doc "SEO/sitemap priority (0.01.0)"
| default = 0.8,
content_type
| String
| doc "Content type for dynamic routes (e.g. 'blog')"
| optional,
menu
| MenuEntry
| doc "Navigation menu configuration for this route",
props
| { _ : Dyn }
| doc "Additional route-specific properties passed to component"
| optional,
},
LogoConfig = {
light_src
| String
| doc "Path to light-mode logo image",
dark_src
| String
| doc "Path to dark-mode logo image (empty string disables dark variant)",
alt
| String
| doc "Alt text for the logo image",
show_in_nav
| Bool
| doc "Whether to show the logo in the navigation bar",
show_in_footer
| Bool
| doc "Whether to show the logo in the footer",
width
| optional
| doc "Optional logo width (CSS value or null)",
height
| optional
| doc "Optional logo height (CSS value or null)",
},
SiteConfig = {
site
| SiteMetadata,
paths
| SitePaths,
themes
| ThemeConfig,
logo
| LogoConfig,
content_types
| Array ContentType,
database
| DatabaseConfig
| doc "Database connection and pool configuration",
footer
| FooterMetadata,
routes
| Array Route,
},
}