feat: HLS streaming, transcripts, agent course generation & landing-page course previews (#663)
New features: - HLS video encoding/streaming (hls routes, hls-encoder) and a media transcripts pipeline (transcripts route + media-transcript queries) - AI assistant chat vs. run model: agent-course-generation worker/queue, run-monitor pane, chat-changes card, content ask-ai bar - Per-theme course-page previews across org landing-page themes (bold, classic, corporate, editorial, etc.) with a shared course token/component set - View-as-student mode and login-link / link-invite invite flows Refactor: - Extract packages/core consolidating config (env, storage, dashboard-url), services and utils previously duplicated under apps/api/src/config - Remove legacy agent service modules (chat-tools, chat-context, context-window, document, fetch-url, lesson-content) - Relax Cross-Origin-Resource-Policy to allow cross-origin media embedding - Add format script to tenant-router so turbo run format covers it
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
import type { CoursePricing, CourseLandingPageProps, CourseLandingPageLabels } from './types';
|
||||
|
||||
export function alignHeroCtaWithPricing(
|
||||
hero: CourseLandingPageProps['hero'],
|
||||
pricing: CoursePricing
|
||||
): CourseLandingPageProps['hero'] {
|
||||
return {
|
||||
...hero,
|
||||
primaryAction: {
|
||||
label: pricing.ctaLabel,
|
||||
href: pricing.ctaHref ?? '#pricing',
|
||||
disabled: hero.primaryAction.disabled
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export interface SectionNavItem {
|
||||
id: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export function buildCourseSectionNavItems(
|
||||
props: Pick<CourseLandingPageProps, 'info' | 'curriculum' | 'chips' | 'instructor' | 'reviews'>,
|
||||
labels?: CourseLandingPageLabels
|
||||
): SectionNavItem[] {
|
||||
const items: SectionNavItem[] = [];
|
||||
const { info, curriculum, chips, reviews } = props;
|
||||
|
||||
const hasInfo = Boolean(info.requirements || info.description || info.goals || info.certificateUrl);
|
||||
if (hasInfo) {
|
||||
items.push({ id: 'course-info', label: labels?.navAboutLabel ?? 'About' });
|
||||
}
|
||||
|
||||
if (curriculum.sections.length > 0) {
|
||||
items.push({ id: 'curriculum', label: labels?.navCurriculumLabel ?? 'Modules' });
|
||||
}
|
||||
|
||||
const hasChips = Boolean((chips?.skills?.length ?? 0) > 0 || (chips?.tools?.length ?? 0) > 0);
|
||||
if (hasChips) {
|
||||
items.push({ id: 'course-chips', label: labels?.navSkillsLabel ?? 'Skills' });
|
||||
}
|
||||
|
||||
items.push({ id: 'instructor', label: labels?.navInstructorLabel ?? 'Instructor' });
|
||||
|
||||
if (reviews.items.length > 0) {
|
||||
items.push({ id: 'reviews', label: labels?.navReviewsLabel ?? 'Reviews' });
|
||||
}
|
||||
|
||||
items.push({ id: 'pricing', label: labels?.navPricingLabel ?? 'Pricing' });
|
||||
|
||||
return items;
|
||||
}
|
||||
Reference in New Issue
Block a user