Skip to content

Build FeatureCard + EffortIndicator (Storybook) #13320

Description

@techanvil

Feature Description

Every feature the hub lists is presented as a card: what the feature is, how much setting up it takes, which service it belongs to, and the controls to read more about it or set it up. One card serves every list the hub shows, wherever that list appears.

This issue builds that card, together with the one new UI primitive it needs — the setup effort indicator. The tabs that list the cards are built by their own issues (#13321, #13328), so what this issue delivers is the card itself, in Storybook.

The card's call to action (#13322), the detail panel its Read more control opens (#13330), and the menu behind its dismiss control (#13357) are also each their own issue. This issue provides the places they occupy.

For reference, see the UI component architecture section in the design doc, and the All services and features and What's new? designs in Figma.


Do not alter or remove anything below. The following sections will be managed by moderators only.

Acceptance criteria

  • A feature card presents a feature registered in the catalog (Register the feature catalog with final copy #13247): its title, its short description, how much setup it takes, the service it belongs to — that service's icon and name — and its badges.
  • A feature that's Site Kit's own rather than a Google service's shows Site Kit's icon and the name "Site Kit feature".
  • How much setup a feature takes is shown by a new indicator: three wrench icons, of which one, two or three are filled to match the feature's setup effort, followed by that effort's label — "Just a few clicks", "A short setup" or "In depth setup".
  • The card shows the "New" badge while the feature is new to the user (Implement the newness model & derived selectors #13246), alongside whichever badges the feature itself carries, such as "Paid service". A list can turn the badge off: All services and features shows it, and What's new? doesn't, every feature it lists being new.
  • The card shows a red dot beside the feature's title while the feature is new to the user and they haven't yet seen it. A list can turn the dot off, as it can the badge: What's new? shows it, and All services and features doesn't.
    • When the feature is marked seen, the dot remains visible for three seconds, then briefly fades out.
  • The card carries a Read more control. The feature detail panel it opens is covered by Build the feature detail panel shell (FeatureDetailPanel) #13330.
  • The card provides the slot its call to action occupies. What fills that slot is covered by Build FeatureCTA with gating rules #13322.
  • The card's dismiss (X) control is optional, shown only where the list the card appears in allows features to be dismissed. What the control does is covered by Add the dismiss-with-feedback menu #13357.
  • The card and the effort indicator match the Figma designs, and are presented in Storybook.

Implementation Brief

Storybook only — neither tab lists these cards yet.

  • Add assets/svg/icons/wrench.svg — a single glyph filled with currentColor, drawn three times by the effort indicator.
  • Add assets/js/components/feature-discovery/EffortIndicator.tsx:
    • Props: effort — the catalog entry's FEATURE_EFFORTS value.
    • Renders three wrench icons, the first effort of them carrying a --filled modifier and the rest muted, followed by that effort's label: 1 "Just a few clicks", 2 "A short setup", 3 "In depth setup". Keep the label map beside the FEATURE_EFFORTS constants in assets/js/googlesitekit/datastore/feature-discovery/constants.ts, so the detail panel's requirements sub-tab (Build the detail-panel sub-tab content (Description / Requirements / Screenshots) #13331) reuses it rather than repeating the copy.
    • The icons are decorative (aria-hidden); the label carries the meaning.
  • Add assets/js/components/feature-discovery/FeatureCard.tsx, modelled on assets/js/components/settings/SetupModule.js:
    • Props: slug, plus the three a list sets to say how it presents a feature — isDismissible, hideNewBadge and hideUnreadDot. Everything else is read from getFeature( slug ) and the per-user selectors.
    • Layout: a title row (unread dot, h3 title, badges, and the dismiss X at its trailing edge), the short description, EffortIndicator, then an action row with the feature's service on the left and the CTA slot followed by Read more on the right.
    • Service identity. ModuleIcon plus the module's name from core/modules getModule(), driven by an explicit moduleSlug on the catalog entry; an entry without one renders @/svg/graphics/logo-g.svg and the literal "Site Kit feature". It has to be explicit rather than derived from prerequisiteModules: Enhanced measurement, Visitor groups and Key Metrics all depend on analytics-4, but only Enhanced measurement is presented as an Analytics feature. The field is new, so the catalog entries registered in Register the feature catalog with final copy #13247 each need a value for it as well — read each one off the service named on that feature's card in the Figma frame.
    • Badges. NewBadge while isFeatureNew( slug ) and hideNewBadge isn't set — What's new? being the one list that sets it. Then one Badge per entry in the feature's badges[]; map the FEATURE_BADGES slugs to their labels (paid-service → "Paid service") alongside the constants.
    • Unread dot. An inlined span before the title in $c-red-r-400, shown while isFeatureUnread( slug ) and hideUnreadDot isn't set — All services and features being the one list that sets it.
    • The dot can't render straight off that selector, though: What's new? marks its whole list seen on view, which flips it false while the user is looking at the list. So hold the rendered value in state, and in a useEffect on the selector, start a three-second timeout when it flips false before clearing the state and fading the dot out — leaving the dot in place while the list is read, and absent on the next visit. Clear the timeout on unmount.
    • CTA slot. Render a placeholder in the action row, for FeatureCTA to replace.
    • Read more. A Button in the action row's trailing position; its onClick opens the detail panel, and isn't wired up here.
    • Dismiss X. An icon Button using @/svg/icons/close.svg with an aria-label naming the feature, rendered only when isDismissible.
  • Add assets/js/components/feature-discovery/FeatureListItem.tsx, a thin wrapper for FeatureCard.
    • Props: same as FeatureCard, passed through to its child.
    • This component will be expanded on later to render custom content for cards which need it.
  • Add assets/sass/components/feature-discovery/_googlesitekit-feature-card.scss and _googlesitekit-effort-indicator.scss, imported in assets/sass/admin.scss. Despite the name, a card isn't a boxed surface: it has no border, background or shadow of its own, and consecutive cards are told apart by a single horizontal rule between them. The card draws that rule as its own bottom border and suppresses it on :last-child, so the lists that use it need no separator styling of their own.

Storybook

  • Add a provideFeatures( registry, features ) helper to tests/js/utils.ts, following provideModules: each entry passed in is registered over a default one, so a story or test names only the fields it varies.
  • Co-locate FeatureCard.stories.tsx and EffortIndicator.stories.tsx, setting the registry up with WithRegistrySetup, provideFeatures and provideModules.
  • Card variants: a Google service's feature; a Site Kit feature; the feature as All services and features presents it (New badge, no dot); as What's new? presents it (dot, no New badge, dismissible); carrying a Paid service badge. Effort indicator: one story per effort.
  • Add a story rendering several cards in sequence, so the separating rules — and their absence below the last card — are visible and covered.
  • Give each story a scenario = {} so it picks up a VRT scenario.

Test Coverage

  • EffortIndicator.test.tsx — the filled icon count and the label for each effort.
  • FeatureCard.test.tsx — copy, effort and service resolved from the catalog entry; the "Site Kit feature" fallback for an entry with no moduleSlug; the New badge shown only while the feature is new and hideNewBadge isn't set, and the dot likewise under isFeatureUnread and hideUnreadDot; the dot still rendered for three seconds after the selector flips false, and gone once the timeout runs (jest.useFakeTimers()); the entry's own badges rendered; the X present only when isDismissible, and Read more always.

QA Brief

  • Storybook has a story for EffortIndicator which shows each effort label with the expected label and icons and matches the design.
  • Storybook has these stories for FeatureCard, each matching the designs and behaving reasonably across display sizes:
    • A standard Site Kit feature.
    • A feature belonging to a module, with a "Paid service" badge.
    • Two features with a separator between them.
    • A new feature, indicated by a "New" badge but no dot, as presented in the design under "All services and features".
    • A new feature, indicated by a dot but no "New" badge, with a dismiss button, as presented in the design under "What's new?".

Note:

Changelog entry

  • Build the FeatureCard and EffortIndicator components for the upcoming Feature Discovery Hub, and present them in Storybook.

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P0High priorityTeam MIssues for Squad 2Type: EnhancementImprovement of an existing feature

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions