@conduction/docusaurus-preset 2.3.1 → 2.4.1
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 +87 -0
- package/src/components/MockScene/MockScene.module.css +26 -0
- package/src/components/SidebarMock/SidebarMock.jsx +55 -34
- package/src/components/SidebarMock/SidebarMock.module.css +5 -3
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,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <MockScene />
|
|
3
|
+
*
|
|
4
|
+
* Free-form positioning surface for assembling overlap shots out of
|
|
5
|
+
* WidgetMocks and SidebarMocks. The scene itself is a transparent
|
|
6
|
+
* stage; the caller decides the canvas size and where each item
|
|
7
|
+
* lands. Multiple sidebars and widgets can share a scene, can be
|
|
8
|
+
* different sizes, and can overlap as needed.
|
|
9
|
+
*
|
|
10
|
+
* Sibling to AppMock + WidgetMock + SidebarMock. AppMock paints a
|
|
11
|
+
* single product surface, WidgetMock one tile, SidebarMock one detail
|
|
12
|
+
* panel; MockScene paints the overlap. No background, no rotation,
|
|
13
|
+
* no centred-anchor pattern; each item carries its own shadow and
|
|
14
|
+
* lifts off whatever card the scene sits inside.
|
|
15
|
+
*
|
|
16
|
+
* Usage:
|
|
17
|
+
*
|
|
18
|
+
* <MockScene
|
|
19
|
+
* width={960}
|
|
20
|
+
* height={420}
|
|
21
|
+
* items={[
|
|
22
|
+
* { type: 'widget', kind: 'nextcloud-mail', x: 0, y: 0, size: 'sm' },
|
|
23
|
+
* { type: 'sidebar', kind: 'openregister-metadata', x: 220, y: 30, size: 'md' },
|
|
24
|
+
* { type: 'widget', kind: 'openregister-activity', x: 540, y: 80, size: 'md' },
|
|
25
|
+
* { type: 'sidebar', kind: 'procest-xwiki', x: 700, y: 0, size: 'sm' },
|
|
26
|
+
* ]}
|
|
27
|
+
* />
|
|
28
|
+
*
|
|
29
|
+
* Each item:
|
|
30
|
+
* - type: 'widget' | 'sidebar'
|
|
31
|
+
* - kind: variant slug (see WidgetMock or SidebarMock VARIANTS)
|
|
32
|
+
* - x, y: pixel offset from the scene's top-left corner
|
|
33
|
+
* - size: 'sm' | 'md' | 'lg' (defaults to 'md' for both types)
|
|
34
|
+
* - z: z-index override (defaults to array order, later items
|
|
35
|
+
* render on top)
|
|
36
|
+
*
|
|
37
|
+
* Caller can also pass a `style` field on an item for inline overrides
|
|
38
|
+
* beyond what `size` provides (custom widths, transforms, etc.). The
|
|
39
|
+
* inline style is merged onto the item wrapper, so anything
|
|
40
|
+
* position-related on the wrapper (left, top, z-index) takes
|
|
41
|
+
* precedence over the caller's style.
|
|
42
|
+
*
|
|
43
|
+
* Props:
|
|
44
|
+
* - items: Array of item descriptors (see above)
|
|
45
|
+
* - width: scene width in px (default 960)
|
|
46
|
+
* - height: scene height in px (default 420)
|
|
47
|
+
* - className: string
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
import React from 'react';
|
|
51
|
+
import styles from './MockScene.module.css';
|
|
52
|
+
import amStyles from '../AppMock/AppMock.module.css';
|
|
53
|
+
import WidgetMock from '../WidgetMock/WidgetMock.jsx';
|
|
54
|
+
import SidebarMock from '../SidebarMock/SidebarMock.jsx';
|
|
55
|
+
|
|
56
|
+
function renderItem(item) {
|
|
57
|
+
const size = item.size || 'md';
|
|
58
|
+
if (item.type === 'widget') {
|
|
59
|
+
return <WidgetMock kind={item.kind} size={size} />;
|
|
60
|
+
}
|
|
61
|
+
if (item.type === 'sidebar') {
|
|
62
|
+
return <SidebarMock kind={item.kind} size={size} />;
|
|
63
|
+
}
|
|
64
|
+
return item.node || null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export default function MockScene({ items = [], width = 960, height = 420, className }) {
|
|
68
|
+
return (
|
|
69
|
+
<div className={[amStyles.am, styles.scene, className].filter(Boolean).join(' ')}>
|
|
70
|
+
<div className={styles.sceneFrame} style={{ width, height }}>
|
|
71
|
+
{items.map((item, i) => {
|
|
72
|
+
const wrapperStyle = {
|
|
73
|
+
...(item.style || {}),
|
|
74
|
+
left: item.x || 0,
|
|
75
|
+
top: item.y || 0,
|
|
76
|
+
zIndex: item.z != null ? item.z : i,
|
|
77
|
+
};
|
|
78
|
+
return (
|
|
79
|
+
<div key={i} className={styles.sceneItem} style={wrapperStyle}>
|
|
80
|
+
{renderItem(item)}
|
|
81
|
+
</div>
|
|
82
|
+
);
|
|
83
|
+
})}
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <MockScene /> styles.
|
|
3
|
+
*
|
|
4
|
+
* Free-form positioning surface. Each item in the items[] prop renders
|
|
5
|
+
* inside a `.sceneItem` wrapper that's absolutely positioned via
|
|
6
|
+
* inline style (`left`, `top`, `z-index`). The scene itself is a
|
|
7
|
+
* transparent stage; layout is up to the caller.
|
|
8
|
+
*
|
|
9
|
+
* No background, no padding, no rotation. The mocks themselves carry
|
|
10
|
+
* their own borders and shadows so they read as panels lifted off
|
|
11
|
+
* the surrounding card.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
.am.scene { display: contents; }
|
|
15
|
+
|
|
16
|
+
.am .sceneFrame {
|
|
17
|
+
position: relative;
|
|
18
|
+
/* Width and height come from inline style on the rendered element
|
|
19
|
+
so the caller decides the canvas size per scene. */
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.am .sceneItem {
|
|
23
|
+
position: absolute;
|
|
24
|
+
/* `left`, `top`, and optionally `z-index` are set inline by the
|
|
25
|
+
component from the item's x/y/z values. */
|
|
26
|
+
}
|
|
@@ -42,6 +42,13 @@
|
|
|
42
42
|
*
|
|
43
43
|
* Props:
|
|
44
44
|
* - kind: one of VARIANTS keys (required)
|
|
45
|
+
* - size: 'sm' | 'md' (default) | 'lg' — standalone frame size
|
|
46
|
+
* (240x320 / 300x400 /
|
|
47
|
+
* 360x480). Ignored in
|
|
48
|
+
* embedded mode (the
|
|
49
|
+
* panel sizes itself
|
|
50
|
+
* to AppMock's .body
|
|
51
|
+
* layout)
|
|
45
52
|
* - embedded: boolean (default false) — drop the standalone
|
|
46
53
|
* .smFrame chrome so the
|
|
47
54
|
* panel slots into
|
|
@@ -52,6 +59,7 @@
|
|
|
52
59
|
import React from 'react';
|
|
53
60
|
import styles from './SidebarMock.module.css';
|
|
54
61
|
import amStyles from '../AppMock/AppMock.module.css';
|
|
62
|
+
import IntegrationIcon from '../IntegrationIcon/IntegrationIcon.jsx';
|
|
55
63
|
|
|
56
64
|
import ProcestXWiki from './variants/ProcestXWiki.jsx';
|
|
57
65
|
import ProcestTimeline from './variants/ProcestTimeline.jsx';
|
|
@@ -71,99 +79,108 @@ import NextcloudActivity from './variants/NextcloudActivity.jsx';
|
|
|
71
79
|
* decorative (rendered as a placeholder bar in .sb-tab .l)
|
|
72
80
|
* but the active flag drives the highlight.
|
|
73
81
|
*/
|
|
82
|
+
/**
|
|
83
|
+
* Each tab carries an `icon` field: the kebab-case key into the
|
|
84
|
+
* IntegrationIcon registry (see IntegrationIcon/registry.js). The
|
|
85
|
+
* SidebarMock renders that icon in the tab's .ico slot, tinted via
|
|
86
|
+
* currentColor so active tabs read full-cobalt and inactive tabs
|
|
87
|
+
* read muted-cobalt. The icon makes the tab self-documenting:
|
|
88
|
+
* Procest's xWiki tab carries the xWiki icon, DocuDesk's Signatures
|
|
89
|
+
* tab carries an activity-style icon for "stuff happens here", etc.
|
|
90
|
+
*/
|
|
74
91
|
const VARIANTS = {
|
|
75
92
|
'procest-xwiki': {
|
|
76
93
|
Component: ProcestXWiki,
|
|
77
94
|
label: 'Procest · Case sidebar, xWiki tab',
|
|
78
95
|
tabs: [
|
|
79
|
-
{ id: 'activity', active: false },
|
|
80
|
-
{ id: 'xwiki', active: true },
|
|
81
|
-
{ id: 'timeline', active: false },
|
|
82
|
-
{ id: 'documents', active: false },
|
|
96
|
+
{ id: 'activity', active: false, icon: 'activity' },
|
|
97
|
+
{ id: 'xwiki', active: true, icon: 'xwiki' },
|
|
98
|
+
{ id: 'timeline', active: false, icon: 'calendar' },
|
|
99
|
+
{ id: 'documents', active: false, icon: 'files' },
|
|
83
100
|
],
|
|
84
101
|
},
|
|
85
102
|
'procest-timeline': {
|
|
86
103
|
Component: ProcestTimeline,
|
|
87
104
|
label: 'Procest · Case sidebar, Timeline tab',
|
|
88
105
|
tabs: [
|
|
89
|
-
{ id: 'activity', active: false },
|
|
90
|
-
{ id: 'xwiki', active: false },
|
|
91
|
-
{ id: 'timeline', active: true },
|
|
92
|
-
{ id: 'documents', active: false },
|
|
106
|
+
{ id: 'activity', active: false, icon: 'activity' },
|
|
107
|
+
{ id: 'xwiki', active: false, icon: 'xwiki' },
|
|
108
|
+
{ id: 'timeline', active: true, icon: 'calendar' },
|
|
109
|
+
{ id: 'documents', active: false, icon: 'files' },
|
|
93
110
|
],
|
|
94
111
|
},
|
|
95
112
|
'docudesk-signatures': {
|
|
96
113
|
Component: DocuDeskSignatures,
|
|
97
114
|
label: 'DocuDesk · Document sidebar, Signatures tab',
|
|
98
115
|
tabs: [
|
|
99
|
-
{ id: 'activity',
|
|
100
|
-
{ id: 'signatures',
|
|
101
|
-
{ id: 'pii',
|
|
102
|
-
{ id: 'versions',
|
|
116
|
+
{ id: 'activity', active: false, icon: 'activity' },
|
|
117
|
+
{ id: 'signatures', active: true, icon: 'mail' },
|
|
118
|
+
{ id: 'pii', active: false, icon: 'keycloak' },
|
|
119
|
+
{ id: 'versions', active: false, icon: 'files' },
|
|
103
120
|
],
|
|
104
121
|
},
|
|
105
122
|
'docudesk-pii-map': {
|
|
106
123
|
Component: DocuDeskPiiMap,
|
|
107
124
|
label: 'DocuDesk · Document sidebar, PII map tab',
|
|
108
125
|
tabs: [
|
|
109
|
-
{ id: 'activity',
|
|
110
|
-
{ id: 'signatures',
|
|
111
|
-
{ id: 'pii',
|
|
112
|
-
{ id: 'versions',
|
|
126
|
+
{ id: 'activity', active: false, icon: 'activity' },
|
|
127
|
+
{ id: 'signatures', active: false, icon: 'mail' },
|
|
128
|
+
{ id: 'pii', active: true, icon: 'keycloak' },
|
|
129
|
+
{ id: 'versions', active: false, icon: 'files' },
|
|
113
130
|
],
|
|
114
131
|
},
|
|
115
132
|
'openregister-metadata': {
|
|
116
133
|
Component: OpenRegisterMetadata,
|
|
117
134
|
label: 'OpenRegister · Object sidebar, Metadata tab',
|
|
118
135
|
tabs: [
|
|
119
|
-
{ id: 'activity', active: false },
|
|
120
|
-
{ id: 'metadata', active: true },
|
|
121
|
-
{ id: 'audit', active: false },
|
|
136
|
+
{ id: 'activity', active: false, icon: 'activity' },
|
|
137
|
+
{ id: 'metadata', active: true, icon: 'files' },
|
|
138
|
+
{ id: 'audit', active: false, icon: 'keycloak' },
|
|
122
139
|
],
|
|
123
140
|
},
|
|
124
141
|
'opencatalogi-publication-history': {
|
|
125
142
|
Component: OpenCatalogiPublicationHistory,
|
|
126
143
|
label: 'OpenCatalogi · Publication sidebar, History tab',
|
|
127
144
|
tabs: [
|
|
128
|
-
{ id: 'activity', active: false },
|
|
129
|
-
{ id: 'history', active: true },
|
|
130
|
-
{ id: 'sources', active: false },
|
|
145
|
+
{ id: 'activity', active: false, icon: 'activity' },
|
|
146
|
+
{ id: 'history', active: true, icon: 'calendar' },
|
|
147
|
+
{ id: 'sources', active: false, icon: 'rss' },
|
|
131
148
|
],
|
|
132
149
|
},
|
|
133
150
|
'openconnector-run-detail': {
|
|
134
151
|
Component: OpenConnectorRunDetail,
|
|
135
152
|
label: 'OpenConnector · Run sidebar, Logs tab',
|
|
136
153
|
tabs: [
|
|
137
|
-
{ id: 'activity', active: false },
|
|
138
|
-
{ id: 'logs', active: true },
|
|
139
|
-
{ id: 'mapping', active: false },
|
|
154
|
+
{ id: 'activity', active: false, icon: 'activity' },
|
|
155
|
+
{ id: 'logs', active: true, icon: 'n8n' },
|
|
156
|
+
{ id: 'mapping', active: false, icon: 'windmill' },
|
|
140
157
|
],
|
|
141
158
|
},
|
|
142
159
|
'decidesk-decision': {
|
|
143
160
|
Component: DeciDeskDecision,
|
|
144
161
|
label: 'DeciDesk · Decision sidebar, Detail tab',
|
|
145
162
|
tabs: [
|
|
146
|
-
{ id: 'activity', active: false },
|
|
147
|
-
{ id: 'detail', active: true },
|
|
148
|
-
{ id: 'actions', active: false },
|
|
163
|
+
{ id: 'activity', active: false, icon: 'activity' },
|
|
164
|
+
{ id: 'detail', active: true, icon: 'files' },
|
|
165
|
+
{ id: 'actions', active: false, icon: 'decks' },
|
|
149
166
|
],
|
|
150
167
|
},
|
|
151
168
|
'nextcloud-activity': {
|
|
152
169
|
Component: NextcloudActivity,
|
|
153
170
|
label: 'Nextcloud · Stock activity feed',
|
|
154
171
|
tabs: [
|
|
155
|
-
{ id: 'activity', active: true },
|
|
156
|
-
{ id: 'comments', active: false },
|
|
172
|
+
{ id: 'activity', active: true, icon: 'activity' },
|
|
173
|
+
{ id: 'comments', active: false, icon: 'talk' },
|
|
157
174
|
],
|
|
158
175
|
},
|
|
159
176
|
};
|
|
160
177
|
|
|
161
|
-
export default function SidebarMock({ kind, embedded = false, className }) {
|
|
178
|
+
export default function SidebarMock({ kind, size = 'md', embedded = false, className }) {
|
|
162
179
|
const variant = VARIANTS[kind];
|
|
163
180
|
if (!variant) {
|
|
164
181
|
return (
|
|
165
182
|
<div className={[amStyles.am, styles.sm].filter(Boolean).join(' ')}>
|
|
166
|
-
<div className={styles.smFrame}>
|
|
183
|
+
<div className={[styles.smFrame, styles[`sb-size-${size}`]].filter(Boolean).join(' ')}>
|
|
167
184
|
<div style={{ padding: 12, color: 'var(--c-cobalt-400)', fontSize: 11 }}>Unknown sidebar: {kind}</div>
|
|
168
185
|
</div>
|
|
169
186
|
</div>
|
|
@@ -184,7 +201,11 @@ export default function SidebarMock({ kind, embedded = false, className }) {
|
|
|
184
201
|
<div className={amStyles['sb-tabs']}>
|
|
185
202
|
{tabs.map((t, i) => (
|
|
186
203
|
<div key={t.id || i} className={[amStyles['sb-tab'], t.active && amStyles.active].filter(Boolean).join(' ')}>
|
|
187
|
-
|
|
204
|
+
{t.icon ? (
|
|
205
|
+
<IntegrationIcon name={t.icon} size="xs" />
|
|
206
|
+
) : (
|
|
207
|
+
<div className={amStyles.ico}></div>
|
|
208
|
+
)}
|
|
188
209
|
<div className={amStyles.l}></div>
|
|
189
210
|
</div>
|
|
190
211
|
))}
|
|
@@ -200,7 +221,7 @@ export default function SidebarMock({ kind, embedded = false, className }) {
|
|
|
200
221
|
|
|
201
222
|
return (
|
|
202
223
|
<div className={[amStyles.am, styles.sm, className].filter(Boolean).join(' ')}>
|
|
203
|
-
<div className={styles.smFrame}>
|
|
224
|
+
<div className={[styles.smFrame, styles[`sb-size-${size}`]].filter(Boolean).join(' ')}>
|
|
204
225
|
{panel}
|
|
205
226
|
</div>
|
|
206
227
|
</div>
|
|
@@ -28,10 +28,9 @@
|
|
|
28
28
|
.am.sm { display: contents; }
|
|
29
29
|
|
|
30
30
|
/* Standalone wrapper card. Inside, the .detail.rich panel renders
|
|
31
|
-
identically to its embedded twin, just clipped to the smFrame box.
|
|
31
|
+
identically to its embedded twin, just clipped to the smFrame box.
|
|
32
|
+
Width/height come from the .sb-size-* modifier on the same element. */
|
|
32
33
|
.am .smFrame {
|
|
33
|
-
width: 300px;
|
|
34
|
-
height: 400px;
|
|
35
34
|
background: white;
|
|
36
35
|
border-radius: var(--radius-md);
|
|
37
36
|
border: 1px solid var(--c-cobalt-100);
|
|
@@ -40,6 +39,9 @@
|
|
|
40
39
|
display: flex;
|
|
41
40
|
flex-direction: column;
|
|
42
41
|
}
|
|
42
|
+
.am .smFrame.sb-size-sm { width: 240px; height: 320px; }
|
|
43
|
+
.am .smFrame.sb-size-md { width: 300px; height: 400px; }
|
|
44
|
+
.am .smFrame.sb-size-lg { width: 360px; height: 480px; }
|
|
43
45
|
|
|
44
46
|
/* Inside .smFrame the .detail.rich child needs to fill the box; the
|
|
45
47
|
default .detail width: 26% rule is meant for an embedded layout so
|