@afeefa/vue-app 0.0.307 → 0.0.309
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/.afeefa/package/release/version.txt +1 -1
- package/package.json +1 -1
- package/src/components/APopup.vue +10 -5
- package/src-admin/components/StickyHeader.vue +5 -1
- package/src-admin/components/app/AppBarNavigation.vue +108 -0
- package/src-admin/components/app/AppBarTitle.vue +1 -1
- package/src-admin/components/detail/EditableDetailProperty.vue +4 -4
- package/src-admin/config/AdminConfig.js +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
0.0.
|
|
1
|
+
0.0.309
|
package/package.json
CHANGED
|
@@ -95,12 +95,17 @@ export default class APopup extends Mixins(CancelOnEscMixin, UsesPositionService
|
|
|
95
95
|
const popups = this.getContainer().children
|
|
96
96
|
let foundMyself = false
|
|
97
97
|
for (const popup of popups) {
|
|
98
|
-
if (foundMyself) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
98
|
+
if (foundMyself && popup.contains(target)) {
|
|
99
|
+
return true
|
|
100
|
+
}
|
|
101
|
+
if (!foundMyself) {
|
|
102
|
+
// wenn ich selbst ein popup bin, sind alle weiteren möglichen popus
|
|
103
|
+
// immer kind-popups von mir, wenn ich dort scrolle/clicke, soll ich
|
|
104
|
+
// selbst also offen bleiben
|
|
105
|
+
// wenn ich selbst ein kind-popup bin soll ich bei scroll/click auf ein
|
|
106
|
+
// parent allerdings wieder selbst zugehen
|
|
107
|
+
foundMyself = popup === this.$el
|
|
102
108
|
}
|
|
103
|
-
foundMyself = popup === this.$el
|
|
104
109
|
}
|
|
105
110
|
return false
|
|
106
111
|
}
|
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
<app-bar-title-container class="appBarTitle flex-grow-1" />
|
|
19
19
|
<app-bar-buttons class="appBarButtons mr-2" />
|
|
20
20
|
</div>
|
|
21
|
+
|
|
22
|
+
<app-bar-navigation v-if="$config.hasAppBarNavigation" />
|
|
21
23
|
</div>
|
|
22
24
|
</template>
|
|
23
25
|
|
|
@@ -25,13 +27,15 @@
|
|
|
25
27
|
import { Component, Vue } from '@a-vue'
|
|
26
28
|
import AppBarButtons from './app/AppBarButtons'
|
|
27
29
|
import AppBarTitleContainer from './app/AppBarTitleContainer'
|
|
30
|
+
import AppBarNavigation from './app/AppBarNavigation'
|
|
28
31
|
import { SidebarEvent } from '@a-admin/events'
|
|
29
32
|
import { sidebarService } from './sidebar/SidebarService'
|
|
30
33
|
|
|
31
34
|
@Component({
|
|
32
35
|
components: {
|
|
33
36
|
AppBarButtons,
|
|
34
|
-
AppBarTitleContainer
|
|
37
|
+
AppBarTitleContainer,
|
|
38
|
+
AppBarNavigation
|
|
35
39
|
}
|
|
36
40
|
})
|
|
37
41
|
export default class StickyHeader extends Vue {
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
id="appBarNavigation"
|
|
4
|
+
class="d-flex align-center gap-1"
|
|
5
|
+
>
|
|
6
|
+
<v-btn
|
|
7
|
+
v-for="link in links"
|
|
8
|
+
:key="link.id"
|
|
9
|
+
class="mt-3 mb-n1"
|
|
10
|
+
x-small
|
|
11
|
+
@click="scrollToSection(link.id)"
|
|
12
|
+
>
|
|
13
|
+
{{ link.label }}
|
|
14
|
+
</v-btn>
|
|
15
|
+
</div>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script>
|
|
19
|
+
import { Component, Vue } from '@a-vue'
|
|
20
|
+
import { debounce } from '@a-vue/utils/debounce'
|
|
21
|
+
|
|
22
|
+
@Component
|
|
23
|
+
export default class AppBarNavigation extends Vue {
|
|
24
|
+
links = []
|
|
25
|
+
|
|
26
|
+
debounceInitLinks = debounce(this.initLinks, 50) // fire immediately if !value (click clearable-x)
|
|
27
|
+
|
|
28
|
+
mounted () {
|
|
29
|
+
const mutationWatcher = new MutationObserver(mutations => {
|
|
30
|
+
let changed = false
|
|
31
|
+
|
|
32
|
+
for (const m of mutations) {
|
|
33
|
+
// Neue Nodes
|
|
34
|
+
for (const node of m.addedNodes) {
|
|
35
|
+
if (!(node instanceof HTMLElement)) continue
|
|
36
|
+
if (node.matches('.collapsible-section') || node.querySelector('.collapsible-section')) {
|
|
37
|
+
changed = true
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Entfernte Nodes
|
|
42
|
+
for (const node of m.removedNodes) {
|
|
43
|
+
if (!(node instanceof HTMLElement)) continue
|
|
44
|
+
if (node.matches('.collapsible-section') || node.querySelector('.collapsible-section')) {
|
|
45
|
+
changed = true
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (changed) {
|
|
51
|
+
this.debounceInitLinks()
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
mutationWatcher.observe(document.body, { childList: true, subtree: true })
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
initLinks () {
|
|
59
|
+
const sections = document.querySelectorAll('.collapsible-section')
|
|
60
|
+
console.log(Array.from(sections).map(s => s.getAttribute('label')))
|
|
61
|
+
this.links = Array.from(sections).map(s => {
|
|
62
|
+
const label = s.getAttribute('label')
|
|
63
|
+
const slug = label
|
|
64
|
+
.toLowerCase()
|
|
65
|
+
.replace(/[^\w]+/g, '-') // Sonderzeichen -> Bindestriche
|
|
66
|
+
.replace(/^-+|-+$/g, '') // führende/trailing -
|
|
67
|
+
.substring(0, 50) // Sicherheitslimit
|
|
68
|
+
|
|
69
|
+
s.id = slug
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
id: s.id,
|
|
73
|
+
label,
|
|
74
|
+
slug
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
scrollToSection (id) {
|
|
80
|
+
const el = document.querySelector(`#${id}`)
|
|
81
|
+
if (!el) return
|
|
82
|
+
|
|
83
|
+
// Scroll-Container auswählen (kann auch this.$refs.scrollContainer sein)
|
|
84
|
+
const container = document.querySelector('#v-main')
|
|
85
|
+
if (!container) return
|
|
86
|
+
|
|
87
|
+
// Abstand in Pixeln (4rem ≈ 64px)
|
|
88
|
+
const offset = 140
|
|
89
|
+
|
|
90
|
+
// Berechne die Scroll-Position relativ zum Container
|
|
91
|
+
const containerTop = container.getBoundingClientRect().top
|
|
92
|
+
const elementTop = el.getBoundingClientRect().top
|
|
93
|
+
|
|
94
|
+
const scrollTarget = container.scrollTop + (elementTop - containerTop) - offset
|
|
95
|
+
|
|
96
|
+
container.scrollTo({
|
|
97
|
+
top: scrollTarget,
|
|
98
|
+
behavior: 'smooth'
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
// // Scroll sanft zur Section
|
|
102
|
+
// el.scrollIntoView({
|
|
103
|
+
// behavior: 'smooth',
|
|
104
|
+
// block: 'start'
|
|
105
|
+
// })
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
</script>
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
<template #actionButton>
|
|
7
7
|
<a-icon
|
|
8
8
|
v-if="buttonEdit"
|
|
9
|
-
size="1.
|
|
10
|
-
class="contextButton
|
|
9
|
+
size="1.6rem"
|
|
10
|
+
class="contextButton"
|
|
11
11
|
title="Bearbeiten"
|
|
12
12
|
@click="openModal"
|
|
13
13
|
>
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
|
|
17
17
|
<a-icon
|
|
18
18
|
v-if="buttonAdd"
|
|
19
|
-
size="1.
|
|
20
|
-
class="contextButton
|
|
19
|
+
size="1.6rem"
|
|
20
|
+
class="contextButton"
|
|
21
21
|
title="Bearbeiten"
|
|
22
22
|
@click="openModal"
|
|
23
23
|
>
|