Compare commits
No commits in common. "0b24b7cc0531a7009b5dc1adea31a39f3f4e3d13" and "b6f50bbf53ba13c054a104fc2c4e0b6913fe921c" have entirely different histories.
0b24b7cc05
...
b6f50bbf53
@ -39,7 +39,6 @@
|
|||||||
"@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",
|
||||||
@ -50,7 +49,6 @@
|
|||||||
"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,7 +67,8 @@
|
|||||||
:max-rows="6"
|
:max-rows="6"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
v-model="data.content"
|
v-model="data.content"
|
||||||
@keydown="onEditorKeydown"
|
@keyup.ctrl.enter="sendMessage"
|
||||||
|
@keyup.meta.enter="sendMessage"
|
||||||
@paste="pasteMedia"
|
@paste="pasteMedia"
|
||||||
>
|
>
|
||||||
<template #append>
|
<template #append>
|
||||||
@ -160,12 +161,6 @@ 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 class="channels-list" value="channels">
|
<v-list-group value="channels">
|
||||||
<template #activator="{ props }">
|
<template #activator="{ props }">
|
||||||
<v-list-item
|
<v-list-item
|
||||||
v-bind="props"
|
v-bind="props"
|
||||||
@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
<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 class="realms-list" value="realms">
|
<v-list-group value="realms">
|
||||||
<template #activator="{ props }">
|
<template #activator="{ props }">
|
||||||
<v-list-item
|
<v-list-item
|
||||||
v-bind="props"
|
v-bind="props"
|
||||||
|
@ -35,12 +35,8 @@
|
|||||||
</v-toolbar>
|
</v-toolbar>
|
||||||
|
|
||||||
<div class="flex-grow-1">
|
<div class="flex-grow-1">
|
||||||
<v-list
|
<v-list density="compact" :opened="drawerMini ? [] : expanded"
|
||||||
class="resources-list"
|
@update:opened="(val) => expanded = val">
|
||||||
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 />
|
||||||
@ -87,17 +83,14 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onMounted, ref } from "vue"
|
import { computed, ref } from "vue"
|
||||||
import { useUserinfo } from "@/stores/userinfo"
|
import { useUserinfo, signout as signoutAccount } 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"])
|
||||||
@ -133,18 +126,5 @@ 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,10 +36,9 @@ 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, {
|
return await request(service, input, Object.assign(init as any, {
|
||||||
...init,
|
headers: { Authorization: `Bearer ${await getAtk()}` }
|
||||||
headers: { ...init?.headers, Authorization: `Bearer ${await getAtk()}` }
|
}), true)
|
||||||
}, 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,10 +62,8 @@ 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,10 +16,9 @@
|
|||||||
|
|
||||||
<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 })
|
||||||
|
|
||||||
@ -64,21 +63,6 @@ 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 { onMounted, onUnmounted, reactive, ref, watch } from "vue"
|
import { 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,7 +41,6 @@ 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()
|
||||||
@ -69,11 +68,11 @@ async function readPosts() {
|
|||||||
const res = await request(
|
const res = await request(
|
||||||
"interactive",
|
"interactive",
|
||||||
`/api/feed?` +
|
`/api/feed?` +
|
||||||
new URLSearchParams({
|
new URLSearchParams({
|
||||||
take: pagination.pageSize.toString(),
|
take: pagination.pageSize.toString(),
|
||||||
offset: ((pagination.page - 1) * pagination.pageSize).toString(),
|
offset: ((pagination.page - 1) * pagination.pageSize).toString(),
|
||||||
realmId: route.params.realmId as string
|
realmId: route.params.realmId as string
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
if (res.status !== 200) {
|
if (res.status !== 200) {
|
||||||
error.value = await res.text()
|
error.value = await res.text()
|
||||||
@ -123,21 +122,6 @@ 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,7 +38,6 @@
|
|||||||
</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"
|
||||||
@ -50,7 +49,7 @@
|
|||||||
<v-file-input
|
<v-file-input
|
||||||
clearable
|
clearable
|
||||||
hide-details
|
hide-details
|
||||||
label="New Avatar"
|
label="Upload another avatar"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
density="comfortable"
|
density="comfortable"
|
||||||
accept="image/*"
|
accept="image/*"
|
||||||
@ -71,7 +70,7 @@
|
|||||||
<v-file-input
|
<v-file-input
|
||||||
clearable
|
clearable
|
||||||
hide-details
|
hide-details
|
||||||
label="New Banner"
|
label="Update your banner"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
density="comfortable"
|
density="comfortable"
|
||||||
accept="image/*"
|
accept="image/*"
|
||||||
@ -79,14 +78,6 @@
|
|||||||
@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">
|
||||||
@ -99,7 +90,7 @@
|
|||||||
:stencil-props="{ aspectRatio: image.ratio }"
|
:stencil-props="{ aspectRatio: image.ratio }"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<v-card-actions class="pb-16">
|
<v-card-actions>
|
||||||
<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>
|
||||||
@ -132,8 +123,6 @@ 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) => {
|
||||||
@ -211,12 +200,8 @@ 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) {
|
if (data == null) reject("Cannot get blob data")
|
||||||
showErrorSnackbar("Cannot get blob data through canvas, please try again in desktop browser.")
|
else resolve(data)
|
||||||
reject("Cannot get blob data")
|
|
||||||
} else {
|
|
||||||
resolve(data)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user