Skip to content

Add BannerComponent (molecule) - #6

Open
PendragonDevelopment wants to merge 4 commits into
fix/lookbook-button-previewsfrom
feat/banner-component
Open

Add BannerComponent (molecule)#6
PendragonDevelopment wants to merge 4 commits into
fix/lookbook-button-previewsfrom
feat/banner-component

Conversation

@PendragonDevelopment

Copy link
Copy Markdown
Collaborator

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 %>
```

Param Values Default
`header` String (optional header label, e.g. "Alert") `nil`
`class` Any Tailwind classes `nil`
Slot Description
`with_icon(...)` Passes args to `IconComponent.new` — e.g. `name: :info`
`with_link(...) { ... }` Passes args + block to `LinkComponent.new`
content block Body text (main message)

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:

  • `p-4` container, `items-start`
  • Optional leading cluster: icon + header text, `gap-1 pr-6`
  • `flex-1` body paragraph (`text-sm leading-5`)
  • Optional trailing link cluster, `pl-4`, right-aligned via `self-stretch`

Test plan

  • 11 new Banner tests pass (body content, header, icon/link slots, composition, consumer override, HTML attrs)
  • Full suite: 60 tests, 121 assertions, 0 failures
  • `rake tailwindcss:build` compiles `bg-background-secondary`
  • `/components` renders three banners: full (icon+header+body+link), icon+header+body, body+link only
  • Lookbook at `/lookbook/preview/shipwright/banner/*` with 5 scenarios including Info/Warning/Success variants

🤖 Generated with Claude Code

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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant