@ditojs/admin 2.5.2 → 2.6.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.
Files changed (42) hide show
  1. package/dist/dito-admin.es.js +1337 -1304
  2. package/dist/dito-admin.umd.js +6 -6
  3. package/dist/style.css +1 -1
  4. package/package.json +4 -4
  5. package/src/DitoContext.js +4 -0
  6. package/src/DitoTypeComponent.js +0 -1
  7. package/src/components/DitoAccount.vue +1 -0
  8. package/src/components/DitoContainer.vue +16 -38
  9. package/src/components/DitoDialog.vue +3 -1
  10. package/src/components/DitoHeader.vue +11 -14
  11. package/src/components/DitoLabel.vue +7 -3
  12. package/src/components/DitoNavigation.vue +40 -0
  13. package/src/components/DitoPane.vue +78 -40
  14. package/src/components/DitoPanel.vue +0 -2
  15. package/src/components/DitoPanels.vue +4 -2
  16. package/src/components/DitoRoot.vue +39 -13
  17. package/src/components/DitoSchema.vue +23 -17
  18. package/src/components/DitoSchemaInlined.vue +1 -3
  19. package/src/components/DitoSidebar.vue +6 -24
  20. package/src/components/DitoView.vue +1 -0
  21. package/src/components/index.js +2 -1
  22. package/src/mixins/DitoMixin.js +9 -1
  23. package/src/mixins/TextMixin.js +1 -1
  24. package/src/styles/_layout.scss +11 -14
  25. package/src/styles/_scroll.scss +1 -2
  26. package/src/styles/_settings.scss +5 -1
  27. package/src/styles/_tippy.scss +1 -0
  28. package/src/types/DitoTypeButton.vue +8 -17
  29. package/src/types/DitoTypeCode.vue +0 -1
  30. package/src/types/DitoTypeComponent.vue +0 -1
  31. package/src/types/DitoTypeLabel.vue +1 -2
  32. package/src/types/DitoTypeList.vue +5 -6
  33. package/src/types/DitoTypeMarkup.vue +14 -16
  34. package/src/types/DitoTypeMultiselect.vue +2 -0
  35. package/src/types/DitoTypeObject.vue +5 -7
  36. package/src/types/DitoTypePanel.vue +0 -1
  37. package/src/types/DitoTypeSection.vue +0 -1
  38. package/src/types/DitoTypeTextarea.vue +0 -1
  39. package/src/types/DitoTypeTreeList.vue +0 -2
  40. package/src/types/DitoTypeUpload.vue +0 -2
  41. package/src/utils/options.js +0 -1
  42. package/src/utils/schema.js +29 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ditojs/admin",
3
- "version": "2.5.2",
3
+ "version": "2.6.1",
4
4
  "type": "module",
5
5
  "description": "Dito.js Admin is a schema based admin interface for Dito.js Server, featuring auto-generated views and forms and built with Vue.js",
6
6
  "repository": "https://github.com/ditojs/dito/tree/master/packages/admin",
@@ -33,8 +33,8 @@
33
33
  "not ie_mob > 0"
34
34
  ],
35
35
  "dependencies": {
36
- "@ditojs/ui": "^2.5.2",
37
- "@ditojs/utils": "^2.5.0",
36
+ "@ditojs/ui": "^2.6.1",
37
+ "@ditojs/utils": "^2.6.0",
38
38
  "@kyvg/vue3-notification": "^2.9.0",
39
39
  "@lk77/vue3-color": "^3.0.6",
40
40
  "@tiptap/core": "^2.0.3",
@@ -83,7 +83,7 @@
83
83
  "vite": "^4.3.4"
84
84
  },
85
85
  "types": "types",
86
- "gitHead": "8c5737b77ba43617cd95ba65fbabcdc2941542a8",
86
+ "gitHead": "a95912074661c314de4a56debf68950e12590dbd",
87
87
  "scripts": {
88
88
  "build": "vite build",
89
89
  "watch": "yarn build --mode 'development' --watch",
@@ -150,6 +150,10 @@ export default class DitoContext {
150
150
  return get(this, 'views', null)
151
151
  }
152
152
 
153
+ get flattenedViews() {
154
+ return get(this, 'flattenedViews', null)
155
+ }
156
+
153
157
  get itemLabel() {
154
158
  return get(this, 'itemLabel', null)
155
159
  }
@@ -21,7 +21,6 @@ export default {
21
21
  generateLabel: true,
22
22
  excludeValue: false,
23
23
  ignoreMissingValue: null,
24
- keepAligned: true,
25
24
  omitPadding: false,
26
25
 
27
26
  component: DitoComponent.component,
@@ -51,6 +51,7 @@ export default DitoComponent.component('DitoAccount', {
51
51
 
52
52
  .dito-account {
53
53
  position: relative;
54
+ display: inline-block;
54
55
 
55
56
  .dito-pulldown {
56
57
  top: $pulldown-padding-ver;
@@ -34,7 +34,7 @@ import { isString, isNumber } from '@ditojs/utils'
34
34
  import DitoComponent from '../DitoComponent.js'
35
35
  import DitoContext from '../DitoContext.js'
36
36
  import { getSchemaAccessor } from '../utils/accessor.js'
37
- import { getTypeComponent, keepAligned, omitPadding } from '../utils/schema.js'
37
+ import { getTypeComponent, hasLabel, omitPadding } from '../utils/schema.js'
38
38
  import { parseFraction } from '../utils/math.js'
39
39
 
40
40
  // @vue/component
@@ -49,8 +49,7 @@ export default DitoComponent.component('DitoContainer', {
49
49
  nested: { type: Boolean, default: true },
50
50
  disabled: { type: Boolean, required: true },
51
51
  generateLabels: { type: Boolean, default: false },
52
- firstInRow: { type: Boolean, default: false },
53
- lastInRow: { type: Boolean, default: false }
52
+ verticalLabels: { type: Boolean, default: false }
54
53
  },
55
54
 
56
55
  data() {
@@ -69,13 +68,7 @@ export default DitoComponent.component('DitoContainer', {
69
68
  },
70
69
 
71
70
  hasLabel() {
72
- const { label } = this.schema
73
- return (
74
- label !== false && (
75
- !!label ||
76
- this.generateLabels && this.typeComponent?.generateLabel
77
- )
78
- )
71
+ return hasLabel(this.schema, this.generateLabels)
79
72
  },
80
73
 
81
74
  label() {
@@ -162,12 +155,8 @@ export default DitoComponent.component('DitoContainer', {
162
155
  const prefix = 'dito-container'
163
156
  return {
164
157
  [`${prefix}--single`]: this.single,
165
- [`${prefix}--has-label`]: this.hasLabel,
166
- [`${prefix}--aligned`]: keepAligned(this.schema),
158
+ [`${prefix}--label-vertical`]: this.verticalLabels,
167
159
  [`${prefix}--omit-padding`]: omitPadding(this.schema),
168
- [`${prefix}--first-in-row`]: this.firstInRow,
169
- [`${prefix}--last-in-row`]: this.lastInRow,
170
- [`${prefix}--alone-in-row`]: this.firstInRow && this.lastInRow,
171
160
  ...(
172
161
  isString(containerClass)
173
162
  ? { [containerClass]: true }
@@ -189,12 +178,11 @@ export default DitoComponent.component('DitoContainer', {
189
178
  },
190
179
 
191
180
  componentClass() {
192
- const basisIsAuto = this.flexBasis === 'auto'
193
181
  return {
194
182
  // TODO: BEM?
195
183
  'dito-single': this.single,
196
184
  'dito-disabled': this.componentDisabled,
197
- 'dito-width-fill': !basisIsAuto || this.width === 'fill',
185
+ 'dito-width-fill': this.width === 'fill' || this.flexBasis !== 'auto',
198
186
  'dito-width-grow': this.flexGrow,
199
187
  'dito-width-shrink': this.flexShrink,
200
188
  'dito-has-errors': !!this.errors
@@ -214,8 +202,6 @@ export default DitoComponent.component('DitoContainer', {
214
202
  @import '../styles/_imports';
215
203
 
216
204
  .dito-container {
217
- $self: &;
218
-
219
205
  position: relative;
220
206
  display: flex;
221
207
  flex-flow: column;
@@ -229,6 +215,12 @@ export default DitoComponent.component('DitoContainer', {
229
215
  // percentages in flex-basis to work.
230
216
  padding: $form-spacing $form-spacing-half;
231
217
 
218
+ .dito-sidebar & {
219
+ @container (width < #{$sidebar-max-width - 2 * $content-padding}) {
220
+ flex-grow: 1 !important;
221
+ }
222
+ }
223
+
232
224
  &:empty {
233
225
  padding: 0;
234
226
  }
@@ -239,25 +231,11 @@ export default DitoComponent.component('DitoContainer', {
239
231
  padding: 0;
240
232
  }
241
233
 
242
- &--aligned {
243
- // For components with labels, align the label at the top and the component
244
- // at the bottom.
245
- --justify: space-between;
246
-
247
- &:has(> :only-child) {
248
- // But if there is no label, still align the component to the bottom.
249
- --justify: flex-end;
250
- }
251
-
252
- &:not(#{$self}--alone-in-row) {
253
- // Now only apply alignment if there are neighbouring components no the
254
- // same row that also align.
255
- // Look ahead:
256
- &:not(#{$self}--last-in-row) + #{&}:not(#{$self}--first-in-row),
257
- // Look behind:
258
- &:not(#{$self}--last-in-row):has(+ #{&}:not(#{$self}--first-in-row)) {
259
- justify-content: var(--justify);
260
- }
234
+ &--label-vertical {
235
+ // For components without labels in rows with other components that have
236
+ // labels, add some spacing to the top to align with the other components:
237
+ > .dito-component:first-child {
238
+ margin-top: $line-height * $font-size + $form-spacing-half;
261
239
  }
262
240
  }
263
241
 
@@ -147,7 +147,9 @@ export default DitoComponent.component('DitoDialog', {
147
147
  },
148
148
 
149
149
  cancel() {
150
- this.resolve(null)
150
+ // When cancelling, resolve as `undefined` so we can have dialogs
151
+ // returning null as a defined value as well.
152
+ this.resolve(undefined)
151
153
  },
152
154
 
153
155
  close() {
@@ -20,7 +20,7 @@ nav.dito-header
20
20
  v-if="isLoading"
21
21
  )
22
22
  //- Teleport target for `.dito-schema-header`:
23
- .dito-header__menu
23
+ .dito-title
24
24
  slot
25
25
  </template>
26
26
 
@@ -88,19 +88,27 @@ export default DitoComponent.component('DitoHeader', {
88
88
  display: inline-block;
89
89
  padding: $header-padding;
90
90
  color: $color-white;
91
+
92
+ &:empty {
93
+ &::after {
94
+ content: '\200b';
95
+ }
96
+ }
91
97
  }
92
98
 
93
99
  .dito-trail {
94
100
  display: flex;
95
101
  box-sizing: border-box;
96
102
  height: 3em;
97
- width: 100%;
98
- max-width: $content-width + $content-padding;
99
103
 
100
104
  ul {
101
105
  display: flex;
102
106
  }
103
107
 
108
+ li {
109
+ white-space: nowrap;
110
+ }
111
+
104
112
  a {
105
113
  position: relative;
106
114
  display: block;
@@ -152,16 +160,5 @@ export default DitoComponent.component('DitoHeader', {
152
160
  border-radius: 100%;
153
161
  }
154
162
  }
155
-
156
- .dito-account,
157
- .dito-login {
158
- position: absolute;
159
- top: 0;
160
- cursor: pointer;
161
- }
162
-
163
- .dito-account {
164
- left: $content-width + $content-padding * 2;
165
- }
166
163
  }
167
164
  </style>
@@ -98,7 +98,11 @@ export default DitoComponent.component('DitoLabel', {
98
98
  // Vertically center all items in the label, e.g. chevron, edit-buttons.
99
99
  align-items: center;
100
100
  padding: var(--label-padding);
101
- margin: 0 0 $form-spacing-half 0;
101
+ margin: 0 $form-spacing-half $form-spacing-half 0;
102
+
103
+ .dito-container:not(.dito-container--label-vertical) > & {
104
+ margin-bottom: 0;
105
+ }
102
106
 
103
107
  &__inner {
104
108
  display: flex;
@@ -175,10 +179,10 @@ a.dito-label {
175
179
  .dito-schema-compact {
176
180
  > .dito-schema-content {
177
181
  > .dito-pane {
178
- > .dito-container {
182
+ > .dito-container:not(.dito-container--label-vertical) {
179
183
  display: flex;
180
184
  flex-flow: row wrap;
181
- align-items: baseline;
185
+ align-items: center;
182
186
  }
183
187
  }
184
188
  }
@@ -0,0 +1,40 @@
1
+ <template lang="pug">
2
+ nav.dito-navigation.dito-scroll-parent
3
+ h1
4
+ RouterLink.dito-link(to="/") {{ appState.title }}
5
+ DitoMenu.dito-scroll(:items="views")
6
+ </template>
7
+
8
+ <script>
9
+ import DitoComponent from '../DitoComponent.js'
10
+
11
+ // @vue/component
12
+ export default DitoComponent.component('DitoNavigation', {})
13
+ </script>
14
+
15
+ <style lang="scss">
16
+ @import '../styles/_imports';
17
+
18
+ .dito-navigation {
19
+ @include user-select(none);
20
+
21
+ flex: 0 0 min-content;
22
+ font-size: $menu-font-size;
23
+ white-space: nowrap;
24
+ background: $color-lighter;
25
+
26
+ h1 {
27
+ display: block;
28
+ line-height: $header-line-height;
29
+ font-weight: bold;
30
+ background: $color-darker;
31
+ border-right: $border-width solid $color-darkest;
32
+ color: $color-white;
33
+
34
+ .dito-link {
35
+ display: block;
36
+ padding: $header-padding;
37
+ }
38
+ }
39
+ }
40
+ </style>
@@ -22,7 +22,7 @@
22
22
  DitoContainer(
23
23
  v-if="shouldRenderSchema(schema)"
24
24
  :key="nestedDataPath"
25
- v-resize="event => onResize(index, event)"
25
+ v-resize="event => onResizeContainer(index, event)"
26
26
  :schema="schema"
27
27
  :dataPath="dataPath"
28
28
  :data="data"
@@ -32,8 +32,7 @@
32
32
  :nested="nested"
33
33
  :disabled="disabled"
34
34
  :generateLabels="generateLabels"
35
- :firstInRow="schema.break === 'before' || isFirstInRow(index)"
36
- :lastInRow="schema.break === 'after' || isLastInRow(index)"
35
+ :verticalLabels="isInLabeledRow(index)"
37
36
  )
38
37
  .dito-break(
39
38
  v-if="schema.break === 'after'"
@@ -124,6 +123,66 @@ export default DitoComponent.component('DitoPane', {
124
123
 
125
124
  isSingleComponent() {
126
125
  return this.single && this.componentSchemas.length === 1
126
+ },
127
+
128
+ verticalLabelsByIndices() {
129
+ const { positions } = this
130
+
131
+ const isLastInRow = index => (
132
+ positions[index] && (
133
+ index === positions.length - 1 ||
134
+ findNextPosition(index).top > positions[index].top
135
+ )
136
+ )
137
+
138
+ const findNextPosition = index => {
139
+ for (let i = index + 1; i < positions.length; i++) {
140
+ if (positions[i]) return positions[i]
141
+ }
142
+ return 0
143
+ }
144
+
145
+ const rows = []
146
+ let row = []
147
+ for (let index = 0; index < positions.length; index++) {
148
+ row.push(index)
149
+ if (isLastInRow(index)) {
150
+ rows.push(row)
151
+ row = []
152
+ }
153
+ }
154
+ if (row.length > 0) {
155
+ rows.push(row)
156
+ }
157
+
158
+ const verticalLabelsByIndices = []
159
+
160
+ for (const row of rows) {
161
+ let hasLabelsInRow = false
162
+ for (const index of row) {
163
+ const position = this.positions[index]
164
+ if (
165
+ position?.height > 4 &&
166
+ position.node.querySelector(':scope > .dito-label')
167
+ ) {
168
+ // TODO: Handle nested schemas, e.g. 'section' or 'object' and
169
+ // detect labels there too.
170
+ hasLabelsInRow = true
171
+ break
172
+ }
173
+ }
174
+ for (const index of row) {
175
+ verticalLabelsByIndices[index] = hasLabelsInRow
176
+ }
177
+ }
178
+
179
+ return verticalLabelsByIndices
180
+ }
181
+ },
182
+
183
+ watch: {
184
+ 'componentSchemas.length'(length) {
185
+ this.positions.length = length
127
186
  }
128
187
  },
129
188
 
@@ -146,66 +205,45 @@ export default DitoComponent.component('DitoPane', {
146
205
  }
147
206
  },
148
207
 
149
- onResize(index, { target }) {
208
+ onResizeContainer(index, { target }) {
150
209
  const { y, width, height } = target.getBoundingClientRect()
151
- this.positions[index] = width > 0 && height > 0 ? y : null
152
- },
153
-
154
- isFirstInRow(index) {
155
- const { positions } = this
156
- return (
157
- positions[index] !== null && (
158
- index === 0 ||
159
- (findNextPosition(positions, index, -1, Infinity) < positions[index])
160
- )
161
- )
210
+ this.positions[index] =
211
+ width > 0 && height > 0
212
+ ? {
213
+ top: y,
214
+ height: height / parseFloat(getComputedStyle(target).fontSize),
215
+ node: target
216
+ }
217
+ : null
162
218
  },
163
219
 
164
- isLastInRow(index) {
165
- const { positions } = this
166
- return (
167
- positions[index] !== null && (
168
- index === positions.length - 1 ||
169
- findNextPosition(positions, index, +1, 0) > positions[index]
170
- )
171
- )
220
+ isInLabeledRow(index) {
221
+ return !!this.verticalLabelsByIndices[index]
172
222
  }
173
223
  }
174
224
  })
175
-
176
- function findNextPosition(positions, index, step, fallback) {
177
- for (let i = index + step; i >= 0 && i < positions.length; i += step) {
178
- const position = positions[i]
179
- if (position) return position
180
- }
181
- return fallback
182
- }
183
225
  </script>
184
226
 
185
227
  <style lang="scss">
186
228
  @import '../styles/_imports';
187
229
 
188
230
  .dito-pane {
189
- $max-width: $content-width + 2 * $content-padding;
190
-
191
231
  display: flex;
192
232
  position: relative;
193
233
  flex-flow: row wrap;
194
234
  align-content: flex-start;
195
235
  align-items: baseline;
196
- padding: $content-padding;
197
236
  // Remove the padding added by `.dito-container` inside `.dito-pane`:
198
- margin: (-$form-spacing) (-$form-spacing-half);
199
- // Add removed horizontal margin again to max-width:
200
- max-width: $max-width + 2 * $form-spacing-half;
237
+ padding: ($content-padding - $form-spacing)
238
+ ($content-padding - $form-spacing-half);
239
+ max-width: calc(var(--max-content-width) + $form-spacing);
201
240
  // Use `flex: 0%` for all `.dito-pane` except `.dito-pane-main`,
202
241
  // so that the `.dito-buttons-main` can be moved all the way to the bottom.
203
242
  flex: 0%;
204
243
 
205
244
  &--single {
206
- // Clear settings from above.
207
- margin: 0;
208
- max-width: $max-width;
245
+ // Clear margin from above.
246
+ padding: $content-padding;
209
247
  }
210
248
 
211
249
  &.dito-pane-main {
@@ -247,8 +247,6 @@ export default DitoComponent.component('DitoPanel', {
247
247
  }
248
248
 
249
249
  .dito-label {
250
- margin: 0;
251
-
252
250
  label {
253
251
  font-weight: normal;
254
252
  }
@@ -45,7 +45,9 @@ export default DitoComponent.component('DitoPanels', {
45
45
  @import '../styles/_imports';
46
46
 
47
47
  .dito-panels {
48
- max-width: $content-sidebar-width;
49
- min-width: calc($content-sidebar-width / 2);
48
+ padding: $content-padding;
49
+ padding-left: $form-spacing;
50
+ // For the `@container` rule in `.dito-container` to work:
51
+ container-type: inline-size;
50
52
  }
51
53
  </style>
@@ -20,21 +20,25 @@
20
20
  :settings="dialog.settings"
21
21
  @remove="removeDialog(key)"
22
22
  )
23
- DitoSidebar
24
- main.dito-page.dito-scroll-parent
23
+ DitoNavigation
24
+ main.dito-page.dito-scroll-parent(:class="appState.pageClass")
25
25
  DitoHeader(
26
26
  :spinner="options.spinner"
27
27
  :isLoading="isLoading"
28
28
  )
29
- DitoAccount(
30
- v-if="user"
31
- )
32
- a.dito-login(
33
- v-else-if="allowLogin"
34
- @click="rootComponent.login()"
35
- )
36
- span Login
37
29
  RouterView
30
+ DitoSidebar
31
+ DitoAccount(
32
+ v-if="user"
33
+ )
34
+ a.dito-login(
35
+ v-else-if="allowLogin"
36
+ @click="rootComponent.login()"
37
+ )
38
+ span Login
39
+ .dito-fill
40
+ .dito-header
41
+ span
38
42
  </template>
39
43
 
40
44
  <script>
@@ -467,12 +471,34 @@ function addRoutes(router, routes) {
467
471
  display: flex;
468
472
  }
469
473
 
470
- .dito-root {
471
- .dito-page {
472
- background: $content-color-background;
474
+ .dito-page {
475
+ --max-content-width: #{$content-width};
476
+
477
+ flex: 1 1 var(--max-content-width);
478
+ background: $content-color-background;
479
+ max-width: calc(var(--max-content-width) + 2 * #{$content-padding});
480
+
481
+ &--wide {
482
+ --max-content-width: #{$content-width-wide};
483
+ }
484
+ }
485
+
486
+ .dito-fill {
487
+ flex: 1;
488
+
489
+ .dito-header {
490
+ span {
491
+ padding-left: 0;
492
+ padding-right: 0;
493
+ }
473
494
  }
474
495
  }
475
496
 
497
+ .dito-account,
498
+ .dito-login {
499
+ cursor: pointer;
500
+ }
501
+
476
502
  .dito-drag-overlay {
477
503
  position: fixed;
478
504
  top: 0;
@@ -8,7 +8,7 @@ slot(name="before")
8
8
  :class="{ 'dito-scroll': scrollable }"
9
9
  )
10
10
  Teleport(
11
- to=".dito-header__menu"
11
+ to=".dito-title"
12
12
  :disabled="!headerInMenu"
13
13
  )
14
14
  .dito-schema-header(
@@ -81,8 +81,9 @@ slot(name="before")
81
81
  v-if="!hasLabel"
82
82
  name="edit-buttons"
83
83
  )
84
- template(
84
+ Teleport(
85
85
  v-else-if="isPopulated"
86
+ to=".dito-sidebar"
86
87
  )
87
88
  DitoPanels(
88
89
  :class="{ 'dito-scroll': scrollable }"
@@ -116,7 +117,7 @@ import {
116
117
  processData,
117
118
  isForm
118
119
  } from '../utils/schema.js'
119
- import { getStoreAccessor } from '../utils/accessor.js'
120
+ import { getSchemaAccessor, getStoreAccessor } from '../utils/accessor.js'
120
121
 
121
122
  // @vue/component
122
123
  export default DitoComponent.component('DitoSchema', {
@@ -334,7 +335,12 @@ export default DitoComponent.component('DitoSchema', {
334
335
 
335
336
  panelsByDataPath() {
336
337
  return this._listEntriesByDataPath(this.panelsRegistry)
337
- }
338
+ },
339
+
340
+ wide: getSchemaAccessor('wide', {
341
+ type: Boolean,
342
+ default: false
343
+ })
338
344
  },
339
345
 
340
346
  watch: {
@@ -385,11 +391,17 @@ export default DitoComponent.component('DitoSchema', {
385
391
  // Delegate change events through to parent schema:
386
392
  this.delegate('change', this.parentSchemaComponent)
387
393
  this.emitEvent('initialize') // Not `'create'`, since that's for data.
394
+ if (this.scrollable && this.wide) {
395
+ this.appState.pageClass = 'dito-page--wide'
396
+ }
388
397
  },
389
398
 
390
399
  unmounted() {
391
400
  this.emitEvent('destroy')
392
401
  this._register(false)
402
+ if (this.scrollable && this.wide) {
403
+ this.appState.pageClass = null
404
+ }
393
405
  },
394
406
 
395
407
  methods: {
@@ -745,15 +757,17 @@ export default DitoComponent.component('DitoSchema', {
745
757
 
746
758
  .dito-schema {
747
759
  box-sizing: border-box;
748
- // To display schema next to panels:
760
+ // To display schema next to buttons:
749
761
  display: flex;
762
+ align-items: flex-start;
750
763
  min-height: 100%;
751
764
 
752
765
  > .dito-schema-content {
753
- flex: 1 1 100%;
766
+ flex: 0 1 100%;
767
+ max-width: 100%;
754
768
  // So that schema buttons can be sticky to the bottom:
755
- display: grid;
756
- grid-template-rows: min-content;
769
+ display: flex;
770
+ flex-direction: column;
757
771
 
758
772
  > *:only-child {
759
773
  grid-row-end: none;
@@ -763,12 +777,9 @@ export default DitoComponent.component('DitoSchema', {
763
777
  // Eat up negative margin of the last child to prevent overscroll.
764
778
  content: '';
765
779
  }
766
-
767
- max-width: $content-width + 2 * $content-padding;
768
780
  }
769
781
 
770
- > .dito-buttons,
771
- > .dito-panels {
782
+ > .dito-buttons {
772
783
  flex: 1 1 0%;
773
784
  }
774
785
 
@@ -776,10 +787,6 @@ export default DitoComponent.component('DitoSchema', {
776
787
  margin-left: $form-spacing;
777
788
  }
778
789
 
779
- > .dito-panels {
780
- padding: $content-padding $content-padding $content-padding 0;
781
- }
782
-
783
790
  // Display a ruler between tabbed components and towards the .dito-buttons
784
791
  .dito-pane-tab + .dito-pane-main {
785
792
  &::before {
@@ -824,7 +831,6 @@ export default DitoComponent.component('DitoSchema', {
824
831
  position: absolute;
825
832
  height: $header-height;
826
833
  padding: 0 $header-padding-hor;
827
- max-width: $content-width;
828
834
  top: 0;
829
835
  left: 0;
830
836
  right: 0;