@radio-garden/ditojs-admin 2.85.2-0.5067ad799
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/README.md +180 -0
- package/dist/dito-admin.css +1 -0
- package/dist/dito-admin.es.js +12106 -0
- package/dist/dito-admin.umd.js +7 -0
- package/package.json +96 -0
- package/src/DitoAdmin.js +293 -0
- package/src/DitoComponent.js +34 -0
- package/src/DitoContext.js +318 -0
- package/src/DitoTypeComponent.js +42 -0
- package/src/DitoUser.js +12 -0
- package/src/appState.js +12 -0
- package/src/components/DitoAccount.vue +60 -0
- package/src/components/DitoAffix.vue +68 -0
- package/src/components/DitoAffixes.vue +200 -0
- package/src/components/DitoButtons.vue +80 -0
- package/src/components/DitoClipboard.vue +186 -0
- package/src/components/DitoContainer.vue +374 -0
- package/src/components/DitoCreateButton.vue +146 -0
- package/src/components/DitoDialog.vue +242 -0
- package/src/components/DitoDraggable.vue +117 -0
- package/src/components/DitoEditButtons.vue +135 -0
- package/src/components/DitoErrors.vue +83 -0
- package/src/components/DitoForm.vue +521 -0
- package/src/components/DitoFormInner.vue +26 -0
- package/src/components/DitoFormNested.vue +17 -0
- package/src/components/DitoHeader.vue +84 -0
- package/src/components/DitoLabel.vue +200 -0
- package/src/components/DitoMenu.vue +186 -0
- package/src/components/DitoNavigation.vue +40 -0
- package/src/components/DitoNotifications.vue +170 -0
- package/src/components/DitoPagination.vue +42 -0
- package/src/components/DitoPane.vue +334 -0
- package/src/components/DitoPanel.vue +256 -0
- package/src/components/DitoPanels.vue +61 -0
- package/src/components/DitoRoot.vue +524 -0
- package/src/components/DitoSchema.vue +846 -0
- package/src/components/DitoSchemaInlined.vue +97 -0
- package/src/components/DitoScopes.vue +76 -0
- package/src/components/DitoSidebar.vue +50 -0
- package/src/components/DitoSpinner.vue +95 -0
- package/src/components/DitoTableCell.vue +64 -0
- package/src/components/DitoTableHead.vue +121 -0
- package/src/components/DitoTabs.vue +103 -0
- package/src/components/DitoTrail.vue +124 -0
- package/src/components/DitoTreeItem.vue +420 -0
- package/src/components/DitoUploadFile.vue +199 -0
- package/src/components/DitoVNode.vue +14 -0
- package/src/components/DitoView.vue +143 -0
- package/src/components/index.js +42 -0
- package/src/directives/resize.js +83 -0
- package/src/index.js +1 -0
- package/src/mixins/ContextMixin.js +68 -0
- package/src/mixins/DataMixin.js +131 -0
- package/src/mixins/DitoMixin.js +591 -0
- package/src/mixins/DomMixin.js +29 -0
- package/src/mixins/EmitterMixin.js +158 -0
- package/src/mixins/ItemMixin.js +144 -0
- package/src/mixins/LoadingMixin.js +23 -0
- package/src/mixins/NumberMixin.js +118 -0
- package/src/mixins/OptionsMixin.js +304 -0
- package/src/mixins/PulldownMixin.js +63 -0
- package/src/mixins/ResourceMixin.js +398 -0
- package/src/mixins/RouteMixin.js +190 -0
- package/src/mixins/SchemaParentMixin.js +33 -0
- package/src/mixins/SortableMixin.js +49 -0
- package/src/mixins/SourceMixin.js +734 -0
- package/src/mixins/TextMixin.js +26 -0
- package/src/mixins/TypeMixin.js +280 -0
- package/src/mixins/ValidationMixin.js +119 -0
- package/src/mixins/ValidatorMixin.js +57 -0
- package/src/mixins/ValueMixin.js +31 -0
- package/src/styles/_base.scss +17 -0
- package/src/styles/_button.scss +191 -0
- package/src/styles/_imports.scss +3 -0
- package/src/styles/_info.scss +19 -0
- package/src/styles/_layout.scss +19 -0
- package/src/styles/_pulldown.scss +38 -0
- package/src/styles/_scroll.scss +13 -0
- package/src/styles/_settings.scss +88 -0
- package/src/styles/_table.scss +223 -0
- package/src/styles/_tippy.scss +45 -0
- package/src/styles/style.scss +9 -0
- package/src/types/DitoTypeButton.vue +143 -0
- package/src/types/DitoTypeCheckbox.vue +27 -0
- package/src/types/DitoTypeCheckboxes.vue +65 -0
- package/src/types/DitoTypeCode.vue +199 -0
- package/src/types/DitoTypeColor.vue +272 -0
- package/src/types/DitoTypeComponent.vue +31 -0
- package/src/types/DitoTypeComputed.vue +50 -0
- package/src/types/DitoTypeDate.vue +99 -0
- package/src/types/DitoTypeLabel.vue +23 -0
- package/src/types/DitoTypeList.vue +364 -0
- package/src/types/DitoTypeMarkup.vue +700 -0
- package/src/types/DitoTypeMultiselect.vue +522 -0
- package/src/types/DitoTypeNumber.vue +66 -0
- package/src/types/DitoTypeObject.vue +136 -0
- package/src/types/DitoTypePanel.vue +18 -0
- package/src/types/DitoTypeProgress.vue +40 -0
- package/src/types/DitoTypeRadio.vue +45 -0
- package/src/types/DitoTypeSection.vue +80 -0
- package/src/types/DitoTypeSelect.vue +133 -0
- package/src/types/DitoTypeSlider.vue +66 -0
- package/src/types/DitoTypeSpacer.vue +11 -0
- package/src/types/DitoTypeSwitch.vue +40 -0
- package/src/types/DitoTypeText.vue +101 -0
- package/src/types/DitoTypeTextarea.vue +48 -0
- package/src/types/DitoTypeTreeList.vue +193 -0
- package/src/types/DitoTypeUpload.vue +503 -0
- package/src/types/index.js +30 -0
- package/src/utils/SchemaGraph.js +147 -0
- package/src/utils/accessor.js +75 -0
- package/src/utils/agent.js +47 -0
- package/src/utils/data.js +92 -0
- package/src/utils/filter.js +266 -0
- package/src/utils/math.js +14 -0
- package/src/utils/options.js +48 -0
- package/src/utils/path.js +5 -0
- package/src/utils/resource.js +44 -0
- package/src/utils/route.js +53 -0
- package/src/utils/schema.js +1121 -0
- package/src/utils/type.js +81 -0
- package/src/utils/uid.js +15 -0
- package/src/utils/units.js +5 -0
- package/src/validators/_creditcard.js +6 -0
- package/src/validators/_decimals.js +11 -0
- package/src/validators/_domain.js +6 -0
- package/src/validators/_email.js +6 -0
- package/src/validators/_hostname.js +6 -0
- package/src/validators/_integer.js +6 -0
- package/src/validators/_max.js +6 -0
- package/src/validators/_min.js +6 -0
- package/src/validators/_password.js +5 -0
- package/src/validators/_range.js +6 -0
- package/src/validators/_required.js +9 -0
- package/src/validators/_url.js +6 -0
- package/src/validators/index.js +12 -0
- package/src/verbs.js +17 -0
- package/types/index.d.ts +3298 -0
- package/types/tests/admin.test-d.ts +27 -0
- package/types/tests/component-buttons.test-d.ts +44 -0
- package/types/tests/component-list.test-d.ts +159 -0
- package/types/tests/component-misc.test-d.ts +137 -0
- package/types/tests/component-object.test-d.ts +69 -0
- package/types/tests/component-section.test-d.ts +174 -0
- package/types/tests/component-select.test-d.ts +107 -0
- package/types/tests/components.test-d.ts +81 -0
- package/types/tests/context.test-d.ts +31 -0
- package/types/tests/fixtures.ts +24 -0
- package/types/tests/form.test-d.ts +109 -0
- package/types/tests/instance.test-d.ts +20 -0
- package/types/tests/schema-features.test-d.ts +402 -0
- package/types/tests/variance.test-d.ts +125 -0
- package/types/tests/view.test-d.ts +146 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
<template lang="pug">
|
|
2
|
+
DitoSchema.dito-schema-inlined(
|
|
3
|
+
:schema="schema"
|
|
4
|
+
:dataPath="dataPath"
|
|
5
|
+
:data="data"
|
|
6
|
+
:meta="meta"
|
|
7
|
+
:store="store"
|
|
8
|
+
:label="isCompact ? null : label"
|
|
9
|
+
:info="info"
|
|
10
|
+
:padding="padding ?? 'inlined'"
|
|
11
|
+
:inlined="true"
|
|
12
|
+
:disabled="disabled"
|
|
13
|
+
:compact="isCompact"
|
|
14
|
+
:collapsed="collapsed"
|
|
15
|
+
:collapsible="collapsible"
|
|
16
|
+
:generateLabels="!isCompact"
|
|
17
|
+
:labelNode="labelNode"
|
|
18
|
+
:accumulatedBasis="accumulatedBasis"
|
|
19
|
+
)
|
|
20
|
+
//- Render dito-edit-buttons for inlined schemas separately from all
|
|
21
|
+
//- others in `TypeList` as a scope, for better handling of layout.
|
|
22
|
+
template(#edit-buttons)
|
|
23
|
+
DitoEditButtons(
|
|
24
|
+
v-if="deletable || draggable || editable"
|
|
25
|
+
:schema="schema"
|
|
26
|
+
:dataPath="dataPath"
|
|
27
|
+
:data="data"
|
|
28
|
+
:meta="meta"
|
|
29
|
+
:store="store"
|
|
30
|
+
:disabled="disabled"
|
|
31
|
+
:deletable="deletable"
|
|
32
|
+
:draggable="draggable"
|
|
33
|
+
:editable="editable"
|
|
34
|
+
:editPath="editPath"
|
|
35
|
+
@delete="$emit('delete')"
|
|
36
|
+
)
|
|
37
|
+
</template>
|
|
38
|
+
|
|
39
|
+
<script>
|
|
40
|
+
import DitoComponent from '../DitoComponent.js'
|
|
41
|
+
import { isCompact } from '../utils/schema.js'
|
|
42
|
+
// @vue/component
|
|
43
|
+
export default DitoComponent.component('DitoSchemaInlined', {
|
|
44
|
+
emits: ['delete'],
|
|
45
|
+
|
|
46
|
+
props: {
|
|
47
|
+
schema: { type: Object, required: true },
|
|
48
|
+
dataPath: { type: String, required: true },
|
|
49
|
+
data: { type: Object, required: true },
|
|
50
|
+
meta: { type: Object, required: true },
|
|
51
|
+
store: { type: Object, required: true },
|
|
52
|
+
label: { type: [String, Object], default: null },
|
|
53
|
+
info: { type: String, default: null },
|
|
54
|
+
padding: { type: String, default: null },
|
|
55
|
+
disabled: { type: Boolean, required: true },
|
|
56
|
+
collapsed: { type: Boolean, default: false },
|
|
57
|
+
collapsible: { type: Boolean, default: false },
|
|
58
|
+
draggable: { type: Boolean, default: false },
|
|
59
|
+
editable: { type: Boolean, default: false },
|
|
60
|
+
deletable: { type: Boolean, default: false },
|
|
61
|
+
editPath: { type: String, default: null },
|
|
62
|
+
labelNode: { type: HTMLElement, default: null },
|
|
63
|
+
accumulatedBasis: { type: Number, default: null }
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
computed: {
|
|
67
|
+
isCompact() {
|
|
68
|
+
return isCompact(this.schema)
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
hasLabel() {
|
|
72
|
+
return !this.isCompact && !!this.label
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
</script>
|
|
77
|
+
|
|
78
|
+
<style lang="scss">
|
|
79
|
+
@import '../styles/_imports';
|
|
80
|
+
|
|
81
|
+
.dito-schema-inlined {
|
|
82
|
+
// Use grid layout for two reasons: For `TransitionHeight` to work smoothly,
|
|
83
|
+
// and to align the header above the content when the header is not teleported
|
|
84
|
+
// outside of the schema.
|
|
85
|
+
display: grid;
|
|
86
|
+
grid-template-rows: min-content;
|
|
87
|
+
grid-template-columns: 100%;
|
|
88
|
+
|
|
89
|
+
&:not(:hover, .dito-schema--open) {
|
|
90
|
+
> .dito-schema-header {
|
|
91
|
+
> .dito-clipboard {
|
|
92
|
+
display: none;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
</style>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<template lang="pug">
|
|
2
|
+
.dito-scopes
|
|
3
|
+
RouterLink(
|
|
4
|
+
v-for="(scope, key) in scopes"
|
|
5
|
+
:key="key"
|
|
6
|
+
v-slot="{ navigate }"
|
|
7
|
+
:to="getScopeLink(scope)"
|
|
8
|
+
custom
|
|
9
|
+
)
|
|
10
|
+
button.dito-button(
|
|
11
|
+
type="button"
|
|
12
|
+
:class="{ 'dito-button--selected': scope.name === query.scope }"
|
|
13
|
+
:title="scope.hint || getLabel(scope)"
|
|
14
|
+
@click="navigate"
|
|
15
|
+
) {{ getLabel(scope) }}
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script>
|
|
19
|
+
import DitoComponent from '../DitoComponent.js'
|
|
20
|
+
|
|
21
|
+
// @vue/component
|
|
22
|
+
export default DitoComponent.component('DitoScopes', {
|
|
23
|
+
props: {
|
|
24
|
+
query: { type: Object, required: true },
|
|
25
|
+
scopes: { type: Object, required: true }
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
methods: {
|
|
29
|
+
getScopeLink(scope) {
|
|
30
|
+
const query = { ...this.query, scope: scope.name }
|
|
31
|
+
if (query.page) {
|
|
32
|
+
query.page = 0
|
|
33
|
+
}
|
|
34
|
+
return this.getQueryLink(query)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<style lang="scss">
|
|
41
|
+
@import '../styles/_imports';
|
|
42
|
+
|
|
43
|
+
.dito-scopes {
|
|
44
|
+
white-space: nowrap;
|
|
45
|
+
display: flex;
|
|
46
|
+
|
|
47
|
+
.dito-button {
|
|
48
|
+
@include ellipsis;
|
|
49
|
+
|
|
50
|
+
border-radius: 0;
|
|
51
|
+
// A bit more than the width of ellipsis, to prevent replacing short words
|
|
52
|
+
// with ellipsis.
|
|
53
|
+
min-width: 3em;
|
|
54
|
+
flex: 0 1 auto;
|
|
55
|
+
|
|
56
|
+
&:first-child {
|
|
57
|
+
border-top-left-radius: 1em;
|
|
58
|
+
border-bottom-left-radius: 1em;
|
|
59
|
+
padding-left: 1em;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
&:last-child {
|
|
63
|
+
border-top-right-radius: 1em;
|
|
64
|
+
border-bottom-right-radius: 1em;
|
|
65
|
+
padding-right: 1em;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
& + .dito-button {
|
|
69
|
+
margin-left: -1px;
|
|
70
|
+
} // Don't cover the focused border of buttons:
|
|
71
|
+
&:focus {
|
|
72
|
+
z-index: 1;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
</style>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<template lang="pug">
|
|
2
|
+
aside.dito-sidebar.dito-scroll-parent(
|
|
3
|
+
v-resize="onResizeSidebar"
|
|
4
|
+
:class="classes"
|
|
5
|
+
)
|
|
6
|
+
nav.dito-header
|
|
7
|
+
slot
|
|
8
|
+
.dito-sidebar__teleport.dito-scroll
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script>
|
|
12
|
+
import DitoComponent from '../DitoComponent.js'
|
|
13
|
+
|
|
14
|
+
// @vue/component
|
|
15
|
+
export default DitoComponent.component('DitoSidebar', {
|
|
16
|
+
data() {
|
|
17
|
+
return {
|
|
18
|
+
sidebarWidth: 0
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
computed: {
|
|
23
|
+
classes() {
|
|
24
|
+
const prefix = 'dito-sidebar'
|
|
25
|
+
// NOTE: Keep synced with $sidebar-max-width in SCSS:
|
|
26
|
+
const sidebarWidth = 360
|
|
27
|
+
return {
|
|
28
|
+
[`${prefix}--width-99`]: this.sidebarWidth < sidebarWidth,
|
|
29
|
+
[`${prefix}--width-60`]: this.sidebarWidth <= sidebarWidth * 0.6
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
methods: {
|
|
35
|
+
onResizeSidebar({ contentRect: { width } }) {
|
|
36
|
+
this.sidebarWidth = width
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<style lang="scss">
|
|
43
|
+
@import '../styles/_imports';
|
|
44
|
+
|
|
45
|
+
.dito-sidebar {
|
|
46
|
+
flex: 0 1 $sidebar-max-width;
|
|
47
|
+
max-width: $sidebar-max-width;
|
|
48
|
+
min-width: $sidebar-min-width;
|
|
49
|
+
}
|
|
50
|
+
</style>
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
<template lang="pug">
|
|
2
|
+
.dito-spinner(
|
|
3
|
+
v-show="loading"
|
|
4
|
+
:style="{ '--color': color, '--size': size, '--margin': margin }"
|
|
5
|
+
)
|
|
6
|
+
.dito-spinner__pulse.dito-spinner__pulse1
|
|
7
|
+
.dito-spinner__pulse.dito-spinner__pulse2
|
|
8
|
+
.dito-spinner__pulse.dito-spinner__pulse3
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script>
|
|
12
|
+
import DitoComponent from '../DitoComponent.js'
|
|
13
|
+
|
|
14
|
+
// @vue/component
|
|
15
|
+
export default DitoComponent.component('DitoSpinner', {
|
|
16
|
+
props: {
|
|
17
|
+
loading: {
|
|
18
|
+
type: Boolean,
|
|
19
|
+
default: true
|
|
20
|
+
},
|
|
21
|
+
color: {
|
|
22
|
+
type: String,
|
|
23
|
+
default: null
|
|
24
|
+
},
|
|
25
|
+
size: {
|
|
26
|
+
type: String,
|
|
27
|
+
default: null
|
|
28
|
+
},
|
|
29
|
+
margin: {
|
|
30
|
+
type: String,
|
|
31
|
+
default: null
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<style lang="scss">
|
|
38
|
+
.dito-spinner {
|
|
39
|
+
--color: #999999;
|
|
40
|
+
--size: 8px;
|
|
41
|
+
--margin: 2px;
|
|
42
|
+
|
|
43
|
+
display: flex;
|
|
44
|
+
align-items: center;
|
|
45
|
+
|
|
46
|
+
&__pulse {
|
|
47
|
+
display: inline-block;
|
|
48
|
+
background: var(--color);
|
|
49
|
+
width: var(--size);
|
|
50
|
+
height: var(--size);
|
|
51
|
+
margin: var(--margin);
|
|
52
|
+
border-radius: 100%;
|
|
53
|
+
animation: dito-spinner-pulse 0.75s cubic-bezier(0.2, 0.68, 0.18, 1.08) 0s
|
|
54
|
+
infinite both;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
&__pulse1 {
|
|
58
|
+
animation-delay: 0.12s;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&__pulse2 {
|
|
62
|
+
animation-delay: 0.24s;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
&__pulse3 {
|
|
66
|
+
animation-delay: 0.36s;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@keyframes dito-spinner-pulse {
|
|
71
|
+
0%,
|
|
72
|
+
80% {
|
|
73
|
+
transform: scale(1);
|
|
74
|
+
opacity: 1;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
45% {
|
|
78
|
+
transform: scale(0.1);
|
|
79
|
+
opacity: 0.7;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@keyframes dito-spinner-pulse {
|
|
84
|
+
0%,
|
|
85
|
+
80% {
|
|
86
|
+
transform: scale(1);
|
|
87
|
+
opacity: 1;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
45% {
|
|
91
|
+
transform: scale(0.1);
|
|
92
|
+
opacity: 0.7;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
</style>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<template lang="pug">
|
|
2
|
+
td(
|
|
3
|
+
:class="cell.class"
|
|
4
|
+
:style="cell.style"
|
|
5
|
+
)
|
|
6
|
+
//- TODO: Implement inlined components in cell mode!
|
|
7
|
+
component(
|
|
8
|
+
v-if="cell.component"
|
|
9
|
+
:is="cell.component"
|
|
10
|
+
:schema="schema"
|
|
11
|
+
:dataPath="dataPath"
|
|
12
|
+
:data="data"
|
|
13
|
+
:meta="meta"
|
|
14
|
+
:store="store"
|
|
15
|
+
:nested="nested"
|
|
16
|
+
:disabled="disabled"
|
|
17
|
+
)
|
|
18
|
+
span(
|
|
19
|
+
v-else
|
|
20
|
+
v-html="renderCell(data)"
|
|
21
|
+
)
|
|
22
|
+
</template>
|
|
23
|
+
|
|
24
|
+
<script>
|
|
25
|
+
import DitoComponent from '../DitoComponent.js'
|
|
26
|
+
import DitoContext from '../DitoContext.js'
|
|
27
|
+
import ContextMixin from '../mixins/ContextMixin.js'
|
|
28
|
+
import { appendDataPath } from '../utils/data.js'
|
|
29
|
+
import { escapeHtml } from '@ditojs/utils'
|
|
30
|
+
|
|
31
|
+
// @vue/component
|
|
32
|
+
export default DitoComponent.component('DitoTableCell', {
|
|
33
|
+
mixins: [ContextMixin],
|
|
34
|
+
|
|
35
|
+
props: {
|
|
36
|
+
cell: { type: Object, required: true },
|
|
37
|
+
schema: { type: Object, required: true },
|
|
38
|
+
dataPath: { type: String, required: true },
|
|
39
|
+
data: { type: Object, required: true },
|
|
40
|
+
meta: { type: Object, required: true },
|
|
41
|
+
store: { type: Object, required: true },
|
|
42
|
+
nested: { type: Boolean, default: true },
|
|
43
|
+
disabled: { type: Boolean, default: false }
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
methods: {
|
|
47
|
+
renderCell(item) {
|
|
48
|
+
const { name, render } = this.cell
|
|
49
|
+
const value = item[name]
|
|
50
|
+
return render
|
|
51
|
+
? render.call(
|
|
52
|
+
this,
|
|
53
|
+
new DitoContext(this, {
|
|
54
|
+
name,
|
|
55
|
+
value,
|
|
56
|
+
data: item,
|
|
57
|
+
dataPath: appendDataPath(this.dataPath, name)
|
|
58
|
+
})
|
|
59
|
+
)
|
|
60
|
+
: escapeHtml(value)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
</script>
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
<template lang="pug">
|
|
2
|
+
thead.dito-table-head
|
|
3
|
+
tr
|
|
4
|
+
template(
|
|
5
|
+
v-for="column in columns"
|
|
6
|
+
)
|
|
7
|
+
th(
|
|
8
|
+
v-if="shouldRenderSchema(column)"
|
|
9
|
+
:class="getColumnClass(column)"
|
|
10
|
+
)
|
|
11
|
+
RouterLink(
|
|
12
|
+
v-if="column.sortable"
|
|
13
|
+
v-slot="{ navigate }"
|
|
14
|
+
:to="getSortLink(column)"
|
|
15
|
+
custom
|
|
16
|
+
)
|
|
17
|
+
button.dito-button(
|
|
18
|
+
type="button"
|
|
19
|
+
:class="getSortClass(column)"
|
|
20
|
+
@click="navigate"
|
|
21
|
+
)
|
|
22
|
+
.dito-button__order-arrows
|
|
23
|
+
span {{ getLabel(column) }}
|
|
24
|
+
span(
|
|
25
|
+
v-else
|
|
26
|
+
) {{ getLabel(column) }}
|
|
27
|
+
th(
|
|
28
|
+
v-if="hasEditButtons"
|
|
29
|
+
)
|
|
30
|
+
//- Empty <span> is needed for styling, see _table.scss
|
|
31
|
+
span
|
|
32
|
+
</template>
|
|
33
|
+
|
|
34
|
+
<script>
|
|
35
|
+
import DitoComponent from '../DitoComponent.js'
|
|
36
|
+
import { hyphenate } from '@ditojs/utils'
|
|
37
|
+
|
|
38
|
+
// @vue/component
|
|
39
|
+
export default DitoComponent.component('DitoTableHead', {
|
|
40
|
+
props: {
|
|
41
|
+
query: { type: Object, required: true },
|
|
42
|
+
columns: { type: Object, required: true },
|
|
43
|
+
hasEditButtons: { type: Boolean, required: true }
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
computed: {
|
|
47
|
+
sort() {
|
|
48
|
+
const order = (this.query.order || '').split(/\s+/)
|
|
49
|
+
return {
|
|
50
|
+
name: order[0],
|
|
51
|
+
order: order[1]
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
methods: {
|
|
57
|
+
getColumnClass(column) {
|
|
58
|
+
return `dito-column--${hyphenate(column.name)}`
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
getSortClass(column) {
|
|
62
|
+
return this.sort.name === column.name
|
|
63
|
+
? `dito-button--selected dito-button--order-${this.sort.order}`
|
|
64
|
+
: null
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
getSortLink(column) {
|
|
68
|
+
// Toggle order if the same column is clicked again.
|
|
69
|
+
const order =
|
|
70
|
+
this.sort.name === column.name && this.sort.order === 'asc'
|
|
71
|
+
? 'desc'
|
|
72
|
+
: 'asc'
|
|
73
|
+
return this.getQueryLink({
|
|
74
|
+
...this.query,
|
|
75
|
+
order: `${column.name} ${order}`
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
</script>
|
|
81
|
+
|
|
82
|
+
<style lang="scss">
|
|
83
|
+
@import '../styles/_imports';
|
|
84
|
+
|
|
85
|
+
.dito-table-head {
|
|
86
|
+
@include user-select(none);
|
|
87
|
+
|
|
88
|
+
tr {
|
|
89
|
+
th {
|
|
90
|
+
padding: 0;
|
|
91
|
+
font-weight: normal;
|
|
92
|
+
text-align: left;
|
|
93
|
+
white-space: nowrap;
|
|
94
|
+
|
|
95
|
+
.dito-button {
|
|
96
|
+
// Convention: Nested spans handle padding, see below
|
|
97
|
+
display: block; // Override default inline-flex positioning.
|
|
98
|
+
padding: 0;
|
|
99
|
+
width: 100%;
|
|
100
|
+
text-align: inherit;
|
|
101
|
+
border-radius: 0;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
span {
|
|
105
|
+
display: inline-block;
|
|
106
|
+
// Convention: Nested spans handle padding
|
|
107
|
+
padding: $input-padding;
|
|
108
|
+
|
|
109
|
+
&:empty::after {
|
|
110
|
+
// Prevent empty <th> from collapsing
|
|
111
|
+
content: '\200b'; // zero-width space;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
> span {
|
|
116
|
+
display: block;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
</style>
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
<template lang="pug">
|
|
2
|
+
.dito-tabs
|
|
3
|
+
template(
|
|
4
|
+
v-for="(tabSchema, key) in tabs"
|
|
5
|
+
)
|
|
6
|
+
a.dito-tabs__link(
|
|
7
|
+
v-if="shouldRenderSchema(tabSchema)"
|
|
8
|
+
:key="key"
|
|
9
|
+
:class="{ 'dito-tabs__link--active': modelValue === key }"
|
|
10
|
+
@click="$emit('update:modelValue', key)"
|
|
11
|
+
) {{ getLabel(tabSchema, key) }}
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script>
|
|
15
|
+
import DitoComponent from '../DitoComponent.js'
|
|
16
|
+
|
|
17
|
+
// @vue/component
|
|
18
|
+
export default DitoComponent.component('DitoTabs', {
|
|
19
|
+
emits: ['update:modelValue'],
|
|
20
|
+
props: {
|
|
21
|
+
tabs: { type: Object, default: null },
|
|
22
|
+
modelValue: { type: String, default: null }
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<style lang="scss">
|
|
28
|
+
@use 'sass:color';
|
|
29
|
+
@import '../styles/_imports';
|
|
30
|
+
|
|
31
|
+
.dito-tabs {
|
|
32
|
+
display: flex;
|
|
33
|
+
|
|
34
|
+
&__link {
|
|
35
|
+
@include user-select(none);
|
|
36
|
+
|
|
37
|
+
display: block;
|
|
38
|
+
white-space: nowrap;
|
|
39
|
+
|
|
40
|
+
&:hover {
|
|
41
|
+
background: $color-white;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// When in main header:
|
|
45
|
+
.dito-header & {
|
|
46
|
+
background: $color-light;
|
|
47
|
+
padding: $tab-padding-ver $tab-padding-hor;
|
|
48
|
+
margin-left: $tab-margin;
|
|
49
|
+
border-top-left-radius: $tab-radius;
|
|
50
|
+
border-top-right-radius: $tab-radius;
|
|
51
|
+
|
|
52
|
+
&:active {
|
|
53
|
+
background: $color-lightest;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
&--active {
|
|
57
|
+
background: $color-lightest;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// When inside a inline schema:
|
|
62
|
+
.dito-schema-inlined &,
|
|
63
|
+
.dito-label & {
|
|
64
|
+
background: $color-lighter;
|
|
65
|
+
border: $border-style;
|
|
66
|
+
padding: $input-padding;
|
|
67
|
+
margin-left: -$border-width;
|
|
68
|
+
white-space: nowrap;
|
|
69
|
+
|
|
70
|
+
&:first-child {
|
|
71
|
+
border-top-left-radius: $tab-radius;
|
|
72
|
+
border-bottom-left-radius: $tab-radius;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
&:last-child {
|
|
76
|
+
border-top-right-radius: $tab-radius;
|
|
77
|
+
border-bottom-right-radius: $tab-radius;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
&:active {
|
|
81
|
+
background: $color-lighter;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
&--active {
|
|
85
|
+
background: $color-active;
|
|
86
|
+
border-color: color.adjust($color-active, $lightness: -10%);
|
|
87
|
+
color: $color-white;
|
|
88
|
+
z-index: 1;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.dito-schema & {
|
|
94
|
+
// Push clipboard to the right in the flex layout, see:
|
|
95
|
+
// https://codepen.io/tholex/pen/hveBx/
|
|
96
|
+
margin-left: auto;
|
|
97
|
+
|
|
98
|
+
&:last-child {
|
|
99
|
+
margin-right: auto;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
</style>
|