mirror of
https://github.com/Xevion/banner.git
synced 2026-01-31 00:23:31 -06:00
feat: enhance table scrolling and eliminate initial theme flash
This commit is contained in:
+1
-1
@@ -1,5 +1,5 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="en" class="no-transition">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
@@ -10,6 +10,10 @@ import {
|
||||
isTimeTBA,
|
||||
} from "$lib/course";
|
||||
import CourseDetail from "./CourseDetail.svelte";
|
||||
import { slide } from "svelte/transition";
|
||||
import { onMount } from "svelte";
|
||||
import { OverlayScrollbars } from "overlayscrollbars";
|
||||
import { themeStore } from "$lib/stores/theme.svelte";
|
||||
import { createSvelteTable, FlexRender } from "$lib/components/ui/data-table/index.js";
|
||||
import {
|
||||
getCoreRowModel,
|
||||
@@ -38,6 +42,33 @@ let {
|
||||
} = $props();
|
||||
|
||||
let expandedCrn: string | null = $state(null);
|
||||
let tableWrapper: HTMLDivElement = undefined!;
|
||||
|
||||
onMount(() => {
|
||||
const osInstance = OverlayScrollbars(tableWrapper, {
|
||||
overflow: { x: "scroll", y: "hidden" },
|
||||
scrollbars: {
|
||||
autoHide: "never",
|
||||
theme: themeStore.isDark ? "os-theme-dark" : "os-theme-light",
|
||||
},
|
||||
});
|
||||
|
||||
// React to theme changes
|
||||
const unwatch = $effect.root(() => {
|
||||
$effect(() => {
|
||||
osInstance.options({
|
||||
scrollbars: {
|
||||
theme: themeStore.isDark ? "os-theme-dark" : "os-theme-light",
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return () => {
|
||||
unwatch();
|
||||
osInstance.destroy();
|
||||
};
|
||||
});
|
||||
|
||||
// Column visibility state
|
||||
let columnVisibility: VisibilityState = $state({});
|
||||
@@ -298,10 +329,10 @@ const table = createSvelteTable({
|
||||
</div>
|
||||
|
||||
<!-- Table with context menu on header -->
|
||||
<div class="overflow-x-auto">
|
||||
<div bind:this={tableWrapper} class="overflow-x-auto">
|
||||
<ContextMenu.Root>
|
||||
<ContextMenu.Trigger class="contents">
|
||||
<table class="w-full border-collapse text-sm">
|
||||
<table class="w-full min-w-[640px] border-collapse text-sm">
|
||||
<thead>
|
||||
{#each table.getHeaderGroups() as headerGroup}
|
||||
<tr class="border-b border-border text-left text-muted-foreground">
|
||||
@@ -372,7 +403,7 @@ const table = createSvelteTable({
|
||||
<span class="font-semibold">{course.subject} {course.courseNumber}</span>{#if course.sequenceNumber}<span class="text-muted-foreground">-{course.sequenceNumber}</span>{/if}
|
||||
</td>
|
||||
{:else if colId === "title"}
|
||||
<td class="py-2 px-2 font-medium">{course.title}</td>
|
||||
<td class="py-2 px-2 font-medium max-w-[200px] truncate" title={course.title}>{course.title}</td>
|
||||
{:else if colId === "instructor"}
|
||||
<td class="py-2 px-2 whitespace-nowrap">
|
||||
{primaryInstructorDisplay(course)}
|
||||
@@ -423,7 +454,9 @@ const table = createSvelteTable({
|
||||
{#if expandedCrn === course.crn}
|
||||
<tr>
|
||||
<td colspan={visibleColumnIds.length} class="p-0">
|
||||
<div transition:slide={{ duration: 200 }}>
|
||||
<CourseDetail {course} />
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{/if}
|
||||
|
||||
@@ -12,6 +12,12 @@ let { children } = $props();
|
||||
onMount(() => {
|
||||
themeStore.init();
|
||||
|
||||
// Enable theme transitions now that the page has rendered with the correct theme.
|
||||
// Without this delay, the initial paint would animate from light to dark colors.
|
||||
requestAnimationFrame(() => {
|
||||
document.documentElement.classList.remove("no-transition");
|
||||
});
|
||||
|
||||
const osInstance = OverlayScrollbars(document.body, {
|
||||
scrollbars: {
|
||||
autoHide: "leave",
|
||||
|
||||
@@ -64,8 +64,8 @@ body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
body,
|
||||
body * {
|
||||
html:not(.no-transition) body,
|
||||
html:not(.no-transition) body * {
|
||||
transition: background-color 300ms, color 300ms, border-color 300ms, fill 300ms;
|
||||
}
|
||||
|
||||
@@ -105,6 +105,42 @@ body::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Native scrollbars — theme-aware styling for inner scrollable elements */
|
||||
* {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(0, 0, 0, 0.25) transparent;
|
||||
}
|
||||
|
||||
.dark * {
|
||||
scrollbar-color: rgba(255, 255, 255, 0.3) transparent;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
|
||||
.dark ::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.dark ::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%,
|
||||
100% {
|
||||
|
||||
Reference in New Issue
Block a user