fix(dashboard): make course list rows real links like cards (#743)
Wrap list-view course rows in anchor tags so users can open courses in new tabs via right-click or modifier-click, matching the grid card layout. Falls back to button behavior when a custom explore click handler is set. Co-authored-by: Rotimi Best <rotimi-best@users.noreply.github.com>
This commit is contained in:
co-authored by
Rotimi Best
parent
7605395f44
commit
7eaff0040c
@@ -5,6 +5,7 @@
|
|||||||
import { Badge } from '@cio/ui/base/badge';
|
import { Badge } from '@cio/ui/base/badge';
|
||||||
import { Button } from '@cio/ui/base/button';
|
import { Button } from '@cio/ui/base/button';
|
||||||
import EllipsisVerticalIcon from '@lucide/svelte/icons/ellipsis-vertical';
|
import EllipsisVerticalIcon from '@lucide/svelte/icons/ellipsis-vertical';
|
||||||
|
import { cn } from '@cio/ui/tools';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { resolve } from '$app/paths';
|
import { resolve } from '$app/paths';
|
||||||
import { ContentType } from '@cio/utils/constants/content';
|
import { ContentType } from '@cio/utils/constants/content';
|
||||||
@@ -114,31 +115,55 @@
|
|||||||
return `Updated ${d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })}`;
|
return `Updated ${d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })}`;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const courseUrl = $derived.by(() => {
|
||||||
|
if (isExplore && onExploreClick) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isExplore) {
|
||||||
|
if (!slug.trim()) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolve(`/course/${slug}`, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLMS) {
|
||||||
|
return resolve(`/courses/${id}/lessons?next=true`, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolve(`/courses/${id}`, {});
|
||||||
|
});
|
||||||
|
|
||||||
function handleRowClick() {
|
function handleRowClick() {
|
||||||
if (isExplore && onExploreClick) {
|
if (isExplore && onExploreClick) {
|
||||||
onExploreClick();
|
onExploreClick();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isExplore) {
|
|
||||||
goto(resolve(`/course/${slug}`, {}));
|
if (!courseUrl) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isLMS) {
|
|
||||||
goto(resolve(`/courses/${id}/lessons?next=true`, {}));
|
goto(courseUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleRowKeydown(event: KeyboardEvent) {
|
||||||
|
if (event.key !== 'Enter' && event.key !== ' ') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
goto(resolve(`/courses/${id}`, {}));
|
|
||||||
|
event.preventDefault();
|
||||||
|
handleRowClick();
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopRowNavigation(event: MouseEvent) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ResourceListRow.Root
|
{#snippet rowContent()}
|
||||||
variant="default"
|
|
||||||
size="sm"
|
|
||||||
align="start"
|
|
||||||
class="cursor-pointer py-4!"
|
|
||||||
onclick={handleRowClick}
|
|
||||||
role="row"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
class="grid w-full grid-cols-1 items-start gap-x-3 gap-y-2 @3xl:grid-cols-[var(--row-cols)]"
|
class="grid w-full grid-cols-1 items-start gap-x-3 gap-y-2 @3xl:grid-cols-[var(--row-cols)]"
|
||||||
style="--row-cols: {gridTemplateColumns}"
|
style="--row-cols: {gridTemplateColumns}"
|
||||||
@@ -265,8 +290,8 @@
|
|||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
onclick={(e) => {
|
onclick={(event) => {
|
||||||
e.stopPropagation();
|
stopRowNavigation(event);
|
||||||
onExploreClick?.();
|
onExploreClick?.();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -282,7 +307,7 @@
|
|||||||
size="icon"
|
size="icon"
|
||||||
class="size-8"
|
class="size-8"
|
||||||
aria-label={$t('courses.course_card.actions_menu_aria')}
|
aria-label={$t('courses.course_card.actions_menu_aria')}
|
||||||
onclick={(e) => e.stopPropagation()}
|
onclick={stopRowNavigation}
|
||||||
>
|
>
|
||||||
<EllipsisVerticalIcon class="size-4" />
|
<EllipsisVerticalIcon class="size-4" />
|
||||||
</Button>
|
</Button>
|
||||||
@@ -317,4 +342,25 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
{/snippet}
|
||||||
|
|
||||||
|
<ResourceListRow.Root variant="default" size="sm" align="start" class="cursor-pointer py-4!">
|
||||||
|
{#snippet child({ props })}
|
||||||
|
{#if courseUrl}
|
||||||
|
<a href={courseUrl} {...props} class={cn('block', props.class as string)}>
|
||||||
|
{@render rowContent()}
|
||||||
|
</a>
|
||||||
|
{:else}
|
||||||
|
<div
|
||||||
|
{...props}
|
||||||
|
class={cn('block', props.class as string)}
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
onclick={handleRowClick}
|
||||||
|
onkeydown={handleRowKeydown}
|
||||||
|
>
|
||||||
|
{@render rowContent()}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/snippet}
|
||||||
</ResourceListRow.Root>
|
</ResourceListRow.Root>
|
||||||
|
|||||||
Reference in New Issue
Block a user