@cloudron/pankow 3.2.5 → 3.2.7

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,6 +1,6 @@
1
1
  <script setup>
2
2
 
3
- import { ref, useTemplateRef, nextTick } from 'vue';
3
+ import { ref, useTemplateRef, nextTick, computed } from 'vue';
4
4
  import Button from './Button.vue';
5
5
  import Icon from './Icon.vue';
6
6
 
@@ -35,6 +35,14 @@ const props = defineProps({
35
35
  type: Boolean,
36
36
  default: true
37
37
  },
38
+ rejectBusy: {
39
+ type: Boolean,
40
+ default: false
41
+ },
42
+ rejectActive: {
43
+ type: Boolean,
44
+ default: true
45
+ },
38
46
  center: {
39
47
  type: Boolean,
40
48
  default: false
@@ -42,8 +50,15 @@ const props = defineProps({
42
50
  confirmLabel: String,
43
51
  rejectLabel: String,
44
52
  alternateLabel: String,
53
+ style: '',
45
54
  });
46
55
 
56
+ const mergedStyle = computed(() => {
57
+ if (typeof props.style === 'object') return { 'z-index': props.zIndex+1, ...props.style };
58
+ if (typeof props.style === 'string') return props.style = `${props.style}; zIndex: ${props.zIndex+1}`;
59
+ return `zIndex: ${props.zIndex+1}`
60
+ })
61
+
47
62
  const visible = ref(false);
48
63
  const dialog = useTemplateRef('dialog');
49
64
  const dialogBody = useTemplateRef('dialogBody');
@@ -94,7 +109,7 @@ defineExpose({ open, close });
94
109
  <div class="pankow-dialog-backdrop" @click="onDismiss" v-show="visible" :style="{ 'z-index': zIndex }"></div>
95
110
  </Transition>
96
111
  <Transition name="pankow-bounce-center-top">
97
- <div ref="dialog" class="pankow-dialog" v-bind="$attrs" :class="{ 'pankow-dialog-center': center }" @click.stop v-show="visible" @keydown.esc="onDismiss" tabindex="0" :style="{ 'z-index': zIndex+1 }">
112
+ <div ref="dialog" class="pankow-dialog" v-bind="$attrs" :class="{ 'pankow-dialog-center': center }" @click.stop v-show="visible" @keydown.esc="onDismiss" tabindex="0" :style="mergedStyle">
98
113
  <div class="pankow-dialog-header" v-show="title">
99
114
  {{ title }}
100
115
  <Icon v-show="showX" icon="fa-solid fa-xmark" style="cursor: pointer;" @click="onReject"/>
@@ -92,21 +92,41 @@ const visibleItems = computed(() => {
92
92
  return props.model.filter((item) => item.label.toLowerCase().indexOf(s) !== -1);
93
93
  });
94
94
 
95
+ // select menu item by .label
96
+ function select(elem) {
97
+ let next = container.value.children[0];
98
+ while (true) {
99
+ if (!next) return;
100
+
101
+ if (next.innerText !== elem.label) {
102
+ next = next.nextElementSibling;
103
+ continue;
104
+ }
105
+
106
+ next.focus();
107
+ break;
108
+ }
109
+ }
110
+
111
+ let search = '';
112
+ let debounceTimer = null;
95
113
  function onKeyDown(event) {
114
+ // only handle alphanumerics
115
+ if (!/^[a-zA-Z0-9]$/.test(event.key)) return;
116
+
96
117
  const key = event.key.toLowerCase();
97
- const target = itemElements.value.find(elem => {
98
- if (elem.separator) return false;
99
- if (elem.isDisabled) return false;
100
- if (!elem.isVisible) return false;
101
-
102
- // if we have a html item, use the innerText instead of label
103
- if (elem.item.label) return elem.item.label.toLowerCase().indexOf(key) === 0;
104
- else return elem.$el.innerText.toLowerCase().indexOf(key) === 0;
105
- });
106
118
 
107
- if (!target) return;
119
+ if (debounceTimer) clearTimeout(debounceTimer);
120
+ debounceTimer = setTimeout(() => search = '', 500);
121
+
122
+ search += key;
123
+
124
+ const found = visibleItems.value.find(elem => {
125
+ if (!elem.label) return false;
126
+ return elem.label.toLowerCase().indexOf(search) === 0;
127
+ });
108
128
 
109
- target.$el.focus();
129
+ if (found) select(found)
110
130
  }
111
131
 
112
132
  function onItemActivated(item) {
@@ -45,7 +45,6 @@ const normalizedValue = computed(() => {
45
45
  .pankow-progress-bar {
46
46
  position: relative;
47
47
  font-weight: 700;
48
- min-height: 12px;
49
48
  user-select: none;
50
49
  border-radius: var(--pankow-border-radius);
51
50
  display: block;
@@ -56,11 +55,13 @@ const normalizedValue = computed(() => {
56
55
  }
57
56
 
58
57
  .pankow-progress-bar-filled {
58
+ position: relative;
59
59
  background-color: var(--pankow-color-primary);
60
60
  transition: width 250ms;
61
61
  white-space: nowrap;
62
62
  border-radius: calc(var(--pankow-border-radius) / 1.5);
63
63
  height: 6px;
64
+ overflow: hidden;
64
65
  }
65
66
 
66
67
  .pankow-progress-bar-glow {
@@ -69,20 +70,18 @@ const normalizedValue = computed(() => {
69
70
  display: inline-block;
70
71
  position: absolute;
71
72
  overflow: hidden;
72
- border-radius: var(--pankow-border-radius);
73
73
  }
74
74
 
75
75
  .pankow-progress-bar-glow::after {
76
76
  content: '';
77
- width: 30%;
77
+ width: max(100px, 30%);
78
78
  height: 100%;
79
- background: linear-gradient(to right, transparent, rgba(255,255,255,0.7));
79
+ background: linear-gradient(to right, transparent, rgba(255,255,255,0.7), transparent 90%);
80
80
  position: absolute;
81
81
  top: 0;
82
82
  left: 0;
83
83
  box-sizing: border-box;
84
84
  animation: pankow-progress-bar-indeterminate-animation 1.5s ease-in-out infinite;
85
- border-radius: var(--pankow-border-radius);
86
85
  }
87
86
 
88
87
  .pankow-progress-bar-indeterminate {
@@ -123,6 +123,29 @@ function onSelectPrev() {
123
123
  selectIndex(index <= 0 ? props.options.length-1 : index-1);
124
124
  }
125
125
 
126
+ let search = '';
127
+ let debounceTimer = null;
128
+ function onKeyDown(event) {
129
+ if (props.disabled) return;
130
+
131
+ // only handle alphanumerics
132
+ if (!/^[a-zA-Z0-9]$/.test(event.key)) return;
133
+
134
+ const key = event.key.toLowerCase();
135
+
136
+ if (debounceTimer) clearTimeout(debounceTimer);
137
+ debounceTimer = setTimeout(() => search = '', 500);
138
+
139
+ search += key;
140
+
141
+ const found = menuModel.value.findIndex(i => {
142
+ if (i.label && i.label.toLowerCase().indexOf(search) === 0) return true;
143
+ return false;
144
+ });
145
+
146
+ if (found !== -1) selectIndex(found);
147
+ }
148
+
126
149
  onMounted(() => {
127
150
  if (props.optionKey) {
128
151
  selectedKey.value = model.value;
@@ -135,7 +158,7 @@ onMounted(() => {
135
158
  </script>
136
159
 
137
160
  <template>
138
- <div class="pankow-singleselect" :class="{ 'pankow-singleselect-disabled': disabled }" ref="elem" tabindex="0" @click="onClick" @keydown.enter="onOpen" @keydown.down.stop.prevent="onSelectNext" @keydown.up.stop.prevent="onSelectPrev" @keydown.esc.stop="onClose">
161
+ <div class="pankow-singleselect" :class="{ 'pankow-singleselect-disabled': disabled }" ref="elem" tabindex="0" @click="onClick" @keydown.enter="onOpen" @keydown.down.stop.prevent="onSelectNext" @keydown.up.stop.prevent="onSelectPrev" @keydown.esc.stop="onClose" @keydown.stop="onKeyDown($event)">
139
162
  <Menu ref="menu" :model="menuModel" :search-threshold="searchThreshold" :close-on-activation="true" @close="onMenuClosed"></Menu>
140
163
  {{ selected ? selected[optionLabel] : placeholder }}
141
164
  <Icon icon="fa-solid fa-chevron-down" class="pankow-button-icon-right-with-text" />
package/package.json CHANGED
@@ -1,12 +1,16 @@
1
1
  {
2
2
  "name": "@cloudron/pankow",
3
3
  "private": false,
4
- "version": "3.2.5",
4
+ "version": "3.2.7",
5
5
  "description": "",
6
6
  "main": "index.js",
7
+ "types": "types/index.d.ts",
8
+ "files": ["*.js", "components", "viewers", "types"],
7
9
  "scripts": {
8
10
  "gallery": "cd gallery && vite",
9
- "build": "cd gallery && vite build"
11
+ "build": "cd gallery && vite build",
12
+ "types": "tsc --allowJs --emitDeclarationOnly --declaration index.js --outDir types --skipLibCheck",
13
+ "prepack": "npm run types"
10
14
  },
11
15
  "type": "module",
12
16
  "author": "",
@@ -19,7 +23,8 @@
19
23
  },
20
24
  "devDependencies": {
21
25
  "@vitejs/plugin-vue": "^6.0.1",
22
- "vite": "^7.0.6",
26
+ "typescript": "^5.9.2",
27
+ "vite": "^7.1.1",
23
28
  "vue": "^3.5.18"
24
29
  }
25
30
  }
@@ -0,0 +1,5 @@
1
+ export default fallbackImage;
2
+ declare namespace fallbackImage {
3
+ export { mounted };
4
+ }
5
+ declare function mounted(el: any, binding: any, vnode: any): void;
@@ -0,0 +1,35 @@
1
+ declare namespace _default {
2
+ export { globalOptions };
3
+ export { head };
4
+ export { get };
5
+ export { post };
6
+ export { put };
7
+ export { del };
8
+ export { del as delete };
9
+ }
10
+ export default _default;
11
+ declare namespace globalOptions {
12
+ let credentials: string;
13
+ let redirect: string;
14
+ let errorHook: any;
15
+ }
16
+ declare function head(uri: any, query?: {}, options?: {}): Promise<{
17
+ status: number;
18
+ body: any;
19
+ }>;
20
+ declare function get(uri: any, query?: {}, options?: {}): Promise<{
21
+ status: number;
22
+ body: any;
23
+ }>;
24
+ declare function post(uri: any, body: any, query?: {}, options?: {}): Promise<{
25
+ status: number;
26
+ body: any;
27
+ }>;
28
+ declare function put(uri: any, body: any, query?: {}, options?: {}): Promise<{
29
+ status: number;
30
+ body: any;
31
+ }>;
32
+ declare function del(uri: any, body: any, query?: {}, options?: {}): Promise<{
33
+ status: number;
34
+ body: any;
35
+ }>;
@@ -0,0 +1,5 @@
1
+ declare namespace _default {
2
+ export { onSwipe };
3
+ }
4
+ export default _default;
5
+ export function onSwipe(elem: any, callback: any, threshold?: number): void;
@@ -0,0 +1,6 @@
1
+ import fetcher from './fetcher.js';
2
+ import gestures from './gestures.js';
3
+ import tooltip from './tooltip.js';
4
+ import fallbackImage from './fallbackImage.js';
5
+ import utils from './utils.js';
6
+ export { BottomBar, Breadcrumb, Button, ButtonGroup, Checkbox, Dialog, DirectoryView, EmailInput, FileUploader, FormGroup, InputGroup, Icon, InputDialog, MainLayout, Menu, MenuItem, SingleSelect, MultiSelect, Notification, NumberInput, OfflineBanner, PasswordInput, Popover, ProgressBar, Radiobutton, SideBar, Spinner, Switch, TableView, TabView, TagInput, TextInput, TextInputRaw, TopBar, fetcher, gestures, tooltip, fallbackImage, utils };
@@ -0,0 +1,9 @@
1
+ export default tooltip;
2
+ declare namespace tooltip {
3
+ export { mounted };
4
+ export { updated };
5
+ export { beforeUnmount };
6
+ }
7
+ declare function mounted(el: any, binding: any, vnode: any): void;
8
+ declare function updated(el: any, binding: any, vnode: any): void;
9
+ declare function beforeUnmount(el: any, binding: any, vnode: any): void;
@@ -0,0 +1,57 @@
1
+ declare namespace _default {
2
+ export { getFileTypeGroup };
3
+ export { translation };
4
+ export { useDebouncedRef };
5
+ export { isValidDomain };
6
+ export { isValidDomainOrURL };
7
+ export { isValidEmail };
8
+ export { prettyBinarySize };
9
+ export { prettyDecimalSize };
10
+ export { prettyDate };
11
+ export { prettyShortDate };
12
+ export { prettyLongDate };
13
+ export { prettyFileSize };
14
+ export { prettyEmailAddresses };
15
+ export { sanitize };
16
+ export { pathJoin };
17
+ export { download };
18
+ export { getExtension };
19
+ export { copyToClipboard };
20
+ export { urlSearchQuery };
21
+ export { parseResourcePath };
22
+ export { getEntryIdentifier };
23
+ export { entryListSort };
24
+ export { sleep };
25
+ export { uuidv4 };
26
+ }
27
+ export default _default;
28
+ export function getFileTypeGroup(item: any): any;
29
+ export function translation(id: any): any;
30
+ export function useDebouncedRef(value: any, delay?: number): import("vue").Ref<any, any>;
31
+ export function isValidDomain(domain: any): boolean;
32
+ export function isValidDomainOrURL(domain: any): boolean;
33
+ export function isValidEmail(email: any): boolean;
34
+ export function prettyBinarySize(size: any, fallback: any): any;
35
+ export function prettyDecimalSize(size: any, fallback: any): any;
36
+ export function prettyDate(value: any): any;
37
+ export function prettyShortDate(value: any): string;
38
+ export function prettyLongDate(value: any): string;
39
+ export function prettyFileSize(value: any): string;
40
+ export function prettyEmailAddresses(addresses: any): any;
41
+ export function sanitize(path: any): any;
42
+ export function pathJoin(...args: any[]): any;
43
+ export function download(entries: any, name: any): void;
44
+ export function getExtension(entry: any): any;
45
+ export function copyToClipboard(value: any): void;
46
+ export function urlSearchQuery(): {};
47
+ export function parseResourcePath(resourcePath: any): {
48
+ type: string;
49
+ path: string;
50
+ shareId: string;
51
+ apiPath: string;
52
+ resourcePath: string;
53
+ };
54
+ export function getEntryIdentifier(entry: any): string;
55
+ export function entryListSort(list: any, prop: any, desc: any): any;
56
+ export function sleep(ms: any): any;
57
+ export function uuidv4(): string;
package/.gitlab-ci.yml DELETED
@@ -1,30 +0,0 @@
1
- # jobs (defined using a top level key) belong to a stage. the jobs of a stage are run in parallel.
2
- # stages are run in sequence.
3
- # artifacts are attached to the jobs on success (downloadable from UI)
4
- # cache is preserved between pipelines (and not meant for jobs)
5
-
6
- default:
7
- image: cloudron/base:5.0.0@sha256:04fd70dbd8ad6149c19de39e35718e024417c3e01dc9c6637eaf4a41ec4e596c
8
-
9
- variables:
10
- DEMO_SERVER: pankow.nebulon.de
11
-
12
- build-gallery:
13
- stage: build
14
- script:
15
- - npm install && npm run build
16
- artifacts:
17
- paths:
18
- - gallery/dist/
19
- expire_in: 2 hours
20
-
21
- deploy-gallery:
22
- stage: deploy
23
- script:
24
- - npm install -g cloudron-surfer && surfer put --server ${DEMO_SERVER} --token ${PANKOW_DEMO_SURFER_TOKEN} --delete gallery/dist/* /
25
- only:
26
- - main
27
-
28
- stages:
29
- - build
30
- - deploy
package/.jshintrc DELETED
@@ -1,8 +0,0 @@
1
- {
2
- "node": true,
3
- "browser": true,
4
- "unused": true,
5
- "esversion": 11,
6
- "globalstrict": false,
7
- "predef": [ "angular", "$", "describe", "it", "before", "after" ]
8
- }
@@ -1,40 +0,0 @@
1
- <template>
2
- <div class="pankow-menu-item" @click.stop="onActivated">
3
- <h1>Large Item</h1>
4
- </div>
5
- </template>
6
-
7
- <script>
8
-
9
- export default {
10
- name: 'CustomMenuItem',
11
- emits: ['activated'],
12
- components: {
13
- },
14
- props: {
15
- item: {
16
- type: Object,
17
- default: {
18
- action: null
19
- }
20
- }
21
- },
22
- computed: {
23
- isVisible() {
24
- if (typeof this.item.visible === 'function') return this.item.visible();
25
- return typeof this.item.visible !== 'undefined' ? this.item.visible : true;
26
- },
27
- isDisabled() {
28
- if (typeof this.item.disabled === 'function') return this.item.disabled();
29
- return typeof this.item.disabled !== 'undefined' ? this.item.disabled : false;
30
- }
31
- },
32
- methods: {
33
- onActivated() {
34
- if (this.isDisabled) return;
35
- this.$emit('activated');
36
- }
37
- }
38
- };
39
-
40
- </script>
@@ -1,73 +0,0 @@
1
- <template>
2
- <div>
3
- <h2>Directory View</h2>
4
- <div class="demo-container">
5
- <DirectoryView
6
- :items="items"
7
- :show-size="true"
8
- :show-owner="true"
9
- :show-modified="true"
10
- :show-extract="false"
11
- show-share="isShared"
12
- />
13
- </div>
14
- </div>
15
- </template>
16
-
17
- <script>
18
-
19
- import DirectoryView from '../components/DirectoryView.vue';
20
-
21
- import fileIconUrl from './logo.png';
22
- import folderIconUrl from './folder.svg';
23
-
24
- export default {
25
- name: 'DirectoryViewDemo',
26
- components: {
27
- DirectoryView
28
- },
29
- data() {
30
- return {
31
- items: []
32
- };
33
- },
34
- mounted() {
35
- for (let i = 0; i < 100; ++i) {
36
- const isDirectory = i % 2;
37
-
38
- this.items.push({
39
- id: `id-${i}`,
40
- name: `Test File ${i}`,
41
- icon: isDirectory ? folderIconUrl : fileIconUrl,
42
- previewUrl: '',
43
-
44
- // optional
45
- isDirectory: isDirectory,
46
- modified: new Date(),
47
- owner: 'admin',
48
- size: 10241024,
49
- isShared: !(i % 4),
50
- href: '',
51
- target: !(i % 5) ? '../symlink/target' : '',
52
-
53
- // TODO maybe better handle type/isDirectory/isFile/isBinary/symlink...
54
- // type: i % 2 ? 'directory' : 'file',
55
- // isBinary: false,
56
- });
57
- }
58
- }
59
- };
60
-
61
- </script>
62
-
63
- <style scoped>
64
-
65
- .demo-container {
66
- border-color: var(--pankow-color-background);
67
- border-style: solid;
68
- border-width: 2px;
69
- border-radius: var(--pankow-border-radius);
70
- height: 300px;
71
- }
72
-
73
- </style>