feat(favorites) drag-and-drop favorites section (#1360)

This commit is contained in:
gitmotion 2024-10-25 13:42:12 -07:00 committed by GitHub
parent ea8c4ed077
commit 0b1b98f93e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 72 additions and 4 deletions

View file

@ -1,6 +1,8 @@
<script setup lang="ts">
import { IconHeart } from '@tabler/icons-vue';
import { IconDragDrop, IconHeart } from '@tabler/icons-vue';
import { useHead } from '@vueuse/head';
import { computed } from 'vue';
import Draggable from 'vuedraggable';
import ColoredCard from '../components/ColoredCard.vue';
import ToolCard from '../components/ToolCard.vue';
import { useToolStore } from '@/tools/tools.store';
@ -10,6 +12,13 @@ const toolStore = useToolStore();
useHead({ title: 'IT Tools - Handy online tools for developers' });
const { t } = useI18n();
const favoriteTools = computed(() => toolStore.favoriteTools);
// Update favorite tools order when drag is finished
function onUpdateFavoriteTools() {
toolStore.updateFavoriteTools(favoriteTools.value); // Update the store with the new order
}
</script>
<template>
@ -66,10 +75,21 @@ const { t } = useI18n();
<div v-if="toolStore.favoriteTools.length > 0">
<h3 class="mb-5px mt-25px font-500 text-neutral-400">
{{ $t('home.categories.favoriteTools') }}
<c-tooltip :tooltip="$t('home.categories.favoritesDndToolTip')">
<n-icon :component="IconDragDrop" size="18" />
</c-tooltip>
</h3>
<div class="grid grid-cols-1 gap-12px lg:grid-cols-3 md:grid-cols-3 sm:grid-cols-2 xl:grid-cols-4">
<ToolCard v-for="tool in toolStore.favoriteTools" :key="tool.name" :tool="tool" />
</div>
<Draggable
:list="favoriteTools"
class="grid grid-cols-1 gap-12px lg:grid-cols-3 md:grid-cols-3 sm:grid-cols-2 xl:grid-cols-4"
ghost-class="ghost-favorites-draggable"
item-key="name"
@end="onUpdateFavoriteTools"
>
<template #item="{ element: tool }">
<ToolCard :tool="tool" />
</template>
</Draggable>
</div>
</transition>
@ -107,4 +127,24 @@ const { t } = useI18n();
opacity: 0;
margin-bottom: 0;
}
.ghost-favorites-draggable {
opacity: 0.4;
background-color: #ccc;
border: 2px dashed #666;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
transform: scale(1.1);
animation: ghost-favorites-draggable-animation 0.2s ease-out;
}
@keyframes ghost-favorites-draggable-animation {
0% {
opacity: 0;
transform: scale(0.9);
}
100% {
opacity: 0.4;
transform: scale(1.0);
}
}
</style>

View file

@ -59,5 +59,9 @@ export const useToolStore = defineStore('tools', () => {
return favoriteToolsName.value.includes(get(tool).name)
|| favoriteToolsName.value.includes(get(tool).path);
},
updateFavoriteTools(newOrder: ToolWithCategory[]) {
favoriteToolsName.value = newOrder.map(tool => tool.path);
},
};
});