diff --git a/web/src/lib/components/CourseDetail.svelte b/web/src/lib/components/CourseDetail.svelte index b8a993f..1796cdc 100644 --- a/web/src/lib/components/CourseDetail.svelte +++ b/web/src/lib/components/CourseDetail.svelte @@ -13,7 +13,7 @@ import { rmpUrl, } from "$lib/course"; import { themeStore } from "$lib/stores/theme.svelte"; -import { cn, formatNumber, tooltipContentClass } from "$lib/utils"; +import { formatNumber } from "$lib/utils"; import { Calendar, Check, @@ -24,7 +24,7 @@ import { Star, Triangle, } from "@lucide/svelte"; -import { Tooltip } from "bits-ui"; +import RichTooltip from "./RichTooltip.svelte"; import SimpleTooltip from "./SimpleTooltip.svelte"; let { course }: { course: CourseResponse } = $props(); @@ -40,8 +40,8 @@ const clipboard = useClipboard(); {#if course.instructors.length > 0}
{#each course.instructors as instructor} - - + + {#snippet children()} @@ -71,11 +71,8 @@ const clipboard = useClipboard(); {/if} - - + {/snippet} + {#snippet content()}
{instructor.displayName} @@ -126,8 +123,8 @@ const clipboard = useClipboard(); {/if}
- - + {/snippet} + {/each}
{:else} @@ -272,8 +269,8 @@ const clipboard = useClipboard(); - - + + {#snippet children()} @@ -288,8 +285,8 @@ const clipboard = useClipboard(); {/if} - - + {/snippet} + {#snippet content()} Group {course.crossList} @@ -297,8 +294,8 @@ const clipboard = useClipboard(); — {formatNumber(course.crossListCount)} enrolled across {formatNumber(course.crossListCapacity)} shared seats {/if} - - + {/snippet} +
{/if} diff --git a/web/src/lib/components/CourseTable.svelte b/web/src/lib/components/CourseTable.svelte index 1c1bcf8..94d8ab2 100644 --- a/web/src/lib/components/CourseTable.svelte +++ b/web/src/lib/components/CourseTable.svelte @@ -24,7 +24,7 @@ import { seatsDotColor, } from "$lib/course"; import { themeStore } from "$lib/stores/theme.svelte"; -import { cn, formatNumber, tooltipContentClass } from "$lib/utils"; +import { formatNumber } from "$lib/utils"; import { ArrowDown, ArrowUp, @@ -43,11 +43,12 @@ import { getCoreRowModel, getSortedRowModel, } from "@tanstack/table-core"; -import { ContextMenu, DropdownMenu, Tooltip } from "bits-ui"; +import { ContextMenu, DropdownMenu } from "bits-ui"; import { flip } from "svelte/animate"; import { cubicOut } from "svelte/easing"; import { fade, slide } from "svelte/transition"; import CourseDetail from "./CourseDetail.svelte"; +import RichTooltip from "./RichTooltip.svelte"; import SimpleTooltip from "./SimpleTooltip.svelte"; let { @@ -532,10 +533,12 @@ const table = createSvelteTable({ {@const lowConfidence = ratingData.count < RMP_CONFIDENCE_THRESHOLD} - - + {#snippet children()} {/if} - - + {/snippet} + {#snippet content()} @@ -592,8 +588,8 @@ const table = createSvelteTable({ {/if} - - + {/snippet} + {/if} {:else if colId === "time"} diff --git a/web/src/lib/components/Pagination.svelte b/web/src/lib/components/Pagination.svelte index d468b73..e71a7ba 100644 --- a/web/src/lib/components/Pagination.svelte +++ b/web/src/lib/components/Pagination.svelte @@ -1,105 +1,116 @@ {#if totalCount > 0 && totalPages > 1} -
- -
- - Showing {formatNumber(start)}–{formatNumber(end)} of {formatNumber(totalCount)} courses - -
+
+ +
+ + Showing {formatNumber(start)}–{formatNumber(end)} of {formatNumber( + totalCount, + )} courses + +
- -
- {#key currentPage} - {#each pageSlots as page, i (i)} - {#if i === 2} - - { - if (v) goToPage(Number(v)); - }} - items={pageItems} - > - + {#key currentPage} + {#each pageSlots as page, i (i)} + {#if i === 2} + + { + if (v) goToPage(Number(v)); + }} + items={pageItems} + > + - {currentPage} - - - - + {currentPage} + + + + - - - - - {#each pageItems as item (item.value)} - + + + + + {#each pageItems as item (item.value)} + - {item.label} - - {/each} - - - - - - - - {:else} - - - {/if} - {/each} - {/key} -
+ {!isSlotVisible(page) + ? 'invisible' + : loading + ? 'opacity-40' + : ''} + {!isSlotVisible(page) || loading + ? 'pointer-events-none' + : ''}" + onclick={() => goToPage(page)} + aria-label="Go to page {page}" + aria-hidden={!isSlotVisible(page)} + tabindex={isSlotVisible(page) ? 0 : -1} + disabled={!isSlotVisible(page) || loading} + use:slideIn={direction} + > + {page} + + {/if} + {/each} + {/key} +
- -
-
+ +
+ {:else if totalCount > 0} - -
- - Showing {formatNumber(start)}–{formatNumber(end)} of {formatNumber(totalCount)} courses - -
+ +
+ + Showing {formatNumber(start)}–{formatNumber(end)} of {formatNumber( + totalCount, + )} courses + +
{/if} diff --git a/web/src/lib/components/RichTooltip.svelte b/web/src/lib/components/RichTooltip.svelte new file mode 100644 index 0000000..d0f28fb --- /dev/null +++ b/web/src/lib/components/RichTooltip.svelte @@ -0,0 +1,64 @@ + + + + + {#snippet child({ props })} + + {@render children()} + + {/snippet} + + {#if portal} + + + {@render content()} + + + {:else} + + {@render content()} + + {/if} + diff --git a/web/src/lib/components/SimpleTooltip.svelte b/web/src/lib/components/SimpleTooltip.svelte index 37801c0..4d21bb7 100644 --- a/web/src/lib/components/SimpleTooltip.svelte +++ b/web/src/lib/components/SimpleTooltip.svelte @@ -11,6 +11,9 @@ let { triggerClass = "", contentClass = "", sideOffset = 6, + portal = true, + avoidCollisions = true, + collisionPadding = 8, children, }: { text: string; @@ -20,6 +23,9 @@ let { triggerClass?: string; contentClass?: string; sideOffset?: number; + portal?: boolean; + avoidCollisions?: boolean; + collisionPadding?: number; children: Snippet; } = $props(); @@ -32,11 +38,27 @@ let { {/snippet} - - {text} - + {#if portal} + + + {text} + + + {:else} + + {text} + + {/if} diff --git a/web/src/routes/+layout.svelte b/web/src/routes/+layout.svelte index 73eeea3..07dc656 100644 --- a/web/src/routes/+layout.svelte +++ b/web/src/routes/+layout.svelte @@ -39,7 +39,7 @@ onMount(() => { }); - +