Add BannerComponent (molecule) - #6
Open
PendragonDevelopment wants to merge 4 commits into
Open
Conversation
New Shipwright::IconComponent renders inline SVG icons from a manifest of Feather Icons (https://feathericons.com, MIT licensed). Matches Shipwright Pro's Figma icon set (node 2:163). Starter manifest includes 21 commonly-needed icons: info, alert-circle, alert-triangle, check, check-circle, x, x-circle, chevron-{up,down,left,right}, plus, minus, search, menu, external-link, settings, arrow-{left,right}, help-circle, trash. Icons live in app/components/shipwright/icons.rb as a frozen constant hash of name => inner-SVG fragment. Adding a new icon = paste Feather's inner markup into the hash. API: <%= render Shipwright::IconComponent.new(name: :info) %> <%= render Shipwright::IconComponent.new(name: :check, size: :lg, class: "text-utility-negative-default") %> <%= render Shipwright::IconComponent.new(name: :info, "aria-label": "More info") %> Props: - name: required symbol/string matching a key in ICONS - size: :sm (16px), :md (24px, default), :lg (32px) - class: consumer override - **html_attrs: pass-through (id, data-*, aria-*, etc.) Icons use stroke="currentColor" so they inherit the parent's text color — consumers control color via text-* utilities. Decorative by default (aria-hidden=true); providing aria-label makes the icon meaningful and skips aria-hidden. 13 new component tests pass. Total suite: 38 tests, 81 assertions. Lookbook previews: default, gallery (all 21), sizes, colored, with_aria_label.
New Shipwright::LinkComponent — inline text link primitive.
Matches Shipwright Pro's Link atom (Figma node 2015:15).
Colors pulled from Figma variables (no new tokens needed):
- Default: text-interactive-primary-default (#14161c)
- Hover: text-interactive-primary-hover (#595d6a)
- Pressed: text-interactive-primary-pressed (#333747)
- Disabled: text-interactive-disable (#eaeaea)
API:
<%= render(Shipwright::LinkComponent.new(href: "/about")) { "About" } %>
<%= render(Shipwright::LinkComponent.new(href: "#", decoration: :none)) { "Plain link" } %>
<%= render(Shipwright::LinkComponent.new(href: "#", disabled: true)) { "Unavailable" } %>
Props:
- href: optional; omitted when disabled so the link isn't navigable
- decoration: :underline (default) or :none — maps to Figma's Decoration variant
- disabled: bool — adds aria-disabled and tabindex=-1, removes href
- class: consumer override
- **html_attrs: pass-through (target, rel, id, data-*, etc.)
Typography matches Figma's Label/Small spec: text-sm (14px) +
leading-4 (16px) + Manrope sans (from --font-sans token).
Hover/pressed/focus states use Tailwind pseudo-class modifiers so
browser events drive the visuals rather than JS state.
11 new tests pass. Total suite: 36 tests, 83 assertions.
Lookbook previews: default, no_decoration, disabled, all_states,
external.
# Conflicts: # test/dummy/app/assets/builds/tailwind.css # test/dummy/app/views/pages/components.html.erb
Implements the Banner molecule from Shipwright Pro Figma (node
2013:5697). Composes IconComponent and LinkComponent as optional
slotted atoms, per the monorepo-style component pattern.
New token in engine.css:
- --color-background-secondary: #f3f3f3 (Banner surface)
BaseComponent MERGER config updated to recognize background-secondary.
API:
<%= render Shipwright::BannerComponent.new(header: "Alert") do |banner| %>
<% banner.with_icon(name: :info) %>
<% banner.with_link(href: "#") { "Link" } %>
Place holder text for notifications.
<% end %>
Props:
- header: optional string rendered in the leading cluster (e.g. "Alert")
- class: consumer override
- **html_attrs: pass-through (id, role, data-*, etc.)
Slots:
- with_icon(...) → renders a Shipwright::IconComponent (accepts any
IconComponent props: name, size, class, etc.)
- with_link(...) { ... } → renders a Shipwright::LinkComponent (href,
decoration, disabled, etc. + block content)
Content block → body text (main message).
Layout matches Figma: flex row with p-4, optional leading cluster
(icon + header) with pr-6 spacing, flex-1 body paragraph, optional
trailing link cluster with pl-4 spacing. Typography: text-sm with
leading-4 (16px) for header and leading-5 (20px) for body.
11 new tests pass. Total suite: 60 tests, 121 assertions.
Lookbook previews: default, body_only, icon_and_body, body_and_link,
header_and_body.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the Banner molecule from Shipwright Pro Figma (node `2013:5697`). Composes IconComponent (#4) and LinkComponent (#5) as optional slots.
Stack order:
API
```erb
<%= render Shipwright::BannerComponent.new(header: "Alert") do |banner| %>
<% banner.with_icon(name: :info) %>
<% banner.with_link(href: "#") { "Link" } %>
Place holder text for notifications.
<% end %>
```
New token
Added to `engine.css`:
```
--color-background-secondary: #f3f3f3 /* Banner surface */
```
MERGER config updated to recognize `background-secondary`.
Layout
Horizontal flex row matching Figma:
Test plan
🤖 Generated with Claude Code