Something went wrong. Try again.
the {coilest,wokest,funnest} client for bluesky next.bbell.vt3e.cat
bluesky client
Something went wrong. Try again.
3.5 kB · 162 lines
Vue
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163<script lang="ts" setup>import { computed, defineAsyncComponent, type Component, watch } from "vue";
import { useNavigationStore } from "@/stores/navigation";import { pages, type RootPageNames } from "@/router";import { useEnvironmentStore } from "@/stores/environment";
const registry: Record<string, Component> = Object.fromEntries( Object.entries(pages).map(([name, page]) => { const comp = page.component; const resolved = typeof comp === "function" ? defineAsyncComponent({ loader: comp as unknown as () => Promise<Component>, }) : comp; return [name, resolved]; }),) as Record<string, Component>;
const props = defineProps<{ tab: RootPageNames }>();const nav = useNavigationStore();const env = useEnvironmentStore();
const isActive = computed(() => nav.activeTab === props.tab);const isPreloadTab = computed(() => props.tab === "home");const shouldRender = computed(() => isActive.value || isPreloadTab.value);
const rawStack = computed(() => nav.stacks[props.tab]);
const displayStack = computed(() => { if (!rawStack.value) return []; return rawStack.value;});
watch( () => nav.pendingPop, (pendingPop) => { if (!pendingPop || pendingPop.tab !== props.tab) return; nav.completePop(); }, { immediate: true },);
const getPagePosition = (index: number, stackLength: number) => { if (index === stackLength - 1) return "current"; if (index === stackLength - 2) return "previous"; return "hidden";};</script>
<template> <div v-show="shouldRender" :class="['tab-stack', env.isDesktop ? 'is-desktop' : 'is-mobile']" :data-tab="props.tab" :id="`tabpanel-${props.tab}`" :aria-hidden="!shouldRender" :aria-labelledby="`tab-${props.tab}`" aria-role="tabpanel" :inert="!shouldRender" > <TransitionGroup name="page"> <div v-for="(entry, index) in displayStack" :key="entry.id" :class="['stack-page', getPagePosition(index, displayStack.length)]" :data-entry-id="entry.id" :data-index="index" :inert="index !== displayStack.length - 1" v-show="index >= displayStack.length - 1" > <Suspense> <template #default> <component :is="registry[entry.page]" v-bind="entry.props" :routeName="entry.page" /> </template> <template #fallback> <div class="page-loading" aria-hidden="true"></div> </template> </Suspense> </div> </TransitionGroup> </div></template>
<style scoped lang="scss">.tab-stack { position: relative; width: 100%; height: 100dvh; overflow-x: hidden; /* overflow: hidden; */}
.stack-page { position: absolute; inset: 0; box-sizing: border-box; z-index: 0; max-height: 100dvh;
&.current { z-index: 10; opacity: 1; }
&.previous { z-index: 5; opacity: 1; }
&.hidden { opacity: 0; pointer-events: none; }}
.page-enter-active,.page-leave-active { transition: 0.3s var(--ease-spring) !important;}
.is-desktop { .stack-page { max-height: calc(100dvh - var(--space-4)); }
.page-enter-from { opacity: 0 !important; transform: translateY(-3rem); &:last-child { transform: translateY(3rem); } }
.page-leave-to { opacity: 0; transform: translateY(-3rem); &:last-child { transform: translateY(3rem); } }}
.is-mobile { .page-enter-from { opacity: 0 !important; transform: translateX(-3rem); &:last-child { transform: translateX(3rem); } }
.page-leave-to { opacity: 0; transform: translateX(-3rem); &:last-child { transform: translateX(3rem); } }}</style>