nuxt-telegram-mini-app 0.0.1 → 0.0.3
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/.github/dependabot.yml +6 -0
- package/README.md +72 -15
- package/app/assets/css/main.css +1 -1
- package/app/components/tg/Button.vue +4 -3
- package/app/components/tg/Cell.vue +1 -1
- package/app/components/tg/Content.vue +1 -0
- package/app/composables/telegram.ts +370 -36
- package/app/pages/components.vue +283 -32
- package/app/pages/index.vue +16 -21
- package/app/types/telegram-webapp.ts +157 -3
- package/app/utils/color.ts +29 -5
- package/nuxt.config.ts +1 -1
- package/package.json +17 -17
- package/tests/pages.spec.ts +9 -12
- package/tests/telegram.spec.ts +1 -1
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { ref, computed, onMounted } from 'vue'
|
|
2
2
|
import type {
|
|
3
3
|
TelegramWebApp,
|
|
4
|
-
|
|
4
|
+
TelegramDownloadFileParams,
|
|
5
|
+
TelegramEmojiStatusParams,
|
|
6
|
+
TelegramHomeScreenStatus,
|
|
7
|
+
TelegramLocationData,
|
|
8
|
+
TelegramStoryShareParams,
|
|
9
|
+
TelegramWebAppDeviceStorage,
|
|
10
|
+
TelegramWebAppInitData,
|
|
11
|
+
TelegramWebAppSecureStorage,
|
|
12
|
+
TelegramWebAppInsets
|
|
5
13
|
} from '~/types/telegram-webapp'
|
|
6
14
|
|
|
7
15
|
// Helper to get WebApp instance
|
|
@@ -26,6 +34,29 @@ function initWebApp() {
|
|
|
26
34
|
}
|
|
27
35
|
}
|
|
28
36
|
|
|
37
|
+
function ensureWebApp() {
|
|
38
|
+
initWebApp()
|
|
39
|
+
return globalWebApp || getWebApp()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const emptyInsets: TelegramWebAppInsets = {
|
|
43
|
+
top: 0,
|
|
44
|
+
bottom: 0,
|
|
45
|
+
left: 0,
|
|
46
|
+
right: 0
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function storageCallback<T>(resolve: (value: T) => void, reject: (reason?: unknown) => void) {
|
|
50
|
+
return (error: unknown, result?: T) => {
|
|
51
|
+
if (error) {
|
|
52
|
+
reject(error)
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
resolve(result as T)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
29
60
|
// Main composable to access Telegram WebApp
|
|
30
61
|
export function useTelegramWebApp() {
|
|
31
62
|
const webApp = ref<TelegramWebApp | null>(null)
|
|
@@ -47,31 +78,39 @@ export function useTelegramWebApp() {
|
|
|
47
78
|
// Back Button
|
|
48
79
|
export function useBackButton() {
|
|
49
80
|
const visible = ref(false)
|
|
81
|
+
const mounted = ref(false)
|
|
50
82
|
|
|
51
83
|
onMounted(() => {
|
|
52
84
|
initWebApp()
|
|
53
85
|
if (globalWebApp?.BackButton) {
|
|
54
|
-
visible.value = globalWebApp.BackButton.isVisible
|
|
86
|
+
visible.value = globalWebApp.BackButton.isVisible ?? false
|
|
55
87
|
}
|
|
56
88
|
})
|
|
57
89
|
|
|
58
90
|
return {
|
|
59
91
|
supported: computed(() => !!globalWebApp?.BackButton),
|
|
60
|
-
mounted: computed(() =>
|
|
92
|
+
mounted: computed(() => mounted.value),
|
|
61
93
|
visible: computed(() => visible.value),
|
|
62
|
-
mount: () =>
|
|
63
|
-
|
|
94
|
+
mount: () => {
|
|
95
|
+
mounted.value = true
|
|
96
|
+
return true
|
|
97
|
+
},
|
|
98
|
+
unmount: () => {
|
|
99
|
+
mounted.value = false
|
|
100
|
+
visible.value = false
|
|
101
|
+
return true
|
|
102
|
+
},
|
|
64
103
|
show: () => {
|
|
65
|
-
if (globalWebApp?.BackButton) {
|
|
104
|
+
if (globalWebApp?.BackButton?.show) {
|
|
66
105
|
globalWebApp.BackButton.show()
|
|
67
|
-
visible.value = true
|
|
68
106
|
}
|
|
107
|
+
visible.value = true
|
|
69
108
|
},
|
|
70
109
|
hide: () => {
|
|
71
|
-
if (globalWebApp?.BackButton) {
|
|
110
|
+
if (globalWebApp?.BackButton?.hide) {
|
|
72
111
|
globalWebApp.BackButton.hide()
|
|
73
|
-
visible.value = false
|
|
74
112
|
}
|
|
113
|
+
visible.value = false
|
|
75
114
|
},
|
|
76
115
|
onClick: (fn: () => void) => {
|
|
77
116
|
if (globalWebApp?.BackButton) {
|
|
@@ -96,7 +135,7 @@ export function useHapticFeedback() {
|
|
|
96
135
|
|
|
97
136
|
return {
|
|
98
137
|
supported: computed(() => !!globalWebApp?.HapticFeedback),
|
|
99
|
-
impactOccurred: (style: 'light' | 'medium' | 'heavy' = 'medium') => {
|
|
138
|
+
impactOccurred: (style: 'light' | 'medium' | 'heavy' | 'rigid' | 'soft' = 'medium') => {
|
|
100
139
|
if (globalWebApp?.HapticFeedback) {
|
|
101
140
|
globalWebApp.HapticFeedback.impactOccurred(style)
|
|
102
141
|
}
|
|
@@ -137,6 +176,7 @@ export function useInitData() {
|
|
|
137
176
|
authDate: computed(() => state.value?.auth_date),
|
|
138
177
|
queryId: computed(() => state.value?.query_id),
|
|
139
178
|
startParam: computed(() => state.value?.start_param),
|
|
179
|
+
signature: computed(() => state.value?.signature),
|
|
140
180
|
restore: () => {
|
|
141
181
|
// Official SDK handles this automatically
|
|
142
182
|
return true
|
|
@@ -146,27 +186,50 @@ export function useInitData() {
|
|
|
146
186
|
|
|
147
187
|
// Main Button
|
|
148
188
|
export function useMainButton() {
|
|
189
|
+
const mounted = ref(false)
|
|
190
|
+
const state = ref({
|
|
191
|
+
icon_custom_emoji_id: '',
|
|
192
|
+
text: '',
|
|
193
|
+
color: '',
|
|
194
|
+
text_color: '',
|
|
195
|
+
has_shine_effect: false,
|
|
196
|
+
is_active: false,
|
|
197
|
+
is_visible: false
|
|
198
|
+
})
|
|
199
|
+
|
|
149
200
|
onMounted(() => {
|
|
150
201
|
initWebApp()
|
|
202
|
+
if (globalWebApp?.MainButton) {
|
|
203
|
+
state.value = {
|
|
204
|
+
icon_custom_emoji_id: globalWebApp.MainButton.iconCustomEmojiId || '',
|
|
205
|
+
text: globalWebApp.MainButton.text || '',
|
|
206
|
+
color: globalWebApp.MainButton.color || '',
|
|
207
|
+
text_color: globalWebApp.MainButton.textColor || '',
|
|
208
|
+
has_shine_effect: globalWebApp.MainButton.hasShineEffect || false,
|
|
209
|
+
is_active: globalWebApp.MainButton.isActive || false,
|
|
210
|
+
is_visible: globalWebApp.MainButton.isVisible || false
|
|
211
|
+
}
|
|
212
|
+
}
|
|
151
213
|
})
|
|
152
214
|
|
|
153
215
|
return {
|
|
154
|
-
mounted: computed(() =>
|
|
155
|
-
enabled: computed(() =>
|
|
216
|
+
mounted: computed(() => mounted.value),
|
|
217
|
+
enabled: computed(() => state.value.is_active),
|
|
156
218
|
loaderVisible: computed(() => globalWebApp?.MainButton?.isProgressVisible || false),
|
|
157
|
-
visible: computed(() =>
|
|
158
|
-
state: computed(() =>
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
219
|
+
visible: computed(() => state.value.is_visible),
|
|
220
|
+
state: computed(() => state.value),
|
|
221
|
+
text: computed(() => state.value.text),
|
|
222
|
+
textColor: computed(() => state.value.text_color || undefined),
|
|
223
|
+
backgroundColor: computed(() => state.value.color || undefined),
|
|
224
|
+
mount: () => {
|
|
225
|
+
mounted.value = true
|
|
226
|
+
return true
|
|
227
|
+
},
|
|
228
|
+
unmount: () => {
|
|
229
|
+
mounted.value = false
|
|
230
|
+
state.value.is_visible = false
|
|
231
|
+
return true
|
|
232
|
+
},
|
|
170
233
|
onClick: (fn: () => void) => {
|
|
171
234
|
if (globalWebApp?.MainButton) {
|
|
172
235
|
globalWebApp.MainButton.onClick(fn)
|
|
@@ -180,19 +243,88 @@ export function useMainButton() {
|
|
|
180
243
|
}
|
|
181
244
|
},
|
|
182
245
|
setParams: (updates: {
|
|
246
|
+
icon_custom_emoji_id?: string
|
|
183
247
|
text?: string
|
|
184
248
|
color?: string
|
|
185
249
|
text_color?: string
|
|
250
|
+
has_shine_effect?: boolean
|
|
251
|
+
position?: 'left' | 'right' | 'top' | 'bottom'
|
|
186
252
|
is_active?: boolean
|
|
187
253
|
is_visible?: boolean
|
|
188
254
|
}) => {
|
|
189
|
-
|
|
255
|
+
state.value = {
|
|
256
|
+
...state.value,
|
|
257
|
+
...updates
|
|
258
|
+
}
|
|
259
|
+
if (globalWebApp?.MainButton?.setParams) {
|
|
190
260
|
globalWebApp.MainButton.setParams(updates)
|
|
191
261
|
}
|
|
192
262
|
}
|
|
193
263
|
}
|
|
194
264
|
}
|
|
195
265
|
|
|
266
|
+
export function useSecondaryButton() {
|
|
267
|
+
onMounted(() => {
|
|
268
|
+
initWebApp()
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
return {
|
|
272
|
+
mounted: computed(() => !!globalWebApp?.SecondaryButton),
|
|
273
|
+
enabled: computed(() => globalWebApp?.SecondaryButton?.isActive || false),
|
|
274
|
+
loaderVisible: computed(() => globalWebApp?.SecondaryButton?.isProgressVisible || false),
|
|
275
|
+
visible: computed(() => globalWebApp?.SecondaryButton?.isVisible || false),
|
|
276
|
+
text: computed(() => globalWebApp?.SecondaryButton?.text || ''),
|
|
277
|
+
textColor: computed(() => globalWebApp?.SecondaryButton?.textColor),
|
|
278
|
+
backgroundColor: computed(() => globalWebApp?.SecondaryButton?.color),
|
|
279
|
+
position: computed(() => globalWebApp?.SecondaryButton?.position),
|
|
280
|
+
onClick: (fn: () => void) => {
|
|
281
|
+
if (globalWebApp?.SecondaryButton) {
|
|
282
|
+
globalWebApp.SecondaryButton.onClick(fn)
|
|
283
|
+
return fn
|
|
284
|
+
}
|
|
285
|
+
return () => {}
|
|
286
|
+
},
|
|
287
|
+
offClick: (fn: () => void) => {
|
|
288
|
+
globalWebApp?.SecondaryButton?.offClick(fn)
|
|
289
|
+
},
|
|
290
|
+
setParams: (updates: {
|
|
291
|
+
icon_custom_emoji_id?: string
|
|
292
|
+
text?: string
|
|
293
|
+
color?: string
|
|
294
|
+
text_color?: string
|
|
295
|
+
has_shine_effect?: boolean
|
|
296
|
+
position?: 'left' | 'right' | 'top' | 'bottom'
|
|
297
|
+
is_active?: boolean
|
|
298
|
+
is_visible?: boolean
|
|
299
|
+
}) => {
|
|
300
|
+
globalWebApp?.SecondaryButton?.setParams(updates)
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
export function useSettingsButton() {
|
|
306
|
+
onMounted(() => {
|
|
307
|
+
initWebApp()
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
return {
|
|
311
|
+
supported: computed(() => !!globalWebApp?.SettingsButton),
|
|
312
|
+
visible: computed(() => globalWebApp?.SettingsButton?.isVisible || false),
|
|
313
|
+
show: () => globalWebApp?.SettingsButton?.show(),
|
|
314
|
+
hide: () => globalWebApp?.SettingsButton?.hide(),
|
|
315
|
+
onClick: (fn: () => void) => {
|
|
316
|
+
if (globalWebApp?.SettingsButton) {
|
|
317
|
+
globalWebApp.SettingsButton.onClick(fn)
|
|
318
|
+
return fn
|
|
319
|
+
}
|
|
320
|
+
return () => {}
|
|
321
|
+
},
|
|
322
|
+
offClick: (fn: () => void) => {
|
|
323
|
+
globalWebApp?.SettingsButton?.offClick(fn)
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
196
328
|
// Mini App / Theme management
|
|
197
329
|
export function useMiniApp() {
|
|
198
330
|
onMounted(() => {
|
|
@@ -203,6 +335,9 @@ export function useMiniApp() {
|
|
|
203
335
|
supported: computed(() => !!globalWebApp),
|
|
204
336
|
mounted: computed(() => !!globalWebApp),
|
|
205
337
|
active: computed(() => true), // Always active when available
|
|
338
|
+
foreground: computed(() => globalWebApp?.isActive ?? true),
|
|
339
|
+
fullscreen: computed(() => globalWebApp?.isFullscreen || false),
|
|
340
|
+
orientationLocked: computed(() => globalWebApp?.isOrientationLocked || false),
|
|
206
341
|
dark: computed(() => globalWebApp?.colorScheme === 'dark'),
|
|
207
342
|
state: computed(() => globalWebApp || null),
|
|
208
343
|
backgroundColor: computed(() => globalWebApp?.backgroundColor),
|
|
@@ -222,7 +357,14 @@ export function useMiniApp() {
|
|
|
222
357
|
if (globalWebApp) {
|
|
223
358
|
globalWebApp.setBottomBarColor(color)
|
|
224
359
|
}
|
|
225
|
-
}
|
|
360
|
+
},
|
|
361
|
+
enableClosingConfirmation: () => globalWebApp?.enableClosingConfirmation(),
|
|
362
|
+
disableClosingConfirmation: () => globalWebApp?.disableClosingConfirmation(),
|
|
363
|
+
enableVerticalSwipes: () => globalWebApp?.enableVerticalSwipes(),
|
|
364
|
+
disableVerticalSwipes: () => globalWebApp?.disableVerticalSwipes(),
|
|
365
|
+
lockOrientation: () => globalWebApp?.lockOrientation?.(),
|
|
366
|
+
unlockOrientation: () => globalWebApp?.unlockOrientation?.(),
|
|
367
|
+
hideKeyboard: () => globalWebApp?.hideKeyboard?.()
|
|
226
368
|
}
|
|
227
369
|
}
|
|
228
370
|
|
|
@@ -277,16 +419,17 @@ export function useViewport() {
|
|
|
277
419
|
return vh === svh
|
|
278
420
|
}),
|
|
279
421
|
insets: computed(() => ({
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
422
|
+
...(globalWebApp?.safeAreaInset || emptyInsets)
|
|
423
|
+
})),
|
|
424
|
+
contentInsets: computed(() => ({
|
|
425
|
+
...(globalWebApp?.contentSafeAreaInset || emptyInsets)
|
|
284
426
|
})),
|
|
427
|
+
fullscreen: computed(() => globalWebApp?.isFullscreen || false),
|
|
285
428
|
requestFullscreen: () => {
|
|
286
|
-
|
|
429
|
+
globalWebApp?.requestFullscreen?.()
|
|
287
430
|
},
|
|
288
431
|
exitFullscreen: () => {
|
|
289
|
-
|
|
432
|
+
globalWebApp?.exitFullscreen?.()
|
|
290
433
|
},
|
|
291
434
|
expand: () => {
|
|
292
435
|
if (globalWebApp) {
|
|
@@ -296,9 +439,155 @@ export function useViewport() {
|
|
|
296
439
|
}
|
|
297
440
|
}
|
|
298
441
|
|
|
442
|
+
export function useHomeScreen() {
|
|
443
|
+
onMounted(() => {
|
|
444
|
+
initWebApp()
|
|
445
|
+
})
|
|
446
|
+
|
|
447
|
+
const status = ref<TelegramHomeScreenStatus | undefined>()
|
|
448
|
+
|
|
449
|
+
return {
|
|
450
|
+
supported: computed(() => !!globalWebApp?.addToHomeScreen || !!globalWebApp?.checkHomeScreenStatus),
|
|
451
|
+
status: computed(() => status.value),
|
|
452
|
+
add: () => globalWebApp?.addToHomeScreen?.(),
|
|
453
|
+
check: () => {
|
|
454
|
+
globalWebApp?.checkHomeScreenStatus?.((nextStatus) => {
|
|
455
|
+
status.value = nextStatus
|
|
456
|
+
})
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
export function useEmojiStatus() {
|
|
462
|
+
onMounted(() => {
|
|
463
|
+
initWebApp()
|
|
464
|
+
})
|
|
465
|
+
|
|
466
|
+
return {
|
|
467
|
+
supported: computed(() => !!globalWebApp?.setEmojiStatus || !!globalWebApp?.requestEmojiStatusAccess),
|
|
468
|
+
set: (customEmojiId: string, params?: TelegramEmojiStatusParams) => {
|
|
469
|
+
return new Promise<boolean>((resolve) => {
|
|
470
|
+
if (!globalWebApp?.setEmojiStatus) {
|
|
471
|
+
resolve(false)
|
|
472
|
+
return
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
globalWebApp.setEmojiStatus(customEmojiId, params, resolve)
|
|
476
|
+
})
|
|
477
|
+
},
|
|
478
|
+
requestAccess: () => {
|
|
479
|
+
return new Promise<boolean>((resolve) => {
|
|
480
|
+
if (!globalWebApp?.requestEmojiStatusAccess) {
|
|
481
|
+
resolve(false)
|
|
482
|
+
return
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
globalWebApp.requestEmojiStatusAccess(resolve)
|
|
486
|
+
})
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
export function useTelegramStorage(type: 'cloud' | 'device' | 'secure' = 'cloud') {
|
|
492
|
+
onMounted(() => {
|
|
493
|
+
initWebApp()
|
|
494
|
+
})
|
|
495
|
+
|
|
496
|
+
const storage = computed(() => {
|
|
497
|
+
if (type === 'device') return globalWebApp?.DeviceStorage
|
|
498
|
+
if (type === 'secure') return globalWebApp?.SecureStorage
|
|
499
|
+
return globalWebApp?.CloudStorage
|
|
500
|
+
})
|
|
501
|
+
|
|
502
|
+
return {
|
|
503
|
+
supported: computed(() => !!storage.value),
|
|
504
|
+
setItem: (key: string, value: string) => {
|
|
505
|
+
return new Promise<boolean>((resolve, reject) => {
|
|
506
|
+
if (!storage.value) {
|
|
507
|
+
resolve(false)
|
|
508
|
+
return
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
storage.value.setItem(key, value, storageCallback(resolve, reject))
|
|
512
|
+
})
|
|
513
|
+
},
|
|
514
|
+
getItem: (key: string) => {
|
|
515
|
+
return new Promise<string | null>((resolve, reject) => {
|
|
516
|
+
if (!storage.value) {
|
|
517
|
+
resolve(null)
|
|
518
|
+
return
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
storage.value.getItem(key, storageCallback(resolve, reject))
|
|
522
|
+
})
|
|
523
|
+
},
|
|
524
|
+
removeItem: (key: string) => {
|
|
525
|
+
return new Promise<boolean>((resolve, reject) => {
|
|
526
|
+
if (!storage.value) {
|
|
527
|
+
resolve(false)
|
|
528
|
+
return
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
storage.value.removeItem(key, storageCallback(resolve, reject))
|
|
532
|
+
})
|
|
533
|
+
},
|
|
534
|
+
clear: () => {
|
|
535
|
+
return new Promise<boolean>((resolve, reject) => {
|
|
536
|
+
const currentStorage = storage.value as TelegramWebAppDeviceStorage | TelegramWebAppSecureStorage | undefined
|
|
537
|
+
if (!currentStorage?.clear) {
|
|
538
|
+
resolve(false)
|
|
539
|
+
return
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
currentStorage.clear(storageCallback(resolve, reject))
|
|
543
|
+
})
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
export function useLocationManager() {
|
|
549
|
+
onMounted(() => {
|
|
550
|
+
initWebApp()
|
|
551
|
+
})
|
|
552
|
+
|
|
553
|
+
return {
|
|
554
|
+
supported: computed(() => !!globalWebApp?.LocationManager),
|
|
555
|
+
inited: computed(() => globalWebApp?.LocationManager?.isInited || false),
|
|
556
|
+
available: computed(() => globalWebApp?.LocationManager?.isLocationAvailable || false),
|
|
557
|
+
accessRequested: computed(() => globalWebApp?.LocationManager?.isAccessRequested || false),
|
|
558
|
+
accessGranted: computed(() => globalWebApp?.LocationManager?.isAccessGranted || false),
|
|
559
|
+
init: () => globalWebApp?.LocationManager?.init(),
|
|
560
|
+
getLocation: () => {
|
|
561
|
+
return new Promise<TelegramLocationData | null>((resolve) => {
|
|
562
|
+
if (!globalWebApp?.LocationManager) {
|
|
563
|
+
resolve(null)
|
|
564
|
+
return
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
globalWebApp.LocationManager.getLocation(resolve)
|
|
568
|
+
})
|
|
569
|
+
},
|
|
570
|
+
openSettings: () => globalWebApp?.LocationManager?.openSettings()
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
export function useDeviceMotion() {
|
|
575
|
+
onMounted(() => {
|
|
576
|
+
initWebApp()
|
|
577
|
+
})
|
|
578
|
+
|
|
579
|
+
return {
|
|
580
|
+
accelerometer: computed(() => globalWebApp?.Accelerometer),
|
|
581
|
+
deviceOrientation: computed(() => globalWebApp?.DeviceOrientation),
|
|
582
|
+
gyroscope: computed(() => globalWebApp?.Gyroscope),
|
|
583
|
+
lockOrientation: () => globalWebApp?.lockOrientation?.(),
|
|
584
|
+
unlockOrientation: () => globalWebApp?.unlockOrientation?.()
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
|
|
299
588
|
// Links and sharing
|
|
300
589
|
export function openLink(url: string, options?: { try_instant_view?: boolean }) {
|
|
301
|
-
const webApp =
|
|
590
|
+
const webApp = ensureWebApp()
|
|
302
591
|
if (webApp) {
|
|
303
592
|
webApp.openLink(url, options)
|
|
304
593
|
} else {
|
|
@@ -308,7 +597,7 @@ export function openLink(url: string, options?: { try_instant_view?: boolean })
|
|
|
308
597
|
}
|
|
309
598
|
|
|
310
599
|
export function openTelegramLink(url: string) {
|
|
311
|
-
const webApp =
|
|
600
|
+
const webApp = ensureWebApp()
|
|
312
601
|
if (webApp) {
|
|
313
602
|
webApp.openTelegramLink(url)
|
|
314
603
|
} else {
|
|
@@ -318,7 +607,7 @@ export function openTelegramLink(url: string) {
|
|
|
318
607
|
}
|
|
319
608
|
|
|
320
609
|
export function shareURL(url: string) {
|
|
321
|
-
const webApp =
|
|
610
|
+
const webApp = ensureWebApp()
|
|
322
611
|
if (webApp) {
|
|
323
612
|
// Use Web Share API if available, otherwise copy to clipboard
|
|
324
613
|
if (navigator.share) {
|
|
@@ -340,3 +629,48 @@ export function shareURL(url: string) {
|
|
|
340
629
|
}
|
|
341
630
|
}
|
|
342
631
|
}
|
|
632
|
+
|
|
633
|
+
export function shareToStory(mediaUrl: string, params?: TelegramStoryShareParams) {
|
|
634
|
+
const webApp = ensureWebApp()
|
|
635
|
+
if (webApp?.shareToStory) {
|
|
636
|
+
webApp.shareToStory(mediaUrl, params)
|
|
637
|
+
} else if (navigator.share) {
|
|
638
|
+
navigator.share({ url: mediaUrl }).catch(() => {})
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
export function shareMessage(messageId: string) {
|
|
643
|
+
const webApp = ensureWebApp()
|
|
644
|
+
return new Promise<boolean>((resolve) => {
|
|
645
|
+
if (!webApp?.shareMessage) {
|
|
646
|
+
resolve(false)
|
|
647
|
+
return
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
webApp.shareMessage(messageId, resolve)
|
|
651
|
+
})
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
export function downloadFile(params: TelegramDownloadFileParams) {
|
|
655
|
+
const webApp = ensureWebApp()
|
|
656
|
+
return new Promise<boolean>((resolve) => {
|
|
657
|
+
if (!webApp?.downloadFile) {
|
|
658
|
+
resolve(false)
|
|
659
|
+
return
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
webApp.downloadFile(params, resolve)
|
|
663
|
+
})
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
export function requestChat(reqId: string) {
|
|
667
|
+
const webApp = ensureWebApp()
|
|
668
|
+
return new Promise<boolean>((resolve) => {
|
|
669
|
+
if (!webApp?.requestChat) {
|
|
670
|
+
resolve(false)
|
|
671
|
+
return
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
webApp.requestChat(reqId, resolve)
|
|
675
|
+
})
|
|
676
|
+
}
|