Compare commits
	
		
			4 Commits
		
	
	
		
			b6f50bbf53
			...
			0b24b7cc05
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 0b24b7cc05 | |||
| 4e4bc3345d | |||
| 4a2ff8fce6 | |||
| 3a42c58013 | 
@@ -39,6 +39,7 @@
 | 
				
			|||||||
    "@types/dompurify": "^3.0.5",
 | 
					    "@types/dompurify": "^3.0.5",
 | 
				
			||||||
    "@types/node": "^20.11.28",
 | 
					    "@types/node": "^20.11.28",
 | 
				
			||||||
    "@types/nprogress": "^0.2.3",
 | 
					    "@types/nprogress": "^0.2.3",
 | 
				
			||||||
 | 
					    "@types/pulltorefreshjs": "^0.1.7",
 | 
				
			||||||
    "@unocss/reset": "^0.58.7",
 | 
					    "@unocss/reset": "^0.58.7",
 | 
				
			||||||
    "@vitejs/plugin-vue": "^5.0.4",
 | 
					    "@vitejs/plugin-vue": "^5.0.4",
 | 
				
			||||||
    "@vitejs/plugin-vue-jsx": "^3.1.0",
 | 
					    "@vitejs/plugin-vue-jsx": "^3.1.0",
 | 
				
			||||||
@@ -49,6 +50,7 @@
 | 
				
			|||||||
    "eslint-plugin-vue": "^9.17.0",
 | 
					    "eslint-plugin-vue": "^9.17.0",
 | 
				
			||||||
    "npm-run-all2": "^6.1.2",
 | 
					    "npm-run-all2": "^6.1.2",
 | 
				
			||||||
    "prettier": "^3.0.3",
 | 
					    "prettier": "^3.0.3",
 | 
				
			||||||
 | 
					    "pulltorefreshjs": "^0.1.22",
 | 
				
			||||||
    "typescript": "~5.4.0",
 | 
					    "typescript": "~5.4.0",
 | 
				
			||||||
    "unocss": "^0.58.7",
 | 
					    "unocss": "^0.58.7",
 | 
				
			||||||
    "vite": "^5.1.6",
 | 
					    "vite": "^5.1.6",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -67,8 +67,7 @@
 | 
				
			|||||||
      :max-rows="6"
 | 
					      :max-rows="6"
 | 
				
			||||||
      :loading="loading"
 | 
					      :loading="loading"
 | 
				
			||||||
      v-model="data.content"
 | 
					      v-model="data.content"
 | 
				
			||||||
      @keyup.ctrl.enter="sendMessage"
 | 
					      @keydown="onEditorKeydown"
 | 
				
			||||||
      @keyup.meta.enter="sendMessage"
 | 
					 | 
				
			||||||
      @paste="pasteMedia"
 | 
					      @paste="pasteMedia"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <template #append>
 | 
					      <template #append>
 | 
				
			||||||
@@ -161,6 +160,12 @@ async function sendMessage() {
 | 
				
			|||||||
  loading.value = false
 | 
					  loading.value = false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function onEditorKeydown(event: KeyboardEvent) {
 | 
				
			||||||
 | 
					  if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === "enter") {
 | 
				
			||||||
 | 
					    sendMessage()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
watch(
 | 
					watch(
 | 
				
			||||||
  () => channels.related.messages.reply_to,
 | 
					  () => channels.related.messages.reply_to,
 | 
				
			||||||
  (val) => {
 | 
					  (val) => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <v-list-group value="channels">
 | 
					  <v-list-group class="channels-list" value="channels">
 | 
				
			||||||
    <template #activator="{ props }">
 | 
					    <template #activator="{ props }">
 | 
				
			||||||
      <v-list-item
 | 
					      <v-list-item
 | 
				
			||||||
        v-bind="props"
 | 
					        v-bind="props"
 | 
				
			||||||
@@ -28,7 +28,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import { useUserinfo } from "@/stores/userinfo"
 | 
					import { useUserinfo } from "@/stores/userinfo"
 | 
				
			||||||
import { useRealms } from "@/stores/realms"
 | 
					 | 
				
			||||||
import { useChannels } from "@/stores/channels"
 | 
					import { useChannels } from "@/stores/channels"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const id = useUserinfo()
 | 
					const id = useUserinfo()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <v-list-group value="realms">
 | 
					  <v-list-group class="realms-list" value="realms">
 | 
				
			||||||
    <template #activator="{ props }">
 | 
					    <template #activator="{ props }">
 | 
				
			||||||
      <v-list-item
 | 
					      <v-list-item
 | 
				
			||||||
        v-bind="props"
 | 
					        v-bind="props"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,8 +35,12 @@
 | 
				
			|||||||
      </v-toolbar>
 | 
					      </v-toolbar>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <div class="flex-grow-1">
 | 
					      <div class="flex-grow-1">
 | 
				
			||||||
        <v-list density="compact" :opened="drawerMini ? [] : expanded"
 | 
					        <v-list
 | 
				
			||||||
                @update:opened="(val) => expanded = val">
 | 
					          class="resources-list"
 | 
				
			||||||
 | 
					          density="compact"
 | 
				
			||||||
 | 
					          :opened="drawerMini ? [] : expanded"
 | 
				
			||||||
 | 
					          @update:opened="(val) => expanded = val"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
          <channel-list />
 | 
					          <channel-list />
 | 
				
			||||||
          <v-divider class="border-opacity-75 my-2" />
 | 
					          <v-divider class="border-opacity-75 my-2" />
 | 
				
			||||||
          <realm-list />
 | 
					          <realm-list />
 | 
				
			||||||
@@ -83,14 +87,17 @@
 | 
				
			|||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import { computed, ref } from "vue"
 | 
					import { computed, onMounted, ref } from "vue"
 | 
				
			||||||
import { useUserinfo, signout as signoutAccount } from "@/stores/userinfo"
 | 
					import { useUserinfo } from "@/stores/userinfo"
 | 
				
			||||||
import { useWellKnown } from "@/stores/wellKnown"
 | 
					import { useWellKnown } from "@/stores/wellKnown"
 | 
				
			||||||
import { useUI } from "@/stores/ui"
 | 
					import { useUI } from "@/stores/ui"
 | 
				
			||||||
 | 
					import { useRealms } from "@/stores/realms"
 | 
				
			||||||
 | 
					import { useChannels } from "@/stores/channels"
 | 
				
			||||||
import RealmList from "@/components/realms/RealmList.vue"
 | 
					import RealmList from "@/components/realms/RealmList.vue"
 | 
				
			||||||
import NotificationList from "@/components/users/NotificationList.vue"
 | 
					import NotificationList from "@/components/users/NotificationList.vue"
 | 
				
			||||||
import ChannelList from "@/components/chat/channels/ChannelList.vue"
 | 
					import ChannelList from "@/components/chat/channels/ChannelList.vue"
 | 
				
			||||||
import UserMenu from "@/components/users/UserMenu.vue"
 | 
					import UserMenu from "@/components/users/UserMenu.vue"
 | 
				
			||||||
 | 
					import PullToRefresh from "pulltorefreshjs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ui = useUI()
 | 
					const ui = useUI()
 | 
				
			||||||
const expanded = ref<string[]>(["channels"])
 | 
					const expanded = ref<string[]>(["channels"])
 | 
				
			||||||
@@ -126,5 +133,18 @@ useWellKnown().readWellKnown()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const drawerOpen = ref(true)
 | 
					const drawerOpen = ref(true)
 | 
				
			||||||
const drawerMini = ref(false)
 | 
					const drawerMini = ref(false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					onMounted(() => {
 | 
				
			||||||
 | 
					  PullToRefresh.init({
 | 
				
			||||||
 | 
					    mainElement: ".resources-list",
 | 
				
			||||||
 | 
					    triggerElement: ".resources-list",
 | 
				
			||||||
 | 
					    onRefresh() {
 | 
				
			||||||
 | 
					      return Promise.all([
 | 
				
			||||||
 | 
					        useRealms().list(),
 | 
				
			||||||
 | 
					        useChannels().list()
 | 
				
			||||||
 | 
					      ])
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@ import { Preferences } from "@capacitor/preferences"
 | 
				
			|||||||
const serviceMap: { [id: string]: string } = {
 | 
					const serviceMap: { [id: string]: string } = {
 | 
				
			||||||
  interactive: "https://co.solsynth.dev",
 | 
					  interactive: "https://co.solsynth.dev",
 | 
				
			||||||
  identity: "https://id.solsynth.dev",
 | 
					  identity: "https://id.solsynth.dev",
 | 
				
			||||||
  messaging: "https://im.solsynth.dev",
 | 
					  messaging: "https://im.solsynth.dev"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export async function request(service: string, input: string, init?: RequestInit, noRetry?: boolean) {
 | 
					export async function request(service: string, input: string, init?: RequestInit, noRetry?: boolean) {
 | 
				
			||||||
@@ -36,9 +36,10 @@ export async function request(service: string, input: string, init?: RequestInit
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    console.info("[REQUEST] Auth context has been refreshed.")
 | 
					    console.info("[REQUEST] Auth context has been refreshed.")
 | 
				
			||||||
    return await request(service, input, Object.assign(init as any, {
 | 
					    return await request(service, input, {
 | 
				
			||||||
      headers: { Authorization: `Bearer ${await getAtk()}` }
 | 
					      ...init,
 | 
				
			||||||
    }), true)
 | 
					      headers: { ...init?.headers, Authorization: `Bearer ${await getAtk()}` }
 | 
				
			||||||
 | 
					    }, true)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return res
 | 
					  return res
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -53,7 +53,7 @@ export const useNotifications = defineStore("notifications", () => {
 | 
				
			|||||||
    })
 | 
					    })
 | 
				
			||||||
    socket.addEventListener("close", (event) => {
 | 
					    socket.addEventListener("close", (event) => {
 | 
				
			||||||
      console.warn("[NOTIFICATIONS] The listen websocket is disconnected... ", event.reason, event.code)
 | 
					      console.warn("[NOTIFICATIONS] The listen websocket is disconnected... ", event.reason, event.code)
 | 
				
			||||||
      if(reconnectCount <= 3) {
 | 
					      if (reconnectCount <= 3) {
 | 
				
			||||||
        connect().then(() => {
 | 
					        connect().then(() => {
 | 
				
			||||||
          console.warn("[NOTIFICATIONS] Now reconnecting!")
 | 
					          console.warn("[NOTIFICATIONS] Now reconnecting!")
 | 
				
			||||||
          reconnectCount++
 | 
					          reconnectCount++
 | 
				
			||||||
@@ -62,8 +62,10 @@ export const useNotifications = defineStore("notifications", () => {
 | 
				
			|||||||
    })
 | 
					    })
 | 
				
			||||||
    socket.addEventListener("message", (event) => {
 | 
					    socket.addEventListener("message", (event) => {
 | 
				
			||||||
      const data = JSON.parse(event.data)
 | 
					      const data = JSON.parse(event.data)
 | 
				
			||||||
 | 
					      if (!data.is_realtime) {
 | 
				
			||||||
        notifications.value.push(data)
 | 
					        notifications.value.push(data)
 | 
				
			||||||
        total.value++
 | 
					        total.value++
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (Capacitor.getPlatform() === "web") {
 | 
					      if (Capacitor.getPlatform() === "web") {
 | 
				
			||||||
        new Notification(data["subject"], {
 | 
					        new Notification(data["subject"], {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,9 +16,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import PostList from "@/components/posts/PostList.vue"
 | 
					import PostList from "@/components/posts/PostList.vue"
 | 
				
			||||||
 | 
					import { onMounted, onUnmounted, reactive, ref } from "vue"
 | 
				
			||||||
import { request } from "@/scripts/request"
 | 
					import { request } from "@/scripts/request"
 | 
				
			||||||
import { reactive, ref } from "vue"
 | 
					 | 
				
			||||||
import { useUI } from "@/stores/ui"
 | 
					import { useUI } from "@/stores/ui"
 | 
				
			||||||
 | 
					import PullToRefresh, { type PullToRefreshInstance } from "pulltorefreshjs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const pagination = reactive({ page: 1, pageSize: 10, total: 0 })
 | 
					const pagination = reactive({ page: 1, pageSize: 10, total: 0 })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -63,6 +64,21 @@ async function readMore({ done }: any) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
readPosts()
 | 
					readPosts()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let refresher: PullToRefreshInstance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					onMounted(() => {
 | 
				
			||||||
 | 
					  refresher = PullToRefresh.init({
 | 
				
			||||||
 | 
					      mainElement: ".wrapper",
 | 
				
			||||||
 | 
					      triggerElement: ".wrapper",
 | 
				
			||||||
 | 
					      onRefresh() {
 | 
				
			||||||
 | 
					        posts.value = []
 | 
				
			||||||
 | 
					        pagination.page = 0
 | 
				
			||||||
 | 
					        return readPosts()
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					onUnmounted(() => refresher.destory())
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style scoped>
 | 
					<style scoped>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,7 +32,7 @@
 | 
				
			|||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import { reactive, ref, watch } from "vue"
 | 
					import { onMounted, onUnmounted, reactive, ref, watch } from "vue"
 | 
				
			||||||
import { request } from "@/scripts/request"
 | 
					import { request } from "@/scripts/request"
 | 
				
			||||||
import { useRealms } from "@/stores/realms"
 | 
					import { useRealms } from "@/stores/realms"
 | 
				
			||||||
import { useRoute } from "vue-router"
 | 
					import { useRoute } from "vue-router"
 | 
				
			||||||
@@ -41,6 +41,7 @@ import dompurify from "dompurify"
 | 
				
			|||||||
import PostList from "@/components/posts/PostList.vue"
 | 
					import PostList from "@/components/posts/PostList.vue"
 | 
				
			||||||
import RealmAction from "@/components/realms/RealmAction.vue"
 | 
					import RealmAction from "@/components/realms/RealmAction.vue"
 | 
				
			||||||
import RealmMembers from "@/components/realms/RealmMembers.vue"
 | 
					import RealmMembers from "@/components/realms/RealmMembers.vue"
 | 
				
			||||||
 | 
					import PullToRefresh, { type PullToRefreshInstance } from "pulltorefreshjs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const route = useRoute()
 | 
					const route = useRoute()
 | 
				
			||||||
const realms = useRealms()
 | 
					const realms = useRealms()
 | 
				
			||||||
@@ -122,6 +123,21 @@ watch(realms, (val) => {
 | 
				
			|||||||
function parseContent(src: string): string {
 | 
					function parseContent(src: string): string {
 | 
				
			||||||
  return dompurify().sanitize(parse(src) as string)
 | 
					  return dompurify().sanitize(parse(src) as string)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let refresher: PullToRefreshInstance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					onMounted(() => {
 | 
				
			||||||
 | 
					  refresher = PullToRefresh.init({
 | 
				
			||||||
 | 
					    mainElement: ".wrapper",
 | 
				
			||||||
 | 
					    triggerElement: ".wrapper",
 | 
				
			||||||
 | 
					    onRefresh() {
 | 
				
			||||||
 | 
					      posts.value = []
 | 
				
			||||||
 | 
					      pagination.page = 0
 | 
				
			||||||
 | 
					      return readPosts()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					onUnmounted(() => refresher.destory())
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style scoped>
 | 
					<style scoped>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,6 +38,7 @@
 | 
				
			|||||||
    </v-card>
 | 
					    </v-card>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <v-card>
 | 
					    <v-card>
 | 
				
			||||||
 | 
					      <section v-if="canEditImage">
 | 
				
			||||||
      <v-card-text class="flex items-center gap-3">
 | 
					      <v-card-text class="flex items-center gap-3">
 | 
				
			||||||
        <v-avatar
 | 
					        <v-avatar
 | 
				
			||||||
          color="grey-lighten-2"
 | 
					          color="grey-lighten-2"
 | 
				
			||||||
@@ -49,7 +50,7 @@
 | 
				
			|||||||
        <v-file-input
 | 
					        <v-file-input
 | 
				
			||||||
          clearable
 | 
					          clearable
 | 
				
			||||||
          hide-details
 | 
					          hide-details
 | 
				
			||||||
          label="Upload another avatar"
 | 
					          label="New Avatar"
 | 
				
			||||||
          variant="outlined"
 | 
					          variant="outlined"
 | 
				
			||||||
          density="comfortable"
 | 
					          density="comfortable"
 | 
				
			||||||
          accept="image/*"
 | 
					          accept="image/*"
 | 
				
			||||||
@@ -70,7 +71,7 @@
 | 
				
			|||||||
        <v-file-input
 | 
					        <v-file-input
 | 
				
			||||||
          clearable
 | 
					          clearable
 | 
				
			||||||
          hide-details
 | 
					          hide-details
 | 
				
			||||||
          label="Update your banner"
 | 
					          label="New Banner"
 | 
				
			||||||
          variant="outlined"
 | 
					          variant="outlined"
 | 
				
			||||||
          density="comfortable"
 | 
					          density="comfortable"
 | 
				
			||||||
          accept="image/*"
 | 
					          accept="image/*"
 | 
				
			||||||
@@ -78,6 +79,14 @@
 | 
				
			|||||||
          @input="(val: InputEvent) => loadImage(val, 'banner')"
 | 
					          @input="(val: InputEvent) => loadImage(val, 'banner')"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </v-card-text>
 | 
					      </v-card-text>
 | 
				
			||||||
 | 
					      </section>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <v-card-text v-else>
 | 
				
			||||||
 | 
					        <v-alert variant="tonal" type="info" class="text-sm">
 | 
				
			||||||
 | 
					          Due to limitations of some browsers (such as Safari). You cannot edit your personal images in this browser.
 | 
				
			||||||
 | 
					          We recommend Chrome or any Chromium-based browser. You can also use a PWA for a better experience!
 | 
				
			||||||
 | 
					        </v-alert>
 | 
				
			||||||
 | 
					      </v-card-text>
 | 
				
			||||||
    </v-card>
 | 
					    </v-card>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <v-bottom-sheet class="max-w-[480px]" v-model="cropping">
 | 
					    <v-bottom-sheet class="max-w-[480px]" v-model="cropping">
 | 
				
			||||||
@@ -90,7 +99,7 @@
 | 
				
			|||||||
            :stencil-props="{ aspectRatio: image.ratio }"
 | 
					            :stencil-props="{ aspectRatio: image.ratio }"
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
        <v-card-actions>
 | 
					        <v-card-actions class="pb-16">
 | 
				
			||||||
          <v-spacer></v-spacer>
 | 
					          <v-spacer></v-spacer>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <v-btn color="grey-darken-3" @click="cropping = false">Cancel</v-btn>
 | 
					          <v-btn color="grey-darken-3" @click="cropping = false">Cancel</v-btn>
 | 
				
			||||||
@@ -123,6 +132,8 @@ const image = ref<any>({
 | 
				
			|||||||
const cropper = ref<any>()
 | 
					const cropper = ref<any>()
 | 
				
			||||||
const cropping = ref(false)
 | 
					const cropping = ref(false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const canEditImage = computed(() => navigator.userAgent.toLowerCase().indexOf("safari") > -1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
watch(
 | 
					watch(
 | 
				
			||||||
  id.userinfo,
 | 
					  id.userinfo,
 | 
				
			||||||
  (val) => {
 | 
					  (val) => {
 | 
				
			||||||
@@ -200,8 +211,12 @@ async function applyImage() {
 | 
				
			|||||||
  const payload = new FormData()
 | 
					  const payload = new FormData()
 | 
				
			||||||
  payload.set(image.value.type, await new Promise<Blob>((resolve, reject) => {
 | 
					  payload.set(image.value.type, await new Promise<Blob>((resolve, reject) => {
 | 
				
			||||||
    canvas.toBlob((data: Blob | null) => {
 | 
					    canvas.toBlob((data: Blob | null) => {
 | 
				
			||||||
      if (data == null) reject("Cannot get blob data")
 | 
					      if (data == null) {
 | 
				
			||||||
      else resolve(data)
 | 
					        showErrorSnackbar("Cannot get blob data through canvas, please try again in desktop browser.")
 | 
				
			||||||
 | 
					        reject("Cannot get blob data")
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        resolve(data)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
  }))
 | 
					  }))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user