Skip to content

Commit 04b22f4

Browse files
authored
Merge pull request #409 from ACM-VIT/dev
Dev
2 parents f1ac199 + 6fb2432 commit 04b22f4

18 files changed

Lines changed: 1278 additions & 51 deletions

app/(app)/client-side.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ function MobileChromeHeader({
114114
aria-label={isNavOn ? "Close tools menu" : "Open tools menu"}
115115
aria-expanded={isNavOn}
116116
style={{ viewTransitionName: "persistent-menu-button" }}
117-
className={`pointer-events-auto flex h-11 w-11 shrink-0 items-center justify-center rounded-lg text-black/65 transition-colors active:bg-black/[0.08] dark:text-[#D5D5D5]/85 dark:active:bg-white/[0.07] ${isNavOn ? "pointer-events-none opacity-0" : "opacity-100"}`}
117+
className={`ec-icon-button pointer-events-auto flex h-11 w-11 shrink-0 items-center justify-center rounded-lg text-black/65 active:bg-black/[0.08] dark:text-[#D5D5D5]/85 dark:active:bg-white/[0.07] ${isNavOn ? "pointer-events-none opacity-0" : "opacity-100"}`}
118118
>
119119
<MoreHorizontal className="h-6 w-6" strokeWidth={2.25} aria-hidden />
120120
</button>

app/(app)/home/course-search.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ export default function CourseSearch({ courses }: CourseSearchProps) {
272272
return (
273273
<div className="mx-auto w-full min-w-0 text-left">
274274
<div className="relative">
275-
<div className="relative flex h-12 sm:h-14 lg:h-16 w-full min-w-0 items-center overflow-hidden bg-white pl-4 pr-2 dark:bg-[#3D414E] border border-black/25 dark:border-[#D5D5D5]/30">
275+
<div className="ec-focus-ring relative flex h-12 sm:h-14 lg:h-16 w-full min-w-0 items-center overflow-hidden bg-white pl-4 pr-2 dark:bg-[#3D414E] border border-black/25 dark:border-[#D5D5D5]/30">
276276
<Image src={SearchIcon} alt="search" className="dark:invert-[.835] h-5 w-5 sm:h-6 sm:w-6 shrink-0" />
277277
{nativeSearchAvailable ? (
278278
<button
@@ -311,8 +311,8 @@ export default function CourseSearch({ courses }: CourseSearchProps) {
311311
)}
312312
<button
313313
onClick={clearSelection}
314-
className={`inline-flex h-9 w-9 shrink-0 items-center justify-center text-black/60 transition-colors hover:text-black dark:text-[#D5D5D5]/70 dark:hover:text-[#3BF4C7] ${query ? "visible" : "invisible pointer-events-none w-0 overflow-hidden"
315-
}`}
314+
data-hidden={query ? "false" : "true"}
315+
className="ec-collapse-toggle ec-icon-button inline-flex h-9 w-9 shrink-0 items-center justify-center text-black/60 hover:text-black dark:text-[#D5D5D5]/70 dark:hover:text-[#3BF4C7]"
316316
type="button"
317317
aria-label="Clear search"
318318
tabIndex={query ? 0 : -1}
@@ -361,7 +361,8 @@ export default function CourseSearch({ courses }: CourseSearchProps) {
361361
resultIndex: index,
362362
})
363363
}
364-
className={`w-full px-4 py-3 text-left flex justify-between items-center gap-3 transition-colors border-b border-black/10 dark:border-[#D5D5D5]/15 last:border-b-0 hover:bg-[#5FC4E7]/25 dark:hover:bg-[#3BF4C7]/10 ${highlightedIndex === index
364+
style={{ ["--ec-row-index" as string]: index } as React.CSSProperties}
365+
className={`ec-row-reveal w-full px-4 py-3 text-left flex justify-between items-center gap-3 transition-colors border-b border-black/10 dark:border-[#D5D5D5]/15 last:border-b-0 hover:bg-[#5FC4E7]/25 dark:hover:bg-[#3BF4C7]/10 ${highlightedIndex === index
365366
? 'bg-[#5FC4E7]/25 dark:bg-[#3BF4C7]/10'
366367
: ''
367368
}`}

app/components/command-palette.tsx

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -874,7 +874,7 @@ function ActionRow({
874874
value={action.id}
875875
keywords={action.keywords}
876876
onSelect={() => onSelect(action)}
877-
className="flex min-h-[3.1rem] cursor-pointer items-center justify-between gap-3 rounded-md px-3 py-2 text-left outline-none transition-colors data-[selected=true]:bg-[#DDEFF4] dark:data-[selected=true]:bg-white/[0.09]"
877+
className="ec-command-row flex min-h-[3.1rem] cursor-pointer items-center justify-between gap-3 rounded-md px-3 py-2 text-left outline-none transition-colors data-[selected=true]:bg-[#DDEFF4] dark:data-[selected=true]:bg-white/[0.09]"
878878
>
879879
<span className="min-w-0 flex-1">
880880
<span className="block truncate text-sm font-semibold text-black dark:text-[#F3F7FA]">
@@ -901,7 +901,7 @@ function UnavailableCourseRow({
901901
resource: CommandResourceIntent;
902902
}) {
903903
return (
904-
<div className="mx-1 mb-1 rounded-md border border-black/10 bg-black/[0.03] px-3 py-2.5 dark:border-white/10 dark:bg-white/[0.045]">
904+
<div className="ec-command-row mx-1 mb-1 rounded-md border border-black/10 bg-black/[0.03] px-3 py-2.5 dark:border-white/10 dark:bg-white/[0.045]">
905905
<div className="text-sm font-semibold text-black dark:text-[#F3F7FA]">
906906
No {getResourceLabel(resource)} for {course.title}
907907
</div>
@@ -940,7 +940,7 @@ function PaperRow({
940940
String(paper.year ?? ""),
941941
]}
942942
onSelect={() => onSelect(paper.href)}
943-
className="flex min-h-[3.1rem] cursor-pointer items-center justify-between gap-3 rounded-md px-3 py-2 text-left outline-none transition-colors data-[selected=true]:bg-[#DDEFF4] dark:data-[selected=true]:bg-white/[0.09]"
943+
className="ec-command-row flex min-h-[3.1rem] cursor-pointer items-center justify-between gap-3 rounded-md px-3 py-2 text-left outline-none transition-colors data-[selected=true]:bg-[#DDEFF4] dark:data-[selected=true]:bg-white/[0.09]"
944944
>
945945
<span className="min-w-0 flex-1">
946946
<span className="block truncate text-sm font-semibold text-black dark:text-[#F3F7FA]">
@@ -957,6 +957,29 @@ function PaperRow({
957957
);
958958
}
959959

960+
function RecentSkeletonRow({ widthHint }: { widthHint: "lg" | "md" | "sm" }) {
961+
const titleWidth =
962+
widthHint === "lg" ? "w-7/12" : widthHint === "md" ? "w-6/12" : "w-5/12";
963+
const metaWidth =
964+
widthHint === "lg" ? "w-4/12" : widthHint === "md" ? "w-3/12" : "w-3/12";
965+
return (
966+
<div
967+
aria-hidden="true"
968+
className="ec-command-skeleton-row flex min-h-[3.1rem] items-center justify-between gap-3 rounded-md px-3 py-2"
969+
>
970+
<span className="min-w-0 flex-1">
971+
<span
972+
className={`block h-2.5 ${titleWidth} rounded-full bg-black/[0.10] dark:bg-white/[0.12]`}
973+
/>
974+
<span
975+
className={`mt-2 block h-2 ${metaWidth} rounded-full bg-black/[0.07] dark:bg-white/[0.08]`}
976+
/>
977+
</span>
978+
<span className="h-4 w-12 shrink-0 rounded border border-black/10 bg-black/[0.05] dark:border-white/10 dark:bg-white/[0.06]" />
979+
</div>
980+
);
981+
}
982+
960983
function CommandSuspenseFallback({
961984
label,
962985
}: {
@@ -1015,8 +1038,9 @@ export default function CommandPalette({ open, onOpenChange }: CommandPalettePro
10151038
}, [isSupportedViewport]);
10161039

10171040
useEffect(() => {
1041+
if (!isSupportedViewport) return;
1042+
10181043
const handleKeyDown = (event: KeyboardEvent) => {
1019-
if (!isSupportedViewport) return;
10201044
if (event.key.toLowerCase() !== "k" || (!event.metaKey && !event.ctrlKey)) {
10211045
return;
10221046
}
@@ -1026,7 +1050,7 @@ export default function CommandPalette({ open, onOpenChange }: CommandPalettePro
10261050

10271051
document.addEventListener("keydown", handleKeyDown);
10281052
return () => document.removeEventListener("keydown", handleKeyDown);
1029-
}, []);
1053+
}, [isSupportedViewport]);
10301054

10311055
if (!isSupportedViewport) {
10321056
return null;
@@ -1379,6 +1403,10 @@ function CommandPaletteSession({
13791403
!hasVisibleResults &&
13801404
!shouldShowResolvingFallback &&
13811405
(courseStatus === "ready" || courseStatus === "error");
1406+
const showRecentSkeletons =
1407+
!hasSearch &&
1408+
recentCourseActions.length === 0 &&
1409+
(courseStatus === "idle" || courseStatus === "loading");
13821410

13831411
const rememberCoursePreference = (action: CommandAction) => {
13841412
if (!action.courseCode || !action.courseTitle) return;
@@ -1486,11 +1514,11 @@ function CommandPaletteSession({
14861514
<Dialog.Portal forceMount>
14871515
<Dialog.Overlay
14881516
forceMount
1489-
className="fixed inset-0 z-[95] bg-[#19323A]/28 backdrop-blur-sm data-[state=closed]:hidden dark:bg-black/42"
1517+
className="ec-command-dialog-overlay fixed inset-0 z-[95] bg-[#19323A]/28 backdrop-blur-sm dark:bg-black/42"
14901518
/>
14911519
<Dialog.Content
14921520
forceMount
1493-
className="ec-command-dialog-panel fixed left-1/2 top-1/2 z-[96] h-[min(20rem,calc(100dvh-2rem))] w-[calc(100vw-2rem)] max-w-[34rem] overflow-hidden rounded-lg border border-[#BED0D7] bg-[#FBFDFE]/98 shadow-[0_24px_70px_rgba(20,54,66,0.24)] outline-none backdrop-blur-xl data-[state=closed]:hidden dark:border-white/14 dark:bg-[#11151D]/98 dark:shadow-[0_24px_90px_rgba(0,0,0,0.62)]"
1521+
className="ec-command-dialog-panel fixed left-1/2 top-1/2 z-[96] h-[min(20rem,calc(100dvh-2rem))] w-[calc(100vw-2rem)] max-w-[34rem] overflow-hidden rounded-lg border border-[#BED0D7] bg-[#FBFDFE]/98 shadow-[0_24px_70px_rgba(20,54,66,0.24)] outline-none backdrop-blur-xl dark:border-white/14 dark:bg-[#11151D]/98 dark:shadow-[0_24px_90px_rgba(0,0,0,0.62)]"
14941522
>
14951523
<Dialog.Title className="sr-only">ExamCooker command menu</Dialog.Title>
14961524
<Dialog.Description className="sr-only">
@@ -1522,6 +1550,14 @@ function CommandPaletteSession({
15221550
</div>
15231551

15241552
<Command.List className="min-h-0 flex-1 overflow-y-auto overscroll-contain px-2 py-2">
1553+
{showRecentSkeletons ? (
1554+
<>
1555+
<RecentSkeletonRow widthHint="lg" />
1556+
<RecentSkeletonRow widthHint="md" />
1557+
<RecentSkeletonRow widthHint="sm" />
1558+
</>
1559+
) : null}
1560+
15251561
{requestedResource
15261562
? unavailableCourses.map((course) => (
15271563
<UnavailableCourseRow

app/components/mobile-tab-bar.tsx

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -202,23 +202,28 @@ export default function MobileTabBar({ toolsSheetOpen = false }: Props) {
202202
}`}
203203
>
204204
<ul
205-
className={`mx-auto flex max-w-lg items-stretch justify-between ${
205+
className={`ec-tab-bar-frame mx-auto flex max-w-lg items-stretch justify-between ${
206206
nativeAndroid ? "gap-0 px-2 py-2" : "gap-1 px-1 pt-1"
207207
}`}
208208
>
209+
<span
210+
aria-hidden
211+
className="ec-tab-pill"
212+
data-variant={nativeAndroid ? "android" : "web"}
213+
/>
209214
{APP_NAV_LINKS.map((link) => {
210215
const isActive = link.matches
211216
? link.matches(pathname)
212217
: pathname === link.href;
213218
return (
214-
<li key={link.href} className="min-w-0 flex-1">
219+
<li key={link.href} className="relative z-[1] min-w-0 flex-1">
215220
<Link
216221
href={link.href}
217222
prefetch
218223
transitionTypes={isActive ? undefined : ["nav-lateral"]}
219224
onClickCapture={(event) => setNavTransitionOrigin(event.currentTarget)}
220225
onClick={(event) => handleTabClick(event, link.href, isActive)}
221-
className={`flex flex-col items-center rounded-xl font-semibold leading-tight tracking-tight transition-[background-color,color,transform] active:scale-[0.98] ${
226+
className={`flex flex-col items-center rounded-xl font-semibold leading-tight tracking-tight transition-[color,transform] active:scale-[0.98] ${
222227
nativeAndroid
223228
? `gap-1 px-1 py-1 text-[11px] ${
224229
isActive
@@ -234,24 +239,23 @@ export default function MobileTabBar({ toolsSheetOpen = false }: Props) {
234239
aria-current={isActive ? "page" : undefined}
235240
>
236241
<span
237-
className={`flex items-center justify-center transition-colors ${
242+
data-variant={nativeAndroid ? "android" : "web"}
243+
className={`relative z-[1] flex items-center justify-center ${
244+
isActive ? "ec-tab-anchor-active" : ""
245+
} ${
238246
nativeAndroid
239-
? `h-8 min-w-[3.5rem] rounded-full px-3 ${
240-
isActive
241-
? "bg-[#D6EEF5] dark:bg-[#113446]"
242-
: "bg-transparent"
243-
}`
244-
: `h-10 w-10 rounded-xl ${isActive ? "bg-black/[0.06] dark:bg-white/[0.07]" : ""}`
247+
? "h-8 min-w-[3.5rem] rounded-full px-3"
248+
: "h-10 w-10 rounded-xl"
245249
}`}
246250
>
247251
<Image
248252
src={link.svgSource}
249253
alt=""
250254
width={22}
251255
height={22}
252-
className={`shrink-0 dark:invert-[.835] ${
256+
className={`shrink-0 transition-transform duration-300 ease-[cubic-bezier(0.32,0.72,0,1)] dark:invert-[.835] ${
253257
nativeAndroid ? "h-6 w-6" : "h-[22px] w-[22px]"
254-
} ${isActive ? "opacity-100" : "opacity-85"}`}
258+
} ${isActive ? "scale-[1.08] opacity-100" : "opacity-85"}`}
255259
/>
256260
</span>
257261
<span className={`max-w-full truncate ${nativeAndroid ? "text-[12px]" : ""}`}>

app/components/nav-bar.tsx

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -442,10 +442,11 @@ const NavBar: React.FC<Props> = ({
442442
<div className="hidden min-h-[2.5rem] lg:block" aria-hidden />
443443
</div>
444444

445-
<div className={`order-2 grid ${toolGridClassName} gap-3 border-b border-black/10 px-5 py-4 dark:border-white/10 lg:order-3 lg:mt-auto lg:flex lg:w-full lg:flex-col lg:items-stretch lg:gap-0 lg:border-b-0 lg:px-1 lg:py-2`}>
445+
<div className={`ec-tools-grid order-2 grid ${toolGridClassName} gap-3 border-b border-black/10 px-5 py-4 dark:border-white/10 lg:order-3 lg:mt-auto lg:flex lg:w-full lg:flex-col lg:items-stretch lg:gap-0 lg:border-b-0 lg:px-1 lg:py-2`}>
446+
<span aria-hidden className="ec-tool-pill" />
446447
{commandPaletteEnabled ? (
447-
<div className="group/action hidden flex-col items-center gap-2 md:flex lg:m-2 lg:min-h-8 lg:flex-row lg:gap-0 lg:px-2 lg:py-1">
448-
<div className="flex min-h-10 items-center justify-center lg:min-h-0 lg:w-full">
448+
<div className="ec-tool-action group/action relative z-[1] hidden flex-col items-center gap-2 md:flex lg:m-2 lg:min-h-8 lg:flex-row lg:gap-0 lg:px-2 lg:py-1">
449+
<div className="ec-tool-action-target flex min-h-10 items-center justify-center lg:min-h-0 lg:w-full">
449450
<button
450451
type="button"
451452
title="Search"
@@ -464,8 +465,8 @@ const NavBar: React.FC<Props> = ({
464465
) : null}
465466

466467
{voiceAgentEnabled ? (
467-
<div className="group/action flex flex-col items-center gap-2 lg:m-2 lg:min-h-8 lg:flex-row lg:gap-0 lg:px-2 lg:py-1">
468-
<div className="flex min-h-10 items-center justify-center lg:min-h-0 lg:w-full">
468+
<div className="ec-tool-action group/action relative z-[1] flex flex-col items-center gap-2 lg:m-2 lg:min-h-8 lg:flex-row lg:gap-0 lg:px-2 lg:py-1">
469+
<div className="ec-tool-action-target flex min-h-10 items-center justify-center lg:min-h-0 lg:w-full">
469470
<div className="flex lg:w-full">
470471
{voiceRuntimeRequested ? (
471472
<VoiceAgentEntry
@@ -500,7 +501,7 @@ const NavBar: React.FC<Props> = ({
500501
</div>
501502
) : null}
502503

503-
<div className="group/action flex flex-col items-center gap-2 lg:m-2 lg:min-h-8 lg:flex-row lg:gap-0 lg:px-2 lg:py-1">
504+
<div className="ec-tool-action group/action relative z-[1] flex flex-col items-center gap-2 lg:m-2 lg:min-h-8 lg:flex-row lg:gap-0 lg:px-2 lg:py-1">
504505
<div className="flex min-h-10 items-center justify-center lg:min-h-0 lg:w-full">
505506
<ThemeToggleSwitch
506507
className={navActionButtonClassName}
@@ -514,8 +515,8 @@ const NavBar: React.FC<Props> = ({
514515
</span>
515516
</div>
516517

517-
<div className="group/action flex flex-col items-center gap-2 lg:m-2 lg:min-h-8 lg:flex-row lg:gap-0 lg:px-2 lg:py-1">
518-
<div className="relative z-10 flex min-h-10 items-center justify-center lg:min-h-0 lg:w-full">
518+
<div className="ec-tool-action group/action relative z-[1] flex flex-col items-center gap-2 lg:m-2 lg:min-h-8 lg:flex-row lg:gap-0 lg:px-2 lg:py-1">
519+
<div className="ec-tool-action-target relative z-10 flex min-h-10 items-center justify-center lg:min-h-0 lg:w-full">
519520
{isAuthed ? (
520521
<div className="lg:w-full" ref={profileRef}>
521522
<button
@@ -564,7 +565,8 @@ const NavBar: React.FC<Props> = ({
564565
</div>
565566
</div>
566567

567-
<div className="order-3 hidden min-h-0 flex-1 flex-col items-stretch overflow-y-auto px-2 py-2 lg:order-2 lg:flex lg:justify-center lg:overflow-visible lg:px-1 lg:py-2">
568+
<div className="ec-nav-rail order-3 hidden min-h-0 flex-1 flex-col items-stretch overflow-y-auto px-2 py-2 lg:order-2 lg:flex lg:justify-center lg:overflow-visible lg:px-1 lg:py-2">
569+
<span aria-hidden className="ec-nav-pill" />
568570
{APP_NAV_LINKS.map((link) => {
569571
const isActive = link.matches
570572
? link.matches(pathname)
@@ -576,7 +578,7 @@ const NavBar: React.FC<Props> = ({
576578
prefetch
577579
transitionTypes={isActive ? undefined : ["nav-lateral"]}
578580
onClick={(event) => handleNavLinkClick(event, link.href, isActive)}
579-
className={`group/action m-2 flex min-h-8 items-center rounded-md px-2 py-1 ${isActive ? "bg-[#ffffff]/20" : ""}`}
581+
className={`group/action relative z-[1] m-2 flex min-h-8 items-center rounded-md px-2 py-1 ${isActive ? "ec-nav-anchor-active" : ""}`}
580582
>
581583
<div className="flex items-center cursor-pointer">
582584
<div className="flex-shrink-0 flex items-center justify-center">

0 commit comments

Comments
 (0)