@conduction/docusaurus-preset 0.1.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 (163) hide show
  1. package/MISSING_COMPONENTS.md +109 -0
  2. package/README.md +171 -0
  3. package/package.json +59 -0
  4. package/src/components/AgentTrace/AgentTrace.jsx +128 -0
  5. package/src/components/AgentTrace/AgentTrace.module.css +115 -0
  6. package/src/components/AppMock/AppMock.jsx +86 -0
  7. package/src/components/AppMock/AppMock.module.css +629 -0
  8. package/src/components/AppMock/variants/DeciDeskMock.jsx +71 -0
  9. package/src/components/AppMock/variants/DocuDeskMock.jsx +69 -0
  10. package/src/components/AppMock/variants/LarpingAppMock.jsx +59 -0
  11. package/src/components/AppMock/variants/MyDashBiMock.jsx +135 -0
  12. package/src/components/AppMock/variants/MyDashMock.jsx +96 -0
  13. package/src/components/AppMock/variants/MyDashTilesMock.jsx +103 -0
  14. package/src/components/AppMock/variants/MyDashWidgetsMock.jsx +123 -0
  15. package/src/components/AppMock/variants/NLDesignMock.jsx +70 -0
  16. package/src/components/AppMock/variants/OpenCatalogiMock.jsx +61 -0
  17. package/src/components/AppMock/variants/OpenConnectorMock.jsx +83 -0
  18. package/src/components/AppMock/variants/OpenRegisterMock.jsx +100 -0
  19. package/src/components/AppMock/variants/OpenWooMock.jsx +61 -0
  20. package/src/components/AppMock/variants/PipelinQMock.jsx +88 -0
  21. package/src/components/AppMock/variants/ProcestMock.jsx +87 -0
  22. package/src/components/AppMock/variants/SoftwareCatalogMock.jsx +71 -0
  23. package/src/components/AppMock/variants/ZaakAfhandelAppMock.jsx +71 -0
  24. package/src/components/AppsGrid/AppsGrid.jsx +84 -0
  25. package/src/components/AppsGrid/AppsGrid.module.css +46 -0
  26. package/src/components/AppsPreview/AppsPreview.jsx +85 -0
  27. package/src/components/AppsPreview/AppsPreview.module.css +128 -0
  28. package/src/components/Clients/Clients.jsx +205 -0
  29. package/src/components/Clients/Clients.module.css +166 -0
  30. package/src/components/ComposeBlock/ComposeBlock.jsx +70 -0
  31. package/src/components/ComposeBlock/ComposeBlock.module.css +74 -0
  32. package/src/components/ConductionBg/ConductionBg.jsx +150 -0
  33. package/src/components/ConductionBg/ConductionBg.module.css +41 -0
  34. package/src/components/ContentCard/ContentCard.jsx +126 -0
  35. package/src/components/ContentCard/ContentCard.module.css +84 -0
  36. package/src/components/ContentDetailHero/ContentDetailHero.jsx +136 -0
  37. package/src/components/ContentDetailHero/ContentDetailHero.module.css +96 -0
  38. package/src/components/ContentTypeFilter/ContentTypeFilter.jsx +103 -0
  39. package/src/components/ContentTypeFilter/ContentTypeFilter.module.css +60 -0
  40. package/src/components/ContentTypeFilter/contentTypes.js +58 -0
  41. package/src/components/CookieCli/CookieCli.jsx +223 -0
  42. package/src/components/CookieCli/CookieCli.module.css +166 -0
  43. package/src/components/CtaBanner/CtaBanner.jsx +61 -0
  44. package/src/components/CtaBanner/CtaBanner.module.css +65 -0
  45. package/src/components/DetailHero/DetailHero.jsx +143 -0
  46. package/src/components/DetailHero/DetailHero.module.css +154 -0
  47. package/src/components/Diagrams/Diagrams.jsx +148 -0
  48. package/src/components/EmployeeCard/EmployeeCard.jsx +127 -0
  49. package/src/components/EmployeeCard/EmployeeCard.module.css +144 -0
  50. package/src/components/ExternalAppShelf/ExternalAppShelf.jsx +61 -0
  51. package/src/components/ExternalAppShelf/ExternalAppShelf.module.css +90 -0
  52. package/src/components/FAQ/FAQ.jsx +42 -0
  53. package/src/components/FAQ/FAQ.module.css +74 -0
  54. package/src/components/FacetedFilters/FacetedFilters.jsx +125 -0
  55. package/src/components/FacetedFilters/FacetedFilters.module.css +133 -0
  56. package/src/components/FeatureGrid/FeatureGrid.jsx +94 -0
  57. package/src/components/FeatureGrid/FeatureGrid.module.css +114 -0
  58. package/src/components/FeatureList/FeatureList.jsx +54 -0
  59. package/src/components/FeatureList/FeatureList.module.css +52 -0
  60. package/src/components/FeaturedCard/FeaturedCard.jsx +101 -0
  61. package/src/components/FeaturedCard/FeaturedCard.module.css +98 -0
  62. package/src/components/GameModal/GameModal.jsx +197 -0
  63. package/src/components/GameModal/GameModal.module.css +184 -0
  64. package/src/components/Hero/Hero.jsx +101 -0
  65. package/src/components/Hero/Hero.module.css +95 -0
  66. package/src/components/HexBackground/HexBackground.jsx +56 -0
  67. package/src/components/HexBackground/HexBackground.module.css +73 -0
  68. package/src/components/HexNetwork/HexNetwork.jsx +141 -0
  69. package/src/components/HexNetwork/HexNetwork.module.css +187 -0
  70. package/src/components/HexRain/HexRain.jsx +81 -0
  71. package/src/components/HowSteps/HowSteps.jsx +57 -0
  72. package/src/components/HowSteps/HowSteps.module.css +52 -0
  73. package/src/components/ManagedCommonGround/ManagedCommonGround.jsx +78 -0
  74. package/src/components/ManagedCommonGround/ManagedCommonGround.module.css +16 -0
  75. package/src/components/NewsletterCta/NewsletterCta.jsx +83 -0
  76. package/src/components/NewsletterCta/NewsletterCta.module.css +103 -0
  77. package/src/components/PairCard/PairCard.jsx +58 -0
  78. package/src/components/PairCard/PairCard.module.css +54 -0
  79. package/src/components/PartnerCard/PartnerCard.jsx +130 -0
  80. package/src/components/PartnerCard/PartnerCard.module.css +198 -0
  81. package/src/components/PartnerDirectory/PartnerDirectory.jsx +122 -0
  82. package/src/components/PartnerDirectory/PartnerDirectory.module.css +25 -0
  83. package/src/components/PartnerSidecard/PartnerSidecard.jsx +116 -0
  84. package/src/components/PartnerSidecard/PartnerSidecard.module.css +185 -0
  85. package/src/components/Pipeline/Pipeline.jsx +198 -0
  86. package/src/components/Pipeline/Pipeline.module.css +206 -0
  87. package/src/components/PlatformDiagram/PlatformDiagram.jsx +110 -0
  88. package/src/components/PlatformOverview/PlatformOverview.jsx +68 -0
  89. package/src/components/PlatformOverview/PlatformOverview.module.css +71 -0
  90. package/src/components/ReferenceCard/ReferenceCard.jsx +44 -0
  91. package/src/components/ReferenceCard/ReferenceCard.module.css +57 -0
  92. package/src/components/RelatedPosts/RelatedPosts.jsx +58 -0
  93. package/src/components/RelatedPosts/RelatedPosts.module.css +51 -0
  94. package/src/components/RotatingCards/RotatingCards.jsx +98 -0
  95. package/src/components/RotatingCards/RotatingCards.module.css +153 -0
  96. package/src/components/Showcase/Showcase.jsx +129 -0
  97. package/src/components/Showcase/Showcase.module.css +168 -0
  98. package/src/components/SolutionCard/SolutionCard.jsx +83 -0
  99. package/src/components/SolutionCard/SolutionCard.module.css +99 -0
  100. package/src/components/StatsStrip/StatsStrip.jsx +38 -0
  101. package/src/components/StatsStrip/StatsStrip.module.css +53 -0
  102. package/src/components/WidgetShelf/WidgetShelf.jsx +67 -0
  103. package/src/components/WidgetShelf/WidgetShelf.module.css +73 -0
  104. package/src/components/index.js +96 -0
  105. package/src/components/primitives/AuthorByline.jsx +85 -0
  106. package/src/components/primitives/AuthorByline.module.css +57 -0
  107. package/src/components/primitives/BrandCitation.jsx +71 -0
  108. package/src/components/primitives/Button.jsx +46 -0
  109. package/src/components/primitives/Button.module.css +88 -0
  110. package/src/components/primitives/Card.jsx +42 -0
  111. package/src/components/primitives/Card.module.css +42 -0
  112. package/src/components/primitives/Eyebrow.jsx +37 -0
  113. package/src/components/primitives/Eyebrow.module.css +19 -0
  114. package/src/components/primitives/HexBullet.jsx +37 -0
  115. package/src/components/primitives/HexBullet.module.css +16 -0
  116. package/src/components/primitives/HexThumbnail.jsx +70 -0
  117. package/src/components/primitives/HexThumbnail.module.css +45 -0
  118. package/src/components/primitives/Pill.jsx +42 -0
  119. package/src/components/primitives/Pill.module.css +30 -0
  120. package/src/components/primitives/Section.jsx +51 -0
  121. package/src/components/primitives/Section.module.css +31 -0
  122. package/src/components/primitives/SectionHead.jsx +36 -0
  123. package/src/components/primitives/SectionHead.module.css +43 -0
  124. package/src/components/primitives/index.js +22 -0
  125. package/src/css/brand.css +158 -0
  126. package/src/css/tokens.css +12 -0
  127. package/src/data/app-downloads.js +42 -0
  128. package/src/diagrams/README.md +74 -0
  129. package/src/diagrams/cn-domain-tree.js +105 -0
  130. package/src/diagrams/cn-hex-prism.js +163 -0
  131. package/src/diagrams/cn-hex.js +181 -0
  132. package/src/diagrams/cn-honeycomb-bg.js +135 -0
  133. package/src/diagrams/cn-pipeline.js +150 -0
  134. package/src/diagrams/cn-platform.js +156 -0
  135. package/src/diagrams/cn-side-box.js +104 -0
  136. package/src/diagrams/index.js +28 -0
  137. package/src/index.js +183 -0
  138. package/src/theme/Footer/index.jsx +516 -0
  139. package/src/theme/MDXPage/index.jsx +134 -0
  140. package/src/theme/Navbar/index.jsx +120 -0
  141. package/src/theme/Navbar/styles.module.css +114 -0
  142. package/src/theme/brand.jsx +63 -0
  143. package/src/theme.js +45 -0
  144. package/src/utils/lazyScript.js +37 -0
  145. package/static/img/favicon.svg +14 -0
  146. package/static/img/honeycomb-scatter.svg +23 -0
  147. package/static/img/honeycomb-watermark.svg +108 -0
  148. package/static/img/logo-dark.svg +11 -0
  149. package/static/img/logo.svg +14 -0
  150. package/static/img/nextcloud-logo.svg +5 -0
  151. package/static/lib/canal-footer.css +418 -0
  152. package/static/lib/canal-footer.js +499 -0
  153. package/static/lib/clients-flow.js +317 -0
  154. package/static/lib/conduction-bg.css +50 -0
  155. package/static/lib/conduction-bg.js +122 -0
  156. package/static/lib/hex-rain.css +128 -0
  157. package/static/lib/hex-rain.js +284 -0
  158. package/static/lib/kade-cyclist.css +264 -0
  159. package/static/lib/kade-cyclist.js +420 -0
  160. package/static/lib/logo-memory.css +219 -0
  161. package/static/lib/logo-memory.js +540 -0
  162. package/static/lib/platform-diagram.css +458 -0
  163. package/static/lib/platform-diagram.js +414 -0
@@ -0,0 +1,68 @@
1
+ /**
2
+ * <PlatformOverview />
3
+ *
4
+ * Section wrapper around the bespoke <platform-diagram> web component
5
+ * (workspace + corner-hex categories + flow lines). Renders the
6
+ * "section-head" pattern (eyebrow + h2 + lede) above the diagram.
7
+ *
8
+ * The platform-diagram custom element is registered by
9
+ * /lib/platform-diagram.js, which sites must include via <Head> on
10
+ * any page that uses this section. The CSS is similarly served from
11
+ * /lib/platform-diagram.css.
12
+ *
13
+ * Mirrors the .platform section in preview/pages/landing.html.
14
+ *
15
+ * Usage in MDX:
16
+ *
17
+ * import Head from '@docusaurus/Head';
18
+ * import {PlatformOverview} from '@conduction/docusaurus-preset/components';
19
+ *
20
+ * <Head>
21
+ * <link rel="stylesheet" href="/lib/platform-diagram.css" />
22
+ * <script src="/lib/platform-diagram.js" defer />
23
+ * </Head>
24
+ *
25
+ * <PlatformOverview
26
+ * eyebrow="The platform"
27
+ * title={<>Five components.<br/>Twenty-four apps. One <span className="next-blue">Nextcloud</span> workspace.</>}
28
+ * lede={<>...</>}
29
+ * >
30
+ * <platform-diagram>
31
+ * <pd-workspace logo="/img/nextcloud-logo.svg" alt="Nextcloud" role="Workspace" />
32
+ * <pd-list position="top" family="nextcloud">
33
+ * <pd-item name="Files" desc="...">
34
+ * <svg>...</svg>
35
+ * </pd-item>
36
+ * ...
37
+ * </pd-list>
38
+ * ...
39
+ * </platform-diagram>
40
+ * </PlatformOverview>
41
+ */
42
+
43
+ import React from 'react';
44
+ import styles from './PlatformOverview.module.css';
45
+
46
+ export default function PlatformOverview({eyebrow, title, lede, children}) {
47
+ return (
48
+ <section className={styles.section}>
49
+ <div className={styles.inner}>
50
+ {(eyebrow || title || lede) && (
51
+ <div className={styles.head}>
52
+ <div>
53
+ {eyebrow && (
54
+ <div className={styles.eyebrow}>
55
+ <span className={styles.eyebrowHex} aria-hidden="true"></span>
56
+ {eyebrow}
57
+ </div>
58
+ )}
59
+ {title && <h2 className={styles.title}>{title}</h2>}
60
+ </div>
61
+ {lede && <p className={styles.lede}>{lede}</p>}
62
+ </div>
63
+ )}
64
+ {children}
65
+ </div>
66
+ </section>
67
+ );
68
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * <PlatformOverview /> styles. Mirrors the .platform section from
3
+ * preview/pages/landing.html (section-head + platform-diagram).
4
+ */
5
+
6
+ .section {
7
+ background: white;
8
+ padding: 96px 64px;
9
+ font-family: var(--conduction-typography-font-family-body);
10
+ }
11
+ @media (max-width: 900px) {
12
+ .section { padding: 64px 24px; }
13
+ }
14
+
15
+ .inner {
16
+ max-width: 1280px;
17
+ margin: 0 auto;
18
+ }
19
+
20
+ .head {
21
+ display: grid;
22
+ grid-template-columns: 1.1fr 1fr;
23
+ gap: 48px;
24
+ align-items: end;
25
+ margin-bottom: 64px;
26
+ }
27
+ @media (max-width: 900px) {
28
+ .head { grid-template-columns: 1fr; gap: 24px; margin-bottom: 48px; }
29
+ }
30
+
31
+ .eyebrow {
32
+ display: inline-flex;
33
+ align-items: center;
34
+ gap: 10px;
35
+ font-family: var(--conduction-typography-font-family-code);
36
+ font-size: 12px;
37
+ letter-spacing: 0.1em;
38
+ text-transform: uppercase;
39
+ color: var(--c-cobalt-400);
40
+ margin-bottom: 16px;
41
+ }
42
+ .eyebrowHex {
43
+ width: 12px;
44
+ height: 14px;
45
+ clip-path: var(--hex-pointy-top);
46
+ background: var(--c-orange-knvb);
47
+ display: inline-block;
48
+ }
49
+
50
+ .title {
51
+ font-size: 44px;
52
+ font-weight: 700;
53
+ line-height: 1.05;
54
+ letter-spacing: -0.02em;
55
+ color: var(--c-blue-cobalt);
56
+ margin: 0;
57
+ max-width: 16ch;
58
+ }
59
+ @media (max-width: 700px) {
60
+ .title { font-size: 32px; }
61
+ }
62
+ .title :global(.next-blue) { color: var(--c-nextcloud-blue); }
63
+
64
+ .lede {
65
+ font-size: 16px;
66
+ line-height: 1.55;
67
+ color: var(--c-cobalt-700);
68
+ margin: 0;
69
+ max-width: 50ch;
70
+ }
71
+ .lede :global(.next-blue) { color: var(--c-nextcloud-blue); }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * <ReferenceCard /> + <ReferenceGrid />
3
+ *
4
+ * Customer-reference card from preview/components/reference-cards.html.
5
+ * Used on partner detail pages and the /references section.
6
+ *
7
+ * Visual structure:
8
+ * ┌─────────────────────────────┐
9
+ * │ [SECTOR-TAG] │
10
+ * │ Customer name │
11
+ * │ What we did paragraph │
12
+ * │ ────────── │
13
+ * │ ⬢ App ⬢ App ⬢ App │
14
+ * └─────────────────────────────┘
15
+ */
16
+
17
+ import React from 'react';
18
+ import HexBullet from '../primitives/HexBullet';
19
+ import styles from './ReferenceCard.module.css';
20
+
21
+ export function ReferenceGrid({columns = 3, children, className}) {
22
+ const composed = [styles.grid, styles['cols-' + columns], className].filter(Boolean).join(' ');
23
+ return <div className={composed}>{children}</div>;
24
+ }
25
+
26
+ export default function ReferenceCard({sector, name, what, stack = [], className}) {
27
+ return (
28
+ <div className={[styles.card, className].filter(Boolean).join(' ')}>
29
+ {sector && <span className={styles.sectorTag}>{sector}</span>}
30
+ {name && <h4 className={styles.name}>{name}</h4>}
31
+ {what && <p className={styles.what}>{what}</p>}
32
+ {stack.length > 0 && (
33
+ <div className={styles.stack}>
34
+ {stack.map((app, i) => (
35
+ <span key={i} className={styles.pill}>
36
+ <HexBullet size="sm" color="var(--c-blue-cobalt)" />
37
+ {app}
38
+ </span>
39
+ ))}
40
+ </div>
41
+ )}
42
+ </div>
43
+ );
44
+ }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * <ReferenceCard /> styles. Mirrors reference-cards.css exactly.
3
+ */
4
+
5
+ .grid { display: grid; gap: 16px; }
6
+ .cols-2 { grid-template-columns: repeat(2, 1fr); }
7
+ .cols-3 { grid-template-columns: repeat(3, 1fr); }
8
+ @media (max-width: 900px) { .grid { grid-template-columns: 1fr; } }
9
+
10
+ .card {
11
+ background: white;
12
+ border: 1px solid var(--c-cobalt-100);
13
+ border-radius: var(--radius-lg);
14
+ padding: 24px;
15
+ display: flex;
16
+ flex-direction: column;
17
+ gap: 12px;
18
+ font-family: var(--conduction-typography-font-family-body);
19
+ }
20
+
21
+ .sectorTag {
22
+ display: inline-flex;
23
+ align-items: center;
24
+ gap: 6px;
25
+ font-family: var(--conduction-typography-font-family-code);
26
+ font-size: 10px;
27
+ letter-spacing: 0.1em;
28
+ text-transform: uppercase;
29
+ color: var(--c-cobalt-700);
30
+ background: var(--c-cobalt-50);
31
+ padding: 4px 10px;
32
+ border-radius: var(--radius-pill);
33
+ align-self: flex-start;
34
+ }
35
+
36
+ .name { font-size: 17px; font-weight: 700; margin: 0; color: var(--c-cobalt-900); }
37
+ .what { font-size: 14px; color: var(--c-cobalt-700); line-height: 1.5; margin: 0; }
38
+
39
+ .stack {
40
+ display: flex;
41
+ gap: 6px;
42
+ flex-wrap: wrap;
43
+ padding-top: 10px;
44
+ border-top: 1px solid var(--c-cobalt-100);
45
+ }
46
+
47
+ .pill {
48
+ display: inline-flex;
49
+ align-items: center;
50
+ gap: 6px;
51
+ background: var(--c-cobalt-50);
52
+ color: var(--c-cobalt-700);
53
+ padding: 3px 9px;
54
+ border-radius: var(--radius-pill);
55
+ font-size: 11px;
56
+ font-family: var(--conduction-typography-font-family-code);
57
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * <RelatedPosts />
3
+ *
4
+ * Section block used at the bottom of every academy detail page (and
5
+ * sometimes on the landing) to surface a few more posts. A "Keep
6
+ * learning…" heading on the left, a "View all" pill link on the right,
7
+ * a content-card grid below.
8
+ *
9
+ * Mirrors the .related-posts section in preview/components/academy.html.
10
+ *
11
+ * Usage in MDX:
12
+ *
13
+ * <RelatedPosts
14
+ * title="Keep learning…"
15
+ * viewAllHref="/"
16
+ * viewAllLabel="View all"
17
+ * columns={2}
18
+ * >
19
+ * <ContentCard ... />
20
+ * <ContentCard ... />
21
+ * </RelatedPosts>
22
+ *
23
+ * Or, instead of children, pass `items` as an array of ContentCard
24
+ * props for a fully data-driven render.
25
+ */
26
+
27
+ import React from 'react';
28
+ import ContentCard, {ContentCardGrid} from '../ContentCard/ContentCard';
29
+ import styles from './RelatedPosts.module.css';
30
+
31
+ export default function RelatedPosts({
32
+ title = 'Keep learning…',
33
+ viewAllHref,
34
+ viewAllLabel = 'View all',
35
+ columns = 2,
36
+ items,
37
+ children,
38
+ className,
39
+ }) {
40
+ return (
41
+ <section className={[styles.section, className].filter(Boolean).join(' ')}>
42
+ <div className={styles.head}>
43
+ <h2 className={styles.title}>{title}</h2>
44
+ {viewAllHref && (
45
+ <a href={viewAllHref} className={styles.link}>
46
+ {viewAllLabel}
47
+ </a>
48
+ )}
49
+ </div>
50
+
51
+ <ContentCardGrid columns={columns}>
52
+ {items
53
+ ? items.map((it, i) => <ContentCard key={it.href || i} {...it} />)
54
+ : children}
55
+ </ContentCardGrid>
56
+ </section>
57
+ );
58
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * <RelatedPosts /> styles. Mirrors .related-posts in
3
+ * preview/components/academy.css.
4
+ */
5
+
6
+ .section {
7
+ display: flex;
8
+ flex-direction: column;
9
+ gap: var(--space-8);
10
+ font-family: var(--conduction-typography-font-family-body);
11
+ }
12
+
13
+ .head {
14
+ display: flex;
15
+ align-items: baseline;
16
+ justify-content: space-between;
17
+ gap: var(--space-6);
18
+ flex-wrap: wrap;
19
+ }
20
+
21
+ .title {
22
+ font-size: 36px;
23
+ font-weight: 700;
24
+ letter-spacing: -0.02em;
25
+ color: var(--c-cobalt-900);
26
+ margin: 0;
27
+ line-height: 1.1;
28
+ }
29
+ @media (max-width: 700px) { .title { font-size: 28px; } }
30
+
31
+ .link {
32
+ display: inline-flex;
33
+ align-items: center;
34
+ padding: 10px 22px;
35
+ background: var(--c-blue-cobalt);
36
+ color: white;
37
+ font-family: var(--conduction-typography-font-family-code);
38
+ font-size: 12px;
39
+ letter-spacing: 0.1em;
40
+ text-transform: uppercase;
41
+ font-weight: 600;
42
+ border-radius: var(--radius-pill);
43
+ text-decoration: none;
44
+ flex-shrink: 0;
45
+ transition: background 120ms ease;
46
+ }
47
+ .link:hover {
48
+ background: var(--c-cobalt-700);
49
+ text-decoration: none;
50
+ color: white;
51
+ }
@@ -0,0 +1,98 @@
1
+ /**
2
+ * <RotatingCards />
3
+ *
4
+ * Scroll-pinned stacked cards, after honeycomb.io home "What
5
+ * Honeycomb helps you do". Each card sticks to the top of the
6
+ * viewport as you scroll past, the next card slides up from below to
7
+ * cover it, so the surface advances by scrolling instead of by click
8
+ * or auto-rotation. No timer, no carousel, no pagination.
9
+ *
10
+ * Per-card layout:
11
+ * ┌────────────────────────────┬────────────────────────┐
12
+ * │ │ │
13
+ * │ [coloured panel] │ [white text panel] │
14
+ * │ │ │
15
+ * │ abstract product mock │ eyebrow │
16
+ * │ on a hex backdrop │ title │
17
+ * │ │ summary │
18
+ * │ │ cta │
19
+ * └────────────────────────────┴────────────────────────┘
20
+ *
21
+ * Each card carries a tone (mint, lavender, terracotta, forest,
22
+ * coral, workspace) that drives the coloured-panel side. The text
23
+ * side stays white throughout for legibility.
24
+ *
25
+ * Usage in MDX:
26
+ *
27
+ * <RotatingCards
28
+ * eyebrow="What Conduction helps you do"
29
+ * title="Six things, in two minutes."
30
+ * cards={[
31
+ * {
32
+ * tone: 'forest',
33
+ * eyebrow: 'See everything',
34
+ * title: 'Publish a public catalogue.',
35
+ * summary: '...',
36
+ * cta: {label: 'See OpenCatalogi', href: '/apps/opencatalogi'},
37
+ * panel: <AppMock app="opencatalogi" />,
38
+ * },
39
+ * ...
40
+ * ]}
41
+ * />
42
+ *
43
+ * Implementation note: each card is `position: sticky; top: <stagger>`,
44
+ * staggered so card N+1 ends up slightly above card N when both are
45
+ * pinned. The total scroll distance is sized by the wrapper's height
46
+ * (one viewport per card minus the stagger).
47
+ */
48
+
49
+ import React from 'react';
50
+ import HexBackground from '../HexBackground/HexBackground.jsx';
51
+ import styles from './RotatingCards.module.css';
52
+
53
+ export default function RotatingCards({
54
+ eyebrow,
55
+ title,
56
+ lede,
57
+ cards = [],
58
+ className,
59
+ }) {
60
+ if (cards.length === 0) return null;
61
+ return (
62
+ <section className={[styles.root, className].filter(Boolean).join(' ')}>
63
+ {(eyebrow || title || lede) && (
64
+ <header className={styles.head}>
65
+ {eyebrow && <div className={styles.eyebrow}><span className={styles.h}></span>{eyebrow}</div>}
66
+ {title && <h2 className={styles.title}>{title}</h2>}
67
+ {lede && <p className={styles.lede}>{lede}</p>}
68
+ </header>
69
+ )}
70
+ <div className={styles.stack} style={{'--stack-count': cards.length}}>
71
+ {cards.map((card, i) => (
72
+ <article
73
+ key={i}
74
+ className={[styles.card, styles[`tone-${card.tone || 'cobalt'}`]].join(' ')}
75
+ style={{'--i': i, top: `calc(var(--card-top, 80px) + ${i * 24}px)`}}
76
+ >
77
+ <div className={styles.cardImage}>
78
+ <HexBackground tone={`${card.tone || 'cobalt'}-100`} position="top" size="lg" density={2} />
79
+ <div className={styles.cardImageInner}>
80
+ {card.panel}
81
+ </div>
82
+ </div>
83
+ <div className={styles.cardText}>
84
+ {card.eyebrow && <div className={styles.cardEyebrow}>{card.eyebrow}</div>}
85
+ {card.title && <h3 className={styles.cardTitle}>{card.title}</h3>}
86
+ {card.summary && <p className={styles.cardSummary}>{card.summary}</p>}
87
+ {card.cta && (
88
+ <a href={card.cta.href} className={styles.cardCta}>
89
+ {card.cta.label}
90
+ </a>
91
+ )}
92
+ </div>
93
+ </article>
94
+ ))}
95
+ </div>
96
+ </section>
97
+ );
98
+ }
@@ -0,0 +1,153 @@
1
+ /**
2
+ * <RotatingCards /> styles. Scroll-pinned stacked cards.
3
+ *
4
+ * Each card is position: sticky and stays pinned at top: calc(...) as
5
+ * the viewport scrolls past it. Cards stagger by 24px each so that
6
+ * when card N is pinned and the user keeps scrolling, card N+1 slides
7
+ * up from below and ends 24px lower than card N — readable as a
8
+ * stack, not a swap.
9
+ */
10
+
11
+ .root {
12
+ max-width: 1280px;
13
+ margin: 0 auto;
14
+ padding: var(--space-12) var(--space-12);
15
+ font-family: var(--conduction-typography-font-family-body);
16
+ }
17
+
18
+ /* ---------- Header ---------- */
19
+ .head { max-width: 70ch; margin: 0 0 var(--space-8); }
20
+ .eyebrow {
21
+ display: inline-flex; align-items: center; gap: var(--space-2);
22
+ font-family: var(--conduction-typography-font-family-code);
23
+ font-size: 12px; letter-spacing: 0.1em; text-transform: uppercase;
24
+ color: var(--c-orange-knvb);
25
+ margin-bottom: var(--space-3);
26
+ }
27
+ .eyebrow .h { width: 10px; height: 12px; clip-path: var(--hex-pointy-top); background: var(--c-orange-knvb); }
28
+ .title {
29
+ font-size: 40px; font-weight: 700; letter-spacing: -0.02em;
30
+ line-height: 1.1; color: var(--c-cobalt-900); margin: 0 0 var(--space-3);
31
+ }
32
+ .lede { font-size: 17px; line-height: 1.5; color: var(--c-cobalt-700); margin: 0; }
33
+
34
+ /* ---------- The stack ---------- */
35
+ .stack {
36
+ display: flex;
37
+ flex-direction: column;
38
+ gap: 0;
39
+ }
40
+
41
+ .card {
42
+ position: sticky;
43
+ /* `top` is set inline as `calc(var(--card-top, 80px) + i * 24px)` so
44
+ each pinned card lands a little lower than the previous one. */
45
+ display: grid;
46
+ /* Image side leans wider so the AppMock has room to breathe;
47
+ text side stays narrower for a comfortable measure. The gap
48
+ between them shows the card's white background as a clean
49
+ gutter, so the coloured image panel and the white text panel
50
+ feel like two distinct planes instead of one fused block. */
51
+ grid-template-columns: 1.15fr 1fr;
52
+ gap: var(--space-8);
53
+ background: white;
54
+ border: 1px solid var(--c-cobalt-100);
55
+ border-radius: var(--radius-xl);
56
+ overflow: hidden;
57
+ box-shadow: var(--shadow-2);
58
+ margin-bottom: var(--space-4);
59
+ /* Each card needs at least one viewport-height of scroll room before
60
+ the next card can pin over it. min-height drives that. */
61
+ min-height: 480px;
62
+ }
63
+
64
+ @media (max-width: 900px) {
65
+ .card { grid-template-columns: 1fr; min-height: auto; }
66
+ }
67
+
68
+ /* ---------- Image side (coloured panel) — full-bleed to all edges
69
+ so the colour clearly demarcates the panel from the white text
70
+ side. The AppMock floats centred on the colour; padding lives on
71
+ the inner wrapper, not on the panel itself. ---------- */
72
+ .cardImage {
73
+ position: relative;
74
+ overflow: hidden;
75
+ display: flex;
76
+ align-items: center;
77
+ justify-content: center;
78
+ padding: 0;
79
+ min-height: 380px;
80
+ }
81
+ .cardImageInner {
82
+ position: relative;
83
+ z-index: 1;
84
+ width: 100%;
85
+ display: flex; align-items: center; justify-content: center;
86
+ padding: var(--space-8) var(--space-6);
87
+ }
88
+
89
+ /* Tone palettes — set the .cardImage background. */
90
+ .tone-mint .cardImage { background: var(--c-mint-100); }
91
+ .tone-mint .cardEyebrow,
92
+ .tone-mint .cardCta { color: var(--c-mint-700); }
93
+
94
+ .tone-lavender .cardImage { background: var(--c-lavender-100); }
95
+ .tone-lavender .cardEyebrow,
96
+ .tone-lavender .cardCta { color: var(--c-lavender-700); }
97
+
98
+ .tone-forest .cardImage { background: var(--c-forest-100); }
99
+ .tone-forest .cardEyebrow,
100
+ .tone-forest .cardCta { color: var(--c-forest-700); }
101
+
102
+ .tone-terracotta .cardImage { background: var(--c-terracotta-100); }
103
+ .tone-terracotta .cardEyebrow,
104
+ .tone-terracotta .cardCta { color: var(--c-terracotta-700); }
105
+
106
+ .tone-coral .cardImage { background: var(--c-coral-100); }
107
+ .tone-coral .cardEyebrow,
108
+ .tone-coral .cardCta { color: var(--c-coral-700); }
109
+
110
+ .tone-workspace .cardImage { background: var(--c-workspace-100); }
111
+ .tone-workspace .cardEyebrow,
112
+ .tone-workspace .cardCta { color: var(--c-cobalt-700); }
113
+
114
+ .tone-cobalt .cardImage { background: var(--c-cobalt-50); }
115
+ .tone-cobalt .cardEyebrow,
116
+ .tone-cobalt .cardCta { color: var(--c-blue-cobalt); }
117
+
118
+ /* ---------- Text side ---------- */
119
+ .cardText {
120
+ display: flex;
121
+ flex-direction: column;
122
+ gap: var(--space-4);
123
+ padding: var(--space-10) var(--space-9);
124
+ justify-content: center;
125
+ }
126
+
127
+ .cardEyebrow {
128
+ font-family: var(--conduction-typography-font-family-code);
129
+ font-size: 12px; letter-spacing: 0.1em; text-transform: uppercase;
130
+ font-weight: 600;
131
+ }
132
+ .cardTitle {
133
+ font-size: 32px; font-weight: 700; letter-spacing: -0.02em;
134
+ line-height: 1.15; color: var(--c-cobalt-900); margin: 0;
135
+ }
136
+ .cardSummary {
137
+ font-size: 17px; line-height: 1.55; color: var(--c-cobalt-700);
138
+ margin: 0;
139
+ }
140
+
141
+ .cardCta {
142
+ align-self: flex-start;
143
+ display: inline-flex; align-items: center;
144
+ background: var(--c-blue-cobalt); color: white !important;
145
+ padding: 10px 18px;
146
+ border-radius: var(--radius-md);
147
+ font-size: 13px; font-weight: 600; letter-spacing: 0.04em;
148
+ text-transform: uppercase;
149
+ text-decoration: none;
150
+ transition: background 160ms;
151
+ margin-top: var(--space-2);
152
+ }
153
+ .cardCta:hover { background: var(--c-cobalt-700); }