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

@ -10,6 +10,7 @@ home:
newestTools: Neueste Tools
favoriteTools: Deine Lieblingstools
allTools: Alle Tools
favoritesDndToolTip: 'Ziehen und Ablegen, um Favoriten neu zu ordnen'
subtitle: Praktische Tools für Entwickler
toggleMenu: Menü umschalten
home: Startseite

View file

@ -3,6 +3,7 @@ home:
newestTools: Newest tools
favoriteTools: 'Your favorite tools'
allTools: 'All the tools'
favoritesDndToolTip: 'Drag and drop to reorder favorites'
subtitle: 'Handy tools for developers'
toggleMenu: 'Toggle menu'
home: Home

View file

@ -3,6 +3,7 @@ home:
newestTools: Nuevas herramientas
favoriteTools: 'Tus herramientas favoritas'
allTools: 'Todas las herramientas'
favoritesDndToolTip: 'Arrastra y suelta para reordenar favoritos'
subtitle: 'Herramientas practicas para desarrolladores'
toggleMenu: 'Toggle menu'
home: Home

View file

@ -3,6 +3,7 @@ home:
newestTools: 'Les nouveaux outils'
favoriteTools: 'Vos outils favoris'
allTools: 'Tous les outils'
favoritesDndToolTip: 'Faites glisser et déposez pour réordonner vos favoris'
subtitle: 'Outils pour les développeurs'
toggleMenu: 'Menu'
home: Accueil

View file

@ -3,6 +3,7 @@ home:
newestTools: Nyeste verktøy
favoriteTools: 'Dine favoritt verktøy'
allTools: 'Alle verktøyene'
favoritesDndToolTip: 'Dra og slipp for å omordne favoritter'
subtitle: 'Nyttige verktøy for utviklere'
toggleMenu: 'Vekslemenmy'
home: Hjem

View file

@ -3,6 +3,7 @@ home:
newestTools: 'Novas ferramentas'
favoriteTools: 'Suas ferramentas favoritas'
allTools: 'Todas as ferramentas'
favoritesDndToolTip: 'Arraste e solte para reordenar favoritos'
subtitle: 'Ferraentas úteis para desenvolvedores'
toggleMenu: 'Menu'
home: 'Início'

View file

@ -3,6 +3,7 @@ home:
newestTools: Найновіші інструменти
favoriteTools: 'Ваші улюблені інструменти'
allTools: 'Усі інструменти'
favoritesDndToolTip: 'Перетягніть і відпустіть, щоб змінити порядок улюблених'
subtitle: 'Зручні інструменти для розробників'
toggleMenu: 'Перемикання меню'
home: Головна

View file

@ -3,6 +3,7 @@ home:
newestTools: Công cụ mới nhất
favoriteTools: 'Công cụ yêu thích của bạn'
allTools: 'Tất cả công cụ'
favoritesDndToolTip: 'Kéo thả để sắp xếp lại yêu thích'
subtitle: 'Công cụ cho nhà phát triển.'
toggleMenu: 'Chuyển đổi menu'
home: Trang chủ

View file

@ -3,6 +3,7 @@ home:
newestTools: '最新工具'
favoriteTools: '我的收藏'
allTools: '全部工具'
favoritesDndToolTip: '拖放重新排列收藏夹'
subtitle: '助力开发人员和 IT 工作者'
toggleMenu: '切换菜单'
home: '主页'

View file

@ -99,6 +99,7 @@
"vue-router": "^4.1.6",
"vue-shadow-dom": "^4.2.0",
"vue-tsc": "^1.8.1",
"vuedraggable": "^4.1.0",
"xml-formatter": "^3.3.2",
"xml-js": "^1.6.11",
"yaml": "^2.2.1"

14
pnpm-lock.yaml generated
View file

@ -194,6 +194,9 @@ dependencies:
vue-tsc:
specifier: ^1.8.1
version: 1.8.1(typescript@5.2.2)
vuedraggable:
specifier: ^4.1.0
version: 4.1.0(vue@3.3.4)
xml-formatter:
specifier: ^3.3.2
version: 3.3.2
@ -8231,6 +8234,9 @@ packages:
tslib: 2.5.0
dev: false
/sortablejs@1.14.0:
resolution: {integrity: sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==}
/source-map-js@1.0.2:
resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
engines: {node: '>=0.10.0'}
@ -9356,6 +9362,14 @@ packages:
'@vue/server-renderer': 3.3.4(vue@3.3.4)
'@vue/shared': 3.3.4
/vuedraggable@4.1.0(vue@3.3.4):
resolution: {integrity: sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==}
peerDependencies:
vue: ^3.0.1
dependencies:
sortablejs: 1.14.0
vue: 3.3.4
/vueuc@0.4.51(vue@3.3.4):
resolution: {integrity: sha512-pLiMChM4f+W8czlIClGvGBYo656lc2Y0/mXFSCydcSmnCR1izlKPGMgiYBGjbY9FDkFG8a2HEVz7t0DNzBWbDw==}
peerDependencies:

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);
},
};
});