@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.
- package/.turbo/turbo-build.log +11 -11
- package/CHANGELOG.md +33 -0
- package/dist/ai-container.css +39 -0
- package/dist/esm/index.js +199 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/index.d.mts +186 -4
- package/dist/index.d.ts +186 -4
- package/dist/index.js +204 -0
- package/dist/index.js.map +1 -1
- package/dist/narrative-attribution.css +56 -0
- package/dist/narrative-data-callout.css +103 -0
- package/dist/narrative-ordered-list.css +112 -0
- package/dist/narrative-social-media-card.css +82 -0
- package/dist/pull-quote.css +4 -25
- package/package.json +12 -5
- package/src/AIContainer/AIContainer.stories.tsx +54 -0
- package/src/AIContainer/AIContainer.tsx +35 -0
- package/src/AIContainer/AIContainerTypes.ts +14 -0
- package/src/AIContainer/__tests__/AIContainer.test.tsx +61 -0
- package/src/AIContainer/index.ts +2 -0
- package/src/NarrativeAttribution/NarrativeAttribution.stories.tsx +78 -0
- package/src/NarrativeAttribution/NarrativeAttribution.tsx +54 -0
- package/src/NarrativeAttribution/NarrativeAttributionTypes.ts +13 -0
- package/src/NarrativeAttribution/index.ts +2 -0
- package/src/NarrativeDataCallout/NarrativeDataCallout.stories.tsx +71 -0
- package/src/NarrativeDataCallout/NarrativeDataCallout.tsx +50 -0
- package/src/NarrativeDataCallout/NarrativeDataCalloutTypes.ts +18 -0
- package/src/NarrativeDataCallout/__tests__/NarrativeDataCallout.test.tsx +69 -0
- package/src/NarrativeDataCallout/index.ts +2 -0
- package/src/NarrativeOrderedList/NarrativeOrderedList.stories.tsx +69 -0
- package/src/NarrativeOrderedList/NarrativeOrderedList.tsx +74 -0
- package/src/NarrativeOrderedList/NarrativeOrderedListTypes.ts +39 -0
- package/src/NarrativeOrderedList/__tests__/NarrativeOrderedList.test.tsx +89 -0
- package/src/NarrativeOrderedList/index.ts +6 -0
- package/src/NarrativeSocialMediaCard/NarrativeSocialMediaCard.stories.tsx +111 -0
- package/src/NarrativeSocialMediaCard/NarrativeSocialMediaCard.tsx +80 -0
- package/src/NarrativeSocialMediaCard/NarrativeSocialMediaCardTypes.ts +30 -0
- package/src/NarrativeSocialMediaCard/__tests__/NarrativeSocialMediaCard.test.tsx +154 -0
- package/src/NarrativeSocialMediaCard/index.ts +5 -0
- package/src/Playground/Playground.stories.tsx +176 -5
- package/src/PullQuote/PullQuote.stories.tsx +1 -0
- package/src/PullQuote/PullQuote.tsx +6 -3
- package/src/ai-container.css +39 -0
- package/src/css.d.ts +1 -0
- package/src/index.ts +25 -0
- package/src/narrative-attribution.css +56 -0
- package/src/narrative-data-callout.css +103 -0
- package/src/narrative-ordered-list.css +112 -0
- package/src/narrative-social-media-card.css +82 -0
- 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=
|
|
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={{
|
|
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={{
|
|
96
|
-
|
|
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
|
);
|
|
@@ -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
|
|
12
|
-
* the classes through
|
|
13
|
-
* are done with
|
|
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
|
+
}
|