96 lines
3.6 KiB
Vue
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®ion=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>
|