@conduction/docusaurus-preset 2.3.1 → 2.4.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/package.json +1 -1
- package/src/components/AppMock/AppMock.module.css +6 -0
- package/src/components/IntegrationIcon/IntegrationIcon.jsx +55 -0
- package/src/components/IntegrationIcon/IntegrationIcon.module.css +34 -0
- package/src/components/IntegrationIcon/registry.js +152 -0
- package/src/components/MockScene/MockScene.jsx +67 -0
- package/src/components/MockScene/MockScene.module.css +99 -0
- package/src/components/SidebarMock/SidebarMock.jsx +45 -31
package/package.json
CHANGED
|
@@ -184,6 +184,12 @@
|
|
|
184
184
|
.am .detail.rich .sb-tab .l { height: 3px; background: var(--c-cobalt-300); width: 24px; border-radius: 1px; }
|
|
185
185
|
.am .detail.rich .sb-tab.active .l { background: var(--c-cobalt-700); }
|
|
186
186
|
|
|
187
|
+
/* When a tab carries an <IntegrationIcon> instead of the default
|
|
188
|
+
.ico dot, tint it via currentColor so inactive tabs stay muted
|
|
189
|
+
(cobalt-300) and active tabs read in full cobalt-700. */
|
|
190
|
+
.am .detail.rich .sb-tab .ii { color: var(--c-cobalt-300); }
|
|
191
|
+
.am .detail.rich .sb-tab.active .ii { color: var(--c-cobalt-700); }
|
|
192
|
+
|
|
187
193
|
.am .detail.rich .sb-body { padding: 10px; display: flex; flex-direction: column; gap: 7px; overflow: hidden; }
|
|
188
194
|
.am .detail.rich .sb-label { height: 4px; background: var(--c-cobalt-700); width: 40%; border-radius: 1px; }
|
|
189
195
|
.am .detail.rich .sb-input { height: 14px; background: white; border: 1px solid var(--c-cobalt-200); border-radius: 3px; }
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <IntegrationIcon />
|
|
3
|
+
*
|
|
4
|
+
* Render a token-painted glyph for one of the integrations in the
|
|
5
|
+
* Conduction registry: Nextcloud-bundled apps (Mail, Calendar, Files,
|
|
6
|
+
* Talk, Decks, RSS, Activity), workflow tools (xWiki, n8n, Windmill,
|
|
7
|
+
* OpenProject, Keycloak), LLM providers (Claude, Mistral, Ollama,
|
|
8
|
+
* OpenAI, Gemini), and adjacent Conduction extensions (OpenTalk,
|
|
9
|
+
* Matrix, Mattermost, OpenExchange).
|
|
10
|
+
*
|
|
11
|
+
* The SVG content lives in registry.js as inline strings, mirroring
|
|
12
|
+
* the .svg files under brand/assets/integrations/. Both copies use
|
|
13
|
+
* `fill="currentColor"` (or stroke) so the icon tints to whatever
|
|
14
|
+
* `color` the parent CSS sets. That means a SidebarMock tab can
|
|
15
|
+
* render a coloured Mail icon when active and a muted Mail icon when
|
|
16
|
+
* inactive without swapping the SVG.
|
|
17
|
+
*
|
|
18
|
+
* Usage:
|
|
19
|
+
*
|
|
20
|
+
* <IntegrationIcon name="claude" /> // 16×16 default
|
|
21
|
+
* <IntegrationIcon name="xwiki" size="md" /> // 24×24
|
|
22
|
+
* <IntegrationIcon name="n8n" size="lg" /> // 40×40
|
|
23
|
+
*
|
|
24
|
+
* Props:
|
|
25
|
+
* - name: one of INTEGRATIONS keys (required)
|
|
26
|
+
* - size: 'xs' | 'sm' (default) | 'md' | 'lg' | 'xl'
|
|
27
|
+
* - title: aria-label override; defaults to registry label
|
|
28
|
+
* - className: string
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import React from 'react';
|
|
32
|
+
import styles from './IntegrationIcon.module.css';
|
|
33
|
+
import amStyles from '../AppMock/AppMock.module.css';
|
|
34
|
+
import { INTEGRATIONS } from './registry.js';
|
|
35
|
+
|
|
36
|
+
export default function IntegrationIcon({ name, size = 'sm', title, className }) {
|
|
37
|
+
const entry = INTEGRATIONS[name];
|
|
38
|
+
if (!entry) {
|
|
39
|
+
return (
|
|
40
|
+
<span
|
|
41
|
+
className={[amStyles.am, styles.ii, styles[size], className].filter(Boolean).join(' ')}
|
|
42
|
+
title={`Unknown integration: ${name}`}
|
|
43
|
+
aria-label={`Unknown integration: ${name}`}
|
|
44
|
+
/>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
return (
|
|
48
|
+
<span
|
|
49
|
+
className={[amStyles.am, styles.ii, styles[size], className].filter(Boolean).join(' ')}
|
|
50
|
+
role="img"
|
|
51
|
+
aria-label={title || entry.label}
|
|
52
|
+
dangerouslySetInnerHTML={{ __html: entry.svg }}
|
|
53
|
+
/>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <IntegrationIcon /> styles.
|
|
3
|
+
*
|
|
4
|
+
* The icon itself is a 24×24 viewBox SVG with `fill="currentColor"`,
|
|
5
|
+
* so it tints to whatever colour the parent CSS sets. The wrapper
|
|
6
|
+
* fixes the rendered box size and inherits the colour from context.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/* IntegrationIcon's root element carries `.am` itself so the rules
|
|
10
|
+
below use a compound selector (no descendant space). The .am scope
|
|
11
|
+
still namespaces the rule so plain `.ii` on a host page that does
|
|
12
|
+
not adopt the design system is unaffected. Sizes are compound for
|
|
13
|
+
the same reason. */
|
|
14
|
+
.am.ii {
|
|
15
|
+
display: inline-flex;
|
|
16
|
+
align-items: center;
|
|
17
|
+
justify-content: center;
|
|
18
|
+
flex-shrink: 0;
|
|
19
|
+
line-height: 0;
|
|
20
|
+
color: var(--c-cobalt-700);
|
|
21
|
+
}
|
|
22
|
+
.am.ii svg {
|
|
23
|
+
width: 100%;
|
|
24
|
+
height: 100%;
|
|
25
|
+
display: block;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* Sizes match the surfaces that consume the icon: tabs (xs), widget
|
|
29
|
+
headers (sm), gallery cards (md), hero scene (lg). */
|
|
30
|
+
.am.ii.xs { width: 12px; height: 12px; }
|
|
31
|
+
.am.ii.sm { width: 16px; height: 16px; }
|
|
32
|
+
.am.ii.md { width: 24px; height: 24px; }
|
|
33
|
+
.am.ii.lg { width: 40px; height: 40px; }
|
|
34
|
+
.am.ii.xl { width: 64px; height: 64px; }
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration icon registry.
|
|
3
|
+
*
|
|
4
|
+
* Each entry mirrors the SVG content of a file under
|
|
5
|
+
* brand/assets/integrations/{category}/{name}.svg. Runtime consumers
|
|
6
|
+
* (the React <IntegrationIcon /> component, build-kit kit pages,
|
|
7
|
+
* future SidebarMock tab labels) read inline strings from here so the
|
|
8
|
+
* icon can render with `currentColor` fill and tint to whatever
|
|
9
|
+
* colour the parent CSS sets. The .svg files in brand/ are the
|
|
10
|
+
* designer-readable copy; this file is the consumer copy. They
|
|
11
|
+
* stay manually in sync (each is one file, edits land in both).
|
|
12
|
+
*
|
|
13
|
+
* Categories:
|
|
14
|
+
* nextcloud-bundled — surfaces the Nextcloud workspace already
|
|
15
|
+
* ships (Mail, Calendar, Files, Talk, Decks, RSS, Activity).
|
|
16
|
+
* workflow — third-party workflow / wiki / SSO tools that
|
|
17
|
+
* Conduction integrates with (xWiki, n8n, Windmill, OpenProject,
|
|
18
|
+
* Keycloak).
|
|
19
|
+
* llm — large-language-model providers we consume via
|
|
20
|
+
* OpenConnector / DocuDesk (Claude, Mistral, Ollama, OpenAI,
|
|
21
|
+
* Gemini).
|
|
22
|
+
* conduction-ext — external apps in the Conduction Nextcloud
|
|
23
|
+
* ecosystem (OpenTalk, Matrix, Mattermost, OpenExchange).
|
|
24
|
+
*
|
|
25
|
+
* The icons themselves are simplified, monochromatic, representational
|
|
26
|
+
* marks in the Conduction visual style. They are NOT replacements for
|
|
27
|
+
* official brand marks; consumers that need the canonical logo of a
|
|
28
|
+
* third-party tool should use that tool's own asset.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
export const INTEGRATIONS = {
|
|
32
|
+
|
|
33
|
+
// ---- Nextcloud-bundled ----
|
|
34
|
+
'mail': {
|
|
35
|
+
category: 'nextcloud-bundled',
|
|
36
|
+
label: 'Mail',
|
|
37
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="6" width="18" height="13" rx="1.5"/><path d="M3.5 7.5l8.5 6 8.5-6"/></svg>',
|
|
38
|
+
},
|
|
39
|
+
'calendar': {
|
|
40
|
+
category: 'nextcloud-bundled',
|
|
41
|
+
label: 'Calendar',
|
|
42
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="5" width="18" height="16" rx="1.5"/><path d="M3 10h18M8 3v4M16 3v4"/><circle cx="12" cy="15" r="1.4" fill="currentColor" stroke="none"/></svg>',
|
|
43
|
+
},
|
|
44
|
+
'files': {
|
|
45
|
+
category: 'nextcloud-bundled',
|
|
46
|
+
label: 'Files',
|
|
47
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 7a2 2 0 0 1 2-2h4l2 2.5h8a2 2 0 0 1 2 2V18a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg>',
|
|
48
|
+
},
|
|
49
|
+
'talk': {
|
|
50
|
+
category: 'nextcloud-bundled',
|
|
51
|
+
label: 'Talk',
|
|
52
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 16V7a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H8l-4 3z"/></svg>',
|
|
53
|
+
},
|
|
54
|
+
'decks': {
|
|
55
|
+
category: 'nextcloud-bundled',
|
|
56
|
+
label: 'Decks',
|
|
57
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><rect x="3" y="4" width="5" height="16" rx="1"/><rect x="9.5" y="4" width="5" height="11" rx="1" opacity="0.7"/><rect x="16" y="4" width="5" height="7" rx="1" opacity="0.4"/></svg>',
|
|
58
|
+
},
|
|
59
|
+
'rss': {
|
|
60
|
+
category: 'nextcloud-bundled',
|
|
61
|
+
label: 'RSS',
|
|
62
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M5 5a14 14 0 0 1 14 14"/><path d="M5 11a8 8 0 0 1 8 8"/><circle cx="6" cy="18" r="2" fill="currentColor"/></svg>',
|
|
63
|
+
},
|
|
64
|
+
'activity': {
|
|
65
|
+
category: 'nextcloud-bundled',
|
|
66
|
+
label: 'Activity',
|
|
67
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h4l2.5-7 5 14L17 12h4"/></svg>',
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
// ---- Workflow / auth ----
|
|
71
|
+
'xwiki': {
|
|
72
|
+
category: 'workflow',
|
|
73
|
+
label: 'xWiki',
|
|
74
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M3 4h3.4L9 9.5 11.6 4H15l-4.4 8.5L15 21h-3.4L9 15.5 6.4 21H3l4.4-8.5z"/><rect x="16.5" y="4" width="1.6" height="17" opacity="0.55"/><rect x="19.4" y="4" width="1.6" height="17" opacity="0.35"/></svg>',
|
|
75
|
+
},
|
|
76
|
+
'n8n': {
|
|
77
|
+
category: 'workflow',
|
|
78
|
+
label: 'n8n',
|
|
79
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="6" cy="12" r="2.5"/><circle cx="18" cy="6" r="2.5"/><circle cx="18" cy="18" r="2.5"/><path d="M9 12h6M9 12l9-6M9 12l9 6" stroke="currentColor" stroke-width="2" fill="none"/></svg>',
|
|
80
|
+
},
|
|
81
|
+
'windmill': {
|
|
82
|
+
category: 'workflow',
|
|
83
|
+
label: 'Windmill',
|
|
84
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="12" cy="12" r="2"/><path d="M12 12L17 5L19 8L14 12zM12 12L19 17L16 19L12 14zM12 12L5 7L8 5L12 10z"/><path d="M11 14h2v8h-2z"/></svg>',
|
|
85
|
+
},
|
|
86
|
+
'openproject': {
|
|
87
|
+
category: 'workflow',
|
|
88
|
+
label: 'OpenProject',
|
|
89
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M19.35.37h-1.86a4.628 4.628 0 0 0-4.652 4.624v5.609H4.652A4.628 4.628 0 0 0 0 15.23v3.721c0 2.569 2.083 4.679 4.652 4.679h1.86c2.57 0 4.652-2.11 4.652-4.679v-3.72h-2.791v3.88c0 1.026-.835 1.886-1.861 1.886h-1.86c-1.027 0-1.861-.864-1.861-1.886V15.23a1.839 1.839 0 0 1 1.86-1.833h14.697c2.57 0 4.652-2.11 4.652-4.679V4.997A4.628 4.628 0 0 0 19.35.37z"/></svg>',
|
|
90
|
+
},
|
|
91
|
+
'keycloak': {
|
|
92
|
+
category: 'workflow',
|
|
93
|
+
label: 'Keycloak',
|
|
94
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="9" cy="12" r="4"/><circle cx="9" cy="12" r="1.4" fill="#fff"/><path d="M13 12h8M17 12v3M21 12v3" stroke="currentColor" stroke-width="2" fill="none"/></svg>',
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
// ---- LLMs ----
|
|
98
|
+
'claude': {
|
|
99
|
+
category: 'llm',
|
|
100
|
+
label: 'Claude',
|
|
101
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="12" cy="12" r="3.5"/><g stroke="currentColor" stroke-width="2" stroke-linecap="round" fill="none"><path d="M12 2v4"/><path d="M12 18v4"/><path d="M2 12h4"/><path d="M18 12h4"/><path d="M5.6 5.6l2.8 2.8"/><path d="M15.6 15.6l2.8 2.8"/><path d="M18.4 5.6l-2.8 2.8"/><path d="M8.4 15.6l-2.8 2.8"/></g></svg>',
|
|
102
|
+
},
|
|
103
|
+
'mistral': {
|
|
104
|
+
category: 'llm',
|
|
105
|
+
label: 'Mistral',
|
|
106
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><rect x="2" y="3" width="20" height="3" rx="0.5"/><rect x="2" y="8" width="14" height="3" rx="0.5" opacity="0.75"/><rect x="2" y="13" width="20" height="3" rx="0.5" opacity="0.6"/><rect x="2" y="18" width="14" height="3" rx="0.5" opacity="0.4"/></svg>',
|
|
107
|
+
},
|
|
108
|
+
'ollama': {
|
|
109
|
+
category: 'llm',
|
|
110
|
+
label: 'Ollama',
|
|
111
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><ellipse cx="9" cy="14" rx="5" ry="6"/><ellipse cx="14.5" cy="6" rx="2" ry="3"/><path d="M14 9l1.5 2.4 2.5-1z"/><circle cx="6.5" cy="13" r="0.9" fill="#fff"/></svg>',
|
|
112
|
+
},
|
|
113
|
+
'openai': {
|
|
114
|
+
category: 'llm',
|
|
115
|
+
label: 'OpenAI',
|
|
116
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" aria-hidden="true"><polygon points="12,3 21,8 21,16 12,21 3,16 3,8"/><polygon points="12,8 17,11 17,14 12,17 7,14 7,11" fill="currentColor" stroke="none"/></svg>',
|
|
117
|
+
},
|
|
118
|
+
'gemini': {
|
|
119
|
+
category: 'llm',
|
|
120
|
+
label: 'Gemini',
|
|
121
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2L8 8h8z"/><path d="M8 8L4 14l8 8 8-8-4-6z" opacity="0.7"/><circle cx="18.5" cy="4.5" r="1" opacity="0.6"/><circle cx="20" cy="7" r="0.6" opacity="0.4"/></svg>',
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
// ---- Conduction Nextcloud-extension apps ----
|
|
125
|
+
'opentalk': {
|
|
126
|
+
category: 'conduction-ext',
|
|
127
|
+
label: 'OpenTalk',
|
|
128
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="11" cy="12.5" r="7"/><circle cx="18.5" cy="6.5" r="2.5" fill="currentColor" stroke="none"/></svg>',
|
|
129
|
+
},
|
|
130
|
+
'matrix': {
|
|
131
|
+
category: 'conduction-ext',
|
|
132
|
+
label: 'Matrix',
|
|
133
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" stroke="none" aria-hidden="true"><path d="M.632.55v22.9H2.28V24H0V0h2.28v.55zm7.043 7.26v1.157h.033c.309-.443.683-.784 1.117-1.024.433-.245.936-.365 1.5-.365.54 0 1.033.107 1.481.314.448.208.785.582 1.02 1.108.254-.374.6-.706 1.034-.992.434-.287.95-.43 1.546-.43.453 0 .872.056 1.26.167.388.11.716.286.993.53.276.245.489.559.646.951.152.392.23.863.23 1.417v5.728h-2.349V11.52c0-.286-.01-.559-.032-.812a1.755 1.755 0 0 0-.18-.66 1.106 1.106 0 0 0-.438-.448c-.194-.11-.457-.166-.785-.166-.332 0-.6.064-.803.189a1.38 1.38 0 0 0-.48.499 1.946 1.946 0 0 0-.231.696 5.56 5.56 0 0 0-.06.785v4.768h-2.35v-4.8c0-.254-.004-.503-.018-.752a2.074 2.074 0 0 0-.143-.688 1.052 1.052 0 0 0-.415-.503c-.194-.125-.476-.19-.854-.19-.111 0-.259.024-.439.074-.18.051-.36.143-.53.282-.171.138-.319.337-.439.595-.12.259-.18.6-.18 1.02v4.966H5.46V7.81zm15.693 15.64V.55H21.72V0H24v24h-2.28v-.55z"/></svg>',
|
|
134
|
+
},
|
|
135
|
+
'mattermost': {
|
|
136
|
+
category: 'conduction-ext',
|
|
137
|
+
label: 'Mattermost',
|
|
138
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" stroke="none" aria-hidden="true"><path d="M12.081 0C7.048-.034 2.339 3.125.637 8.153c-2.125 6.276 1.24 13.086 7.516 15.21 6.276 2.125 13.086-1.24 15.21-7.516 1.727-5.1-.172-10.552-4.311-13.557l.126 2.547c2.065 2.282 2.88 5.512 1.852 8.549-1.534 4.532-6.594 6.915-11.3 5.321-4.708-1.593-7.28-6.559-5.745-11.092 1.031-3.046 3.655-5.121 6.694-5.67l1.642-1.94A4.87 4.87 0 0 0 12.08 0z"/></svg>',
|
|
139
|
+
},
|
|
140
|
+
'openexchange': {
|
|
141
|
+
category: 'conduction-ext',
|
|
142
|
+
label: 'OpenExchange',
|
|
143
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" aria-hidden="true"><circle cx="8.5" cy="12" r="5"/><path d="M14.5 7l6 10M14.5 17l6-10"/></svg>',
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export const INTEGRATION_CATEGORIES = {
|
|
148
|
+
'nextcloud-bundled': { label: 'Nextcloud bundled', desc: 'Surfaces every Nextcloud workspace already ships.' },
|
|
149
|
+
'workflow': { label: 'Workflow & auth', desc: 'Third-party tools we wire into Conduction apps via OpenConnector.' },
|
|
150
|
+
'llm': { label: 'LLM providers', desc: 'Models we call from OpenConnector and DocuDesk.' },
|
|
151
|
+
'conduction-ext': { label: 'Conduction extensions', desc: 'Adjacent apps in the Conduction Nextcloud ecosystem.' },
|
|
152
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <MockScene />
|
|
3
|
+
*
|
|
4
|
+
* Marketing-surface composition. A SidebarMock anchors the centre,
|
|
5
|
+
* three to five WidgetMocks float around it on a tinted cobalt-50
|
|
6
|
+
* surface with a soft hex-network watermark. Reach for this when a
|
|
7
|
+
* card or hero needs to show "data surfaced across the whole
|
|
8
|
+
* workspace": one sidebar + several widgets, each carrying a real
|
|
9
|
+
* integration icon, all lit on the same surface.
|
|
10
|
+
*
|
|
11
|
+
* Sibling to AppMock + WidgetMock + SidebarMock in the mock family.
|
|
12
|
+
* AppMock paints a single product surface with chassis chrome.
|
|
13
|
+
* WidgetMock paints a single dashboard tile. SidebarMock paints a
|
|
14
|
+
* single detail panel. MockScene paints the overlap.
|
|
15
|
+
*
|
|
16
|
+
* Usage:
|
|
17
|
+
*
|
|
18
|
+
* <MockScene
|
|
19
|
+
* sidebar={<SidebarMock kind="openregister-metadata" />}
|
|
20
|
+
* widgets={[
|
|
21
|
+
* { node: <WidgetMock kind="nextcloud-mail" />, pos: 'top-left' },
|
|
22
|
+
* { node: <WidgetMock kind="nextcloud-files" />, pos: 'top-right' },
|
|
23
|
+
* { node: <WidgetMock kind="openregister-activity" />, pos: 'bottom-right' },
|
|
24
|
+
* ]}
|
|
25
|
+
* />
|
|
26
|
+
*
|
|
27
|
+
* Each widget entry is { node, pos } where `pos` selects a corner of
|
|
28
|
+
* the stage:
|
|
29
|
+
* 'top-left' | 'top-right' |
|
|
30
|
+
* 'middle-left' | 'middle-right' |
|
|
31
|
+
* 'bottom-left' | 'bottom-right'
|
|
32
|
+
*
|
|
33
|
+
* Default rotations and offsets give each widget a slight tilt so
|
|
34
|
+
* the composition reads as playfully arranged rather than gridded.
|
|
35
|
+
*
|
|
36
|
+
* Props:
|
|
37
|
+
* - sidebar: ReactNode (typically <SidebarMock />)
|
|
38
|
+
* - widgets: Array<{node: ReactNode, pos: string}>
|
|
39
|
+
* - compact: boolean (default false) — tighter scene for use
|
|
40
|
+
* inside a card
|
|
41
|
+
* - className: string
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
import React from 'react';
|
|
45
|
+
import styles from './MockScene.module.css';
|
|
46
|
+
import amStyles from '../AppMock/AppMock.module.css';
|
|
47
|
+
|
|
48
|
+
export default function MockScene({ sidebar, widgets = [], compact = false, className }) {
|
|
49
|
+
return (
|
|
50
|
+
<div className={[amStyles.am, styles.scene, className].filter(Boolean).join(' ')}>
|
|
51
|
+
<div className={[styles.sceneFrame, compact && styles.compact].filter(Boolean).join(' ')}>
|
|
52
|
+
<div className={styles.sceneStage}>
|
|
53
|
+
{widgets.map((w, i) => (
|
|
54
|
+
<div key={i} className={styles.sceneFloat} data-pos={w.pos || 'top-left'}>
|
|
55
|
+
{w.node}
|
|
56
|
+
</div>
|
|
57
|
+
))}
|
|
58
|
+
{sidebar && (
|
|
59
|
+
<div className={styles.sceneCenter}>
|
|
60
|
+
{sidebar}
|
|
61
|
+
</div>
|
|
62
|
+
)}
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <MockScene /> styles.
|
|
3
|
+
*
|
|
4
|
+
* Marketing-surface composition. A single sidebar sits at the centre
|
|
5
|
+
* (slightly larger than its standalone size), with three to five
|
|
6
|
+
* widgets floating around it at staggered offsets and rotations.
|
|
7
|
+
* Background: a tinted cobalt-50 surface with a soft hex-network
|
|
8
|
+
* watermark, so the scene reads as "the workspace" without committing
|
|
9
|
+
* to a specific app frame.
|
|
10
|
+
*
|
|
11
|
+
* Use as the illustration on a card that talks about cross-cutting
|
|
12
|
+
* integration ("typed data, surfaced everywhere"; "every register,
|
|
13
|
+
* every workspace surface"). The scene is layout-only; the props pass
|
|
14
|
+
* through fully-formed SidebarMock + WidgetMock JSX.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
.am.scene { display: contents; }
|
|
18
|
+
|
|
19
|
+
.am .sceneFrame {
|
|
20
|
+
position: relative;
|
|
21
|
+
background: var(--c-cobalt-50);
|
|
22
|
+
border-radius: var(--radius-lg);
|
|
23
|
+
border: 1px solid var(--c-cobalt-100);
|
|
24
|
+
padding: var(--space-8);
|
|
25
|
+
min-height: 360px;
|
|
26
|
+
overflow: hidden;
|
|
27
|
+
isolation: isolate;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* Soft hex-network watermark using radial gradients on top of cobalt-50.
|
|
31
|
+
Cheap visual texture; no need to bring HexNetwork in for this. */
|
|
32
|
+
.am .sceneFrame::before {
|
|
33
|
+
content: "";
|
|
34
|
+
position: absolute;
|
|
35
|
+
inset: 0;
|
|
36
|
+
background-image:
|
|
37
|
+
radial-gradient(circle at 20% 25%, var(--c-cobalt-100) 0, transparent 35%),
|
|
38
|
+
radial-gradient(circle at 80% 70%, var(--c-cobalt-100) 0, transparent 35%),
|
|
39
|
+
radial-gradient(circle at 50% 90%, var(--c-cobalt-100) 0, transparent 30%);
|
|
40
|
+
opacity: 0.5;
|
|
41
|
+
pointer-events: none;
|
|
42
|
+
z-index: 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* Stage holds the sidebar at the centre and widgets at offsets.
|
|
46
|
+
position: relative so child position: absolute resolves here. */
|
|
47
|
+
.am .sceneStage {
|
|
48
|
+
position: relative;
|
|
49
|
+
display: flex;
|
|
50
|
+
align-items: center;
|
|
51
|
+
justify-content: center;
|
|
52
|
+
min-height: 360px;
|
|
53
|
+
z-index: 1;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* Centre sidebar: anchored, slightly enlarged, drop-shadow for lift. */
|
|
57
|
+
.am .sceneCenter {
|
|
58
|
+
position: relative;
|
|
59
|
+
z-index: 4;
|
|
60
|
+
filter: drop-shadow(0 16px 32px rgba(15, 35, 75, 0.2));
|
|
61
|
+
}
|
|
62
|
+
.am .sceneCenter > .am > .smFrame,
|
|
63
|
+
.am .sceneCenter > .smFrame {
|
|
64
|
+
width: 320px;
|
|
65
|
+
height: 440px;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* Floating widget wrappers. Each one positions absolutely relative
|
|
69
|
+
to .sceneStage; the data-pos attribute maps to a corner. */
|
|
70
|
+
.am .sceneFloat {
|
|
71
|
+
position: absolute;
|
|
72
|
+
z-index: 2;
|
|
73
|
+
filter: drop-shadow(0 12px 22px rgba(15, 35, 75, 0.15));
|
|
74
|
+
transition: transform 200ms;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.am .sceneFloat[data-pos="top-left"] { top: 0; left: 0; transform: rotate(-3deg); }
|
|
78
|
+
.am .sceneFloat[data-pos="top-right"] { top: 4%; right: 0; transform: rotate(2deg); }
|
|
79
|
+
.am .sceneFloat[data-pos="bottom-left"] { bottom: 0; left: 6%; transform: rotate(2deg); }
|
|
80
|
+
.am .sceneFloat[data-pos="bottom-right"] { bottom: 0; right: 0; transform: rotate(-2deg); }
|
|
81
|
+
.am .sceneFloat[data-pos="middle-left"] { top: 40%; left: 0; transform: translateY(-50%) rotate(-2deg); }
|
|
82
|
+
.am .sceneFloat[data-pos="middle-right"] { top: 40%; right: 0; transform: translateY(-50%) rotate(2deg); }
|
|
83
|
+
|
|
84
|
+
/* Widget frames inside floats: scale down a hair and drop their own
|
|
85
|
+
shadow so the float-level shadow does the heavy lifting. */
|
|
86
|
+
.am .sceneFloat .wmFrame {
|
|
87
|
+
box-shadow: none;
|
|
88
|
+
width: 240px;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* Tighter scenes for cards: pass `compact` to the component. */
|
|
92
|
+
.am .sceneFrame.compact {
|
|
93
|
+
padding: var(--space-6);
|
|
94
|
+
min-height: 300px;
|
|
95
|
+
}
|
|
96
|
+
.am .sceneFrame.compact .sceneStage { min-height: 300px; }
|
|
97
|
+
.am .sceneFrame.compact .sceneCenter > .am > .smFrame,
|
|
98
|
+
.am .sceneFrame.compact .sceneCenter > .smFrame { width: 260px; height: 360px; }
|
|
99
|
+
.am .sceneFrame.compact .sceneFloat .wmFrame { width: 200px; }
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
import React from 'react';
|
|
53
53
|
import styles from './SidebarMock.module.css';
|
|
54
54
|
import amStyles from '../AppMock/AppMock.module.css';
|
|
55
|
+
import IntegrationIcon from '../IntegrationIcon/IntegrationIcon.jsx';
|
|
55
56
|
|
|
56
57
|
import ProcestXWiki from './variants/ProcestXWiki.jsx';
|
|
57
58
|
import ProcestTimeline from './variants/ProcestTimeline.jsx';
|
|
@@ -71,89 +72,98 @@ import NextcloudActivity from './variants/NextcloudActivity.jsx';
|
|
|
71
72
|
* decorative (rendered as a placeholder bar in .sb-tab .l)
|
|
72
73
|
* but the active flag drives the highlight.
|
|
73
74
|
*/
|
|
75
|
+
/**
|
|
76
|
+
* Each tab carries an `icon` field: the kebab-case key into the
|
|
77
|
+
* IntegrationIcon registry (see IntegrationIcon/registry.js). The
|
|
78
|
+
* SidebarMock renders that icon in the tab's .ico slot, tinted via
|
|
79
|
+
* currentColor so active tabs read full-cobalt and inactive tabs
|
|
80
|
+
* read muted-cobalt. The icon makes the tab self-documenting:
|
|
81
|
+
* Procest's xWiki tab carries the xWiki icon, DocuDesk's Signatures
|
|
82
|
+
* tab carries an activity-style icon for "stuff happens here", etc.
|
|
83
|
+
*/
|
|
74
84
|
const VARIANTS = {
|
|
75
85
|
'procest-xwiki': {
|
|
76
86
|
Component: ProcestXWiki,
|
|
77
87
|
label: 'Procest · Case sidebar, xWiki tab',
|
|
78
88
|
tabs: [
|
|
79
|
-
{ id: 'activity', active: false },
|
|
80
|
-
{ id: 'xwiki', active: true },
|
|
81
|
-
{ id: 'timeline', active: false },
|
|
82
|
-
{ id: 'documents', active: false },
|
|
89
|
+
{ id: 'activity', active: false, icon: 'activity' },
|
|
90
|
+
{ id: 'xwiki', active: true, icon: 'xwiki' },
|
|
91
|
+
{ id: 'timeline', active: false, icon: 'calendar' },
|
|
92
|
+
{ id: 'documents', active: false, icon: 'files' },
|
|
83
93
|
],
|
|
84
94
|
},
|
|
85
95
|
'procest-timeline': {
|
|
86
96
|
Component: ProcestTimeline,
|
|
87
97
|
label: 'Procest · Case sidebar, Timeline tab',
|
|
88
98
|
tabs: [
|
|
89
|
-
{ id: 'activity', active: false },
|
|
90
|
-
{ id: 'xwiki', active: false },
|
|
91
|
-
{ id: 'timeline', active: true },
|
|
92
|
-
{ id: 'documents', active: false },
|
|
99
|
+
{ id: 'activity', active: false, icon: 'activity' },
|
|
100
|
+
{ id: 'xwiki', active: false, icon: 'xwiki' },
|
|
101
|
+
{ id: 'timeline', active: true, icon: 'calendar' },
|
|
102
|
+
{ id: 'documents', active: false, icon: 'files' },
|
|
93
103
|
],
|
|
94
104
|
},
|
|
95
105
|
'docudesk-signatures': {
|
|
96
106
|
Component: DocuDeskSignatures,
|
|
97
107
|
label: 'DocuDesk · Document sidebar, Signatures tab',
|
|
98
108
|
tabs: [
|
|
99
|
-
{ id: 'activity',
|
|
100
|
-
{ id: 'signatures',
|
|
101
|
-
{ id: 'pii',
|
|
102
|
-
{ id: 'versions',
|
|
109
|
+
{ id: 'activity', active: false, icon: 'activity' },
|
|
110
|
+
{ id: 'signatures', active: true, icon: 'mail' },
|
|
111
|
+
{ id: 'pii', active: false, icon: 'keycloak' },
|
|
112
|
+
{ id: 'versions', active: false, icon: 'files' },
|
|
103
113
|
],
|
|
104
114
|
},
|
|
105
115
|
'docudesk-pii-map': {
|
|
106
116
|
Component: DocuDeskPiiMap,
|
|
107
117
|
label: 'DocuDesk · Document sidebar, PII map tab',
|
|
108
118
|
tabs: [
|
|
109
|
-
{ id: 'activity',
|
|
110
|
-
{ id: 'signatures',
|
|
111
|
-
{ id: 'pii',
|
|
112
|
-
{ id: 'versions',
|
|
119
|
+
{ id: 'activity', active: false, icon: 'activity' },
|
|
120
|
+
{ id: 'signatures', active: false, icon: 'mail' },
|
|
121
|
+
{ id: 'pii', active: true, icon: 'keycloak' },
|
|
122
|
+
{ id: 'versions', active: false, icon: 'files' },
|
|
113
123
|
],
|
|
114
124
|
},
|
|
115
125
|
'openregister-metadata': {
|
|
116
126
|
Component: OpenRegisterMetadata,
|
|
117
127
|
label: 'OpenRegister · Object sidebar, Metadata tab',
|
|
118
128
|
tabs: [
|
|
119
|
-
{ id: 'activity', active: false },
|
|
120
|
-
{ id: 'metadata', active: true },
|
|
121
|
-
{ id: 'audit', active: false },
|
|
129
|
+
{ id: 'activity', active: false, icon: 'activity' },
|
|
130
|
+
{ id: 'metadata', active: true, icon: 'files' },
|
|
131
|
+
{ id: 'audit', active: false, icon: 'keycloak' },
|
|
122
132
|
],
|
|
123
133
|
},
|
|
124
134
|
'opencatalogi-publication-history': {
|
|
125
135
|
Component: OpenCatalogiPublicationHistory,
|
|
126
136
|
label: 'OpenCatalogi · Publication sidebar, History tab',
|
|
127
137
|
tabs: [
|
|
128
|
-
{ id: 'activity', active: false },
|
|
129
|
-
{ id: 'history', active: true },
|
|
130
|
-
{ id: 'sources', active: false },
|
|
138
|
+
{ id: 'activity', active: false, icon: 'activity' },
|
|
139
|
+
{ id: 'history', active: true, icon: 'calendar' },
|
|
140
|
+
{ id: 'sources', active: false, icon: 'rss' },
|
|
131
141
|
],
|
|
132
142
|
},
|
|
133
143
|
'openconnector-run-detail': {
|
|
134
144
|
Component: OpenConnectorRunDetail,
|
|
135
145
|
label: 'OpenConnector · Run sidebar, Logs tab',
|
|
136
146
|
tabs: [
|
|
137
|
-
{ id: 'activity', active: false },
|
|
138
|
-
{ id: 'logs', active: true },
|
|
139
|
-
{ id: 'mapping', active: false },
|
|
147
|
+
{ id: 'activity', active: false, icon: 'activity' },
|
|
148
|
+
{ id: 'logs', active: true, icon: 'n8n' },
|
|
149
|
+
{ id: 'mapping', active: false, icon: 'windmill' },
|
|
140
150
|
],
|
|
141
151
|
},
|
|
142
152
|
'decidesk-decision': {
|
|
143
153
|
Component: DeciDeskDecision,
|
|
144
154
|
label: 'DeciDesk · Decision sidebar, Detail tab',
|
|
145
155
|
tabs: [
|
|
146
|
-
{ id: 'activity', active: false },
|
|
147
|
-
{ id: 'detail', active: true },
|
|
148
|
-
{ id: 'actions', active: false },
|
|
156
|
+
{ id: 'activity', active: false, icon: 'activity' },
|
|
157
|
+
{ id: 'detail', active: true, icon: 'files' },
|
|
158
|
+
{ id: 'actions', active: false, icon: 'decks' },
|
|
149
159
|
],
|
|
150
160
|
},
|
|
151
161
|
'nextcloud-activity': {
|
|
152
162
|
Component: NextcloudActivity,
|
|
153
163
|
label: 'Nextcloud · Stock activity feed',
|
|
154
164
|
tabs: [
|
|
155
|
-
{ id: 'activity', active: true },
|
|
156
|
-
{ id: 'comments', active: false },
|
|
165
|
+
{ id: 'activity', active: true, icon: 'activity' },
|
|
166
|
+
{ id: 'comments', active: false, icon: 'talk' },
|
|
157
167
|
],
|
|
158
168
|
},
|
|
159
169
|
};
|
|
@@ -184,7 +194,11 @@ export default function SidebarMock({ kind, embedded = false, className }) {
|
|
|
184
194
|
<div className={amStyles['sb-tabs']}>
|
|
185
195
|
{tabs.map((t, i) => (
|
|
186
196
|
<div key={t.id || i} className={[amStyles['sb-tab'], t.active && amStyles.active].filter(Boolean).join(' ')}>
|
|
187
|
-
|
|
197
|
+
{t.icon ? (
|
|
198
|
+
<IntegrationIcon name={t.icon} size="xs" />
|
|
199
|
+
) : (
|
|
200
|
+
<div className={amStyles.ico}></div>
|
|
201
|
+
)}
|
|
188
202
|
<div className={amStyles.l}></div>
|
|
189
203
|
</div>
|
|
190
204
|
))}
|