From a9e0bc7ad34ac26802235c74f791e8b9b30f2936 Mon Sep 17 00:00:00 2001 From: Zhongwei Li Date: Sun, 30 Nov 2025 08:48:10 +0800 Subject: [PATCH] Initial commit --- .claude-plugin/plugin.json | 12 + README.md | 3 + plugin.lock.json | 68 +++ skills/brand-yml/README.md | 82 +++ skills/brand-yml/SKILL.md | 383 +++++++++++++ skills/brand-yml/references/brand-yml-in-r.md | 447 ++++++++++++++++ skills/brand-yml/references/brand-yml-spec.md | 408 ++++++++++++++ skills/brand-yml/references/quarto.md | 504 ++++++++++++++++++ skills/brand-yml/references/shiny-python.md | 395 ++++++++++++++ skills/brand-yml/references/shiny-r.md | 378 +++++++++++++ 10 files changed, 2680 insertions(+) create mode 100644 .claude-plugin/plugin.json create mode 100644 README.md create mode 100644 plugin.lock.json create mode 100644 skills/brand-yml/README.md create mode 100644 skills/brand-yml/SKILL.md create mode 100644 skills/brand-yml/references/brand-yml-in-r.md create mode 100644 skills/brand-yml/references/brand-yml-spec.md create mode 100644 skills/brand-yml/references/quarto.md create mode 100644 skills/brand-yml/references/shiny-python.md create mode 100644 skills/brand-yml/references/shiny-r.md diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..bbe5133 --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,12 @@ +{ + "name": "quarto", + "description": "Collection of skills for Quarto document creation", + "version": "0.0.0-2025.11.28", + "author": { + "name": "Garrick Aden-Buie (Posit, PBC)", + "email": "garrick@posit.co" + }, + "skills": [ + "./skills/brand-yml" + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..ee89960 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# quarto + +Collection of skills for Quarto document creation diff --git a/plugin.lock.json b/plugin.lock.json new file mode 100644 index 0000000..bbd5fba --- /dev/null +++ b/plugin.lock.json @@ -0,0 +1,68 @@ +{ + "$schema": "internal://schemas/plugin.lock.v1.json", + "pluginId": "gh:posit-dev/skills:quarto", + "normalized": { + "repo": null, + "ref": "refs/tags/v20251128.0", + "commit": "f026c20bc2cfe1047a6bc3351b6c4d7902ef1720", + "treeHash": "ce436a7c5d8d9ef05ddffe2881164ced6bc9608f69ed15a10a6d5eb791a26fb7", + "generatedAt": "2025-11-28T10:27:40.229594Z", + "toolVersion": "publish_plugins.py@0.2.0" + }, + "origin": { + "remote": "git@github.com:zhongweili/42plugin-data.git", + "branch": "master", + "commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390", + "repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data" + }, + "manifest": { + "name": "quarto", + "description": "Collection of skills for Quarto document creation" + }, + "content": { + "files": [ + { + "path": "README.md", + "sha256": "4b23f4c6f5763c0ceea2addbe86c6fcfb02db59745e85c637a2516a507832d94" + }, + { + "path": ".claude-plugin/plugin.json", + "sha256": "1e734b1cecbf4327e77dce3f79afd900ccaf4fc93c44d718b859257b31e9cc84" + }, + { + "path": "skills/brand-yml/README.md", + "sha256": "3ead89473df4809ad5d7effbbe513a691de054acd985e808025ff0726d0241e6" + }, + { + "path": "skills/brand-yml/SKILL.md", + "sha256": "25ac6c5b31223486df06ea742f952ff608a186dfa07f801d3dab10fdf52a0ebc" + }, + { + "path": "skills/brand-yml/references/brand-yml-in-r.md", + "sha256": "780fb3bbe9a2750ca5b8ad6e26ee33252442111a6f2304cb94b9dfacf3ca1f40" + }, + { + "path": "skills/brand-yml/references/shiny-r.md", + "sha256": "0109581d56119a7a6c1dbb1b06254deee018ef922da2ceec2a7039b1244cb59d" + }, + { + "path": "skills/brand-yml/references/quarto.md", + "sha256": "81427cd4b7154faa638d5e5e56a569239cca83d13f3a208bbf2d20f43e29d30e" + }, + { + "path": "skills/brand-yml/references/brand-yml-spec.md", + "sha256": "4c1c8800cb9a80563a78ba3b7ac7590f775535fc91c338f04e0b9ed61e5ec606" + }, + { + "path": "skills/brand-yml/references/shiny-python.md", + "sha256": "6d034f3bba828070478c62e2b8272ea6572971f2fd607b1128504d50125cf2db" + } + ], + "dirSha256": "ce436a7c5d8d9ef05ddffe2881164ced6bc9608f69ed15a10a6d5eb791a26fb7" + }, + "security": { + "scannedAt": null, + "scannerVersion": null, + "flags": [] + } +} \ No newline at end of file diff --git a/skills/brand-yml/README.md b/skills/brand-yml/README.md new file mode 100644 index 0000000..4a938e7 --- /dev/null +++ b/skills/brand-yml/README.md @@ -0,0 +1,82 @@ +# brand.yml Skill + +Create and use `_brand.yml` files for consistent branding across Shiny applications and Quarto documents. + +## What This Skill Does + +This skill helps Claude: +- Create `_brand.yml` files from brand guidelines +- Apply brand styling to Shiny for R apps using bslib +- Apply brand styling to Shiny for Python apps using ui.Theme +- Use brand.yml in Quarto documents, presentations, and PDFs +- Troubleshoot brand integration issues + +## When to Use + +Use this skill when working with: +- Brand styling and corporate identity +- Colors, fonts, and logos in Shiny or Quarto +- Creating or modifying brand.yml files +- Applying consistent branding across multiple projects + +## What is brand.yml? + +brand.yml is a YAML-based specification that translates brand guidelines into a portable, machine-readable format. It enables consistent styling across Shiny apps (R and Python) and Quarto documents (HTML, PDFs, presentations, dashboards) from a single `_brand.yml` file. + +## Key Features + +- **Complete specification**: Full brand.yml spec with all sections, fields, and validation rules +- **Framework integration guides**: Separate guides for Shiny R, Shiny Python, and Quarto +- **Self-contained**: All necessary information to create and use brand.yml files without external documentation +- **Best practices**: Guidance on file structure, naming conventions, and common patterns + +## Skill Structure + +``` +brand-yml/ +├── SKILL.md # Main skill file with workflows and decision tree +└── references/ + ├── brand-yml-spec.md # Complete brand.yml specification + ├── shiny-r.md # Shiny for R integration (bslib) + ├── shiny-python.md # Shiny for Python integration (ui.Theme) + └── quarto.md # Quarto integration (all formats) +``` + +## Usage + +The skill automatically loads based on keywords related to brand styling, colors, fonts, or brand.yml files. Claude will: + +1. Determine the user's goal (creating, using, or troubleshooting) +2. Load the appropriate reference documentation +3. Guide the user through the workflow +4. Create or modify files as needed + +## Examples + +**Creating a brand.yml file:** +> "Create a _brand.yml file for our company with primary color #0066cc and Inter font from Google Fonts" + +**Applying to Shiny R:** +> "Add brand styling to this Shiny app using our _brand.yml file" + +**Applying to Quarto:** +> "Use our brand colors in this Quarto presentation" + +**Troubleshooting:** +> "Why aren't the brand colors showing up in my Shiny app?" + +## Marketplace Registration + +This skill is registered in two marketplace categories: + +- **shiny**: For Shiny app developers +- **quarto**: For Quarto document creators + +Both point to the same skill directory but provide context-appropriate discovery. + +## Related Resources + +- [brand.yml project](https://posit-dev.github.io/brand-yml/) +- [Shiny for R brand.yml guide](https://rstudio.github.io/bslib/articles/brand-yml/) +- [Shiny for Python brand.yml docs](https://shiny.posit.co/py/api/core/ui.Theme.html#shiny.ui.Theme.from_brand) +- [Quarto brand.yml docs](https://quarto.org/docs/authoring/brand.html) diff --git a/skills/brand-yml/SKILL.md b/skills/brand-yml/SKILL.md new file mode 100644 index 0000000..8a9f4bc --- /dev/null +++ b/skills/brand-yml/SKILL.md @@ -0,0 +1,383 @@ +--- +name: brand-yml +description: > + Create and use brand.yml files for consistent branding across Shiny apps and Quarto documents. + Use when working with brand styling, colors, fonts, logos, or corporate identity in Shiny or + Quarto projects. Covers: (1) Creating new _brand.yml files from brand guidelines, (2) Applying + brand.yml to Shiny for R apps with bslib, (3) Applying brand.yml to Shiny for Python apps with + ui.Theme, (4) Using brand.yml in Quarto documents, presentations, dashboards, and PDFs, (5) + Modifying existing brand.yml files, (6) Troubleshooting brand integration issues. Includes + complete specifications and framework-specific integration guides. +--- + +# brand.yml Skill + +Create and use `_brand.yml` files for consistent branding across Shiny applications and Quarto documents. + +## What is brand.yml? + +brand.yml is a YAML-based format that translates brand guidelines into a machine-readable file usable across Shiny and Quarto. A single `_brand.yml` file defines: + +- **Colors** - Palette and semantic colors (primary, success, warning, etc.) +- **Typography** - Fonts, sizes, weights, line heights +- **Logos** - Multiple sizes and light/dark variants +- **Meta** - Company name, links, identity information + +## File Naming Convention + +- **Standard name**: `_brand.yml` (auto-discovered by Shiny and Quarto) +- **Custom names**: Any name like `company-brand.yml` (requires explicit paths) +- **Location**: Typically at project root, or in `_brand/` or `brand/` subdirectories + +## Decision Tree + +Determine the user's goal and follow the appropriate workflow: + +1. **Creating a new _brand.yml file?** → Follow "Creating brand.yml Files" +2. **Using brand.yml in Shiny for R?** → Read `references/shiny-r.md` +3. **Using brand.yml in Shiny for Python?** → Read `references/shiny-python.md` +4. **Using brand.yml in Quarto?** → Read `references/quarto.md` +5. **Using brand.yml in R (general)?** → Read `references/brand-yml-in-r.md` (R Markdown, theming functions, programmatic access) +6. **Modifying existing _brand.yml?** → Follow "Modifying Existing Files" +7. **Troubleshooting integration?** → Follow "Troubleshooting" + +## Creating brand.yml Files + +When creating `_brand.yml` files from brand guidelines: + +### Step 1: Gather Information + +Collect brand information: +- **Colors**: Primary, secondary, accent colors with hex values +- **Fonts**: Font families and where they're sourced (Google Fonts, local files, etc.) +- **Logos**: Logo file paths or URLs for different sizes +- **Company info**: Name, website, social links (optional) + +### Step 2: Read the Specification + +Load `references/brand-yml-spec.md` to understand the complete brand.yml structure, field options, and syntax. + +### Step 3: Build the File Incrementally + +Start with the essential sections and add optional elements: + +**Minimum viable _brand.yml:** + +```yaml +color: + palette: + brand-blue: "#0066cc" + primary: brand-blue + background: "#ffffff" + +typography: + fonts: + - family: Inter + source: google + weight: [400, 600] + base: Inter +``` + +**Add colors as needed:** + +```yaml +color: + palette: + brand-blue: "#0066cc" + brand-orange: "#ff6600" + brand-gray: "#666666" + primary: brand-blue + secondary: brand-gray + warning: brand-orange + foreground: "#333333" + background: "#ffffff" +``` + +**Add typography details:** + +```yaml +typography: + fonts: + - family: Inter + source: google + weight: [400, 600, 700] + style: [normal, italic] + - family: Fira Code + source: google + weight: [400, 500] + base: + family: Inter + size: 16px + line-height: 1.5 + headings: + family: Inter + weight: 600 + monospace: Fira Code +``` + +**Add logos:** + +```yaml +logo: + small: logos/icon.png + medium: logos/header.png + large: logos/full.svg +``` + +**Add meta information:** + +```yaml +meta: + name: Company Name + link: https://example.com +``` + +### Step 4: Apply Best Practices + +Follow these rules from `references/brand-yml-spec.md`: + +- All fields are optional - only include what's needed +- Use hex color format: `"#0066cc"` +- Prefer simple syntax (strings over objects) when possible +- Use lowercase names with hyphens: `brand-blue`, `success-green` +- Include `https://` in all URLs +- Define colors/fonts before referencing them +- For color ranges (shades/tints), choose the midpoint color + +### Step 5: Validate Structure + +Check that: +- YAML syntax is valid (proper indentation, quotes on hex colors) +- Color references match palette names +- Font families are defined before use +- File paths are relative to `_brand.yml` location +- All URLs include protocol (`https://`) + +## Modifying Existing Files + +When modifying existing `_brand.yml` files: + +1. **Read the current file** to understand existing structure +2. **Consult brand-yml-spec.md** for valid field options +3. **Maintain consistency** with existing naming patterns +4. **Preserve references** - if other colors/elements reference a name, update consistently +5. **Test integration** - verify changes apply correctly in Shiny/Quarto + +Common modifications: +- **Adding colors**: Add to `color.palette`, then reference in semantic colors +- **Changing fonts**: Update in `typography.fonts`, ensure weights/styles are available +- **Adding logo variants**: Use `light`/`dark` structure for multiple variants +- **Light/dark mode**: Add `light` and `dark` variants to colors + +## Using with Shiny for R + +When the user wants to apply brand.yml to a Shiny for R app: + +1. **Read `references/shiny-r.md`** for complete integration guide +2. **Key function**: `bs_theme(brand = TRUE)` or `bs_theme(brand = "path")` +3. **Automatic discovery**: Place `_brand.yml` at app root +4. **Page functions**: Works with `page_fluid()`, `page_sidebar()`, etc. + +Quick example: + +```r +library(shiny) +library(bslib) + +ui <- page_fluid( + theme = bs_theme(brand = TRUE), + # ... UI elements +) +``` + +## Using with Shiny for Python + +When the user wants to apply brand.yml to a Shiny for Python app: + +1. **Read `references/shiny-python.md`** for complete integration guide +2. **Key function**: `ui.Theme.from_brand(__file__)` +3. **Automatic discovery**: Place `_brand.yml` at app root +4. **Installation**: Requires `pip install "shiny[theme]"` + +Quick example (Shiny Express): + +```python +from shiny.express import ui + +ui.page_opts(theme=ui.Theme.from_brand(__file__)) +``` + +Quick example (Shiny Core): + +```python +from shiny import App, ui + +app_ui = ui.page_fluid( + theme=ui.Theme.from_brand(__file__), + # ... UI elements +) +``` + +## Using with Quarto + +When the user wants to apply brand.yml to Quarto documents: + +1. **Read `references/quarto.md`** for complete integration guide +2. **Automatic discovery**: Place `_brand.yml` at project root with `_quarto.yml` +3. **Supported formats**: HTML, dashboards, RevealJS, Typst PDFs +4. **Theme layering**: Use `brand` keyword to control precedence + +Quick example (document): + +```yaml +--- +title: "My Document" +format: + html: + brand: _brand.yml +--- +``` + +Quick example (project in `_quarto.yml`): + +```yaml +project: + brand: _brand.yml + +format: + html: + theme: default +``` + +## Troubleshooting + +### Brand Not Applying + +**Shiny:** +- Verify file is named `_brand.yml` (with underscore) +- Check file location (app directory or parent directories) +- Try explicit path: `bs_theme(brand = "path/to/_brand.yml")` or `ui.Theme.from_brand("path")` +- For Python: Ensure `libsass` is installed + +**Quarto:** +- Verify `_brand.yml` is at project root +- Ensure `_quarto.yml` exists for project-level branding +- Try explicit path in document frontmatter +- Check theme layering order if using custom themes + +### Colors Not Matching + +- Ensure hex colors have quotes: `"#0066cc"` not `#0066cc` +- Verify color names match palette definitions exactly +- Check semantic colors (primary, success, etc.) reference valid palette names +- Ensure palette is defined before semantic colors + +### Fonts Not Loading + +- Verify Google Fonts spelling and availability +- Check internet connection (required for Google Fonts) +- Ensure `source: google` or `source: bunny` is specified +- Verify font family names match exactly in typography elements +- For Typst: Check font cache with `quarto typst fonts` + +### YAML Syntax Errors + +- Check indentation (use spaces, not tabs) +- Ensure hex colors have quotes: `"#447099"` +- Verify colons have space after them: `primary: blue` +- Check list items have hyphens: `- family: Inter` +- Use YAML validator if syntax issues persist + +## Reference Documentation + +Load these as needed for detailed information: + +- **`references/brand-yml-spec.md`**: Complete brand.yml specification with all sections, fields, examples, and validation rules +- **`references/shiny-r.md`**: Using brand.yml with Shiny for R via bslib (bs_theme, automatic discovery, Shiny-specific integration) +- **`references/shiny-python.md`**: Using brand.yml with Shiny for Python via ui.Theme (from_brand(), installation, performance) +- **`references/quarto.md`**: Using brand.yml with Quarto (formats, light/dark mode, layering, extensions, Typst) +- **`references/brand-yml-in-r.md`**: General R usage including R Markdown integration, theming functions (ggplot2, gt, flextable, plotly, thematic), and programmatic brand access + +## Key Principles + +- **Start simple**: Begin with colors and one font family +- **Keep it concise**: Only include fields directly relevant to the brand +- **Prefer standard names**: Use Bootstrap color names when possible (blue, green, red, etc.) +- **Use automatic discovery**: Name file `_brand.yml` for auto-detection +- **Test across targets**: Verify brand applies correctly in all intended formats +- **Version control**: Include `_brand.yml` in git repository + +## Common Patterns + +### Light/Dark Mode Colors + +```yaml +color: + primary: + light: "#0066cc" + dark: "#3399ff" + background: + light: "#ffffff" + dark: "#1a1a1a" + foreground: + light: "#333333" + dark: "#e0e0e0" +``` + +Light/dark color modes were added in Quarto version 1.8 and currently are not supported in the R or Python brand.yml packages. + +### Logo Variants + +```yaml +logo: + images: + logo-dark: logos/logo-dark.svg + logo-white: logos/logo-white.svg + icon: logos/icon.png + small: icon + medium: + light: logo-dark + dark: logo-white +``` + +### Multiple Font Weights + +```yaml +typography: + fonts: + - family: Inter + source: google + weight: [300, 400, 500, 600, 700] + style: [normal, italic] + base: + family: Inter + weight: 400 + headings: + family: Inter + weight: 600 +``` + +### Color Aliases + +```yaml +color: + palette: + navy: "#003366" + ocean-blue: "#0066cc" + sky-blue: "#3399ff" + primary-color: ocean-blue # Alias + brand-blue: ocean-blue # Alias + blue: sky-blue # Alias for primary colors + primary: brand-blue +``` + +Include Bootstrap color names when possible, either defined directly or as aliases: `blue`, `indigo`, `purple`, `pink`, `red`, `orange`, `yellow`, `green`, `teal`, `cyan`, `white`, `black`. This is useful for consistency and these colors are picked up automatically by tools that use brand.yml. + +## Tips + +- **Read specification first**: Always consult `brand-yml-spec.md` when creating or modifying files +- **Framework-specific guides**: Load the appropriate reference (shiny-r.md, shiny-python.md, quarto.md) for integration details +- **Validate incrementally**: Start with minimal structure, test, then add complexity +- **Use references**: Define colors in palette, then reference by name in semantic colors +- **Standard file name**: Use `_brand.yml` for automatic discovery +- **Explicit paths**: Use custom file names only when necessary (shared branding, multiple variants) diff --git a/skills/brand-yml/references/brand-yml-in-r.md b/skills/brand-yml/references/brand-yml-in-r.md new file mode 100644 index 0000000..0ac2853 --- /dev/null +++ b/skills/brand-yml/references/brand-yml-in-r.md @@ -0,0 +1,447 @@ +# Using brand.yml in R + +Guide for using brand.yml in R projects beyond Shiny, including R Markdown documents, theming functions for plots and tables, and programmatic access to brand data. + +## Overview + +The brand.yml R package provides tools for applying brand styling to R visualizations and documents. These tools work in any R context, including R Markdown documents, Quarto, standalone scripts, and Shiny applications. + +## Installation + +```r +# Install brand.yml package +install.packages("brand.yml") +``` + +## R Markdown Integration + +Use brand.yml in R Markdown documents (without `runtime: shiny`): + +```yaml +--- +title: "My Report" +output: + html_document: + theme: + version: 5 # Required for brand.yml + brand: true # Auto-discover _brand.yml +--- +``` + +Or specify a path: + +```yaml +--- +title: "My Report" +output: + html_document: + theme: + version: 5 + brand: "path/to/brand.yml" +--- +``` + +**Important**: Set `version: 5` to use Bootstrap 5, which has the best brand.yml support. + +### Other R Markdown Formats + +Brand.yml works with various R Markdown output formats: + +```yaml +--- +title: "Branded Report" +output: + html_document: + theme: + version: 5 + brand: _brand.yml + pdf_document: default +--- +``` + +## Programmatic Access + +Read and access brand data programmatically in any R script or document: + +```r +library(brand.yml) + +# Read from default location (_brand.yml in project) +brand <- read_brand_yml() + +# Read from specific path +brand <- read_brand_yml("path/to/brand.yml") + +# Access brand elements +brand$color$palette$blue # "#447099" +brand$color$primary # blue -> "#447099" +brand$typography$base$family # "Open Sans" +brand$meta$name # "Company Name" + +# Access all colors +brand$color$palette # List of all palette colors +brand$color$foreground # Foreground color +brand$color$background # Background color +``` + +Use programmatically accessed brand data to: +- Display brand colors in custom visualizations +- Show brand logo with correct paths +- Apply brand fonts to custom elements +- Build branded themes dynamically +- Generate branded reports programmatically + +## Branded Theming Functions + +The brand.yml package includes helper functions to apply brand colors to plots and tables from popular R packages. These functions work in any R context (scripts, R Markdown, Quarto, Shiny). + +### theme_brand_ggplot2() + +Apply brand colors to ggplot2 visualizations: + +```r +library(ggplot2) +library(brand.yml) + +# Automatic brand detection +ggplot(mtcars, aes(mpg, hp)) + + geom_point() + + theme_brand_ggplot2() + +# Explicit brand file +ggplot(mtcars, aes(mpg, hp)) + + geom_point() + + theme_brand_ggplot2(brand = "_brand.yml") + +# Override specific colors +ggplot(mtcars, aes(mpg, hp)) + + geom_point() + + theme_brand_ggplot2( + background = "white", + foreground = "brand-gray", + accent = "brand-blue" + ) +``` + +**Parameters:** +- `brand`: NULL (auto-detect), file path, brand object, or FALSE +- `background`, `foreground`, `accent`: Primary color settings +- `base_size`: Base font size (default: 11) +- Additional parameters for fine-grained control: `title_color`, `line_color`, `rect_fill`, `panel_background_fill`, `panel_grid_major_color`, etc. + +### theme_brand_gt() + +Apply brand colors to gt tables: + +```r +library(gt) +library(brand.yml) + +# Create branded table +mtcars |> + head() |> + gt() |> + theme_brand_gt() + +# With explicit brand +mtcars |> + head() |> + gt() |> + theme_brand_gt(brand = "_brand.yml") + +# Override colors +mtcars |> + head() |> + gt() |> + theme_brand_gt( + background = "white", + foreground = "brand-gray" + ) +``` + +**Parameters:** +- `table`: The gt table object to theme +- `brand`: NULL (auto-detect), file path, brand object, or FALSE +- `background`: Table background color (default: `brand.color.background`) +- `foreground`: Text color (default: `brand.color.foreground`) + +### theme_brand_flextable() + +Apply brand colors to flextable tables: + +```r +library(flextable) +library(brand.yml) + +# Create branded flextable +mtcars |> + head() |> + flextable() |> + theme_brand_flextable() + +# With explicit brand +mtcars |> + head() |> + flextable() |> + theme_brand_flextable(brand = "_brand.yml") + +# Override colors +mtcars |> + head() |> + flextable() |> + theme_brand_flextable( + background = "white", + foreground = "brand-gray" + ) +``` + +**Parameters:** +- `table`: The flextable object to theme +- `brand`: NULL (auto-detect), file path, brand object, or FALSE +- `background`: Table background color (default: `brand.color.background`) +- `foreground`: Text color (default: `brand.color.foreground`) + +### theme_brand_plotly() + +Apply brand colors to plotly visualizations: + +```r +library(plotly) +library(brand.yml) + +# Create branded plotly chart +plot_ly(mtcars, x = ~mpg, y = ~hp, type = "scatter", mode = "markers") |> + theme_brand_plotly() + +# With explicit brand +plot_ly(mtcars, x = ~mpg, y = ~hp, type = "scatter", mode = "markers") |> + theme_brand_plotly(brand = "_brand.yml") + +# Override colors +plot_ly(mtcars, x = ~mpg, y = ~hp, type = "scatter", mode = "markers") |> + theme_brand_plotly( + background = "white", + foreground = "brand-gray", + accent = "brand-blue" + ) +``` + +**Parameters:** +- `plot`: The plotly plot object to theme +- `brand`: NULL (auto-detect), file path, brand object, or FALSE +- `background`: Plot background color (default: `brand.color.background`) +- `foreground`: Text/foreground color (default: `brand.color.foreground`) +- `accent`: Accent/highlight color (default: `brand.color.primary`) + +### theme_brand_thematic() + +Apply brand colors to base R graphics via thematic: + +```r +library(thematic) +library(brand.yml) + +# Create theme object +theme <- theme_brand_thematic() + +# Use with thematic_with_theme() +thematic::thematic_with_theme(theme, { + plot(mtcars$mpg, mtcars$hp) +}) + +# Or use with ggplot2 +thematic::thematic_with_theme(theme, { + ggplot(mtcars, aes(mpg, hp)) + + geom_point() +}) +``` + +### theme_brand_thematic_on() + +Immediately activate brand theming globally for base R graphics: + +```r +library(thematic) +library(brand.yml) + +# Turn on brand theming globally +theme_brand_thematic_on() + +# Now all plots use brand colors +plot(mtcars$mpg, mtcars$hp) +hist(mtcars$mpg) + +# Turn off later +thematic::thematic_off() +``` + +**Parameters (both functions):** +- `brand`: NULL (auto-detect), file path, brand object, or FALSE +- `background`: Background color (default: `brand.color.background`) +- `foreground`: Foreground color (default: `brand.color.foreground`) +- `accent`: Accent color (default: `brand.color.primary`) +- `...`: Additional arguments passed to thematic package + +**Difference:** +- `theme_brand_thematic()`: Returns theme object for scoped use +- `theme_brand_thematic_on()`: Immediately applies theme globally + +## R Markdown Example + +Complete example showing theming functions in R Markdown: + +````markdown +--- +title: "Branded Report" +output: + html_document: + theme: + version: 5 + brand: _brand.yml +--- + +```{r setup} +library(ggplot2) +library(gt) +library(brand.yml) +``` + +## Sales Analysis + +```{r plot} +ggplot(mtcars, aes(mpg, hp, color = factor(cyl))) + + geom_point(size = 3) + + labs(title = "MPG vs Horsepower", color = "Cylinders") + + theme_brand_ggplot2() +``` + +## Data Summary + +```{r table} +mtcars |> + head(10) |> + gt() |> + theme_brand_gt() |> + tab_header(title = "Motor Trend Car Data") +``` +```` + +## Quarto Integration + +Works seamlessly in Quarto documents: + +````markdown +--- +title: "Branded Analysis" +format: + html: + brand: _brand.yml +--- + +```{r} +#| label: branded-plot +library(ggplot2) +library(brand.yml) + +ggplot(iris, aes(Sepal.Length, Sepal.Width, color = Species)) + + geom_point() + + theme_brand_ggplot2() +``` +```` + +## Script Usage + +Use in standalone R scripts: + +```r +#!/usr/bin/env Rscript + +library(brand.yml) +library(ggplot2) + +# Read brand +brand <- read_brand_yml("_brand.yml") + +# Create branded plot +p <- ggplot(mtcars, aes(mpg, hp)) + + geom_point(color = brand$color$primary) + + theme_brand_ggplot2() + +# Save with brand colors +ggsave("output.png", p, width = 8, height = 6) +``` + +## Benefits + +- **Consistency**: Same brand styling across all R outputs (plots, tables, documents) +- **Automatic detection**: Functions find `_brand.yml` automatically +- **Flexible override**: Easy to customize colors when needed +- **Works everywhere**: R scripts, R Markdown, Quarto, Shiny + +## Tips + +- **Place `_brand.yml` at project root** for automatic discovery +- **Use `read_brand_yml()`** for programmatic access to brand data +- **Combine theming functions** for cohesive branded reports +- **Set `version: 5`** in R Markdown YAML for Bootstrap 5 support +- **Test theme functions** individually before combining in documents + +## Common Patterns + +### Branded Report with Multiple Visualizations + +```r +library(brand.yml) +library(ggplot2) +library(gt) + +# Load brand +brand <- read_brand_yml() + +# Create consistent visualizations +plot1 <- ggplot(data1, aes(x, y)) + + geom_point() + + theme_brand_ggplot2() + +plot2 <- ggplot(data2, aes(x, y)) + + geom_line() + + theme_brand_ggplot2() + +table1 <- data3 |> + gt() |> + theme_brand_gt() +``` + +### Dynamic Brand Colors + +```r +library(brand.yml) + +brand <- read_brand_yml() + +# Use brand colors in custom visualizations +my_colors <- c( + brand$color$primary, + brand$color$secondary, + brand$color$success +) + +# Apply to plot +plot(data, col = my_colors[factor(group)]) +``` + +### Conditional Branding + +```r +library(brand.yml) + +# Use different brands for different contexts +if (Sys.getenv("BRAND_MODE") == "internal") { + brand <- read_brand_yml("internal-brand.yml") +} else { + brand <- read_brand_yml("external-brand.yml") +} + +# Apply to visualizations +theme <- theme_brand_ggplot2(brand = brand) +``` diff --git a/skills/brand-yml/references/brand-yml-spec.md b/skills/brand-yml/references/brand-yml-spec.md new file mode 100644 index 0000000..76bae71 --- /dev/null +++ b/skills/brand-yml/references/brand-yml-spec.md @@ -0,0 +1,408 @@ +# brand.yml Specification + +Complete specification for creating valid `_brand.yml` files for the brand.yml project. + +## File Naming Convention + +- **Conventional name**: `_brand.yml` (auto-discovered by Shiny and Quarto) +- **Custom names**: Any `.yml` file (e.g., `my-brand.yml`) requires explicit paths +- **Location**: Typically at project root or in `_brand/` or `brand/` subdirectories + +## File Structure + +All fields are **optional**. Only include fields directly relevant to the brand. + +```yaml +meta: # Company/project identity information +logo: # Logo files and variants +color: # Color palette and semantic colors +typography: # Fonts and text styling +defaults: # Framework-specific customizations +``` + +## Meta Section + +Company or project metadata. + +### Simple Format + +```yaml +meta: + name: Acme + link: https://acmecorp.com +``` + +### Extended Format + +```yaml +meta: + name: + short: Acme + full: Acme Corporation International + link: + home: https://www.acmecorp.com + docs: https://docs.acmecorp.com + github: https://github.com/acmecorp + bluesky: https://bsky.app/profile/acmecorp.bsky.social + mastodon: https://mastodon.social/@acmecorp + linkedin: https://www.linkedin.com/company/acmecorp + facebook: https://www.facebook.com/acmecorp + twitter: https://twitter.com/acmecorp +``` + +**Requirements:** +- All links must include `https://` prefix +- Additional custom fields are allowed + +## Logo Section + +Logo files for different contexts and sizes. + +### Structure + +```yaml +logo: + images: # Named logo resources (optional) + name: path # Map names to file paths or URLs + small: path # Icon-sized logo (favicons, mobile) + medium: path # Standard logo (headers, navigation) + large: path # Large logo (hero, title slides) +``` + +### File Paths + +- **Local files**: Relative paths from `_brand.yml` location (e.g., `logos/logo.png`) +- **Remote files**: Full URLs with `http://` or `https://` + +### Light/Dark Variants + +```yaml +logo: + medium: + light: logo-dark.png # For light backgrounds + dark: logo-white.png # For dark backgrounds +``` + +### With Alt Text + +```yaml +logo: + images: + header: + path: logos/header.svg + alt: Company logo + medium: header +``` + +### Complete Example + +```yaml +logo: + images: + header: logos/header-logo.png + header-white: logos/header-logo-white.png + icon: logos/icon.png + full: + path: logos/full-logo.svg + alt: Acme Corporation logo + small: icon + medium: + light: header + dark: header-white + large: full +``` + +## Color Section + +Brand color palette and semantic color assignments. + +### Structure + +```yaml +color: + palette: # Named brand colors + name: "#hex" # Flat list of color names and hex values + # Semantic theme colors (all optional) + foreground: "#color" # Main text color + background: "#color" # Main background color + primary: "#color" # Links, buttons, primary actions + secondary: "#color" # Lighter text, disabled states + tertiary: "#color" # Hover states, accents + success: "#color" # Positive actions + info: "#color" # Neutral information + warning: "#color" # Cautions + danger: "#color" # Errors, negative actions + light: "#color" # High contrast on dark + dark: "#color" # High contrast on light +``` + +### Color Palette Best Practices + +- Use hex color values: `"#447099"` +- Use descriptive names following Sass conventions: `blue`, `brand-orange`, `success-green` +- Create aliases by referencing other palette colors: `purple: burgundy` +- Include Bootstrap color names when possible: `blue`, `indigo`, `purple`, `pink`, `red`, `orange`, `yellow`, `green`, `teal`, `cyan`, `white`, `black` +- When brands define ranges of shades, choose the midpoint as the primary color + +### Referencing Colors + +Theme colors can reference palette names: + +```yaml +color: + palette: + brand-blue: "#447099" + brand-orange: "#EE6331" + primary: brand-blue # References palette + warning: brand-orange # References palette +``` + +### Complete Example + +```yaml +color: + palette: + white: "#FFFFFF" + black: "#151515" + blue: "#447099" + orange: "#EE6331" + green: "#72994E" + teal: "#419599" + burgundy: "#9A4665" + foreground: black + background: white + primary: blue + success: green + info: teal + warning: orange + danger: burgundy +``` + +## Typography Section + +Font definitions and text element styling. + +### Structure + +```yaml +typography: + fonts: # Font definitions + - family: Name + source: type # file, google, bunny, or system + # Additional source-specific fields + base: # Body text (optional) + headings: # Heading text (optional) + monospace: # Code text (optional) + monospace-inline: # Inline code (optional) + monospace-block: # Code blocks (optional) + link: # Hyperlinks (optional) +``` + +### Font Sources + +#### Local/Remote Files + +```yaml +fonts: + - family: Open Sans + source: file + files: + - path: fonts/OpenSans-Regular.ttf + weight: 400 + style: normal + - path: fonts/OpenSans-Bold.ttf + weight: 700 + style: normal + - path: https://example.com/fonts/OpenSans-Italic.ttf + weight: 400 + style: italic +``` + +Proprietary fonts, should be downloaded and stored adjacent to the brand.yml file and referenced via relative paths in the `path` field. + +#### Google Fonts + +```yaml +fonts: + - family: Roboto + source: google + weight: [400, 700] # Optional: specific weights + style: [normal, italic] # Optional: specific styles + display: block # Optional: font-display property +``` + +Weight options: +- Array of numbers: `[400, 700]` +- Range (variable fonts): `400..900` +- Named weights: `[thin, normal, bold]` + +#### Bunny Fonts (GDPR-compliant alternative) + +```yaml +fonts: + - family: Inter + source: bunny + weight: [400, 600] + style: [normal, italic] +``` + +Same syntax as Google Fonts. + +### Typographic Elements + +All elements support these fields: +- `family`: Font family name (must match a defined font) +- `weight`: `100`-`900` or `thin`, `normal`, `bold`, etc. +- `style`: `normal` or `italic` +- `size`: CSS units (`16px`, `1rem`, `0.9em`) +- `line-height`: Number or CSS unit +- `color`: Hex value or reference to color name +- `background-color`: Hex value or reference to color name + +#### Simple Format (String) + +```yaml +typography: + base: Open Sans + headings: Roboto + monospace: Fira Code +``` + +#### Extended Format (Object) + +```yaml +typography: + base: + family: Open Sans + weight: 400 + size: 16px + line-height: 1.5 + headings: + family: Roboto + weight: 600 + style: normal + line-height: 1.2 + color: "#333333" + monospace: + family: Fira Code + weight: 400 + size: 0.9em + monospace-inline: + color: "#7d12ba" + background-color: "#f8f9fa" + monospace-block: + color: foreground + background-color: background + line-height: 1.4 + link: + weight: 600 + color: primary + decoration: underline +``` + +**Note**: Base text color uses `color.foreground` by default. Do not specify color in base unless overriding. + +### Complete Example + +```yaml +typography: + fonts: + - family: Open Sans + source: google + weight: [400, 600, 700] + style: [normal, italic] + - family: Roboto Slab + source: google + weight: [600, 900] + - family: Fira Code + source: bunny + weight: [400, 500] + base: + family: Open Sans + size: 16px + line-height: 1.5 + headings: + family: Roboto Slab + weight: 600 + monospace: Fira Code + link: + color: primary + weight: 600 +``` + +## Defaults Section + +Framework-specific customizations. Use sparingly - only when brand requirements cannot be met through the standard sections above. + +### Structure + +```yaml +defaults: + bootstrap: # Bootstrap/bslib customizations + functions: # SCSS function declarations (string) + defaults: # Bootstrap variable overrides (mapping) + mixins: # SCSS mixins (string) + rules: # Additional SCSS rules (string) + quarto: # Quarto-specific settings + format: # Format-specific options + shiny: # Shiny-specific settings + theme: + defaults: # Bootstrap variables + rules: # Additional SCSS rules +``` + +### Example + +```yaml +defaults: + bootstrap: + defaults: + navbar-bg: $brand-orange + rules: | + .btn-primary { + border-radius: 0.5rem; + } + shiny: + theme: + defaults: + navbar-padding-y: 1rem +``` + +**Note**: Colors from `color.palette` are available as Sass variables: `$brand-{color_name}` + +## Validation Rules + +When creating `_brand.yml` files: + +1. **All fields are optional** - only include what's needed +2. **Prefer hex colors** - use `"#447099"` format +3. **Prefer simple syntax** - use strings instead of objects when possible +4. **Follow Sass naming** - color/font names use lowercase and hyphens +5. **Include URLs with protocol** - always use `https://` +6. **Reference before use** - define colors/fonts before referencing them +7. **Keep it concise** - simpler is better + +## Complete Minimal Example + +```yaml +color: + palette: + blue: "#0066cc" + gray: "#666666" + primary: blue + foreground: gray + background: "#ffffff" + +typography: + fonts: + - family: Inter + source: google + weight: [400, 600] + base: Inter + headings: + weight: 600 +``` + +## Complete Comprehensive Example + +See the example in the document provided to you (brand-yml.prompt.txt) for a full-featured _brand.yml with all options demonstrated. diff --git a/skills/brand-yml/references/quarto.md b/skills/brand-yml/references/quarto.md new file mode 100644 index 0000000..b99d16c --- /dev/null +++ b/skills/brand-yml/references/quarto.md @@ -0,0 +1,504 @@ +# Using brand.yml with Quarto + +Guide for applying brand.yml styling to Quarto documents, presentations, websites, and PDFs. + +## Overview + +Quarto automatically integrates `_brand.yml` to provide unified visual styling across multiple output formats including HTML, dashboards, RevealJS presentations, and Typst PDFs. + +## Quick Start + +Place `_brand.yml` at your project root: + +``` +my-project/ +├── _quarto.yml +├── _brand.yml +├── index.qmd +└── ... +``` + +Quarto automatically discovers and applies `_brand.yml` - no configuration needed. + +## Supported Formats + +Brand styling automatically applies to: + +- **HTML documents** - Web pages, reports +- **HTML dashboards** - Interactive dashboards +- **RevealJS presentations** - Slide decks +- **Typst PDFs** - PDF documents via Typst +- **Websites** - Multi-page Quarto websites + +## Document-Level Usage + +Specify brand in document frontmatter: + +```yaml +--- +title: "My Document" +format: + html: + brand: _brand.yml +--- +``` + +Or use default discovery: + +```yaml +--- +title: "My Document" +format: html +--- +``` + +If `_brand.yml` exists at project root, it's automatically applied. + +## Project-Level Usage + +Configure in `_quarto.yml`: + +```yaml +project: + type: website + brand: _brand.yml + +format: + html: + theme: default +``` + +## Custom Brand File Location + +Specify a non-standard path: + +```yaml +--- +title: "My Document" +format: + html: + brand: branding/company-brand.yml +--- +``` + +Or in project config: + +```yaml +project: + brand: path/to/brand.yml +``` + +## Light/Dark Mode + +Specify color variants for light and dark modes: + +```yaml +color: + palette: + blue: "#0066cc" + primary: + light: "#0066cc" + dark: "#3399ff" + background: + light: "#ffffff" + dark: "#1a1a1a" + foreground: + light: "#333333" + dark: "#e0e0e0" +``` + +Any color in `color` or `typography` can have light/dark variants. + +## Theme Layering + +Control precedence with the `"brand"` keyword: + +### Default (Brand Lowest Priority) + +```yaml +format: + revealjs: + theme: + - custom.scss + - cosmo +``` + +Priority: `cosmo` > `custom.scss` > `_brand.yml` + +### Brand Highest Priority + +```yaml +format: + revealjs: + theme: + - cosmo + - custom.scss + - brand +``` + +Priority: `_brand.yml` > `custom.scss` > `cosmo` + +### Brand in Middle + +```yaml +format: + html: + theme: + - cosmo + - brand + - custom.scss +``` + +Priority: `custom.scss` > `_brand.yml` > `cosmo` + +## Accessing Brand Data in Documents + +### Shortcodes + +Use shortcodes to access brand values (requires Quarto extensions): + +```markdown + +Our primary color is {{{< brand-color primary >}}}. + + +Welcome to {{{< brand-meta name >}}}. +``` + +### SCSS Variables + +Access brand colors in custom SCSS: + +```scss +// Custom SCSS file +.branded-element { + color: $brand-primary; + background: $brand-background; + border-color: $brand-secondary; +} +``` + +Brand colors are automatically available as Sass variables: `$brand-{color-name}`. + +## Typst PDF Support + +Brand styling works with Typst PDF output: + +```yaml +--- +title: "My Document" +format: + typst: + brand: _brand.yml +--- +``` + +### Typst Color Variables + +Access colors in Typst templates: + +- `brand-color.{name}` - Palette colors (e.g., `brand-color.blue`, `brand-color.primary`) +- `brand-background-color.{name}` - Lighter background variants + +### Typst Typography Support + +| Element | family | weight | color | background-color | line-height | +|---------|--------|--------|-------|------------------|-------------| +| base | ✓ | ✓ | ✓ | - | ✓ | +| headings | ✓ | ✓ | ✓ | - | ✓ | +| title | ✓ | ✓ | ✓ | - | ✓ | +| monospace-inline | ✓ | ✓ | ✓ | ✓ | - | +| monospace-block | ✓ | ✓ | ✓ | ✓ | ✓ | +| link | - | ✓ | ✓ | ✓ | - | + +### Typst Font Handling + +Quarto automatically downloads Google Fonts and caches them for Typst. Check fonts: + +```bash +quarto typst fonts --ignore-system-fonts --font-path .quarto/typst-font-cache/ +``` + +Disable font fallback in Typst: + +```typst +#set text(fallback: false) +``` + +## Complete Examples + +### Simple HTML Document + +```yaml +--- +title: "Quarterly Report" +format: + html: + toc: true +--- + +# Executive Summary + +Content here uses brand colors and typography automatically. +``` + +With `_brand.yml` at project root: + +```yaml +color: + palette: + blue: "#0066cc" + primary: blue + background: "#ffffff" + +typography: + fonts: + - family: Inter + source: google + weight: [400, 600] + base: + family: Inter + size: 16px + headings: + family: Inter + weight: 600 +``` + +### RevealJS Presentation + +```yaml +--- +title: "Company Overview" +format: + revealjs: + theme: + - default + - brand + logo: logo.png +--- + +# Introduction + +Slides automatically use brand colors and fonts. +``` + +### Website with Brand + +`_quarto.yml`: + +```yaml +project: + type: website + brand: _brand.yml + +website: + title: "My Company" + navbar: + left: + - href: index.qmd + text: Home + - about.qmd + +format: + html: + theme: cosmo + css: styles.css +``` + +Brand colors and typography apply across all pages. + +### Dashboard + +```yaml +--- +title: "Sales Dashboard" +format: + dashboard: + brand: _brand.yml + theme: default +--- + +## Row + +```{python} +# Dashboard content +``` +``` + +### Typst PDF + +```yaml +--- +title: "Technical Report" +format: + typst: + brand: _brand.yml + margin: + x: 2cm + y: 2cm +--- + +# Overview + +PDF uses brand colors and fonts via Typst. +``` + +## Brand Extensions + +Create reusable brand packages: + +```bash +quarto create extension brand +``` + +Structure: + +``` +my-brand-extension/ +├── _extension.yml +├── brand.yml +├── logo.png +└── fonts/ + └── ... +``` + +`_extension.yml`: + +```yaml +title: Company Brand +author: Your Name +version: 1.0.0 +contributes: + brand: brand.yml +``` + +Install extension in projects: + +```bash +quarto add username/my-brand-extension +``` + +**Requirement**: Brand extensions need `_quarto.yml` project file. + +## Sample _brand.yml for Quarto + +Minimal example: + +```yaml +color: + palette: + brand-blue: "#0066cc" + brand-gray: "#666666" + primary: brand-blue + foreground: brand-gray + background: "#ffffff" + +typography: + fonts: + - family: Inter + source: google + weight: [400, 600] + base: + family: Inter + size: 1rem + line-height: 1.6 + headings: + family: Inter + weight: 600 + line-height: 1.2 +``` + +Complete example with light/dark mode: + +```yaml +meta: + name: My Company + link: https://mycompany.com + +logo: + small: logo-icon.png + medium: + light: logo-dark.svg + dark: logo-white.svg + +color: + palette: + blue: "#0066cc" + navy: "#003366" + gray: "#666666" + light-gray: "#f5f5f5" + primary: blue + secondary: gray + success: "#28a745" + info: blue + warning: "#ffc107" + danger: "#dc3545" + foreground: + light: navy + dark: "#e0e0e0" + background: + light: "#ffffff" + dark: "#1a1a1a" + +typography: + fonts: + - family: Inter + source: google + weight: [400, 500, 600, 700] + style: [normal, italic] + - family: Fira Code + source: google + weight: [400, 500] + base: + family: Inter + size: 1rem + line-height: 1.6 + headings: + family: Inter + weight: 600 + line-height: 1.2 + monospace: + family: Fira Code + size: 0.9em + link: + color: primary + weight: 500 +``` + +## Tips + +- **Automatic discovery**: Place `_brand.yml` at project root for automatic application +- **Light/dark variants**: Use for websites with theme toggles +- **Layer strategically**: Use `brand` keyword to control theme precedence +- **Test across formats**: Verify brand applies correctly to HTML, PDF, and presentations +- **Extension for reuse**: Create brand extensions for multi-project consistency +- **Version control**: Include `_brand.yml` in git repository + +## Troubleshooting + +**Brand not applying?** +- Verify file is named `_brand.yml` (with underscore) +- Check file is at project root or specified in `brand:` field +- Ensure `_quarto.yml` exists for project-level branding +- Try explicit path in frontmatter + +**Colors not matching?** +- Ensure hex colors have quotes: `"#0066cc"` +- Check color references match palette definitions +- Verify theme layering order + +**Fonts not loading?** +- Verify Google Fonts spelling +- Check internet connection (required for Google Fonts) +- For Typst, check font cache: `quarto typst fonts` +- Ensure `source: google` is specified correctly + +**Typst-specific issues?** +- Check font cache path: `.quarto/typst-font-cache/` +- Add `#set text(fallback: false)` to debug font issues +- Verify typography properties are supported (see table above) + +**Brand extension not working?** +- Ensure `_quarto.yml` exists in project +- Verify extension is installed: `quarto list extensions` +- Check extension contributes brand: look for `contributes.brand` in `_extension.yml` diff --git a/skills/brand-yml/references/shiny-python.md b/skills/brand-yml/references/shiny-python.md new file mode 100644 index 0000000..993a792 --- /dev/null +++ b/skills/brand-yml/references/shiny-python.md @@ -0,0 +1,395 @@ +# Using brand.yml with Shiny for Python + +Guide for applying brand.yml styling to Shiny for Python applications using ui.Theme. + +## Overview + +Shiny for Python integrates brand.yml through the `ui.Theme.from_brand()` method, which creates custom themes from `_brand.yml` files. This enables consistent branding across Shiny apps with minimal configuration. + +## Installation + +```bash +# Install Shiny with theme support +pip install "shiny[theme]" + +# Or install separately +pip install shiny libsass + +# Optional: Install brand_yml for programmatic access +pip install brand_yml +``` + +## Quick Start + +### Automatic Discovery + +Place `_brand.yml` at your app directory root: + +``` +my-app/ +├── _brand.yml +├── app.py +└── ... +``` + +Then use `ui.Theme.from_brand()`: + +**Shiny Express:** + +```python +from shiny.express import ui + +ui.page_opts(theme=ui.Theme.from_brand(__file__)) + +# ... rest of app +``` + +**Shiny Core:** + +```python +from shiny import App, ui + +app_ui = ui.page_fluid( + ui.Theme.from_brand(__file__), + ui.h2("My App"), + # ... rest of UI +) + +def server(input, output, session): + pass + +app = App(app_ui, server) +``` + +## ui.Theme.from_brand() Parameters + +```python +ui.Theme.from_brand(brand) +``` + +The `brand` parameter accepts: + +### File Path (Most Common) + +```python +# Use __file__ for app directory +ui.Theme.from_brand(__file__) + +# Explicit file path +ui.Theme.from_brand("path/to/_brand.yml") + +# Explicit directory (auto-finds _brand.yml) +ui.Theme.from_brand("branding/") +``` + +### Brand Object + +```python +from brand_yml import Brand + +brand = Brand.from_yaml("_brand.yml") +ui.Theme.from_brand(brand) +``` + +## Search Behavior + +When given `__file__` or a directory path, the method searches for `_brand.yml`: + +1. In the specified directory +2. In `_brand/` subdirectory +3. In `brand/` subdirectory +4. In parent directories (recursive) + +## Complete Examples + +### Shiny Express App + +```python +from shiny.express import input, render, ui + +ui.page_opts( + title="My Dashboard", + theme=ui.Theme.from_brand(__file__) +) + +with ui.sidebar(): + ui.input_slider("n", "Number of observations", 1, 100, 50) + +@render.plot +def histogram(): + import matplotlib.pyplot as plt + import numpy as np + + data = np.random.randn(input.n()) + plt.hist(data, bins=20) + plt.xlabel("Value") + plt.ylabel("Frequency") +``` + +### Shiny Core App + +```python +from shiny import App, render, ui + +app_ui = ui.page_sidebar( + ui.sidebar( + ui.input_slider("n", "Number of observations", 1, 100, 50), + ), + ui.output_plot("histogram"), + title="My Dashboard", + theme=ui.Theme.from_brand(__file__) +) + +def server(input, output, session): + @render.plot + def histogram(): + import matplotlib.pyplot as plt + import numpy as np + + data = np.random.randn(input.n()) + plt.hist(data, bins=20) + plt.xlabel("Value") + plt.ylabel("Frequency") + +app = App(app_ui, server) +``` + +### With Custom Path + +```python +from shiny.express import ui + +# Shared brand file +ui.page_opts(theme=ui.Theme.from_brand("../shared-branding/_brand.yml")) + +# Named brand file +ui.page_opts(theme=ui.Theme.from_brand("company-brand.yml")) + +# Directory with _brand.yml inside +ui.page_opts(theme=ui.Theme.from_brand("branding/")) +``` + +### Multiple Page Types + +```python +from shiny import App, ui + +# page_fluid +app_ui = ui.page_fluid( + theme=ui.Theme.from_brand(__file__), + # ... content +) + +# page_sidebar +app_ui = ui.page_sidebar( + theme=ui.Theme.from_brand(__file__), + ui.sidebar( + # ... sidebar content + ), + # ... main content +) + +# page_navbar +app_ui = ui.page_navbar( + ui.nav_panel("Tab 1", # ...), + ui.nav_panel("Tab 2", # ...), + title="My App", + theme=ui.Theme.from_brand(__file__) +) + +# page_fillable +app_ui = ui.page_fillable( + theme=ui.Theme.from_brand(__file__), + # ... content +) +``` + +## Combining with Custom Theme Rules + +Extend brand.yml themes with custom Sass: + +```python +from shiny.express import ui + +theme = ( + ui.Theme.from_brand(__file__) + .add_rules(""" + .custom-card { + border-radius: 0.5rem; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + } + """) +) + +ui.page_opts(theme=theme) +``` + +Available theme methods (chainable): +- `.add_defaults()` - Override Bootstrap variables +- `.add_functions()` - Add Sass functions +- `.add_mixins()` - Add Sass mixins +- `.add_rules()` - Add CSS rules +- `.add_uses()` - Add Sass declarations + +## Programmatic Access with brand_yml + +For advanced use cases, access brand data programmatically: + +```python +from brand_yml import Brand + +# Read brand file +brand = Brand.from_yaml("_brand.yml") + +# Or from string +yaml_content = """ +color: + palette: + blue: "#0066cc" + primary: blue +""" +brand = Brand.from_yaml_str(yaml_content) + +# Access brand elements +brand.meta.name # Organization name +brand.color.palette.blue # "#0066cc" +brand.color.primary # "blue" +brand.typography.base.family # Font family name + +# Use in UI +from shiny import ui + +app_ui = ui.page_fluid( + theme=ui.Theme.from_brand(brand), + ui.h2(brand.meta.name), + # ... more content +) +``` + +## Sample _brand.yml for Shiny + +Minimal example: + +```yaml +color: + palette: + brand-blue: "#0066cc" + brand-gray: "#666666" + primary: brand-blue + foreground: brand-gray + background: "#ffffff" + +typography: + fonts: + - family: Inter + source: google + weight: [400, 600] + base: + family: Inter + size: 16px + headings: + family: Inter + weight: 600 +``` + +More complete example: + +```yaml +meta: + name: My Company + link: https://mycompany.com + +color: + palette: + blue: "#0066cc" + navy: "#003366" + gray: "#666666" + light-gray: "#f5f5f5" + primary: blue + secondary: gray + success: "#28a745" + info: blue + warning: "#ffc107" + danger: "#dc3545" + foreground: navy + background: "#ffffff" + +typography: + fonts: + - family: Inter + source: google + weight: [400, 500, 600, 700] + style: [normal, italic] + - family: Fira Code + source: google + weight: [400, 500] + base: + family: Inter + size: 16px + line-height: 1.5 + headings: + family: Inter + weight: 600 + line-height: 1.2 + monospace: + family: Fira Code + size: 14px +``` + +## Tips + +- **Use __file__**: Most reliable way to locate `_brand.yml` in app directory +- **Start simple**: Begin with colors and one font +- **Test paths**: If brand doesn't apply, try explicit paths +- **Version control**: Include `_brand.yml` in git repository +- **Precompile for production**: Use `.to_css()` to avoid runtime Sass compilation + +```python +# Development +theme = ui.Theme.from_brand(__file__) + +# Production (precompile) +theme_css = ui.Theme.from_brand(__file__).to_css() +# Save to static/theme.css, then reference in production +``` + +## Troubleshooting + +**Theme not applying?** +- Check file is named `_brand.yml` (with underscore) +- Verify `libsass` is installed: `pip install libsass` +- Try explicit path: `ui.Theme.from_brand("path/to/_brand.yml")` +- Check for YAML syntax errors + +**Colors not matching?** +- Ensure hex colors have quotes: `"#0066cc"` +- Verify color names match palette definitions +- Check semantic colors reference valid palette names + +**Fonts not loading?** +- Verify Google Fonts spelling and availability +- Ensure `source: google` is specified +- Check font family names match exactly +- Internet connection required for Google Fonts + +**Import errors?** +- Install theme support: `pip install "shiny[theme]"` +- Or install libsass separately: `pip install libsass` + +## Performance Considerations + +For production apps with many instances, precompile the theme: + +```python +# build_theme.py +from shiny import ui + +theme = ui.Theme.from_brand("_brand.yml") +css = theme.to_css() + +with open("static/brand-theme.css", "w") as f: + f.write(css) + +# Then in app.py, reference the CSS file directly +# This avoids runtime Sass compilation overhead +``` diff --git a/skills/brand-yml/references/shiny-r.md b/skills/brand-yml/references/shiny-r.md new file mode 100644 index 0000000..9dddcd5 --- /dev/null +++ b/skills/brand-yml/references/shiny-r.md @@ -0,0 +1,378 @@ +# Using brand.yml with Shiny for R + +Guide for applying brand.yml styling to Shiny applications using the bslib package. + +## Overview + +The bslib package integrates brand.yml to provide unified visual theming across Shiny applications. Define colors, fonts, and logos once in `_brand.yml`, and bslib automatically applies them to your Shiny app UI. + +## Installation + +```r +# Install bslib (includes brand.yml support) +install.packages("bslib") + +# Optional: Install brand.yml package for theming plots/tables +install.packages("brand.yml") +``` + +## Quick Start + +### Automatic Discovery + +Place `_brand.yml` at your app directory root: + +``` +my-app/ +├── _brand.yml +├── app.R +└── ... +``` + +Then use `bs_theme()` in your app: + +```r +library(shiny) +library(bslib) + +ui <- page_fluid( + theme = bs_theme(), # Automatically finds _brand.yml + titlePanel("My App"), + # ... rest of UI +) + +server <- function(input, output, session) { + # ... +} + +shinyApp(ui, server) +``` + +### Search Paths + +bslib automatically searches for `_brand.yml` in this order: + +1. Current app directory +2. `_brand/` subdirectory +3. `brand/` subdirectory +4. Parent directories (recursive) + +## bs_theme() Brand Parameter + +The `brand` parameter controls how branding is applied: + +### Automatic (Default) + +```r +theme = bs_theme() +``` + +Searches for `_brand.yml` and applies it if found. No error if file doesn't exist. + +### Required Brand + +```r +theme = bs_theme(brand = TRUE) +``` + +Requires `_brand.yml` to exist. Throws error if not found. + +### Explicit Path + +```r +theme = bs_theme(brand = "path/to/my-brand.yml") +``` + +Uses specific brand file. Path can be: +- Relative to app directory: `"branding/company-brand.yml"` +- Absolute: `"/Users/name/brands/company.yml"` +- Directory (auto-finds `_brand.yml`): `"branding/"` + +### Inline Brand Definition + +```r +theme = bs_theme( + brand = list( + color = list( + palette = list( + blue = "#0066cc", + gray = "#666666" + ), + primary = "blue", + foreground = "gray" + ), + typography = list( + fonts = list( + list(family = "Inter", source = "google", weight = c(400, 600)) + ), + base = "Inter" + ) + ) +) +``` + +### Disable Branding + +```r +theme = bs_theme(brand = FALSE) +``` + +Ignores `_brand.yml` even if it exists. + +## Using with page_*() Functions + +All bslib page functions support automatic brand discovery: + +```r +# page_fluid +ui <- page_fluid( + theme = bs_theme(), + # ... content +) + +# page_sidebar +ui <- page_sidebar( + theme = bs_theme(), + sidebar = sidebar( + # ... sidebar content + ), + # ... main content +) + +# page_navbar +ui <- page_navbar( + theme = bs_theme(), + nav_panel("Tab 1", # ...), + nav_panel("Tab 2", # ...) +) + +# page_fillable +ui <- page_fillable( + theme = bs_theme(), + # ... content +) +``` + +## Branded Plots and Tables in Shiny + +Use theming functions from the brand.yml package to style plots and tables within Shiny apps. See `brand-yml-in-r.md` for complete documentation of theming functions. + +### Basic Example + +```r +library(shiny) +library(bslib) +library(ggplot2) +library(gt) +library(brand.yml) + +ui <- page_sidebar( + theme = bs_theme(brand = TRUE), + + sidebar = sidebar( + selectInput("dataset", "Dataset:", c("mtcars", "iris")) + ), + + card( + card_header("Branded Plot"), + plotOutput("plot") + ), + card( + card_header("Branded Table"), + gt_output("table") + ) +) + +server <- function(input, output, session) { + output$plot <- renderPlot({ + ggplot(mtcars, aes(mpg, hp)) + + geom_point() + + theme_brand_ggplot2() + }) + + output$table <- render_gt({ + head(mtcars) |> + gt() |> + theme_brand_gt() + }) +} + +shinyApp(ui, server) +``` + +**Benefits:** +- Consistent styling across UI, plots, and tables +- Automatic brand detection from `_brand.yml` +- Works with ggplot2, gt, flextable, plotly, and base R graphics + +For detailed theming function documentation, see `brand-yml-in-r.md`. + +## Complete Shiny Example + +```r +library(shiny) +library(bslib) + +ui <- page_sidebar( + theme = bs_theme(brand = TRUE), # Require _brand.yml + + sidebar = sidebar( + title = "Controls", + selectInput("dataset", "Dataset:", + choices = c("iris", "mtcars")), + numericInput("n", "Number of rows:", 10, min = 1, max = 50) + ), + + card( + card_header("Data Summary"), + tableOutput("summary") + ), + + card( + card_header("Data Details"), + verbatimTextOutput("details") + ) +) + +server <- function(input, output, session) { + dataset <- reactive({ + get(input$dataset) + }) + + output$summary <- renderTable({ + head(dataset(), input$n) + }) + + output$details <- renderPrint({ + summary(dataset()) + }) +} + +shinyApp(ui, server) +``` + +With `_brand.yml`: + +```yaml +color: + palette: + brand-blue: "#0066cc" + brand-gray: "#666666" + primary: brand-blue + foreground: brand-gray + background: "#ffffff" + +typography: + fonts: + - family: Inter + source: google + weight: [400, 600] + base: + family: Inter + size: 16px + headings: + family: Inter + weight: 600 +``` + +## R Markdown Shiny Documents + +Use brand.yml in R Markdown documents with Shiny runtime: + +```yaml +--- +title: "Interactive Dashboard" +output: + html_document: + theme: + version: 5 # Required for brand.yml + brand: true # Auto-discover _brand.yml +runtime: shiny +--- +``` + +Or specify a path: + +```yaml +--- +title: "Interactive Dashboard" +output: + html_document: + theme: + version: 5 + brand: "path/to/brand.yml" +runtime: shiny +--- +``` + +**Important**: Set `version: 5` to use Bootstrap 5, which has the best brand.yml support. + +**Note**: For R Markdown documents without `runtime: shiny`, see `brand-yml-in-r.md`. + +## Programmatic Brand Access + +For advanced use cases, access brand data programmatically within Shiny: + +```r +library(brand.yml) + +server <- function(input, output, session) { + # Read brand data + brand <- read_brand_yml() + + # Use in custom UI elements + output$brand_info <- renderUI({ + div( + style = paste0("color: ", brand$color$primary, ";"), + h3(brand$meta$name), + p("Welcome to our branded app!") + ) + }) + + # Use in plots with custom styling + output$custom_plot <- renderPlot({ + plot(mtcars$mpg, mtcars$hp, + col = brand$color$primary, + pch = 19) + }) +} +``` + +For complete documentation on programmatic access and theming functions, see `brand-yml-in-r.md`. + +## Tips + +- **Start simple**: Begin with colors and one font family +- **Test automatically**: Automatic discovery works well for most cases +- **Use explicit paths**: For shared brand files across multiple apps +- **Version control**: Include `_brand.yml` in your git repository +- **Validate early**: Use `brand = TRUE` during development to catch missing files +- **Combine with theming functions**: Style plots and tables consistently (see `brand-yml-in-r.md`) + +## Troubleshooting + +**Brand not applying to Shiny UI?** +- Check file is named `_brand.yml` (with underscore) +- Verify file is in app directory or parent directories +- Try explicit path: `bs_theme(brand = "path/to/_brand.yml")` +- Check for YAML syntax errors + +**Colors not matching?** +- Verify hex colors have quotes: `"#0066cc"` +- Check color names match palette definitions +- Ensure primary/secondary colors reference valid palette names + +**Fonts not loading?** +- Verify Google Fonts spelling and availability +- Check `source: google` is specified correctly +- Ensure font family names match exactly in typography elements + +**Plots/tables not branded?** +- Ensure brand.yml package is installed: `install.packages("brand.yml")` +- Use theming functions: `theme_brand_ggplot2()`, `theme_brand_gt()`, etc. +- See `brand-yml-in-r.md` for complete theming documentation + +## Related Documentation + +- **[brand-yml-in-r.md](brand-yml-in-r.md)**: General R usage, R Markdown integration, theming functions, and programmatic access +- **[brand-yml-spec.md](brand-yml-spec.md)**: Complete brand.yml file specification