@hraness/design-kit 0.33.0 → 0.35.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/README.md +19 -3
- package/dist/{chunk-mr1vdcjq.js → chunk-8xfssb9c.js} +6 -3
- package/dist/{chunk-95mpmzc9.js → chunk-c9mhn3yb.js} +1130 -442
- package/dist/{chunk-h4k7yv6x.js → chunk-fjf81bww.js} +28 -2
- package/dist/chunk-gmea6p0d.js +13 -0
- package/dist/index.js +5 -1
- package/dist/mockups/client.js +50 -15
- package/dist/portfolio.js +586 -85
- package/dist/react/index.js +141 -13
- package/dist/react/platform-install.js +3 -2
- package/dist/react/server.js +17 -3
- package/dist/stylex-manifest.json +1 -1
- package/dist/stylex.css +350 -36
- package/package.json +14 -3
- package/portfolio-inventory.json +1 -1
- package/src/diagrams.ts +11 -0
- package/src/index.ts +2 -0
- package/src/marketing-comparison.css +162 -0
- package/src/marketing-diagram.css +24 -0
- package/src/mockups/client.tsx +25 -17
- package/src/mockups.css +19 -0
- package/src/plain-publication.css +9 -6
- package/src/portfolio.generated.json +578 -86
- package/src/portfolio.generated.ts +578 -86
- package/src/portfolio.ts +73 -0
- package/src/product-marketing-foundation.css +29 -0
- package/src/product-marketing.css +136 -39
- package/src/react/article.tsx +2 -2
- package/src/react/design-gallery.tsx +37 -8
- package/src/react/index.ts +3 -0
- package/src/react/marketing-account.stylex.ts +74 -0
- package/src/react/marketing-account.tsx +69 -0
- package/src/react/marketing-comparison.stylex.ts +24 -0
- package/src/react/marketing-comparison.tsx +73 -0
- package/src/react/marketing-diagram.stylex.ts +8 -0
- package/src/react/marketing-diagram.tsx +33 -0
- package/src/react/platform-install.stylex.ts +2 -1
- package/src/react/platform-install.tsx +2 -1
- package/src/react/product-marketing.stylex.ts +144 -111
- package/src/react/product-marketing.tsx +83 -45
- package/src/react/server.ts +3 -0
- package/src/styles.css +2 -0
- package/src/typography.css +32 -0
- /package/dist/{chunk-4d79eskk.js → chunk-c80g58j1.js} +0 -0
package/src/portfolio.ts
CHANGED
|
@@ -108,11 +108,39 @@ export type PortfolioProvenance = Readonly<{
|
|
|
108
108
|
files: readonly Readonly<{ path: string; sha256: string }>[];
|
|
109
109
|
}>;
|
|
110
110
|
|
|
111
|
+
export type PortfolioPackTone = "rose" | "indigo" | "amber" | "emerald";
|
|
112
|
+
|
|
113
|
+
/** The homepage categories, in the same order as hraness.com. */
|
|
114
|
+
export type PortfolioPack = Readonly<{
|
|
115
|
+
slug: string;
|
|
116
|
+
title: string;
|
|
117
|
+
tone: PortfolioPackTone;
|
|
118
|
+
members: readonly PortfolioProductId[];
|
|
119
|
+
}>;
|
|
120
|
+
|
|
121
|
+
export type PortfolioStudioItem = Readonly<{
|
|
122
|
+
productId: PortfolioProductId;
|
|
123
|
+
href: string;
|
|
124
|
+
name: string;
|
|
125
|
+
role: string;
|
|
126
|
+
mark: string;
|
|
127
|
+
domain: string;
|
|
128
|
+
}>;
|
|
129
|
+
|
|
130
|
+
/** Product-neutral data shaped for the shared MarketingRelated composition. */
|
|
131
|
+
export type PortfolioStudioGroup = Readonly<{
|
|
132
|
+
heading: string;
|
|
133
|
+
headingId: string;
|
|
134
|
+
tone: PortfolioPackTone | "neutral";
|
|
135
|
+
items: readonly PortfolioStudioItem[];
|
|
136
|
+
}>;
|
|
137
|
+
|
|
111
138
|
export type PortfolioSnapshot = Readonly<{
|
|
112
139
|
contract: "hraness.design-kit-portfolio/v1";
|
|
113
140
|
formatVersion: 1;
|
|
114
141
|
provenance: PortfolioProvenance;
|
|
115
142
|
products: Readonly<Record<PortfolioProductId, PortfolioProduct>>;
|
|
143
|
+
packs: readonly PortfolioPack[];
|
|
116
144
|
relations: readonly PortfolioRelation[];
|
|
117
145
|
/** SHA-256 of the snapshot's compact JSON without this key. Pin it in a consumer test. */
|
|
118
146
|
digest: string;
|
|
@@ -154,6 +182,7 @@ function deepFreeze<T>(value: T): T {
|
|
|
154
182
|
/** The whole snapshot, frozen so one consumer cannot change another's facts at runtime. */
|
|
155
183
|
export const portfolioFacts: PortfolioSnapshot = deepFreeze(portfolioSnapshot);
|
|
156
184
|
export const portfolioProducts: PortfolioSnapshot["products"] = portfolioFacts.products;
|
|
185
|
+
export const portfolioPacks: readonly PortfolioPack[] = portfolioFacts.packs;
|
|
157
186
|
export const portfolioRelations: PortfolioSnapshot["relations"] = portfolioFacts.relations;
|
|
158
187
|
export const portfolioProvenance: PortfolioProvenance = portfolioFacts.provenance;
|
|
159
188
|
export const portfolioDigest: string = portfolioFacts.digest;
|
|
@@ -224,3 +253,47 @@ export function usesPairs(): readonly PortfolioUsesPair[] {
|
|
|
224
253
|
target: product(relation.target),
|
|
225
254
|
}));
|
|
226
255
|
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Present only the caller's selected products, once each, in the homepage's
|
|
259
|
+
* category and member order. Categories with no selected products disappear.
|
|
260
|
+
* Products outside a pack follow in a neutral group. This does not infer an
|
|
261
|
+
* integration or expand a site's curated related-product selection.
|
|
262
|
+
*/
|
|
263
|
+
export function portfolioRelatedGroups(
|
|
264
|
+
ids: readonly PortfolioProductId[],
|
|
265
|
+
headingPrefix = "related",
|
|
266
|
+
): readonly PortfolioStudioGroup[] {
|
|
267
|
+
if (!/^[a-z][a-z0-9-]*$/u.test(headingPrefix)) {
|
|
268
|
+
throw new PortfolioFactsError("The related heading prefix must be a lowercase HTML identifier.");
|
|
269
|
+
}
|
|
270
|
+
const selected = new Set(ids.map((id) => product(id).id));
|
|
271
|
+
const item = (id: PortfolioProductId): PortfolioStudioItem => {
|
|
272
|
+
const entry = product(id);
|
|
273
|
+
return {
|
|
274
|
+
productId: id,
|
|
275
|
+
href: entry.canonicalUrl,
|
|
276
|
+
name: entry.messaging.names.name,
|
|
277
|
+
role: entry.oneLiner,
|
|
278
|
+
mark: entry.mark,
|
|
279
|
+
domain: entry.canonicalUrl.replace(/^https?:\/\/(?:www\.)?([^/:?#]+).*$/u, "$1"),
|
|
280
|
+
};
|
|
281
|
+
};
|
|
282
|
+
const groups: PortfolioStudioGroup[] = [];
|
|
283
|
+
for (const pack of portfolioPacks) {
|
|
284
|
+
const members = pack.members.filter((id) => selected.delete(id));
|
|
285
|
+
if (members.length > 0) groups.push({
|
|
286
|
+
heading: pack.title,
|
|
287
|
+
headingId: `${headingPrefix}-${pack.slug}`,
|
|
288
|
+
tone: pack.tone,
|
|
289
|
+
items: members.map(item),
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
if (selected.size > 0) groups.push({
|
|
293
|
+
heading: "More from Hraness",
|
|
294
|
+
headingId: `${headingPrefix}-more`,
|
|
295
|
+
tone: "neutral",
|
|
296
|
+
items: portfolioProductIds.filter((id) => selected.has(id)).map(item),
|
|
297
|
+
});
|
|
298
|
+
return groups;
|
|
299
|
+
}
|
|
@@ -108,6 +108,21 @@
|
|
|
108
108
|
text-underline-offset: 0.16em;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
+
|
|
112
|
+
.hraness-marketing-page :where(p, li, dd, dt, figcaption) a:not([role="button"], [data-emphasis], [data-hraness-marketing], [data-foil]),
|
|
113
|
+
.hraness-marketing-maker__links a {
|
|
114
|
+
text-decoration-line: underline;
|
|
115
|
+
text-decoration-style: dotted;
|
|
116
|
+
text-decoration-color: color-mix(in srgb, currentColor 40%, transparent);
|
|
117
|
+
text-decoration-thickness: 1px;
|
|
118
|
+
text-underline-offset: 0.2em;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.hraness-marketing-page :where(p, li, dd, dt, figcaption) a:not([role="button"], [data-emphasis], [data-hraness-marketing], [data-foil]):is(:hover, :focus-visible),
|
|
122
|
+
.hraness-marketing-maker__links a:is(:hover, :focus-visible) {
|
|
123
|
+
text-decoration-color: currentColor;
|
|
124
|
+
}
|
|
125
|
+
|
|
111
126
|
.hraness-marketing-page :where(code, kbd, pre) {
|
|
112
127
|
font-family: var(--hraness-marketing-mono-font);
|
|
113
128
|
}
|
|
@@ -431,3 +446,17 @@ html:has(:is(.hraness-marketing-header, .hraness-marketing-header-surface):not([
|
|
|
431
446
|
}
|
|
432
447
|
|
|
433
448
|
}
|
|
449
|
+
|
|
450
|
+
/* Product-owned SVG content grammar; the diagram's React frame stays compiled. */
|
|
451
|
+
@layer components.hraness-design-kit.legacy {
|
|
452
|
+
.hraness-diagram .hraness-diagram__label { fill: var(--foreground); font-family: var(--font-text); font-size: 20px; font-weight: 500; }
|
|
453
|
+
.hraness-diagram .hraness-diagram__detail { fill: var(--muted); font-family: var(--font-text); font-size: 16px; font-weight: 400; }
|
|
454
|
+
.hraness-diagram .hraness-diagram__node { fill: var(--background); stroke: var(--line); stroke-width: 1; }
|
|
455
|
+
.hraness-diagram .hraness-diagram__connector,
|
|
456
|
+
.hraness-diagram .hraness-diagram__icon { color: var(--primary); fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
|
|
457
|
+
@media (forced-colors: active) {
|
|
458
|
+
.hraness-diagram .hraness-diagram__label, .hraness-diagram .hraness-diagram__detail { fill: CanvasText; }
|
|
459
|
+
.hraness-diagram .hraness-diagram__node { fill: Canvas; stroke: CanvasText; }
|
|
460
|
+
.hraness-diagram .hraness-diagram__connector, .hraness-diagram .hraness-diagram__icon { color: CanvasText; }
|
|
461
|
+
}
|
|
462
|
+
}
|
|
@@ -101,6 +101,21 @@
|
|
|
101
101
|
text-underline-offset: 0.16em;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
|
|
105
|
+
.hraness-marketing-page :where(p, li, dd, dt, figcaption) a:not([role="button"], [data-emphasis], [data-hraness-marketing], [data-foil]),
|
|
106
|
+
.hraness-marketing-maker__links a {
|
|
107
|
+
text-decoration-line: underline;
|
|
108
|
+
text-decoration-style: dotted;
|
|
109
|
+
text-decoration-color: color-mix(in srgb, currentColor 40%, transparent);
|
|
110
|
+
text-decoration-thickness: 1px;
|
|
111
|
+
text-underline-offset: 0.2em;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.hraness-marketing-page :where(p, li, dd, dt, figcaption) a:not([role="button"], [data-emphasis], [data-hraness-marketing], [data-foil]):is(:hover, :focus-visible),
|
|
115
|
+
.hraness-marketing-maker__links a:is(:hover, :focus-visible) {
|
|
116
|
+
text-decoration-color: currentColor;
|
|
117
|
+
}
|
|
118
|
+
|
|
104
119
|
.hraness-marketing-page :where(code, kbd, pre) {
|
|
105
120
|
font-family: var(--hraness-marketing-mono-font);
|
|
106
121
|
}
|
|
@@ -749,6 +764,8 @@ html:has(:is(.hraness-marketing-header, .hraness-marketing-header-surface):not([
|
|
|
749
764
|
line-height: var(--hraness-marketing-summary-leading, 1.6);
|
|
750
765
|
}
|
|
751
766
|
|
|
767
|
+
.hraness-marketing-hero__install { inline-size: min(100%, 44rem); min-inline-size: 0; margin-block-start: 0.75rem; text-align: start; }
|
|
768
|
+
|
|
752
769
|
.hraness-marketing-hero__example {
|
|
753
770
|
max-inline-size: var(--hraness-marketing-example-measure, var(--hraness-marketing-copy-measure));
|
|
754
771
|
margin-block-start: -0.35rem;
|
|
@@ -1029,6 +1046,11 @@ html:has(:is(.hraness-marketing-header, .hraness-marketing-header-surface):not([
|
|
|
1029
1046
|
line-height: 1.5;
|
|
1030
1047
|
}
|
|
1031
1048
|
|
|
1049
|
+
.hraness-marketing-pillars[data-presentation="benefits"] { border-block: 0; gap: 2.75rem 3rem; }
|
|
1050
|
+
.hraness-marketing-pillars[data-presentation="benefits"] > div { border: 0; padding: 0; gap: 0.75rem; }
|
|
1051
|
+
.hraness-marketing-pillars__icon { display: block; inline-size: 1.5rem; block-size: 1.5rem; margin-block-end: 1.1rem; color: var(--primary); }
|
|
1052
|
+
.hraness-marketing-pillars__icon > svg { inline-size: 100%; block-size: 100%; }
|
|
1053
|
+
|
|
1032
1054
|
/* Product frame */
|
|
1033
1055
|
|
|
1034
1056
|
.hraness-marketing-proof-frame {
|
|
@@ -1345,12 +1367,28 @@ html:has(:is(.hraness-marketing-header, .hraness-marketing-header-surface):not([
|
|
|
1345
1367
|
max-inline-size: none;
|
|
1346
1368
|
}
|
|
1347
1369
|
|
|
1348
|
-
/*
|
|
1370
|
+
/* Studio products use the portfolio category rule and compact mark rows. */
|
|
1371
|
+
|
|
1372
|
+
.hraness-marketing-related__groups {
|
|
1373
|
+
display: grid;
|
|
1374
|
+
grid-template-columns: repeat(auto-fit, minmax(min(100%, 24rem), 1fr));
|
|
1375
|
+
gap: 2.5rem 3.5rem;
|
|
1376
|
+
align-items: start;
|
|
1377
|
+
}
|
|
1349
1378
|
|
|
1350
1379
|
.hraness-marketing-related__group {
|
|
1380
|
+
--hraness-marketing-related-tone: var(--hraness-marketing-ink);
|
|
1351
1381
|
display: grid;
|
|
1352
|
-
gap:
|
|
1382
|
+
gap: 1rem;
|
|
1353
1383
|
min-inline-size: 0;
|
|
1384
|
+
border-block-start: 2px solid var(--hraness-marketing-related-tone);
|
|
1385
|
+
padding-block-start: 1rem;
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
@media (forced-colors: active) {
|
|
1389
|
+
.hraness-marketing-related__group {
|
|
1390
|
+
--hraness-marketing-related-tone: CanvasText;
|
|
1391
|
+
}
|
|
1354
1392
|
}
|
|
1355
1393
|
|
|
1356
1394
|
.hraness-marketing-related__group-header {
|
|
@@ -1359,93 +1397,151 @@ html:has(:is(.hraness-marketing-header, .hraness-marketing-header-surface):not([
|
|
|
1359
1397
|
gap: 0.5rem;
|
|
1360
1398
|
}
|
|
1361
1399
|
|
|
1362
|
-
/* Tier headings take the third heading size so a display face never renders
|
|
1363
|
-
* at caption size. */
|
|
1364
1400
|
.hraness-marketing-related__group-heading {
|
|
1365
1401
|
margin: 0;
|
|
1366
1402
|
color: var(--hraness-marketing-ink);
|
|
1367
|
-
font-family: var(--hraness-marketing-
|
|
1368
|
-
font-weight:
|
|
1369
|
-
letter-spacing:
|
|
1370
|
-
line-height:
|
|
1403
|
+
font-family: var(--hraness-marketing-text-font);
|
|
1404
|
+
font-weight: 600;
|
|
1405
|
+
letter-spacing: -0.01em;
|
|
1406
|
+
line-height: 1.35;
|
|
1371
1407
|
text-wrap: balance;
|
|
1372
|
-
font-size:
|
|
1408
|
+
font-size: 1.125rem;
|
|
1373
1409
|
}
|
|
1374
1410
|
|
|
1375
1411
|
.hraness-marketing-related__group-summary {
|
|
1376
1412
|
margin: 0;
|
|
1377
1413
|
color: var(--hraness-marketing-muted);
|
|
1378
1414
|
font-family: var(--hraness-marketing-text-font);
|
|
1379
|
-
font-size:
|
|
1415
|
+
font-size: 1rem;
|
|
1380
1416
|
line-height: 1.5;
|
|
1381
1417
|
}
|
|
1382
1418
|
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1419
|
+
.hraness-marketing-related__list {
|
|
1420
|
+
--hraness-marketing-grid-columns: initial;
|
|
1421
|
+
--_hraness-marketing-grid-track: max(16rem, calc((100% - (var(--hraness-marketing-grid-columns) - 1) * 0.5rem) / var(--hraness-marketing-grid-columns)));
|
|
1422
|
+
grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--_hraness-marketing-grid-track, 100%)), 1fr));
|
|
1423
|
+
display: grid;
|
|
1424
|
+
gap: 0.5rem;
|
|
1425
|
+
list-style: none;
|
|
1426
|
+
margin: 0;
|
|
1427
|
+
padding: 0;
|
|
1428
|
+
min-inline-size: 0;
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
.hraness-marketing-related__item {
|
|
1432
|
+
margin: 0;
|
|
1433
|
+
min-inline-size: 0;
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1386
1436
|
.hraness-marketing-related__card {
|
|
1387
1437
|
display: flex;
|
|
1388
1438
|
flex-direction: row;
|
|
1389
|
-
align-items:
|
|
1439
|
+
align-items: flex-start;
|
|
1390
1440
|
position: relative;
|
|
1391
|
-
isolation: isolate;
|
|
1392
1441
|
min-inline-size: 0;
|
|
1393
|
-
min-block-size:
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
border:
|
|
1398
|
-
border-radius:
|
|
1399
|
-
background:
|
|
1400
|
-
color:
|
|
1442
|
+
min-block-size: 2.75rem;
|
|
1443
|
+
gap: 0.85rem;
|
|
1444
|
+
padding: 0.55rem 0.5rem;
|
|
1445
|
+
margin-inline: 0;
|
|
1446
|
+
border: 0;
|
|
1447
|
+
border-radius: 0.375rem;
|
|
1448
|
+
background-color: transparent;
|
|
1449
|
+
color: var(--hraness-marketing-ink);
|
|
1401
1450
|
text-decoration: none;
|
|
1402
|
-
box-shadow:
|
|
1451
|
+
box-shadow: none;
|
|
1403
1452
|
}
|
|
1404
1453
|
|
|
1405
1454
|
.hraness-marketing-related__card:hover {
|
|
1406
|
-
|
|
1455
|
+
background-color: color-mix(in srgb, var(--hraness-marketing-related-tone, var(--hraness-marketing-ink)) 6%, transparent);
|
|
1407
1456
|
}
|
|
1408
1457
|
|
|
1409
1458
|
.hraness-marketing-related__card:focus-visible {
|
|
1410
|
-
outline: 2px solid var(--hraness-marketing-
|
|
1411
|
-
outline-offset: 2px;
|
|
1459
|
+
outline: 2px solid var(--hraness-marketing-ink);
|
|
1460
|
+
outline-offset: -2px;
|
|
1412
1461
|
}
|
|
1413
1462
|
|
|
1414
1463
|
.hraness-marketing-related__card-mark {
|
|
1464
|
+
--hraness-foil-text-base: var(--hraness-marketing-related-tone, var(--hraness-marketing-ink));
|
|
1465
|
+
color: var(--hraness-marketing-related-tone, var(--hraness-marketing-ink));
|
|
1466
|
+
flex-grow: 0;
|
|
1467
|
+
flex-shrink: 0;
|
|
1468
|
+
flex-basis: auto;
|
|
1415
1469
|
display: inline-flex;
|
|
1416
|
-
flex: 0 0 auto;
|
|
1417
1470
|
align-items: center;
|
|
1418
1471
|
justify-content: center;
|
|
1419
|
-
inline-size:
|
|
1420
|
-
block-size:
|
|
1472
|
+
inline-size: 1.75rem;
|
|
1473
|
+
block-size: 1.75rem;
|
|
1474
|
+
margin-block-start: 0.1rem;
|
|
1421
1475
|
}
|
|
1422
1476
|
|
|
1423
1477
|
.hraness-marketing-related__card-text {
|
|
1424
1478
|
display: grid;
|
|
1425
|
-
gap: 0.
|
|
1479
|
+
gap: 0.05rem;
|
|
1426
1480
|
min-inline-size: 0;
|
|
1427
1481
|
}
|
|
1428
1482
|
|
|
1483
|
+
.hraness-marketing-related__card-heading {
|
|
1484
|
+
display: flex;
|
|
1485
|
+
flex-wrap: wrap;
|
|
1486
|
+
align-items: baseline;
|
|
1487
|
+
column-gap: 0.6rem;
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1429
1490
|
.hraness-marketing-related__card-name {
|
|
1430
1491
|
margin: 0;
|
|
1431
1492
|
color: var(--hraness-marketing-ink);
|
|
1432
1493
|
font-family: var(--hraness-marketing-text-font);
|
|
1433
|
-
font-size: 1.
|
|
1434
|
-
font-weight:
|
|
1494
|
+
font-size: 1.0625rem;
|
|
1495
|
+
font-weight: 600;
|
|
1435
1496
|
letter-spacing: -0.01em;
|
|
1436
|
-
line-height: 1.
|
|
1497
|
+
line-height: 1.35;
|
|
1498
|
+
overflow-wrap: anywhere;
|
|
1499
|
+
text-decoration-line: underline;
|
|
1500
|
+
text-decoration-style: dotted;
|
|
1501
|
+
text-decoration-color: color-mix(in srgb, currentColor 40%, transparent);
|
|
1502
|
+
text-decoration-thickness: 1px;
|
|
1503
|
+
text-underline-offset: 0.2em;
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
.hraness-marketing-related__card-domain {
|
|
1507
|
+
color: var(--hraness-marketing-muted);
|
|
1508
|
+
font-family: var(--hraness-marketing-text-font);
|
|
1509
|
+
font-size: 0.8125rem;
|
|
1510
|
+
font-weight: 400;
|
|
1511
|
+
line-height: 1.5;
|
|
1437
1512
|
overflow-wrap: anywhere;
|
|
1438
1513
|
}
|
|
1439
1514
|
|
|
1440
1515
|
.hraness-marketing-related__card-role {
|
|
1441
1516
|
margin: 0;
|
|
1442
|
-
color: var(--hraness-marketing-
|
|
1517
|
+
color: var(--hraness-marketing-muted);
|
|
1443
1518
|
font-family: var(--hraness-marketing-text-font);
|
|
1444
|
-
font-size:
|
|
1519
|
+
font-size: 0.9375rem;
|
|
1445
1520
|
line-height: 1.45;
|
|
1521
|
+
overflow-wrap: anywhere;
|
|
1446
1522
|
text-wrap: pretty;
|
|
1447
1523
|
}
|
|
1448
1524
|
|
|
1525
|
+
.hraness-marketing-related__group[data-tone="rose"] {
|
|
1526
|
+
--hraness-marketing-related-tone: var(--hraness-studio-rose);
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
.hraness-marketing-related__group[data-tone="indigo"] {
|
|
1530
|
+
--hraness-marketing-related-tone: var(--hraness-studio-indigo);
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
.hraness-marketing-related__group[data-tone="amber"] {
|
|
1534
|
+
--hraness-marketing-related-tone: var(--hraness-studio-amber);
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
.hraness-marketing-related__group[data-tone="emerald"] {
|
|
1538
|
+
--hraness-marketing-related-tone: var(--hraness-studio-emerald);
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
@media (forced-colors: active) {
|
|
1542
|
+
.hraness-marketing-related__group[data-tone] { --hraness-marketing-related-tone: CanvasText; }
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1449
1545
|
/* Primitives: numbered building blocks */
|
|
1450
1546
|
|
|
1451
1547
|
.hraness-marketing-primitives {
|
|
@@ -1513,11 +1609,13 @@ html:has(:is(.hraness-marketing-header, .hraness-marketing-header-surface):not([
|
|
|
1513
1609
|
|
|
1514
1610
|
.hraness-marketing-interface-grid,
|
|
1515
1611
|
.hraness-marketing-trust-grid {
|
|
1612
|
+
--hraness-marketing-grid-columns: initial;
|
|
1613
|
+
--_hraness-marketing-grid-track: max(16rem, calc((100% - (var(--hraness-marketing-grid-columns) - 1) * 1rem) / var(--hraness-marketing-grid-columns)));
|
|
1516
1614
|
display: grid;
|
|
1517
1615
|
align-items: stretch;
|
|
1518
1616
|
margin: 0;
|
|
1519
1617
|
gap: 1rem;
|
|
1520
|
-
grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
|
|
1618
|
+
grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--_hraness-marketing-grid-track, 16rem)), 1fr));
|
|
1521
1619
|
}
|
|
1522
1620
|
|
|
1523
1621
|
.hraness-marketing-interface-grid > *,
|
|
@@ -1718,7 +1816,7 @@ html:has(:is(.hraness-marketing-header, .hraness-marketing-header-surface):not([
|
|
|
1718
1816
|
}
|
|
1719
1817
|
|
|
1720
1818
|
.hraness-marketing-quote figcaption a:hover {
|
|
1721
|
-
text-decoration: underline;
|
|
1819
|
+
text-decoration-line: underline;
|
|
1722
1820
|
}
|
|
1723
1821
|
|
|
1724
1822
|
/* Pricing */
|
|
@@ -2124,7 +2222,6 @@ html:has(:is(.hraness-marketing-header, .hraness-marketing-header-surface):not([
|
|
|
2124
2222
|
.hraness-marketing-trust-item,
|
|
2125
2223
|
.hraness-marketing-card,
|
|
2126
2224
|
.hraness-marketing-card__art,
|
|
2127
|
-
.hraness-marketing-related__card,
|
|
2128
2225
|
.hraness-marketing-quote,
|
|
2129
2226
|
.hraness-marketing-plan {
|
|
2130
2227
|
border: 1px solid CanvasText;
|
package/src/react/article.tsx
CHANGED
|
@@ -512,10 +512,10 @@ export type ComparisonRow = Readonly<{
|
|
|
512
512
|
|
|
513
513
|
const COMPARISON_TEXT = { yes: "Yes", no: "No", partial: "Partly" } as const;
|
|
514
514
|
|
|
515
|
-
function ComparisonGlyph({ kind }: Readonly<{ kind: "yes" | "no" | "partial" }>) {
|
|
515
|
+
export function ComparisonGlyph({ kind, className }: Readonly<{ kind: "yes" | "no" | "partial"; className?: string }>) {
|
|
516
516
|
const path = kind === "yes" ? "M3.5 8.5l3 3 6-7" : kind === "no" ? "M4.5 4.5l7 7m0-7l-7 7" : "M4 8h8";
|
|
517
517
|
return (
|
|
518
|
-
<svg aria-hidden="true" className="plain-publication__comparison-glyph" focusable="false" height="16" viewBox="0 0 16 16" width="16">
|
|
518
|
+
<svg aria-hidden="true" className={joinClasses("plain-publication__comparison-glyph", className)} focusable="false" height="16" viewBox="0 0 16 16" width="16">
|
|
519
519
|
<path d={path} fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="1.75" />
|
|
520
520
|
</svg>
|
|
521
521
|
);
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
+
import { MarketingAccount, MarketingAccountActions } from "./marketing-account.js";
|
|
4
|
+
import { MarketingComparison } from "./marketing-comparison.js";
|
|
5
|
+
import { MarketingDiagram, DiagramArrowhead } from "./marketing-diagram.js";
|
|
3
6
|
import {
|
|
4
7
|
Badge,
|
|
5
8
|
Button,
|
|
@@ -343,6 +346,7 @@ export function DesignSystemGallery({
|
|
|
343
346
|
/>
|
|
344
347
|
<MarketingPillars
|
|
345
348
|
ariaLabel="Relay in three points"
|
|
349
|
+
presentation="benefits"
|
|
346
350
|
columns={3}
|
|
347
351
|
pillars={[
|
|
348
352
|
{ label: "No hosted service", summary: "Jobs run on your machine and never wait on a server." },
|
|
@@ -436,7 +440,7 @@ export function DesignSystemGallery({
|
|
|
436
440
|
<MarketingSectionLabel size="body">Reference</MarketingSectionLabel>
|
|
437
441
|
<p>Consumer-owned content can include <a href="#gallery-install">links</a> and <code>inline code</code>.</p>
|
|
438
442
|
</MarketingSection>
|
|
439
|
-
<MarketingInterfaceGrid heading="Choose your interface." headingId="gallery-marketing-interfaces" headingLevel={3} label="Interfaces" interfaces={[
|
|
443
|
+
<MarketingInterfaceGrid columns={2} heading="Choose your interface." headingId="gallery-marketing-interfaces" headingLevel={3} label="Interfaces" interfaces={[
|
|
440
444
|
{ label: "CLI", summary: "Run a named job.", example: <MarketingCodeBlock code="relay run job-01" /> },
|
|
441
445
|
{ label: "SDK", summary: "Use typed application code." },
|
|
442
446
|
]} />
|
|
@@ -444,7 +448,7 @@ export function DesignSystemGallery({
|
|
|
444
448
|
{ art: <svg aria-hidden="true" viewBox="0 0 24 24" width="24" height="24"><circle cx="12" cy="12" r="8" /></svg>, href: "#marketing", title: "Grok 4.7", meta: "First observed 21 September 2026." },
|
|
445
449
|
{ art: <svg aria-hidden="true" viewBox="0 0 24 24" width="24" height="24"><rect x="4" y="4" width="16" height="16" rx="4" /></svg>, href: "#gallery-install", title: "GLM 5.3 Flash", meta: "First observed 26 August 2026. Early DeepSWE coverage on OpenRouter." },
|
|
446
450
|
]} />
|
|
447
|
-
<MarketingTrustBoundary heading="What leaves your machine." headingId="gallery-marketing-trust" headingLevel={3} label="Boundary" items={[
|
|
451
|
+
<MarketingTrustBoundary columns={2} heading="What leaves your machine." headingId="gallery-marketing-trust" headingLevel={3} label="Boundary" items={[
|
|
448
452
|
{ label: "Stays local", detail: "Source files and credentials." },
|
|
449
453
|
{ label: "Shared", detail: "Only the logs you choose to sync." },
|
|
450
454
|
]} />
|
|
@@ -520,42 +524,67 @@ export function DesignSystemGallery({
|
|
|
520
524
|
]}
|
|
521
525
|
/>
|
|
522
526
|
<MarketingRelated
|
|
527
|
+
columns={2}
|
|
523
528
|
groups={[
|
|
524
529
|
{
|
|
525
|
-
heading: "
|
|
530
|
+
heading: "Relationships",
|
|
531
|
+
tone: "rose",
|
|
526
532
|
headingId: "design-gallery-related-tools",
|
|
527
533
|
items: [
|
|
528
534
|
{
|
|
529
535
|
href: "#gallery-install",
|
|
530
536
|
name: "Ledger",
|
|
537
|
+
domain: "ledger.example",
|
|
531
538
|
role: "Long-term storage for run logs",
|
|
532
539
|
},
|
|
533
540
|
{
|
|
534
541
|
href: "#marketing",
|
|
535
542
|
name: "Index",
|
|
543
|
+
domain: "index.example",
|
|
536
544
|
role: "A local search index",
|
|
537
545
|
},
|
|
538
546
|
],
|
|
539
547
|
},
|
|
540
548
|
{
|
|
541
|
-
|
|
549
|
+
columns: 1,
|
|
550
|
+
heading: "Knowledge",
|
|
551
|
+
tone: "indigo",
|
|
542
552
|
headingId: "design-gallery-related-infra",
|
|
543
553
|
items: [
|
|
544
554
|
{
|
|
545
555
|
href: "#marketing",
|
|
546
556
|
name: "Relay",
|
|
557
|
+
domain: "relay.example",
|
|
547
558
|
role: "The shared job runner",
|
|
548
559
|
},
|
|
549
560
|
],
|
|
550
|
-
summary: "The runner the other tools depend on.",
|
|
551
561
|
},
|
|
552
562
|
]}
|
|
553
|
-
heading="
|
|
563
|
+
heading="Other tools from our studio"
|
|
554
564
|
headingId="design-gallery-related-title"
|
|
555
565
|
headingLevel={3}
|
|
556
|
-
label="Related"
|
|
557
|
-
summary="Each is a separate release. Its card says how it works with Relay."
|
|
558
566
|
/>
|
|
567
|
+
<MarketingDiagram width={720} height={216} label="Your sources stay on your device; your chosen agent reads the local workspace.">
|
|
568
|
+
<defs><DiagramArrowhead id="gallery-diagram-arrow" /></defs>
|
|
569
|
+
<rect className="hraness-diagram__node" x={24} y={40} width={276} height={136} rx={12} />
|
|
570
|
+
<rect className="hraness-diagram__node" x={420} y={40} width={276} height={136} rx={12} />
|
|
571
|
+
<path className="hraness-diagram__icon" d="M48 66h18v14H48z M53 84h8 M57 80v4" />
|
|
572
|
+
<text className="hraness-diagram__label" x={48} y={116}>Your sources</text>
|
|
573
|
+
<text className="hraness-diagram__detail" x={48} y={143}>Stored on your device</text>
|
|
574
|
+
<path className="hraness-diagram__connector" d="M320 108H400" markerEnd="url(#gallery-diagram-arrow)" />
|
|
575
|
+
<path className="hraness-diagram__icon" d="M444 73h18 M453 64v18 M447 67l12 12 M459 67l-12 12" />
|
|
576
|
+
<text className="hraness-diagram__label" x={444} y={116}>Your chosen agent</text>
|
|
577
|
+
<text className="hraness-diagram__detail" x={444} y={143}>Reads the local workspace</text>
|
|
578
|
+
</MarketingDiagram>
|
|
579
|
+
<MarketingComparison caption="Choose where your work lives" options={[{ name: "Relay" }, { name: "Hosted workspace" }]} highlight={0} rows={[
|
|
580
|
+
{ label: "Works offline", values: [true, false] },
|
|
581
|
+
{ label: "Bring your model", values: [true, { status: "optional", label: "On some plans" }] },
|
|
582
|
+
{ label: "Local storage", values: [true, { status: "depends", detail: "Check the provider's export format." }] },
|
|
583
|
+
{ label: "Cost", values: ["Free locally", "Subscription"] },
|
|
584
|
+
]} note="An illustrative comparison. Product pages supply current facts and sources." />
|
|
585
|
+
<MarketingAccount id="gallery-account" summary="Keep your preferences and shared work together.">
|
|
586
|
+
<MarketingAccountActions primary={{ href: "#gallery-account", label: "Create account" }} signIn={{ href: "#gallery-account" }} />
|
|
587
|
+
</MarketingAccount>
|
|
559
588
|
<MarketingMaker
|
|
560
589
|
heading="Who builds Relay"
|
|
561
590
|
headingId="design-gallery-maker-title"
|
package/src/react/index.ts
CHANGED
|
@@ -26,6 +26,8 @@ export * from "./procedural-recipe.js";
|
|
|
26
26
|
export * from "./relative-time.js";
|
|
27
27
|
export * from "./production-data-preview-notice.js";
|
|
28
28
|
export * from "./product-marketing.js";
|
|
29
|
+
export * from "./marketing-account.js";
|
|
30
|
+
export * from "./marketing-comparison.js";
|
|
29
31
|
export * from "./route-state.js";
|
|
30
32
|
export * from "./sticky-offset.js";
|
|
31
33
|
export * from "./surfaces.js";
|
|
@@ -37,3 +39,4 @@ export * from "./launch-beats.js";
|
|
|
37
39
|
export * from "./social-kit-panel.js";
|
|
38
40
|
export * from "./platform-icons.js";
|
|
39
41
|
export * from "./platform-install.js";
|
|
42
|
+
export * from "./marketing-diagram.js";
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import * as stylex from "@stylexjs/stylex";
|
|
2
|
+
|
|
3
|
+
export const marketingAccountStyles = stylex.create({
|
|
4
|
+
section: {
|
|
5
|
+
alignItems: "center",
|
|
6
|
+
"border-top": "var(--hraness-marketing-rule, 1px solid var(--line))",
|
|
7
|
+
color: "var(--foreground)",
|
|
8
|
+
display: "grid",
|
|
9
|
+
gap: "2rem 4rem",
|
|
10
|
+
gridTemplateColumns: { default: "minmax(0, 1fr)", "@media (min-width: 50rem)": "minmax(0, 1fr) minmax(0, 1fr)" },
|
|
11
|
+
paddingBlock: "clamp(2.5rem, 6vw, 4rem)",
|
|
12
|
+
scrollMarginTop: "calc(var(--hraness-sticky-offset, 5rem) + 2rem)",
|
|
13
|
+
},
|
|
14
|
+
copy: { minWidth: 0 },
|
|
15
|
+
heading: {
|
|
16
|
+
fontFamily: "var(--font-text)",
|
|
17
|
+
fontSize: "clamp(1.625rem, 1.3rem + 1vw, 2.25rem)",
|
|
18
|
+
fontWeight: 550,
|
|
19
|
+
letterSpacing: "-0.02em",
|
|
20
|
+
lineHeight: 1.15,
|
|
21
|
+
margin: 0,
|
|
22
|
+
textWrap: "balance",
|
|
23
|
+
},
|
|
24
|
+
summary: {
|
|
25
|
+
color: "var(--muted)",
|
|
26
|
+
fontSize: "1rem",
|
|
27
|
+
lineHeight: 1.6,
|
|
28
|
+
marginTop: "1rem",
|
|
29
|
+
maxWidth: "42ch",
|
|
30
|
+
textWrap: "pretty",
|
|
31
|
+
},
|
|
32
|
+
content: { minWidth: 0 },
|
|
33
|
+
actions: { alignItems: "center", display: "flex", flexWrap: "wrap", gap: "0.75rem 1.5rem" },
|
|
34
|
+
primary: {
|
|
35
|
+
alignItems: "center",
|
|
36
|
+
backgroundColor: { default: "var(--primary)", ":hover": "color-mix(in oklch, var(--primary) 88%, var(--foreground))", "@media (forced-colors: active)": "ButtonFace" },
|
|
37
|
+
borderWidth: "1px",
|
|
38
|
+
borderStyle: "solid",
|
|
39
|
+
borderColor: { default: "transparent", "@media (forced-colors: active)": "ButtonText" },
|
|
40
|
+
borderRadius: "0.625rem",
|
|
41
|
+
color: { default: "var(--primary-foreground)", "@media (forced-colors: active)": "ButtonText" },
|
|
42
|
+
display: "inline-flex",
|
|
43
|
+
fontFamily: "var(--font-text)",
|
|
44
|
+
fontSize: "1.0625rem",
|
|
45
|
+
fontWeight: 550,
|
|
46
|
+
justifyContent: "center",
|
|
47
|
+
lineHeight: 1.3,
|
|
48
|
+
maxWidth: "100%",
|
|
49
|
+
minHeight: "3.5rem",
|
|
50
|
+
outline: { default: null, ":focus-visible": "2px solid var(--primary)" },
|
|
51
|
+
outlineOffset: { default: null, ":focus-visible": "3px" },
|
|
52
|
+
paddingBlock: "0.875rem",
|
|
53
|
+
paddingInline: "1.5rem",
|
|
54
|
+
textAlign: "center",
|
|
55
|
+
textDecoration: "none",
|
|
56
|
+
},
|
|
57
|
+
signIn: {
|
|
58
|
+
alignItems: "center",
|
|
59
|
+
color: "var(--foreground)",
|
|
60
|
+
display: "inline-flex",
|
|
61
|
+
fontFamily: "var(--font-text)",
|
|
62
|
+
fontSize: "1.0625rem",
|
|
63
|
+
fontWeight: 450,
|
|
64
|
+
lineHeight: 1.3,
|
|
65
|
+
minHeight: "3.5rem",
|
|
66
|
+
outline: { default: null, ":focus-visible": "2px solid var(--primary)" },
|
|
67
|
+
outlineOffset: { default: null, ":focus-visible": "3px" },
|
|
68
|
+
textDecorationLine: "underline",
|
|
69
|
+
textDecorationStyle: "dotted",
|
|
70
|
+
textDecorationColor: { default: "color-mix(in srgb, currentColor 45%, transparent)", ":hover": "currentColor", "@media (forced-colors: active)": "LinkText" },
|
|
71
|
+
textDecorationThickness: "1px",
|
|
72
|
+
textUnderlineOffset: "0.22em",
|
|
73
|
+
},
|
|
74
|
+
});
|