mirror of
https://github.com/unraid/api.git
synced 2026-01-02 22:50:02 -06:00
feat(web): make notifications list scrollable inside the sheet & tabs
This commit is contained in:
@@ -6,13 +6,28 @@ import {
|
||||
import type { NotificationType } from "~/composables/gql/graphql";
|
||||
import { useFragment } from "~/composables/gql/fragment-masking";
|
||||
import { useQuery } from "@vue/apollo-composable";
|
||||
// import { useInfiniteScroll } from "@vueuse/core";
|
||||
import { vInfiniteScroll } from "@vueuse/components";
|
||||
|
||||
const props = defineProps<{ type: NotificationType }>();
|
||||
const element = ref<HTMLElement | null>(null);
|
||||
|
||||
const { result, error } = useQuery(getNotifications, {
|
||||
/**
|
||||
* Page size is the max amount of items fetched from the api in a single request.
|
||||
*/
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
type: NotificationType;
|
||||
pageSize?: number;
|
||||
}>(),
|
||||
{
|
||||
pageSize: 25,
|
||||
}
|
||||
);
|
||||
|
||||
const { result, error, fetchMore } = useQuery(getNotifications, {
|
||||
filter: {
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
limit: props.pageSize,
|
||||
type: props.type,
|
||||
},
|
||||
});
|
||||
@@ -31,14 +46,35 @@ const notifications = computed(() => {
|
||||
// and we don't want to display them in the wrong list client-side.
|
||||
return list.filter((n) => n.type === props.type);
|
||||
});
|
||||
|
||||
async function onLoadMore() {
|
||||
console.log("[getNotifications] onLoadMore");
|
||||
// void fetchMore({
|
||||
// variables: {
|
||||
// filter: {
|
||||
// offset: notifications.value.length,
|
||||
// limit: props.pageSize,
|
||||
// type: props.type,
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
}
|
||||
|
||||
// const { isLoading } = useInfiniteScroll(element, onLoadMore, {
|
||||
// distance: 25,
|
||||
// });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="notifications?.length > 0" class="divide-y divide-gray-200">
|
||||
<NotificationsItem
|
||||
v-for="notification in notifications"
|
||||
:key="notification.id"
|
||||
v-bind="notification"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="notifications?.length > 0"
|
||||
v-infinite-scroll="onLoadMore"
|
||||
class="divide-y divide-gray-200 overflow-y-scroll px-6 h-full"
|
||||
>
|
||||
<NotificationsItem
|
||||
v-for="notification in notifications"
|
||||
:key="notification.id"
|
||||
v-bind="notification"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -28,13 +28,13 @@ const { teleportTarget, determineTeleportTarget } = useTeleport();
|
||||
|
||||
<SheetContent
|
||||
:to="teleportTarget"
|
||||
class="w-full overflow-y-scroll sm:max-w-[540px] space-y-3"
|
||||
class="w-full sm:max-w-[540px] space-y-3 h-screen"
|
||||
>
|
||||
<SheetHeader>
|
||||
<SheetTitle>Notifications</SheetTitle>
|
||||
</SheetHeader>
|
||||
|
||||
<Tabs default-value="unread" class="">
|
||||
<Tabs default-value="unread" class="h-full">
|
||||
<div class="flex flex-row justify-between items-center flex-wrap gap-2">
|
||||
<TabsList class="ml-[1px]">
|
||||
<TabsTrigger value="unread"> Unread </TabsTrigger>
|
||||
@@ -66,7 +66,7 @@ const { teleportTarget, determineTeleportTarget } = useTeleport();
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<TabsContent value="unread">
|
||||
<TabsContent value="unread" class="h-[92%]">
|
||||
<NotificationsList :type="NotificationType.Unread" />
|
||||
</TabsContent>
|
||||
|
||||
@@ -75,9 +75,6 @@ const { teleportTarget, determineTeleportTarget } = useTeleport();
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
|
||||
<SheetFooter class="text-center">
|
||||
<p>Future pagination station</p>
|
||||
</SheetFooter>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
</template>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { DialogRoot, type DialogRootEmits, type DialogRootProps, useForwardPropsEmits } from 'radix-vue'
|
||||
|
||||
const props = defineProps<DialogRootProps>()
|
||||
const props = defineProps<DialogRootProps & { class?: string }>()
|
||||
const emits = defineEmits<DialogRootEmits>()
|
||||
|
||||
const forwarded = useForwardPropsEmits(props, emits)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { type HTMLAttributes, computed } from 'vue'
|
||||
import { type HTMLAttributes, computed } from "vue";
|
||||
import {
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
@@ -8,44 +8,54 @@ import {
|
||||
DialogOverlay,
|
||||
DialogPortal,
|
||||
useForwardPropsEmits,
|
||||
} from 'radix-vue'
|
||||
import { X } from 'lucide-vue-next'
|
||||
import { type SheetVariants, sheetVariants } from '.'
|
||||
import { cn } from '~/components/shadcn/utils'
|
||||
} from "radix-vue";
|
||||
import { X } from "lucide-vue-next";
|
||||
import { type SheetVariants, sheetVariants } from ".";
|
||||
import { cn } from "~/components/shadcn/utils";
|
||||
import { vInfiniteScroll } from "@vueuse/components";
|
||||
|
||||
type ScrollLoader = Parameters<typeof useInfiniteScroll>[1];
|
||||
|
||||
interface SheetContentProps extends DialogContentProps {
|
||||
class?: HTMLAttributes['class']
|
||||
side?: SheetVariants['side']
|
||||
disabled?: boolean
|
||||
forceMount?: boolean
|
||||
to?: string | HTMLElement | Element
|
||||
class?: HTMLAttributes["class"];
|
||||
side?: SheetVariants["side"];
|
||||
padding?: SheetVariants["padding"];
|
||||
disabled?: boolean;
|
||||
forceMount?: boolean;
|
||||
to?: string | HTMLElement | Element;
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
})
|
||||
});
|
||||
|
||||
const props = defineProps<SheetContentProps>()
|
||||
const props = defineProps<SheetContentProps>();
|
||||
|
||||
const emits = defineEmits<DialogContentEmits>()
|
||||
const emits = defineEmits<
|
||||
DialogContentEmits & { loadMore: Parameters<ScrollLoader> }
|
||||
>();
|
||||
|
||||
const delegatedProps = computed(() => {
|
||||
const { class: _, side, ...delegated } = props
|
||||
|
||||
return delegated
|
||||
})
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
const { class: _, side, padding, ...delegated } = props;
|
||||
console.log("[SheetContent] delegatedProps", delegated);
|
||||
return delegated;
|
||||
});
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DialogPortal :disabled="disabled" :force-mount="forceMount" :to="to as HTMLElement">
|
||||
<DialogPortal
|
||||
:disabled="disabled"
|
||||
:force-mount="forceMount"
|
||||
:to="to as HTMLElement"
|
||||
>
|
||||
<DialogOverlay
|
||||
class="fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
|
||||
class="fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
|
||||
/>
|
||||
<DialogContent
|
||||
:class="cn(sheetVariants({ side }), props.class)"
|
||||
:class="cn(sheetVariants({ side, padding }), props.class)"
|
||||
v-bind="{ ...forwarded, ...$attrs }"
|
||||
v-infinite-scroll="(state) => $emit('loadMore', state)"
|
||||
>
|
||||
<slot />
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ export { default as SheetDescription } from './SheetDescription.vue'
|
||||
export { default as SheetFooter } from './SheetFooter.vue'
|
||||
|
||||
export const sheetVariants = cva(
|
||||
'fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500',
|
||||
'fixed z-50 gap-4 bg-background shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500',
|
||||
{
|
||||
variants: {
|
||||
side: {
|
||||
@@ -21,9 +21,14 @@ export const sheetVariants = cva(
|
||||
right:
|
||||
'inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm',
|
||||
},
|
||||
padding: {
|
||||
none: '',
|
||||
md: 'p-6'
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
side: 'right',
|
||||
padding: 'md',
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user