@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.
- package/MISSING_COMPONENTS.md +109 -0
- package/README.md +171 -0
- package/package.json +59 -0
- package/src/components/AgentTrace/AgentTrace.jsx +128 -0
- package/src/components/AgentTrace/AgentTrace.module.css +115 -0
- package/src/components/AppMock/AppMock.jsx +86 -0
- package/src/components/AppMock/AppMock.module.css +629 -0
- package/src/components/AppMock/variants/DeciDeskMock.jsx +71 -0
- package/src/components/AppMock/variants/DocuDeskMock.jsx +69 -0
- package/src/components/AppMock/variants/LarpingAppMock.jsx +59 -0
- package/src/components/AppMock/variants/MyDashBiMock.jsx +135 -0
- package/src/components/AppMock/variants/MyDashMock.jsx +96 -0
- package/src/components/AppMock/variants/MyDashTilesMock.jsx +103 -0
- package/src/components/AppMock/variants/MyDashWidgetsMock.jsx +123 -0
- package/src/components/AppMock/variants/NLDesignMock.jsx +70 -0
- package/src/components/AppMock/variants/OpenCatalogiMock.jsx +61 -0
- package/src/components/AppMock/variants/OpenConnectorMock.jsx +83 -0
- package/src/components/AppMock/variants/OpenRegisterMock.jsx +100 -0
- package/src/components/AppMock/variants/OpenWooMock.jsx +61 -0
- package/src/components/AppMock/variants/PipelinQMock.jsx +88 -0
- package/src/components/AppMock/variants/ProcestMock.jsx +87 -0
- package/src/components/AppMock/variants/SoftwareCatalogMock.jsx +71 -0
- package/src/components/AppMock/variants/ZaakAfhandelAppMock.jsx +71 -0
- package/src/components/AppsGrid/AppsGrid.jsx +84 -0
- package/src/components/AppsGrid/AppsGrid.module.css +46 -0
- package/src/components/AppsPreview/AppsPreview.jsx +85 -0
- package/src/components/AppsPreview/AppsPreview.module.css +128 -0
- package/src/components/Clients/Clients.jsx +205 -0
- package/src/components/Clients/Clients.module.css +166 -0
- package/src/components/ComposeBlock/ComposeBlock.jsx +70 -0
- package/src/components/ComposeBlock/ComposeBlock.module.css +74 -0
- package/src/components/ConductionBg/ConductionBg.jsx +150 -0
- package/src/components/ConductionBg/ConductionBg.module.css +41 -0
- package/src/components/ContentCard/ContentCard.jsx +126 -0
- package/src/components/ContentCard/ContentCard.module.css +84 -0
- package/src/components/ContentDetailHero/ContentDetailHero.jsx +136 -0
- package/src/components/ContentDetailHero/ContentDetailHero.module.css +96 -0
- package/src/components/ContentTypeFilter/ContentTypeFilter.jsx +103 -0
- package/src/components/ContentTypeFilter/ContentTypeFilter.module.css +60 -0
- package/src/components/ContentTypeFilter/contentTypes.js +58 -0
- package/src/components/CookieCli/CookieCli.jsx +223 -0
- package/src/components/CookieCli/CookieCli.module.css +166 -0
- package/src/components/CtaBanner/CtaBanner.jsx +61 -0
- package/src/components/CtaBanner/CtaBanner.module.css +65 -0
- package/src/components/DetailHero/DetailHero.jsx +143 -0
- package/src/components/DetailHero/DetailHero.module.css +154 -0
- package/src/components/Diagrams/Diagrams.jsx +148 -0
- package/src/components/EmployeeCard/EmployeeCard.jsx +127 -0
- package/src/components/EmployeeCard/EmployeeCard.module.css +144 -0
- package/src/components/ExternalAppShelf/ExternalAppShelf.jsx +61 -0
- package/src/components/ExternalAppShelf/ExternalAppShelf.module.css +90 -0
- package/src/components/FAQ/FAQ.jsx +42 -0
- package/src/components/FAQ/FAQ.module.css +74 -0
- package/src/components/FacetedFilters/FacetedFilters.jsx +125 -0
- package/src/components/FacetedFilters/FacetedFilters.module.css +133 -0
- package/src/components/FeatureGrid/FeatureGrid.jsx +94 -0
- package/src/components/FeatureGrid/FeatureGrid.module.css +114 -0
- package/src/components/FeatureList/FeatureList.jsx +54 -0
- package/src/components/FeatureList/FeatureList.module.css +52 -0
- package/src/components/FeaturedCard/FeaturedCard.jsx +101 -0
- package/src/components/FeaturedCard/FeaturedCard.module.css +98 -0
- package/src/components/GameModal/GameModal.jsx +197 -0
- package/src/components/GameModal/GameModal.module.css +184 -0
- package/src/components/Hero/Hero.jsx +101 -0
- package/src/components/Hero/Hero.module.css +95 -0
- package/src/components/HexBackground/HexBackground.jsx +56 -0
- package/src/components/HexBackground/HexBackground.module.css +73 -0
- package/src/components/HexNetwork/HexNetwork.jsx +141 -0
- package/src/components/HexNetwork/HexNetwork.module.css +187 -0
- package/src/components/HexRain/HexRain.jsx +81 -0
- package/src/components/HowSteps/HowSteps.jsx +57 -0
- package/src/components/HowSteps/HowSteps.module.css +52 -0
- package/src/components/ManagedCommonGround/ManagedCommonGround.jsx +78 -0
- package/src/components/ManagedCommonGround/ManagedCommonGround.module.css +16 -0
- package/src/components/NewsletterCta/NewsletterCta.jsx +83 -0
- package/src/components/NewsletterCta/NewsletterCta.module.css +103 -0
- package/src/components/PairCard/PairCard.jsx +58 -0
- package/src/components/PairCard/PairCard.module.css +54 -0
- package/src/components/PartnerCard/PartnerCard.jsx +130 -0
- package/src/components/PartnerCard/PartnerCard.module.css +198 -0
- package/src/components/PartnerDirectory/PartnerDirectory.jsx +122 -0
- package/src/components/PartnerDirectory/PartnerDirectory.module.css +25 -0
- package/src/components/PartnerSidecard/PartnerSidecard.jsx +116 -0
- package/src/components/PartnerSidecard/PartnerSidecard.module.css +185 -0
- package/src/components/Pipeline/Pipeline.jsx +198 -0
- package/src/components/Pipeline/Pipeline.module.css +206 -0
- package/src/components/PlatformDiagram/PlatformDiagram.jsx +110 -0
- package/src/components/PlatformOverview/PlatformOverview.jsx +68 -0
- package/src/components/PlatformOverview/PlatformOverview.module.css +71 -0
- package/src/components/ReferenceCard/ReferenceCard.jsx +44 -0
- package/src/components/ReferenceCard/ReferenceCard.module.css +57 -0
- package/src/components/RelatedPosts/RelatedPosts.jsx +58 -0
- package/src/components/RelatedPosts/RelatedPosts.module.css +51 -0
- package/src/components/RotatingCards/RotatingCards.jsx +98 -0
- package/src/components/RotatingCards/RotatingCards.module.css +153 -0
- package/src/components/Showcase/Showcase.jsx +129 -0
- package/src/components/Showcase/Showcase.module.css +168 -0
- package/src/components/SolutionCard/SolutionCard.jsx +83 -0
- package/src/components/SolutionCard/SolutionCard.module.css +99 -0
- package/src/components/StatsStrip/StatsStrip.jsx +38 -0
- package/src/components/StatsStrip/StatsStrip.module.css +53 -0
- package/src/components/WidgetShelf/WidgetShelf.jsx +67 -0
- package/src/components/WidgetShelf/WidgetShelf.module.css +73 -0
- package/src/components/index.js +96 -0
- package/src/components/primitives/AuthorByline.jsx +85 -0
- package/src/components/primitives/AuthorByline.module.css +57 -0
- package/src/components/primitives/BrandCitation.jsx +71 -0
- package/src/components/primitives/Button.jsx +46 -0
- package/src/components/primitives/Button.module.css +88 -0
- package/src/components/primitives/Card.jsx +42 -0
- package/src/components/primitives/Card.module.css +42 -0
- package/src/components/primitives/Eyebrow.jsx +37 -0
- package/src/components/primitives/Eyebrow.module.css +19 -0
- package/src/components/primitives/HexBullet.jsx +37 -0
- package/src/components/primitives/HexBullet.module.css +16 -0
- package/src/components/primitives/HexThumbnail.jsx +70 -0
- package/src/components/primitives/HexThumbnail.module.css +45 -0
- package/src/components/primitives/Pill.jsx +42 -0
- package/src/components/primitives/Pill.module.css +30 -0
- package/src/components/primitives/Section.jsx +51 -0
- package/src/components/primitives/Section.module.css +31 -0
- package/src/components/primitives/SectionHead.jsx +36 -0
- package/src/components/primitives/SectionHead.module.css +43 -0
- package/src/components/primitives/index.js +22 -0
- package/src/css/brand.css +158 -0
- package/src/css/tokens.css +12 -0
- package/src/data/app-downloads.js +42 -0
- package/src/diagrams/README.md +74 -0
- package/src/diagrams/cn-domain-tree.js +105 -0
- package/src/diagrams/cn-hex-prism.js +163 -0
- package/src/diagrams/cn-hex.js +181 -0
- package/src/diagrams/cn-honeycomb-bg.js +135 -0
- package/src/diagrams/cn-pipeline.js +150 -0
- package/src/diagrams/cn-platform.js +156 -0
- package/src/diagrams/cn-side-box.js +104 -0
- package/src/diagrams/index.js +28 -0
- package/src/index.js +183 -0
- package/src/theme/Footer/index.jsx +516 -0
- package/src/theme/MDXPage/index.jsx +134 -0
- package/src/theme/Navbar/index.jsx +120 -0
- package/src/theme/Navbar/styles.module.css +114 -0
- package/src/theme/brand.jsx +63 -0
- package/src/theme.js +45 -0
- package/src/utils/lazyScript.js +37 -0
- package/static/img/favicon.svg +14 -0
- package/static/img/honeycomb-scatter.svg +23 -0
- package/static/img/honeycomb-watermark.svg +108 -0
- package/static/img/logo-dark.svg +11 -0
- package/static/img/logo.svg +14 -0
- package/static/img/nextcloud-logo.svg +5 -0
- package/static/lib/canal-footer.css +418 -0
- package/static/lib/canal-footer.js +499 -0
- package/static/lib/clients-flow.js +317 -0
- package/static/lib/conduction-bg.css +50 -0
- package/static/lib/conduction-bg.js +122 -0
- package/static/lib/hex-rain.css +128 -0
- package/static/lib/hex-rain.js +284 -0
- package/static/lib/kade-cyclist.css +264 -0
- package/static/lib/kade-cyclist.js +420 -0
- package/static/lib/logo-memory.css +219 -0
- package/static/lib/logo-memory.js +540 -0
- package/static/lib/platform-diagram.css +458 -0
- package/static/lib/platform-diagram.js +414 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <DetailHero /> styles. Mirrors the .head pattern in preview/pages/
|
|
3
|
+
* app-detail.html, solution-page.html, partner-detail.html.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
.head {
|
|
7
|
+
max-width: 1280px;
|
|
8
|
+
margin: 0 auto;
|
|
9
|
+
padding: 24px 64px 56px;
|
|
10
|
+
font-family: var(--conduction-typography-font-family-body);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.crumb {
|
|
14
|
+
font-family: var(--conduction-typography-font-family-code);
|
|
15
|
+
font-size: 12px;
|
|
16
|
+
letter-spacing: 0.04em;
|
|
17
|
+
text-transform: uppercase;
|
|
18
|
+
color: var(--c-cobalt-400);
|
|
19
|
+
margin-bottom: 24px;
|
|
20
|
+
}
|
|
21
|
+
.crumb a { color: var(--c-cobalt-400); text-decoration: none; }
|
|
22
|
+
.crumb a:hover { color: var(--c-orange-knvb); }
|
|
23
|
+
.sep { margin: 0 8px; color: var(--c-cobalt-200); }
|
|
24
|
+
|
|
25
|
+
.headInner {
|
|
26
|
+
display: grid;
|
|
27
|
+
grid-template-columns: 1fr;
|
|
28
|
+
gap: 48px;
|
|
29
|
+
align-items: center;
|
|
30
|
+
}
|
|
31
|
+
.withIllustration .headInner {
|
|
32
|
+
grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
|
|
33
|
+
gap: 64px;
|
|
34
|
+
}
|
|
35
|
+
@media (max-width: 900px) {
|
|
36
|
+
.withIllustration .headInner { grid-template-columns: 1fr; }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.badgeRow {
|
|
40
|
+
display: flex;
|
|
41
|
+
gap: 16px;
|
|
42
|
+
align-items: center;
|
|
43
|
+
margin-bottom: 20px;
|
|
44
|
+
flex-wrap: wrap;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.badge {
|
|
48
|
+
display: inline-flex;
|
|
49
|
+
align-items: center;
|
|
50
|
+
gap: 6px;
|
|
51
|
+
font-family: var(--conduction-typography-font-family-code);
|
|
52
|
+
font-size: 11px;
|
|
53
|
+
letter-spacing: 0.08em;
|
|
54
|
+
text-transform: uppercase;
|
|
55
|
+
color: var(--c-cobalt-700);
|
|
56
|
+
}
|
|
57
|
+
.versionBadge { color: var(--c-cobalt-400); }
|
|
58
|
+
|
|
59
|
+
.downloadsBadge {
|
|
60
|
+
color: var(--c-blue-cobalt);
|
|
61
|
+
background: var(--c-cobalt-50);
|
|
62
|
+
border: 1px solid var(--c-cobalt-100);
|
|
63
|
+
border-radius: var(--radius-sm);
|
|
64
|
+
padding: 4px 10px;
|
|
65
|
+
letter-spacing: 0.04em;
|
|
66
|
+
}
|
|
67
|
+
.downloadIcon {
|
|
68
|
+
width: 12px;
|
|
69
|
+
height: 12px;
|
|
70
|
+
fill: none;
|
|
71
|
+
stroke: currentColor;
|
|
72
|
+
stroke-width: 2;
|
|
73
|
+
stroke-linecap: round;
|
|
74
|
+
stroke-linejoin: round;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.title {
|
|
78
|
+
font-size: 64px;
|
|
79
|
+
font-weight: 700;
|
|
80
|
+
letter-spacing: -0.025em;
|
|
81
|
+
line-height: 1.05;
|
|
82
|
+
margin: 0 0 20px;
|
|
83
|
+
color: var(--c-cobalt-900);
|
|
84
|
+
display: flex;
|
|
85
|
+
align-items: center;
|
|
86
|
+
gap: 22px;
|
|
87
|
+
flex-wrap: wrap;
|
|
88
|
+
}
|
|
89
|
+
@media (max-width: 1100px) { .title { font-size: 52px; } }
|
|
90
|
+
@media (max-width: 700px) { .title { font-size: 40px; gap: 14px; } }
|
|
91
|
+
.title :global(.next-blue) { color: var(--c-nextcloud-blue); }
|
|
92
|
+
.titleText { display: inline-block; }
|
|
93
|
+
|
|
94
|
+
/* Leading hex inline with the H1. Sized to roughly cap-height × 1.3
|
|
95
|
+
of the title so it reads as a typographic-scale mark, not a separate
|
|
96
|
+
illustration. */
|
|
97
|
+
.titleIcon {
|
|
98
|
+
display: inline-flex;
|
|
99
|
+
align-items: center;
|
|
100
|
+
justify-content: center;
|
|
101
|
+
width: 80px;
|
|
102
|
+
height: 92px;
|
|
103
|
+
clip-path: var(--hex-pointy-top);
|
|
104
|
+
background: var(--c-blue-cobalt);
|
|
105
|
+
color: white;
|
|
106
|
+
flex-shrink: 0;
|
|
107
|
+
}
|
|
108
|
+
.titleIcon svg {
|
|
109
|
+
width: 38px;
|
|
110
|
+
height: 38px;
|
|
111
|
+
stroke: currentColor;
|
|
112
|
+
stroke-width: 1.6;
|
|
113
|
+
fill: none;
|
|
114
|
+
stroke-linecap: round;
|
|
115
|
+
stroke-linejoin: round;
|
|
116
|
+
}
|
|
117
|
+
@media (max-width: 1100px) {
|
|
118
|
+
.titleIcon { width: 64px; height: 74px; }
|
|
119
|
+
.titleIcon svg { width: 30px; height: 30px; }
|
|
120
|
+
}
|
|
121
|
+
@media (max-width: 700px) {
|
|
122
|
+
.titleIcon { width: 48px; height: 55px; }
|
|
123
|
+
.titleIcon svg { width: 22px; height: 22px; }
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.tagline {
|
|
127
|
+
font-size: 22px;
|
|
128
|
+
line-height: 1.5;
|
|
129
|
+
color: var(--c-cobalt-700);
|
|
130
|
+
max-width: 60ch;
|
|
131
|
+
margin: 0 0 32px;
|
|
132
|
+
}
|
|
133
|
+
.tagline :global(.next-blue) { color: var(--c-nextcloud-blue); }
|
|
134
|
+
|
|
135
|
+
.actions {
|
|
136
|
+
display: flex;
|
|
137
|
+
gap: 14px;
|
|
138
|
+
align-items: center;
|
|
139
|
+
flex-wrap: wrap;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* Right-side illustration slot. Holds an <AppMock>, a custom JSX
|
|
143
|
+
diagram, or any other panel a page wants to show next to its
|
|
144
|
+
title. Sized to balance the left copy column without dominating. */
|
|
145
|
+
.illustration {
|
|
146
|
+
display: flex;
|
|
147
|
+
align-items: center;
|
|
148
|
+
justify-content: flex-end;
|
|
149
|
+
width: 100%;
|
|
150
|
+
}
|
|
151
|
+
.illustration > * { width: 100%; max-width: 560px; }
|
|
152
|
+
@media (max-width: 900px) {
|
|
153
|
+
.illustration { justify-content: flex-start; }
|
|
154
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin React wrappers for the framework-agnostic diagram web
|
|
3
|
+
* components in @conduction/diagrams: <cn-hex>, <cn-hex-prism>,
|
|
4
|
+
* <cn-platform>, <cn-domain-tree>, etc.
|
|
5
|
+
*
|
|
6
|
+
* Why React wrappers around already-working web components?
|
|
7
|
+
* - Type-checked prop names (no remembering "size" vs "scale")
|
|
8
|
+
* - Lazy-imports the runtime so MDX pages don't have to remember
|
|
9
|
+
* the @conduction/diagrams import in <Hero/>'s useEffect
|
|
10
|
+
* - Auto-conversion of camelCase props to dashed HTML attributes
|
|
11
|
+
* where needed (e.g. brandColor → brand-color)
|
|
12
|
+
*
|
|
13
|
+
* Slot-based content (icon, label, etc.) is passed through as
|
|
14
|
+
* children with `slot="..."` attributes, so callers compose like
|
|
15
|
+
* regular React components.
|
|
16
|
+
*
|
|
17
|
+
* Usage in MDX:
|
|
18
|
+
*
|
|
19
|
+
* import {Hex, HexPrism} from '@conduction/docusaurus-preset/components';
|
|
20
|
+
*
|
|
21
|
+
* <Hex color="cobalt" size="md" variant="solid">
|
|
22
|
+
* <span slot="kicker">DATA</span>
|
|
23
|
+
* OpenRegister
|
|
24
|
+
* </Hex>
|
|
25
|
+
*
|
|
26
|
+
* <HexPrism family="coral" size="lg" state="hover">
|
|
27
|
+
* <span slot="kicker">CATALOG</span>
|
|
28
|
+
* OpenCatalogi
|
|
29
|
+
* </HexPrism>
|
|
30
|
+
*
|
|
31
|
+
* The runtime is lazy-loaded once, then customElements.define guards
|
|
32
|
+
* keep subsequent imports a no-op. If the package isn't installed
|
|
33
|
+
* (non-Conduction sites), the import fails silently and the elements
|
|
34
|
+
* render as plain unknown HTML, which the browser tolerates.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
import React, {useEffect} from 'react';
|
|
38
|
+
import useIsBrowser from '@docusaurus/useIsBrowser';
|
|
39
|
+
|
|
40
|
+
let runtimeImported = false;
|
|
41
|
+
function ensureRuntime() {
|
|
42
|
+
if (typeof window === 'undefined' || runtimeImported) return;
|
|
43
|
+
runtimeImported = true;
|
|
44
|
+
import('../../diagrams/index.js').catch(() => {
|
|
45
|
+
/* Side-effect import that registers every <cn-*> custom element.
|
|
46
|
+
In rare environments where dynamic import fails (e.g. an old SSR
|
|
47
|
+
runtime), fall back to plain unknown-element rendering. */
|
|
48
|
+
runtimeImported = false;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* Lazy-runtime hook shared by every diagram wrapper. */
|
|
53
|
+
function useDiagramRuntime() {
|
|
54
|
+
const isBrowser = useIsBrowser();
|
|
55
|
+
useEffect(() => { if (isBrowser) ensureRuntime(); }, [isBrowser]);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* Strip undefined props before forwarding so we don't emit empty
|
|
59
|
+
attributes on the custom element. */
|
|
60
|
+
function attrs(obj) {
|
|
61
|
+
const out = {};
|
|
62
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
63
|
+
if (v === undefined || v === null || v === false) continue;
|
|
64
|
+
out[k] = v;
|
|
65
|
+
}
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* ============================================================
|
|
70
|
+
<Hex /> wraps <cn-hex>
|
|
71
|
+
Observed: color, size, variant, layout, interactive
|
|
72
|
+
============================================================ */
|
|
73
|
+
export function Hex({color, size, variant, layout, interactive, children, ...rest}) {
|
|
74
|
+
useDiagramRuntime();
|
|
75
|
+
return (
|
|
76
|
+
<cn-hex {...attrs({color, size, variant, layout, interactive: interactive ? '' : undefined})} {...rest}>
|
|
77
|
+
{children}
|
|
78
|
+
</cn-hex>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* ============================================================
|
|
83
|
+
<HexPrism /> wraps <cn-hex-prism>
|
|
84
|
+
Observed: family, size, state
|
|
85
|
+
============================================================ */
|
|
86
|
+
export function HexPrism({family, size, state, children, ...rest}) {
|
|
87
|
+
useDiagramRuntime();
|
|
88
|
+
return (
|
|
89
|
+
<cn-hex-prism {...attrs({family, size, state})} {...rest}>
|
|
90
|
+
{children}
|
|
91
|
+
</cn-hex-prism>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* ============================================================
|
|
96
|
+
<Platform /> wraps <cn-platform>
|
|
97
|
+
Slot-based: a centre apex + surrounding hexes/prisms as children.
|
|
98
|
+
Optional ground={true} adds the cobalt ground line. The component's
|
|
99
|
+
own attributes are loose; pass through verbatim.
|
|
100
|
+
============================================================ */
|
|
101
|
+
export function Platform({ground, children, ...rest}) {
|
|
102
|
+
useDiagramRuntime();
|
|
103
|
+
return (
|
|
104
|
+
<cn-platform {...attrs({ground: ground ? '' : undefined})} {...rest}>
|
|
105
|
+
{children}
|
|
106
|
+
</cn-platform>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* ============================================================
|
|
111
|
+
<DomainTree /> wraps <cn-domain-tree>
|
|
112
|
+
Pass children with slot="apex" / slot="branch" / slot="leaf" to
|
|
113
|
+
build the hierarchy.
|
|
114
|
+
============================================================ */
|
|
115
|
+
export function DomainTree({children, ...rest}) {
|
|
116
|
+
useDiagramRuntime();
|
|
117
|
+
return <cn-domain-tree {...rest}>{children}</cn-domain-tree>;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* ============================================================
|
|
121
|
+
<Pipeline /> wraps <cn-pipeline> (note: NOT the layout-grid
|
|
122
|
+
<Pipeline/> from components/Pipeline; this one is the SVG-driven
|
|
123
|
+
web-component version).
|
|
124
|
+
Re-exported as DiagramPipeline to avoid the name collision; if
|
|
125
|
+
you import it, alias on use.
|
|
126
|
+
============================================================ */
|
|
127
|
+
export function DiagramPipeline({children, ...rest}) {
|
|
128
|
+
useDiagramRuntime();
|
|
129
|
+
return <cn-pipeline {...rest}>{children}</cn-pipeline>;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/* ============================================================
|
|
133
|
+
<SideBox /> wraps <cn-side-box>
|
|
134
|
+
============================================================ */
|
|
135
|
+
export function SideBox({children, ...rest}) {
|
|
136
|
+
useDiagramRuntime();
|
|
137
|
+
return <cn-side-box {...rest}>{children}</cn-side-box>;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* ============================================================
|
|
141
|
+
<HoneycombBg /> wraps <cn-honeycomb-bg>
|
|
142
|
+
Honeycomb-pattern background as a web component (alongside the
|
|
143
|
+
React <ConductionBg/>; this one is for plain-HTML surfaces).
|
|
144
|
+
============================================================ */
|
|
145
|
+
export function HoneycombBg(props) {
|
|
146
|
+
useDiagramRuntime();
|
|
147
|
+
return <cn-honeycomb-bg {...props} />;
|
|
148
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <EmployeeCard /> + <TeamGrid />
|
|
3
|
+
*
|
|
4
|
+
* Person-card pattern from preview/components/employee-cards.html.
|
|
5
|
+
* Three variants:
|
|
6
|
+
* - compact: row card for dense team grids (avatar + name + role + links)
|
|
7
|
+
* - photo: centered photo card for /about (large hex avatar + bio + links)
|
|
8
|
+
* - detail: spotlight card with the cobalt-50 corner-hex for /about/team
|
|
9
|
+
*
|
|
10
|
+
* The avatar is a 44x50 (compact) or 72x83 (large) pointy-top hex.
|
|
11
|
+
* Pass `initials` for an avatar-fill, or `photo` for a photographed person.
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
*
|
|
15
|
+
* <TeamGrid columns={3}>
|
|
16
|
+
* <EmployeeCard
|
|
17
|
+
* variant="compact"
|
|
18
|
+
* name="Ruben van der Linde"
|
|
19
|
+
* role="Founder · Architect"
|
|
20
|
+
* initials="RV"
|
|
21
|
+
* avatarColor="var(--c-blue-cobalt)"
|
|
22
|
+
* links={[
|
|
23
|
+
* {label: 'email', href: 'mailto:ruben@conduction.nl', icon: 'mail'},
|
|
24
|
+
* {label: 'github', href: 'https://github.com/...', icon: 'github'},
|
|
25
|
+
* ]}
|
|
26
|
+
* />
|
|
27
|
+
* </TeamGrid>
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import React from 'react';
|
|
31
|
+
import styles from './EmployeeCard.module.css';
|
|
32
|
+
|
|
33
|
+
const ICONS = {
|
|
34
|
+
mail: <svg viewBox="0 0 24 24"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 7l9 6 9-6"/></svg>,
|
|
35
|
+
github: <svg viewBox="0 0 24 24"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>,
|
|
36
|
+
linkedin: <svg viewBox="0 0 24 24"><path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-4 0v7h-4v-7a6 6 0 0 1 6-6z"/><rect x="2" y="9" width="4" height="12"/><circle cx="4" cy="4" r="2"/></svg>,
|
|
37
|
+
phone: <svg viewBox="0 0 24 24"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.37 1.9.72 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.35 1.85.59 2.81.72A2 2 0 0 1 22 16.92z"/></svg>,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export function TeamGrid({columns = 3, children, className}) {
|
|
41
|
+
const composed = [styles.grid, styles['cols-' + columns], className].filter(Boolean).join(' ');
|
|
42
|
+
return <div className={composed}>{children}</div>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export default function EmployeeCard({
|
|
46
|
+
variant = 'compact',
|
|
47
|
+
name,
|
|
48
|
+
role,
|
|
49
|
+
initials,
|
|
50
|
+
photo,
|
|
51
|
+
avatarColor,
|
|
52
|
+
bio,
|
|
53
|
+
apps = [],
|
|
54
|
+
links = [],
|
|
55
|
+
className,
|
|
56
|
+
}) {
|
|
57
|
+
if (variant === 'photo') {
|
|
58
|
+
return (
|
|
59
|
+
<div className={[styles.cardPhoto, className].filter(Boolean).join(' ')}>
|
|
60
|
+
<div className={styles.avatarLarge} style={!photo ? {background: avatarColor || 'var(--c-blue-cobalt)'} : undefined}>
|
|
61
|
+
{photo ? <img src={photo} alt={name} /> : initials}
|
|
62
|
+
</div>
|
|
63
|
+
{name && <div className={styles.name}>{name}</div>}
|
|
64
|
+
{role && <div className={styles.role}>{role}</div>}
|
|
65
|
+
{bio && <p className={styles.bio}>{bio}</p>}
|
|
66
|
+
{links.length > 0 && (
|
|
67
|
+
<div className={styles.contacts}>
|
|
68
|
+
{links.map((l, i) => (
|
|
69
|
+
<a key={i} href={l.href} aria-label={l.label}>{ICONS[l.icon] || l.label}</a>
|
|
70
|
+
))}
|
|
71
|
+
</div>
|
|
72
|
+
)}
|
|
73
|
+
</div>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (variant === 'detail') {
|
|
78
|
+
return (
|
|
79
|
+
<div className={[styles.cardDetail, className].filter(Boolean).join(' ')}>
|
|
80
|
+
<div className={styles.avatarLarge} style={!photo ? {background: avatarColor || 'var(--c-blue-cobalt)'} : undefined}>
|
|
81
|
+
{photo ? <img src={photo} alt={name} /> : initials}
|
|
82
|
+
</div>
|
|
83
|
+
<div>
|
|
84
|
+
{name && <div className={styles.name}>{name}</div>}
|
|
85
|
+
{role && <div className={styles.role}>{role}</div>}
|
|
86
|
+
</div>
|
|
87
|
+
{bio && <p className={styles.bio}>{bio}</p>}
|
|
88
|
+
{apps.length > 0 && (
|
|
89
|
+
<div>
|
|
90
|
+
<div className={styles.appsLabel}>Apps I work on</div>
|
|
91
|
+
<div className={styles.appsList}>
|
|
92
|
+
{apps.map((a, i) => <span key={i} className={styles.appPill}>{a}</span>)}
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
)}
|
|
96
|
+
{links.length > 0 && (
|
|
97
|
+
<div className={styles.contactsInline}>
|
|
98
|
+
{links.map((l, i) => (
|
|
99
|
+
<a key={i} href={l.href}>{ICONS[l.icon]}{l.label}</a>
|
|
100
|
+
))}
|
|
101
|
+
</div>
|
|
102
|
+
)}
|
|
103
|
+
</div>
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/* default: compact */
|
|
108
|
+
const Tag = links.length > 0 && links[0].href ? 'a' : 'div';
|
|
109
|
+
return (
|
|
110
|
+
<Tag href={Tag === 'a' ? links[0].href : undefined} className={[styles.cardCompact, className].filter(Boolean).join(' ')}>
|
|
111
|
+
<div className={styles.avatar} style={!photo ? {background: avatarColor || 'var(--c-blue-cobalt)'} : undefined}>
|
|
112
|
+
{photo ? <img src={photo} alt={name} /> : initials}
|
|
113
|
+
</div>
|
|
114
|
+
<div className={styles.info}>
|
|
115
|
+
{name && <div className={styles.name}>{name}</div>}
|
|
116
|
+
{role && <div className={styles.role}>{role}</div>}
|
|
117
|
+
</div>
|
|
118
|
+
{links.length > 0 && (
|
|
119
|
+
<div className={styles.linksRow}>
|
|
120
|
+
{links.map((l, i) => (
|
|
121
|
+
<a key={i} href={l.href} aria-label={l.label}>{ICONS[l.icon]}</a>
|
|
122
|
+
))}
|
|
123
|
+
</div>
|
|
124
|
+
)}
|
|
125
|
+
</Tag>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <EmployeeCard /> styles. Mirrors employee-cards.css scoped per variant.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
.grid { display: grid; gap: 16px; font-family: var(--conduction-typography-font-family-body); }
|
|
6
|
+
.cols-2 { grid-template-columns: repeat(2, 1fr); }
|
|
7
|
+
.cols-3 { grid-template-columns: repeat(3, 1fr); }
|
|
8
|
+
.cols-4 { grid-template-columns: repeat(4, 1fr); }
|
|
9
|
+
@media (max-width: 900px) { .grid { grid-template-columns: 1fr; } }
|
|
10
|
+
|
|
11
|
+
/* avatar shapes shared across variants */
|
|
12
|
+
.avatar, .avatarLarge {
|
|
13
|
+
clip-path: var(--hex-pointy-top);
|
|
14
|
+
display: inline-flex;
|
|
15
|
+
align-items: center;
|
|
16
|
+
justify-content: center;
|
|
17
|
+
color: white;
|
|
18
|
+
font-weight: 700;
|
|
19
|
+
flex-shrink: 0;
|
|
20
|
+
letter-spacing: -0.01em;
|
|
21
|
+
overflow: hidden;
|
|
22
|
+
background: var(--c-blue-cobalt);
|
|
23
|
+
font-family: var(--conduction-typography-font-family-body);
|
|
24
|
+
}
|
|
25
|
+
.avatar { width: 44px; height: 50px; font-size: 16px; }
|
|
26
|
+
.avatarLarge { width: 72px; height: 83px; font-size: 24px; }
|
|
27
|
+
.avatar img, .avatarLarge img { width: 100%; height: 100%; object-fit: cover; display: block; }
|
|
28
|
+
|
|
29
|
+
/* Compact variant */
|
|
30
|
+
.cardCompact {
|
|
31
|
+
background: white;
|
|
32
|
+
border: 1px solid var(--c-cobalt-100);
|
|
33
|
+
border-radius: var(--radius-lg);
|
|
34
|
+
padding: 20px;
|
|
35
|
+
display: flex;
|
|
36
|
+
align-items: center;
|
|
37
|
+
gap: 14px;
|
|
38
|
+
box-shadow: var(--shadow-1);
|
|
39
|
+
transition: all 160ms ease;
|
|
40
|
+
text-decoration: none;
|
|
41
|
+
color: inherit;
|
|
42
|
+
}
|
|
43
|
+
.cardCompact:hover {
|
|
44
|
+
transform: translateY(-1px);
|
|
45
|
+
box-shadow: var(--shadow-2);
|
|
46
|
+
border-color: var(--c-cobalt-200);
|
|
47
|
+
text-decoration: none;
|
|
48
|
+
color: inherit;
|
|
49
|
+
}
|
|
50
|
+
.info { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
|
|
51
|
+
.name { font-size: 15px; font-weight: 600; color: var(--c-blue-cobalt); line-height: 1.2; }
|
|
52
|
+
.role { font-family: var(--conduction-typography-font-family-code); font-size: 11px; color: var(--c-cobalt-400); letter-spacing: 0.05em; }
|
|
53
|
+
.linksRow { display: flex; gap: 8px; flex-shrink: 0; }
|
|
54
|
+
.linksRow a {
|
|
55
|
+
width: 26px; height: 26px;
|
|
56
|
+
border-radius: var(--radius-sm);
|
|
57
|
+
background: var(--c-cobalt-50);
|
|
58
|
+
color: var(--c-cobalt-700);
|
|
59
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
60
|
+
transition: all 140ms ease;
|
|
61
|
+
}
|
|
62
|
+
.linksRow a:hover { background: var(--c-blue-cobalt); color: white; }
|
|
63
|
+
.linksRow svg { width: 13px; height: 13px; stroke: currentColor; strokeWidth: 2; fill: none; }
|
|
64
|
+
|
|
65
|
+
/* Photo variant */
|
|
66
|
+
.cardPhoto {
|
|
67
|
+
background: white;
|
|
68
|
+
border: 1px solid var(--c-cobalt-100);
|
|
69
|
+
border-radius: var(--radius-lg);
|
|
70
|
+
padding: 28px 24px;
|
|
71
|
+
display: flex;
|
|
72
|
+
flex-direction: column;
|
|
73
|
+
align-items: center;
|
|
74
|
+
text-align: center;
|
|
75
|
+
gap: 12px;
|
|
76
|
+
box-shadow: var(--shadow-1);
|
|
77
|
+
font-family: var(--conduction-typography-font-family-body);
|
|
78
|
+
}
|
|
79
|
+
.cardPhoto .name { font-size: 19px; font-weight: 700; color: var(--c-cobalt-900); }
|
|
80
|
+
.cardPhoto .role { font-size: 13px; color: var(--c-cobalt-700); font-family: var(--conduction-typography-font-family-body); letter-spacing: 0; max-width: 28ch; }
|
|
81
|
+
.bio { font-size: 14px; color: var(--c-cobalt-700); line-height: 1.6; margin: 8px 0 0; max-width: 36ch; }
|
|
82
|
+
|
|
83
|
+
.contacts { display: flex; gap: 10px; margin-top: 10px; }
|
|
84
|
+
.contacts a {
|
|
85
|
+
width: 32px; height: 32px;
|
|
86
|
+
border-radius: var(--radius-sm);
|
|
87
|
+
background: var(--c-cobalt-50);
|
|
88
|
+
color: var(--c-cobalt-700);
|
|
89
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
90
|
+
transition: all 140ms ease;
|
|
91
|
+
}
|
|
92
|
+
.contacts a:hover { background: var(--c-blue-cobalt); color: white; }
|
|
93
|
+
.contacts svg { width: 16px; height: 16px; stroke: currentColor; stroke-width: 2; fill: none; }
|
|
94
|
+
|
|
95
|
+
/* Detail variant */
|
|
96
|
+
.cardDetail {
|
|
97
|
+
background: white;
|
|
98
|
+
border: 1px solid var(--c-cobalt-100);
|
|
99
|
+
border-radius: var(--radius-lg);
|
|
100
|
+
padding: 32px;
|
|
101
|
+
box-shadow: var(--shadow-1);
|
|
102
|
+
display: flex;
|
|
103
|
+
flex-direction: column;
|
|
104
|
+
gap: 16px;
|
|
105
|
+
position: relative;
|
|
106
|
+
overflow: hidden;
|
|
107
|
+
font-family: var(--conduction-typography-font-family-body);
|
|
108
|
+
}
|
|
109
|
+
.cardDetail::before {
|
|
110
|
+
content: "";
|
|
111
|
+
position: absolute;
|
|
112
|
+
top: 0; right: 0;
|
|
113
|
+
width: 140px; height: 160px;
|
|
114
|
+
clip-path: var(--hex-pointy-top);
|
|
115
|
+
background: var(--c-cobalt-50);
|
|
116
|
+
transform: translate(40px, -50px);
|
|
117
|
+
z-index: 0;
|
|
118
|
+
}
|
|
119
|
+
.cardDetail > * { position: relative; z-index: 1; }
|
|
120
|
+
.cardDetail .name { font-size: 20px; font-weight: 700; color: var(--c-cobalt-900); }
|
|
121
|
+
.cardDetail .role { font-size: 13px; }
|
|
122
|
+
.appsLabel {
|
|
123
|
+
font-family: var(--conduction-typography-font-family-code);
|
|
124
|
+
font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
|
|
125
|
+
color: var(--c-cobalt-400);
|
|
126
|
+
margin-bottom: 8px;
|
|
127
|
+
}
|
|
128
|
+
.appsList { display: flex; gap: 6px; flex-wrap: wrap; }
|
|
129
|
+
.appPill {
|
|
130
|
+
background: var(--c-cobalt-50);
|
|
131
|
+
color: var(--c-cobalt-700);
|
|
132
|
+
padding: 4px 10px;
|
|
133
|
+
border-radius: var(--radius-pill);
|
|
134
|
+
font-size: 12px;
|
|
135
|
+
font-family: var(--conduction-typography-font-family-code);
|
|
136
|
+
}
|
|
137
|
+
.contactsInline { display: flex; flex-wrap: wrap; gap: 16px; }
|
|
138
|
+
.contactsInline a {
|
|
139
|
+
display: inline-flex; align-items: center; gap: 6px;
|
|
140
|
+
font-size: 13px; color: var(--c-cobalt-700);
|
|
141
|
+
text-decoration: none;
|
|
142
|
+
}
|
|
143
|
+
.contactsInline a:hover { color: var(--c-blue-cobalt); }
|
|
144
|
+
.contactsInline svg { width: 14px; height: 14px; stroke: currentColor; stroke-width: 2; fill: none; }
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <ExternalAppShelf />
|
|
3
|
+
*
|
|
4
|
+
* Card grid for external open-source apps that Conduction integrates
|
|
5
|
+
* into the Nextcloud workspace as ExApps. Each card carries the
|
|
6
|
+
* project's brand-coloured logo tile + name + a one-sentence
|
|
7
|
+
* description + an outbound link. Used on /connext to show the
|
|
8
|
+
* "we don't own these projects, we provide the interface" story.
|
|
9
|
+
*
|
|
10
|
+
* Usage in MDX:
|
|
11
|
+
*
|
|
12
|
+
* <ExternalAppShelf
|
|
13
|
+
* apps={[
|
|
14
|
+
* {
|
|
15
|
+
* name: 'OpenTalk',
|
|
16
|
+
* brandColor: '#00485C',
|
|
17
|
+
* desc: 'Open-source video conferencing.',
|
|
18
|
+
* href: 'https://opentalk.eu/',
|
|
19
|
+
* icon: <svg viewBox="0 0 24 24">...</svg>,
|
|
20
|
+
* },
|
|
21
|
+
* ...
|
|
22
|
+
* ]}
|
|
23
|
+
* />
|
|
24
|
+
*
|
|
25
|
+
* The grid is responsive (auto-fill, min 240px). Each card lifts on
|
|
26
|
+
* hover, the brand-colour wash on the icon tile bleeds slightly into
|
|
27
|
+
* the card on hover so the brand reads as the primary identifier.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import React from 'react';
|
|
31
|
+
import styles from './ExternalAppShelf.module.css';
|
|
32
|
+
|
|
33
|
+
export default function ExternalAppShelf({apps = [], className}) {
|
|
34
|
+
return (
|
|
35
|
+
<div className={[styles.shelf, className].filter(Boolean).join(' ')}>
|
|
36
|
+
{apps.map((app, i) => {
|
|
37
|
+
const Tag = app.href ? 'a' : 'div';
|
|
38
|
+
const linkProps = app.href
|
|
39
|
+
? {href: app.href, target: '_blank', rel: 'noopener noreferrer'}
|
|
40
|
+
: {};
|
|
41
|
+
return (
|
|
42
|
+
<Tag
|
|
43
|
+
key={i}
|
|
44
|
+
className={[styles.card, app.href && styles.linked].filter(Boolean).join(' ')}
|
|
45
|
+
{...linkProps}
|
|
46
|
+
>
|
|
47
|
+
<div className={styles.iconTile} style={{background: app.brandColor || 'var(--c-cobalt-700)'}}>
|
|
48
|
+
<span className={styles.icon} aria-hidden="true">{app.icon}</span>
|
|
49
|
+
</div>
|
|
50
|
+
<div className={styles.body}>
|
|
51
|
+
<h3 className={styles.name}>{app.name}</h3>
|
|
52
|
+
{app.meta && <span className={styles.meta}>{app.meta}</span>}
|
|
53
|
+
{app.desc && <p className={styles.desc}>{app.desc}</p>}
|
|
54
|
+
</div>
|
|
55
|
+
{app.href && <span className={styles.arrow} aria-hidden="true">↗</span>}
|
|
56
|
+
</Tag>
|
|
57
|
+
);
|
|
58
|
+
})}
|
|
59
|
+
</div>
|
|
60
|
+
);
|
|
61
|
+
}
|