Skip to content

Commit

Permalink
feat: finish list CRUD (#1532)
Browse files Browse the repository at this point in the history
Co-authored-by: userquin <userquin@gmail.com>
closes #372
  • Loading branch information
boehs committed Feb 2, 2023
1 parent 809d4a6 commit e58d09b
Show file tree
Hide file tree
Showing 10 changed files with 383 additions and 150 deletions.
94 changes: 48 additions & 46 deletions components/account/AccountHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -91,56 +91,58 @@ const isNotifiedOnPost = $computed(() => !!relationship?.notifying)
</component>
<div p4 mt--18 flex flex-col gap-4>
<div relative>
<div flex="~ col gap-2 1">
<button :class="{ 'rounded-full': !isSelf, 'squircle': isSelf }" w-30 h-30 p1 bg-base border-bg-base z-2 @click="previewAvatar">
<div flex justify-between>
<button shrink-0 :class="{ 'rounded-full': !isSelf, 'squircle': isSelf }" w-30 h-30 p1 bg-base border-bg-base z-2 @click="previewAvatar">
<AccountAvatar :square="isSelf" :account="account" hover:opacity-90 transition-opacity />
</button>
<div flex="~ col gap1">
<div flex justify-between>
<AccountDisplayName :account="account" font-bold sm:text-2xl text-xl />
<AccountBotIndicator v-if="account.bot" show-label />
</div>
<AccountHandle :account="account" />
<div inset-ie-0 flex="~ wrap row-reverse" gap-2 items-center pt18 justify-start>
<!-- Edit profile -->
<NuxtLink
v-if="isSelf"
to="/settings/profile/appearance"
gap-1 items-center border="1" rounded-full flex="~ gap2 center" font-500 min-w-30 h-fit px3 py1
hover="border-primary text-primary bg-active"
>
{{ $t('settings.profile.appearance.title') }}
</NuxtLink>
<AccountFollowButton :account="account" :command="command" />
<span inset-ie-0 flex gap-2 items-center>
<AccountMoreButton :account="account" :command="command" />
<CommonTooltip v-if="!isSelf && relationship?.following" :content="getNotificationIconTitle()">
<button
:aria-pressed="isNotifiedOnPost"
:aria-label="t('account.notifications_on_post_enable', { username: `@${account.username}` })"
rounded-full text-sm p2 border-1 transition-colors
:class="isNotifiedOnPost ? 'text-primary border-primary hover:bg-red/20 hover:text-red hover:border-red' : 'border-base hover:text-primary'"
@click="toggleNotifications"
>
<span v-if="isNotifiedOnPost" i-ri:notification-4-fill block text-current />
<span v-else i-ri-notification-4-line block text-current />
</button>
</CommonTooltip>
<CommonTooltip :content="$t('list.modify_account')">
<VDropdown v-if="!isSelf && relationship?.following">
<button
:aria-label="$t('list.modify_account')"
rounded-full text-sm p2 border-1 transition-colors
border-base hover:text-primary
>
<span i-ri:play-list-add-fill block text-current />
</button>
<template #popper>
<ListLists :user-id="account.id" />
</template>
</VDropdown>
</CommonTooltip>
</span>
</div>
</div>
<div absolute top-18 inset-ie-0 flex gap-2 items-center>
<AccountMoreButton :account="account" :command="command" />
<CommonTooltip v-if="!isSelf && relationship?.following" :content="getNotificationIconTitle()">
<button
:aria-pressed="isNotifiedOnPost"
:aria-label="t('account.notifications_on_post_enable', { username: `@${account.username}` })"
rounded-full text-sm p2 border-1 transition-colors
:class="isNotifiedOnPost ? 'text-primary border-primary hover:bg-red/20 hover:text-red hover:border-red' : 'border-base hover:text-primary'"
@click="toggleNotifications"
>
<span v-if="isNotifiedOnPost" i-ri:notification-4-fill block text-current />
<span v-else i-ri-notification-4-line block text-current />
</button>
</CommonTooltip>
<CommonTooltip :content="$t('list.modify_account')">
<VDropdown v-if="!isSelf && relationship?.following">
<button
:aria-label="$t('list.modify_account')"
rounded-full text-sm p2 border-1 transition-colors
border-base hover:text-primary
>
<span i-ri:play-list-add-fill block text-current />
</button>
<template #popper>
<ListLists :user-id="account.id" />
</template>
</VDropdown>
</CommonTooltip>
<AccountFollowButton :account="account" :command="command" />
<!-- Edit profile -->
<NuxtLink
v-if="isSelf"
to="/settings/profile/appearance"
gap-1 items-center border="1" rounded-full flex="~ gap2 center" font-500 min-w-30 h-fit px3 py1
hover="border-primary text-primary bg-active"
>
{{ $t('settings.profile.appearance.title') }}
</NuxtLink>
<div flex="~ col gap1" pt2>
<div flex justify-between>
<AccountDisplayName :account="account" font-bold sm:text-2xl text-xl />
<AccountBotIndicator v-if="account.bot" show-label />
</div>
<AccountHandle :account="account" />
</div>
</div>
<div v-if="account.note" max-h-100 overflow-y-auto>
Expand Down
17 changes: 17 additions & 0 deletions components/common/CommonPaginator.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,23 @@ nuxtApp.hook('elk-logo:click', () => {
update()
nuxtApp.$scrollToTop()
})
function createEntry(item: any) {
items.value = [...items.value, preprocess?.([item]) ?? item]
}
function updateEntry(item: any) {
const id = item[keyProp]
const index = items.value.findIndex(i => (i as any)[keyProp] === id)
if (index > -1)
items.value = [...items.value.slice(0, index), preprocess?.([item]) ?? item, ...items.value.slice(index + 1)]
}
function removeEntry(entryId: any) {
items.value = items.value.filter(i => (i as any)[keyProp] !== entryId)
}
defineExpose({ createEntry, removeEntry, updateEntry })
</script>

<template>
Expand Down
169 changes: 169 additions & 0 deletions components/list/ListEntry.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
<script setup lang="ts">
import type { mastodon } from 'masto'
const emit = defineEmits<{
(e: 'listUpdated', list: mastodon.v1.List): void
(e: 'listRemoved', id: string): void
}>()
const { list } = $defineProps<{
list: mastodon.v1.List
}>()
const { modelValue } = defineModel<{
modelValue: string
}>()
modelValue.value = list.title
const { t } = useI18n()
const client = useMastoClient()
let isEditing = $ref<boolean>(false)
let busy = $ref<boolean>(false)
let deleteBusy = $ref<boolean>(false)
const enableSaveButton = computed(() => list.title !== modelValue.value)
const edit = ref()
const input = ref()
const prepareEdit = () => {
isEditing = true
nextTick(() => {
input.value.focus()
})
}
const cancelEdit = (updateTitle = true) => {
isEditing = false
if (updateTitle)
modelValue.value = list.title
nextTick(() => {
edit.value.focus()
})
}
async function finishEditing() {
if (busy || !isEditing || !enableSaveButton.value)
return
busy = true
await nextTick()
try {
const updateList = await client.v1.lists.update(list.id, {
title: modelValue.value,
})
cancelEdit(false)
emit('listUpdated', updateList)
}
finally {
busy = false
}
}
async function removeList() {
if (deleteBusy)
return
deleteBusy = true
await nextTick()
const confirmDelete = await openConfirmDialog({
title: t('confirm.delete_list.title'),
confirm: t('confirm.delete_list.confirm'),
cancel: t('confirm.delete_list.cancel'),
})
if (confirmDelete === 'confirm') {
await nextTick()
try {
await client.v1.lists.remove(list.id)
emit('listRemoved', list.id)
}
finally {
deleteBusy = false
}
}
else {
deleteBusy = false
}
}
onBeforeUnmount(() => cancelEdit(false))
</script>

<template>
<form hover:bg-active flex justify-between items-center @submit.prevent="finishEditing">
<div
v-if="isEditing"
bg-base border="~ base" h10 m2 ps-1 pe-4 rounded-3 w-full flex="~ row"
items-center relative focus-within:box-shadow-outline gap-3
>
<CommonTooltip v-if="isEditing" :content="$t('list.cancel_edit')">
<button
type="button"
rounded-full text-sm p2 transition-colors
hover:text-primary
@click="cancelEdit(true)"
>
<span block text-current i-ri:close-fill />
</button>
</CommonTooltip>
<input
ref="input"
v-model="modelValue"
rounded-3
w-full
bg-transparent
outline="focus:none"
pe-4
pb="1px"
flex-1
placeholder-text-secondary
@keydown.esc="cancelEdit(true)"
>
</div>
<NuxtLink v-else :to="`list/${list.id}`" block grow p4>
{{ list.title }}
</NuxtLink>
<div mr4 flex gap2>
<CommonTooltip v-if="isEditing" :content="$t('list.save')">
<button
type="submit"
text-sm p2 border-1 transition-colors
border-dark hover:text-primary
btn-action-icon
:disabled="deleteBusy || !enableSaveButton || busy"
>
<template v-if="isEditing">
<span v-if="busy" aria-hidden="true" block animate animate-spin preserve-3d class="rtl-flip">
<span block i-ri:loader-2-fill aria-hidden="true" />
</span>
<span v-else block text-current i-ri:save-2-fill class="rtl-flip" />
</template>
</button>
</CommonTooltip>
<CommonTooltip v-else :content="$t('list.edit')">
<button
ref="edit"
type="button"
text-sm p2 border-1 transition-colors
border-dark hover:text-primary
btn-action-icon
@click.prevent="prepareEdit"
>
<span block text-current i-ri:edit-2-line class="rtl-flip" />
</button>
</CommonTooltip>
<CommonTooltip :content="$t('list.delete')">
<button
type="button"
text-sm p2 border-1 transition-colors
border-dark hover:text-primary
btn-action-icon
:disabled="isEditing"
@click.prevent="removeList"
>
<span v-if="deleteBusy" aria-hidden="true" block animate animate-spin preserve-3d class="rtl-flip">
<span block i-ri:loader-2-fill aria-hidden="true" />
</span>
<span v-else block text-current i-ri:delete-bin-2-line class="rtl-flip" />
</button>
</CommonTooltip>
</div>
</form>
</template>
13 changes: 12 additions & 1 deletion locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@
"cancel": "No",
"confirm": "Yes"
},
"delete_list": {
"cancel": "Cancel",
"confirm": "Delete",
"title": "Are you sure you want to delete this list?"
},
"delete_posts": {
"cancel": "Cancel",
"confirm": "Delete",
Expand Down Expand Up @@ -177,8 +182,14 @@
},
"list": {
"add_account": "Add account to list",
"cancel_edit": "Cancel editing",
"create": "Create",
"delete": "Delete this list",
"edit": "Edit this list",
"list_title_placeholder": "List title",
"modify_account": "Modify lists with account",
"remove_account": "Remove account from list"
"remove_account": "Remove account from list",
"save": "Save changes"
},
"menu": {
"block_account": "Block {0}",
Expand Down
55 changes: 0 additions & 55 deletions pages/[[server]]/list.vue

This file was deleted.

Loading

0 comments on commit e58d09b

Please sign in to comment.