feat: basic mutli-accounts support

This commit is contained in:
Anthony Fu 2022-11-23 11:48:01 +08:00
parent 24c573ccf0
commit 241b28241c
15 changed files with 170 additions and 34 deletions

View file

@ -1,10 +1,13 @@
<script setup lang="ts">
import type { Account } from 'masto'
const { link = true } = defineProps<{
const { account, link = true, fullServer = false } = defineProps<{
account: Account
link?: boolean
fullServer?: boolean
}>()
const id = computed(() => fullServer && !account.acct.includes('@') ? `@${account.acct}@${account.url.match(UserLinkRE)?.[1]}` : `@${account.acct}`)
</script>
<template>
@ -17,7 +20,7 @@ const { link = true } = defineProps<{
<NuxtLink flex flex-col :to="link ? `/@${account.acct}` : null">
<CommonRichContent font-bold :content="getDisplayName(account)" :emojis="account.emojis" />
<p op35 text-sm>
@{{ account.acct }}
{{ id }}
</p>
<slot name="bottom" />
</NuxtLink>

View file

@ -1,15 +0,0 @@
<script setup lang="ts">
const account = $computed(() => currentUser.value?.account)
</script>
<template>
<div flex flex-col gap-4 p4>
<!-- TODO: multiple account switcher -->
<template v-if="account">
<AccountInfo :account="account" />
<PublishWidget draft-key="home" />
</template>
<!-- TODO: dialog for select server -->
<a v-else href="/api/mas.to/login" px2 py1 bg-teal6 text-white m2 rounded>Login</a>
</div>
</template>

View file

@ -4,25 +4,21 @@ import { DEFAULT_SERVER } from '~/constants'
const server = ref<string>()
async function oauth() {
const a = document.createElement('a')
a.href = `/api/${server.value || DEFAULT_SERVER}/login`
a.target = '_blank'
a.click()
location.href = `/api/${server.value || DEFAULT_SERVER}/login`
}
</script>
<template>
<div h-full text-center justify-center flex="~ col items-center gap2">
<div text-4xl mb-10>
Nuxtodon
<div text-3xl mb2>
Sign in
</div>
<div>Mastodon Server</div>
<div>Mastodon Server Name</div>
<div flex bg-gray:10 px2 py1 mxa rounded border="~ border" w-80 text-xl items-center>
<span op35 mr1 text-sm>https://</span>
<input v-model="server" :placeholder="DEFAULT_SERVER" outline-none bg-transparent>
</div>
<button btn-solid mxa @click="oauth()">
<button btn-solid mxa mt2 @click="oauth()">
Sign in
</button>
</div>

View file

@ -0,0 +1,9 @@
<script setup lang="ts">
const accounts = useAccounts()
</script>
<template>
<div flex flex-col gap-4 p4>
<AccountInfo :account="currentUser?.account" :link="false" @click="openAccountSwitcher" />
</div>
</template>

View file

@ -0,0 +1,35 @@
<script setup lang="ts">
import { isAccountSwitcherOpen, isSigninDialogOpen } from '~/composables/dialog'
const accounts = useAccounts()
</script>
<template>
<ModalDrawer
v-model="isAccountSwitcherOpen"
>
<div max-w-60rem mxa p4>
<h1 text-2xl>
Switch Account
</h1>
<template v-for="acc of accounts" :key="acc.id">
<AccountInfo
:account="acc.account"
:link="false"
:full-server="true"
py4 border="b base"
@click="loginTo(acc)"
/>
</template>
<div py2 mx--2>
<button btn-text flex="~ gap-1" items-center @click="openSigninDialog">
<div i-ri:user-add-line />
Add another account
</button>
</div>
</div>
</ModalDrawer>
<ModalDialog v-model="isSigninDialogOpen">
<AccountSignIn m6 />
</ModalDialog>
</template>

View file

@ -0,0 +1,29 @@
<script setup lang='ts'>
const { modelValue } = defineModel<{
modelValue: boolean
}>()
</script>
<template>
<div
class="fixed top-0 bottom-0 left-0 right-0 z-60"
:class="modelValue ? '' : 'pointer-events-none'"
>
<div
class="
bg-base bottom-0 left-0 right-0 top-0 absolute transition-opacity duration-500 ease-out
"
:class="modelValue ? 'opacity-85' : 'opacity-0'"
@click="modelValue = false"
/>
<div
class="
bg-base absolute transition-all duration-200 ease-out shadow rounded-md transform
border border-base left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2
"
:class="modelValue ? 'opacity-100' : 'opacity-0'"
>
<slot />
</div>
</div>
</template>

View file

@ -0,0 +1,61 @@
<script setup lang='ts'>
const {
direction = 'bottom',
} = defineProps<{
direction?: string
}>()
const { modelValue } = defineModel<{
modelValue: boolean
}>()
const positionClass = computed(() => {
switch (direction) {
case 'bottom':
return 'bottom-0 left-0 right-0 border-t'
case 'top':
return 'top-0 left-0 right-0 border-b'
case 'left':
return 'bottom-0 left-0 top-0 border-r'
case 'right':
return 'bottom-0 top-0 right-0 border-l'
default:
return ''
}
})
const transform = computed(() => {
switch (direction) {
case 'bottom':
return 'translateY(100%)'
case 'top':
return 'translateY(-100%)'
case 'left':
return 'translateX(-100%)'
case 'right':
return 'translateX(100%)'
default:
return ''
}
})
</script>
<template>
<div
fixed top-0 bottom-0 left-0 right-0 z-40
:class="modelValue ? '' : 'pointer-events-none'"
>
<div
bg-base bottom-0 left-0 right-0 top-0 absolute transition-opacity duration-500 ease-out
:class="modelValue ? 'opacity-85' : 'opacity-0'"
@click="modelValue = false"
/>
<div
bg-base border border-base absolute transition-all duration-200 ease-out
:class="positionClass"
:style="modelValue ? {} : { transform }"
>
<slot />
</div>
</div>
</template>