@sproutsocial/seeds-react-narrative-kit 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/.turbo/turbo-build.log +11 -11
  2. package/CHANGELOG.md +33 -0
  3. package/dist/ai-container.css +39 -0
  4. package/dist/esm/index.js +199 -0
  5. package/dist/esm/index.js.map +1 -1
  6. package/dist/index.d.mts +186 -4
  7. package/dist/index.d.ts +186 -4
  8. package/dist/index.js +204 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/narrative-attribution.css +56 -0
  11. package/dist/narrative-data-callout.css +103 -0
  12. package/dist/narrative-ordered-list.css +112 -0
  13. package/dist/narrative-social-media-card.css +82 -0
  14. package/dist/pull-quote.css +4 -25
  15. package/package.json +12 -5
  16. package/src/AIContainer/AIContainer.stories.tsx +54 -0
  17. package/src/AIContainer/AIContainer.tsx +35 -0
  18. package/src/AIContainer/AIContainerTypes.ts +14 -0
  19. package/src/AIContainer/__tests__/AIContainer.test.tsx +61 -0
  20. package/src/AIContainer/index.ts +2 -0
  21. package/src/NarrativeAttribution/NarrativeAttribution.stories.tsx +78 -0
  22. package/src/NarrativeAttribution/NarrativeAttribution.tsx +54 -0
  23. package/src/NarrativeAttribution/NarrativeAttributionTypes.ts +13 -0
  24. package/src/NarrativeAttribution/index.ts +2 -0
  25. package/src/NarrativeDataCallout/NarrativeDataCallout.stories.tsx +71 -0
  26. package/src/NarrativeDataCallout/NarrativeDataCallout.tsx +50 -0
  27. package/src/NarrativeDataCallout/NarrativeDataCalloutTypes.ts +18 -0
  28. package/src/NarrativeDataCallout/__tests__/NarrativeDataCallout.test.tsx +69 -0
  29. package/src/NarrativeDataCallout/index.ts +2 -0
  30. package/src/NarrativeOrderedList/NarrativeOrderedList.stories.tsx +69 -0
  31. package/src/NarrativeOrderedList/NarrativeOrderedList.tsx +74 -0
  32. package/src/NarrativeOrderedList/NarrativeOrderedListTypes.ts +39 -0
  33. package/src/NarrativeOrderedList/__tests__/NarrativeOrderedList.test.tsx +89 -0
  34. package/src/NarrativeOrderedList/index.ts +6 -0
  35. package/src/NarrativeSocialMediaCard/NarrativeSocialMediaCard.stories.tsx +111 -0
  36. package/src/NarrativeSocialMediaCard/NarrativeSocialMediaCard.tsx +80 -0
  37. package/src/NarrativeSocialMediaCard/NarrativeSocialMediaCardTypes.ts +30 -0
  38. package/src/NarrativeSocialMediaCard/__tests__/NarrativeSocialMediaCard.test.tsx +154 -0
  39. package/src/NarrativeSocialMediaCard/index.ts +5 -0
  40. package/src/Playground/Playground.stories.tsx +176 -5
  41. package/src/PullQuote/PullQuote.stories.tsx +1 -0
  42. package/src/PullQuote/PullQuote.tsx +6 -3
  43. package/src/ai-container.css +39 -0
  44. package/src/css.d.ts +1 -0
  45. package/src/index.ts +25 -0
  46. package/src/narrative-attribution.css +56 -0
  47. package/src/narrative-data-callout.css +103 -0
  48. package/src/narrative-ordered-list.css +112 -0
  49. package/src/narrative-social-media-card.css +82 -0
  50. package/src/pull-quote.css +4 -25
@@ -10,9 +10,15 @@ import MetricHighlight from "../MetricHighlight/MetricHighlight";
10
10
  import EyebrowToken from "../EyebrowToken/EyebrowToken";
11
11
  import NarrativeDivider from "../NarrativeDivider/NarrativeDivider";
12
12
  import NarrativeSummary from "../NarrativeSummary/NarrativeSummary";
13
+ import NarrativeOrderedList from "../NarrativeOrderedList/NarrativeOrderedList";
14
+ import NarrativeDataCallout from "../NarrativeDataCallout/NarrativeDataCallout";
15
+ import NarrativeSocialMediaCard from "../NarrativeSocialMediaCard/NarrativeSocialMediaCard";
13
16
  import Button from "@sproutsocial/seeds-react-button";
14
17
  import Text from "@sproutsocial/seeds-react-text";
15
18
  import { SparklineChart } from "@sproutsocial/seeds-react-data-viz/sparkline";
19
+ import { DonutChart } from "@sproutsocial/seeds-react-data-viz/donut";
20
+ import { PartnerLogo } from "@sproutsocial/seeds-react-partner-logo";
21
+ import Icon from "@sproutsocial/seeds-react-icon";
16
22
  import "../narrative-container.css";
17
23
  import "../narrative-headline.css";
18
24
  import "../pull-quote.css";
@@ -20,12 +26,15 @@ import "../metric-highlight.css";
20
26
  import "../eyebrow-token.css";
21
27
  import "../narrative-divider.css";
22
28
  import "../narrative-summary.css";
29
+ import "../narrative-ordered-list.css";
30
+ import "../narrative-data-callout.css";
31
+ import "../narrative-social-media-card.css";
23
32
  import "@sproutsocial/seeds-react-button/dist/button.css";
24
33
  import "@sproutsocial/seeds-react-data-viz/sparkline.css";
25
34
 
26
- const spark = (data: number[]) => (
35
+ const spark = (data: number[], variant: "line" | "bar" = "line") => (
27
36
  <SparklineChart
28
- variant="line"
37
+ variant={variant}
29
38
  description="Trend"
30
39
  data={data}
31
40
  className="h-full w-full"
@@ -86,14 +95,22 @@ const Brief = () => (
86
95
  <MetricHighlight
87
96
  label="Engagement rate"
88
97
  value="6.4%"
89
- trend={{ direction: "up", value: "240%", "aria-label": "up 240%" }}
98
+ trend={{
99
+ direction: "up",
100
+ value: "240%",
101
+ "aria-label": "up 240%",
102
+ }}
90
103
  sparkline={spark([3, 5, 4, 7, 6, 9])}
91
104
  />
92
105
  <MetricHighlight
93
106
  label="Response time"
94
107
  value="2h"
95
- trend={{ direction: "down", value: "12%", "aria-label": "down 12%" }}
96
- sparkline={spark([18, 16, 17, 13, 14, 10])}
108
+ trend={{
109
+ direction: "down",
110
+ value: "12%",
111
+ "aria-label": "down 12%",
112
+ }}
113
+ sparkline={spark([18, 16, 17, 13, 14, 10], "bar")}
97
114
  />
98
115
  </Grid>
99
116
 
@@ -120,6 +137,37 @@ const Brief = () => (
120
137
 
121
138
  <NarrativeDivider />
122
139
 
140
+ <NarrativeOrderedList
141
+ items={[
142
+ {
143
+ title: "Double down on reply threads",
144
+ description:
145
+ "Shift a slice of paid budget toward the organic reply threads that outperformed this week.",
146
+ action: (
147
+ <Button appearance="ai-secondary">Suggested Action</Button>
148
+ ),
149
+ },
150
+ {
151
+ title: "Protect response time at peak",
152
+ description:
153
+ "Add coverage during the two peak windows to hold response time under two hours.",
154
+ action: (
155
+ <Button appearance="ai-secondary">Suggested Action</Button>
156
+ ),
157
+ },
158
+ {
159
+ title: "Lean into the enterprise segment",
160
+ description:
161
+ "Build a follow-up sequence for the enterprise cohort that drove the most new engagement.",
162
+ action: (
163
+ <Button appearance="ai-secondary">Suggested Action</Button>
164
+ ),
165
+ },
166
+ ]}
167
+ />
168
+
169
+ <NarrativeDivider />
170
+
123
171
  {/* Narrative summary (3-column) — below the pull quotes --------- */}
124
172
  <NarrativeSummary
125
173
  eyebrow="Quarterly review"
@@ -138,8 +186,131 @@ const Brief = () => (
138
186
  quote="This rollout cut our average response time nearly in half."
139
187
  attribution={<Attribution name="Priya Nair" />}
140
188
  />
189
+
190
+ <NarrativeDivider />
191
+
192
+ {/* Data callout — a data-viz visual paired with narrative copy ---- */}
193
+ <NarrativeDataCallout
194
+ visual={
195
+ <DonutChart
196
+ description="Goal completion: 80% complete"
197
+ data={[
198
+ { name: "Complete", value: 80 },
199
+ { name: "Remaining", value: 20 },
200
+ ]}
201
+ />
202
+ }
203
+ >
204
+ We're 80% of the way to closing out this quarter's goal — a clear
205
+ signal that the cross-functional alignment we drove upstream is now
206
+ compounding into measurable downstream velocity. With the remaining
207
+ 20% squarely in view, we're doubling down on the workstreams that
208
+ move the needle and sunsetting the low-leverage noise to land this
209
+ initiative ahead of the curve.
210
+ </NarrativeDataCallout>
211
+
212
+ <NarrativeDivider />
213
+
214
+ {/* Social media cards — a row of 3 sample posts -------------------- */}
215
+ <Grid columns={{ sm: 1, md: 2, lg: 3 }} gap={400}>
216
+ <NarrativeSocialMediaCard
217
+ avatar="https://api.dicebear.com/7.x/avataaars/svg?seed=Felix"
218
+ avatarAlt="Sprout Social avatar"
219
+ displayName="Sprout Social"
220
+ socialIcon={<PartnerLogo partnerName="twitter" size="small" />}
221
+ text="Just launched our new product! Check it out and let us know what you think."
222
+ meta={[
223
+ {
224
+ icon: <Icon name="reply-outline" />,
225
+ value: 12,
226
+ label: "Replies",
227
+ },
228
+ {
229
+ icon: <Icon name="heart-outline" />,
230
+ value: 128,
231
+ label: "Likes",
232
+ },
233
+ {
234
+ icon: <Icon name="repost-outline" />,
235
+ value: 42,
236
+ label: "Reposts",
237
+ },
238
+ ]}
239
+ />
240
+ <NarrativeSocialMediaCard
241
+ avatar="https://api.dicebear.com/7.x/avataaars/svg?seed=Jordan"
242
+ avatarAlt="Marketing Team avatar"
243
+ displayName="Marketing Team"
244
+ socialIcon={<PartnerLogo partnerName="linkedin" size="small" />}
245
+ text="Our most viral post ever! Thanks for all the engagement. The community response has been incredible and we're excited to keep the momentum going."
246
+ meta={[
247
+ {
248
+ icon: <Icon name="reply-outline" />,
249
+ value: 45,
250
+ label: "Comments",
251
+ },
252
+ {
253
+ icon: <Icon name="heart-outline" />,
254
+ value: 892,
255
+ label: "Likes",
256
+ },
257
+ {
258
+ icon: <Icon name="repost-outline" />,
259
+ value: 156,
260
+ label: "Shares",
261
+ },
262
+ ]}
263
+ />
264
+ <NarrativeSocialMediaCard
265
+ avatar="https://api.dicebear.com/7.x/avataaars/svg?seed=Alex"
266
+ avatarAlt="Brand Studio avatar"
267
+ displayName="Brand Studio"
268
+ socialIcon={<PartnerLogo partnerName="instagram" size="small" />}
269
+ text="Behind the scenes of today's campaign launch. Swipe to see the creative process!"
270
+ meta={[
271
+ {
272
+ icon: <Icon name="reply-outline" />,
273
+ value: 89,
274
+ label: "Comments",
275
+ },
276
+ {
277
+ icon: <Icon name="heart-outline" />,
278
+ value: 1240,
279
+ label: "Likes",
280
+ },
281
+ {
282
+ icon: <Icon name="repost-outline" />,
283
+ value: 203,
284
+ label: "Shares",
285
+ },
286
+ ]}
287
+ />
288
+ </Grid>
141
289
  </Grid>
142
290
  </NarrativeContainer>
291
+
292
+ <NarrativeContainer>
293
+ <NarrativeOrderedList
294
+ orientation="horizontal"
295
+ items={[
296
+ {
297
+ title: "Unlock audience momentum",
298
+ description:
299
+ "Reallocate engagement capacity toward the content clusters generating outsized share-of-voice gains across high-intent segments.",
300
+ },
301
+ {
302
+ title: "Operationalize your top performers",
303
+ description:
304
+ "Templatize the creative formats moving the needle this quarter and activate them across your highest-converting touchpoints.",
305
+ },
306
+ {
307
+ title: "Accelerate pipeline velocity",
308
+ description:
309
+ "Trigger a nurture sequence for the buyer personas showing the strongest conversion propensity signals right now.",
310
+ },
311
+ ]}
312
+ />
313
+ </NarrativeContainer>
143
314
  </div>
144
315
  </div>
145
316
  );
@@ -2,6 +2,7 @@ import React from "react";
2
2
  import type { Meta, StoryObj } from "@storybook/react";
3
3
  import PullQuote from "./PullQuote";
4
4
  import "../pull-quote.css";
5
+ import "../ai-container.css";
5
6
 
6
7
  const meta = {
7
8
  title: "Narrative Kit/PullQuote",
@@ -8,9 +8,10 @@ import type { TypePullQuoteProps } from "./PullQuoteTypes";
8
8
  * optional attribution row (author name, avatar, network).
9
9
  *
10
10
  * Rendered as semantic `<figure>` / `<blockquote>` / `<figcaption>` markup.
11
- * Styled via `pull-quote.css` (Seeds CSS custom properties); consumers import
12
- * the classes through `@sproutsocial/racine/css/components`. Surface overrides
13
- * are done with standard `className` / `style`.
11
+ * Styled via `pull-quote.css` and `ai-container.css` (Seeds CSS custom
12
+ * properties); consumers import the classes through
13
+ * `@sproutsocial/racine/css/components`. Surface overrides are done with
14
+ * standard `className` / `style`.
14
15
  */
15
16
  const PullQuote = React.forwardRef<HTMLElement, TypePullQuoteProps>(
16
17
  ({ quote, attribution, appearance = "subtle", className, ...props }, ref) => {
@@ -19,6 +20,8 @@ const PullQuote = React.forwardRef<HTMLElement, TypePullQuoteProps>(
19
20
  ref={ref}
20
21
  className={cn(
21
22
  "seeds-pull-quote",
23
+ "seeds-ai-container",
24
+ { "seeds-ai-container-vivid": appearance === "vivid" },
22
25
  { "seeds-pull-quote-vivid": appearance === "vivid" },
23
26
  className
24
27
  )}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Seeds AIContainer component classes.
3
+ * Use these instead of writing out individual Tailwind utility classes.
4
+ *
5
+ * Requires @sproutsocial/seeds-react-theme/dist/theme-all.css imported for
6
+ * CSS variable definitions and dark mode support.
7
+ *
8
+ * Usage:
9
+ * <div class="seeds-ai-container">…</div> // subtle (default)
10
+ * <div class="seeds-ai-container seeds-ai-container-vivid">…</div>
11
+ */
12
+
13
+ @layer components {
14
+
15
+ .seeds-ai-container {
16
+ position: relative;
17
+ overflow: hidden;
18
+ box-sizing: border-box;
19
+ border-radius: var(--radius-800);
20
+ box-shadow: var(--shadow-low);
21
+ font-family: var(--font-family);
22
+ /* Subtle (default): the 20% AI gradient tint composited over the base
23
+ surface. --color-gradient-ai-subtle is already translucent, so layering it
24
+ over the opaque base color produces the soft wash. */
25
+ background-color: var(--color-container-bg-base);
26
+ background-image: var(--color-gradient-ai-subtle);
27
+ color: var(--color-text-headline);
28
+ }
29
+
30
+ /* Vivid: the full-saturation AI gradient with white content. White has no
31
+ semantic Seeds token; it is part of the AI gradient treatment (mirrors the
32
+ raw brand hex used in --color-gradient-ai). */
33
+ .seeds-ai-container-vivid {
34
+ background-color: transparent;
35
+ background-image: var(--color-gradient-ai);
36
+ color: #fff;
37
+ }
38
+
39
+ }
package/src/css.d.ts ADDED
@@ -0,0 +1 @@
1
+ declare module "*.css";
package/src/index.ts CHANGED
@@ -36,4 +36,29 @@ export {
36
36
  type TypeNarrativeSummaryLayout,
37
37
  } from "./NarrativeSummary";
38
38
 
39
+ export {
40
+ NarrativeOrderedList,
41
+ type TypeNarrativeOrderedListProps,
42
+ type TypeNarrativeOrderedListItem,
43
+ type TypeNarrativeOrderedListOrientation,
44
+ } from "./NarrativeOrderedList";
45
+
46
+ export {
47
+ NarrativeDataCallout,
48
+ type TypeNarrativeDataCalloutProps,
49
+ } from "./NarrativeDataCallout";
50
+
51
+ export { AIContainer, type TypeAIContainerProps } from "./AIContainer";
52
+
53
+ export {
54
+ NarrativeSocialMediaCard,
55
+ type TypeNarrativeSocialMediaCardProps,
56
+ type TypeNarrativeSocialMediaCardMeta,
57
+ } from "./NarrativeSocialMediaCard";
58
+
59
+ export {
60
+ NarrativeAttribution,
61
+ type TypeNarrativeAttributionProps,
62
+ } from "./NarrativeAttribution";
63
+
39
64
  export type { TypeNarrativeTone } from "./_internal/types";
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Seeds NarrativeAttribution component classes.
3
+ * Use these instead of writing out individual Tailwind utility classes.
4
+ *
5
+ * Requires @sproutsocial/seeds-react-theme/dist/theme-all.css imported for
6
+ * CSS variable definitions and dark mode support.
7
+ *
8
+ * Usage:
9
+ * <div class="seeds-narrative-attribution">
10
+ * <img class="seeds-narrative-attribution-avatar" />
11
+ * <div class="seeds-narrative-attribution-social-icon">...</div>
12
+ * <span class="seeds-narrative-attribution-user-name">...</span>
13
+ * </div>
14
+ */
15
+
16
+ @layer components {
17
+
18
+ /* Main container — horizontal layout with avatar, social icon, and user name. */
19
+ .seeds-narrative-attribution {
20
+ box-sizing: border-box;
21
+ display: flex;
22
+ align-items: center;
23
+ gap: var(--space-300); /* 8px */;
24
+ font-family: var(--font-family);
25
+ }
26
+
27
+ /* Circular avatar image — fixed size with rounded corners. */
28
+ .seeds-narrative-attribution-avatar {
29
+ width: var(--space-450); /* 24px */
30
+ height: var(--space-450); /* 24px */
31
+ border-radius: var(--radius-circular); /* 50% */
32
+ object-fit: cover;
33
+ flex-shrink: 0;
34
+ }
35
+
36
+ /* Social network icon container — flexible sizing for partner logos. */
37
+ .seeds-narrative-attribution-social-icon {
38
+ flex-shrink: 0;
39
+ display: flex;
40
+ align-items: center;
41
+ justify-content: center;
42
+ }
43
+
44
+ /* User name text — bold headline text with ellipsis overflow. */
45
+ .seeds-narrative-attribution-user-name {
46
+ overflow: hidden;
47
+ color: var(--color-text-headline);
48
+ text-overflow: ellipsis;
49
+ font-family: var(--font-family);
50
+ font-size: var(--text-base-font-size, 14px);
51
+ font-style: normal;
52
+ font-weight: var(--font-weight-bold, 700);
53
+ line-height: var(--text-base-line-height, 24px);
54
+ }
55
+
56
+ }
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Seeds NarrativeDataCallout component classes.
3
+ * Use these instead of writing out individual Tailwind utility classes.
4
+ *
5
+ * Requires @sproutsocial/seeds-react-theme/dist/theme-all.css imported for
6
+ * CSS variable definitions and dark mode support.
7
+ *
8
+ * The layout is a flex row driven by a container query on the root, so the
9
+ * visual/text columns stack based on the width the component is given, not the
10
+ * viewport.
11
+ *
12
+ * Usage:
13
+ * <div class="seeds-narrative-data-callout">
14
+ * <div class="seeds-narrative-data-callout-row">
15
+ * <div class="seeds-narrative-data-callout-visual">…chart…</div>
16
+ * <div class="seeds-narrative-data-callout-body">…copy…</div>
17
+ * </div>
18
+ * </div>
19
+ */
20
+
21
+ @layer components {
22
+
23
+ /* Establishes the query container. The row inside reacts to this element's
24
+ inline size. A container query only styles DESCENDANTS of the query container,
25
+ so the flex row lives on the inner element, not this one. */
26
+ .seeds-narrative-data-callout {
27
+ container-type: inline-size;
28
+ box-sizing: border-box;
29
+ font-family: var(--font-family);
30
+ }
31
+
32
+ /* Stacked single column by default (narrow). The container query below turns it
33
+ into the horizontal 1/3 + 2/3 row once there is room. */
34
+ .seeds-narrative-data-callout-row {
35
+ box-sizing: border-box;
36
+ display: flex;
37
+ flex-direction: column;
38
+ align-items: center;
39
+ gap: var(--space-450); /* 24px */
40
+ }
41
+
42
+ /* Visual slot — layout only, no stroke/background so the injected chart controls
43
+ its own look and its own size. No fixed height: charts like the data-viz
44
+ DonutChart carry their own intrinsic height (and a legend), so the slot sizes
45
+ to the chart rather than clipping it. Stacked full-width until the container
46
+ query expands the row. */
47
+ .seeds-narrative-data-callout-visual {
48
+ box-sizing: border-box;
49
+ display: flex;
50
+ align-items: center;
51
+ justify-content: center;
52
+ width: 100%;
53
+ min-width: 0;
54
+ }
55
+
56
+ /* Stretch the injected visual to the slot's full width. A fluid-width chart like
57
+ the v2 DonutChart otherwise shrinks to content inside this centered flex slot,
58
+ so Highcharts fills that shrunk width and the ring gets width-capped below its
59
+ fixed 270px height — leaving an empty vertical band. Filling the width lets the
60
+ ring become height-capped and fill its box top-to-bottom, like the standalone
61
+ chart story. */
62
+ .seeds-narrative-data-callout-visual > * {
63
+ width: 100%;
64
+ }
65
+
66
+ /* Body copy — fills the remaining space. */
67
+ .seeds-narrative-data-callout-body {
68
+ box-sizing: border-box;
69
+ min-width: 0;
70
+ font-size: var(--font-size-300); /* 16px */
71
+ line-height: var(--line-height-400); /* ~28px */
72
+ font-weight: var(--font-weight-normal);
73
+ color: var(--color-text-body);
74
+ overflow-wrap: break-word;
75
+ }
76
+
77
+ /* Expand to the horizontal 1/3 + 2/3 split once the component is wide enough.
78
+ The threshold is on the component's own width (container query), so a narrow
79
+ callout on a wide screen still stacks. 480px keeps the donut + copy readable
80
+ side by side. */
81
+ @container (min-width: 480px) {
82
+ .seeds-narrative-data-callout-row {
83
+ flex-direction: row;
84
+ }
85
+
86
+ .seeds-narrative-data-callout-visual {
87
+ /* Nominally one-third, but never narrower than the injected chart's fixed
88
+ height (the v2 DonutChart is 270px tall). Below that width a fluid-width,
89
+ fixed-height chart like the donut gets width-capped and leaves an empty
90
+ vertical band above/below the ring; the min-width keeps the visual square
91
+ enough that the ring fills its box top-to-bottom, matching the standalone
92
+ chart story. */
93
+ flex: 0 0 33.333%;
94
+ min-width: 270px;
95
+ width: auto;
96
+ }
97
+
98
+ .seeds-narrative-data-callout-body {
99
+ flex: 1 1 0;
100
+ }
101
+ }
102
+
103
+ }
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Seeds NarrativeOrderedList component classes.
3
+ * Use these instead of writing out individual Tailwind utility classes.
4
+ *
5
+ * Requires @sproutsocial/seeds-react-theme/dist/theme-all.css imported for
6
+ * CSS variable definitions and dark mode support.
7
+ *
8
+ * Usage:
9
+ * <div class="seeds-narrative-ordered-list">
10
+ * <ol class="seeds-narrative-ordered-list-track">
11
+ * <li class="seeds-narrative-ordered-list-item">…</li>
12
+ * </ol>
13
+ * </div>
14
+ */
15
+
16
+ @layer components {
17
+
18
+ /* Establishes the query container. The track inside reacts to this element's
19
+ inline size — a container query can only style descendants of the container,
20
+ never the container element itself. */
21
+ .seeds-narrative-ordered-list {
22
+ container-type: inline-size;
23
+ box-sizing: border-box;
24
+ font-family: var(--font-family);
25
+ }
26
+
27
+ /* The list itself, and the default (stacked) layout. The horizontal modifier
28
+ only expands to a row once the container query below has room, so horizontal
29
+ collapses back to this stack when narrow. */
30
+ .seeds-narrative-ordered-list-track {
31
+ display: flex;
32
+ flex-direction: column;
33
+ gap: var(--space-400); /* 16px */
34
+ margin: 0;
35
+ padding: 0;
36
+ list-style: none;
37
+ }
38
+
39
+ /* An item row: the ordinal beside the body, on its own rounded surface. */
40
+ .seeds-narrative-ordered-list-item {
41
+ display: flex;
42
+ gap: var(--space-450); /* 24px */
43
+ align-items: flex-start;
44
+ box-sizing: border-box;
45
+ min-width: 0;
46
+ padding: var(--space-400) var(--space-450); /* 16px 24px */
47
+ border-radius: var(--radius-800); /* 12px */
48
+ background-color: var(--color-app-bg-base);
49
+ }
50
+
51
+ /* The ordinal (01, 02, …). No mono token exists yet, so fall back to a system
52
+ monospace stack — mirrors the value treatment in metric-highlight.css. */
53
+ .seeds-narrative-ordered-list-number {
54
+ margin: 0;
55
+ flex-shrink: 0;
56
+ font-family: var(--font-family-mono, ui-monospace, "SF Mono", SFMono-Regular, Menlo, monospace);
57
+ font-size: var(--font-size-700); /* 32px */
58
+ line-height: var(--line-height-700); /* 40px */
59
+ font-weight: var(--font-weight-bold);
60
+ color: var(--color-text-headline);
61
+ }
62
+
63
+ /* Title + description + optional action, stacked. */
64
+ .seeds-narrative-ordered-list-body {
65
+ flex: 1 1 auto;
66
+ display: flex;
67
+ flex-direction: column;
68
+ gap: var(--space-200); /* 4px */
69
+ min-width: 0;
70
+ }
71
+
72
+ /* Title. 16px / 28px — the 28px line-height has no exact type token (the scale
73
+ skips from 24px to 32px), so the design value is kept verbatim. Same
74
+ rationale as narrative-summary.css. */
75
+ .seeds-narrative-ordered-list-title {
76
+ margin: 0;
77
+ font-size: var(--font-size-300); /* 16px */
78
+ line-height: 28px; /* off-scale, see comment above */
79
+ font-weight: var(--font-weight-bold);
80
+ color: var(--color-text-body);
81
+ }
82
+
83
+ /* Description. 14px / 24px has no exact type token, so it is kept verbatim —
84
+ same rationale as the title above. */
85
+ .seeds-narrative-ordered-list-description {
86
+ margin: 0;
87
+ font-size: 14px; /* off-scale, see title above */
88
+ line-height: 24px;
89
+ font-weight: var(--font-weight-normal);
90
+ color: var(--color-text-body);
91
+ }
92
+
93
+ .seeds-narrative-ordered-list-action {
94
+ padding-top: var(--space-350); /* 12px */
95
+ }
96
+
97
+ /* Expand the horizontal variant to a row of equal columns once the component is
98
+ wide enough. The threshold is on the component's own width (container query),
99
+ so a narrow card on a wide screen still stacks. 640px = Tailwind/Seeds sm
100
+ breakpoint, matching narrative-summary.css. */
101
+ @container (min-width: 640px) {
102
+ .seeds-narrative-ordered-list-horizontal {
103
+ flex-direction: row;
104
+ }
105
+
106
+ .seeds-narrative-ordered-list-horizontal > .seeds-narrative-ordered-list-item {
107
+ flex: 1 1 0;
108
+ min-width: 0;
109
+ }
110
+ }
111
+
112
+ }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Seeds NarrativeSocialMediaCard component classes.
3
+ * Use these instead of writing out individual Tailwind utility classes.
4
+ *
5
+ * Requires @sproutsocial/seeds-react-theme/dist/theme-all.css imported for
6
+ * CSS variable definitions and dark mode support.
7
+ *
8
+ * Usage:
9
+ * <div class="seeds-narrative-social-media-card">
10
+ * <div class="seeds-narrative-social-media-card-header">...</div>
11
+ * <div class="seeds-narrative-social-media-card-content">...</div>
12
+ * <div class="seeds-narrative-social-media-card-footer">...</div>
13
+ * </div>
14
+ */
15
+
16
+ /* Import dependent component styles */
17
+ @import "./narrative-attribution.css";
18
+
19
+ @layer components {
20
+
21
+ /* Main card container — gray background with rounded corners and padding.
22
+ Uses Seeds tokens for spacing, colors, and radius to match the design system. */
23
+ .seeds-narrative-social-media-card {
24
+ box-sizing: border-box;
25
+ display: flex;
26
+ flex-direction: column;
27
+ align-items: flex-start;
28
+ max-width: 320px;
29
+ padding: var(--space-450); /* 24px */
30
+ border-radius: var(--radius-500); /* 6px */
31
+ background-color: var(--color-app-bg-base);
32
+ font-family: var(--font-family);
33
+ color: var(--color-text-body);
34
+ }
35
+
36
+ /* No background — transparent background for cards that blend seamlessly with the page. */
37
+ .seeds-narrative-social-media-card--no-background {
38
+ background-color: transparent;
39
+ }
40
+
41
+ /* Main content area — standard body text styling. */
42
+ .seeds-narrative-social-media-card-content {
43
+ flex: 1;
44
+ margin-top: var(--space-400); /* 16px */
45
+ font-family: var(--font-family);
46
+ font-size: 14px;
47
+ font-style: normal;
48
+ font-weight: 400;
49
+ line-height: 24px;
50
+ color: var(--color-text-body);
51
+ }
52
+
53
+ /* Footer section — horizontal layout for stats with equal spacing. */
54
+ .seeds-narrative-social-media-card-footer {
55
+ display: flex;
56
+ align-items: center;
57
+ gap: var(--space-400); /* 16px */
58
+ margin-top: var(--space-400); /* 16px */;
59
+ }
60
+
61
+ /* Hide footer when empty (no metadata items). */
62
+ .seeds-narrative-social-media-card-footer:empty {
63
+ display: none;
64
+ }
65
+
66
+ /* Individual stat container — icon + value in horizontal layout. */
67
+ .seeds-narrative-social-media-card-stat {
68
+ display: flex;
69
+ align-items: center;
70
+ gap: var(--space-200); /* 4px */
71
+ }
72
+
73
+ /* Stat value text — monospace font for numeric values. */
74
+ .seeds-narrative-social-media-card-stat-value {
75
+ font-family: var(--font-family-mono, ui-monospace, "SF Mono", SFMono-Regular, Menlo, monospace); font-size: 14px;
76
+ font-style: normal;
77
+ font-weight: 400;
78
+ line-height: 24px;
79
+ color: var(--color-text-body);
80
+ }
81
+
82
+ }