feat: live class sessions, CE workflow, and docs (#683)
Adds live-class session scheduling on lessons (join link, date/time, timezone) with automatic 24h and 1h reminder emails plus a calendar invite (.ics), a time-change notification with an updated invite, a teacher-authored welcome email and session invite on enrollment, and a "Notify students" quiz nudge. LMS gets an upcoming live-sessions card and Join buttons, plus a reusable live-session card component (3 states) in @cio/ui with a Storybook story. The sidebar content tree now reflects sequential progression locking like the content list, and the course-completion confetti regression is fixed. Org-based emails no longer reference ClassroomIO by name. Docs add live-class, welcome-email, and course-progression guides, expand the certificates guide (design, signatures, corrected labels), move plan-required callouts to the top, flatten how-to-guides to the docs root with redirects, and add screenshots. Includes an add-docs-image skill.
This commit is contained in:
+27
-2
@@ -19,7 +19,7 @@ const DEFAULT_META_TITLE =
|
||||
'ClassroomIO Docs | Customer, Partner, and Employee Education';
|
||||
const DEFAULT_META_DESCRIPTION =
|
||||
'Learn how to create customer academies, partner certification programs, and employee training workflows in ClassroomIO.';
|
||||
const DEFAULT_OG_IMAGE_URL = 'https://brand.cdn.clsrio.com/og/classroomio-opengraph.png';
|
||||
const DEFAULT_OG_IMAGE_URL = 'https://brand.cdn.clsrio.com/og/classroomio-opengraph.jpg';
|
||||
const DEFAULT_OG_IMAGE_ALT = 'ClassroomIO documentation for customer, partner, and employee education';
|
||||
|
||||
export const links: LinksFunction = () => [
|
||||
@@ -60,7 +60,7 @@ export const meta: MetaFunction = () => [
|
||||
},
|
||||
{
|
||||
property: 'og:image:type',
|
||||
content: 'image/png'
|
||||
content: 'image/jpeg'
|
||||
},
|
||||
{
|
||||
property: 'og:image:width',
|
||||
@@ -74,6 +74,31 @@ export const meta: MetaFunction = () => [
|
||||
property: 'og:image:secure_url',
|
||||
content: DEFAULT_OG_IMAGE_URL
|
||||
},
|
||||
// WebP fallback for better compression on supported platforms
|
||||
{
|
||||
property: 'og:image',
|
||||
content: 'https://brand.cdn.clsrio.com/og/classroomio-opengraph.webp'
|
||||
},
|
||||
{
|
||||
property: 'og:image:alt',
|
||||
content: DEFAULT_OG_IMAGE_ALT
|
||||
},
|
||||
{
|
||||
property: 'og:image:type',
|
||||
content: 'image/webp'
|
||||
},
|
||||
{
|
||||
property: 'og:image:width',
|
||||
content: '1920'
|
||||
},
|
||||
{
|
||||
property: 'og:image:height',
|
||||
content: '1080'
|
||||
},
|
||||
{
|
||||
property: 'og:image:secure_url',
|
||||
content: 'https://brand.cdn.clsrio.com/og/classroomio-opengraph.webp'
|
||||
},
|
||||
{
|
||||
name: 'twitter:card',
|
||||
content: 'summary_large_image'
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useMemo } from 'react';
|
||||
|
||||
import type * as PageTree from 'fumadocs-core/page-tree';
|
||||
import browserCollections from 'fumadocs-mdx:collections/browser';
|
||||
import { isRouteErrorResponse, useLoaderData, useRouteError } from 'react-router';
|
||||
import { isRouteErrorResponse, redirect, useLoaderData, useRouteError } from 'react-router';
|
||||
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
|
||||
import { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page';
|
||||
import { HomeLayout } from 'fumadocs-ui/layouts/home';
|
||||
@@ -26,6 +26,13 @@ const clientLoader = browserCollections.docs.createClientLoader({
|
||||
|
||||
export async function loader({ params }: { params: Record<string, string | undefined> }) {
|
||||
const slug = params['*'];
|
||||
|
||||
// How-to guides were flattened to the docs root; permanently redirect the old
|
||||
// `.../how-to-guides/<page>` URLs to `.../<page>`.
|
||||
if (slug && slug.includes('how-to-guides/')) {
|
||||
throw redirect('/' + slug.replace('how-to-guides/', ''), 301);
|
||||
}
|
||||
|
||||
const slugs = slug ? slug.split('/') : ['home'];
|
||||
const { getDocsRouteData } = await import('@/lib/source.server');
|
||||
const routeData = await getDocsRouteData(slugs);
|
||||
|
||||
Reference in New Issue
Block a user