feat: preview templates, thumbnail features, 2 new org templates

This commit is contained in:
Rotimi Best
2026-05-23 12:24:57 +01:00
parent 4fdd4115b9
commit 78ab13f54b
106 changed files with 8320 additions and 2040 deletions
@@ -18,7 +18,13 @@
import { MagicCard } from '@cio/ui/custom/animation/magic-card';
import { getLectureNo } from '$features/course/utils/functions';
import { normalizeLandingPageSettings } from '$features/org/utils/landing-page';
import {
importThemeNavHero,
normalizeLandingPageSettings,
themeHeaderShellClass,
themeStyle,
themeRendersNavInsideHero
} from '$features/org/utils/landing-page';
import { currentOrg } from '$lib/utils/store/org';
import { basePath } from '$lib/utils/store/app';
import { user } from '$lib/utils/store/user';
@@ -57,11 +63,9 @@
const landingSettings = $derived(normalizeLandingPageSettings($currentOrg.landingpage));
const heroShellClass = $derived(
landingSettings.theme === 'classic'
? 'ui:w-full ui:bg-muted/10 ui:text-foreground ui:font-sans'
: 'ui:w-full ui:bg-background ui:text-foreground ui:font-sans'
);
const heroShellClass = $derived(`ui:w-full ${themeHeaderShellClass(landingSettings.theme)}`);
const heroShellStyle = $derived(themeStyle(landingSettings.theme));
const navInsideHero = $derived(themeRendersNavInsideHero(landingSettings.theme));
const orgNameForNav = $derived($currentOrg.name || get(courseData, 'org.name', '') || 'ClassroomIO');
const logoUrlForNav = $derived($currentOrg.avatarUrl || undefined);
@@ -115,21 +119,10 @@
const theme = landingSettings.theme;
let cancelled = false;
void Promise.all([
theme === 'bold'
? import('@cio/ui/custom/org-landing-page/bold/nav.svelte')
: theme === 'classic'
? import('@cio/ui/custom/org-landing-page/classic/nav.svelte')
: import('@cio/ui/custom/org-landing-page/minimal/nav.svelte'),
theme === 'bold'
? import('@cio/ui/custom/org-landing-page/bold/hero.svelte')
: theme === 'classic'
? import('@cio/ui/custom/org-landing-page/classic/hero.svelte')
: import('@cio/ui/custom/org-landing-page/minimal/hero.svelte')
]).then(([navMod, heroMod]) => {
void importThemeNavHero(theme).then(({ NavComponent: nav, HeroComponent: hero }) => {
if (!cancelled) {
NavComponent = navMod.default;
HeroComponent = heroMod.default;
NavComponent = nav;
HeroComponent = hero;
}
});
@@ -202,10 +195,10 @@
<div class="flex w-full flex-col items-center bg-white dark:bg-black">
{#if showMarketingHero}
<div class={heroShellClass}>
<div class={heroShellClass} style={heroShellStyle}>
{#if NavComponent && HeroComponent}
{#if landingSettings.theme === 'minimal'}
<HeroComponent hero={courseHero}>
{#if navInsideHero}
<HeroComponent hero={courseHero} orgName={orgNameForNav}>
{#snippet navigation()}
<NavComponent
orgName={orgNameForNav}
@@ -222,7 +215,7 @@
navItems={landingSettings.navItems}
{authAction}
/>
<HeroComponent hero={courseHero} />
<HeroComponent hero={courseHero} orgName={orgNameForNav} />
{/if}
{/if}
@@ -11,6 +11,7 @@
import { currentOrg } from '$lib/utils/store/org';
import { setupProgressApi } from '$features/setup/api/setup-progress.svelte';
import AppSetup from './app-setup.svelte';
import VisitOrgSiteBtn from '$features/ui/visit-org-site-btn.svelte';
const siteName = $derived($currentOrg.siteName);
@@ -36,6 +37,8 @@
<span class="grow"></span>
<AppSetup />
<VisitOrgSiteBtn variant="outline" labelKey="dashboard.open_academy" />
<Search />
<Popover.Root>
@@ -1,13 +1,6 @@
import { QUESTION_TYPE_KEY, QUESTION_TYPE_REGISTRY, type QuestionTypeKey } from '@cio/question-types';
/** Question types that require a paid plan. On free plan, these show a premium icon and open upgrade modal on click. */
export const PREMIUM_QUESTION_TYPE_KEYS = new Set<QuestionTypeKey>([
QUESTION_TYPE_KEY.FILE_UPLOAD,
QUESTION_TYPE_KEY.ORDERING,
QUESTION_TYPE_KEY.LINK,
QUESTION_TYPE_KEY.STAR,
QUESTION_TYPE_KEY.VIDEO_RECORDING
]);
export { PREMIUM_QUESTION_TYPE_KEYS } from '@cio/question-types';
const QUESTION_TYPE_LABEL_KEYS: Partial<Record<QuestionTypeKey, string>> = {
[QUESTION_TYPE_KEY.RADIO]: 'course.navItem.lessons.exercises.all_exercises.edit_mode.question_types.single',
@@ -1,7 +1,8 @@
<script lang="ts">
import { browser } from '$app/environment';
import { Button, type ButtonVariant } from '@cio/ui/base/button';
import ArrowUpRightIcon from '@lucide/svelte/icons/arrow-up-right';
import SquareArrowOutUpRight from '@lucide/svelte/icons/square-arrow-out-up-right';
import { TENANT_ROOT_DOMAIN } from '@cio/utils/constants';
import { currentOrg, currentOrgDomain } from '$lib/utils/store/org';
import { isMobile } from '$lib/utils/store/useMobile';
@@ -45,13 +46,15 @@
});
</script>
<Button {href} target="_blank" {variant} class={`ml-2 ${className}`.trim()}>
<Button {href} target="_blank" {variant} class={`&_span:hidden! md:&_span:block ml-2 ${className}`.trim()}>
{#if !$isMobile}
{#if isLMS}
{$t('dashboard.visit_site')}
{:else}
{$t(labelKey)}
{/if}
<span>
{#if isLMS}
{$t('dashboard.visit_site')}
{:else}
{$t(labelKey)}
{/if}
</span>
{/if}
<ArrowUpRightIcon class="custom" />
<SquareArrowOutUpRight class="custom" />
</Button>