feat(slides): Slidev deck for the Kotlin Nexus workshop - #11
Open
nadvolod wants to merge 3 commits into
Open
Conversation
Slidev 52. slides.md holds headmatter plus src: imports only; each segment is its own file so one can be rewritten or cut without touching its neighbours. The theme is vendored at slides/theme rather than installed as a dependency. `pnpm add github:temporalio/slidev-theme-temporal` installs fine and then fails the build: pnpm names the store directory for a git dep with a #<commit> suffix, and Vite's CSS url() resolver treats # as a fragment separator, so the theme's five background images resolve to a truncated path and error with ENOENT. Vendoring is Option 2 in the theme's own README and what the Replay workshop deck does. Also pins prettier-plugin-slidev. Without it a format-on-save pass rewrites every per-slide frontmatter block: in Markdown a line of text followed by --- is a setext H2, which is exactly what Slidev frontmatter looks like, so `layout: default` between two --- lines becomes the heading "## layout: default" and the slide loses its layout entirely. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A project-local layout rather than an edit to the vendored theme, so pulling a newer theme cannot clobber it. Code across the top, definition across the full width below. The definition takes only the height it needs and the code claims the slack, so a one-line definition hands its space to the code instead of reserving an empty third of the slide. Both panes then measure themselves after render and step their font size down until the content fits, watching for resizes and content changes, so no slide scrolls or clips. Three CSS traps are documented in comments, each found by measuring the live DOM rather than reasoning: - `title` is reserved by Slidev for slide metadata and never reaches a layout as a prop, so the heading prop is `heading`. - minmax(0, auto) collapses the prose track: with a zero floor its min-content contribution is zero and the greedy 1fr code row eats the space. - A percentage max-height on a grid item resolves against its own track, so capping an auto-sized track at 40% yields 40% of its own content. fit-content() resolves against the grid container, which is what we want. scripts/probe-fit.mjs drives the dev server with Playwright and reports the settled font size and overflow for every code slide. It caught two clipping bugs that eyeballing missed, and it walks the deck rather than hardcoding slide numbers so it survives slides being added or removed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three opener slides, a section divider, then one definition-plus-code slide per Nexus concept: Service, Operation, Endpoint, Caller, Handler, sync vs async. Every concept is taught with real Kotlin from the solution tree before anyone opens the editor, which lets segments 2 through 4 shrink to recall rather than first exposure. Registry is deliberately absent from the concept block. The lab names it once in challenge 2's notes and no challenge ever touches it. The architecture diagram on the before-and-after slide comes from temporalio/temporal-learning -> docs/tutorials/nexus/ui/architecture-overview.svg, rendered in the Overview of the Java sync tutorial. It labels exactly the pieces this workshop builds. Bound as :src rather than src: Vite statically analyses a literal src in the compiled Vue template and tries to resolve it as a module, which fails for a public/ path inside Slidev's virtual modules. Presenter notes on each slide carry the source file:line for the snippet and, where a definition is still unwritten, what it needs to establish. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a Slidev-based slide deck for the Kotlin Nexus workshop and vendors an expanded slidev-theme-temporal theme (layouts/components/styles + example decks) to support the workshop’s design and pacing goals.
Changes:
- Introduces a full Slidev deck under
kotlin/slides/, segmented into workshop sections and backed by a Playwright-based “fit probe” script for code-slide overflow checks. - Vendors and extends the Temporal Slidev theme under
kotlin/slides/theme/(palette + Shiki + Mermaid + 29 layouts + reusable components + example decks + scaffolding script). - Adds a project-local
code-stacklayout to support “code + definition” slides with auto-fitting panes.
Reviewed changes
Copilot reviewed 70 out of 77 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| kotlin/slides/theme/styles/layout.css | Global palette, typography, layout primitives, and background helpers for the vendored theme |
| kotlin/slides/theme/styles/index.ts | Theme styles entrypoint wiring layout + code CSS |
| kotlin/slides/theme/styles/code.css | Code block typography and panel styling |
| kotlin/slides/theme/spec.md | Theme parity/audit spec vs 2026 PPT template and build plan/reference |
| kotlin/slides/theme/setup/temporal.json | Shiki token theme JSON for “temporal” |
| kotlin/slides/theme/setup/shiki.ts | Registers Shiki theme for Slidev |
| kotlin/slides/theme/setup/mermaid.ts | Mermaid themeVariables aligned with Temporal palette |
| kotlin/slides/theme/scripts/new-deck.sh | Script to scaffold a new deck wired to the vendored theme |
| kotlin/slides/theme/README.md | Theme documentation (usage, layouts, examples, brand rules) |
| kotlin/slides/theme/package.json | Theme package metadata + Slidev defaults |
| kotlin/slides/theme/LICENSE | Theme license |
| kotlin/slides/theme/layouts/two-cols.vue | Two-column layout with footer + grid background |
| kotlin/slides/theme/layouts/two-cols-header.vue | Two-column layout with shared title + optional eyebrows |
| kotlin/slides/theme/layouts/toc.vue | Agenda/TOC layout using configurable TOC component |
| kotlin/slides/theme/layouts/timeline.vue | Timeline layout using TimelineRail component |
| kotlin/slides/theme/layouts/success-story.vue | Customer success story layout with logo slot + challenges/solution columns |
| kotlin/slides/theme/layouts/subsection.vue | Sub-section divider layout with eyebrow label |
| kotlin/slides/theme/layouts/section.vue | Section divider layout |
| kotlin/slides/theme/layouts/release-stages.vue | 3-stage release explainer layout |
| kotlin/slides/theme/layouts/quote.vue | Quote card layout with avatar + attribution |
| kotlin/slides/theme/layouts/qa.vue | Minimal Q&A divider layout |
| kotlin/slides/theme/layouts/profile.vue | Profile card layout with avatar + attribution block |
| kotlin/slides/theme/layouts/model-diagram.vue | Model diagram layout with asset-pending placeholder slot |
| kotlin/slides/theme/layouts/image-right.vue | Text-left, image-right layout |
| kotlin/slides/theme/layouts/image-left.vue | Image-left, text-right layout |
| kotlin/slides/theme/layouts/feature-grid.vue | N-column feature grid layout driven by items prop |
| kotlin/slides/theme/layouts/feature-card.vue | Feature card layout with release-stage chip + 3 body slots |
| kotlin/slides/theme/layouts/eyebrow-hero.vue | Eyebrow + large heading hero layout |
| kotlin/slides/theme/layouts/exercise.vue | Workshop exercise timer layout |
| kotlin/slides/theme/layouts/end.vue | Closing slide layout with logo + brand rule enforcement |
| kotlin/slides/theme/layouts/default.vue | Default content layout with footer pinned via flex |
| kotlin/slides/theme/layouts/cta-icons.vue | CTA icon grid layout (asset-pending icons) |
| kotlin/slides/theme/layouts/cta-banner.vue | Single CTA banner layout |
| kotlin/slides/theme/layouts/cover.vue | Cover layout using BackgroundLayer variants + logo brand rule |
| kotlin/slides/theme/layouts/comparison.vue | Two-card comparison layout with checkmark feature lists |
| kotlin/slides/theme/layouts/code-explain.vue | Code + prose side-by-side layout |
| kotlin/slides/theme/layouts/checklist.vue | Checklist grid layout with checkmarks |
| kotlin/slides/theme/layouts/chart.vue | Chart slot + caption layout |
| kotlin/slides/theme/layouts/big-stat.vue | Big stat hero layout with optional ribbon slot |
| kotlin/slides/theme/layouts/architecture.vue | Architecture diagram layout with before/after variant + placeholder slot |
| kotlin/slides/theme/justfile | Dev/build/export recipes for running theme example decks |
| kotlin/slides/theme/example/workshop.md | Example workshop deck demonstrating TOC + exercise layout |
| kotlin/slides/theme/example/slides.md | Full reference deck exercising every layout |
| kotlin/slides/theme/example/README.md | Documentation for running/maintaining example decks |
| kotlin/slides/theme/example/feature-launch.md | Example mini-deck for feature launches |
| kotlin/slides/theme/example/customer-story.md | Example mini-deck for customer stories |
| kotlin/slides/theme/components/WorkshopToc.vue | Configurable TOC driven by themeConfig.toc |
| kotlin/slides/theme/components/TimelineRail.vue | Timeline rail primitive used by timeline layout |
| kotlin/slides/theme/components/TemporalLogo.vue | Inline SVG Temporal mark with brand rule reminder |
| kotlin/slides/theme/components/TemporalFooter.vue | Footer component (deck title + page indicator) |
| kotlin/slides/theme/components/ReleaseStageChip.vue | Pill chip for release stages |
| kotlin/slides/theme/components/QuoteAttribution.vue | Name + role attribution block |
| kotlin/slides/theme/components/ProfileAvatar.vue | Avatar primitive with placeholder fallback |
| kotlin/slides/theme/components/FeatureBlock.vue | Title/body block primitive |
| kotlin/slides/theme/components/Checkmark.vue | Inline SVG checkmark primitive |
| kotlin/slides/theme/components/BackgroundLayer.vue | Background variant → CSS class mapping wrapper |
| kotlin/slides/theme/CHANGELOG.md | Theme changelog describing parity work and breaking changes |
| kotlin/slides/slides.md | Main Slidev deck entry referencing segment files |
| kotlin/slides/segments/06-close.md | Placeholder workshop segment 6 |
| kotlin/slides/segments/05-durability.md | Placeholder workshop segment 5 |
| kotlin/slides/segments/04-caller.md | Placeholder workshop segment 4 |
| kotlin/slides/segments/03-handlers.md | Placeholder workshop segment 3 |
| kotlin/slides/segments/02-contract.md | Placeholder workshop segment 2 |
| kotlin/slides/segments/01-coupling.md | Placeholder workshop segment 1 |
| kotlin/slides/segments/00-open.md | Segment 0 draft (concept slides + diagram slide) |
| kotlin/slides/scripts/probe-fit.mjs | Playwright-driven overflow/font-size probe for code-stack slides |
| kotlin/slides/public/nexus-architecture.svg | Animated architecture diagram asset used in slides |
| kotlin/slides/package.json | Slides project devDependencies + Slidev scripts |
| kotlin/slides/layouts/code-stack.vue | Project-local auto-fitting code+definition layout |
| kotlin/slides/.prettierrc | Prettier config using prettier-plugin-slidev for deck/segments |
| kotlin/slides/.gitignore | Slidev/build output ignore rules |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+119
to
+122
| # Copy the example deck, rewriting its in-repo `theme: ../` reference to | ||
| # the relative path from the new deck back to the theme repo. | ||
| sed "s|^theme: \.\./\$|theme: $rel_theme|" "$src_file" > "$target_abs/slides.md" | ||
| fi |
Comment on lines
+25
to
+30
| <template> | ||
| <div class="temporal-footer"> | ||
| <span>{{ $slidev.themeConfigs?.footer ?? '' }}</span> | ||
| <span class="page">{{ pageLabel }}</span> | ||
| </div> | ||
| </template> |
Comment on lines
+1
to
+38
| <!-- | ||
| ABOUTME: Inline SVG check mark used by checklist and POC layouts. | ||
| ABOUTME: Inherits color via currentColor so any layout can tint it. | ||
|
|
||
| Usage: | ||
| <Checkmark /> | ||
| <Checkmark label="Completed" /> <!-- announces to screen readers --> | ||
| --> | ||
| <script setup lang="ts"> | ||
| defineProps<{ label?: string }>() | ||
| </script> | ||
|
|
||
| <template> | ||
| <svg | ||
| class="checkmark" | ||
| viewBox="0 0 24 24" | ||
| fill="none" | ||
| stroke="currentColor" | ||
| stroke-width="2.5" | ||
| stroke-linecap="round" | ||
| stroke-linejoin="round" | ||
| :aria-hidden="label ? undefined : 'true'" | ||
| :aria-label="label" | ||
| :role="label ? 'img' : undefined" | ||
| > | ||
| <polyline points="4 12 10 18 20 6" /> | ||
| </svg> | ||
| </template> | ||
|
|
||
| <style scoped> | ||
| .checkmark { | ||
| display: inline-block; | ||
| width: 1.1em; | ||
| height: 1.1em; | ||
| color: var(--temporal-green); | ||
| vertical-align: -0.15em; | ||
| } | ||
| </style> |
Comment on lines
+156
to
+173
| ```kotlin {1-8|10|all} | ||
| //The Caller Workflow | ||
| public val NexusCallerWorkflowImpl implements NexusCallerWorkflow { | ||
|
|
||
| private val complianceService: ComplianceNexusService = | ||
| //Nexus stub: The delivery app. Use it to place orders | ||
| Workflow.newNexusServiceStub( | ||
| //The menu tells you what you can order | ||
| ComplianceNexusService::class.java, | ||
| NexusServiceOptions.newBuilder() | ||
| .setOperationOptions(/* scheduleToCloseTimeout */) | ||
| .build(), | ||
| ) | ||
|
|
||
| // ... | ||
| //One of the menu items is checkCompliance() | ||
| val compliance = complianceService.checkCompliance(compReq) | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A Slidev deck for the 90-minute Kotlin Nexus workshop, interleaved with the five
challenges of the
nexus-kotlin-decouple-monolithInstruqt track (merged in #9).Only
kotlin/slides/. The design and plan behind it are #8.Approach
Interleaved, not front-loaded. Slide segments between challenges rather than a
lecture followed by a lab. ~35 speaking minutes against the track's 40-minute lab
block, leaving ~15 for Q&A.
Question-first spine. Each segment opens with the framing question already
written in that challenge's Instruqt
notes, so the notes and the slides reinforcerather than duplicate.
A concept block in Segment 0. One definition-plus-code slide per Nexus concept —
Service, Operation, Endpoint, Caller, Handler, sync vs async — each showing real
Kotlin from the solution tree, taught before anyone opens the editor. Segments 2
through 4 shrink correspondingly: they become recall, not first exposure.
Registry is deliberately absent. The lab names it once in challenge 2's notes and no
challenge ever touches it.
What reviewers may want to weigh in on
The theme is vendored at
kotlin/slides/theme/(~1.1MB, 29 layouts) rather thaninstalled as a dependency, and it is most of this PR's line count.
pnpm add github:temporalio/slidev-theme-temporalinstalls fine and then fails the build:pnpm names the store directory for a git dependency with a
#<commit>suffix, andVite's CSS
url()resolver treats#as a fragment separator, so the theme's fivebackground images resolve to a truncated path. Vendoring is Option 2 in the theme's
own README and what the Replay workshop deck does.
kotlin/slides/layouts/code-stack.vueis a project-local layout so a themeupdate cannot clobber it. Code on top, definition below, both panes auto-shrinking
so no slide scrolls or clips. Three CSS traps are documented in comments there,
each found by measuring the live DOM rather than reasoning about it.
Verification
Drives the dev server with Playwright and reports the settled font size and
overflow for every code slide. It caught two clipping bugs that eyeballing missed.
All six currently report zero overflow.
Still to write
Segments 1 through 6 are placeholder files. Segment 0 is drafted apart from the
sync-vs-async definition.
🤖 Generated with Claude Code