claude-presentation-master 3.8.0 → 3.8.6

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/dist/index.mjs CHANGED
@@ -1,3 +1,5 @@
1
+ import "./chunk-HEBXNMVQ.mjs";
2
+
1
3
  // src/kb/KnowledgeGateway.ts
2
4
  import { readFileSync } from "fs";
3
5
  import { join } from "path";
@@ -2140,29 +2142,29 @@ var SlideGeneratorV2 = class {
2140
2142
  }
2141
2143
  /**
2142
2144
  * Process section content into slides.
2143
- * Tables become table slides. Lists become bullet slides.
2145
+ * RULES:
2146
+ * 1. Tables ALWAYS become table slides - NEVER extract to metrics
2147
+ * 2. Empty sections are SKIPPED - no blank divider slides
2148
+ * 3. Sections with minimal content are combined into statement slides
2144
2149
  */
2145
2150
  processSectionContent(section, startIndex) {
2146
2151
  const slides = [];
2147
- const hasTable = section.tokens.some((t) => t.type === "table");
2152
+ const tableTokens = section.tokens.filter((t) => t.type === "table");
2148
2153
  const hasList = section.tokens.some((t) => t.type === "list");
2149
2154
  const hasSignificantText = this.hasSignificantParagraphs(section.tokens);
2150
- if (hasTable) {
2151
- const tableToken = section.tokens.find((t) => t.type === "table");
2152
- if (tableToken) {
2153
- slides.push(this.createTableSlide(section.title, tableToken));
2154
- }
2155
+ for (const tableToken of tableTokens) {
2156
+ slides.push(this.createTableSlide(section.title, tableToken));
2155
2157
  }
2156
2158
  if (hasList) {
2157
2159
  const listSlides = this.createBulletSlides(section.title, section.tokens);
2158
2160
  slides.push(...listSlides);
2159
2161
  }
2160
- if (hasSignificantText && !hasList && !hasTable) {
2162
+ if (hasSignificantText && !hasList && tableTokens.length === 0) {
2161
2163
  slides.push(this.createContentSlide(section.title, section.tokens));
2162
2164
  }
2163
2165
  if (slides.length === 0 && section.tokens.length > 0) {
2164
2166
  const statement = this.extractStatement(section.tokens);
2165
- if (statement) {
2167
+ if (statement && statement.length > 20) {
2166
2168
  slides.push({
2167
2169
  index: startIndex,
2168
2170
  type: "statement",
@@ -2193,7 +2195,10 @@ var SlideGeneratorV2 = class {
2193
2195
  }
2194
2196
  /**
2195
2197
  * Create bullet slides from list content.
2196
- * NEVER truncate bullets. Split into multiple slides if needed.
2198
+ * RULES:
2199
+ * 1. NEVER truncate bullets
2200
+ * 2. NEVER create slides with only 1-2 bullets (orphan slides)
2201
+ * 3. If there are fewer than minBulletsToKeep bullets, combine them into a statement slide
2197
2202
  */
2198
2203
  createBulletSlides(title, tokens) {
2199
2204
  const slides = [];
@@ -2208,40 +2213,61 @@ var SlideGeneratorV2 = class {
2208
2213
  }
2209
2214
  }
2210
2215
  }
2216
+ if (allBullets.length === 0) {
2217
+ return slides;
2218
+ }
2211
2219
  const maxBullets = this.config.maxBulletsPerSlide;
2212
2220
  const minBullets = this.config.minBulletsToKeep;
2221
+ if (allBullets.length < minBullets) {
2222
+ const statement = allBullets.join(" \u2022 ");
2223
+ slides.push({
2224
+ index: 0,
2225
+ type: "statement",
2226
+ title,
2227
+ content: { statement }
2228
+ });
2229
+ return slides;
2230
+ }
2213
2231
  if (allBullets.length <= maxBullets) {
2214
- if (allBullets.length >= minBullets || allBullets.length === 0) {
2215
- slides.push({
2216
- index: 0,
2217
- type: "bullets",
2218
- title,
2219
- content: { bullets: allBullets }
2220
- });
2221
- } else {
2222
- slides.push({
2223
- index: 0,
2224
- type: "bullets",
2225
- title,
2226
- content: { bullets: allBullets },
2227
- notes: "Consider combining with adjacent content"
2228
- });
2229
- }
2232
+ slides.push({
2233
+ index: 0,
2234
+ type: "bullets",
2235
+ title,
2236
+ content: { bullets: allBullets }
2237
+ });
2230
2238
  } else {
2231
- for (let i = 0; i < allBullets.length; i += maxBullets) {
2232
- const chunk = allBullets.slice(i, i + maxBullets);
2239
+ const chunks = this.splitBulletsWithoutOrphans(allBullets, maxBullets, minBullets);
2240
+ for (let i = 0; i < chunks.length; i++) {
2233
2241
  const isFirst = i === 0;
2234
2242
  const slideTitle = isFirst ? title : `${title} (continued)`;
2235
2243
  slides.push({
2236
2244
  index: 0,
2237
2245
  type: "bullets",
2238
2246
  title: slideTitle,
2239
- content: { bullets: chunk }
2247
+ content: { bullets: chunks[i] }
2240
2248
  });
2241
2249
  }
2242
2250
  }
2243
2251
  return slides;
2244
2252
  }
2253
+ /**
2254
+ * Split bullets into chunks without creating orphan slides.
2255
+ * If the last chunk would have fewer than minBullets, steal from previous chunk.
2256
+ */
2257
+ splitBulletsWithoutOrphans(bullets, maxBullets, minBullets) {
2258
+ const chunks = [];
2259
+ for (let i = 0; i < bullets.length; i += maxBullets) {
2260
+ chunks.push(bullets.slice(i, i + maxBullets));
2261
+ }
2262
+ const lastChunk = chunks[chunks.length - 1];
2263
+ if (lastChunk && lastChunk.length < minBullets && chunks.length > 1) {
2264
+ const prevChunk = chunks[chunks.length - 2];
2265
+ const bulletsToMove = minBullets - lastChunk.length;
2266
+ const movedBullets = prevChunk.splice(-bulletsToMove);
2267
+ chunks[chunks.length - 1] = [...movedBullets, ...lastChunk];
2268
+ }
2269
+ return chunks;
2270
+ }
2245
2271
  /**
2246
2272
  * Get complete text from a list item, including nested content.
2247
2273
  * NEVER truncate.
@@ -4883,6 +4909,7 @@ async function initRenderer() {
4883
4909
  }
4884
4910
 
4885
4911
  // src/output/RendererV2.ts
4912
+ import { writeFileSync } from "fs";
4886
4913
  var RendererV2 = class {
4887
4914
  /**
4888
4915
  * Render slides to complete HTML document.
@@ -4922,6 +4949,287 @@ ${slidesHtml}
4922
4949
  </body>
4923
4950
  </html>`;
4924
4951
  }
4952
+ /**
4953
+ * Render slides to both HTML and PDF files.
4954
+ * Always generates both formats for easy sharing.
4955
+ */
4956
+ async renderToFiles(slides, outputPath, title = "Presentation") {
4957
+ const html = this.render(slides, title);
4958
+ const htmlPath = outputPath.replace(/\.pdf$/i, "") + ".html";
4959
+ const pdfPath = outputPath.replace(/\.html$/i, "") + ".pdf";
4960
+ writeFileSync(htmlPath, html);
4961
+ console.log(`\u2705 HTML saved: ${htmlPath}`);
4962
+ await this.renderToPDF(slides, pdfPath, title);
4963
+ console.log(`\u2705 PDF saved: ${pdfPath}`);
4964
+ return { htmlPath, pdfPath };
4965
+ }
4966
+ /**
4967
+ * Render slides directly to PDF using Puppeteer.
4968
+ * Creates a printable PDF with one slide per page.
4969
+ */
4970
+ async renderToPDF(slides, outputPath, title = "Presentation") {
4971
+ const puppeteer = await import("./puppeteer-EG4MVFUF.mjs");
4972
+ const printHtml = this.renderForPrint(slides, title);
4973
+ const browser = await puppeteer.default.launch({
4974
+ headless: true,
4975
+ args: ["--no-sandbox", "--disable-setuid-sandbox"]
4976
+ });
4977
+ try {
4978
+ const page = await browser.newPage();
4979
+ await page.setViewport({ width: 1920, height: 1080 });
4980
+ await page.setContent(printHtml, { waitUntil: "networkidle0" });
4981
+ const pdfBuffer = await page.pdf({
4982
+ path: outputPath,
4983
+ width: "1920px",
4984
+ height: "1080px",
4985
+ printBackground: true,
4986
+ margin: { top: 0, right: 0, bottom: 0, left: 0 },
4987
+ preferCSSPageSize: true
4988
+ });
4989
+ return pdfBuffer;
4990
+ } finally {
4991
+ await browser.close();
4992
+ }
4993
+ }
4994
+ /**
4995
+ * Render HTML optimized for PDF printing (no reveal.js, static pages).
4996
+ */
4997
+ renderForPrint(slides, title) {
4998
+ const slidesHtml = slides.map((slide) => {
4999
+ const content = this.renderSlideContent(slide);
5000
+ return `<div class="slide slide-${slide.type}">${content}</div>`;
5001
+ }).join("\n");
5002
+ return `<!DOCTYPE html>
5003
+ <html lang="en">
5004
+ <head>
5005
+ <meta charset="UTF-8">
5006
+ <title>${this.escapeHtml(title)}</title>
5007
+ <style>
5008
+ @page {
5009
+ size: 1920px 1080px;
5010
+ margin: 0;
5011
+ }
5012
+
5013
+ * {
5014
+ box-sizing: border-box;
5015
+ margin: 0;
5016
+ padding: 0;
5017
+ }
5018
+
5019
+ body {
5020
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
5021
+ background: #1a1a2e;
5022
+ color: #ffffff;
5023
+ }
5024
+
5025
+ .slide {
5026
+ width: 1920px;
5027
+ height: 1080px;
5028
+ padding: 80px 100px;
5029
+ background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
5030
+ page-break-after: always;
5031
+ page-break-inside: avoid;
5032
+ position: relative;
5033
+ display: flex;
5034
+ flex-direction: column;
5035
+ justify-content: flex-start;
5036
+ overflow: hidden;
5037
+ }
5038
+
5039
+ /* Content area takes full available height */
5040
+ .slide ul,
5041
+ .slide .data-table,
5042
+ .slide .statement {
5043
+ flex: 1;
5044
+ display: flex;
5045
+ flex-direction: column;
5046
+ justify-content: flex-start;
5047
+ }
5048
+
5049
+ .slide ul {
5050
+ margin-top: 20px;
5051
+ }
5052
+
5053
+ .slide:last-child {
5054
+ page-break-after: auto;
5055
+ }
5056
+
5057
+ h1 {
5058
+ font-size: 52px;
5059
+ font-weight: 700;
5060
+ color: #ffffff;
5061
+ margin-bottom: 32px;
5062
+ line-height: 1.1;
5063
+ letter-spacing: -0.02em;
5064
+ }
5065
+
5066
+ h2 {
5067
+ font-size: 32px;
5068
+ font-weight: 500;
5069
+ color: rgba(255, 255, 255, 0.85);
5070
+ margin-bottom: 24px;
5071
+ }
5072
+
5073
+ p {
5074
+ font-size: 24px;
5075
+ color: rgba(255, 255, 255, 0.85);
5076
+ line-height: 1.6;
5077
+ margin-bottom: 20px;
5078
+ }
5079
+
5080
+ ul {
5081
+ margin: 0;
5082
+ padding: 0;
5083
+ list-style: none;
5084
+ }
5085
+
5086
+ li {
5087
+ font-size: 24px;
5088
+ color: rgba(255, 255, 255, 0.85);
5089
+ line-height: 1.5;
5090
+ margin-bottom: 20px;
5091
+ padding-left: 32px;
5092
+ position: relative;
5093
+ }
5094
+
5095
+ li::before {
5096
+ content: '';
5097
+ position: absolute;
5098
+ left: 0;
5099
+ top: 12px;
5100
+ width: 10px;
5101
+ height: 10px;
5102
+ background: #4a9eff;
5103
+ border-radius: 50%;
5104
+ }
5105
+
5106
+ li strong {
5107
+ color: #ffffff;
5108
+ font-weight: 600;
5109
+ }
5110
+
5111
+ .data-table {
5112
+ width: 100%;
5113
+ border-collapse: collapse;
5114
+ margin-top: 24px;
5115
+ font-size: 20px;
5116
+ }
5117
+
5118
+ .data-table th {
5119
+ background: rgba(255, 255, 255, 0.08);
5120
+ color: #ffffff;
5121
+ font-weight: 600;
5122
+ text-align: left;
5123
+ padding: 16px 20px;
5124
+ border-bottom: 2px solid rgba(255, 255, 255, 0.1);
5125
+ }
5126
+
5127
+ .data-table td {
5128
+ color: rgba(255, 255, 255, 0.85);
5129
+ padding: 14px 20px;
5130
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
5131
+ }
5132
+
5133
+ .data-table td.number {
5134
+ text-align: right;
5135
+ font-family: 'SF Mono', 'Monaco', monospace;
5136
+ font-weight: 500;
5137
+ color: #4a9eff;
5138
+ }
5139
+
5140
+ .metrics-container {
5141
+ display: flex;
5142
+ justify-content: flex-start;
5143
+ gap: 40px;
5144
+ flex-wrap: wrap;
5145
+ margin-top: 40px;
5146
+ }
5147
+
5148
+ .metric {
5149
+ background: rgba(255, 255, 255, 0.05);
5150
+ border: 1px solid rgba(255, 255, 255, 0.1);
5151
+ border-radius: 12px;
5152
+ padding: 32px 48px;
5153
+ text-align: center;
5154
+ min-width: 200px;
5155
+ }
5156
+
5157
+ .metric-value {
5158
+ font-size: 56px;
5159
+ font-weight: 700;
5160
+ color: #4a9eff;
5161
+ line-height: 1;
5162
+ margin-bottom: 12px;
5163
+ }
5164
+
5165
+ .metric-label {
5166
+ font-size: 16px;
5167
+ color: rgba(255, 255, 255, 0.6);
5168
+ text-transform: uppercase;
5169
+ letter-spacing: 0.1em;
5170
+ }
5171
+
5172
+ .statement {
5173
+ font-size: 36px;
5174
+ color: #ffffff;
5175
+ line-height: 1.4;
5176
+ max-width: 80%;
5177
+ }
5178
+
5179
+ .subtext {
5180
+ font-size: 24px;
5181
+ color: rgba(255, 255, 255, 0.6);
5182
+ }
5183
+
5184
+ .slide-title, .slide-thank_you {
5185
+ justify-content: center;
5186
+ align-items: center;
5187
+ text-align: center;
5188
+ }
5189
+
5190
+ .slide-title h1, .slide-thank_you h1 {
5191
+ font-size: 72px;
5192
+ }
5193
+
5194
+ .source {
5195
+ position: absolute;
5196
+ bottom: 24px;
5197
+ left: 80px;
5198
+ font-size: 14px;
5199
+ color: rgba(255, 255, 255, 0.6);
5200
+ }
5201
+ </style>
5202
+ </head>
5203
+ <body>
5204
+ ${slidesHtml}
5205
+ </body>
5206
+ </html>`;
5207
+ }
5208
+ /**
5209
+ * Render slide content (shared between HTML and PDF renderers).
5210
+ */
5211
+ renderSlideContent(slide) {
5212
+ switch (slide.type) {
5213
+ case "title":
5214
+ return this.renderTitleSlide(slide);
5215
+ case "section":
5216
+ return this.renderSectionSlide(slide);
5217
+ case "bullets":
5218
+ return this.renderBulletSlide(slide);
5219
+ case "table":
5220
+ return this.renderTableSlide(slide);
5221
+ case "metrics":
5222
+ return this.renderMetricsSlide(slide);
5223
+ case "statement":
5224
+ return this.renderStatementSlide(slide);
5225
+ case "call_to_action":
5226
+ return this.renderCTASlide(slide);
5227
+ case "thank_you":
5228
+ return this.renderThankYouSlide(slide);
5229
+ default:
5230
+ return this.renderBulletSlide(slide);
5231
+ }
5232
+ }
4925
5233
  /**
4926
5234
  * Render a single slide.
4927
5235
  */
@@ -5143,10 +5451,22 @@ ${content}
5143
5451
  }
5144
5452
 
5145
5453
  .reveal .slides section {
5146
- padding: 60px 80px;
5454
+ padding: 80px 100px;
5147
5455
  background: linear-gradient(135deg, var(--bg-primary) 0%, var(--bg-secondary) 50%, var(--bg-accent) 100%);
5148
5456
  height: 100%;
5149
5457
  box-sizing: border-box;
5458
+ display: flex !important;
5459
+ flex-direction: column;
5460
+ justify-content: flex-start;
5461
+ align-items: stretch;
5462
+ }
5463
+
5464
+ .reveal .slides section > ul,
5465
+ .reveal .slides section > .data-table {
5466
+ flex: 1;
5467
+ display: flex;
5468
+ flex-direction: column;
5469
+ justify-content: flex-start;
5150
5470
  }
5151
5471
 
5152
5472
  /* Typography */
@@ -0,0 +1,56 @@
1
+ import {
2
+ Browser,
3
+ BrowserPlatform,
4
+ BrowserTag,
5
+ CDP_WEBSOCKET_ENDPOINT_REGEX,
6
+ CLI,
7
+ Cache,
8
+ ChromeReleaseChannel,
9
+ InstalledBrowser,
10
+ Process,
11
+ TimeoutError,
12
+ WEBDRIVER_BIDI_WEBSOCKET_ENDPOINT_REGEX,
13
+ canDownload,
14
+ computeExecutablePath,
15
+ computeSystemExecutablePath,
16
+ createProfile,
17
+ detectBrowserPlatform,
18
+ getDownloadUrl,
19
+ getInstalledBrowsers,
20
+ getVersionComparator,
21
+ install,
22
+ launch,
23
+ makeProgressCallback,
24
+ resolveBuildId,
25
+ resolveDefaultUserDataDir,
26
+ uninstall
27
+ } from "./chunk-5NJVL3OH.mjs";
28
+ import "./chunk-QUYDTLMJ.mjs";
29
+ import "./chunk-HEBXNMVQ.mjs";
30
+ export {
31
+ Browser,
32
+ BrowserPlatform,
33
+ BrowserTag,
34
+ CDP_WEBSOCKET_ENDPOINT_REGEX,
35
+ CLI,
36
+ Cache,
37
+ ChromeReleaseChannel,
38
+ InstalledBrowser,
39
+ Process,
40
+ TimeoutError,
41
+ WEBDRIVER_BIDI_WEBSOCKET_ENDPOINT_REGEX,
42
+ canDownload,
43
+ computeExecutablePath,
44
+ computeSystemExecutablePath,
45
+ createProfile,
46
+ detectBrowserPlatform,
47
+ getDownloadUrl,
48
+ getInstalledBrowsers,
49
+ getVersionComparator,
50
+ install,
51
+ launch,
52
+ makeProgressCallback,
53
+ resolveBuildId,
54
+ resolveDefaultUserDataDir,
55
+ uninstall
56
+ };