This commit is contained in:
三咲智子 2023-01-03 08:11:10 +08:00
parent 3468c13e75
commit 1816530f84
No known key found for this signature in database
GPG key ID: 69992F2250DFD93E
10 changed files with 70 additions and 44 deletions

View file

@ -6,7 +6,7 @@ const all = useUsers()
const router = useRouter()
const masto = useMasto()
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))
else
masto.loginTo(user)
@ -21,7 +21,7 @@ const switchUser = (user: UserLogin) => {
flex rounded
cursor-pointer
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"
@click="switchUser(user)"
>

View file

@ -1,7 +1,8 @@
<script setup lang="ts">
import Fuse from 'fuse.js'
import { $fetch } from 'ofetch'
import { DEFAULT_SERVER } from '~/constants'
const masto = useMasto()
const input = $ref<HTMLInputElement>()
let server = $ref<string>('')
@ -26,7 +27,7 @@ async function oauth() {
server = server.split('/')[0]
try {
location.href = await $fetch<string>(`/api/${server || DEFAULT_SERVER}/login`, {
location.href = await $fetch<string>(`/api/${server}/login`, {
method: 'POST',
body: {
origin: location.origin,
@ -46,6 +47,10 @@ async function oauth() {
}
}
function explore() {
masto.loginTo({ server, guest: true })
}
async function handleInput() {
if (server.startsWith('https://'))
server = server.replace('https://', '')
@ -180,9 +185,19 @@ onClickOutside($$(input), () => {
</i18n-t>
</span>
</div>
<button flex="~ row" gap-x-2 items-center btn-solid mt2 :disabled="!server || busy">
<div flex="~ gap2" mt2 items-center>
<button
type="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>
</template>

View file

@ -344,9 +344,9 @@ export const provideGlobalCommands = () => {
parent: 'account-switch',
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',
onActivate() {
@ -357,8 +357,7 @@ export const provideGlobalCommands = () => {
scope: 'Account',
visible: () => currentUser.value,
name: () => t('user.sign_out_account', [getFullHandle(currentUser.value!.account)]),
name: () => currentUser.value ? t('user.sign_out_account', [getFullHandle(currentUser.value)]) : '',
icon: 'i-ri:logout-box-line',
onActivate() {

View file

@ -1,7 +1,7 @@
import type { Ref } from 'vue'
import type { Account, Relationship, Status } from 'masto'
import { withoutProtocol } from 'ufo'
import type { ElkMasto } from '~/types'
import type { ElkMasto, UserLogin } from '~/types'
export const useMasto = () => useNuxtApp().$masto as ElkMasto
@ -33,7 +33,11 @@ export function getServerName(account: Account) {
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}`
if (!currentUser.value || account.acct.includes('@'))
return handle

View file

@ -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 : '')
export const currentUser = computed<UserLogin | undefined>(() => {
if (currentUserId.value) {
if (!currentUserId.value)
// Fallback to the first account
return users.value[0]
const user = users.value.find(user => user.account?.id === currentUserId.value)
if (user)
return user
}
// Fallback to the first account
return users.value[0]
})
const publicInstance = ref<Instance | null>(null)
export const currentInstance = computed<null | Instance>(() => currentUser.value ? instances.value[currentUser.value.server] ?? null : publicInstance.value)
export const isGuest = computed(
() => currentUserId.value.startsWith('[anonymous]@') || !currentUser.value?.account?.acct,
)
export const publicServer = ref(DEFAULT_SERVER)
export const currentServer = computed<string>(() => currentUser.value?.server || publicServer.value)
export const currentServer = computed<string>(() => currentUser.value?.server || DEFAULT_SERVER)
export const currentInstance = computed<null | Instance>(() => {
return instances.value[currentServer.value] ?? null
})
export const currentUserHandle = computed(() => currentUser.value?.account.id
? `${currentUser.value.account.acct}@${currentInstance.value?.uri || currentServer.value}`
: '[anonymous]',
export const currentUserHandle = computed(() =>
isGuest.value ? '[anonymous]' : currentUser.value!.account!.acct
,
)
export const useUsers = () => users
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 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({
url: `https://${server}`,
accessToken: user?.token,
@ -82,8 +85,11 @@ async function loginTo(user?: Omit<UserLogin, 'account'> & { account?: AccountCr
})
if (!user?.token) {
publicServer.value = server
publicInstance.value = await masto.instances.fetch()
const instance = await masto.instances.fetch()
currentUserId.value = `[anonymous]@${server}`
instances.value[server] = instance
users.value.push({ server, guest: true })
}
else {
@ -107,7 +113,7 @@ async function loginTo(user?: Omit<UserLogin, 'account'> & { account?: AccountCr
instances.value[server] = instance
if (!users.value.some(u => u.server === user.server && u.token === user.token))
users.value.push(user as UserLogin)
users.value.push(user)
}
catch {
await signout()
@ -154,7 +160,7 @@ export function getUsersIndexByUserId(userId: string) {
export async function removePushNotificationData(user: UserLogin, fromSWPushManager = true) {
// clear push subscription
user.pushSubscription = undefined
const { acct } = user.account
const { acct } = user.account!
// clear request notification permission
delete useLocalStorage<PushNotificationRequest>(STORAGE_KEY_NOTIFICATION, {}).value[acct]
// clear push notification policy
@ -197,7 +203,7 @@ export async function signout() {
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)
@ -228,7 +234,7 @@ export async function signout() {
const notifications = reactive<Record<string, undefined | [Promise<WsEvents>, number]>>({})
export const useNotifications = () => {
const id = currentUser.value?.account.id
const id = currentUser.value?.account!.id
const masto = useMasto()
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>>
return computed(() => {
const id = currentUser.value?.account.id
? currentUser.value.account.acct
: '[anonymous]'
const id = isGuest.value
? '[anonymous]'
: currentUser.value!.account!.acct
all.value[id] = Object.assign(initial(), all.value[id] || {})
return all.value[id]
})

View file

@ -49,6 +49,7 @@
"confirm": "Confirm",
"edit": "Edit",
"enter_app": "Enter App",
"explore_as_a_guest": "Explore as a guest",
"favourite": "Favourite",
"favourited": "Favourited",
"more": "More",

View file

@ -50,6 +50,7 @@
"confirm": "Confirm",
"edit": "Edit",
"enter_app": "Enter App",
"explore_as_a_guest": "Explore as a guest",
"favourite": "Favorite",
"favourite_count": "{0}",
"favourited": "Favorited",

View file

@ -49,6 +49,7 @@
"confirm": "确认",
"edit": "编辑",
"enter_app": "进入应用",
"explore_as_a_guest": "游客浏览",
"favourite": "喜欢",
"favourited": "已喜欢",
"more": "更多",

View file

@ -12,16 +12,15 @@ export interface AppInfo {
vapid_key: string
}
export interface UserLogin {
export type UserLogin = {
server: string
token?: string
account: AccountCredentials
vapidKey?: string
pushSubscription?: PushSubscription
}
} & ({ account: AccountCredentials; guest: false } | { account?: undefined; guest: true })
export interface ElkMasto extends MastoClient {
loginTo (user?: Omit<UserLogin, 'account'> & { account?: AccountCredentials }): Promise<MastoClient>
loginTo(user?: UserLogin): Promise<MastoClient>
loggedIn: Ref<boolean>
}

View file

@ -35,7 +35,7 @@ export default defineConfig({
// buttons
'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-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-action-icon': 'btn-base hover:bg-active rounded-full h9 w9 flex items-center justify-center disabled:bg-transparent disabled:text-$c-text-secondary',