@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.
@@ -1 +1 @@
1
- 0.0.307
1
+ 0.0.309
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@afeefa/vue-app",
3
- "version": "0.0.307",
3
+ "version": "0.0.309",
4
4
  "description": "",
5
5
  "author": "Afeefa Kollektiv <kollektiv@afeefa.de>",
6
6
  "license": "MIT",
@@ -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
- if (popup.contains(target)) {
100
- return true
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>
@@ -16,7 +16,7 @@
16
16
 
17
17
  <v-icon
18
18
  :color="icon.color"
19
- size="3.5rem"
19
+ size="2.2rem"
20
20
  v-text="icon.icon"
21
21
  />
22
22
 
@@ -6,8 +6,8 @@
6
6
  <template #actionButton>
7
7
  <a-icon
8
8
  v-if="buttonEdit"
9
- size="1.3rem"
10
- class="contextButton mt-n1"
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.3rem"
20
- class="contextButton mt-n1"
19
+ size="1.6rem"
20
+ class="contextButton"
21
21
  title="Bearbeiten"
22
22
  @click="openModal"
23
23
  >
@@ -24,7 +24,8 @@ class AdminConfig {
24
24
  }
25
25
 
26
26
  config = {
27
- has2FA: false
27
+ has2FA: false,
28
+ hasAppBarNavigation: false
28
29
  }
29
30
  }
30
31