@mixd-id/web-scaffold 0.1.2301231323 → 0.1.2301231325

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mixd-id/web-scaffold",
3
3
  "private": false,
4
- "version": "0.1.2301231323",
4
+ "version": "0.1.2301231325",
5
5
  "scripts": {
6
6
  "dev": "vite serve",
7
7
  "build": "vite build",
@@ -3,12 +3,12 @@
3
3
  <div :class="$style.inner">
4
4
  <span v-if="images && images.length && images.length > 0" v-for="image in images" :key="image">
5
5
  <a v-if="image.target && image.target.indexOf('://') >= 0" :href="image.target" @click="checkClick">
6
- <Image :src="image.imageUrl" :class="imageClass" />
6
+ <Image :src="image.imageUrl" :outerClass="imageClass" />
7
7
  </a>
8
8
  <router-link v-if="image.target" :to="scrolling ? '' : image.target">
9
- <Image :src="image.imageUrl" :class="imageClass"/>
9
+ <Image :src="image.imageUrl" :outerClass="imageClass"/>
10
10
  </router-link>
11
- <Image v-else :src="image.imageUrl" :class="imageClass" />
11
+ <Image v-else :src="image.imageUrl" :outerClass="imageClass" />
12
12
  </span>
13
13
  <div v-else :class="imageClass" class="bg-gray-200 animate-pulse"></div>
14
14
  </div>
@@ -5,7 +5,7 @@
5
5
  <img :class="computedClass" :src="actualSrc" ref="img" :style="imageStyle"/>
6
6
  <input v-if="Boolean(editable)" class="hidden" type="file" accept="image/*" ref="file" @change="onChange"/>
7
7
  <slot></slot>
8
- <div :class="$style.isLoading" v-if="isLoading">
8
+ <div :class="$style.loading" v-if="loading">
9
9
  <svg class="animate-spin aspect-square w-[15%] text-primary" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg>
10
10
  </div>
11
11
  </div>
@@ -80,8 +80,7 @@ export default{
80
80
 
81
81
  data(){
82
82
  return {
83
- visible: 0,
84
- isLoading: false,
83
+ loading: false,
85
84
  actualSrc: null,
86
85
  loaded: false
87
86
  }
@@ -113,10 +112,8 @@ export default{
113
112
 
114
113
  async loadSrc(){
115
114
 
116
- this.loaded = false
117
-
118
115
  if(typeof this.src === 'string') {
119
- if (this.src.startsWith('data:image')) {
116
+ if (!this.loaded && this.src.startsWith('data:image')) {
120
117
  this.loaded = true
121
118
  this.actualSrc = this.src
122
119
  }
@@ -139,34 +136,36 @@ export default{
139
136
  img.addEventListener('load', () => {
140
137
  this.loaded = true
141
138
  this.actualSrc = img.src
142
- this.isLoading = false
139
+ this.loading = false
143
140
  })
144
141
  img.addEventListener('error', () => {
145
142
  this.loaded = true
146
143
  this.actualSrc = this.defaultSrc
147
- this.isLoading = false
144
+ this.loading = false
148
145
  })
149
146
  img.src = src[screens[b]]
147
+ this.loading = true
150
148
  }
151
149
  }
152
150
  }
153
151
  }
154
- else if(this.src instanceof File){
152
+ else if(!this.loaded && this.src instanceof File){
155
153
  var reader = new FileReader();
156
154
 
157
155
  reader.addEventListener('load', () => {
158
156
  this.loaded = true
159
157
  this.actualSrc = reader.result
160
- this.isLoading = false
158
+ this.loading = false
161
159
  }, false)
162
160
 
163
161
  reader.addEventListener('error', () => {
164
162
  this.loaded = true
165
163
  this.actualSrc = this.defaultSrc
166
- this.isLoading = false
164
+ this.loading = false
167
165
  })
168
166
 
169
167
  reader.readAsDataURL(this.src)
168
+ this.loading = true
170
169
  }
171
170
  }
172
171
 
@@ -175,14 +174,12 @@ export default{
175
174
  watch:{
176
175
 
177
176
  src(to){
177
+ this.loaded = false
178
178
  this.loadSrc()
179
+ },
179
180
 
180
- window.setTimeout(() => {
181
- if(!this.loaded){
182
- this.actualSrc = null
183
- this.isLoading = true
184
- }
185
- }, 200)
181
+ "isMobile.value"(to){
182
+ this.loadSrc()
186
183
  }
187
184
 
188
185
  }
@@ -200,7 +197,7 @@ export default{
200
197
  @apply absolute top-0 left-0 right-0 bottom-0;
201
198
  }
202
199
 
203
- .isLoading{
200
+ .loading{
204
201
  @apply absolute top-0 left-0 right-0 bottom-0;
205
202
  @apply flex items-center justify-center;
206
203
  }
@@ -32,11 +32,21 @@ export default{
32
32
  open(imageUrl){
33
33
  this.imageUrl = imageUrl
34
34
  this.isOpen = true
35
+ window.addEventListener('keyup', this.onKeyUp)
35
36
  },
36
37
 
37
38
  close(){
38
39
  this.isOpen = false
39
40
  this.imageUrl = null
41
+ window.removeEventListener('keyup', this.onKeyUp)
42
+ },
43
+
44
+ onKeyUp(e){
45
+ if(e.keyCode === 27){
46
+ e.preventDefault()
47
+ e.stopPropagation()
48
+ this.close()
49
+ }
40
50
  }
41
51
 
42
52
  }
@@ -53,7 +63,7 @@ export default{
53
63
 
54
64
  .previewModal{
55
65
  @apply !w-screen !h-screen !bg-base-300;
56
- z-index: 21;
66
+ z-index: 21 !important;
57
67
  max-width: unset !important;
58
68
  max-height: unset !important;
59
69
  }
@@ -5,10 +5,11 @@
5
5
  <div class="flex-1 flex flex-col">
6
6
 
7
7
  <div class="p-6 pb-0 flex flex-row gap-3 items-center">
8
- <div class="mr-6">
8
+ <div class="mr-6 hidden md:block">
9
9
  <h2>{{ title }}</h2>
10
10
  </div>
11
- <div class="flex-1 overflow-hidden mr-4">
11
+ <div class="flex-1"></div>
12
+ <div class="overflow-hidden mr-4 hidden md:block">
12
13
  <slot v-if="$slots['lp-search']" name="lp-search" :preset="preset"/>
13
14
  <Textbox v-else :clearable="true" placeholder="Cari..." class="w-[200px]" v-model="preset.search"
14
15
  @clear="clearSearch" @submit="load">
@@ -21,7 +22,7 @@
21
22
  </template>
22
23
  </Textbox>
23
24
  </div>
24
- <div>
25
+ <div class="hidden md:block">
25
26
  <slot name="lp-tabspace" :preset="preset"/>
26
27
  </div>
27
28
  <div class="flex flex-row gap-1 items-center">
@@ -45,8 +46,17 @@
45
46
  </div>
46
47
  </div>
47
48
 
48
- <VirtualTable class="flex-1 m-6" :columns="presetColumns" :items="items"
49
- :appearances="appearances" @scroll-end="loadNext">
49
+ <VirtualScroll v-if="isMobile.value" :items="items" class="flex-1" @scroll-end="loadNext">
50
+ <template #item="{ item, index }">
51
+ <slot v-if="$slots.mobile" name="mobile" :item="item" :index="index"></slot>
52
+ <div v-else>
53
+ <div class="h-[2rem] bg-base-300 rounded-lg my-2"></div>
54
+ </div>
55
+ </template>
56
+ </VirtualScroll>
57
+
58
+ <VirtualTable v-else class="flex-1 m-6" :columns="presetColumns" :items="items"
59
+ :appearances="appearances" @scroll-end="loadNext" :pinned="pinned">
50
60
  <template v-for="(_, slot) in $slots" #[slot]="{ item, index }">
51
61
  <slot :name="slot" :item="item" :index="index"></slot>
52
62
  </template>
@@ -191,6 +201,8 @@ export default{
191
201
 
192
202
  title: String,
193
203
 
204
+ pinned: Function
205
+
194
206
  },
195
207
 
196
208
  computed: {
@@ -80,6 +80,8 @@ export default{
80
80
 
81
81
  items: Array,
82
82
 
83
+ pinned: Function,
84
+
83
85
  defaultColumnWidth: {
84
86
  type: String,
85
87
  default: _DEFAULT_COLUMN_WIDTH
@@ -108,9 +110,30 @@ export default{
108
110
  return Math.round(this.scrollTop / this.itemHeight)
109
111
  },
110
112
 
113
+ sortedItems(){
114
+ if(!Array.isArray(this.items)) return []
115
+
116
+ if(typeof this.pinned === 'function'){
117
+ const pinnedItems = []
118
+ const unpinnedItems = []
119
+ this.items.forEach((item) => {
120
+ if(this.pinned(item))
121
+ pinnedItems.push(item)
122
+ else
123
+ unpinnedItems.push(item)
124
+ })
125
+
126
+ return [
127
+ ...pinnedItems,
128
+ ...unpinnedItems
129
+ ]
130
+ }
131
+ return this.items
132
+ },
133
+
111
134
  visibleItems(){
112
135
  if(this.itemHeight <= 0) return []
113
- return this.items ? this.items.slice(this.visibleStartIndex, this.visibleStartIndex + this.maxVisibleItems) : []
136
+ return this.sortedItems.slice(this.visibleStartIndex, this.visibleStartIndex + this.maxVisibleItems)
114
137
  },
115
138
 
116
139
  spacerStyle(){
package/src/index.js CHANGED
@@ -1,14 +1,11 @@
1
- import {defineAsyncComponent} from "vue"
1
+ import {defineAsyncComponent, ref} from "vue"
2
2
  import {observeInit} from './helper.js'
3
+ import throttle from "lodash-es/throttle";
3
4
  //import './index.css'
4
5
 
5
- const isBrowser = () => {
6
- return typeof window === 'object'
7
- }
8
-
9
- const isMobile = () => {
10
- return isBrowser &&
11
- (window.innerWidth < window.innerHeight && window.innerWidth <= 800)
6
+ const calculateIsMobile = () => {
7
+ if(typeof window === 'undefined') return false
8
+ return window.innerWidth < window.innerHeight && window.innerWidth <= 800
12
9
  }
13
10
 
14
11
  let _UNIQID = 0
@@ -36,14 +33,18 @@ export default{
36
33
  install: (app, options) => {
37
34
  //console.log('installing webfxfy-vue...')
38
35
 
39
- app.config.globalProperties.isBrowser = isBrowser
40
- app.config.globalProperties.isMobile = isMobile
41
- app.config.globalProperties.uniqid = uniqid
36
+ let isMobile = ref(calculateIsMobile())
42
37
 
43
38
  if(typeof window !== 'undefined' && 'IntersectionObserver' in window) {
44
39
  app.config.globalProperties.$observe = observeInit()
40
+
41
+ window.addEventListener('resize', throttle(() => {
42
+ isMobile.value = calculateIsMobile()
43
+ }, 300, { trailing:true }))
45
44
  }
46
45
 
46
+ app.config.globalProperties.uniqid = uniqid
47
+ app.config.globalProperties.isMobile = isMobile
47
48
  app.config.globalProperties.$download = download
48
49
 
49
50
  app.component('Alert', defineAsyncComponent(() => import("./components/Alert.vue")))