` |
+ | `contained` | No | If True, adds contained variant styling |
+ """
+ template = Template(
+ """
+
+
+
+ -
+ {% include "v3/includes/_content_event_card_item.html" with title="Boost 1.90.0 closed for major changes" description="Release closed for major code changes. Still open for serious problem fixes and docs changes without release manager review." date="29/10/25" datetime="29/10/25" card_url="#event-0" card_aria_label="Boost 1.90.0 closed for major changes" event_card_wrapper=False %}
+
+ -
+ {% include "v3/includes/_content_event_card_item.html" with title="C++ Now 2025 call for submissions" description="C++ Now conference is accepting talk proposals until March 15. Topics include modern C++, Boost libraries, and tooling." date="12/02/25" datetime="12/02/25" card_url="#event-1" card_aria_label="C++ Now 2025 call for submissions" event_card_wrapper=False %}
+
+ -
+ {% include "v3/includes/_content_event_card_item.html" with title="Boost 1.89.0 released" description="Boost 1.89.0 is available with updates to Asio, Beast, and several other libraries. See release notes for details." date="15/01/25" datetime="15/01/25" card_url="#event-2" card_aria_label="Boost 1.89.0 released" event_card_wrapper=False %}
+
+
+ {% include "v3/includes/_button.html" with label="View all" url="#" %}
+
+ """
+ )
+ return template.render(Context({}))
+
+ def as_cards(self, **kwargs):
+ """
+ Content event cards with the card wrapper enabled (clickable cards).
+ """
+ template = Template(
+ """
+
+
+
+ -
+ {% include "v3/includes/_content_event_card_item.html" with title="Boost 1.90.0 closed for major changes" description="Release closed for major code changes. Still open for serious problem fixes and docs changes without release manager review." date="29/10/25" datetime="29/10/25" card_url="#event-0" card_aria_label="Boost 1.90.0 closed for major changes" event_card_wrapper=True %}
+
+ -
+ {% include "v3/includes/_content_event_card_item.html" with title="C++ Now 2025 call for submissions" description="C++ Now conference is accepting talk proposals until March 15. Topics include modern C++, Boost libraries, and tooling." date="12/02/25" datetime="12/02/25" card_url="#event-1" card_aria_label="C++ Now 2025 call for submissions" event_card_wrapper=True %}
+
+ -
+ {% include "v3/includes/_content_event_card_item.html" with title="Boost 1.89.0 released" description="Boost 1.89.0 is available with updates to Asio, Beast, and several other libraries. See release notes for details." date="15/01/25" datetime="15/01/25" card_url="#event-2" card_aria_label="Boost 1.89.0 released" event_card_wrapper=True %}
+
+
+ {% include "v3/includes/_button.html" with label="View all" url="#" %}
+
+ """
+ )
+ return template.render(Context({}))
+
+
+class EventCardsPreview(LookbookPreview):
+
+ def all_variants_gallery(self, **kwargs):
+ """
+ Event cards gallery showing all theme variants (white, grey, yellow, green, teal)
+ plus clickable card variant.
+
+ Template: `v3/includes/_event_cards.html`
+
+ When called without `event_list` and `variant`, the template renders
+ the full gallery of all variants with sample content.
+
+ | Variable | Required | Description |
+ |---|---|---|
+ | `event_list` | No | List of event dicts (title, description, date, datetime) |
+ | `variant` | No | "white", "grey", "yellow", "green", or "teal" |
+ | `section_heading` | No | Default: "Upcoming Events" |
+ | `primary_btn_text` | No | Primary button text |
+ | `primary_btn_url` | No | Primary button URL |
+ | `secondary_btn_text` | No | Secondary button text |
+ | `secondary_btn_url` | No | Secondary button URL |
+ """
+ return render_to_string("v3/includes/_event_cards.html")
+
+
+class WhyBoostCardsPreview(LookbookPreview):
+
+ def default(self, **kwargs):
+ """
+ Why Boost section — a grid of icon + title + description cards.
+
+ Uses the same inline markup as the demo page with all 11 cards.
+
+ Template: `v3/includes/_content_detail_card_item.html` (wrapped in why-boost-cards section)
+
+ | Variable | Required | Description |
+ |---|---|---|
+ | `title` | Yes | Card heading |
+ | `description` | Yes | Card body text |
+ | `icon_name` | No | Icon name |
+ """
+ template = Template(
+ """
+
+ Why Boost?
+
+ {% include "v3/includes/_content_detail_card_item.html" with title="Get help" description="Tap into quick answers, networking, and chat with 24,000+ members." icon_name="bullseye-arrow" %}
+ {% include "v3/includes/_content_detail_card_item.html" with title="Documentation" description="Browse library docs, examples, and release notes in one place." icon_name="link" %}
+ {% include "v3/includes/_content_detail_card_item.html" with title="Community" description="Mailing lists, GitHub, and community guidelines for contributors." icon_name="human" %}
+ {% include "v3/includes/_content_detail_card_item.html" with title="Releases" description="Latest releases, download links, and release notes." icon_name="info-box" %}
+ {% include "v3/includes/_content_detail_card_item.html" with title="Learn" description="Access documentation, books, and courses to level up your C++." icon_name="bullseye-arrow" %}
+ {% include "v3/includes/_content_detail_card_item.html" with title="Contribute" description="Report issues, submit patches, and join the community." icon_name="bullseye-arrow" %}
+ {% include "v3/includes/_content_detail_card_item.html" with title="Stay updated" description="Releases, news, and announcements from the Boost community." icon_name="bullseye-arrow" %}
+ {% include "v3/includes/_content_detail_card_item.html" with title="Libraries" description="Portable, peer-reviewed libraries for a wide range of use cases." icon_name="bullseye-arrow" %}
+ {% include "v3/includes/_content_detail_card_item.html" with title="Standards" description="Many Boost libraries have been adopted into the C++ standard." icon_name="bullseye-arrow" %}
+ {% include "v3/includes/_content_detail_card_item.html" with title="Quality" description="Peer-reviewed code and documentation maintained by the community." icon_name="bullseye-arrow" %}
+ {% include "v3/includes/_content_detail_card_item.html" with title="Cross-platform" description="Libraries designed to work across compilers and platforms." icon_name="bullseye-arrow" %}
+
+
+ """
+ )
+ return template.render(Context({}))
+
+
+class CategoryTagsPreview(LookbookPreview):
+
+ def all_variants(self, **kwargs):
+ """
+ Category tags — all size and colour variants with default and hover states.
+
+ Template: `v3/includes/_category_cards.html`
+
+ When called without `category_tags`, shows the full variant gallery.
+
+ | Variable | Required | Description |
+ |---|---|---|
+ | `category_tags` | No | List of dicts (tag_label, url, variant, size, aria_label) |
+ | `section_heading` | No | Default: "Category tags" |
+ | `show_version_tags` | No | If truthy, shows version tags block |
+ """
+ return render_to_string(
+ "v3/includes/_category_cards.html",
+ {
+ "show_version_tags": True,
+ },
+ )
diff --git a/previews/dialog_preview.py b/previews/dialog_preview.py
new file mode 100644
index 000000000..07353c680
--- /dev/null
+++ b/previews/dialog_preview.py
@@ -0,0 +1,31 @@
+from django_lookbook.preview import LookbookPreview
+from django.template import Context, Template
+
+
+class DialogPreview(LookbookPreview):
+
+ def with_description(self, **kwargs):
+ """
+ Dialog modal with title, description, and two action buttons.
+
+ Template: `v3/includes/_dialog.html`
+
+ | Variable | Required | Description |
+ |---|---|---|
+ | `dialog_id` | Yes | Unique ID for this dialog instance |
+ | `title` | Yes | Dialog title |
+ | `description` | No | Descriptive text below the title |
+ | `primary_label` | Yes | Primary action button text |
+ | `secondary_label` | Yes | Secondary action button text |
+ | `primary_style` | No | Primary button style. Default: "secondary-grey" |
+ | `secondary_style` | No | Secondary button style. Default: "primary" |
+ | `primary_url` | No | Primary button URL |
+ | `secondary_url` | No | Secondary button URL. Default: "#" (closes dialog) |
+ """
+ template = Template(
+ """
+
Open dialog
+ {% include "v3/includes/_dialog.html" with dialog_id="demo-dialog-with-desc" title="Title of Dialog" description="Description that can go inside of Dialog" primary_url="#_" secondary_url="#_" primary_label="Button" secondary_label="Button" %}
+ """
+ )
+ return template.render(Context({}))
diff --git a/previews/forms_preview.py b/previews/forms_preview.py
new file mode 100644
index 000000000..47c5fd7cc
--- /dev/null
+++ b/previews/forms_preview.py
@@ -0,0 +1,163 @@
+import json
+
+from django_lookbook.preview import LookbookPreview
+from django.template.loader import render_to_string
+
+
+class FormsPreview(LookbookPreview):
+
+ def text_field(self, **kwargs):
+ """
+ Basic text input field.
+
+ Template: `v3/includes/_field_text.html`
+
+ | Variable | Required | Description |
+ |---|---|---|
+ | `name` | Yes | Input name attribute |
+ | `label` | No | Label text |
+ | `placeholder` | No | Placeholder text |
+ | `value` | No | Pre-filled value |
+ | `type` | No | Input type. Default: "text" |
+ | `help_text` | No | Help text below the field |
+ | `error` | No | Error message (activates error state) |
+ | `icon_left` | No | Icon name for left slot |
+ | `submit_icon` | No | Icon name for a submit button in right slot |
+ | `submit_label` | No | Aria-label for submit button |
+ | `required` | No | Adds required attribute |
+ | `disabled` | No | Adds disabled attribute |
+ | `extra_class` | No | Additional CSS classes |
+ """
+ return render_to_string(
+ "v3/includes/_field_text.html",
+ {
+ "name": "ex_basic",
+ "label": "Text field",
+ "placeholder": "Enter text...",
+ },
+ )
+
+ def text_field_with_icon(self, **kwargs):
+ """
+ Text field with a left-side icon (e.g. search).
+ """
+ return render_to_string(
+ "v3/includes/_field_text.html",
+ {
+ "name": "ex_search",
+ "label": "With icon",
+ "placeholder": "Search...",
+ "icon_left": "search",
+ },
+ )
+
+ def text_field_error(self, **kwargs):
+ """
+ Text field in error state with a validation message.
+ """
+ return render_to_string(
+ "v3/includes/_field_text.html",
+ {
+ "name": "ex_error",
+ "label": "Error state",
+ "placeholder": "Enter value",
+ "error": "This field is required.",
+ },
+ )
+
+ def checkbox(self, **kwargs):
+ """
+ Checkbox field.
+
+ Template: `v3/includes/_field_checkbox.html`
+
+ | Variable | Required | Description |
+ |---|---|---|
+ | `name` | Yes | Input name attribute |
+ | `label` | Yes | Label text |
+ | `checked` | No | If truthy, checkbox is checked |
+ | `value` | No | Input value. Default: "on" |
+ | `required` | No | Adds required attribute |
+ | `disabled` | No | Adds disabled attribute |
+ | `extra_class` | No | Additional CSS classes |
+ """
+ return render_to_string(
+ "v3/includes/_field_checkbox.html",
+ {
+ "name": "ex_agree",
+ "label": "I agree to the terms and conditions",
+ },
+ )
+
+ def combo_field(self, **kwargs):
+ """
+ Searchable combo (dropdown) field. Requires Alpine.js.
+
+ Template: `v3/includes/_field_combo.html`
+
+ | Variable | Required | Description |
+ |---|---|---|
+ | `name` | Yes | Input name attribute |
+ | `label` | No | Label text |
+ | `placeholder` | No | Placeholder when nothing selected |
+ | `options_json` | Yes | JSON string of options `[{"value":"...","label":"..."}]` |
+ | `selected` | No | Pre-selected value |
+ | `help_text` | No | Help text |
+ | `error` | No | Error message |
+ | `required` | No | Adds required attribute |
+ | `extra_class` | No | Additional CSS classes |
+ """
+ options = json.dumps(
+ [
+ {"value": "asio", "label": "Asio"},
+ {"value": "beast", "label": "Beast"},
+ {"value": "filesystem", "label": "Filesystem"},
+ {"value": "json", "label": "JSON"},
+ {"value": "spirit", "label": "Spirit"},
+ ]
+ )
+ return render_to_string(
+ "v3/includes/_field_combo.html",
+ {
+ "name": "ex_library",
+ "label": "Combo (searchable)",
+ "placeholder": "Search libraries...",
+ "options_json": options,
+ },
+ )
+
+ def multiselect_field(self, **kwargs):
+ """
+ Multi-select dropdown field. Requires Alpine.js.
+
+ Template: `v3/includes/_field_multiselect.html`
+
+ | Variable | Required | Description |
+ |---|---|---|
+ | `name` | Yes | Input name attribute |
+ | `label` | No | Label text |
+ | `placeholder` | No | Placeholder when nothing selected |
+ | `options_json` | Yes | JSON string of options |
+ | `selected_json` | No | JSON string of pre-selected values |
+ | `help_text` | No | Help text |
+ | `error` | No | Error message |
+ | `extra_class` | No | Additional CSS classes |
+ """
+ options = json.dumps(
+ [
+ {"value": "algorithms", "label": "Algorithms"},
+ {"value": "containers", "label": "Containers"},
+ {"value": "io", "label": "I/O"},
+ {"value": "math", "label": "Math & Numerics"},
+ {"value": "networking", "label": "Networking"},
+ ]
+ )
+ return render_to_string(
+ "v3/includes/_field_multiselect.html",
+ {
+ "name": "ex_categories",
+ "label": "Multi-select",
+ "placeholder": "Select categories...",
+ "options_json": options,
+ },
+ )
diff --git a/previews/horizontal_card_preview.py b/previews/horizontal_card_preview.py
new file mode 100644
index 000000000..0329c7570
--- /dev/null
+++ b/previews/horizontal_card_preview.py
@@ -0,0 +1,33 @@
+from django_lookbook.preview import LookbookPreview
+from django.template.loader import render_to_string
+from django.conf import settings
+
+
+class HorizontalCardPreview(LookbookPreview):
+
+ def default(self, **kwargs):
+ """
+ Horizontal card with side-by-side text and image, plus CTA button.
+
+ Template: `v3/includes/_horizontal_card.html`
+
+ | Variable | Required | Description |
+ |---|---|---|
+ | `title` | Yes | Card heading |
+ | `text` | Yes | Description text beside the image |
+ | `image_url` | Yes | URL of the image |
+ | `image_alt` | No | Alt text for image |
+ | `button_url` | No | CTA link destination |
+ | `button_label` | No | CTA button text |
+ | `button_style` | No | Button style variant |
+ """
+ return render_to_string(
+ "v3/includes/_horizontal_card.html",
+ {
+ "title": "Build anything with Boost",
+ "text": "Use, modify, and distribute Boost libraries freely. No binary attribution needed.",
+ "image_url": f"{settings.STATIC_URL}img/checker.png",
+ "button_url": "#",
+ "button_label": "See license details",
+ },
+ )
diff --git a/previews/install_card_preview.py b/previews/install_card_preview.py
new file mode 100644
index 000000000..64714f980
--- /dev/null
+++ b/previews/install_card_preview.py
@@ -0,0 +1,52 @@
+from django_lookbook.preview import LookbookPreview
+from django.template.loader import render_to_string
+
+
+INSTALL_CARD_PKG_MANAGERS = [
+ {"label": "Conan", "value": "conan", "command": "conan install boost"},
+ {"label": "Vcpkg", "value": "vcpkg", "command": "vcpkg install boost"},
+]
+
+INSTALL_CARD_SYSTEM_INSTALL = [
+ {
+ "label": "Ubuntu",
+ "value": "ubuntu",
+ "command": "sudo apt install libboost-all-dev",
+ },
+ {
+ "label": "Fedora",
+ "value": "fedora",
+ "command": "sudo dnf install boost-devel",
+ },
+ {
+ "label": "CentOS",
+ "value": "centos",
+ "command": "sudo yum install boost-devel",
+ },
+ {"label": "Arch", "value": "arch", "command": "sudo pacman -S boost"},
+ {"label": "Homebrew", "value": "homebrew", "command": "brew install boost"},
+]
+
+
+class InstallCardPreview(LookbookPreview):
+
+ def default(self, **kwargs):
+ """
+ Install card with tabbed installation methods and dynamic command display.
+
+ Template: `v3/includes/_install_card.html`
+
+ | Variable | Required | Description |
+ |---|---|---|
+ | `title` | No | Card heading. Default: "Install Boost and get started in your terminal." |
+ | `install_card_pkg_managers` | Yes | List of dicts with: label, value, command |
+ | `install_card_system_install` | Yes | List of dicts with: label, value, command |
+ """
+ return render_to_string(
+ "v3/includes/_install_card.html",
+ {
+ "title": "Install Boost and get started in your terminal.",
+ "install_card_pkg_managers": INSTALL_CARD_PKG_MANAGERS,
+ "install_card_system_install": INSTALL_CARD_SYSTEM_INSTALL,
+ },
+ )
diff --git a/previews/stats_preview.py b/previews/stats_preview.py
new file mode 100644
index 000000000..dd126ec82
--- /dev/null
+++ b/previews/stats_preview.py
@@ -0,0 +1,130 @@
+from django_lookbook.preview import LookbookPreview
+from django.template.loader import render_to_string
+
+
+SAMPLE_BARS = [
+ {"label": "1.80.0", "height_px": 45},
+ {"label": "1.81.0", "height_px": 62},
+ {"label": "1.82.0", "height_px": 78},
+ {"label": "1.83.0", "height_px": 55},
+ {"label": "1.84.0", "height_px": 90},
+ {"label": "1.85.0", "height_px": 40},
+ {"label": "1.86.0", "height_px": 72},
+ {"label": "1.87.0", "height_px": 85},
+ {"label": "1.88.0", "height_px": 60},
+ {"label": "1.89.0", "height_px": 95},
+]
+
+
+class StatsInNumbersPreview(LookbookPreview):
+
+ def default_theme(self, **kwargs):
+ """
+ Stats bar chart card with the default theme.
+
+ Template: `v3/includes/_stats_in_numbers.html`
+
+ | Variable | Required | Description |
+ |---|---|---|
+ | `heading` | Yes | Section heading |
+ | `description` | Yes | Short description below heading |
+ | `theme` | No | "default", "yellow", "green", or "teal". Default: "default" |
+ | `bars` | Yes | List of dicts with `label` and `height_px` |
+ | `primary_cta_label` | Yes | Primary button text |
+ | `primary_cta_url` | Yes | Primary button URL |
+ | `secondary_cta_label` | No | Secondary button text |
+ | `secondary_cta_url` | No | Secondary button URL |
+ """
+ return render_to_string(
+ "v3/includes/_stats_in_numbers.html",
+ {
+ "heading": "Commits per release",
+ "description": "Commit count by Boost release for this library.",
+ "bars": SAMPLE_BARS,
+ "theme": "default",
+ "primary_cta_label": "View library",
+ "primary_cta_url": "#",
+ },
+ )
+
+ def yellow_theme(self, **kwargs):
+ """
+ Stats bar chart with yellow theme.
+ """
+ return render_to_string(
+ "v3/includes/_stats_in_numbers.html",
+ {
+ "heading": "Commits per release",
+ "description": "Commit count by Boost release for this library.",
+ "bars": SAMPLE_BARS,
+ "theme": "yellow",
+ "primary_cta_label": "View library",
+ "primary_cta_url": "#",
+ },
+ )
+
+ def green_theme(self, **kwargs):
+ """
+ Stats bar chart with green theme.
+ """
+ return render_to_string(
+ "v3/includes/_stats_in_numbers.html",
+ {
+ "heading": "Commits per release",
+ "description": "Commit count by Boost release for this library.",
+ "bars": SAMPLE_BARS,
+ "theme": "green",
+ "primary_cta_label": "View library",
+ "primary_cta_url": "#",
+ },
+ )
+
+ def teal_theme(self, **kwargs):
+ """
+ Stats bar chart with teal theme.
+ """
+ return render_to_string(
+ "v3/includes/_stats_in_numbers.html",
+ {
+ "heading": "Commits per release",
+ "description": "Commit count by Boost release for this library.",
+ "bars": SAMPLE_BARS,
+ "theme": "teal",
+ "primary_cta_label": "View library",
+ "primary_cta_url": "#",
+ },
+ )
+
+ def with_secondary_cta(self, **kwargs):
+ """
+ Stats card with both primary and secondary CTA buttons.
+ """
+ return render_to_string(
+ "v3/includes/_stats_in_numbers.html",
+ {
+ "heading": "Commits per release",
+ "description": "Commit count by Boost release for this library.",
+ "bars": SAMPLE_BARS,
+ "theme": "default",
+ "primary_cta_label": "View library",
+ "primary_cta_url": "#",
+ "secondary_cta_label": "View all stats",
+ "secondary_cta_url": "#",
+ },
+ )
+
+ def few_bars(self, **kwargs):
+ """
+ Stats card with only 5 bars, demonstrating flexible chart sizing.
+ """
+ return render_to_string(
+ "v3/includes/_stats_in_numbers.html",
+ {
+ "heading": "Commits per release",
+ "description": "Same data limited to 5 bars.",
+ "bars": SAMPLE_BARS[:5],
+ "theme": "teal",
+ "primary_cta_label": "View library",
+ "primary_cta_url": "#",
+ },
+ )
diff --git a/previews/template_preview.py b/previews/template_preview.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/previews/tooltips_preview.py b/previews/tooltips_preview.py
new file mode 100644
index 000000000..885e95f9a
--- /dev/null
+++ b/previews/tooltips_preview.py
@@ -0,0 +1,47 @@
+from django_lookbook.preview import LookbookPreview
+from django.template import Context, Template
+
+
+class TooltipsPreview(LookbookPreview):
+
+ def tooltip_buttons_with_text(self, **kwargs):
+ """
+ Tooltip buttons that include visible button text alongside the icon.
+
+ Template: `v3/includes/_button_tooltip_v3.html`
+
+ | Variable | Required | Description |
+ |---|---|---|
+ | `label` | Yes | Tooltip content text |
+ | `position` | No | Tooltip position: `top`, `right`, `bottom`, `left`. Default: `bottom` |
+ | `button_text` | No | Visible text on the trigger button |
+ | `url` | No | If set, renders as `
` instead of `