@erclx/canon 4.0.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/agents/commands.md
CHANGED
|
@@ -22,7 +22,7 @@ Full help: `canon <command> --help`. Behavior notes for the install and sync ver
|
|
|
22
22
|
| `canon indexes regen` | Regenerate `index.md` files from sibling frontmatter |
|
|
23
23
|
| `canon docs [topic]` | Emit toolkit reference docs (`list`, or a topic by name) |
|
|
24
24
|
| `canon design render` | Render `.claude/DESIGN.md` tokens to HTML and CSS |
|
|
25
|
-
| `canon slides render` | Render a `.claude/SLIDES.md` source into a PowerPoint deck
|
|
25
|
+
| `canon slides render` | Render a `.claude/SLIDES.md` source into a PowerPoint deck, reporting any unrecognized layout name on stderr |
|
|
26
26
|
| `canon slides list` | List the available slide layouts (`--json` for the catalog) |
|
|
27
27
|
| `canon feedback` | Write toolkit feedback from stdin to `.claude/review/feedback/`, or open a GitHub issue with `--github` |
|
|
28
28
|
| `canon transcripts <url>` | Fetch a YouTube transcript with metadata frontmatter (needs `yt-dlp`) |
|
package/package.json
CHANGED
package/src/commands/slides.ts
CHANGED
|
@@ -48,6 +48,13 @@ export function register(program: Command): void {
|
|
|
48
48
|
process.stderr.write(
|
|
49
49
|
`${GREY}│${NC} ${GREEN}✓${NC} ${result.slideCount} slides\n${GREY}│${NC} ${GREEN}✓${NC} ${result.pptxPath}\n`,
|
|
50
50
|
)
|
|
51
|
+
const validNames = LAYOUTS.map((layout) => layout.name).join(', ')
|
|
52
|
+
for (const { value, slideNumbers } of result.unrecognizedLayouts) {
|
|
53
|
+
const noun = slideNumbers.length === 1 ? 'slide' : 'slides'
|
|
54
|
+
process.stderr.write(
|
|
55
|
+
`${GREY}│${NC} ${RED}✗${NC} unrecognized layout "${value}" on ${noun} ${slideNumbers.join(', ')}. Valid layouts: ${validNames}\n`,
|
|
56
|
+
)
|
|
57
|
+
}
|
|
51
58
|
if (result.mirrorPath) {
|
|
52
59
|
process.stderr.write(
|
|
53
60
|
`${GREY}│${NC} ${GREEN}✓${NC} mirrored to ${result.mirrorPath}\n`,
|
package/src/slides/layouts.ts
CHANGED
|
@@ -32,6 +32,12 @@ export const LAYOUTS: LayoutInfo[] = [
|
|
|
32
32
|
{ name: 'quote', description: 'Large pull quote with attribution' },
|
|
33
33
|
]
|
|
34
34
|
|
|
35
|
+
const LAYOUT_NAMES = new Set(LAYOUTS.map((layout) => layout.name))
|
|
36
|
+
|
|
37
|
+
export function isKnownLayout(name: string): boolean {
|
|
38
|
+
return LAYOUT_NAMES.has(name)
|
|
39
|
+
}
|
|
40
|
+
|
|
35
41
|
const W = 13.333
|
|
36
42
|
const H = 7.5
|
|
37
43
|
const MX = 0.7
|
package/src/slides/render.ts
CHANGED
|
@@ -4,16 +4,23 @@ import PptxGenJS from 'pptxgenjs'
|
|
|
4
4
|
import {
|
|
5
5
|
addFooter,
|
|
6
6
|
type DeckNav,
|
|
7
|
+
isKnownLayout,
|
|
7
8
|
renderDeckSlide,
|
|
8
9
|
renderToc,
|
|
9
10
|
} from '@/slides/layouts'
|
|
10
11
|
import { type Deck, parseSlidesDoc } from '@/slides/parse'
|
|
11
12
|
import { buildTheme, type Variant } from '@/slides/styles'
|
|
12
13
|
|
|
14
|
+
export interface UnrecognizedLayout {
|
|
15
|
+
value: string
|
|
16
|
+
slideNumbers: number[]
|
|
17
|
+
}
|
|
18
|
+
|
|
13
19
|
export interface RenderResult {
|
|
14
20
|
pptxPath: string
|
|
15
21
|
mirrorPath?: string
|
|
16
22
|
slideCount: number
|
|
23
|
+
unrecognizedLayouts: UnrecognizedLayout[]
|
|
17
24
|
}
|
|
18
25
|
|
|
19
26
|
export interface RenderOptions {
|
|
@@ -35,16 +42,22 @@ export async function renderSlidesDoc(
|
|
|
35
42
|
if (deck.meta.title) pptx.title = deck.meta.title
|
|
36
43
|
|
|
37
44
|
const nav = buildNav(deck)
|
|
38
|
-
|
|
45
|
+
const unrecognizedSlideNumbers = new Map<string, number[]>()
|
|
46
|
+
deck.slides.forEach((slide, index) => {
|
|
39
47
|
const target = pptx.addSlide()
|
|
40
48
|
target.background = { color: theme.background }
|
|
49
|
+
if (!isKnownLayout(slide.layout)) {
|
|
50
|
+
const slideNumbers = unrecognizedSlideNumbers.get(slide.layout) ?? []
|
|
51
|
+
slideNumbers.push(index + 1)
|
|
52
|
+
unrecognizedSlideNumbers.set(slide.layout, slideNumbers)
|
|
53
|
+
}
|
|
41
54
|
if (slide.layout === 'toc') {
|
|
42
55
|
renderToc(target, slide, theme, nav)
|
|
43
56
|
} else {
|
|
44
57
|
renderDeckSlide(target, slide, theme)
|
|
45
58
|
}
|
|
46
59
|
addFooter(target, slide, theme, nav)
|
|
47
|
-
}
|
|
60
|
+
})
|
|
48
61
|
|
|
49
62
|
mkdirSync(outDir, { recursive: true })
|
|
50
63
|
const fileName = outputName(sourcePath)
|
|
@@ -54,7 +67,16 @@ export async function renderSlidesDoc(
|
|
|
54
67
|
const mirrorPath = options.mirror
|
|
55
68
|
? mirrorDeck(pptxPath, options.mirror, fileName)
|
|
56
69
|
: undefined
|
|
57
|
-
|
|
70
|
+
const unrecognizedLayouts = Array.from(
|
|
71
|
+
unrecognizedSlideNumbers,
|
|
72
|
+
([value, slideNumbers]) => ({ value, slideNumbers }),
|
|
73
|
+
)
|
|
74
|
+
return {
|
|
75
|
+
pptxPath,
|
|
76
|
+
mirrorPath,
|
|
77
|
+
slideCount: deck.slides.length,
|
|
78
|
+
unrecognizedLayouts,
|
|
79
|
+
}
|
|
58
80
|
}
|
|
59
81
|
|
|
60
82
|
function mirrorDeck(
|