Skip to content

Instantly share code, notes, and snippets.

@mary-ext
Created October 21, 2024 12:31
Show Gist options
  • Save mary-ext/1089a1da08df72dbd08381c956bb8a93 to your computer and use it in GitHub Desktop.
Save mary-ext/1089a1da08df72dbd08381c956bb8a93 to your computer and use it in GitHub Desktop.
vue modal router thing
<script setup lang="ts">
import { computed } from 'vue';
import { type RouteLocationNormalizedLoaded as LoadedRouteLocation, RouterView, useRoute } from 'vue-router';
import { assert } from '~/utils/misc.ts';
const route = useRoute();
const handleModalRoute = (route: LoadedRouteLocation): LoadedRouteLocation => {
// on modal routes, we only want the actual modal itself to be rendered
return { ...route, matched: route.matched.slice(-1) };
};
const resolvedRoute = computed((): [bg: LoadedRouteLocation, fg: LoadedRouteLocation | null] => {
const meta = route.meta;
if (meta && meta.defaultBackgroundRoute) {
const resolved = meta._bgRoute;
assert(resolved != null);
return [resolved, handleModalRoute(route)];
}
return [route, null];
});
</script>
<template>
<RouterView :route="resolvedRoute[0]" :key="resolvedRoute[0].fullPath" />
<template v-if="resolvedRoute[1]">
<RouterView :route="resolvedRoute[1]" :key="resolvedRoute[1].fullPath" />
</template>
</template>
import { createRouter, createWebHistory, loadRouteLocation } from 'vue-router';
import { isDid } from '~/api/utils.ts';
import { multiagent } from '~/globals/agent.ts';
export const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
component: () => import('~/views/FrontPage.vue'),
},
{
path: '/u/:uid',
component: () => import('~/views/main/MainLayout.vue'),
beforeEnter(to) {
const uid = to.params.uid as string;
const $accounts = multiagent.accounts;
if (!$accounts || !isDid(uid) || !$accounts[uid]) {
const path = to.path.slice(4 + uid.length);
return {
path: '/',
query: {
to: `@uid/${path}`,
},
};
}
},
children: [
{
path: '',
component: () => import('~/views/main/home/HomePage.vue'),
},
{
path: 'notifications',
component: () => import('~/views/main/notifications/NotificationsPage.vue'),
},
{
path: 'profile/:actor',
component: () => import('~/views/main/profile/ProfileLayout.vue'),
children: [
{
path: '',
component: () => import('~/views/main/profile/ProfileTimelinePage.vue'),
},
],
},
{
path: 'profile/:actor/post/:tid',
component: () => import('~/views/main/modals/PostsModal.vue'),
meta: {
defaultBackgroundRoute(to) {
const uid = to.params.uid as DID;
const actor = to.params.actor as string;
return `/u/${uid}/profile/${actor}`;
},
},
},
],
},
{
path: '/:rest(.*)*',
component: () => import('~/views/NotFoundPage.vue'),
},
],
});
// Modal route handling
let first = true;
router.beforeResolve(async (to, from) => {
const meta = to.meta;
if (meta.defaultBackgroundRoute) {
if (first) {
const bg = meta.defaultBackgroundRoute(to);
const resolved = router.resolve(bg);
await loadRouteLocation(resolved);
meta._bgRoute = resolved;
} else if (from.meta._bgRoute) {
meta._bgRoute = from.meta._bgRoute;
} else {
meta._bgRoute = from;
}
}
first = false;
});
declare module 'vue-router' {
interface RouteMeta {
/**
* Indicates that this route is a modal route, it will try to use the route
* it was transitioning from as the background view, but if it can't, it
* will call this function to get the "default" background view for use
*/
defaultBackgroundRoute?: (to: RouteLocationNormalized) => RouteLocationRaw;
/**
* @internal
* This is an internal property for our navigation guards to attach the
* appropriate background view to use for a modal route.
*/
_bgRoute?: RouteLocation;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment