renusify 2.4.4 → 2.5.1

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.
@@ -12,7 +12,7 @@
12
12
  width: 40px;
13
13
  height: 40px;
14
14
  position: absolute;
15
- transition: 2s all map.get(base.$transition, 'swing');
15
+ transition: 0.5s all map.get(base.$transition, 'swing');
16
16
  @include mixins.rtl() {
17
17
  right: -40px;
18
18
  }
@@ -25,7 +25,7 @@
25
25
  height: 100%;
26
26
  overflow: auto;
27
27
  position: absolute;
28
- transition: .5s all map.get(base.$transition, 'swing');
28
+ transition: .3s all map.get(base.$transition, 'swing');
29
29
  background-color: var(--color-sheet);
30
30
  color: var(--color-on-sheet);
31
31
  @include mixins.rtl() {
@@ -42,7 +42,7 @@
42
42
  height: 100vh;
43
43
  z-index: map.get(base.$z-index, 'important');
44
44
  background-color: var(--color-overlay);
45
- transition: 1s width map.get(base.$transition, 'swing');
45
+ transition: .1s width map.get(base.$transition, 'swing');
46
46
  overflow: hidden;
47
47
  @include mixins.rtl() {
48
48
  right: 0;
@@ -56,7 +56,7 @@
56
56
  width: 100vw;
57
57
  }
58
58
  .toolbar-side {
59
- transition: 2s all map.get(base.$transition, 'swing');
59
+ transition: 0.3s all map.get(base.$transition, 'swing');
60
60
  @include mixins.rtl() {
61
61
  right: 0;
62
62
  }
@@ -106,7 +106,7 @@
106
106
  }
107
107
 
108
108
  .menu-list {
109
- transition: 1s map.get(base.$transition, 'swing');
109
+ transition: 0.3s map.get(base.$transition, 'swing');
110
110
  min-width: 200px;
111
111
  max-height: 500px;
112
112
  overflow-y: auto;
@@ -129,7 +129,7 @@
129
129
  position: relative;
130
130
 
131
131
  .toolbar-childs {
132
- transition: 1s map.get(base.$transition, 'swing');
132
+ transition: 0.3s map.get(base.$transition, 'swing');
133
133
  position: absolute;
134
134
  top: 40px;
135
135
  max-height: 0;
@@ -2,20 +2,24 @@ export const color = {
2
2
  methods: {
3
3
  setColorValue(color) {
4
4
  let rgba = {r: 0, g: 0, b: 0, a: 1}
5
- if (/#/.test(color)) {
5
+ const rgbRegex = /^rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*([01]?\.\d+)?\s*)?\)$/;
6
+ const hexRegex = /^#([a-f0-9]{6}|[a-f0-9]{8})$/i;
7
+ if (hexRegex.test(color)) {
6
8
  rgba = this.hex2rgba(color)
7
- } else if (/rgb/.test(color)) {
9
+ } else if (rgbRegex.test(color)) {
8
10
  rgba = this.rgb2rgba(color)
9
11
  } else if (Object.prototype.toString.call(color) === '[object Object]') {
10
12
  rgba = color
13
+ } else {
14
+ return
11
15
  }
12
16
  this.r = rgba.r
13
17
  this.g = rgba.g
14
18
  this.b = rgba.b
15
- if (rgba.a >= 0) {
19
+ if (rgba.a >= 0 && rgba.a <= 1) {
16
20
  this.a = rgba.a
17
21
  } else {
18
- this.a = rgba.a || 1
22
+ this.a = 1
19
23
  }
20
24
 
21
25
  this.set_hsv(rgba)
@@ -56,20 +60,35 @@ export const color = {
56
60
  ctx.fillStyle = gradient
57
61
  ctx.fillRect(0, 0, width, height)
58
62
  },
59
- rgb2hex({r, g, b}, toUpper) {
60
- const change = (val) => ('0' + Number(val).toString(16)).slice(-2)
61
- const color = `#${change(r)}${change(g)}${change(b)}`
62
- return toUpper ? color.toUpperCase() : color
63
+ rgb2hex({r, g, b, a}, toUpper = false) {
64
+ const change = (val) => {
65
+ const hex = Math.round(val).toString(16);
66
+ return hex.length === 1 ? '0' + hex : hex;
67
+ };
68
+
69
+ let color = `#${change(r)}${change(g)}${change(b)}`;
70
+
71
+ if (a !== undefined && a !== 1) {
72
+ const alpha = Math.round(a * 255);
73
+ color += change(alpha);
74
+ }
75
+
76
+ return toUpper ? color.toUpperCase() : color;
63
77
  },
64
78
  hex2rgba(hex) {
65
79
  hex = hex.slice(1)
66
- const change = (val) => parseInt(val, 16) || 0 // Avoid NaN situations
67
- return {
68
- r: change(hex.slice(0, 2)),
69
- g: change(hex.slice(2, 4)),
70
- b: change(hex.slice(4, 6)),
71
- a: 1
80
+ const change = (val) => parseInt(val, 16) || 0;
81
+ const r = change(hex.slice(0, 2));
82
+ const g = change(hex.slice(2, 4));
83
+ const b = change(hex.slice(4, 6));
84
+
85
+ let a = 1;
86
+ if (hex.length === 8) {
87
+ const alphaHex = hex.slice(6, 8);
88
+ a = parseFloat((parseInt(alphaHex, 16) / 255).toFixed(2));
72
89
  }
90
+
91
+ return {r, g, b, a};
73
92
  },
74
93
  rgb2rgba(rgba) {
75
94
  rgba = (/rgba?\((.*?)\)/.exec(rgba) || ['', '0,0,0,1'])[1].split(',')
@@ -129,9 +129,6 @@ export default {
129
129
  },
130
130
  inputHex(color) {
131
131
  const value = color.target.value
132
- if (value.length !== 7) {
133
- return
134
- }
135
132
  this.setColorValue(value)
136
133
  this.$nextTick(() => {
137
134
 
@@ -5,7 +5,7 @@
5
5
  :active="active"
6
6
  inputControlClass="v-center"
7
7
  >
8
- <r-btn @click.prevent.stop="minus" class="minus" icon :text="btnText">
8
+ <r-btn :disabled="min!==undefined&&number<=min" :text="btnText" class="minus" icon @click.prevent.stop="minus">
9
9
  <r-icon v-html="$r.icons.minus"></r-icon>
10
10
  </r-btn>
11
11
  <input @input="emit"
@@ -18,7 +18,7 @@
18
18
  autocomplete="no"
19
19
  v-model="number"
20
20
  />
21
- <r-btn @click.prevent.stop="plus" class="plus" icon :text="btnText">
21
+ <r-btn :disabled="max!==undefined&&number>=max" :text="btnText" class="plus" icon @click.prevent.stop="plus">
22
22
  <r-icon v-html="$r.icons.plus"></r-icon>
23
23
  </r-btn>
24
24
  </r-input>
@@ -85,7 +85,7 @@ emits:['update:modelValue','change'],
85
85
  width: 100%;
86
86
  height: 100%;
87
87
  border-radius: 10px;
88
- background-color: var(--color-sheet-container);
88
+ background-color: var(--color-border);
89
89
  }
90
90
 
91
91
  .switch-dot {
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <div :class="`${$r.prefix}input-tel`">
3
3
  <r-btn :disabled="!select||readonly"
4
- :rounded="!c_tile" class="btn-country ltr ms-1" outlined @click.stop="toggleDropdown">
4
+ :rounded="!c_tile" class="btn-country ltr mr-1" outlined @click.stop="toggleDropdown">
5
5
  <div :class="activeCountry.iso2.toLowerCase()" class="iti-flag"></div>
6
6
  <span class="country-code pa-1"> +{{ activeCountry.dialCode }} </span>
7
7
  <span class="dropdown-arrow">{{ open ? "▲" : "▼" }}</span>
@@ -152,7 +152,7 @@ export default {
152
152
 
153
153
  .#{base.$prefix}input-tel {
154
154
  display: flex;
155
- align-items: baseline;
155
+ align-items: end;
156
156
  direction: ltr;
157
157
  flex-wrap: wrap;
158
158
  .btn-country {
@@ -1,18 +1,13 @@
1
1
  <template>
2
2
  <div v-intersect.[modifier]="check" :class="{
3
3
  [$r.prefix+'img']:true,
4
- 'img-hoverZoom':hoverZoom,'img-hoverDark':hoverDark,'img-hoverTitle':hoverTitle}"
4
+ 'img-hoverZoom':hoverZoom,'img-hoverDark':hoverDark,'img-hover-preview':preview}"
5
5
  ref="rImg">
6
- <div v-if="hoverTitle" class="title-3 color-white-text img-title w-full pa-1"
7
- :class="{
8
- 'title-hs':titleHs,
9
- 'title-hc':titleHc,
10
- 'title-he':titleHe,
11
- 'title-vs':titleVs,
12
- 'title-vc':titleVc,
13
- 'title-ve':titleVe
14
- }"
15
- >{{ alt }}
6
+ <div v-if="preview" class="img-preview w-full h-full d-flex v-center h-center"
7
+ >
8
+ <r-btn icon @click="show_preview=true">
9
+ <r-icon v-html="$r.icons.eye"></r-icon>
10
+ </r-btn>
16
11
  </div>
17
12
  <img v-if="load &&!isSvg" ref="img" :alt="alt" :height="size.height>0?size.height:'auto'" :src="link" :style="{'height':size.height>0?undefined:'auto',
18
13
  'width':size.width>0?undefined:'auto'
@@ -21,6 +16,9 @@
21
16
  draggable="false"/>
22
17
  <svg-img v-else-if="load &&isSvg&&link" :link="link" :size="size">
23
18
  </svg-img>
19
+ <teleport v-if="preview&&show_preview" :to="`.${$r.prefix}app`">
20
+ <preview-img :src="preview" @close="show_preview=false"></preview-img>
21
+ </teleport>
24
22
  </div>
25
23
  </template>
26
24
  <script>
@@ -28,12 +26,16 @@ import {defineAsyncComponent} from 'vue'
28
26
 
29
27
  export default {
30
28
  name: 'r-img',
31
- components: {SvgImg:defineAsyncComponent(()=>import('./svgImg.vue'))},
29
+ components: {
30
+ SvgImg: defineAsyncComponent(() => import('./svgImg.vue')),
31
+ previewImg: defineAsyncComponent(() => import('./preview.vue')),
32
+ },
32
33
  props: {
33
34
  src: {
34
35
  type: String,
35
36
  required: true
36
37
  },
38
+ preview: String,
37
39
  alt: {
38
40
  type: String,
39
41
  required: true
@@ -55,19 +57,13 @@ export default {
55
57
  autoSize: Boolean,
56
58
  hoverZoom: Boolean,
57
59
  hoverDark: Boolean,
58
- hoverTitle: Boolean,
59
- titleHs: Boolean,
60
- titleHc: Boolean,
61
- titleHe: Boolean,
62
- titleVs: Boolean,
63
- titleVc: Boolean,
64
- titleVe: Boolean,
65
60
  isSvg: Boolean,
66
61
  svgCache: {type: Number, default: 86400},
67
62
  wPH: Number
68
63
  },
69
64
  data() {
70
65
  return {
66
+ show_preview: false,
71
67
  load: false,
72
68
  view: false,
73
69
  modifier: this.lazy !== 'no' ? 'once' : 'pre',
@@ -180,6 +176,7 @@ export default {
180
176
  }
181
177
  </script>
182
178
  <style lang="scss">
179
+ @use "sass:map";
183
180
  @use "../../style/variables/base";
184
181
 
185
182
  .#{base.$prefix}img {
@@ -211,44 +208,65 @@ export default {
211
208
  }
212
209
  }
213
210
 
214
- &.img-hoverTitle {
211
+ &.img-hover-preview {
215
212
  &:hover {
216
- .img-title {
213
+ .img-preview {
214
+ background: rgba(0, 0, 0, 0.5);
217
215
  max-width: 100%;
218
216
  }
219
217
  }
220
218
  }
221
219
 
222
- .img-title {
220
+ .img-preview {
221
+ transition: 0.1s all ease;
223
222
  position: absolute;
224
223
  z-index: 1;
224
+ top: 0;
225
+ left: 0;
225
226
  max-width: 0;
226
227
  overflow: hidden;
228
+ }
229
+ }
227
230
 
228
- &.title-hs {
229
- text-align: start;
230
- }
231
-
232
- &.title-hc {
233
- text-align: center;
234
- }
235
-
236
- &.title-he {
237
- text-align: end;
238
- }
231
+ .#{base.$prefix}img-preview-container {
232
+ width: 100vw;
233
+ height: 100vh;
234
+ overflow: hidden;
235
+ position: fixed;
236
+ touch-action: none;
237
+ background: var(--color-overlay);
238
+ backdrop-filter: blur(3px) grayscale(30%);
239
+ z-index: map.get(base.$z-index, 'important');
240
+ top: 0;
241
+ left: 0;
239
242
 
240
- &.title-vs {
241
- top: 10px
242
- }
243
+ .image-wrapper {
244
+ position: absolute;
245
+ will-change: transform;
246
+ }
243
247
 
244
- &.title-vc {
245
- top: 50%
246
- }
248
+ .image-wrapper img {
249
+ display: block;
250
+ }
247
251
 
248
- &.title-ve {
249
- bottom: 10px
250
- }
252
+ .controls {
253
+ position: absolute;
254
+ bottom: 10px;
255
+ left: 50%;
256
+ transform: translateX(-50%);
257
+ background: rgba(0, 0, 0, 0.5);
258
+ color: white;
259
+ padding: 5px 10px;
260
+ border-radius: 5px;
261
+ display: flex;
262
+ gap: 10px;
263
+ align-items: center;
264
+ z-index: 2;
265
+ }
251
266
 
267
+ .controls button {
268
+ padding: 2px 8px;
269
+ cursor: pointer;
252
270
  }
253
271
  }
254
272
  </style>
@@ -0,0 +1,238 @@
1
+ <template>
2
+ <div ref="container"
3
+ class="ltr"
4
+ :class="{ [$r.prefix+'img-preview-container']:true}">
5
+ <div
6
+ :style="wrapperStyle"
7
+ class="image-wrapper"
8
+ @mousedown="startDrag"
9
+ @touchstart="startDrag"
10
+ @wheel.prevent="handleWheel"
11
+ >
12
+ <span :style="imageHolderStyle">
13
+ <img
14
+ :src="src"
15
+ :style="imageStyle"
16
+ alt="Preview image"
17
+ @load="handleImageLoad"
18
+ >
19
+ </span>
20
+ </div>
21
+
22
+ <div v-if="showControls" class="controls">
23
+ <button @click="zoomIn">
24
+ <r-icon v-html="$r.icons.plus"></r-icon>
25
+ </button>
26
+ <button @click="zoomOut">
27
+ <r-icon v-html="$r.icons.minus"></r-icon>
28
+ </button>
29
+ <button class="font-weight-bold" @click="rotate">↻</button>
30
+ <button @click="reset">R</button>
31
+ <button @click="$emit('close',true)">
32
+ <r-icon v-html="$r.icons.close"></r-icon>
33
+ </button>
34
+ </div>
35
+ </div>
36
+ </template>
37
+
38
+ <script>
39
+ import {computed, onBeforeUnmount, onMounted, ref} from 'vue';
40
+
41
+ export default {
42
+ props: {
43
+ src: {
44
+ type: String,
45
+ required: true
46
+ },
47
+ maxScale: {
48
+ type: Number,
49
+ default: 5
50
+ },
51
+ minScale: {
52
+ type: Number,
53
+ default: 0.1
54
+ },
55
+ showControls: {
56
+ type: Boolean,
57
+ default: true
58
+ }
59
+ },
60
+
61
+ setup(props) {
62
+ const container = ref(null);
63
+ const scale = ref(1);
64
+ const rotation = ref(0);
65
+ const position = ref({x: 0, y: 0});
66
+ const isDragging = ref(false);
67
+ const dragStart = ref({x: 0, y: 0});
68
+ const naturalSize = ref({width: 0, height: 0});
69
+ const containerSize = ref({width: 0, height: 0});
70
+
71
+ const wrapperStyle = computed(() => ({
72
+ transform: `translate(${position.value.x}px, ${position.value.y}px)`,
73
+ cursor: isDragging.value ? 'grabbing' : 'grab'
74
+ }));
75
+
76
+ const imageStyle = computed(() => ({
77
+ transform: `scale(${scale.value})`,
78
+ transformOrigin: '0 0',
79
+ width: naturalSize.value.width ? `${naturalSize.value.width}px` : 'auto',
80
+ height: naturalSize.value.height ? `${naturalSize.value.height}px` : 'auto',
81
+ display: 'block'
82
+ }));
83
+ const imageHolderStyle = computed(() => ({
84
+ transform: `rotate(${rotation.value}deg)`,
85
+ transformOrigin: 'center center',
86
+ width: naturalSize.value.width ? `${naturalSize.value.width * scale.value}px` : 'auto',
87
+ height: naturalSize.value.height ? `${naturalSize.value.height * scale.value}px` : 'auto',
88
+ display: 'block'
89
+ }));
90
+
91
+ const handleImageLoad = (event) => {
92
+ naturalSize.value = {
93
+ width: event.target.naturalWidth,
94
+ height: event.target.naturalHeight
95
+ };
96
+ updateContainerSize();
97
+ centerImage();
98
+ };
99
+
100
+ const updateContainerSize = () => {
101
+ if (container.value) {
102
+ containerSize.value = {
103
+ width: container.value.clientWidth,
104
+ height: container.value.clientHeight
105
+ };
106
+ }
107
+ };
108
+
109
+ const centerImage = () => {
110
+ if (!container.value || !naturalSize.value.width) return;
111
+
112
+ const widthRatio = containerSize.value.width / naturalSize.value.width;
113
+ const heightRatio = containerSize.value.height / naturalSize.value.height;
114
+ const initialScale = Math.min(widthRatio, heightRatio, 1); // Don't scale up initially
115
+
116
+ scale.value = initialScale;
117
+ rotation.value = 0;
118
+
119
+ position.value = {
120
+ x: (containerSize.value.width - naturalSize.value.width * scale.value) / 2,
121
+ y: (containerSize.value.height - naturalSize.value.height * scale.value) / 2
122
+ };
123
+ };
124
+
125
+ const rotate = () => {
126
+ if (!container.value) return;
127
+ rotation.value = (rotation.value + 22.5) % 360;
128
+ };
129
+
130
+ const zoom = (factor, clientX, clientY) => {
131
+ if (!container.value) return;
132
+
133
+ const oldScale = scale.value;
134
+ scale.value = Math.min(
135
+ Math.max(scale.value * factor, props.minScale),
136
+ props.maxScale
137
+ );
138
+
139
+ const rect = container.value.getBoundingClientRect();
140
+ const containerX = clientX - rect.left;
141
+ const containerY = clientY - rect.top;
142
+
143
+ const imageX = (containerX - position.value.x) / oldScale;
144
+ const imageY = (containerY - position.value.y) / oldScale;
145
+
146
+ position.value.x = containerX - imageX * scale.value;
147
+ position.value.y = containerY - imageY * scale.value;
148
+ };
149
+
150
+ const zoomIn = () => {
151
+ if (!container.value) return;
152
+ const rect = container.value.getBoundingClientRect();
153
+ zoom(1.2, rect.left + rect.width / 2, rect.top + rect.height / 2);
154
+ };
155
+
156
+ const zoomOut = () => {
157
+ if (!container.value) return;
158
+ const rect = container.value.getBoundingClientRect();
159
+ zoom(0.8, rect.left + rect.width / 2, rect.top + rect.height / 2);
160
+ };
161
+
162
+ const reset = () => {
163
+ centerImage();
164
+ };
165
+
166
+ const startDrag = (e) => {
167
+ if (isDragging.value) return
168
+ isDragging.value = true;
169
+ const clientX = e.clientX || e.touches[0].clientX;
170
+ const clientY = e.clientY || e.touches[0].clientY;
171
+
172
+ dragStart.value = {
173
+ x: clientX - position.value.x,
174
+ y: clientY - position.value.y
175
+ };
176
+
177
+ e.preventDefault();
178
+ };
179
+
180
+ const handleDrag = (e) => {
181
+ if (!isDragging.value) return;
182
+
183
+ const clientX = e.clientX || (e.touches && e.touches[0].clientX);
184
+ const clientY = e.clientY || (e.touches && e.touches[0].clientY);
185
+
186
+ if (clientX === undefined || clientY === undefined) return;
187
+
188
+ position.value = {
189
+ x: clientX - dragStart.value.x,
190
+ y: clientY - dragStart.value.y
191
+ };
192
+ e.preventDefault();
193
+ };
194
+
195
+ const endDrag = () => {
196
+ isDragging.value = false;
197
+ };
198
+
199
+ const handleWheel = (e) => {
200
+ const factor = e.deltaY < 0 ? 1.1 : 0.9;
201
+ zoom(factor, e.clientX, e.clientY);
202
+ };
203
+
204
+ onMounted(() => {
205
+ window.addEventListener('mousemove', handleDrag);
206
+ window.addEventListener('mouseup', endDrag);
207
+ window.addEventListener('touchmove', handleDrag, {passive: false});
208
+ window.addEventListener('touchend', endDrag);
209
+ window.addEventListener('resize', updateContainerSize);
210
+ });
211
+
212
+ onBeforeUnmount(() => {
213
+ window.removeEventListener('mousemove', handleDrag);
214
+ window.removeEventListener('mouseup', endDrag);
215
+ window.removeEventListener('touchmove', handleDrag);
216
+ window.removeEventListener('touchend', endDrag);
217
+ window.removeEventListener('resize', updateContainerSize);
218
+ });
219
+
220
+ return {
221
+ container,
222
+ scale,
223
+ rotation,
224
+ position,
225
+ wrapperStyle,
226
+ imageStyle,
227
+ imageHolderStyle,
228
+ handleImageLoad,
229
+ startDrag,
230
+ handleWheel,
231
+ zoomIn,
232
+ zoomOut,
233
+ reset,
234
+ rotate
235
+ };
236
+ }
237
+ };
238
+ </script>