mirror of
https://github.com/elk-zone/elk.git
synced 2024-12-13 14:49:47 +03:00
wip
This commit is contained in:
parent
3468c13e75
commit
1816530f84
10 changed files with 70 additions and 44 deletions
|
@ -6,7 +6,7 @@ const all = useUsers()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const masto = useMasto()
|
const masto = useMasto()
|
||||||
const switchUser = (user: UserLogin) => {
|
const switchUser = (user: UserLogin) => {
|
||||||
if (user.account.id === currentUser.value?.account.id)
|
if (!user.guest && !currentUser.value?.guest && user.account.id === currentUser.value?.account.id)
|
||||||
router.push(getAccountRoute(user.account))
|
router.push(getAccountRoute(user.account))
|
||||||
else
|
else
|
||||||
masto.loginTo(user)
|
masto.loginTo(user)
|
||||||
|
@ -21,7 +21,7 @@ const switchUser = (user: UserLogin) => {
|
||||||
flex rounded
|
flex rounded
|
||||||
cursor-pointer
|
cursor-pointer
|
||||||
aria-label="Switch user"
|
aria-label="Switch user"
|
||||||
:class="user.account.id === currentUser?.account.id ? '' : 'op25 grayscale'"
|
:class="user.account?.id === currentUser?.account?.id ? '' : 'op25 grayscale'"
|
||||||
hover="filter-none op100"
|
hover="filter-none op100"
|
||||||
@click="switchUser(user)"
|
@click="switchUser(user)"
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Fuse from 'fuse.js'
|
import Fuse from 'fuse.js'
|
||||||
import { $fetch } from 'ofetch'
|
import { $fetch } from 'ofetch'
|
||||||
import { DEFAULT_SERVER } from '~/constants'
|
|
||||||
|
const masto = useMasto()
|
||||||
|
|
||||||
const input = $ref<HTMLInputElement>()
|
const input = $ref<HTMLInputElement>()
|
||||||
let server = $ref<string>('')
|
let server = $ref<string>('')
|
||||||
|
@ -26,7 +27,7 @@ async function oauth() {
|
||||||
server = server.split('/')[0]
|
server = server.split('/')[0]
|
||||||
|
|
||||||
try {
|
try {
|
||||||
location.href = await $fetch<string>(`/api/${server || DEFAULT_SERVER}/login`, {
|
location.href = await $fetch<string>(`/api/${server}/login`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: {
|
body: {
|
||||||
origin: location.origin,
|
origin: location.origin,
|
||||||
|
@ -46,6 +47,10 @@ async function oauth() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function explore() {
|
||||||
|
masto.loginTo({ server, guest: true })
|
||||||
|
}
|
||||||
|
|
||||||
async function handleInput() {
|
async function handleInput() {
|
||||||
if (server.startsWith('https://'))
|
if (server.startsWith('https://'))
|
||||||
server = server.replace('https://', '')
|
server = server.replace('https://', '')
|
||||||
|
@ -180,9 +185,19 @@ onClickOutside($$(input), () => {
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<button flex="~ row" gap-x-2 items-center btn-solid mt2 :disabled="!server || busy">
|
<div flex="~ gap2" mt2 items-center>
|
||||||
<span aria-hidden="true" inline-block :class="busy ? 'i-ri:loader-2-fill animate animate-spin' : 'i-ri:login-circle-line'" class="rtl-flip" />
|
<button
|
||||||
{{ $t('action.sign_in') }}
|
type="button"
|
||||||
</button>
|
flex="~ row" gap-x-2 items-center btn-outline text-sm px2 py1 h-fit :disabled="!server || busy"
|
||||||
|
@click="explore"
|
||||||
|
>
|
||||||
|
<span aria-hidden="true" inline-block :class="busy ? 'i-ri:loader-2-fill animate animate-spin' : 'i-ri:user-4-line'" />
|
||||||
|
{{ $t('action.explore_as_a_guest') }}
|
||||||
|
</button>
|
||||||
|
<button flex="~ row" gap-x-2 items-center btn-solid :disabled="!server || busy">
|
||||||
|
<span aria-hidden="true" inline-block :class="busy ? 'i-ri:loader-2-fill animate animate-spin' : 'i-ri:login-circle-line'" class="rtl-flip" />
|
||||||
|
{{ $t('action.sign_in') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -344,9 +344,9 @@ export const provideGlobalCommands = () => {
|
||||||
parent: 'account-switch',
|
parent: 'account-switch',
|
||||||
scope: 'Switch account',
|
scope: 'Switch account',
|
||||||
|
|
||||||
visible: () => user.account.id !== currentUser.value?.account.id,
|
visible: () => !user.guest && user.account.id !== currentUser.value?.account?.id,
|
||||||
|
|
||||||
name: () => t('command.switch_account', [getFullHandle(user.account)]),
|
name: () => t('command.switch_account', [getFullHandle(user)]),
|
||||||
icon: 'i-ri:user-shared-line',
|
icon: 'i-ri:user-shared-line',
|
||||||
|
|
||||||
onActivate() {
|
onActivate() {
|
||||||
|
@ -357,8 +357,7 @@ export const provideGlobalCommands = () => {
|
||||||
scope: 'Account',
|
scope: 'Account',
|
||||||
|
|
||||||
visible: () => currentUser.value,
|
visible: () => currentUser.value,
|
||||||
|
name: () => currentUser.value ? t('user.sign_out_account', [getFullHandle(currentUser.value)]) : '',
|
||||||
name: () => t('user.sign_out_account', [getFullHandle(currentUser.value!.account)]),
|
|
||||||
icon: 'i-ri:logout-box-line',
|
icon: 'i-ri:logout-box-line',
|
||||||
|
|
||||||
onActivate() {
|
onActivate() {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type { Ref } from 'vue'
|
import type { Ref } from 'vue'
|
||||||
import type { Account, Relationship, Status } from 'masto'
|
import type { Account, Relationship, Status } from 'masto'
|
||||||
import { withoutProtocol } from 'ufo'
|
import { withoutProtocol } from 'ufo'
|
||||||
import type { ElkMasto } from '~/types'
|
import type { ElkMasto, UserLogin } from '~/types'
|
||||||
|
|
||||||
export const useMasto = () => useNuxtApp().$masto as ElkMasto
|
export const useMasto = () => useNuxtApp().$masto as ElkMasto
|
||||||
|
|
||||||
|
@ -33,7 +33,11 @@ export function getServerName(account: Account) {
|
||||||
return currentInstance.value?.uri || ''
|
return currentInstance.value?.uri || ''
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFullHandle(account: Account) {
|
export function getFullHandle(_account: Account | UserLogin) {
|
||||||
|
if ('guest' in _account && _account.guest)
|
||||||
|
return `[anonymous]@${_account.server}`
|
||||||
|
|
||||||
|
const account = 'server' in _account ? _account.account : _account
|
||||||
const handle = `@${account.acct}`
|
const handle = `@${account.acct}`
|
||||||
if (!currentUser.value || account.acct.includes('@'))
|
if (!currentUser.value || account.acct.includes('@'))
|
||||||
return handle
|
return handle
|
||||||
|
|
|
@ -45,34 +45,37 @@ const instances = useLocalStorage<Record<string, Instance>>(STORAGE_KEY_SERVERS,
|
||||||
const currentUserId = useLocalStorage<string>(STORAGE_KEY_CURRENT_USER, mock ? mock.user.account.id : '')
|
const currentUserId = useLocalStorage<string>(STORAGE_KEY_CURRENT_USER, mock ? mock.user.account.id : '')
|
||||||
|
|
||||||
export const currentUser = computed<UserLogin | undefined>(() => {
|
export const currentUser = computed<UserLogin | undefined>(() => {
|
||||||
if (currentUserId.value) {
|
if (!currentUserId.value)
|
||||||
const user = users.value.find(user => user.account?.id === currentUserId.value)
|
// Fallback to the first account
|
||||||
if (user)
|
return users.value[0]
|
||||||
return user
|
|
||||||
}
|
const user = users.value.find(user => user.account?.id === currentUserId.value)
|
||||||
// Fallback to the first account
|
if (user)
|
||||||
return users.value[0]
|
return user
|
||||||
})
|
})
|
||||||
|
|
||||||
const publicInstance = ref<Instance | null>(null)
|
export const isGuest = computed(
|
||||||
export const currentInstance = computed<null | Instance>(() => currentUser.value ? instances.value[currentUser.value.server] ?? null : publicInstance.value)
|
() => currentUserId.value.startsWith('[anonymous]@') || !currentUser.value?.account?.acct,
|
||||||
|
)
|
||||||
|
|
||||||
export const publicServer = ref(DEFAULT_SERVER)
|
export const currentServer = computed<string>(() => currentUser.value?.server || DEFAULT_SERVER)
|
||||||
export const currentServer = computed<string>(() => currentUser.value?.server || publicServer.value)
|
export const currentInstance = computed<null | Instance>(() => {
|
||||||
|
return instances.value[currentServer.value] ?? null
|
||||||
|
})
|
||||||
|
|
||||||
export const currentUserHandle = computed(() => currentUser.value?.account.id
|
export const currentUserHandle = computed(() =>
|
||||||
? `${currentUser.value.account.acct}@${currentInstance.value?.uri || currentServer.value}`
|
isGuest.value ? '[anonymous]' : currentUser.value!.account!.acct
|
||||||
: '[anonymous]',
|
,
|
||||||
)
|
)
|
||||||
|
|
||||||
export const useUsers = () => users
|
export const useUsers = () => users
|
||||||
|
|
||||||
export const characterLimit = computed(() => currentInstance.value?.configuration.statuses.maxCharacters ?? DEFAULT_POST_CHARS_LIMIT)
|
export const characterLimit = computed(() => currentInstance.value?.configuration.statuses.maxCharacters ?? DEFAULT_POST_CHARS_LIMIT)
|
||||||
|
|
||||||
async function loginTo(user?: Omit<UserLogin, 'account'> & { account?: AccountCredentials }) {
|
async function loginTo(user?: UserLogin) {
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const server = user?.server || route.params.server as string || publicServer.value
|
const server = user?.server || (route.params.server as string)
|
||||||
const masto = await loginMasto({
|
const masto = await loginMasto({
|
||||||
url: `https://${server}`,
|
url: `https://${server}`,
|
||||||
accessToken: user?.token,
|
accessToken: user?.token,
|
||||||
|
@ -82,8 +85,11 @@ async function loginTo(user?: Omit<UserLogin, 'account'> & { account?: AccountCr
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!user?.token) {
|
if (!user?.token) {
|
||||||
publicServer.value = server
|
const instance = await masto.instances.fetch()
|
||||||
publicInstance.value = await masto.instances.fetch()
|
|
||||||
|
currentUserId.value = `[anonymous]@${server}`
|
||||||
|
instances.value[server] = instance
|
||||||
|
users.value.push({ server, guest: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
|
@ -107,7 +113,7 @@ async function loginTo(user?: Omit<UserLogin, 'account'> & { account?: AccountCr
|
||||||
instances.value[server] = instance
|
instances.value[server] = instance
|
||||||
|
|
||||||
if (!users.value.some(u => u.server === user.server && u.token === user.token))
|
if (!users.value.some(u => u.server === user.server && u.token === user.token))
|
||||||
users.value.push(user as UserLogin)
|
users.value.push(user)
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
await signout()
|
await signout()
|
||||||
|
@ -154,7 +160,7 @@ export function getUsersIndexByUserId(userId: string) {
|
||||||
export async function removePushNotificationData(user: UserLogin, fromSWPushManager = true) {
|
export async function removePushNotificationData(user: UserLogin, fromSWPushManager = true) {
|
||||||
// clear push subscription
|
// clear push subscription
|
||||||
user.pushSubscription = undefined
|
user.pushSubscription = undefined
|
||||||
const { acct } = user.account
|
const { acct } = user.account!
|
||||||
// clear request notification permission
|
// clear request notification permission
|
||||||
delete useLocalStorage<PushNotificationRequest>(STORAGE_KEY_NOTIFICATION, {}).value[acct]
|
delete useLocalStorage<PushNotificationRequest>(STORAGE_KEY_NOTIFICATION, {}).value[acct]
|
||||||
// clear push notification policy
|
// clear push notification policy
|
||||||
|
@ -197,7 +203,7 @@ export async function signout() {
|
||||||
|
|
||||||
const masto = useMasto()
|
const masto = useMasto()
|
||||||
|
|
||||||
const _currentUserId = currentUser.value.account.id
|
const _currentUserId = currentUser.value.account!.id
|
||||||
|
|
||||||
const index = users.value.findIndex(u => u.account?.id === _currentUserId)
|
const index = users.value.findIndex(u => u.account?.id === _currentUserId)
|
||||||
|
|
||||||
|
@ -228,7 +234,7 @@ export async function signout() {
|
||||||
const notifications = reactive<Record<string, undefined | [Promise<WsEvents>, number]>>({})
|
const notifications = reactive<Record<string, undefined | [Promise<WsEvents>, number]>>({})
|
||||||
|
|
||||||
export const useNotifications = () => {
|
export const useNotifications = () => {
|
||||||
const id = currentUser.value?.account.id
|
const id = currentUser.value?.account!.id
|
||||||
const masto = useMasto()
|
const masto = useMasto()
|
||||||
|
|
||||||
const clearNotifications = () => {
|
const clearNotifications = () => {
|
||||||
|
@ -286,9 +292,9 @@ export function useUserLocalStorage<T extends object>(key: string, initial: () =
|
||||||
const all = storages.get(key) as Ref<Record<string, T>>
|
const all = storages.get(key) as Ref<Record<string, T>>
|
||||||
|
|
||||||
return computed(() => {
|
return computed(() => {
|
||||||
const id = currentUser.value?.account.id
|
const id = isGuest.value
|
||||||
? currentUser.value.account.acct
|
? '[anonymous]'
|
||||||
: '[anonymous]'
|
: currentUser.value!.account!.acct
|
||||||
all.value[id] = Object.assign(initial(), all.value[id] || {})
|
all.value[id] = Object.assign(initial(), all.value[id] || {})
|
||||||
return all.value[id]
|
return all.value[id]
|
||||||
})
|
})
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
"confirm": "Confirm",
|
"confirm": "Confirm",
|
||||||
"edit": "Edit",
|
"edit": "Edit",
|
||||||
"enter_app": "Enter App",
|
"enter_app": "Enter App",
|
||||||
|
"explore_as_a_guest": "Explore as a guest",
|
||||||
"favourite": "Favourite",
|
"favourite": "Favourite",
|
||||||
"favourited": "Favourited",
|
"favourited": "Favourited",
|
||||||
"more": "More",
|
"more": "More",
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
"confirm": "Confirm",
|
"confirm": "Confirm",
|
||||||
"edit": "Edit",
|
"edit": "Edit",
|
||||||
"enter_app": "Enter App",
|
"enter_app": "Enter App",
|
||||||
|
"explore_as_a_guest": "Explore as a guest",
|
||||||
"favourite": "Favorite",
|
"favourite": "Favorite",
|
||||||
"favourite_count": "{0}",
|
"favourite_count": "{0}",
|
||||||
"favourited": "Favorited",
|
"favourited": "Favorited",
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
"confirm": "确认",
|
"confirm": "确认",
|
||||||
"edit": "编辑",
|
"edit": "编辑",
|
||||||
"enter_app": "进入应用",
|
"enter_app": "进入应用",
|
||||||
|
"explore_as_a_guest": "游客浏览",
|
||||||
"favourite": "喜欢",
|
"favourite": "喜欢",
|
||||||
"favourited": "已喜欢",
|
"favourited": "已喜欢",
|
||||||
"more": "更多",
|
"more": "更多",
|
||||||
|
|
|
@ -12,16 +12,15 @@ export interface AppInfo {
|
||||||
vapid_key: string
|
vapid_key: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UserLogin {
|
export type UserLogin = {
|
||||||
server: string
|
server: string
|
||||||
token?: string
|
token?: string
|
||||||
account: AccountCredentials
|
|
||||||
vapidKey?: string
|
vapidKey?: string
|
||||||
pushSubscription?: PushSubscription
|
pushSubscription?: PushSubscription
|
||||||
}
|
} & ({ account: AccountCredentials; guest: false } | { account?: undefined; guest: true })
|
||||||
|
|
||||||
export interface ElkMasto extends MastoClient {
|
export interface ElkMasto extends MastoClient {
|
||||||
loginTo (user?: Omit<UserLogin, 'account'> & { account?: AccountCredentials }): Promise<MastoClient>
|
loginTo(user?: UserLogin): Promise<MastoClient>
|
||||||
loggedIn: Ref<boolean>
|
loggedIn: Ref<boolean>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ export default defineConfig({
|
||||||
// buttons
|
// buttons
|
||||||
'btn-base': 'cursor-pointer disabled:pointer-events-none disabled:bg-$c-bg-btn-disabled disabled:text-$c-text-btn-disabled',
|
'btn-base': 'cursor-pointer disabled:pointer-events-none disabled:bg-$c-bg-btn-disabled disabled:text-$c-text-btn-disabled',
|
||||||
'btn-solid': 'btn-base px-4 py-2 rounded text-$c-text-btn bg-$c-primary hover:bg-$c-primary-active',
|
'btn-solid': 'btn-base px-4 py-2 rounded text-$c-text-btn bg-$c-primary hover:bg-$c-primary-active',
|
||||||
'btn-outline': 'btn-base px-4 py-2 rounded text-$c-primary border border-$c-primary hover:bg-$c-primary hover:text-inverted',
|
'btn-outline': 'btn-base px-4 py-2 rounded text-$c-primary border border-$c-primary hover:bg-$c-primary hover:text-inverted disabled:border-$c-bg-btn-disabled',
|
||||||
'btn-text': 'btn-base px-4 py-2 text-$c-primary hover:text-$c-primary-active',
|
'btn-text': 'btn-base px-4 py-2 text-$c-primary hover:text-$c-primary-active',
|
||||||
'btn-action-icon': 'btn-base hover:bg-active rounded-full h9 w9 flex items-center justify-center disabled:bg-transparent disabled:text-$c-text-secondary',
|
'btn-action-icon': 'btn-base hover:bg-active rounded-full h9 w9 flex items-center justify-center disabled:bg-transparent disabled:text-$c-text-secondary',
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue