@cloudron/pankow 4.1.1 → 4.1.2

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.
@@ -6,6 +6,8 @@
6
6
  ref="main"
7
7
  @keydown.up.prevent="onKeyUp($event)"
8
8
  @keydown.down.prevent="onKeyDown($event)"
9
+ @keydown.left.prevent="onKeyLeft($event)"
10
+ @keydown.right.prevent="onKeyRight($event)"
9
11
  @keydown.enter="onKeyEnter($event)"
10
12
  @keydown.delete="onKeyDelete($event)"
11
13
  @keydown.esc="onKeyEscape($event)"
@@ -28,7 +30,7 @@
28
30
  </slot>
29
31
  </div>
30
32
 
31
- <div class="directory-view-header" v-show="items.length">
33
+ <div class="directory-view-header" v-if="items.length && viewMode === 'list'">
32
34
  <div class="directory-view-header-icon"></div>
33
35
  <div class="directory-view-header-name" @click="toggleSort(SORT_BY.NAME)"><i v-show="sortBy === SORT_BY.NAME" class="fa-solid" :class="{ 'fa-arrow-up': sortDirection === SORT_DIRECTION.DESC, 'fa-arrow-down': sortDirection === SORT_DIRECTION.ASC }"></i> {{ tr('filemanager.list.name') }}</div>
34
36
  <div class="directory-view-header-star" v-show="showStar" @click="toggleSort(SORT_BY.STAR)"><i v-show="sortBy === SORT_BY.STAR" class="fa-solid" :class="{ 'fa-arrow-up': sortDirection === SORT_DIRECTION.DESC, 'fa-arrow-down': sortDirection === SORT_DIRECTION.ASC }"></i> <i class="fa-regular fa-star"></i></div>
@@ -37,32 +39,55 @@
37
39
  <div class="directory-view-header-modified" v-show="showModified" @click="toggleSort(SORT_BY.MTIME)"><i v-show="sortBy === SORT_BY.MTIME" class="fa-solid" :class="{ 'fa-arrow-up': sortDirection === SORT_DIRECTION.DESC, 'fa-arrow-down': sortDirection === SORT_DIRECTION.ASC }"></i> {{ tr('filemanager.list.mtime') }}</div>
38
40
  <div class="directory-view-header-actions"></div>
39
41
  </div>
40
- <div class="directory-view-body-container" v-show="items.length">
42
+ <div class="directory-view-body-container" :class="{ 'directory-view-body-container-full': viewMode !== 'list' }" v-show="items.length">
41
43
  <div
44
+ ref="gridBody"
42
45
  class="directory-view-body"
46
+ :class="{ 'directory-view-body-grid': viewMode === 'grid' }"
43
47
  @contextmenu="onContextMenuBody($event)"
44
48
  >
45
- <DirectoryViewListItem v-for="item in filteredSortedItems" :ref="(el) => this.elements[item.id] = el"
46
- :key="item.id"
47
- :fallbackIcon="fallbackIcon"
48
- :item="item"
49
- :show-owner="showOwner"
50
- :show-extract="showExtract"
51
- :show-size="showSize"
52
- :show-star="showStar"
53
- :show-modified="showModified"
54
- :rename-handler="renameHandler"
55
- :share-indicator-property="shareIndicatorProperty"
56
- :select-handler="onSelectAndFocus"
57
- :drop-handler="onDrop"
58
- :can-drop-handler="onCanDropHandler"
59
- :star-handler="starHandler"
60
- @contextmenu="onContextMenu(item, $event)"
61
- @action-menu="onContextMenu"
62
- @dblclick="onItemActivated(item)"
63
- @activated="onItemActivated(item)"
64
- @dragstart="onItemDragStart($event, item)"
65
- />
49
+ <template v-if="viewMode === 'list'">
50
+ <DirectoryViewListItem v-for="item in filteredSortedItems" :ref="(el) => this.elements[item.id] = el"
51
+ :key="item.id"
52
+ :fallbackIcon="fallbackIcon"
53
+ :item="item"
54
+ :show-owner="showOwner"
55
+ :show-extract="showExtract"
56
+ :show-size="showSize"
57
+ :show-star="showStar"
58
+ :show-modified="showModified"
59
+ :rename-handler="renameHandler"
60
+ :share-indicator-property="shareIndicatorProperty"
61
+ :select-handler="onSelectAndFocus"
62
+ :drop-handler="onDrop"
63
+ :can-drop-handler="onCanDropHandler"
64
+ :star-handler="starHandler"
65
+ @contextmenu="onContextMenu(item, $event)"
66
+ @action-menu="onContextMenu"
67
+ @dblclick="onItemActivated(item)"
68
+ @activated="onItemActivated(item)"
69
+ @dragstart="onItemDragStart($event, item)"
70
+ />
71
+ </template>
72
+ <template v-else-if="viewMode === 'grid'">
73
+ <DirectoryViewGridItem v-for="item in filteredSortedItems" :ref="(el) => this.elements[item.id] = el"
74
+ :key="item.id"
75
+ :fallbackIcon="fallbackIcon"
76
+ :item="item"
77
+ :show-star="showStar"
78
+ :rename-handler="renameHandler"
79
+ :share-indicator-property="shareIndicatorProperty"
80
+ :select-handler="onSelectAndFocus"
81
+ :drop-handler="onDrop"
82
+ :can-drop-handler="onCanDropHandler"
83
+ :star-handler="starHandler"
84
+ @contextmenu="onContextMenu(item, $event)"
85
+ @action-menu="onContextMenu"
86
+ @dblclick="onItemActivated(item)"
87
+ @activated="onItemActivated(item)"
88
+ @dragstart="onItemDragStart($event, item)"
89
+ />
90
+ </template>
66
91
  </div>
67
92
 
68
93
  <div class="drag-handle"></div>
@@ -74,6 +99,7 @@
74
99
 
75
100
  import SingleSelect from './SingleSelect.vue';
76
101
  import DirectoryViewListItem from './DirectoryViewListItem.vue';
102
+ import DirectoryViewGridItem from './DirectoryViewGridItem.vue';
77
103
  import Dialog from './Dialog.vue';
78
104
  import Menu from './Menu.vue';
79
105
 
@@ -99,11 +125,19 @@ export default {
99
125
  components: {
100
126
  Dialog,
101
127
  DirectoryViewListItem,
128
+ DirectoryViewGridItem,
102
129
  SingleSelect,
103
130
  Menu
104
131
  },
105
132
  emits: [ 'selectionChanged', 'item-activated' ],
106
133
  props: {
134
+ viewMode: {
135
+ type: String,
136
+ default: 'list',
137
+ validator(value) {
138
+ return ['list', 'grid'].includes(value);
139
+ }
140
+ },
107
141
  busy: {
108
142
  type: Boolean,
109
143
  default: false
@@ -508,11 +542,33 @@ export default {
508
542
  event.dataTransfer.setData('application/x-pankow', 'selected');
509
543
  event.dataTransfer.setDragImage(dragHandle, 0, 0);
510
544
  },
545
+ getGridColumns() {
546
+ const el = this.$refs.gridBody;
547
+ if (this.viewMode !== 'grid' || !el || !el.children.length) return 1;
548
+ const firstRowTop = el.children[0].getBoundingClientRect().top;
549
+ const tolerance = 2;
550
+ let cols = 0;
551
+ for (const child of el.children) {
552
+ if (Math.abs(child.getBoundingClientRect().top - firstRowTop) <= tolerance) cols++;
553
+ else break;
554
+ }
555
+ return cols || 1;
556
+ },
511
557
  onKeyUp(event) {
512
- this.onSelectAndFocusIndex(this.focusItemIndex-1, event.shiftKey);
558
+ const step = this.viewMode === 'grid' ? this.getGridColumns() : 1;
559
+ this.onSelectAndFocusIndex(this.focusItemIndex - step, event.shiftKey);
513
560
  },
514
561
  onKeyDown(event) {
515
- this.onSelectAndFocusIndex(this.focusItemIndex+1, event.shiftKey);
562
+ const step = this.viewMode === 'grid' ? this.getGridColumns() : 1;
563
+ this.onSelectAndFocusIndex(this.focusItemIndex + step, event.shiftKey);
564
+ },
565
+ onKeyLeft(event) {
566
+ if (this.viewMode !== 'grid') return;
567
+ this.onSelectAndFocusIndex(this.focusItemIndex - 1, event.shiftKey);
568
+ },
569
+ onKeyRight(event) {
570
+ if (this.viewMode !== 'grid') return;
571
+ this.onSelectAndFocusIndex(this.focusItemIndex + 1, event.shiftKey);
516
572
  },
517
573
  onKeyEnter(event) {
518
574
  if (this.focusItem) this.onItemActivated(this.focusItem);
@@ -748,6 +804,10 @@ export default {
748
804
  height: calc(100% - 38px); /* 38px is the header size */
749
805
  }
750
806
 
807
+ .directory-view-body-container-full {
808
+ height: 100%;
809
+ }
810
+
751
811
  .directory-view-body {
752
812
  padding: 0 10px;
753
813
  padding-bottom: 10px;
@@ -755,6 +815,13 @@ export default {
755
815
  overflow: auto;
756
816
  }
757
817
 
818
+ .directory-view-body-grid {
819
+ display: grid;
820
+ grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
821
+ gap: 4px;
822
+ align-content: start;
823
+ }
824
+
758
825
  .directory-view-header-icon {
759
826
  width: 40px;
760
827
  }
@@ -0,0 +1,363 @@
1
+ <template>
2
+ <div class="grid-item-wrapper"
3
+ :draggable="!rename"
4
+ @mouseup="onSelect($event)"
5
+ @drop="onDrop($event)"
6
+ @dragover="onDragOver($event)"
7
+ @dragexit="onDragExit($event)"
8
+ >
9
+
10
+ <div class="grid-item" :class="{ 'focused': item.focused, 'selected': item.selected, 'drop-target-active': dropTargetActive }">
11
+ <div v-if="visible && showStar" class="grid-item-star" @dblclick.stop.prevent @click.stop.prevent="onToggleStar">
12
+ <Icon :icon="`${item.star ? 'fa-solid' : 'fa-regular'} fa-star`" class="star-icon" :class="{ 'star-visible': item.star }" />
13
+ </div>
14
+ <div v-if="visible" class="grid-item-actions" @mouseup.stop="onActionMenu($event)">
15
+ <i class="fa-solid fa-ellipsis-vertical"/>
16
+ </div>
17
+
18
+ <div class="grid-item-icon">
19
+ <template v-if="visible">
20
+ <img :src="item.previewUrl || item.icon" ref="iconImage" @error="iconError($event)"/>
21
+ <i v-show="shareIndicatorProperty !== '' && !!item[shareIndicatorProperty]" class="fa-solid fa-share-nodes is-shared"></i>
22
+ </template>
23
+ </div>
24
+
25
+ <div v-if="visible && !rename" class="grid-item-label" :title="item.name + (item.target ? ` → ${item.target}` : '')">
26
+ <a v-if="item.href" class="open-action" @dblclick.stop @click="onOpen($event)" :href="item.href">{{ item.name }}</a>
27
+ <span v-else>{{ item.name }}</span>
28
+ </div>
29
+ <div v-if="visible && rename" class="grid-item-label grid-item-rename">
30
+ <TextInput
31
+ ref="renameInput"
32
+ v-model="newName"
33
+ :disabled="renameBusy"
34
+ @blur="onRenameEnd"
35
+ @dblclick.stop
36
+ @keydown.enter.stop="onRenameSubmit"
37
+ @keydown.esc.stop="onRenameEnd"
38
+ @keydown.stop
39
+ />
40
+ </div>
41
+ </div>
42
+ </div>
43
+ </template>
44
+
45
+ <script>
46
+
47
+ import Icon from './Icon.vue';
48
+ import TextInput from './TextInput.vue';
49
+
50
+ export default {
51
+ name: 'DirectoryViewGridItem',
52
+ emits: [ 'activated', 'action-menu' ],
53
+ components: {
54
+ Icon,
55
+ TextInput
56
+ },
57
+ props: {
58
+ item: Object,
59
+ showStar: {
60
+ type: Boolean,
61
+ default: false
62
+ },
63
+ shareIndicatorProperty: {
64
+ type: String,
65
+ default: '',
66
+ },
67
+ fallbackIcon: String,
68
+ renameHandler: {
69
+ type: Function,
70
+ default() {
71
+ console.warn('Missing renameHandler for DirectoryViewGridItem');
72
+ }
73
+ },
74
+ starHandler: {
75
+ type: Function,
76
+ default() {
77
+ console.warn('Missing starHandler for DirectoryViewGridItem');
78
+ }
79
+ },
80
+ selectHandler: {
81
+ type: Function,
82
+ default() {
83
+ console.warn('Missing selectHandler for DirectoryViewGridItem');
84
+ }
85
+ },
86
+ dropHandler: {
87
+ type: Function,
88
+ default() {
89
+ console.warn('Missing dropHandler for DirectoryViewGridItem');
90
+ }
91
+ },
92
+ canDropHandler: {
93
+ type: Function,
94
+ default() {
95
+ console.warn('Missing canDropHandler for DirectoryViewGridItem');
96
+ }
97
+ }
98
+ },
99
+ data() {
100
+ return {
101
+ visible: false,
102
+ rename: false,
103
+ renameBusy: false,
104
+ newName: '',
105
+ dropTargetActive: false,
106
+ previewRetries: 0
107
+ };
108
+ },
109
+ methods: {
110
+ highlight() {
111
+ this.$el.classList.add('pankow-directory-view-highlight-animation');
112
+ setTimeout(() => { this.$el.classList.remove('pankow-directory-view-highlight-animation'); }, 4000);
113
+ },
114
+ onToggleStar() {
115
+ this.starHandler(this.item);
116
+ },
117
+ onActionMenu(event) {
118
+ this.onSelect(event, true);
119
+ this.$emit('action-menu', this.item, event);
120
+ },
121
+ onRenameBegin() {
122
+ this.rename = true;
123
+ this.newName = this.item.name;
124
+
125
+ setTimeout(() => {
126
+ const elem = this.$refs.renameInput.$el;
127
+ elem.focus();
128
+
129
+ if (typeof elem.selectionStart !== 'undefined') {
130
+ elem.selectionStart = 0;
131
+ elem.selectionEnd = this.item.name.lastIndexOf('.');
132
+ }
133
+ }, 0);
134
+ },
135
+ onRenameEnd() {
136
+ this.rename = false;
137
+ this.renameBusy = false;
138
+ this.newName = '';
139
+ },
140
+ async onRenameSubmit() {
141
+ if (!this.newName) return;
142
+
143
+ this.renameBusy = true;
144
+ await this.renameHandler(this.item, this.newName);
145
+ this.onRenameEnd();
146
+ },
147
+ onOpen(event) {
148
+ if (event.ctrlKey || event.metaKey) return;
149
+
150
+ event.preventDefault();
151
+ event.stopPropagation();
152
+
153
+ this.$emit('activated', this.item);
154
+ },
155
+ onSelect(event, actionMenu = false) {
156
+ if ((event.button === 2 || actionMenu) && event.ctrlKey) {
157
+ this.selectHandler(this.item, event, true);
158
+ } else {
159
+ this.selectHandler(this.item, event);
160
+ }
161
+ },
162
+ onDrop(event) {
163
+ if (!this.canDropHandler(this.item)) return;
164
+
165
+ event.stopPropagation();
166
+
167
+ this.dropHandler(this.item, event);
168
+ this.dropTargetActive = false;
169
+ },
170
+ onDragOver(event) {
171
+ if (!this.canDropHandler(this.item)) return;
172
+
173
+ event.preventDefault();
174
+ event.stopPropagation();
175
+
176
+ event.dataTransfer.dropEffect = 'move';
177
+ this.dropTargetActive = true;
178
+ },
179
+ onDragExit(event) {
180
+ if (!this.item.isDirectory) return;
181
+
182
+ this.dropTargetActive = false;
183
+ },
184
+ iconError(event) {
185
+ event.target.src = this.fallbackIcon;
186
+
187
+ setTimeout(() => {
188
+ if (this.previewRetries > 5) return;
189
+ ++this.previewRetries;
190
+
191
+ event.target.src = this.item.previewUrl || this.item.icon;
192
+ }, 1000);
193
+ }
194
+ },
195
+ mounted() {
196
+ const observer = new IntersectionObserver(result => {
197
+ if (result[0].isIntersecting) {
198
+ this.visible = true;
199
+ observer.unobserve(this.$el);
200
+ }
201
+ });
202
+
203
+ observer.observe(this.$el);
204
+ }
205
+ };
206
+
207
+ </script>
208
+
209
+ <style scoped>
210
+
211
+ .grid-item-wrapper {
212
+ --background-color-hover: #ededed;
213
+ --background-color-selected: #dbedfb;
214
+ --border-color-focus: #b3cfe5;
215
+ }
216
+
217
+ @media (prefers-color-scheme: dark) {
218
+ .grid-item-wrapper {
219
+ --background-color-hover: rgba(255, 255, 255, 0.1);
220
+ --background-color-selected: rgba(255, 255, 255, 0.2);
221
+ --border-color-focus: rgba(255, 255, 255, 0.3);
222
+ }
223
+ }
224
+
225
+ .grid-item-wrapper {
226
+ padding: 2px;
227
+ }
228
+
229
+ .grid-item {
230
+ display: flex;
231
+ flex-direction: column;
232
+ align-items: center;
233
+ padding: 10px 8px 8px;
234
+ border-radius: 6px;
235
+ border: 2px solid transparent;
236
+ position: relative;
237
+ transition: all 100ms;
238
+ cursor: default;
239
+ }
240
+
241
+ .grid-item-wrapper:hover > .grid-item {
242
+ background-color: var(--background-color-hover);
243
+ }
244
+
245
+ .grid-item.drop-target-active {
246
+ border: 2px solid var(--pankow-color-primary);
247
+ }
248
+
249
+ .grid-item.selected {
250
+ background-color: var(--background-color-selected) !important;
251
+ }
252
+
253
+ .grid-item.focused {
254
+ border: solid 2px var(--border-color-focus);
255
+ }
256
+
257
+ .grid-item-actions {
258
+ position: absolute;
259
+ top: 4px;
260
+ right: 4px;
261
+ padding: 2px 6px;
262
+ cursor: pointer;
263
+ border-radius: 3px;
264
+ opacity: 0;
265
+ transition: opacity 100ms;
266
+ }
267
+
268
+ .grid-item-actions:hover {
269
+ background-color: var(--background-color-hover);
270
+ }
271
+
272
+ .grid-item-wrapper:hover .grid-item-actions,
273
+ .grid-item.focused .grid-item-actions,
274
+ .grid-item.selected .grid-item-actions {
275
+ opacity: 1;
276
+ }
277
+
278
+ .grid-item-icon {
279
+ width: 80px;
280
+ height: 80px;
281
+ display: flex;
282
+ align-items: center;
283
+ justify-content: center;
284
+ position: relative;
285
+ flex-shrink: 0;
286
+ }
287
+
288
+ .grid-item-icon > img {
289
+ max-width: 64px;
290
+ max-height: 64px;
291
+ object-fit: contain;
292
+ }
293
+
294
+ .is-shared {
295
+ position: absolute;
296
+ right: 2px;
297
+ bottom: 2px;
298
+ font-size: 1rem;
299
+ }
300
+
301
+ .grid-item-label {
302
+ width: 100%;
303
+ text-align: center;
304
+ overflow: hidden;
305
+ text-overflow: ellipsis;
306
+ white-space: nowrap;
307
+ margin-top: 4px;
308
+ font-size: 0.85rem;
309
+ padding: 0 2px;
310
+ }
311
+
312
+ .grid-item-rename {
313
+ overflow: hidden;
314
+ }
315
+
316
+ .grid-item-rename :deep(input) {
317
+ width: 100%;
318
+ box-sizing: border-box;
319
+ text-align: center;
320
+ font-size: 0.85rem;
321
+ padding: 1px 4px;
322
+ }
323
+
324
+ .grid-item-star {
325
+ position: absolute;
326
+ top: 4px;
327
+ left: 4px;
328
+ padding: 2px 6px;
329
+ cursor: pointer;
330
+ border-radius: 3px;
331
+ opacity: 0;
332
+ transition: opacity 100ms;
333
+ }
334
+
335
+ .grid-item-star:hover {
336
+ background-color: var(--background-color-hover);
337
+ }
338
+
339
+ .grid-item-wrapper:hover .grid-item-star,
340
+ .grid-item.focused .grid-item-star,
341
+ .grid-item.selected .grid-item-star {
342
+ opacity: 1;
343
+ }
344
+
345
+ .star-icon {
346
+ color: #ffcb00;
347
+ cursor: pointer;
348
+ font-size: 0.8rem;
349
+ }
350
+
351
+ .grid-item-star:has(.star-visible) {
352
+ opacity: 1 !important;
353
+ }
354
+
355
+ .open-action {
356
+ cursor: pointer;
357
+ }
358
+
359
+ .open-action:hover {
360
+ text-decoration: underline;
361
+ }
362
+
363
+ </style>
@@ -78,6 +78,7 @@ let targetTop = 0;
78
78
  const offsetY = ref(0);
79
79
  const rollUp = ref(false);
80
80
  const searchString = ref('');
81
+ const keyboardNav = ref(false);
81
82
  const emptyItem = ref({
82
83
  label: '',
83
84
  disabled: true,
@@ -193,12 +194,22 @@ async function open(event, element = null) {
193
194
  else container.value.focus();
194
195
  }
195
196
 
197
+ function onMouseMove(event) {
198
+ keyboardNav.value = false;
199
+ const item = event.target.closest('.pankow-menu-item');
200
+ if (item && !item.classList.contains('pankow-menu-item-disabled') && item.getAttribute('separator') !== 'true') {
201
+ item.focus();
202
+ }
203
+ }
204
+
196
205
  function onBackdrop(event) {
197
206
  close();
198
207
  event.preventDefault();
199
208
  }
200
209
 
201
210
  function selectUp() {
211
+ keyboardNav.value = true;
212
+
202
213
  if (!container.value.children[0]) return;
203
214
 
204
215
  const active = getActiveElement(container.value.children);
@@ -219,6 +230,8 @@ function selectUp() {
219
230
  }
220
231
 
221
232
  function selectDown() {
233
+ keyboardNav.value = true;
234
+
222
235
  if (!container.value.children[0]) return;
223
236
 
224
237
  const active = getActiveElement(container.value.children);
@@ -312,7 +325,7 @@ defineExpose({
312
325
  <teleport to="#app">
313
326
  <div class="pankow-menu-backdrop" @click="onBackdrop($event)" @contextmenu="onBackdrop($event)" v-show="isOpen"></div>
314
327
  <Transition :name="rollUp ? 'pankow-roll-up' : 'pankow-roll-down'">
315
- <div class="pankow-menu" v-show="isOpen" ref="container" tabindex="0" @keydown.up.stop="selectUp()" @keydown.down.stop="selectDown()" @keydown.esc.stop="close()" @keydown="onKeyDown">
328
+ <div class="pankow-menu" :class="{ 'pankow-menu--keyboard-nav': keyboardNav }" v-show="isOpen" ref="container" tabindex="0" @keydown.up.stop="selectUp()" @keydown.down.stop="selectDown()" @keydown.esc.stop="close()" @keydown="onKeyDown" @mousemove="onMouseMove">
316
329
  <TextInput placeholder="Filter ..." autocomplete="off" @keydown.up.stop="selectUp()" @keydown.down.stop="selectDown()" @keydown.stop @keydown.esc.stop="close()" @click.stop style="width: 100%; border: 0; padding: 8px 12px;" v-model="searchString" v-if="searchThreshold < model.length"/>
317
330
  <component v-for="item in visibleItems" ref="itemElements" :is="item.type || (item.href ? MenuItemLink : MenuItem)" @activated="onItemActivated(item)" :item="item" :has-icons="hasIcons" />
318
331
  <MenuItem v-if="model.length === 0" :item="emptyItem"/>
@@ -77,13 +77,31 @@ function onActivated() {
77
77
  opacity: .6
78
78
  }
79
79
 
80
- .pankow-menu-item:focus,
80
+ .pankow-menu-item:focus {
81
+ background-color: var(--pankow-color-primary-hover);
82
+ color: white;
83
+ }
84
+
81
85
  .pankow-menu-item:hover {
82
86
  background-color: var(--pankow-color-primary-hover);
83
87
  color: white;
84
88
  }
85
89
 
86
- .pankow-menu-item-disabled:focus,
90
+ .pankow-menu--keyboard-nav .pankow-menu-item:hover {
91
+ background-color: inherit;
92
+ color: inherit;
93
+ }
94
+
95
+ .pankow-menu--keyboard-nav .pankow-menu-item:focus {
96
+ background-color: var(--pankow-color-primary-hover);
97
+ color: white;
98
+ }
99
+
100
+ .pankow-menu-item-disabled:focus {
101
+ background-color: inherit;
102
+ color: inherit;
103
+ }
104
+
87
105
  .pankow-menu-item-disabled:hover {
88
106
  background-color: inherit;
89
107
  color: inherit;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloudron/pankow",
3
3
  "private": false,
4
- "version": "4.1.1",
4
+ "version": "4.1.2",
5
5
  "description": "",
6
6
  "main": "index.js",
7
7
  "types": "types/index.d.ts",
@@ -34,7 +34,7 @@
34
34
  "highlight.js": "^11.11.1",
35
35
  "typescript": "^5.9.3",
36
36
  "vite": "^7.3.1",
37
- "vue": "^3.5.28",
38
- "vue-router": "^5.0.2"
37
+ "vue": "^3.5.29",
38
+ "vue-router": "^5.0.3"
39
39
  }
40
40
  }