# Callout Shortcode — Design Spec **Date:** 2026-04-29 **Status:** Approved --- ## Context Articles on danix.xyz need a way to call out notes, tips, warnings, and other semantic asides inline. No callout shortcode exists yet. SHORTCODES.md lists it as a planned future shortcode. This spec defines the design, CSS architecture, A11y requirements, and shortcode API. --- ## Approach **Single shortcode + CSS-only variants** (Approach C from brainstorm). One `callout.html` template handles all 6 types. Type-specific styling lives entirely in `main.css` via CSS custom properties and Tailwind utility classes. No inline style logic in the template. CSS rebuild required after adding new types. Chosen over: - Single shortcode with inline Hugo logic (more template complexity) - Separate shortcode per type (6 files, duplicated logic) --- ## Shortcode API ``` {{< callout type="note" >}} Content here. Supports **markdown**. {{< /callout >}} {{< callout type="danger" title="Custom heading" >}} Overrides the default i18n title. {{< /callout >}} ``` ### Parameters | Parameter | Required | Default | Description | |-----------|----------|---------|-------------| | `type` | Yes | — | One of: `note`, `tip`, `info`, `warning`, `danger`, `success` | | `title` | No | i18n key for type | Overrides the default translated title | --- ## Visual Design **Layout:** Left border accent (4px solid, type color) + fading bottom border (gradient left→transparent, 50% width, 1px, type color). Subtle background tint. Rounded on right side only (`border-radius: 0 6px 6px 0`). **Title row:** Feather icon (14×14, `aria-hidden="true"`) + uppercase label in `font-family: var(--font-mono)` (JetBrains Mono), 11px, 0.08em letter-spacing, type color. **Body text:** `var(--text)`, 14px, 1.6 line-height. Supports markdown via `.Inner | markdownify`. **Spacing:** `my-6` vertical margin, `py-3 px-4` inner padding. **Background opacity:** dark 0.08, light 0.06 — consistent with existing toast/badge pattern. --- ## Color System All colors via CSS custom properties. No hardcoded hex except the approved Danger exception. ### CSS Variables (added to `main.css`) ```css /* Dark mode (:root) */ --callout-note: var(--accent); /* purple #a855f7 */ --callout-tip: var(--accent2); /* green #00ff88 */ --callout-info: var(--type-link); /* cyan #38bdf8 */ --callout-warning: var(--type-life); /* amber #f59e0b */ --callout-danger: #ef4444; /* red — approved exception, universally semantic */ --callout-success: var(--accent2); /* green #00ff88 */ /* Light mode (html.theme-light) */ --callout-note: var(--accent); /* purple #7c3aed */ --callout-tip: var(--accent2); /* green #008f5a */ --callout-info: var(--type-link); /* cyan #0284c7 */ --callout-warning: var(--type-life); /* amber #d97706 */ --callout-danger: #ef4444; /* red — same in both themes */ --callout-success: var(--accent2); /* green #008f5a */ ``` ### Tailwind Classes (added to `main.css` via `@apply`) ```css .callout { @apply relative my-6 py-3 px-4 rounded-r-md; } /* Each type sets --callout-color so ::after gradient picks it up automatically */ .callout-note { --callout-color: var(--callout-note); border-left: 4px solid var(--callout-note); background: rgba(168,85,247,0.08); } .callout-tip { --callout-color: var(--callout-tip); border-left: 4px solid var(--callout-tip); background: rgba(0,255,136,0.08); } .callout-info { --callout-color: var(--callout-info); border-left: 4px solid var(--callout-info); background: rgba(56,189,248,0.08); } .callout-warning { --callout-color: var(--callout-warning); border-left: 4px solid var(--callout-warning); background: rgba(245,158,11,0.08); } .callout-danger { --callout-color: var(--callout-danger); border-left: 4px solid var(--callout-danger); background: rgba(239,68,68,0.08); } .callout-success { --callout-color: var(--callout-success); border-left: 4px solid var(--callout-success); background: rgba(0,255,136,0.08); } ``` The fading bottom border is a `::after` pseudo-element: ```css .callout::after { content: ''; position: absolute; bottom: 0; left: 0; width: 50%; height: 1px; background: linear-gradient(to right, var(--callout-color), transparent); } ``` **Light mode background opacity** — reduce to 0.06 per theming standard (light needs less emphasis). rgba values use THEMING-STANDARD.md corrected light vars: `--accent #7c3aed`, `--accent2 #008f5a`, `--type-link #0284c7`, `--type-life #d97706`. **Prerequisite:** `html.theme-light` in `main.css` must first be corrected to match THEMING-STANDARD.md (see implementation plan Task 0). ```css html.theme-light .callout-note { background: rgba(124,58,237,0.06); } /* #7c3aed */ html.theme-light .callout-tip { background: rgba(0,143,90,0.06); } /* #008f5a */ html.theme-light .callout-info { background: rgba(2,132,199,0.06); } /* #0284c7 */ html.theme-light .callout-warning { background: rgba(217,119,6,0.06); } /* #d97706 */ html.theme-light .callout-danger { background: rgba(239,68,68,0.06); } /* #ef4444 */ html.theme-light .callout-success { background: rgba(0,143,90,0.06); } /* #008f5a */ ``` --- ## Feather Icons per Type | Type | Feather icon name | Rationale | |------|-------------------|-----------| | note | `edit-2` | Writing/annotation | | tip | `zap` | Quick insight | | info | `info` | Standard info | | warning | `alert-triangle` | Universal warning symbol | | danger | `x-circle` | Stop/error | | success | `check-circle` | Confirmed/done | Icons rendered inline as ``. Feather is already loaded site-wide via `baseof.html`. --- ## i18n Keys Added to all 4 i18n files: `themes/danix-xyz-hacker/i18n/en.yaml`, `it.yaml` and content repo `i18n/en.yaml`, `it.yaml`. ```yaml # en.yaml callout_note: "Note" callout_tip: "Tip" callout_info: "Info" callout_warning: "Warning" callout_danger: "Danger" callout_success: "Success" # it.yaml callout_note: "Nota" callout_tip: "Suggerimento" callout_info: "Informazione" callout_warning: "Attenzione" callout_danger: "Pericolo" callout_success: "Successo" ``` --- ## Accessibility - `role="note"` on all types — semantic, non-intrusive to screen readers - `role="alert"` on `danger` type only — interrupts screen readers immediately (appropriate for critical warnings) - `aria-hidden="true"` on all Feather icons — decorative - Title text always present (i18n fallback) — color never used alone to convey meaning (WCAG 1.4.1) - Body text uses `var(--text)` — verified ≥4.5:1 contrast ratio against `var(--bg)` in both themes per THEMING-STANDARD.md - No animations — `prefers-reduced-motion` not required, but `::after` pseudo is static CSS, no transitions added --- ## Files to Create / Modify | File | Action | Notes | |------|--------|-------| | `themes/danix-xyz-hacker/layouts/shortcodes/callout.html` | **Create** | Shortcode template | | `themes/danix-xyz-hacker/assets/css/main.css` | **Modify** | Add `--callout-*` vars + `.callout-*` classes | | `themes/danix-xyz-hacker/i18n/en.yaml` | **Modify** | Add 6 callout title keys | | `themes/danix-xyz-hacker/i18n/it.yaml` | **Modify** | Add 6 callout title keys (Italian) | | `i18n/en.yaml` | **Modify** | Mirror keys in content repo | | `i18n/it.yaml` | **Modify** | Mirror keys in content repo | | `SHORTCODES.md` | **Modify** | Document callout shortcode | CSS rebuild required (`npm run build`) after CSS changes. --- ## Shortcode Template Sketch ```html {{- $type := .Get "type" | default "note" -}} {{- $title := .Get "title" | default (i18n (printf "callout_%s" $type)) -}} {{- $role := cond (eq $type "danger") "alert" "note" -}}
{{ $title }}
{{ .Inner | markdownify }}
``` Icon selection via Hugo `dict` lookup — no if/else chain: ``` {{- $icons := dict "note" "edit-2" "tip" "zap" "info" "info" "warning" "alert-triangle" "danger" "x-circle" "success" "check-circle" -}} {{- $icon := index $icons $type | default "info" -}} ``` --- ## Verification 1. Run `hugo server` — render an article with all 6 callout types 2. Toggle dark/light theme — verify colors switch correctly via CSS vars 3. Override title with `title="Custom"` — verify it replaces i18n default 4. Screen reader test: `danger` type must announce immediately (`role="alert"`); others must not interrupt 5. Run `npm run build` — verify CSS compiles without errors and Tailwind includes all `.callout-*` classes 6. Check light theme backgrounds use lower opacity (0.06) vs dark (0.08)