@crombolo/backoffice-host 0.0.0-stage → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +69 -0
  3. package/assets/login.js +352 -0
  4. package/package.json +35 -4
  5. package/plugin/assistant/client.js +53 -0
  6. package/plugin/assistant/drawer.js +865 -0
  7. package/plugin/assistant/umbraco-package.json +16 -0
  8. package/plugin/branding/backdrop.svg +1 -0
  9. package/plugin/branding/branding.js +100 -0
  10. package/plugin/branding/bundle-builder-labels.js +63 -0
  11. package/plugin/branding/client-credentials.js +49 -0
  12. package/plugin/branding/components-tree.js +40 -0
  13. package/plugin/branding/content-type-labels.js +27 -0
  14. package/plugin/branding/favicon.svg +1 -0
  15. package/plugin/branding/help-menu.js +46 -0
  16. package/plugin/branding/icon-mark.js +15 -0
  17. package/plugin/branding/icon-registry.js +40 -0
  18. package/plugin/branding/localization-en.js +115 -0
  19. package/plugin/branding/log-viewer-menu.js +70 -0
  20. package/plugin/branding/logo-header.svg +1 -0
  21. package/plugin/branding/logo-surface.svg +1 -0
  22. package/plugin/branding/query-builder.js +28 -0
  23. package/plugin/branding/sign-in.js +80 -0
  24. package/plugin/branding/sysinfo.js +89 -0
  25. package/plugin/branding/theme.css +102 -0
  26. package/plugin/bundles-carries.js +16 -0
  27. package/plugin/bundles-client.js +40 -0
  28. package/plugin/bundles-created-overview.js +244 -0
  29. package/plugin/bundles-created.js +70 -0
  30. package/plugin/bundles-installed.js +176 -0
  31. package/plugin/bundles-marketplace.js +236 -0
  32. package/plugin/changes-dashboard.js +169 -0
  33. package/plugin/element-type-hint.js +58 -0
  34. package/plugin/form-picker.js +116 -0
  35. package/plugin/forms-client.js +52 -0
  36. package/plugin/forms-entries.js +244 -0
  37. package/plugin/forms-overview.js +380 -0
  38. package/plugin/localizations/ar.js +97 -0
  39. package/plugin/localizations/bs.js +86 -0
  40. package/plugin/localizations/cs.js +73 -0
  41. package/plugin/localizations/cy.js +92 -0
  42. package/plugin/localizations/da.js +101 -0
  43. package/plugin/localizations/de.js +79 -0
  44. package/plugin/localizations/en.js +71 -0
  45. package/plugin/localizations/es.js +52 -0
  46. package/plugin/localizations/fr.js +78 -0
  47. package/plugin/localizations/he.js +24 -0
  48. package/plugin/localizations/hr.js +89 -0
  49. package/plugin/localizations/it.js +86 -0
  50. package/plugin/localizations/ja.js +43 -0
  51. package/plugin/localizations/ko.js +24 -0
  52. package/plugin/localizations/nb.js +44 -0
  53. package/plugin/localizations/nl.js +85 -0
  54. package/plugin/localizations/pl.js +44 -0
  55. package/plugin/localizations/pt-br.js +25 -0
  56. package/plugin/localizations/pt.js +100 -0
  57. package/plugin/localizations/ro.js +9 -0
  58. package/plugin/localizations/ru.js +46 -0
  59. package/plugin/localizations/sv.js +46 -0
  60. package/plugin/localizations/tr.js +80 -0
  61. package/plugin/localizations/uk.js +46 -0
  62. package/plugin/localizations/umbraco-package.json +279 -0
  63. package/plugin/localizations/vi.js +104 -0
  64. package/plugin/localizations/zh-tw.js +38 -0
  65. package/plugin/localizations/zh.js +38 -0
  66. package/plugin/read-only-banner.js +48 -0
  67. package/plugin/report-client.js +13 -0
  68. package/plugin/seo/client.js +35 -0
  69. package/plugin/seo/dashboard.js +242 -0
  70. package/plugin/seo/document-view.js +161 -0
  71. package/plugin/seo/type-hint.js +45 -0
  72. package/plugin/seo/umbraco-package.json +61 -0
  73. package/plugin/settings-dashboard.js +123 -0
  74. package/plugin/tsx-editors.js +337 -0
  75. package/plugin/tsx-snippets.js +63 -0
  76. package/plugin/umbraco-package.json +298 -0
  77. package/plugin/welcome-dashboard.js +106 -0
  78. package/src/branding.ts +59 -0
  79. package/src/bundle-package.ts +266 -0
  80. package/src/extensions.ts +189 -0
  81. package/src/graphics.ts +87 -0
  82. package/src/index.ts +8 -0
  83. package/src/login-assets.ts +18 -0
  84. package/src/manifests.ts +154 -0
  85. package/src/paths.ts +117 -0
  86. package/src/shell.ts +139 -0
  87. package/src/static.ts +107 -0
  88. package/src/text-imports.d.ts +23 -0
  89. package/README.md +0 -3
@@ -0,0 +1,298 @@
1
+ {
2
+ "$schema": "../../backoffice-dist/dist/umbraco-package-schema.json",
3
+ "name": "Crombolo",
4
+ "id": "Crombolo.Core",
5
+ "version": "0.10.0",
6
+ "allowPublicAccess": false,
7
+ "extensions": [
8
+ {
9
+ "type": "sectionView",
10
+ "alias": "Crombolo.SectionView.Bundles.Marketplace",
11
+ "name": "Crombolo Packages Marketplace",
12
+ "element": "/crombolo-plugin/bundles-marketplace.js",
13
+ "weight": 300,
14
+ "overwrites": ["Umb.SectionView.Packages.Marketplace"],
15
+ "meta": {
16
+ "label": "Marketplace",
17
+ "pathname": "packages",
18
+ "icon": "icon-cloud"
19
+ },
20
+ "conditions": [
21
+ {
22
+ "alias": "Umb.Condition.SectionAlias",
23
+ "match": "Umb.Section.Packages"
24
+ }
25
+ ]
26
+ },
27
+ {
28
+ "type": "sectionView",
29
+ "alias": "Crombolo.SectionView.Bundles.Created",
30
+ "name": "Crombolo Created Bundles",
31
+ "element": "/crombolo-plugin/bundles-created.js",
32
+ "weight": 100,
33
+ "overwrites": ["Umb.SectionView.Packages.Builder"],
34
+ "meta": {
35
+ "label": "Created",
36
+ "pathname": "created",
37
+ "icon": "icon-files"
38
+ },
39
+ "conditions": [
40
+ {
41
+ "alias": "Umb.Condition.SectionAlias",
42
+ "match": "Umb.Section.Packages"
43
+ }
44
+ ]
45
+ },
46
+ {
47
+ "type": "sectionView",
48
+ "alias": "Crombolo.SectionView.Bundles.Installed",
49
+ "name": "Crombolo Installed Packages",
50
+ "element": "/crombolo-plugin/bundles-installed.js",
51
+ "weight": 200,
52
+ "overwrites": ["Umb.SectionView.Packages.Installed"],
53
+ "meta": {
54
+ "label": "Installed",
55
+ "pathname": "installed",
56
+ "icon": "icon-box"
57
+ },
58
+ "conditions": [
59
+ {
60
+ "alias": "Umb.Condition.SectionAlias",
61
+ "match": "Umb.Section.Packages"
62
+ }
63
+ ]
64
+ },
65
+ {
66
+ "type": "dashboard",
67
+ "alias": "Crombolo.Dashboard.Changes",
68
+ "name": "Crombolo Changes Dashboard",
69
+ "element": "/crombolo-plugin/changes-dashboard.js",
70
+ "weight": 5,
71
+ "meta": {
72
+ "label": "Changes",
73
+ "pathname": "changes"
74
+ },
75
+ "conditions": [
76
+ {
77
+ "alias": "Umb.Condition.SectionAlias",
78
+ "match": "Umb.Section.Settings"
79
+ }
80
+ ]
81
+ },
82
+ {
83
+ "type": "dashboard",
84
+ "alias": "Crombolo.Dashboard.Welcome",
85
+ "name": "Crombolo Welcome Dashboard",
86
+ "element": "/crombolo-plugin/welcome-dashboard.js",
87
+ "weight": 20,
88
+ "overwrites": ["Umb.Dashboard.UmbracoNews"],
89
+ "meta": {
90
+ "label": "Welcome",
91
+ "pathname": "welcome"
92
+ },
93
+ "conditions": [
94
+ {
95
+ "alias": "Umb.Condition.SectionAlias",
96
+ "match": "Umb.Section.Content"
97
+ }
98
+ ]
99
+ },
100
+ {
101
+ "type": "dashboard",
102
+ "alias": "Crombolo.Dashboard.Settings",
103
+ "name": "Crombolo Settings Dashboard",
104
+ "element": "/crombolo-plugin/settings-dashboard.js",
105
+ "weight": 500,
106
+ "overwrites": ["Umb.Dashboard.SettingsWelcome"],
107
+ "meta": {
108
+ "label": "Welcome",
109
+ "pathname": "welcome"
110
+ },
111
+ "conditions": [
112
+ {
113
+ "alias": "Umb.Condition.SectionAlias",
114
+ "match": "Umb.Section.Settings"
115
+ }
116
+ ]
117
+ },
118
+ {
119
+ "type": "backofficeEntryPoint",
120
+ "alias": "Crombolo.EntryPoint.TsxEditors",
121
+ "name": "Crombolo TSX Template and Partial View Editors",
122
+ "js": "/crombolo-plugin/tsx-editors.js"
123
+ },
124
+ {
125
+ "type": "headerApp",
126
+ "alias": "Crombolo.HeaderApp.ReadOnly",
127
+ "name": "Crombolo Read-only Banner",
128
+ "element": "/crombolo-plugin/read-only-banner.js",
129
+ "weight": 1000
130
+ },
131
+ {
132
+ "type": "workspaceFooterApp",
133
+ "alias": "Crombolo.WorkspaceFooterApp.ElementTypeHint",
134
+ "name": "Crombolo Element Type Library Hint",
135
+ "element": "/crombolo-plugin/element-type-hint.js",
136
+ "weight": 900,
137
+ "conditions": [
138
+ {
139
+ "alias": "Umb.Condition.WorkspaceAlias",
140
+ "match": "Umb.Workspace.DocumentType"
141
+ }
142
+ ]
143
+ },
144
+ {
145
+ "type": "localization",
146
+ "alias": "Crombolo.Localization.EN",
147
+ "name": "Crombolo English Overrides",
148
+ "weight": 0,
149
+ "meta": {
150
+ "culture": "en"
151
+ },
152
+ "js": "/crombolo-plugin/branding/localization-en.js"
153
+ },
154
+ {
155
+ "type": "localization",
156
+ "alias": "Crombolo.Localization.EN_US",
157
+ "name": "Crombolo English (United States) Overrides",
158
+ "weight": 0,
159
+ "meta": {
160
+ "culture": "en-us"
161
+ },
162
+ "js": "/crombolo-plugin/branding/localization-en.js"
163
+ },
164
+ {
165
+ "type": "backofficeEntryPoint",
166
+ "alias": "Crombolo.EntryPoint.Branding",
167
+ "name": "Crombolo Branding",
168
+ "js": "/crombolo-plugin/branding/branding.js"
169
+ },
170
+ {
171
+ "type": "backofficeEntryPoint",
172
+ "alias": "Crombolo.EntryPoint.HelpMenu",
173
+ "name": "Crombolo Help Menu",
174
+ "js": "/crombolo-plugin/branding/help-menu.js"
175
+ },
176
+ {
177
+ "type": "backofficeEntryPoint",
178
+ "alias": "Crombolo.EntryPoint.Sysinfo",
179
+ "name": "Crombolo System Information Branding",
180
+ "js": "/crombolo-plugin/branding/sysinfo.js"
181
+ },
182
+ {
183
+ "type": "section",
184
+ "alias": "Crombolo.Section.Forms",
185
+ "name": "Crombolo Forms Section",
186
+ "weight": 50,
187
+ "meta": {
188
+ "label": "Forms",
189
+ "pathname": "forms"
190
+ }
191
+ },
192
+ {
193
+ "type": "sectionView",
194
+ "alias": "Crombolo.SectionView.Forms.Overview",
195
+ "name": "Crombolo Forms Overview",
196
+ "element": "/crombolo-plugin/forms-overview.js",
197
+ "weight": 200,
198
+ "meta": {
199
+ "label": "Forms",
200
+ "pathname": "forms",
201
+ "icon": "icon-notepad"
202
+ },
203
+ "conditions": [
204
+ {
205
+ "alias": "Umb.Condition.SectionAlias",
206
+ "match": "Crombolo.Section.Forms"
207
+ }
208
+ ]
209
+ },
210
+ {
211
+ "type": "sectionView",
212
+ "alias": "Crombolo.SectionView.Forms.Entries",
213
+ "name": "Crombolo Forms Entries",
214
+ "element": "/crombolo-plugin/forms-entries.js",
215
+ "weight": 100,
216
+ "meta": {
217
+ "label": "Entries",
218
+ "pathname": "entries",
219
+ "icon": "icon-inbox"
220
+ },
221
+ "conditions": [
222
+ {
223
+ "alias": "Umb.Condition.SectionAlias",
224
+ "match": "Crombolo.Section.Forms"
225
+ }
226
+ ]
227
+ },
228
+ {
229
+ "type": "propertyEditorSchema",
230
+ "name": "Form Picker",
231
+ "alias": "Crombolo.FormPicker",
232
+ "meta": {
233
+ "defaultPropertyEditorUiAlias": "Crombolo.PropertyEditorUi.FormPicker"
234
+ }
235
+ },
236
+ {
237
+ "type": "propertyEditorUi",
238
+ "alias": "Crombolo.PropertyEditorUi.FormPicker",
239
+ "name": "Form Picker",
240
+ "element": "/crombolo-plugin/form-picker.js",
241
+ "meta": {
242
+ "label": "Form Picker",
243
+ "icon": "icon-notepad",
244
+ "group": "pickers",
245
+ "propertyEditorSchemaAlias": "Crombolo.FormPicker"
246
+ }
247
+ },
248
+ {
249
+ "type": "backofficeEntryPoint",
250
+ "alias": "Crombolo.EntryPoint.ClientCredentials",
251
+ "name": "Crombolo Client Credential Prefix",
252
+ "js": "/crombolo-plugin/branding/client-credentials.js"
253
+ },
254
+ {
255
+ "type": "backofficeEntryPoint",
256
+ "alias": "Crombolo.EntryPoint.BundleBuilderLabels",
257
+ "name": "Crombolo Bundle Builder Labels",
258
+ "js": "/crombolo-plugin/branding/bundle-builder-labels.js"
259
+ },
260
+ {
261
+ "type": "backofficeEntryPoint",
262
+ "alias": "Crombolo.EntryPoint.ComponentsTree",
263
+ "name": "Crombolo Components Tree",
264
+ "js": "/crombolo-plugin/branding/components-tree.js"
265
+ },
266
+ {
267
+ "type": "backofficeEntryPoint",
268
+ "alias": "Crombolo.EntryPoint.ContentTypeLabels",
269
+ "name": "Crombolo Content Type Labels",
270
+ "js": "/crombolo-plugin/branding/content-type-labels.js"
271
+ },
272
+ {
273
+ "type": "backofficeEntryPoint",
274
+ "alias": "Crombolo.EntryPoint.QueryBuilder",
275
+ "name": "Crombolo Query Builder Language",
276
+ "js": "/crombolo-plugin/branding/query-builder.js"
277
+ },
278
+ {
279
+ "type": "backofficeEntryPoint",
280
+ "alias": "Crombolo.EntryPoint.SignIn",
281
+ "name": "Crombolo Sign-in Button",
282
+ "js": "/crombolo-plugin/branding/sign-in.js"
283
+ },
284
+ {
285
+ "type": "backofficeEntryPoint",
286
+ "alias": "Crombolo.EntryPoint.LogViewerMenu",
287
+ "name": "Crombolo Log Viewer Search Menu",
288
+ "js": "/crombolo-plugin/branding/log-viewer-menu.js"
289
+ },
290
+ {
291
+ "type": "globalContext",
292
+ "alias": "Crombolo.GlobalContext.Icons",
293
+ "name": "Crombolo Icons Context",
294
+ "overwrites": ["Umb.GlobalContext.Icons"],
295
+ "api": "/crombolo-plugin/branding/icon-registry.js"
296
+ }
297
+ ]
298
+ }
@@ -0,0 +1,106 @@
1
+ /**
2
+ * The Welcome dashboard in the Content section. Its manifest declares
3
+ * `overwrites: ['Umb.Dashboard.UmbracoNews']`, which takes the place of
4
+ * Umbraco's news dashboard without mutating the registry while the backoffice
5
+ * is rendering — the hazard the TSX entry point documents.
6
+ */
7
+ // UmbLitElement, not plain LitElement: a dashboard is used as a controller host,
8
+ // and a plain element fails with `controllerHost.provideContext is not a function`.
9
+ import { css, html } from '@umbraco-cms/backoffice/external/lit'
10
+ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'
11
+
12
+ const STEPS = [
13
+ {
14
+ title: 'Model the content',
15
+ body: html`Open <strong>Settings → Content Types</strong> and describe a page: its
16
+ properties, its tabs, and which types may sit beneath it. This is the same
17
+ editor Umbraco ships, so anything you know about Umbraco document types applies.`,
18
+ },
19
+ {
20
+ title: 'Write a template',
21
+ body: html`Templates are <strong>TSX</strong>, not Razor. A template is a file in
22
+ <code>Views/</code> that default-exports a component and receives the page as
23
+ <code>model</code>; <code>export const layout = 'alias'</code> names its master.
24
+ The editor under Settings → Templates writes that shape for you.`,
25
+ },
26
+ {
27
+ title: 'Create and publish',
28
+ body: html`Back in <strong>Content</strong>, create a page from your content type, fill it
29
+ in and publish. Publishing is per culture, and the published version is what the
30
+ site renders — drafts stay invisible until you say otherwise.`,
31
+ },
32
+ {
33
+ title: 'Keep the schema in the repository',
34
+ body: html`Content types, data types and templates are also files:
35
+ <code>schema/*.toml</code>. <code>crombolo schema sync</code> writes changes made in
36
+ the backoffice back out, and <code>crombolo schema check</code> tells you whether a
37
+ database matches. Schema travels through Git, not a database export.`,
38
+ },
39
+ ]
40
+
41
+ export default class CromboloWelcomeDashboardElement extends UmbLitElement {
42
+ render() {
43
+ return html`
44
+ <uui-box headline="Welcome to Crombolo">
45
+ <p class="lede">
46
+ Crombolo is a content management system that runs on
47
+ <strong>Bun and TypeScript</strong>. It serves the real Umbraco backoffice you
48
+ are looking at now and follows Umbraco's API contract, so the editing
49
+ experience is Umbraco's — while the server, the templates and the schema are
50
+ TypeScript, and the database is SQLite or Postgres.
51
+ </p>
52
+ <p class="lede">
53
+ There is no .NET anywhere in it: templates are TSX rather than Razor, and a
54
+ site's schema lives in TOML files beside its code.
55
+ </p>
56
+ </uui-box>
57
+
58
+ <uui-box headline="Getting started">
59
+ <ol>
60
+ ${STEPS.map(
61
+ (step) => html`<li>
62
+ <h4>${step.title}</h4>
63
+ <p>${step.body}</p>
64
+ </li>`,
65
+ )}
66
+ </ol>
67
+ </uui-box>
68
+
69
+ <uui-box headline="Worth knowing">
70
+ <ul>
71
+ <li>
72
+ The <strong>Settings</strong> section holds templates, partial views,
73
+ stylesheets and scripts — all served from your site's folders.
74
+ </li>
75
+ <li>
76
+ <strong>Upgrade</strong>, also under Settings, reports anything a version
77
+ change needs from you before it will run.
78
+ </li>
79
+ <li>
80
+ The log viewer under Settings reads the server's own structured logs, so a
81
+ failed publish or a broken template is searchable rather than guessed at.
82
+ </li>
83
+ </ul>
84
+ </uui-box>
85
+ `
86
+ }
87
+
88
+ static styles = css`
89
+ :host { display: block; padding: var(--uui-size-layout-1); }
90
+ uui-box { margin-bottom: var(--uui-size-layout-1); }
91
+ .lede { max-width: 70ch; line-height: 1.6; }
92
+ ol { margin: 0; padding-left: var(--uui-size-layout-1); }
93
+ ol li { margin-bottom: var(--uui-size-space-5); max-width: 70ch; }
94
+ ol h4 { margin: 0 0 var(--uui-size-space-2); }
95
+ ol p { margin: 0; line-height: 1.6; }
96
+ ul { margin: 0; padding-left: var(--uui-size-layout-1); }
97
+ ul li { margin-bottom: var(--uui-size-space-3); max-width: 70ch; line-height: 1.6; }
98
+ code {
99
+ background: var(--uui-color-surface-alt);
100
+ padding: 0 var(--uui-size-space-1);
101
+ border-radius: var(--uui-border-radius);
102
+ }
103
+ `
104
+ }
105
+
106
+ customElements.define('crombolo-welcome-dashboard', CromboloWelcomeDashboardElement)
@@ -0,0 +1,59 @@
1
+ /**
2
+ * The brand as data: the marks, and the palette behind them.
3
+ *
4
+ * The back office serves these as files, by path (`graphics.ts`). This exports
5
+ * the same bytes to anything that has to *draw* the brand rather than serve it
6
+ * — the enterprise console, which is a separate product surface in another
7
+ * repository and reaches the CMS only through the `@crombolo/crombolo` umbrella.
8
+ *
9
+ * Imported as text rather than duplicated as string literals, so the `.svg`
10
+ * and `.css` files stay the one source of truth and a new logo is one file to
11
+ * change. Bun inlines a text import at bundle time, so this works in a browser
12
+ * bundle as well as on the server — which matters, because the console that
13
+ * consumes it is a client-side app and could not read a file at runtime.
14
+ */
15
+ /// <reference path="./text-imports.d.ts" />
16
+ import faviconText from '../plugin/branding/favicon.svg' with { type: 'text' }
17
+ import logoText from '../plugin/branding/logo-header.svg' with { type: 'text' }
18
+ import themeText from '../plugin/branding/theme.css' with { type: 'text' }
19
+
20
+ /** The mark and wordmark, for a header or a sign-in card. */
21
+ export const logoSvg: string = logoText.trim()
22
+
23
+ /** The mark alone, square, for a tab icon. */
24
+ export const faviconSvg: string = faviconText.trim()
25
+
26
+ /**
27
+ * The palette, read out of `theme.css` rather than restated here.
28
+ *
29
+ * The theme is what the back office is actually painted with, so parsing it is
30
+ * what makes a consumer's colours the same colours rather than a copy that was
31
+ * the same once. Only the `--crombolo-*` tokens are ours; everything else in
32
+ * that file is an Umbraco variable being pointed at one of them.
33
+ */
34
+ export interface BrandPalette {
35
+ orange: string
36
+ orangeLight: string
37
+ orangeDeep: string
38
+ orangeText: string
39
+ cocoa: string
40
+ cream: string
41
+ }
42
+
43
+ /** `--crombolo-orange-deep` → `orangeDeep`. */
44
+ const camel = (name: string) =>
45
+ name.replace(/-([a-z])/g, (_, letter: string) => letter.toUpperCase())
46
+
47
+ export function paletteFrom(css: string): BrandPalette {
48
+ const found: Record<string, string> = {}
49
+ for (const [, name, value] of css.matchAll(/--crombolo-([a-z-]+)\s*:\s*([^;]+);/g))
50
+ found[camel(name as string)] = (value as string).trim()
51
+ const wanted = ['orange', 'orangeLight', 'orangeDeep', 'orangeText', 'cocoa', 'cream']
52
+ const missing = wanted.filter((key) => found[key] === undefined)
53
+ // A theme that stopped declaring one of these would otherwise hand a
54
+ // consumer `undefined` and paint something invisible.
55
+ if (missing.length > 0) throw new Error(`theme.css declares no ${missing.join(', ')}.`)
56
+ return Object.fromEntries(wanted.map((key) => [key, found[key]])) as unknown as BrandPalette
57
+ }
58
+
59
+ export const brandPalette: BrandPalette = paletteFrom(themeText)