diff --git a/components/common/CommonTooltip.vue b/components/common/CommonTooltip.vue new file mode 100644 index 00000000..f80e659c --- /dev/null +++ b/components/common/CommonTooltip.vue @@ -0,0 +1,16 @@ +<script setup lang="ts"> + +</script> + +<template> + <VTooltip + v-bind="$attrs" + > + <slot /> + <template #popper> + <div text-3> + <slot name="popper" /> + </div> + </template> + </VTooltip> +</template> diff --git a/components/status/StatusActionButton.vue b/components/status/StatusActionButton.vue new file mode 100644 index 00000000..c0d023d7 --- /dev/null +++ b/components/status/StatusActionButton.vue @@ -0,0 +1,37 @@ +<script setup lang="ts"> +defineProps<{ + text?: string | number + color: string + icon: string + activeIcon: string + tooltip: string + hover: string + groupHover: string + active?: boolean + disabled?: boolean +}>() + +defineOptions({ + inheritAttrs: false, +}) +</script> + +<template> + <CommonTooltip placement="bottom"> + <button + flex gap-1 items-center rounded :hover="`op100 ${hover}`" group + :class="active ? [color, 'op100'] : 'op50'" + v-bind="$attrs" + > + <div rounded-full p2 :group-hover="groupHover"> + <div :class="[active && activeIcon ? activeIcon : icon, { 'pointer-events-none': disabled }]" /> + </div> + + <span v-if="text">{{ text }}</span> + </button> + + <template #popper> + {{ tooltip }} + </template> + </CommonTooltip> +</template> diff --git a/components/status/StatusActions.vue b/components/status/StatusActions.vue index 773256ea..411c073a 100644 --- a/components/status/StatusActions.vue +++ b/components/status/StatusActions.vue @@ -37,45 +37,53 @@ const toggleBookmark = () => toggleStatusAction( <template> <div flex justify-between gap-8> - <RouterLink flex gap-1 items-center rounded op50 hover="op100 text-blue" group :to="getStatusPath(status)"> - <div rounded-full p2 group-hover="bg-blue/10"> - <div i-ri:chat-3-line /> - </div> - <span v-if="status.repliesCount">{{ status.repliesCount }}</span> + <RouterLink :to="getStatusPath(status)"> + <StatusActionButton + :text="status.repliesCount" + color="text-blue" hover="text-blue" group-hover="bg-blue/10" + icon="i-ri:chat-3-line" + tooltip="Replay" + /> </RouterLink> - <button - flex gap-1 items-center rounded op50 hover="op100 text-green" group - :class="(status.reblogged ? 'text-green op100' : 'op50') + (isLoading.reblogged ? ' pointer-events-none' : '')" + + <StatusActionButton + :text="status.reblogsCount" + color="text-green" hover="text-green" group-hover="bg-green/10" + icon="i-ri:repeat-line" + active-icon="i-ri:repeat-fill" + :active="status.reblogged" + :disabled="isLoading.reblogged" + tooltip="Boost" @click="toggleReblog()" - > - <div rounded-full p2 group-hover="bg-green/10"> - <div :class="status.reblogged ? 'i-ri:repeat-fill' : 'i-ri:repeat-line'" /> - </div> - <span v-if="status.reblogsCount">{{ status.reblogsCount }}</span> - </button> - <button - flex gap-1 items-center rounded hover="op100 text-rose" group - :class="status.favourited ? 'text-rose op100' : 'op50'" + /> + + <StatusActionButton + :text="status.favouritesCount" + color="text-rose" hover="text-rose" group-hover="bg-rose/10" + icon="i-ri:heart-3-line" + active-icon="i-ri:heart-3-fill" + :active="status.favourited" + :disabled="isLoading.favourited" + tooltip="Favourite" @click="toggleFavourite()" - > - <div rounded-full p2 group-hover="bg-rose/10"> - <div :class="(status.favourited ? 'i-ri:heart-3-fill' : 'i-ri:heart-3-line') + (isLoading.favourited ? ' pointer-events-none' : '')" /> - </div> - <span v-if="status.favouritesCount">{{ status.favouritesCount }}</span> - </button> - <button - flex gap-1 items-center rounded hover="op100 text-yellow" group - :class="status.bookmarked ? 'text-yellow op100' : 'op50'" + /> + + <StatusActionButton + color="text-yellow" hover="text-yellow" group-hover="bg-yellow/10" + icon="i-ri:bookmark-line" + active-icon="i-ri:bookmark-fill" + :active="status.bookmarked" + :disabled="isLoading.bookmarked" + tooltip="Bookmark" @click="toggleBookmark()" - > - <div rounded-full p2 group-hover="bg-rose/10"> - <div :class="(status.bookmarked ? 'i-ri:bookmark-fill' : 'i-ri:bookmark-line') + (isLoading.bookmarked ? ' pointer-events-none' : '')" /> - </div> - </button> - <!-- <button flex gap-1 items-center rounded op50 hover="op100 text-purple" group> - <div rounded-full p2 group-hover="bg-purple/10"> - <div i-ri:share-circle-line /> - </div> - </button> --> + /> + + <!-- <VDropdown> + <button flex gap-1 items-center rounded op50 hover="op100 text-purple" group> + <div rounded-full p2 group-hover="bg-purple/10"> + <div i-ri:share-circle-line /> + </div> + </button> + </VDropdown> --> </div> </template> diff --git a/package.json b/package.json index 8ad5c323..1f9111a3 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "blurhash": "^2.0.4", "eslint": "^8.27.0", "esno": "^0.16.3", + "floating-vue": "2.0.0-beta.20", "form-data": "^4.0.0", "fs-extra": "^10.1.0", "js-yaml": "^4.1.0", diff --git a/plugins/floating-vue.ts b/plugins/floating-vue.ts new file mode 100644 index 00000000..0b012419 --- /dev/null +++ b/plugins/floating-vue.ts @@ -0,0 +1,7 @@ +import FloatingVue from 'floating-vue' +import { defineNuxtPlugin } from '#app' +import 'floating-vue/dist/style.css' + +export default defineNuxtPlugin((nuxtApp) => { + nuxtApp.vueApp.use(FloatingVue) +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e22b2be6..c094ecf9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,7 @@ specifiers: blurhash: ^2.0.4 eslint: ^8.27.0 esno: ^0.16.3 + floating-vue: 2.0.0-beta.20 form-data: ^4.0.0 fs-extra: ^10.1.0 js-yaml: ^4.1.0 @@ -50,6 +51,7 @@ devDependencies: blurhash: 2.0.4 eslint: 8.27.0 esno: 0.16.3 + floating-vue: 2.0.0-beta.20 form-data: 4.0.0 fs-extra: 10.1.0 js-yaml: 4.1.0 @@ -660,6 +662,16 @@ packages: - supports-color dev: true + /@floating-ui/core/0.3.1: + resolution: {integrity: sha512-ensKY7Ub59u16qsVIFEo2hwTCqZ/r9oZZFh51ivcLGHfUwTn8l1Xzng8RJUe91H/UP8PeqeBronAGx0qmzwk2g==} + dev: true + + /@floating-ui/dom/0.1.10: + resolution: {integrity: sha512-4kAVoogvQm2N0XE0G6APQJuCNuErjOfPW8Ux7DFxh8+AfugWflwVJ5LDlHOwrwut7z/30NUvdtHzQ3zSip4EzQ==} + dependencies: + '@floating-ui/core': 0.3.1 + dev: true + /@humanwhocodes/config-array/0.11.7: resolution: {integrity: sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==} engines: {node: '>=10.10.0'} @@ -3952,6 +3964,15 @@ packages: resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} dev: true + /floating-vue/2.0.0-beta.20: + resolution: {integrity: sha512-N68otcpp6WwcYC7zP8GeJqNZVdfvS7tEY88lwmuAHeqRgnfWx1Un8enzLxROyVnBDZ3TwUoUdj5IFg+bUT7JeA==} + peerDependencies: + vue: ^3.2.0 + dependencies: + '@floating-ui/dom': 0.1.10 + vue-resize: 2.0.0-alpha.1 + dev: true + /follow-redirects/1.15.2: resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} engines: {node: '>=4.0'} @@ -7587,6 +7608,12 @@ packages: - supports-color dev: true + /vue-resize/2.0.0-alpha.1: + resolution: {integrity: sha512-7+iqOueLU7uc9NrMfrzbG8hwMqchfVfSzpVlCMeJQe4pyibqyoifDNbKTZvwxZKDvGkB+PdFeKvnGZMoEb8esg==} + peerDependencies: + vue: ^3.0.0 + dev: true + /vue-router/4.1.6_vue@3.2.45: resolution: {integrity: sha512-DYWYwsG6xNPmLq/FmZn8Ip+qrhFEzA14EI12MsMgVxvHFDYvlr4NXpVF5hrRH1wVcDP8fGi5F4rxuJSl8/r+EQ==} peerDependencies: