feat: add sequential progression and video watch lesson completion
Gate student content by completion order, track per-video watch progress with seek enforcement, and auto-complete lessons at the configured threshold. Show ring progress in the lesson header, keep watch progress on rewatch, and sync progression locks client-side so the next item unlocks after completion.
This commit is contained in:
@@ -1,4 +1,11 @@
|
||||
import { escapeHtml, getYear, type TemplateRenderer } from './shared';
|
||||
import {
|
||||
escapeHtml,
|
||||
getYear,
|
||||
renderFooterMetaBlock,
|
||||
renderSignatoryBlock,
|
||||
SIGNATURE_IMAGE_STYLES,
|
||||
type TemplateRenderer
|
||||
} from './shared';
|
||||
|
||||
export const renderPoster: TemplateRenderer = ({ design, data }) => {
|
||||
const accent = design.accentColor;
|
||||
@@ -26,18 +33,9 @@ export const renderPoster: TemplateRenderer = ({ design, data }) => {
|
||||
</div>
|
||||
<div class="description">${escapeHtml(description)}</div>
|
||||
<div class="bottom">
|
||||
<div>
|
||||
<div class="k">${escapeHtml(signatoryOne.role)}</div>
|
||||
<div class="v">${escapeHtml(signatoryOne.name)}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="k">${escapeHtml(signatoryTwo.role)}</div>
|
||||
<div class="v">${escapeHtml(signatoryTwo.name)}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="k">Issued</div>
|
||||
<div class="v">${escapeHtml(data.date)}</div>
|
||||
</div>
|
||||
${renderSignatoryBlock(signatoryOne, { nameClass: 'v', roleClass: 'k', roleFirst: true })}
|
||||
${renderSignatoryBlock(signatoryTwo, { nameClass: 'v', roleClass: 'k', roleFirst: true })}
|
||||
${renderFooterMetaBlock('Issued', data.date, { labelClass: 'k', valueClass: 'v' })}
|
||||
</div>
|
||||
</div>
|
||||
<div class="corner-num">${getYear(data.date)}</div>
|
||||
@@ -162,11 +160,20 @@ export const renderPoster: TemplateRenderer = ({ design, data }) => {
|
||||
margin-top: auto;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
align-items: end;
|
||||
gap: 24px;
|
||||
border-top: 2px solid #1a1a1a;
|
||||
padding-top: 18px;
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
}
|
||||
.t-poster .bottom .sig-content,
|
||||
.t-poster .bottom .sig-text {
|
||||
align-items: flex-start;
|
||||
text-align: left;
|
||||
}
|
||||
.t-poster .bottom .sig-img-slot {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.t-poster .bottom .k {
|
||||
font-size: 9px;
|
||||
letter-spacing: 0.2em;
|
||||
@@ -192,6 +199,7 @@ export const renderPoster: TemplateRenderer = ({ design, data }) => {
|
||||
z-index: 3;
|
||||
line-height: 0.8;
|
||||
}
|
||||
${SIGNATURE_IMAGE_STYLES}
|
||||
`;
|
||||
|
||||
return { body, styles };
|
||||
|
||||
Reference in New Issue
Block a user