Files
2024-08-28 15:35:35 +02:00

96 lines
3.6 KiB
Vue

<!-- eslint-disable vue/multi-word-component-names -->
<template>
<div class="relative">
<transition name="slide-fade" @before-enter="beforeEnter" @enter="enter" @leave="leave">
<div v-if="isVisible"
class="fixed bottom-0 left-0 w-full bg-white shadow-lg rounded-t-lg transition-transform transform"
:class="{ 'translate-y-full': !isVisible, 'translate-y-0': isVisible }">
<div class="p-4">
<p class="mb-3">Moje serwisy.</p>
<div class="flex overflow-x-auto">
<Card v-for="service in services" :key="service.title" v-bind="service" />
</div>
</div>
</div>
</transition>
<button @click="toggleOffcanvas"
class="fixed bottom-4 right-4 w-16 h-16 bg-blue-500 text-white rounded-full flex items-center justify-center shadow-lg hover:bg-blue-600 focus:outline-none">
<span class="text-2xl">+</span>
</button>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import Card from './Card.vue';
const isVisible = ref(false);
const services = [
{
title: "FileCloud",
description: "Moja prywatna chmura plików.",
link: "https://filecloud.garandplg.com/ui/core/index.html#/",
},
{
title: "Invidious",
description: "Open-source'owy frontend dla YouTube.",
link: "https://invidious.garandplg.com",
},
{
title: "Materialious",
description: "Polepszony interface dla Invidious.",
link: "https://materialious.garandplg.com/?returnYTDislikesInstance=https%3A%2F%2Fryd-proxy.garandplg.com&darkMode=true&themeColor=%23ffff22&autoPlay=true&alwaysLoop=false&proxyVideos=true&listenByDefault=false&savePlaybackPosition=true&dashEnabled=true&theatreModeByDefault=true&autoplayNextByDefault=false&returnYtDislikes=true&searchSuggestions=true&previewVideoOnHover=true&sponsorBlock=true&sponsorBlockUrl=https%3A%2F%2Fsponsor.ajay.app&sponsorBlockCategories=sponsor%2Cselfpromo%2Cinteraction%2Cintro%2Coutro%2Cpreview&deArrowInstance=https%3A%2F%2Fsponsor.ajay.app&deArrowEnabled=true&deArrowThumbnailInstance=https%3A%2F%2Fdearrow-thumb.ajay.app&playerMiniPlayer=true&syncious=true&synciousInstance=https%3A%2F%2Fsyncious.garandplg.com&region=PL&autoExpandComments=true&autoExpandDesc=false&deArrowTitlesOnly=true&sponsorBlockDisplayToast=true",
},
{
title: "SearXNG",
description: "Moja własna meta-wyszukiwarka internetowa.",
link: "https://search.garandplg.com/",
},
{
title: "Pterodactyl",
description: "Serwis do zarządzania serwerami do gier.",
link: "https://pterodactyl-panel.garandplg.com",
},
{
title: "Open WebUI",
description: "Własne interface do modeli AI.",
link: "https://ai.garandplg.com/",
}
]
const toggleOffcanvas = () => isVisible.value = !isVisible.value;
const beforeEnter = (el: HTMLElement) => el.style.transform = 'translateY(100%)';
const enter = (el: HTMLElement) => {
el.offsetHeight;
el.style.transition = 'transform 0.3s ease-out';
el.style.transform = 'translateY(0)';
};
const leave = (el: HTMLElement) => {
el.style.transition = 'transform 0.3s ease-in';
el.style.transform = 'translateY(100%)';
};
</script>
<style scoped>
.slide-fade-enter-active,
.slide-fade-leave-active {
@apply transition-transform duration-300 ease-in-out;
}
.slide-fade-enter,
.slide-fade-leave-to {
@apply translate-y-full;
}
.offcanvas {
@apply fixed bottom-0 left-0 w-full bg-white shadow-lg rounded-t-lg;
}
.floating-button {
@apply fixed bottom-4 right-4 w-16 h-16 bg-blue-500 text-white rounded-full flex items-center justify-center shadow-lg hover:bg-blue-600 focus:outline-none;
}
</style>