From 4d1dc76e31bd27d6369893c4c38d214777afcbb9 Mon Sep 17 00:00:00 2001 From: yulonger's MacBook Pro 14 Date: Sat, 29 Aug 2026 19:00:14 +0800 Subject: [PATCH] build: add precompiled CLI distribution --- dist-cli/build.d.ts | 1 + dist-cli/build.js | 129 ++++ dist-cli/build.js.map | 1 + dist-cli/check.d.ts | 11 + dist-cli/check.js | 49 ++ dist-cli/check.js.map | 1 + dist-cli/cli.d.ts | 2 + dist-cli/cli.js | 58 ++ dist-cli/cli.js.map | 1 + dist-cli/dev.d.ts | 1 + dist-cli/dev.js | 29 + dist-cli/dev.js.map | 1 + dist-cli/export.d.ts | 1 + dist-cli/export.js | 37 + dist-cli/export.js.map | 1 + dist-cli/index.d.ts | 2 + dist-cli/index.js | 2 + dist-cli/index.js.map | 1 + dist-cli/init.d.ts | 1 + dist-cli/init.js | 124 ++++ dist-cli/init.js.map | 1 + dist-cli/lib/config.d.ts | 10 + dist-cli/lib/config.js | 61 ++ dist-cli/lib/config.js.map | 1 + dist-cli/lib/content.d.ts | 26 + dist-cli/lib/content.js | 124 ++++ dist-cli/lib/content.js.map | 1 + dist-cli/lib/dev-overflow-audit.d.ts | 13 + dist-cli/lib/dev-overflow-audit.js | 90 +++ dist-cli/lib/dev-overflow-audit.js.map | 1 + dist-cli/lib/overflow-audit.d.ts | 37 + dist-cli/lib/overflow-audit.js | 228 ++++++ dist-cli/lib/overflow-audit.js.map | 1 + dist-cli/lib/overflow-report.d.ts | 6 + dist-cli/lib/overflow-report.js | 58 ++ dist-cli/lib/overflow-report.js.map | 1 + dist-cli/lib/run-slidev.d.ts | 8 + dist-cli/lib/run-slidev.js | 33 + dist-cli/lib/run-slidev.js.map | 1 + dist-cli/lib/site-base.d.ts | 2 + dist-cli/lib/site-base.js | 15 + dist-cli/lib/site-base.js.map | 1 + dist-cli/lib/static-overflow.d.ts | 28 + dist-cli/lib/static-overflow.js | 313 ++++++++ dist-cli/lib/static-overflow.js.map | 1 + dist-cli/lib/theme.d.ts | 1 + dist-cli/lib/theme.js | 16 + dist-cli/lib/theme.js.map | 1 + dist-cli/lib/token.d.ts | 2 + dist-cli/lib/token.js | 8 + dist-cli/lib/token.js.map | 1 + dist-cli/present.d.ts | 1 + dist-cli/present.js | 41 + dist-cli/present.js.map | 1 + .../theme/components/ContentScaleControls.vue | 699 ++++++++++++++++++ dist-cli/theme/components/PresenterAccess.vue | 137 ++++ .../theme/components/SlideScrollFallback.vue | 31 + dist-cli/theme/components/SmartImages.vue | 32 + dist-cli/theme/global-bottom.vue | 13 + dist-cli/theme/layouts/center.vue | 5 + dist-cli/theme/layouts/cover.vue | 5 + dist-cli/theme/layouts/default.vue | 5 + dist-cli/theme/layouts/image-auto.vue | 74 ++ dist-cli/theme/layouts/image-full.vue | 21 + dist-cli/theme/layouts/image-left.vue | 23 + dist-cli/theme/layouts/image-right.vue | 23 + dist-cli/theme/layouts/quote.vue | 5 + dist-cli/theme/layouts/section.vue | 5 + dist-cli/theme/layouts/two-cols.vue | 9 + dist-cli/theme/package.json | 33 + dist-cli/theme/setup/markdown.ts | 8 + dist-cli/theme/styles/base.css | 233 ++++++ dist-cli/theme/styles/content.css | 69 ++ dist-cli/theme/styles/index.ts | 4 + dist-cli/theme/styles/layouts.css | 283 +++++++ dist-cli/theme/styles/presenter.css | 143 ++++ dist-cli/theme/utils/resolve-image.ts | 15 + 77 files changed, 3461 insertions(+) create mode 100644 dist-cli/build.d.ts create mode 100644 dist-cli/build.js create mode 100644 dist-cli/build.js.map create mode 100644 dist-cli/check.d.ts create mode 100644 dist-cli/check.js create mode 100644 dist-cli/check.js.map create mode 100644 dist-cli/cli.d.ts create mode 100755 dist-cli/cli.js create mode 100644 dist-cli/cli.js.map create mode 100644 dist-cli/dev.d.ts create mode 100644 dist-cli/dev.js create mode 100644 dist-cli/dev.js.map create mode 100644 dist-cli/export.d.ts create mode 100644 dist-cli/export.js create mode 100644 dist-cli/export.js.map create mode 100644 dist-cli/index.d.ts create mode 100644 dist-cli/index.js create mode 100644 dist-cli/index.js.map create mode 100644 dist-cli/init.d.ts create mode 100644 dist-cli/init.js create mode 100644 dist-cli/init.js.map create mode 100644 dist-cli/lib/config.d.ts create mode 100644 dist-cli/lib/config.js create mode 100644 dist-cli/lib/config.js.map create mode 100644 dist-cli/lib/content.d.ts create mode 100644 dist-cli/lib/content.js create mode 100644 dist-cli/lib/content.js.map create mode 100644 dist-cli/lib/dev-overflow-audit.d.ts create mode 100644 dist-cli/lib/dev-overflow-audit.js create mode 100644 dist-cli/lib/dev-overflow-audit.js.map create mode 100644 dist-cli/lib/overflow-audit.d.ts create mode 100644 dist-cli/lib/overflow-audit.js create mode 100644 dist-cli/lib/overflow-audit.js.map create mode 100644 dist-cli/lib/overflow-report.d.ts create mode 100644 dist-cli/lib/overflow-report.js create mode 100644 dist-cli/lib/overflow-report.js.map create mode 100644 dist-cli/lib/run-slidev.d.ts create mode 100644 dist-cli/lib/run-slidev.js create mode 100644 dist-cli/lib/run-slidev.js.map create mode 100644 dist-cli/lib/site-base.d.ts create mode 100644 dist-cli/lib/site-base.js create mode 100644 dist-cli/lib/site-base.js.map create mode 100644 dist-cli/lib/static-overflow.d.ts create mode 100644 dist-cli/lib/static-overflow.js create mode 100644 dist-cli/lib/static-overflow.js.map create mode 100644 dist-cli/lib/theme.d.ts create mode 100644 dist-cli/lib/theme.js create mode 100644 dist-cli/lib/theme.js.map create mode 100644 dist-cli/lib/token.d.ts create mode 100644 dist-cli/lib/token.js create mode 100644 dist-cli/lib/token.js.map create mode 100644 dist-cli/present.d.ts create mode 100644 dist-cli/present.js create mode 100644 dist-cli/present.js.map create mode 100644 dist-cli/theme/components/ContentScaleControls.vue create mode 100644 dist-cli/theme/components/PresenterAccess.vue create mode 100644 dist-cli/theme/components/SlideScrollFallback.vue create mode 100644 dist-cli/theme/components/SmartImages.vue create mode 100644 dist-cli/theme/global-bottom.vue create mode 100644 dist-cli/theme/layouts/center.vue create mode 100644 dist-cli/theme/layouts/cover.vue create mode 100644 dist-cli/theme/layouts/default.vue create mode 100644 dist-cli/theme/layouts/image-auto.vue create mode 100644 dist-cli/theme/layouts/image-full.vue create mode 100644 dist-cli/theme/layouts/image-left.vue create mode 100644 dist-cli/theme/layouts/image-right.vue create mode 100644 dist-cli/theme/layouts/quote.vue create mode 100644 dist-cli/theme/layouts/section.vue create mode 100644 dist-cli/theme/layouts/two-cols.vue create mode 100644 dist-cli/theme/package.json create mode 100644 dist-cli/theme/setup/markdown.ts create mode 100644 dist-cli/theme/styles/base.css create mode 100644 dist-cli/theme/styles/content.css create mode 100644 dist-cli/theme/styles/index.ts create mode 100644 dist-cli/theme/styles/layouts.css create mode 100644 dist-cli/theme/styles/presenter.css create mode 100644 dist-cli/theme/utils/resolve-image.ts diff --git a/dist-cli/build.d.ts b/dist-cli/build.d.ts new file mode 100644 index 0000000..0b172b7 --- /dev/null +++ b/dist-cli/build.d.ts @@ -0,0 +1 @@ +import 'dotenv/config'; diff --git a/dist-cli/build.js b/dist-cli/build.js new file mode 100644 index 0000000..04794f8 --- /dev/null +++ b/dist-cli/build.js @@ -0,0 +1,129 @@ +import 'dotenv/config'; +import { cp, mkdir, readFile, rm, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import { checkProject, printIssues } from "./check.js"; +import { joinBase, normalizeSiteBase } from "./lib/site-base.js"; +import { auditBuiltDecks } from "./lib/overflow-audit.js"; +import { formatOverflowAuditResult } from "./lib/overflow-report.js"; +import { runSlidev } from "./lib/run-slidev.js"; +import { resolveTheme } from "./lib/theme.js"; +const cwd = process.cwd(); +const siteBase = normalizeSiteBase(process.env.SITE_BASE); +let config; +let dist; +async function main() { + const result = await checkProject(cwd); + config = result.config; + dist = path.join(cwd, config.outDir); + const { decks, issues } = result; + printIssues(issues, cwd); + if (issues.some(issue => issue.level === 'error')) + throw new Error('内容检查失败,已停止构建'); + const published = decks.filter(deck => !deck.draft); + await rm(dist, { recursive: true, force: true }); + await mkdir(dist, { recursive: true }); + for (const deck of published) + await buildDeck(deck); + await reportSlideOverflow(published); + await writeFile(path.join(dist, 'index.html'), renderIndex(published), 'utf8'); + await writeFile(path.join(dist, '_headers'), renderHeaders(), 'utf8'); + await writeFile(path.join(dist, '_redirects'), renderRedirects(published), 'utf8'); + console.log(`\n构建完成:${published.length} 套演示 → ${path.relative(cwd, dist)}`); +} +async function buildDeck(deck) { + const output = path.join(dist, deck.slug); + const base = joinBase(siteBase, deck.slug); + console.log(`\nBuilding ${deck.slug} (${base})`); + await runSlidev([ + 'build', + deck.entry, + '--theme', + resolveTheme(config.theme), + '--out', + output, + '--base', + base, + '--router-mode', + 'hash', + ]); + const assets = path.join(deck.directory, 'assets'); + await cp(assets, path.join(output, 'assets'), { recursive: true, force: true }).catch(() => undefined); + await copySpaEntry(output, 'presenter'); + await copySpaEntry(output, 'overview'); + await copySpaEntry(output, 'notes-edit'); +} +async function copySpaEntry(output, route) { + const html = await readFile(path.join(output, 'index.html'), 'utf8'); + const routeBootstrap = ``; + const routedHtml = html.replace('', `${routeBootstrap}`); + const directory = path.join(output, route); + await mkdir(directory, { recursive: true }); + await writeFile(path.join(directory, 'index.html'), routedHtml, 'utf8'); +} +async function reportSlideOverflow(decks) { + if (!decks.length) + return; + console.log('\n检查编译后的幻灯片内容边界...'); + const result = await auditBuiltDecks({ root: dist, decks, siteBase }); + formatOverflowAuditResult(result, cwd).forEach(line => console.log(line)); +} +function renderIndex(decks) { + const cards = decks.map((deck) => { + const href = joinBase(siteBase, deck.slug); + const cover = deck.cover + ? `` + : ``; + const tags = deck.tags.map(tag => `
  • ${escapeHtml(tag)}
  • `).join(''); + return `
    + ${cover} +
    +

    ${escapeHtml(deck.date || 'Undated')}${deck.author ? ` · ${escapeHtml(deck.author)}` : ''}

    +

    ${escapeHtml(deck.title)}

    + ${deck.description ? `

    ${escapeHtml(deck.description)}

    ` : ''} + ${tags ? `
      ${tags}
    ` : ''} +
    +
    `; + }).join('\n'); + return ` + + + + + + ${escapeHtml(config.title)} + + + +
    +
    +

    MARKDOWN PRESENTATIONS

    +

    ${escapeHtml(config.title)}

    +

    ${escapeHtml(config.description)}

    +
    +
    + ${cards || '

    暂无公开演示。

    '} +
    +
    + +`; +} +function landingStyles() { + return `:root{font-family:Inter,"Noto Sans SC","PingFang SC","Microsoft YaHei",sans-serif;color:#222;background:#f6f5f2}*{box-sizing:border-box}body{margin:0}main{width:min(1120px,calc(100% - 40px));margin:auto;padding:72px 0 96px}header{border-bottom:2px solid #1d4ed8;padding-bottom:28px;margin-bottom:36px}.eyebrow{font-size:12px;font-weight:700;letter-spacing:.18em;color:#1d4ed8}h1{font-size:clamp(48px,8vw,82px);line-height:1;margin:14px 0}.lede{font-size:clamp(19px,2.2vw,26px);color:#555;margin:0}.deck-list{display:grid;gap:28px}.deck-card{display:grid;grid-template-columns:minmax(220px,36%) 1fr;background:#fff;border:1px solid #d9d7d2;border-radius:10px;overflow:hidden;box-shadow:0 12px 36px rgba(30,64,175,.08)}.cover{display:block;min-height:230px;background:#eae7e2}.cover img{display:block;width:100%;height:100%;min-height:230px;object-fit:cover}.cover-fallback{height:100%;min-height:230px;display:grid;place-items:center;background:linear-gradient(135deg,#eff6ff,#dbeafe);color:#1d4ed8;font-size:92px;font-weight:700}.deck-copy{padding:32px}.meta{font-size:13px;color:#777;margin:0 0 10px}h2{font-size:clamp(26px,3vw,38px);line-height:1.15;margin:0}h2 a{color:inherit;text-decoration:none}h2 a:hover{color:#1d4ed8}.description{font-size:17px;line-height:1.7;color:#555}.tags{display:flex;gap:8px;flex-wrap:wrap;list-style:none;padding:0;margin:24px 0 0}.tags li{font-size:12px;background:#eff6ff;color:#1d4ed8;padding:5px 9px;border-radius:999px}@media(max-width:680px){main{padding-top:44px}.deck-card{grid-template-columns:1fr}.cover,.cover img,.cover-fallback{min-height:190px}.deck-copy{padding:24px}}`; +} +function renderHeaders() { + return `/*.html\n Cache-Control: public, max-age=0, must-revalidate\n\n/*/assets/*\n Cache-Control: public, max-age=31536000, immutable\n`; +} +function renderRedirects(decks) { + return decks.map(deck => `${joinBase(siteBase, deck.slug)}* ${joinBase(siteBase, deck.slug)}index.html 200`).join('\n'); +} +function escapeHtml(value) { + return value.replace(/[&<>"']/g, character => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[character]); +} +function escapeAttribute(value) { + return escapeHtml(value); +} +await main().catch((error) => { + console.error(error instanceof Error ? error.message : error); + process.exitCode = 1; +}); +//# sourceMappingURL=build.js.map \ No newline at end of file diff --git a/dist-cli/build.js.map b/dist-cli/build.js.map new file mode 100644 index 0000000..0d66892 --- /dev/null +++ b/dist-cli/build.js.map @@ -0,0 +1 @@ +{"version":3,"file":"build.js","sourceRoot":"","sources":["../scripts/build.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist-cli/check.d.ts b/dist-cli/check.d.ts new file mode 100644 index 0000000..40ba78d --- /dev/null +++ b/dist-cli/check.d.ts @@ -0,0 +1,11 @@ +import 'dotenv/config'; +import { type ValidationIssue } from './lib/content.ts'; +import { type EasySlidesConfig } from './lib/config.ts'; +export declare function checkProject(cwd?: string, providedConfig?: EasySlidesConfig): Promise<{ + config: EasySlidesConfig; + decks: import("./lib/content.ts").DeckMetadata[]; + issues: ValidationIssue[]; + staticOverflow: import("./lib/static-overflow.ts").StaticOverflowResult; +}>; +export declare function printIssues(issues: ValidationIssue[], cwd?: string): void; +export declare function runCheck(): Promise; diff --git a/dist-cli/check.js b/dist-cli/check.js new file mode 100644 index 0000000..6fe3784 --- /dev/null +++ b/dist-cli/check.js @@ -0,0 +1,49 @@ +import 'dotenv/config'; +import path from 'node:path'; +import { discoverDecks, validateDeck } from "./lib/content.js"; +import { loadProjectConfig } from "./lib/config.js"; +import { formatStaticOverflowResult } from "./lib/overflow-report.js"; +import { auditStaticDecks } from "./lib/static-overflow.js"; +import { hasPresenterToken } from "./lib/token.js"; +export async function checkProject(cwd = process.cwd(), providedConfig) { + const config = providedConfig ?? await loadProjectConfig(cwd); + const decks = await discoverDecks(cwd, config.slidesDir); + const issues = []; + if (decks.length === 0) + issues.push({ level: 'error', file: path.join(cwd, config.slidesDir), message: `没有发现 ${config.slidesDir}//slides.md` }); + for (const deck of decks) + issues.push(...await validateDeck(deck)); + const staticOverflow = await auditStaticDecks(decks); + if (!hasPresenterToken()) { + issues.push({ + level: 'warning', + file: path.join(cwd, '.env'), + message: '未设置 PRESENTER_TOKEN;生产构建将隐藏演示者入口', + }); + } + return { config, decks, issues, staticOverflow }; +} +export function printIssues(issues, cwd = process.cwd()) { + for (const issue of issues) { + const marker = issue.level === 'error' ? 'ERROR' : 'WARN '; + console.log(`${marker} ${path.relative(cwd, issue.file)}: ${issue.message}`); + } +} +export async function runCheck() { + const result = await checkProject(); + printIssues(result.issues); + formatStaticOverflowResult(result.staticOverflow).forEach(line => console.log(line)); + const errors = result.issues.filter(issue => issue.level === 'error'); + if (errors.length > 0) { + console.error(`\n检查失败:${errors.length} 个错误`); + process.exitCode = 1; + return; + } + const warnings = result.issues.filter(issue => issue.level === 'warning').length + + result.staticOverflow.issues.length + + result.staticOverflow.errors.length; + console.log(`\n检查通过:${result.decks.length} 套演示,${warnings} 个警告`); +} +if (import.meta.url === new URL(process.argv[1], 'file:').href) + await runCheck(); +//# sourceMappingURL=check.js.map \ No newline at end of file diff --git a/dist-cli/check.js.map b/dist-cli/check.js.map new file mode 100644 index 0000000..80e87d1 --- /dev/null +++ b/dist-cli/check.js.map @@ -0,0 +1 @@ +{"version":3,"file":"check.js","sourceRoot":"","sources":["../scripts/check.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAA;AACtB,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,aAAa,EAAE,YAAY,EAAwB,MAAM,kBAAkB,CAAA;AACpF,OAAO,EAAE,iBAAiB,EAAyB,MAAM,iBAAiB,CAAA;AAC1E,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAA;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAElD,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,EAAE,cAAiC;IACvF,MAAM,MAAM,GAAG,cAAc,IAAI,MAAM,iBAAiB,CAAC,GAAG,CAAC,CAAA;IAC7D,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,SAAS,CAAC,CAAA;IACxD,MAAM,MAAM,GAAsB,EAAE,CAAA;IAEpC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QACpB,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,QAAQ,MAAM,CAAC,SAAS,mBAAmB,EAAE,CAAC,CAAA;IAE/H,KAAK,MAAM,IAAI,IAAI,KAAK;QACtB,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC,CAAA;IAE1C,MAAM,cAAc,GAAG,MAAM,gBAAgB,CAAC,KAAK,CAAC,CAAA;IAEpD,IAAI,CAAC,iBAAiB,EAAE,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,CAAC;YACV,KAAK,EAAE,SAAS;YAChB,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC;YAC5B,OAAO,EAAE,kCAAkC;SAC5C,CAAC,CAAA;IACJ,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,CAAA;AAClD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAAyB,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IACxE,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAA;QAC1D,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;IAC9E,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ;IAC5B,MAAM,MAAM,GAAG,MAAM,YAAY,EAAE,CAAA;IACnC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IAC1B,0BAA0B,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAA;IACpF,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,KAAK,OAAO,CAAC,CAAA;IACrE,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,KAAK,CAAC,UAAU,MAAM,CAAC,MAAM,MAAM,CAAC,CAAA;QAC5C,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAA;QACpB,OAAM;IACR,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,MAAM;UAC5E,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,MAAM;UACnC,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,MAAM,CAAA;IACvC,OAAO,CAAC,GAAG,CAAC,UAAU,MAAM,CAAC,KAAK,CAAC,MAAM,QAAQ,QAAQ,MAAM,CAAC,CAAA;AAClE,CAAC;AAED,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI;IAC5D,MAAM,QAAQ,EAAE,CAAA"} \ No newline at end of file diff --git a/dist-cli/cli.d.ts b/dist-cli/cli.d.ts new file mode 100644 index 0000000..b798801 --- /dev/null +++ b/dist-cli/cli.d.ts @@ -0,0 +1,2 @@ +#!/usr/bin/env node +export {}; diff --git a/dist-cli/cli.js b/dist-cli/cli.js new file mode 100755 index 0000000..a8a9f5e --- /dev/null +++ b/dist-cli/cli.js @@ -0,0 +1,58 @@ +#!/usr/bin/env node +import path from 'node:path'; +const rawArgs = process.argv.slice(2); +const command = rawArgs.shift(); +const rootIndex = rawArgs.indexOf('--root'); +if (rootIndex >= 0) { + const root = rawArgs[rootIndex + 1]; + if (!root) + throw new Error('--root 需要一个目录'); + rawArgs.splice(rootIndex, 2); + process.chdir(path.resolve(root)); +} +process.argv = [process.argv[0], process.argv[1], ...rawArgs]; +switch (command) { + case 'dev': + await import("./dev.js"); + break; + case 'present': + await import("./present.js"); + break; + case 'build': + await import("./build.js"); + break; + case 'check': + await (await import("./check.js")).runCheck(); + break; + case 'export': + await import("./export.js"); + break; + case 'init': + await import("./init.js"); + break; + case undefined: + case 'help': + case '--help': + case '-h': + printHelp(); + break; + default: + console.error(`未知命令:${command}`); + printHelp(); + process.exitCode = 1; +} +function printHelp() { + console.log(`easy-slides + +用法: + easy-slides init [directory] [--engine ] + easy-slides dev [slug|slides.md] + easy-slides present + easy-slides build + easy-slides check + easy-slides export --format pdf|png|pptx + +全局选项: + --root 在指定内容项目中运行`); +} +//# sourceMappingURL=cli.js.map \ No newline at end of file diff --git a/dist-cli/cli.js.map b/dist-cli/cli.js.map new file mode 100644 index 0000000..9577c20 --- /dev/null +++ b/dist-cli/cli.js.map @@ -0,0 +1 @@ +{"version":3,"file":"cli.js","sourceRoot":"","sources":["../scripts/cli.ts"],"names":[],"mappings":";AACA,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;AACrC,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,EAAE,CAAA;AAC/B,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;AAC3C,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;IACnB,MAAM,IAAI,GAAG,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC,CAAA;IACnC,IAAI,CAAC,IAAI;QACP,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAA;IAClC,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAA;IAC5B,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;AACnC,CAAC;AACD,OAAO,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,CAAA;AAE7D,QAAQ,OAAO,EAAE,CAAC;IAChB,KAAK,KAAK;QACR,MAAM,MAAM,CAAC,UAAU,CAAC,CAAA;QACxB,MAAK;IACP,KAAK,SAAS;QACZ,MAAM,MAAM,CAAC,cAAc,CAAC,CAAA;QAC5B,MAAK;IACP,KAAK,OAAO;QACV,MAAM,MAAM,CAAC,YAAY,CAAC,CAAA;QAC1B,MAAK;IACP,KAAK,OAAO;QACV,MAAM,CAAC,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;QAC7C,MAAK;IACP,KAAK,QAAQ;QACX,MAAM,MAAM,CAAC,aAAa,CAAC,CAAA;QAC3B,MAAK;IACP,KAAK,MAAM;QACT,MAAM,MAAM,CAAC,WAAW,CAAC,CAAA;QACzB,MAAK;IACP,KAAK,SAAS,CAAC;IACf,KAAK,MAAM,CAAC;IACZ,KAAK,QAAQ,CAAC;IACd,KAAK,IAAI;QACP,SAAS,EAAE,CAAA;QACX,MAAK;IACP;QACE,OAAO,CAAC,KAAK,CAAC,QAAQ,OAAO,EAAE,CAAC,CAAA;QAChC,SAAS,EAAE,CAAA;QACX,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAA;AACxB,CAAC;AAED,SAAS,SAAS;IAChB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;iCAWmB,CAAC,CAAA;AAClC,CAAC"} \ No newline at end of file diff --git a/dist-cli/dev.d.ts b/dist-cli/dev.d.ts new file mode 100644 index 0000000..0b172b7 --- /dev/null +++ b/dist-cli/dev.d.ts @@ -0,0 +1 @@ +import 'dotenv/config'; diff --git a/dist-cli/dev.js b/dist-cli/dev.js new file mode 100644 index 0000000..7810885 --- /dev/null +++ b/dist-cli/dev.js @@ -0,0 +1,29 @@ +import 'dotenv/config'; +import { loadProjectConfig } from "./lib/config.js"; +import { resolveDeck } from "./lib/content.js"; +import { startDevOverflowAudit } from "./lib/dev-overflow-audit.js"; +import { startSlidev, waitForSlidev } from "./lib/run-slidev.js"; +import { resolveTheme } from "./lib/theme.js"; +const input = process.argv.slice(2).find(argument => !argument.startsWith('-')); +const config = await loadProjectConfig(); +const deck = await resolveDeck(input, process.cwd(), config.slidesDir); +const port = process.env.PORT || '3030'; +const slidev = startSlidev([ + deck.entry, + '--theme', + resolveTheme(config.theme), + '--open', + '--port', + port, +]); +const overflowAudit = startDevOverflowAudit({ + deck, +}); +slidev.once('exit', () => void overflowAudit.close()); +try { + await waitForSlidev(slidev); +} +finally { + await overflowAudit.close(); +} +//# sourceMappingURL=dev.js.map \ No newline at end of file diff --git a/dist-cli/dev.js.map b/dist-cli/dev.js.map new file mode 100644 index 0000000..74ccb86 --- /dev/null +++ b/dist-cli/dev.js.map @@ -0,0 +1 @@ +{"version":3,"file":"dev.js","sourceRoot":"","sources":["../scripts/dev.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAA;AACtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAA;AACnE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAE7C,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAA;AAC/E,MAAM,MAAM,GAAG,MAAM,iBAAiB,EAAE,CAAA;AACxC,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,SAAS,CAAC,CAAA;AACtE,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,CAAA;AACvC,MAAM,MAAM,GAAG,WAAW,CAAC;IACzB,IAAI,CAAC,KAAK;IACV,SAAS;IACT,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC;IAC1B,QAAQ;IACR,QAAQ;IACR,IAAI;CACL,CAAC,CAAA;AACF,MAAM,aAAa,GAAG,qBAAqB,CAAC;IAC1C,IAAI;CACL,CAAC,CAAA;AACF,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,KAAK,aAAa,CAAC,KAAK,EAAE,CAAC,CAAA;AAErD,IAAI,CAAC;IACH,MAAM,aAAa,CAAC,MAAM,CAAC,CAAA;AAC7B,CAAC;QACO,CAAC;IACP,MAAM,aAAa,CAAC,KAAK,EAAE,CAAA;AAC7B,CAAC"} \ No newline at end of file diff --git a/dist-cli/export.d.ts b/dist-cli/export.d.ts new file mode 100644 index 0000000..0b172b7 --- /dev/null +++ b/dist-cli/export.d.ts @@ -0,0 +1 @@ +import 'dotenv/config'; diff --git a/dist-cli/export.js b/dist-cli/export.js new file mode 100644 index 0000000..baf9e79 --- /dev/null +++ b/dist-cli/export.js @@ -0,0 +1,37 @@ +import 'dotenv/config'; +import { mkdir } from 'node:fs/promises'; +import path from 'node:path'; +import { loadProjectConfig } from "./lib/config.js"; +import { resolveDeck } from "./lib/content.js"; +import { runSlidev } from "./lib/run-slidev.js"; +import { resolveTheme } from "./lib/theme.js"; +const args = process.argv.slice(2); +const slug = args.find(argument => !argument.startsWith('-')); +const formatIndex = args.indexOf('--format'); +const format = formatIndex >= 0 ? args[formatIndex + 1] : 'pdf'; +const allowed = new Set(['pdf', 'png', 'pptx', 'md']); +if (!allowed.has(format)) + throw new Error(`不支持导出格式:${format}`); +const config = await loadProjectConfig(); +const deck = await resolveDeck(slug, process.cwd(), config.slidesDir); +const exportDir = path.join(process.cwd(), config.exportDir); +await mkdir(exportDir, { recursive: true }); +const output = path.join(exportDir, `${deck.slug}.${format}`); +const slidevArgs = [ + 'export', + deck.entry, + '--theme', + resolveTheme(config.theme), + '--format', + format, + '--output', + output, +]; +// Slidev's one-piece exporter may capture off-screen lazy images before they +// are painted. Per-slide export renders each canvas as the active slide and is +// reliable for Markdown images across PNG, PDF, and screenshot-based PPTX. +if (format !== 'md') + slidevArgs.push('--per-slide'); +await runSlidev(slidevArgs); +console.log(`导出完成:${path.relative(process.cwd(), output)}`); +//# sourceMappingURL=export.js.map \ No newline at end of file diff --git a/dist-cli/export.js.map b/dist-cli/export.js.map new file mode 100644 index 0000000..77dc6ca --- /dev/null +++ b/dist-cli/export.js.map @@ -0,0 +1 @@ +{"version":3,"file":"export.js","sourceRoot":"","sources":["../scripts/export.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAA;AACtB,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACxC,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAE7C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;AAClC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAA;AAC7D,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;AAC5C,MAAM,MAAM,GAAG,WAAW,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;AAC/D,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAA;AAErD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;IACtB,MAAM,IAAI,KAAK,CAAC,WAAW,MAAM,EAAE,CAAC,CAAA;AAEtC,MAAM,MAAM,GAAG,MAAM,iBAAiB,EAAE,CAAA;AACxC,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,SAAS,CAAC,CAAA;AACrE,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,SAAS,CAAC,CAAA;AAC5D,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;AAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,IAAI,IAAI,MAAM,EAAE,CAAC,CAAA;AAE7D,MAAM,UAAU,GAAG;IACjB,QAAQ;IACR,IAAI,CAAC,KAAK;IACV,SAAS;IACT,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC;IAC1B,UAAU;IACV,MAAM;IACN,UAAU;IACV,MAAM;CACP,CAAA;AAED,6EAA6E;AAC7E,+EAA+E;AAC/E,2EAA2E;AAC3E,IAAI,MAAM,KAAK,IAAI;IACjB,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;AAEhC,MAAM,SAAS,CAAC,UAAU,CAAC,CAAA;AAE3B,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAA"} \ No newline at end of file diff --git a/dist-cli/index.d.ts b/dist-cli/index.d.ts new file mode 100644 index 0000000..f41af26 --- /dev/null +++ b/dist-cli/index.d.ts @@ -0,0 +1,2 @@ +export { loadProjectConfig, normalizeConfig } from './lib/config.ts'; +export type { EasySlidesConfig } from './lib/config.ts'; diff --git a/dist-cli/index.js b/dist-cli/index.js new file mode 100644 index 0000000..9b24c40 --- /dev/null +++ b/dist-cli/index.js @@ -0,0 +1,2 @@ +export { loadProjectConfig, normalizeConfig } from "./lib/config.js"; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist-cli/index.js.map b/dist-cli/index.js.map new file mode 100644 index 0000000..b85c7ba --- /dev/null +++ b/dist-cli/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../scripts/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA"} \ No newline at end of file diff --git a/dist-cli/init.d.ts b/dist-cli/init.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/dist-cli/init.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist-cli/init.js b/dist-cli/init.js new file mode 100644 index 0000000..62bf180 --- /dev/null +++ b/dist-cli/init.js @@ -0,0 +1,124 @@ +import { mkdir, writeFile } from 'node:fs/promises'; +import { createRequire } from 'node:module'; +import path from 'node:path'; +const require = createRequire(import.meta.url); +const engineVersion = String(require('../package.json').version); +const args = process.argv.slice(2); +const engineIndex = args.indexOf('--engine'); +const engineSpec = engineIndex >= 0 ? args[engineIndex + 1] : `^${engineVersion}`; +if (!engineSpec) + throw new Error('--engine 需要 npm 版本、Git URL 或本地路径'); +const targetInput = args.find((argument, index) => !argument.startsWith('-') && index !== engineIndex + 1) ?? '.'; +const target = path.resolve(targetInput); +await mkdir(path.join(target, 'slides', 'welcome', 'assets'), { recursive: true }); +await mkdir(path.join(target, '.github', 'workflows'), { recursive: true }); +await writeNew('package.json', `${JSON.stringify({ + name: path.basename(target), + private: true, + scripts: { + dev: 'easy-slides dev', + present: 'easy-slides present', + build: 'easy-slides build', + check: 'easy-slides check', + export: 'easy-slides export', + }, + devDependencies: { + '@easy-slides/cli': engineSpec, + }, +}, null, 2)}\n`); +await writeNew('easy-slides.config.mjs', `export default { + title: '${escapeJavaScript(path.basename(target))}', + description: 'Markdown presentations', + slidesDir: 'slides', + outDir: 'dist', +} +`); +await writeNew(path.join('slides', 'welcome', 'slides.md'), `--- +title: Welcome +description: Your first easy-slides deck +date: ${new Date().toISOString().slice(0, 10)} +tags: [Markdown] +--- + +# Welcome + +> Edit slides/welcome/slides.md and push to deploy. + + + +--- + +## Content lives here + +- The engine is an npm dependency +- This repository owns slides and assets +- The static build can deploy anywhere +`); +await writeNew('.gitignore', `node_modules/ +dist/ +exports/ +.env +.DS_Store +`); +await writeNew('pnpm-workspace.yaml', `allowBuilds: + playwright-chromium: false +`); +await writeNew(path.join('.github', 'workflows', 'deploy-pages.yml'), `name: Deploy slides + +on: + push: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +jobs: + deploy: + runs-on: ubuntu-latest + environment: + name: github-pages + url: \${{ steps.deployment.outputs.page_url }} + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + version: 11.19.0 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + - run: pnpm install --frozen-lockfile + - run: pnpm check + env: + PRESENTER_TOKEN: \${{ secrets.PRESENTER_TOKEN }} + - run: pnpm build + env: + SITE_BASE: /\${{ github.event.repository.name }}/ + PRESENTER_TOKEN: \${{ secrets.PRESENTER_TOKEN }} + - uses: actions/configure-pages@v5 + - uses: actions/upload-pages-artifact@v4 + with: + path: dist + - id: deployment + uses: actions/deploy-pages@v4 +`); +console.log(`内容项目已创建:${target}`); +console.log('下一步:pnpm install && pnpm dev -- welcome'); +async function writeNew(relative, content) { + const filename = path.join(target, relative); + await mkdir(path.dirname(filename), { recursive: true }); + await writeFile(filename, content, { encoding: 'utf8', flag: 'wx' }).catch((error) => { + if (error.code === 'EEXIST') + throw new Error(`拒绝覆盖已有文件:${filename}`); + throw error; + }); +} +function escapeJavaScript(value) { + return value.replaceAll('\\', '\\\\').replaceAll("'", "\\'"); +} +//# sourceMappingURL=init.js.map \ No newline at end of file diff --git a/dist-cli/init.js.map b/dist-cli/init.js.map new file mode 100644 index 0000000..03bafb2 --- /dev/null +++ b/dist-cli/init.js.map @@ -0,0 +1 @@ +{"version":3,"file":"init.js","sourceRoot":"","sources":["../scripts/init.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist-cli/lib/config.d.ts b/dist-cli/lib/config.d.ts new file mode 100644 index 0000000..73608c4 --- /dev/null +++ b/dist-cli/lib/config.d.ts @@ -0,0 +1,10 @@ +export interface EasySlidesConfig { + title: string; + description: string; + slidesDir: string; + outDir: string; + exportDir: string; + theme?: string; +} +export declare function loadProjectConfig(cwd?: string): Promise; +export declare function normalizeConfig(value: Partial | undefined): EasySlidesConfig; diff --git a/dist-cli/lib/config.js b/dist-cli/lib/config.js new file mode 100644 index 0000000..e5df1ec --- /dev/null +++ b/dist-cli/lib/config.js @@ -0,0 +1,61 @@ +var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) { + if (typeof path === "string" && /^\.\.?\//.test(path)) { + return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) { + return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js"); + }); + } + return path; +}; +import { access, readFile } from 'node:fs/promises'; +import path from 'node:path'; +import { pathToFileURL } from 'node:url'; +const defaults = { + title: 'easy-slides', + description: 'Markdown presentations powered by easy-slides', + slidesDir: 'slides', + outDir: 'dist', + exportDir: 'exports', +}; +export async function loadProjectConfig(cwd = process.cwd()) { + const candidates = [ + 'easy-slides.config.mjs', + 'easy-slides.config.js', + 'easy-slides.config.json', + ]; + for (const candidate of candidates) { + const filename = path.join(cwd, candidate); + if (!(await exists(filename))) + continue; + const loaded = candidate.endsWith('.json') + ? JSON.parse(await readFile(filename, 'utf8')) + : (await import(__rewriteRelativeImportExtension(`${pathToFileURL(filename).href}?t=${Date.now()}`))).default; + return normalizeConfig(loaded); + } + return { ...defaults }; +} +export function normalizeConfig(value) { + return { + ...defaults, + ...value, + slidesDir: normalizeRelativePath(value?.slidesDir ?? defaults.slidesDir, 'slidesDir'), + outDir: normalizeRelativePath(value?.outDir ?? defaults.outDir, 'outDir'), + exportDir: normalizeRelativePath(value?.exportDir ?? defaults.exportDir, 'exportDir'), + }; +} +function normalizeRelativePath(value, field) { + const normalized = value.trim().replace(/[\\/]+$/, ''); + const portable = normalized.replaceAll('\\', '/'); + if (!normalized || path.isAbsolute(normalized) || portable === '..' || portable.startsWith('../')) + throw new Error(`${field} 必须是项目内的相对路径`); + return normalized; +} +async function exists(filename) { + try { + await access(filename); + return true; + } + catch { + return false; + } +} +//# sourceMappingURL=config.js.map \ No newline at end of file diff --git a/dist-cli/lib/config.js.map b/dist-cli/lib/config.js.map new file mode 100644 index 0000000..cd6d12c --- /dev/null +++ b/dist-cli/lib/config.js.map @@ -0,0 +1 @@ +{"version":3,"file":"config.js","sourceRoot":"","sources":["../../scripts/lib/config.ts"],"names":[],"mappings":";;;;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAWxC,MAAM,QAAQ,GAAqB;IACjC,KAAK,EAAE,aAAa;IACpB,WAAW,EAAE,+CAA+C;IAC5D,SAAS,EAAE,QAAQ;IACnB,MAAM,EAAE,MAAM;IACd,SAAS,EAAE,SAAS;CACrB,CAAA;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IACzD,MAAM,UAAU,GAAG;QACjB,wBAAwB;QACxB,uBAAuB;QACvB,yBAAyB;KAC1B,CAAA;IAED,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA;QAC1C,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC3B,SAAQ;QAEV,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC;YACxC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YAC9C,CAAC,CAAC,CAAC,MAAM,MAAM,kCAAC,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC,IAAI,MAAM,IAAI,CAAC,GAAG,EAAE,EAAE,EAAC,CAAC,CAAC,OAAO,CAAA;QAE7E,OAAO,eAAe,CAAC,MAAM,CAAC,CAAA;IAChC,CAAC;IAED,OAAO,EAAE,GAAG,QAAQ,EAAE,CAAA;AACxB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAA4C;IAC1E,OAAO;QACL,GAAG,QAAQ;QACX,GAAG,KAAK;QACR,SAAS,EAAE,qBAAqB,CAAC,KAAK,EAAE,SAAS,IAAI,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC;QACrF,MAAM,EAAE,qBAAqB,CAAC,KAAK,EAAE,MAAM,IAAI,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;QACzE,SAAS,EAAE,qBAAqB,CAAC,KAAK,EAAE,SAAS,IAAI,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC;KACtF,CAAA;AACH,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAa,EAAE,KAAa;IACzD,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;IACtD,MAAM,QAAQ,GAAG,UAAU,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;IACjD,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC;QAC/F,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,cAAc,CAAC,CAAA;IACzC,OAAO,UAAU,CAAA;AACnB,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,QAAgB;IACpC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAA;QACtB,OAAO,IAAI,CAAA;IACb,CAAC;IACD,MAAM,CAAC;QACL,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC"} \ No newline at end of file diff --git a/dist-cli/lib/content.d.ts b/dist-cli/lib/content.d.ts new file mode 100644 index 0000000..da16f14 --- /dev/null +++ b/dist-cli/lib/content.d.ts @@ -0,0 +1,26 @@ +export interface DeckMetadata { + slug: string; + entry: string; + directory: string; + title: string; + description: string; + author: string; + date: string; + tags: string[]; + cover?: string; + draft: boolean; +} +export interface ValidationIssue { + level: 'error' | 'warning'; + file: string; + message: string; +} +export declare function discoverDecks(cwd?: string, slidesDir?: string): Promise; +export declare function readDeck(entry: string): Promise; +export declare function resolveDeck(input: string | undefined, cwd?: string, slidesDir?: string): Promise; +export declare function validateDeck(deck: DeckMetadata): Promise; +export declare function extractMarkdownImages(markdown: string): { + source: string; + attributes: Record; +}[]; +export declare function parseAttributes(input: string): Record; diff --git a/dist-cli/lib/content.js b/dist-cli/lib/content.js new file mode 100644 index 0000000..ae74b32 --- /dev/null +++ b/dist-cli/lib/content.js @@ -0,0 +1,124 @@ +import { access, readFile } from 'node:fs/promises'; +import path from 'node:path'; +import fg from 'fast-glob'; +import matter from 'gray-matter'; +const slugPattern = /^[a-z0-9]+(?:-[a-z0-9]+)*$/; +const allowedFits = new Set(['contain', 'cover', 'fill', 'scale-down', 'none']); +export async function discoverDecks(cwd = process.cwd(), slidesDir = 'slides') { + const entries = await fg(`${slidesDir.replaceAll('\\', '/')}/*/slides.md`, { cwd, absolute: true, onlyFiles: true }); + const decks = await Promise.all(entries.map(entry => readDeck(entry))); + return decks.sort((a, b) => compareDecks(a, b)); +} +export async function readDeck(entry) { + const source = await readFile(entry, 'utf8'); + const parsed = matter(source); + const directory = path.dirname(entry); + const slug = path.basename(directory); + const tags = Array.isArray(parsed.data.tags) + ? parsed.data.tags.map((tag) => String(tag).trim()).filter(Boolean) + : []; + return { + slug, + entry, + directory, + title: String(parsed.data.title ?? '').trim(), + description: String(parsed.data.description ?? '').trim(), + author: String(parsed.data.author ?? '').trim(), + date: normalizeDate(parsed.data.date), + tags, + cover: parsed.data.cover ? String(parsed.data.cover).trim() : undefined, + draft: parsed.data.draft === true, + }; +} +export async function resolveDeck(input, cwd = process.cwd(), slidesDir = 'slides') { + const decks = await discoverDecks(cwd, slidesDir); + if (!input) + return decks.find(deck => !deck.draft) ?? decks[0]; + const direct = path.resolve(cwd, input); + const bySlug = decks.find(deck => deck.slug === input); + const byPath = decks.find(deck => path.resolve(deck.entry) === direct); + const deck = bySlug ?? byPath; + if (!deck) + throw new Error(`找不到演示“${input}”。可用 slug:${decks.map(item => item.slug).join(', ') || '无'}`); + return deck; +} +export async function validateDeck(deck) { + const issues = []; + const source = await readFile(deck.entry, 'utf8'); + const parsed = matter(source); + if (!slugPattern.test(deck.slug)) + issues.push(error(deck.entry, '目录名必须是小写 kebab-case slug')); + if (!deck.title) + issues.push(error(deck.entry, 'frontmatter 缺少必填 title')); + if (deck.date && Number.isNaN(Date.parse(deck.date))) + issues.push(error(deck.entry, `date 不是有效日期:${deck.date}`)); + if (parsed.data.tags !== undefined && !Array.isArray(parsed.data.tags)) + issues.push(error(deck.entry, 'tags 必须是数组')); + if (parsed.data.theme && parsed.data.theme !== 'easy-jyy') + issues.push(warning(deck.entry, `当前主题为 ${parsed.data.theme},easy-jyy 主题能力可能不会生效`)); + if (deck.cover && !isRemote(deck.cover)) { + const coverPath = path.resolve(deck.directory, deck.cover); + if (!(await exists(coverPath))) + issues.push(error(deck.entry, `封面不存在:${deck.cover}`)); + } + for (const image of extractMarkdownImages(parsed.content)) { + if (!isRemote(image.source) && !image.source.startsWith('/') && !(await exists(path.resolve(deck.directory, image.source)))) + issues.push(error(deck.entry, `图片不存在:${image.source}`)); + if (image.attributes.fit && !allowedFits.has(image.attributes.fit)) + issues.push(error(deck.entry, `图片 fit 不受支持:${image.attributes.fit}`)); + if (image.attributes['max-height'] && !isSafeCssSize(image.attributes['max-height'])) + issues.push(error(deck.entry, `图片 max-height 不合法:${image.attributes['max-height']}`)); + } + return issues; +} +export function extractMarkdownImages(markdown) { + const images = []; + const pattern = /!\[[^\]]*\]\(([^)\s]+)(?:\s+["'][^"']*["'])?\)\s*(?:\{([^}]*)\})?/g; + for (const match of markdown.matchAll(pattern)) { + images.push({ + source: match[1], + attributes: parseAttributes(match[2] ?? ''), + }); + } + return images; +} +export function parseAttributes(input) { + const attributes = {}; + const pattern = /([\w-]+)=(?:"([^"]*)"|'([^']*)'|([^\s]+))/g; + for (const match of input.matchAll(pattern)) + attributes[match[1]] = match[2] ?? match[3] ?? match[4] ?? ''; + return attributes; +} +function normalizeDate(value) { + if (!value) + return ''; + if (value instanceof Date) + return value.toISOString().slice(0, 10); + return String(value).trim(); +} +function compareDecks(a, b) { + const byDate = (Date.parse(b.date || '1970-01-01') || 0) - (Date.parse(a.date || '1970-01-01') || 0); + return byDate || a.title.localeCompare(b.title, 'zh-CN'); +} +function isRemote(value) { + return /^(?:https?:)?\/\//.test(value) || value.startsWith('data:'); +} +function isSafeCssSize(value) { + return /^(?:\d+(?:\.\d+)?)(?:px|rem|em|vh|vw|%|vmin|vmax)$/.test(value); +} +async function exists(file) { + try { + await access(file); + return true; + } + catch { + return false; + } +} +function error(file, message) { + return { level: 'error', file, message }; +} +function warning(file, message) { + return { level: 'warning', file, message }; +} +//# sourceMappingURL=content.js.map \ No newline at end of file diff --git a/dist-cli/lib/content.js.map b/dist-cli/lib/content.js.map new file mode 100644 index 0000000..f1e71ca --- /dev/null +++ b/dist-cli/lib/content.js.map @@ -0,0 +1 @@ +{"version":3,"file":"content.js","sourceRoot":"","sources":["../../scripts/lib/content.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist-cli/lib/dev-overflow-audit.d.ts b/dist-cli/lib/dev-overflow-audit.d.ts new file mode 100644 index 0000000..3322821 --- /dev/null +++ b/dist-cli/lib/dev-overflow-audit.d.ts @@ -0,0 +1,13 @@ +import type { DeckMetadata } from './content.ts'; +interface DevOverflowAuditOptions { + cwd?: string; + debounceMs?: number; + deck: DeckMetadata; + output?: (line: string) => void; +} +export interface DevOverflowAuditController { + close: () => Promise; + ready: Promise; +} +export declare function startDevOverflowAudit(options: DevOverflowAuditOptions): DevOverflowAuditController; +export {}; diff --git a/dist-cli/lib/dev-overflow-audit.js b/dist-cli/lib/dev-overflow-audit.js new file mode 100644 index 0000000..2759354 --- /dev/null +++ b/dist-cli/lib/dev-overflow-audit.js @@ -0,0 +1,90 @@ +import { watch } from 'node:fs'; +import path from 'node:path'; +import { formatStaticOverflowResult, staticOverflowFingerprint } from "./overflow-report.js"; +import { StaticOverflowAuditor } from "./static-overflow.js"; +export function startDevOverflowAudit(options) { + const auditor = new StaticOverflowAuditor(); + const cwd = options.cwd ?? process.cwd(); + const debounceMs = options.debounceMs ?? 250; + const output = options.output ?? console.log; + let activeAudit; + let closed = false; + let fingerprint = ''; + let queued = false; + let timer; + let watcher; + function scheduleAudit(delay = debounceMs) { + if (closed) + return; + if (timer) + clearTimeout(timer); + timer = setTimeout(() => { + timer = undefined; + void runAudit(); + }, delay); + } + async function runAudit() { + if (closed) + return; + if (activeAudit) { + queued = true; + return activeAudit; + } + activeAudit = auditor.audit([options.deck]) + .then((result) => { + if (closed) + return; + const nextFingerprint = staticOverflowFingerprint(result); + if (nextFingerprint !== fingerprint) { + fingerprint = nextFingerprint; + formatStaticOverflowResult(result, cwd).forEach(line => output(line)); + } + }) + .catch((error) => { + if (closed) + return; + const message = error instanceof Error ? error.message : String(error); + const nextFingerprint = `error:${message}`; + if (nextFingerprint !== fingerprint) { + fingerprint = nextFingerprint; + output(`WARN ${path.relative(cwd, options.deck.entry)}: 无法完成静态内容检查:${message}`); + } + }) + .finally(() => { + activeAudit = undefined; + if (queued) { + queued = false; + scheduleAudit(0); + } + }); + return activeAudit; + } + function startWatcher() { + const handleChange = () => scheduleAudit(); + try { + watcher = watch(options.deck.directory, { recursive: true }, handleChange); + } + catch { + watcher = watch(options.deck.entry, handleChange); + } + } + const ready = (async () => { + output('\n检查开发内容中的静态溢出风险...'); + startWatcher(); + await runAudit(); + })(); + return { + ready, + async close() { + if (closed) + return; + closed = true; + watcher?.close(); + if (timer) + clearTimeout(timer); + await ready.catch(() => undefined); + await activeAudit?.catch(() => undefined); + }, + }; +} +//# sourceMappingURL=dev-overflow-audit.js.map \ No newline at end of file diff --git a/dist-cli/lib/dev-overflow-audit.js.map b/dist-cli/lib/dev-overflow-audit.js.map new file mode 100644 index 0000000..db7cb25 --- /dev/null +++ b/dist-cli/lib/dev-overflow-audit.js.map @@ -0,0 +1 @@ +{"version":3,"file":"dev-overflow-audit.js","sourceRoot":"","sources":["../../scripts/lib/dev-overflow-audit.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist-cli/lib/overflow-audit.d.ts b/dist-cli/lib/overflow-audit.d.ts new file mode 100644 index 0000000..6f93320 --- /dev/null +++ b/dist-cli/lib/overflow-audit.d.ts @@ -0,0 +1,37 @@ +export interface OverflowAuditDeck { + entry: string; + slug: string; +} +export interface SlideOverflowIssue { + deck: OverflowAuditDeck; + heading: string; + horizontal: number; + slide: number; + vertical: number; +} +export interface OverflowAuditResult { + errors: Array<{ + deck: OverflowAuditDeck; + message: string; + }>; + issues: SlideOverflowIssue[]; +} +interface OverflowAuditOptions { + decks: OverflowAuditDeck[]; + root: string; + siteBase: string; +} +export interface OverflowAuditTarget { + deck: OverflowAuditDeck; + routerMode?: 'hash' | 'history'; + url: string; +} +export declare class OverflowAuditor { + private browser?; + private page?; + audit(targets: OverflowAuditTarget[]): Promise; + close(): Promise; + private ensurePage; +} +export declare function auditBuiltDecks(options: OverflowAuditOptions): Promise; +export {}; diff --git a/dist-cli/lib/overflow-audit.js b/dist-cli/lib/overflow-audit.js new file mode 100644 index 0000000..d341a9f --- /dev/null +++ b/dist-cli/lib/overflow-audit.js @@ -0,0 +1,228 @@ +import { createReadStream } from 'node:fs'; +import { stat } from 'node:fs/promises'; +import { createServer } from 'node:http'; +import path from 'node:path'; +import { chromium } from 'playwright-chromium'; +const overflowTolerance = 2; +export class OverflowAuditor { + browser; + page; + async audit(targets) { + const page = await this.ensurePage(); + const result = { errors: [], issues: [] }; + for (const target of targets) { + try { + result.issues.push(...await auditDeck(page, target)); + } + catch (error) { + result.errors.push({ + deck: target.deck, + message: error instanceof Error ? error.message : String(error), + }); + } + } + return result; + } + async close() { + await this.browser?.close(); + this.browser = undefined; + this.page = undefined; + } + async ensurePage() { + if (this.page && !this.page.isClosed()) + return this.page; + await this.browser?.close().catch(() => undefined); + this.browser = await chromium.launch({ headless: true }); + const context = await this.browser.newContext({ viewport: { height: 900, width: 1200 } }); + await context.addInitScript(() => { + Object.defineProperty(navigator, 'wakeLock', { + configurable: true, + value: { + async request(type) { + const sentinel = new EventTarget(); + sentinel.released = false; + sentinel.type = type; + sentinel.release = async () => { + if (sentinel.released) + return; + sentinel.released = true; + sentinel.dispatchEvent(new Event('release')); + }; + return sentinel; + }, + }, + }); + }); + this.page = await context.newPage(); + return this.page; + } +} +export async function auditBuiltDecks(options) { + const server = await startStaticServer(options.root, options.siteBase); + const address = server.address(); + const origin = `http://127.0.0.1:${address.port}`; + const auditor = new OverflowAuditor(); + try { + return await auditor.audit(options.decks.map(deck => ({ + deck, + url: new URL(`${options.siteBase}${deck.slug}/`.replace(/\/{2,}/g, '/'), origin).href, + }))); + } + finally { + await auditor.close(); + await new Promise(resolve => server.close(() => resolve())); + } +} +async function auditDeck(page, target) { + const issues = []; + const overviewUrl = auditRouteUrl(target, 'overview'); + await page.goto(overviewUrl.href, { timeout: 30_000, waitUntil: 'networkidle' }); + await page.locator('.slidev-layout').first().waitFor({ state: 'attached', timeout: 15_000 }); + await waitForPageAssets(page); + const slideNumbers = await page.locator('[class*="slidev-page-"]').evaluateAll((pages) => { + const numbers = pages.flatMap((page) => { + const pageClass = Array.from(page.classList).find(className => /^slidev-page-\d+$/.test(className)); + const number = Number.parseInt(pageClass?.replace('slidev-page-', '') ?? '', 10); + return Number.isFinite(number) ? [number] : []; + }); + return Array.from(new Set(numbers)).sort((a, b) => a - b); + }); + if (slideNumbers.length && target.routerMode !== 'history') { + await page.evaluate((number) => { + window.location.hash = `#/${number}`; + }, slideNumbers[0]); + await page.reload({ timeout: 30_000, waitUntil: 'networkidle' }); + await page.evaluate(async () => { + await document.fonts?.ready; + }); + } + for (const slide of slideNumbers) { + if (target.routerMode === 'history') + await page.goto(auditRouteUrl(target, String(slide)).href, { timeout: 30_000, waitUntil: 'networkidle' }); + else + await page.evaluate((number) => { + window.location.hash = `#/${number}`; + }, slide); + await page.waitForFunction((number) => { + const layouts = Array.from(document.querySelectorAll(`.slidev-page-${number} .slidev-layout`)); + return layouts.some(layout => layout.getBoundingClientRect().width > 0); + }, slide, { timeout: 10_000 }); + await waitForSlideAssets(page, slide); + await page.evaluate(() => new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(() => resolve())))); + const measurement = await page.evaluate((number) => { + const layouts = Array.from(document.querySelectorAll(`.slidev-page-${number} .slidev-layout`)); + const layout = layouts.find(item => item.getBoundingClientRect().width > 0) ?? layouts[0]; + return { + heading: layout?.querySelector('h1, h2, h3')?.textContent?.trim() ?? '', + horizontal: layout ? Math.max(0, Math.ceil(layout.scrollWidth - layout.clientWidth)) : 0, + slide: number, + vertical: layout ? Math.max(0, Math.ceil(layout.scrollHeight - layout.clientHeight)) : 0, + }; + }, slide); + if (measurement.vertical <= overflowTolerance && measurement.horizontal <= overflowTolerance) + continue; + issues.push({ deck: target.deck, ...measurement }); + } + return issues; +} +function auditRouteUrl(target, route) { + const url = target.routerMode === 'history' + ? new URL(`${route.replace(/^\/+/, '')}${route === 'overview' ? '/' : ''}`, ensureTrailingSlash(target.url)) + : new URL(target.url); + url.searchParams.set('easy-slides-audit', '1'); + if (target.routerMode !== 'history') + url.hash = `#/${route}`; + return url; +} +function ensureTrailingSlash(value) { + return value.endsWith('/') ? value : `${value}/`; +} +async function waitForPageAssets(page) { + await page.evaluate(async () => { + await document.fonts?.ready; + const images = Array.from(document.images); + await Promise.race([ + Promise.all(images.map(image => image.complete + ? Promise.resolve() + : new Promise((resolve) => { + image.addEventListener('load', () => resolve(), { once: true }); + image.addEventListener('error', () => resolve(), { once: true }); + }))), + new Promise(resolve => setTimeout(resolve, 5_000)), + ]); + }); +} +async function waitForSlideAssets(page, slide) { + await page.evaluate(async (number) => { + const layout = Array.from(document.querySelectorAll(`.slidev-page-${number} .slidev-layout`)) + .find(item => item.getBoundingClientRect().width > 0); + const images = Array.from(layout?.querySelectorAll('img') ?? []); + await Promise.race([ + Promise.all(images.map(image => image.complete + ? Promise.resolve() + : new Promise((resolve) => { + image.addEventListener('load', () => resolve(), { once: true }); + image.addEventListener('error', () => resolve(), { once: true }); + }))), + new Promise(resolve => setTimeout(resolve, 5_000)), + ]); + }, slide); +} +async function startStaticServer(root, siteBase) { + const server = createServer(async (request, response) => { + if (request.method !== 'GET' && request.method !== 'HEAD') { + response.writeHead(405).end(); + return; + } + try { + const requestUrl = new URL(request.url ?? '/', 'http://127.0.0.1'); + const file = await resolveStaticFile(root, requestUrl.pathname, siteBase); + response.statusCode = 200; + response.setHeader('Content-Type', contentType(file)); + if (request.method === 'HEAD') { + response.end(); + return; + } + createReadStream(file).pipe(response); + } + catch { + response.writeHead(404).end('Not found'); + } + }); + await new Promise((resolve, reject) => { + server.once('error', reject); + server.listen(0, '127.0.0.1', () => resolve()); + }); + return server; +} +async function resolveStaticFile(root, requestPath, siteBase) { + let pathname = decodeURIComponent(requestPath); + const basePrefix = siteBase === '/' ? '' : siteBase.replace(/\/$/, ''); + if (basePrefix && pathname.startsWith(`${basePrefix}/`)) + pathname = pathname.slice(basePrefix.length); + const candidate = path.resolve(root, pathname.replace(/^\/+/, '')); + const relative = path.relative(root, candidate); + if (relative.startsWith('..') || path.isAbsolute(relative)) + throw new Error('Path outside static root'); + const details = await stat(candidate); + return details.isDirectory() ? path.join(candidate, 'index.html') : candidate; +} +function contentType(file) { + const extension = path.extname(file).toLowerCase(); + return { + '.css': 'text/css; charset=utf-8', + '.gif': 'image/gif', + '.html': 'text/html; charset=utf-8', + '.jpeg': 'image/jpeg', + '.jpg': 'image/jpeg', + '.js': 'text/javascript; charset=utf-8', + '.json': 'application/json; charset=utf-8', + '.png': 'image/png', + '.svg': 'image/svg+xml', + '.ttf': 'font/ttf', + '.webp': 'image/webp', + '.woff': 'font/woff', + '.woff2': 'font/woff2', + }[extension] ?? 'application/octet-stream'; +} +//# sourceMappingURL=overflow-audit.js.map \ No newline at end of file diff --git a/dist-cli/lib/overflow-audit.js.map b/dist-cli/lib/overflow-audit.js.map new file mode 100644 index 0000000..5358f4f --- /dev/null +++ b/dist-cli/lib/overflow-audit.js.map @@ -0,0 +1 @@ +{"version":3,"file":"overflow-audit.js","sourceRoot":"","sources":["../../scripts/lib/overflow-audit.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist-cli/lib/overflow-report.d.ts b/dist-cli/lib/overflow-report.d.ts new file mode 100644 index 0000000..219a495 --- /dev/null +++ b/dist-cli/lib/overflow-report.d.ts @@ -0,0 +1,6 @@ +import type { OverflowAuditResult } from './overflow-audit.ts'; +import type { StaticOverflowResult } from './static-overflow.ts'; +export declare function formatOverflowAuditResult(result: OverflowAuditResult, cwd?: string): string[]; +export declare function overflowAuditFingerprint(result: OverflowAuditResult): string; +export declare function formatStaticOverflowResult(result: StaticOverflowResult, cwd?: string): string[]; +export declare function staticOverflowFingerprint(result: StaticOverflowResult): string; diff --git a/dist-cli/lib/overflow-report.js b/dist-cli/lib/overflow-report.js new file mode 100644 index 0000000..c3e1016 --- /dev/null +++ b/dist-cli/lib/overflow-report.js @@ -0,0 +1,58 @@ +import path from 'node:path'; +const overflowTolerance = 2; +export function formatOverflowAuditResult(result, cwd = process.cwd()) { + const lines = []; + for (const issue of result.issues) { + const dimensions = [ + issue.vertical > overflowTolerance ? `纵向 ${issue.vertical}px` : '', + issue.horizontal > overflowTolerance ? `横向 ${issue.horizontal}px` : '', + ].filter(Boolean).join('、'); + const heading = issue.heading ? `(${issue.heading})` : ''; + lines.push(`WARN ${path.relative(cwd, issue.deck.entry)}: 第 ${issue.slide} 页${heading}内容溢出:${dimensions};放映时可上下滚动,请优先拆页或精简内容`); + } + for (const error of result.errors) + lines.push(`WARN ${path.relative(cwd, error.deck.entry)}: 无法完成内容溢出检查:${error.message}`); + if (!lines.length) + lines.push('内容边界检查通过:未发现溢出'); + return lines; +} +export function overflowAuditFingerprint(result) { + return JSON.stringify({ + errors: result.errors.map(error => [error.deck.entry, error.message]), + issues: result.issues.map(issue => [ + issue.deck.entry, + issue.slide, + issue.heading, + issue.horizontal, + issue.vertical, + ]), + }); +} +export function formatStaticOverflowResult(result, cwd = process.cwd()) { + const lines = []; + for (const issue of result.issues) { + const directions = issue.directions + .map(direction => direction === 'vertical' ? '纵向' : '横向') + .join('、'); + const heading = issue.heading ? `(${issue.heading})` : ''; + lines.push(`WARN ${path.relative(cwd, issue.deck.entry)}: 第 ${issue.slide} 页${heading}存在静态${directions}溢出风险:${issue.reason};请优先拆页或精简内容(最终以 build 渲染检查为准)`); + } + for (const error of result.errors) + lines.push(`WARN ${path.relative(cwd, error.deck.entry)}: 无法完成静态内容检查:${error.message}`); + if (!lines.length) + lines.push('静态内容检查通过:未发现明显溢出风险(最终以 build 渲染检查为准)'); + return lines; +} +export function staticOverflowFingerprint(result) { + return JSON.stringify({ + errors: result.errors.map(error => [error.deck.entry, error.message]), + issues: result.issues.map(issue => [ + issue.deck.entry, + issue.slide, + issue.heading, + issue.directions, + issue.reason, + ]), + }); +} +//# sourceMappingURL=overflow-report.js.map \ No newline at end of file diff --git a/dist-cli/lib/overflow-report.js.map b/dist-cli/lib/overflow-report.js.map new file mode 100644 index 0000000..189c3f6 --- /dev/null +++ b/dist-cli/lib/overflow-report.js.map @@ -0,0 +1 @@ +{"version":3,"file":"overflow-report.js","sourceRoot":"","sources":["../../scripts/lib/overflow-report.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist-cli/lib/run-slidev.d.ts b/dist-cli/lib/run-slidev.d.ts new file mode 100644 index 0000000..012b6d3 --- /dev/null +++ b/dist-cli/lib/run-slidev.d.ts @@ -0,0 +1,8 @@ +import type { ChildProcess } from 'node:child_process'; +interface RunSlidevOptions { + env?: NodeJS.ProcessEnv; +} +export declare function startSlidev(args: string[], options?: RunSlidevOptions): ChildProcess; +export declare function waitForSlidev(child: ChildProcess): Promise; +export declare function runSlidev(args: string[], options?: RunSlidevOptions): Promise; +export {}; diff --git a/dist-cli/lib/run-slidev.js b/dist-cli/lib/run-slidev.js new file mode 100644 index 0000000..73df963 --- /dev/null +++ b/dist-cli/lib/run-slidev.js @@ -0,0 +1,33 @@ +import { spawn } from 'node:child_process'; +import { createRequire } from 'node:module'; +import { hashPresenterToken } from "./token.js"; +const require = createRequire(import.meta.url); +const slidevCli = require.resolve('@slidev/cli/bin/slidev.mjs'); +export function startSlidev(args, options = {}) { + const token = options.env?.PRESENTER_TOKEN ?? process.env.PRESENTER_TOKEN; + const presenterHash = token?.trim() ? hashPresenterToken(token) : ''; + return spawn(process.execPath, [slidevCli, ...args], { + cwd: process.cwd(), + env: { + ...process.env, + ...options.env, + VITE_EASY_SLIDES_PRESENTER_HASH: presenterHash, + }, + stdio: 'inherit', + }); +} +export async function waitForSlidev(child) { + await new Promise((resolve, reject) => { + child.once('error', reject); + child.once('exit', (code, signal) => { + if (code === 0) + resolve(); + else + reject(new Error(`Slidev 退出:${signal ?? `code ${code}`}`)); + }); + }); +} +export async function runSlidev(args, options = {}) { + await waitForSlidev(startSlidev(args, options)); +} +//# sourceMappingURL=run-slidev.js.map \ No newline at end of file diff --git a/dist-cli/lib/run-slidev.js.map b/dist-cli/lib/run-slidev.js.map new file mode 100644 index 0000000..794ab9a --- /dev/null +++ b/dist-cli/lib/run-slidev.js.map @@ -0,0 +1 @@ +{"version":3,"file":"run-slidev.js","sourceRoot":"","sources":["../../scripts/lib/run-slidev.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAE1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAE/C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAC9C,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,4BAA4B,CAAC,CAAA;AAM/D,MAAM,UAAU,WAAW,CAAC,IAAc,EAAE,UAA4B,EAAE;IACxE,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,eAAe,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,CAAA;IACzE,MAAM,aAAa,GAAG,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IACpE,OAAO,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,EAAE;QACnD,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;QAClB,GAAG,EAAE;YACH,GAAG,OAAO,CAAC,GAAG;YACd,GAAG,OAAO,CAAC,GAAG;YACd,+BAA+B,EAAE,aAAa;SAC/C;QACD,KAAK,EAAE,SAAS;KACjB,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAmB;IACrD,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QAC3B,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE;YAClC,IAAI,IAAI,KAAK,CAAC;gBACZ,OAAO,EAAE,CAAA;;gBAET,MAAM,CAAC,IAAI,KAAK,CAAC,aAAa,MAAM,IAAI,QAAQ,IAAI,EAAE,EAAE,CAAC,CAAC,CAAA;QAC9D,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAc,EAAE,UAA4B,EAAE;IAC5E,MAAM,aAAa,CAAC,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAA;AACjD,CAAC"} \ No newline at end of file diff --git a/dist-cli/lib/site-base.d.ts b/dist-cli/lib/site-base.d.ts new file mode 100644 index 0000000..b0ea1e8 --- /dev/null +++ b/dist-cli/lib/site-base.d.ts @@ -0,0 +1,2 @@ +export declare function normalizeSiteBase(value?: string): string; +export declare function joinBase(base: string, ...parts: string[]): string; diff --git a/dist-cli/lib/site-base.js b/dist-cli/lib/site-base.js new file mode 100644 index 0000000..6804381 --- /dev/null +++ b/dist-cli/lib/site-base.js @@ -0,0 +1,15 @@ +export function normalizeSiteBase(value = '/') { + const trimmed = value.trim(); + if (!trimmed || trimmed === '/') + return '/'; + return `/${trimmed.replace(/^\/+|\/+$/g, '')}/`; +} +export function joinBase(base, ...parts) { + const normalized = normalizeSiteBase(base); + const suffix = parts + .map(part => part.replace(/^\/+|\/+$/g, '')) + .filter(Boolean) + .join('/'); + return suffix ? `${normalized}${suffix}/` : normalized; +} +//# sourceMappingURL=site-base.js.map \ No newline at end of file diff --git a/dist-cli/lib/site-base.js.map b/dist-cli/lib/site-base.js.map new file mode 100644 index 0000000..0159098 --- /dev/null +++ b/dist-cli/lib/site-base.js.map @@ -0,0 +1 @@ +{"version":3,"file":"site-base.js","sourceRoot":"","sources":["../../scripts/lib/site-base.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,iBAAiB,CAAC,KAAK,GAAG,GAAG;IAC3C,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAA;IAC5B,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,GAAG;QAC7B,OAAO,GAAG,CAAA;IAEZ,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,GAAG,CAAA;AACjD,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,GAAG,KAAe;IACvD,MAAM,UAAU,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAA;IAC1C,MAAM,MAAM,GAAG,KAAK;SACjB,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;SAC3C,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,CAAA;IAEZ,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,UAAU,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC,UAAU,CAAA;AACxD,CAAC"} \ No newline at end of file diff --git a/dist-cli/lib/static-overflow.d.ts b/dist-cli/lib/static-overflow.d.ts new file mode 100644 index 0000000..861f013 --- /dev/null +++ b/dist-cli/lib/static-overflow.d.ts @@ -0,0 +1,28 @@ +import type { DeckMetadata } from './content.ts'; +export type StaticOverflowDirection = 'horizontal' | 'vertical'; +export interface StaticOverflowIssue { + deck: DeckMetadata; + directions: StaticOverflowDirection[]; + heading: string; + reason: string; + slide: number; +} +export interface StaticOverflowResult { + errors: Array<{ + deck: DeckMetadata; + message: string; + }>; + issues: StaticOverflowIssue[]; +} +interface StaticOverflowAuditorOptions { + onAnalyzeSlide?: (deck: DeckMetadata, slide: number) => void; +} +export declare class StaticOverflowAuditor { + private cache; + private onAnalyzeSlide?; + constructor(options?: StaticOverflowAuditorOptions); + audit(decks: DeckMetadata[]): Promise; + private auditDeck; +} +export declare function auditStaticDecks(decks: DeckMetadata[]): Promise; +export {}; diff --git a/dist-cli/lib/static-overflow.js b/dist-cli/lib/static-overflow.js new file mode 100644 index 0000000..c67e9d4 --- /dev/null +++ b/dist-cli/lib/static-overflow.js @@ -0,0 +1,313 @@ +import { readFile } from 'node:fs/promises'; +import { parseSync } from '@slidev/parser'; +const canvasHeight = 768; +const canvasWidth = 1024; +const slidePaddingX = 52; +const slidePaddingY = 42; +const contentHeight = canvasHeight - slidePaddingY * 2; +const contentWidth = canvasWidth - slidePaddingX * 2; +const twoColumnGap = 46; +const baseFontSize = 32; +const baseLineHeight = baseFontSize * 1.42; +const verticalRiskTolerance = 1.08; +const codeHeightPresets = new Map([ + ['easy-code-height-sm', 180], + ['easy-code-height-md', 300], + ['easy-code-height-lg', 420], +]); +export class StaticOverflowAuditor { + cache = new Map(); + onAnalyzeSlide; + constructor(options = {}) { + this.onAnalyzeSlide = options.onAnalyzeSlide; + } + async audit(decks) { + const result = { errors: [], issues: [] }; + for (const deck of decks) { + try { + result.issues.push(...await this.auditDeck(deck)); + } + catch (error) { + result.errors.push({ + deck, + message: error instanceof Error ? error.message : String(error), + }); + } + } + return result; + } + async auditDeck(deck) { + const source = await readFile(deck.entry, 'utf8'); + const parsed = parseSync(source, deck.entry); + const previous = this.cache.get(deck.entry) ?? new Map(); + const next = new Map(); + const issues = []; + parsed.slides.forEach((slide, index) => { + const number = index + 1; + const fingerprint = slide.revision ?? slide.raw; + const cached = previous.get(number); + if (cached?.fingerprint === fingerprint) { + next.set(number, cached); + issues.push(...cached.issues); + return; + } + this.onAnalyzeSlide?.(deck, number); + const slideIssues = analyzeSlide(deck, number, slide); + next.set(number, { fingerprint, issues: slideIssues }); + issues.push(...slideIssues); + }); + this.cache.set(deck.entry, next); + return issues; + } +} +export async function auditStaticDecks(decks) { + return await new StaticOverflowAuditor().audit(decks); +} +function analyzeSlide(deck, number, slide) { + const content = stripComments(slide.content); + const layout = String(slide.frontmatter.layout ?? (number === 1 ? 'cover' : 'default')); + const classNames = normalizeClasses(slide.frontmatter.class); + const heading = slide.title?.trim() || extractHeading(content); + const estimates = estimateSlide(content, layout, classNames, String(slide.frontmatter.imagePlacement ?? 'auto')); + const directions = []; + if (estimates.some(estimate => estimate.height > contentHeight * verticalRiskTolerance)) + directions.push('vertical'); + if (estimates.some(estimate => estimate.horizontalRisk)) + directions.push('horizontal'); + if (!directions.length) + return []; + const reason = directions.length === 2 + ? '估算内容高度超过画布容量,且存在无法可靠换行的宽内容' + : directions[0] === 'vertical' + ? '估算内容高度超过 easy-jyy 画布容量' + : '存在无法可靠换行的宽内容'; + return [{ deck, directions, heading, reason, slide: number }]; +} +function estimateSlide(content, layout, classNames, imagePlacement) { + if (layout === 'two-cols') { + const slots = splitTwoColumnContent(content); + const headingEstimate = estimateRegion(slots.before, contentWidth, layout, classNames); + const columnWidth = (contentWidth - twoColumnGap) / 2; + const left = estimateRegion(slots.left, columnWidth, layout, classNames); + const right = estimateRegion(slots.right, columnWidth, layout, classNames); + return [ + { + height: headingEstimate.height + Math.max(left.height, right.height), + horizontalRisk: headingEstimate.horizontalRisk || left.horizontalRisk || right.horizontalRisk, + }, + ]; + } + const splitImageLayout = ['image-left', 'image-right'].includes(layout) + || (layout === 'image-auto' && ['left', 'right'].includes(imagePlacement)); + const width = splitImageLayout ? (contentWidth - 42) / 2 : contentWidth; + return [estimateRegion(content, width, layout, classNames)]; +} +function splitTwoColumnContent(content) { + const leftMarker = /^::left::\s*$/m; + const rightMarker = /^::right::\s*$/m; + const leftMatch = leftMarker.exec(content); + const rightMatch = rightMarker.exec(content); + if (!leftMatch && !rightMatch) + return { before: content, left: '', right: '' }; + const firstIndex = Math.min(leftMatch?.index ?? Number.POSITIVE_INFINITY, rightMatch?.index ?? Number.POSITIVE_INFINITY); + const before = content.slice(0, firstIndex); + const left = leftMatch + ? content.slice(leftMatch.index + leftMatch[0].length, rightMatch && rightMatch.index > leftMatch.index ? rightMatch.index : undefined) + : ''; + const right = rightMatch + ? content.slice(rightMatch.index + rightMatch[0].length, leftMatch && leftMatch.index > rightMatch.index ? leftMatch.index : undefined) + : ''; + return { before, left, right }; +} +function estimateRegion(markdown, width, layout, classNames) { + const lines = markdown.replace(/\r/g, '').split('\n'); + let height = 0; + let horizontalRisk = false; + for (let index = 0; index < lines.length;) { + const raw = lines[index]; + const line = raw.trim(); + if (!line || isStructuralLine(line)) { + index++; + continue; + } + const fence = /^(?:`{3,}|~{3,})([^\s{]*)/.exec(line); + if (fence) { + const marker = line.startsWith('`') ? '`' : '~'; + const markerLength = line.match(new RegExp(`^\\${marker}+`))?.[0].length ?? 3; + const language = fence[1].toLowerCase(); + let end = index + 1; + while (end < lines.length && !new RegExp(`^\\s*\\${marker}{${markerLength},}`).test(lines[end])) + end++; + if (language === 'mermaid') + height += 180; + else + height += explicitCodeHeight(lines, index, classNames); + index = Math.min(lines.length, end + 1); + continue; + } + const heading = /^(#{1,4})\s+(.+)$/.exec(line); + if (heading) { + const level = heading[1].length; + const fontSize = level === 1 ? (layout === 'cover' ? 68 : 60) : level === 2 ? 48 : level === 3 ? 38 : 32; + const wraps = wrappedLines(heading[2], width, fontSize); + const margins = level === 1 ? 26 : level === 2 ? 39 : level === 3 ? 34 : 24; + height += wraps * fontSize * 1.15 + margins; + horizontalRisk ||= hasHorizontalRisk(heading[2], width, fontSize); + index++; + continue; + } + if (line === '$$' || line.startsWith('$$')) { + let end = index + 1; + while (end < lines.length && !lines[end].includes('$$')) + end++; + height += 82 + Math.max(0, end - index - 2) * 38; + index = Math.min(lines.length, end + 1); + continue; + } + if (isStandaloneImage(line)) { + height += canvasHeight * 0.46 + 16; + index++; + continue; + } + if (isTableRow(line) && isTableSeparator(lines[index + 1] ?? '')) { + const tableLines = [line]; + index += 2; + while (index < lines.length && isTableRow(lines[index].trim())) { + tableLines.push(lines[index].trim()); + index++; + } + const columnCount = Math.max(1, splitTableRow(tableLines[0]).length); + const cellWidth = width / columnCount - 28; + for (const row of tableLines) { + const rowWraps = Math.max(...splitTableRow(row).map(cell => wrappedLines(cell, cellWidth, 30)), 1); + height += rowWraps * 30 * 1.42 + 20; + } + continue; + } + if (isListLine(line)) { + const items = []; + while (index < lines.length && (isListLine(lines[index].trim()) || /^\s{2,}\S/.test(lines[index]))) { + if (isListLine(lines[index].trim())) + items.push(lines[index].trim().replace(/^(?:[-+*]|\d+[.)])\s+/, '')); + index++; + } + const itemHeight = items.reduce((sum, item) => sum + wrappedLines(item, width - baseFontSize * 1.2, baseFontSize) * baseLineHeight, 0); + height += itemHeight + Math.max(0, items.length - 1) * 10 + 28; + horizontalRisk ||= items.some(item => hasHorizontalRisk(item, width - baseFontSize * 1.2, baseFontSize)); + continue; + } + if (line.startsWith('>')) { + const quote = []; + while (index < lines.length && lines[index].trim().startsWith('>')) { + quote.push(lines[index].trim().replace(/^>\s?/, '')); + index++; + } + const fontSize = layout === 'quote' ? 46 : baseFontSize; + height += wrappedLines(quote.join(' '), width - 29, fontSize) * fontSize * (layout === 'quote' ? 1.35 : 1.42) + 48; + horizontalRisk ||= hasHorizontalRisk(quote.join(' '), width - 29, fontSize); + continue; + } + const paragraph = []; + while (index < lines.length && !isBlockStart(lines, index)) { + const text = stripMarkup(lines[index]); + if (text) + paragraph.push(text); + index++; + } + if (paragraph.length) { + const text = paragraph.join(' '); + height += wrappedLines(text, width, baseFontSize) * baseLineHeight + 28; + horizontalRisk ||= hasHorizontalRisk(text, width, baseFontSize); + } + else { + index++; + } + } + horizontalRisk ||= explicitWidthRisk(markdown, width); + return { height, horizontalRisk }; +} +function isBlockStart(lines, index) { + const line = lines[index].trim(); + if (!line || isStructuralLine(line) || /^(?:`{3,}|~{3,}|#{1,4}\s|\$\$|>)/.test(line)) + return true; + if (isStandaloneImage(line) || isListLine(line)) + return true; + return isTableRow(line) && isTableSeparator(lines[index + 1] ?? ''); +} +function explicitCodeHeight(lines, fenceIndex, classNames) { + const nearby = `${classNames.join(' ')} ${lines.slice(Math.max(0, fenceIndex - 8), fenceIndex + 1).join(' ')}`; + for (const [className, height] of codeHeightPresets) { + if (new RegExp(`(?:^|\\s|["'])${className}(?:$|\\s|["'])`).test(nearby)) + return height; + } + const inlineHeight = /(?:height|max-height)\s*:\s*(\d+(?:\.\d+)?)px/i.exec(nearby); + return inlineHeight ? Number.parseFloat(inlineHeight[1]) : 0; +} +function wrappedLines(value, width, fontSize) { + const available = Math.max(1, width / fontSize); + return Math.max(1, Math.ceil(displayWidth(stripMarkup(value)) / available)); +} +function displayWidth(value) { + let width = 0; + for (const character of value) { + if (/\s/.test(character)) + width += 0.33; + else if (/[\u1100-\u115f\u2e80-\ua4cf\uac00-\ud7a3\uf900-\ufaff\ufe10-\ufe6f\uff01-\uff60\uffe0-\uffe6]/.test(character)) + width += 1; + else + width += 0.56; + } + return width; +} +function hasHorizontalRisk(value, width, fontSize) { + const available = width / fontSize; + return stripMarkup(value) + .split(/\s+/) + .some(token => !/[\u2e80-\u9fff]/.test(token) && displayWidth(token) > available * 1.05); +} +function explicitWidthRisk(markdown, width) { + for (const match of markdown.matchAll(/(?:width\s*:\s*|width\s*=\s*["']?)(\d+(?:\.\d+)?)px/gi)) { + if (Number.parseFloat(match[1]) > width) + return true; + } + return false; +} +function normalizeClasses(value) { + if (Array.isArray(value)) + return value.flatMap(item => String(item).split(/\s+/)).filter(Boolean); + return String(value ?? '').split(/\s+/).filter(Boolean); +} +function extractHeading(markdown) { + return /^(?:#{1,4})\s+(.+)$/m.exec(markdown)?.[1].trim() ?? ''; +} +function stripComments(markdown) { + return markdown.replace(//g, ''); +} +function stripMarkup(value) { + return value + .replace(/!\[[^\]]*\]\([^)]*\)(?:\{[^}]*\})?/g, '') + .replace(/\[([^\]]+)\]\([^)]*\)/g, '$1') + .replace(/<[^>]+>/g, ' ') + .replace(/[`*_~]/g, '') + .trim(); +} +function isStructuralLine(line) { + return /^::(?:left|right|image)::$/i.test(line) + || /^<\/?(?:v-clicks|div|span|template|slot)(?:\s[^>]*)?>$/i.test(line); +} +function isStandaloneImage(line) { + return /^!\[[^\]]*\]\([^)]*\)(?:\{[^}]*\})?$/.test(line); +} +function isListLine(line) { + return /^(?:[-+*]|\d+[.)])\s+/.test(line); +} +function isTableRow(line) { + return line.includes('|'); +} +function isTableSeparator(line) { + return /^\s*\|?\s*:?-{3,}:?(?:\s*\|\s*:?-{3,}:?)+\s*\|?\s*$/.test(line); +} +function splitTableRow(line) { + return line.replace(/^\s*\||\|\s*$/g, '').split('|').map(cell => cell.trim()); +} +//# sourceMappingURL=static-overflow.js.map \ No newline at end of file diff --git a/dist-cli/lib/static-overflow.js.map b/dist-cli/lib/static-overflow.js.map new file mode 100644 index 0000000..0403bcd --- /dev/null +++ b/dist-cli/lib/static-overflow.js.map @@ -0,0 +1 @@ +{"version":3,"file":"static-overflow.js","sourceRoot":"","sources":["../../scripts/lib/static-overflow.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist-cli/lib/theme.d.ts b/dist-cli/lib/theme.d.ts new file mode 100644 index 0000000..69d8815 --- /dev/null +++ b/dist-cli/lib/theme.d.ts @@ -0,0 +1 @@ +export declare function resolveTheme(theme?: string): string; diff --git a/dist-cli/lib/theme.js b/dist-cli/lib/theme.js new file mode 100644 index 0000000..dcbeb5d --- /dev/null +++ b/dist-cli/lib/theme.js @@ -0,0 +1,16 @@ +import { existsSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +const directory = path.dirname(fileURLToPath(import.meta.url)); +const bundledTheme = path.resolve(directory, '..', 'theme'); +const workspaceTheme = path.resolve(directory, '..', '..', 'packages', 'slidev-theme-easy-jyy'); +export function resolveTheme(theme) { + if (theme) + return theme; + if (existsSync(path.join(bundledTheme, 'package.json'))) + return bundledTheme; + if (existsSync(path.join(workspaceTheme, 'package.json'))) + return workspaceTheme; + throw new Error('easy-slides 主题不存在;请重新安装或构建 @easy-slides/cli'); +} +//# sourceMappingURL=theme.js.map \ No newline at end of file diff --git a/dist-cli/lib/theme.js.map b/dist-cli/lib/theme.js.map new file mode 100644 index 0000000..cf9819f --- /dev/null +++ b/dist-cli/lib/theme.js.map @@ -0,0 +1 @@ +{"version":3,"file":"theme.js","sourceRoot":"","sources":["../../scripts/lib/theme.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AAC9D,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;AAC3D,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,uBAAuB,CAAC,CAAA;AAE/F,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK;QACP,OAAO,KAAK,CAAA;IACd,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;QACrD,OAAO,YAAY,CAAA;IACrB,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC;QACvD,OAAO,cAAc,CAAA;IACvB,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAA;AAChE,CAAC"} \ No newline at end of file diff --git a/dist-cli/lib/token.d.ts b/dist-cli/lib/token.d.ts new file mode 100644 index 0000000..8b1a1fb --- /dev/null +++ b/dist-cli/lib/token.d.ts @@ -0,0 +1,2 @@ +export declare function hashPresenterToken(token: string): string; +export declare function hasPresenterToken(env?: NodeJS.ProcessEnv): boolean; diff --git a/dist-cli/lib/token.js b/dist-cli/lib/token.js new file mode 100644 index 0000000..c7f03a0 --- /dev/null +++ b/dist-cli/lib/token.js @@ -0,0 +1,8 @@ +import { createHash } from 'node:crypto'; +export function hashPresenterToken(token) { + return createHash('sha256').update(token.trim()).digest('hex'); +} +export function hasPresenterToken(env = process.env) { + return Boolean(env.PRESENTER_TOKEN?.trim()); +} +//# sourceMappingURL=token.js.map \ No newline at end of file diff --git a/dist-cli/lib/token.js.map b/dist-cli/lib/token.js.map new file mode 100644 index 0000000..87e8272 --- /dev/null +++ b/dist-cli/lib/token.js.map @@ -0,0 +1 @@ +{"version":3,"file":"token.js","sourceRoot":"","sources":["../../scripts/lib/token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAExC,MAAM,UAAU,kBAAkB,CAAC,KAAa;IAC9C,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AAChE,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACpE,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,EAAE,CAAC,CAAA;AAC7C,CAAC"} \ No newline at end of file diff --git a/dist-cli/present.d.ts b/dist-cli/present.d.ts new file mode 100644 index 0000000..0b172b7 --- /dev/null +++ b/dist-cli/present.d.ts @@ -0,0 +1 @@ +import 'dotenv/config'; diff --git a/dist-cli/present.js b/dist-cli/present.js new file mode 100644 index 0000000..4c3b79d --- /dev/null +++ b/dist-cli/present.js @@ -0,0 +1,41 @@ +import 'dotenv/config'; +import { networkInterfaces } from 'node:os'; +import qrcode from 'qrcode-terminal'; +import { loadProjectConfig } from "./lib/config.js"; +import { resolveDeck } from "./lib/content.js"; +import { runSlidev } from "./lib/run-slidev.js"; +import { resolveTheme } from "./lib/theme.js"; +const input = process.argv.slice(2).find(argument => !argument.startsWith('-')); +const config = await loadProjectConfig(); +const deck = await resolveDeck(input, process.cwd(), config.slidesDir); +const port = process.env.PORT || '3030'; +const address = firstLanAddress(); +const remoteToken = process.env.SLIDEV_REMOTE_TOKEN || 'easy-slides-local'; +const remotePassword = encodeURIComponent(remoteToken); +const presenterUrl = `http://${address}:${port}/presenter/?password=${remotePassword}`; +const remoteUrl = `http://${address}:${port}/entry?password=${remotePassword}`; +console.log(`\n观众视图:http://${address}:${port}/`); +console.log(`演示者视图:${presenterUrl}`); +console.log(`手机遥控器:${remoteUrl}`); +qrcode.generate(presenterUrl, { small: true }); +await runSlidev([ + deck.entry, + '--theme', + resolveTheme(config.theme), + '--port', + port, + '--remote', + remoteToken, + '--bind', + '0.0.0.0', +]); +function firstLanAddress() { + for (const entries of Object.values(networkInterfaces())) { + for (const entry of entries ?? []) { + if (entry.family === 'IPv4' && !entry.internal) + return entry.address; + } + } + return 'localhost'; +} +//# sourceMappingURL=present.js.map \ No newline at end of file diff --git a/dist-cli/present.js.map b/dist-cli/present.js.map new file mode 100644 index 0000000..a5a9078 --- /dev/null +++ b/dist-cli/present.js.map @@ -0,0 +1 @@ +{"version":3,"file":"present.js","sourceRoot":"","sources":["../scripts/present.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAA;AACtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAC3C,OAAO,MAAM,MAAM,iBAAiB,CAAA;AACpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAE7C,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAA;AAC/E,MAAM,MAAM,GAAG,MAAM,iBAAiB,EAAE,CAAA;AACxC,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,SAAS,CAAC,CAAA;AACtE,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,CAAA;AACvC,MAAM,OAAO,GAAG,eAAe,EAAE,CAAA;AACjC,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,mBAAmB,CAAA;AAC1E,MAAM,cAAc,GAAG,kBAAkB,CAAC,WAAW,CAAC,CAAA;AACtD,MAAM,YAAY,GAAG,UAAU,OAAO,IAAI,IAAI,wBAAwB,cAAc,EAAE,CAAA;AACtF,MAAM,SAAS,GAAG,UAAU,OAAO,IAAI,IAAI,mBAAmB,cAAc,EAAE,CAAA;AAE9E,OAAO,CAAC,GAAG,CAAC,iBAAiB,OAAO,IAAI,IAAI,GAAG,CAAC,CAAA;AAChD,OAAO,CAAC,GAAG,CAAC,SAAS,YAAY,EAAE,CAAC,CAAA;AACpC,OAAO,CAAC,GAAG,CAAC,SAAS,SAAS,EAAE,CAAC,CAAA;AACjC,MAAM,CAAC,QAAQ,CAAC,YAAY,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;AAE9C,MAAM,SAAS,CAAC;IACd,IAAI,CAAC,KAAK;IACV,SAAS;IACT,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC;IAC1B,QAAQ;IACR,IAAI;IACJ,UAAU;IACV,WAAW;IACX,QAAQ;IACR,SAAS;CACV,CAAC,CAAA;AAEF,SAAS,eAAe;IACtB,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC,EAAE,CAAC;QACzD,KAAK,MAAM,KAAK,IAAI,OAAO,IAAI,EAAE,EAAE,CAAC;YAClC,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ;gBAC5C,OAAO,KAAK,CAAC,OAAO,CAAA;QACxB,CAAC;IACH,CAAC;IACD,OAAO,WAAW,CAAA;AACpB,CAAC"} \ No newline at end of file diff --git a/dist-cli/theme/components/ContentScaleControls.vue b/dist-cli/theme/components/ContentScaleControls.vue new file mode 100644 index 0000000..f2074ce --- /dev/null +++ b/dist-cli/theme/components/ContentScaleControls.vue @@ -0,0 +1,699 @@ + + + diff --git a/dist-cli/theme/components/PresenterAccess.vue b/dist-cli/theme/components/PresenterAccess.vue new file mode 100644 index 0000000..c5fc84f --- /dev/null +++ b/dist-cli/theme/components/PresenterAccess.vue @@ -0,0 +1,137 @@ + + + diff --git a/dist-cli/theme/components/SlideScrollFallback.vue b/dist-cli/theme/components/SlideScrollFallback.vue new file mode 100644 index 0000000..9ed8596 --- /dev/null +++ b/dist-cli/theme/components/SlideScrollFallback.vue @@ -0,0 +1,31 @@ + + + diff --git a/dist-cli/theme/components/SmartImages.vue b/dist-cli/theme/components/SmartImages.vue new file mode 100644 index 0000000..17222bf --- /dev/null +++ b/dist-cli/theme/components/SmartImages.vue @@ -0,0 +1,32 @@ + + + diff --git a/dist-cli/theme/global-bottom.vue b/dist-cli/theme/global-bottom.vue new file mode 100644 index 0000000..34f2681 --- /dev/null +++ b/dist-cli/theme/global-bottom.vue @@ -0,0 +1,13 @@ + + + diff --git a/dist-cli/theme/layouts/center.vue b/dist-cli/theme/layouts/center.vue new file mode 100644 index 0000000..ff4b658 --- /dev/null +++ b/dist-cli/theme/layouts/center.vue @@ -0,0 +1,5 @@ + diff --git a/dist-cli/theme/layouts/cover.vue b/dist-cli/theme/layouts/cover.vue new file mode 100644 index 0000000..f333814 --- /dev/null +++ b/dist-cli/theme/layouts/cover.vue @@ -0,0 +1,5 @@ + diff --git a/dist-cli/theme/layouts/default.vue b/dist-cli/theme/layouts/default.vue new file mode 100644 index 0000000..13c4c9a --- /dev/null +++ b/dist-cli/theme/layouts/default.vue @@ -0,0 +1,5 @@ + diff --git a/dist-cli/theme/layouts/image-auto.vue b/dist-cli/theme/layouts/image-auto.vue new file mode 100644 index 0000000..f6d3732 --- /dev/null +++ b/dist-cli/theme/layouts/image-auto.vue @@ -0,0 +1,74 @@ + + + diff --git a/dist-cli/theme/layouts/image-full.vue b/dist-cli/theme/layouts/image-full.vue new file mode 100644 index 0000000..8653b53 --- /dev/null +++ b/dist-cli/theme/layouts/image-full.vue @@ -0,0 +1,21 @@ + + + diff --git a/dist-cli/theme/layouts/image-left.vue b/dist-cli/theme/layouts/image-left.vue new file mode 100644 index 0000000..2a650b2 --- /dev/null +++ b/dist-cli/theme/layouts/image-left.vue @@ -0,0 +1,23 @@ + + + diff --git a/dist-cli/theme/layouts/image-right.vue b/dist-cli/theme/layouts/image-right.vue new file mode 100644 index 0000000..e6d880b --- /dev/null +++ b/dist-cli/theme/layouts/image-right.vue @@ -0,0 +1,23 @@ + + + diff --git a/dist-cli/theme/layouts/quote.vue b/dist-cli/theme/layouts/quote.vue new file mode 100644 index 0000000..51a5def --- /dev/null +++ b/dist-cli/theme/layouts/quote.vue @@ -0,0 +1,5 @@ + diff --git a/dist-cli/theme/layouts/section.vue b/dist-cli/theme/layouts/section.vue new file mode 100644 index 0000000..3d1f164 --- /dev/null +++ b/dist-cli/theme/layouts/section.vue @@ -0,0 +1,5 @@ + diff --git a/dist-cli/theme/layouts/two-cols.vue b/dist-cli/theme/layouts/two-cols.vue new file mode 100644 index 0000000..9b89a75 --- /dev/null +++ b/dist-cli/theme/layouts/two-cols.vue @@ -0,0 +1,9 @@ + diff --git a/dist-cli/theme/package.json b/dist-cli/theme/package.json new file mode 100644 index 0000000..c15e394 --- /dev/null +++ b/dist-cli/theme/package.json @@ -0,0 +1,33 @@ +{ + "name": "slidev-theme-easy-jyy", + "version": "0.2.0", + "description": "JYY-inspired presentation theme for easy-slides and Slidev", + "license": "MIT", + "private": false, + "type": "module", + "keywords": ["slidev-theme", "slidev"], + "publishConfig": { + "access": "public" + }, + "engines": { + "node": ">=20.12.0", + "slidev": ">=52.0.0" + }, + "slidev": { + "defaults": { + "aspectRatio": "4/3", + "canvasWidth": 1024, + "colorSchema": "light", + "fonts": { + "sans": "Lato,Noto Sans SC,PingFang SC,Microsoft YaHei,sans-serif", + "mono": "Inconsolata,JetBrains Mono,Fira Code,monospace", + "serif": "Noto Serif SC,STKaiti,KaiTi,serif" + } + } + }, + "dependencies": { + "@slidev/client": "52.19.1", + "@slidev/types": "52.19.1", + "markdown-it-attrs": "4.3.1" + } +} diff --git a/dist-cli/theme/setup/markdown.ts b/dist-cli/theme/setup/markdown.ts new file mode 100644 index 0000000..4869f80 --- /dev/null +++ b/dist-cli/theme/setup/markdown.ts @@ -0,0 +1,8 @@ +import { defineMarkdownSetup } from '@slidev/types' +import markdownItAttrs from 'markdown-it-attrs' + +export default defineMarkdownSetup(() => ({ + markdownItSetup(md) { + md.use(markdownItAttrs) + }, +})) diff --git a/dist-cli/theme/styles/base.css b/dist-cli/theme/styles/base.css new file mode 100644 index 0000000..6975ab3 --- /dev/null +++ b/dist-cli/theme/styles/base.css @@ -0,0 +1,233 @@ +:root { + --easy-accent: #1d4ed8; + --easy-accent-dark: #1e40af; + --easy-accent-soft: #eff6ff; + --easy-ink: #222; + --easy-muted: #666; + --easy-border: #ddd; + --easy-code-bg: #eee; + --easy-code-font-size: 28px; + --easy-table-font-size: 30px; + --easy-table-padding-x: 14px; + --easy-table-padding-y: 10px; + --easy-slide-padding-x: 52px; + --easy-slide-padding-y: 42px; + --easy-presenter-note-size: 20px; +} + +.easy-table-sm { + --easy-table-font-size: 24px; + --easy-table-padding-x: 10px; + --easy-table-padding-y: 7px; +} + +.easy-table-md { + --easy-table-font-size: 30px; + --easy-table-padding-x: 14px; + --easy-table-padding-y: 10px; +} + +.easy-table-lg { + --easy-table-font-size: 36px; + --easy-table-padding-x: 18px; + --easy-table-padding-y: 13px; +} + +.easy-code-sm { --easy-code-font-size: 22px; } +.easy-code-md { --easy-code-font-size: 28px; } +.easy-code-lg { --easy-code-font-size: 34px; } + +.easy-code-height-sm { --easy-code-height: 180px; } +.easy-code-height-md { --easy-code-height: 300px; } +.easy-code-height-lg { --easy-code-height: 420px; } + +.slidev-layout { + position: relative; + width: 100%; + height: 100%; + padding: var(--easy-slide-padding-y) var(--easy-slide-padding-x); + overflow: hidden; + border: 1.5px solid var(--easy-border); + border-radius: 7px; + background: #fff; + color: var(--easy-ink); + text-align: left; + font-family: Lato, "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif; + font-size: 32px; + font-weight: 300; + line-height: 1.42; +} + +.slidev-layout h1, +.slidev-layout h2, +.slidev-layout h3, +.slidev-layout h4 { + color: var(--easy-ink); + font-weight: 400; + letter-spacing: 0; + line-height: 1.15; +} + +.slidev-layout h1 { + margin: 0 0 26px; + font-size: 60px; +} + +.slidev-layout h2 { + margin: 0 0 28px; + padding-bottom: 8px; + border-bottom: 3px solid var(--easy-accent); + font-size: 48px; +} + +.slidev-layout h3 { + margin: 20px 0 14px; + font-size: 38px; +} + +.slidev-layout p, +.slidev-layout ul, +.slidev-layout ol { + margin-top: 14px; + margin-bottom: 14px; +} + +.slidev-layout ul, +.slidev-layout ol { + display: block; + padding-left: 1.2em; +} + +.slidev-layout li + li { + margin-top: 10px; +} + +.slidev-layout a { + color: var(--easy-accent); + text-decoration-thickness: 1px; + text-underline-offset: .13em; +} + +.slidev-layout strong { + font-weight: 700; +} + +.slidev-layout blockquote { + margin: 24px 0; + padding: 4px 0 4px 24px; + border-left: 5px solid var(--easy-accent); + color: #1e3a5f; + font-family: "Noto Serif SC", STKaiti, KaiTi, serif; + font-style: normal; +} + +.slidev-layout code { + font-family: Inconsolata, "JetBrains Mono", "Fira Code", monospace; +} + +.slidev-layout :not(pre) > code { + border-radius: 5px; + background: var(--easy-accent-soft); + color: var(--easy-accent-dark); + padding: .08em .28em; + font-size: .86em; +} + +.slidev-layout pre { + box-sizing: border-box; + height: var(--easy-code-height, var(--easy-code-auto-height, auto)); + max-height: var(--easy-code-height, var(--easy-code-auto-max-height, var(--easy-code-auto-height, none))); + overflow-x: hidden; + overflow-y: auto; + border-radius: 10px; + background: var(--easy-code-bg); + padding: 18px 20px; + font-size: var(--easy-code-scaled-font-size, var(--easy-code-font-size)) !important; + line-height: 1.38 !important; + white-space: pre-wrap; + overflow-wrap: anywhere; +} + +.slidev-layout pre code, +.slidev-layout pre code .line { + min-width: 0 !important; + white-space: pre-wrap !important; + overflow-wrap: anywhere; + word-break: normal; +} + +.slidev-layout table { + width: 100%; + border-collapse: collapse; + font-size: var(--easy-table-font-size); +} + +.slidev-layout th, +.slidev-layout td { + padding: var(--easy-table-padding-y) var(--easy-table-padding-x); + border-bottom: 1px solid #d5d5d5; +} + +.slidev-layout th { + background: #eee; + font-weight: 600; +} + +.slidev-layout tr:nth-child(even) { + background: #f7faff; +} + +.slidev-layout img { + display: block; + max-width: 100%; + max-height: 60vh; + margin: 16px auto; + object-fit: contain; +} + +.slidev-layout p:has(> img:only-child) { + display: grid; + place-items: center; + min-height: 46vh; + margin: 8px 0; +} + +.slidev-layout p:has(> img:only-child) > img { + width: 100%; + height: 46vh; + max-height: 60vh; + margin: 0; + object-fit: contain; +} + +.slidev-layout img[fit="cover"] { + width: 100%; + height: 100%; + object-fit: cover; +} + +.slidev-layout img[fit="fill"] { object-fit: fill; } +.slidev-layout img[fit="scale-down"] { object-fit: scale-down; } +.slidev-layout img[fit="none"] { object-fit: none; } + +.slidev-layout .katex-display, +.slidev-layout .mermaid { + max-width: 100%; + max-height: 60vh; + overflow: auto; +} + +.slidev-page-number { + border-radius: 5px; + background: rgba(0, 0, 0, .26); + padding: 3px 9px; + color: #fff; + font-size: 18px; +} + +@media (max-width: 760px) { + :root { + --easy-slide-padding-x: 34px; + --easy-slide-padding-y: 30px; + } +} diff --git a/dist-cli/theme/styles/content.css b/dist-cli/theme/styles/content.css new file mode 100644 index 0000000..0d60a59 --- /dev/null +++ b/dist-cli/theme/styles/content.css @@ -0,0 +1,69 @@ +/* Shared content utilities for course and technical decks. */ +.slidev-layout .lead { + color: var(--easy-accent); + font-size: 1.16em; + line-height: 1.35; +} + +.slidev-layout .muted { + color: var(--easy-muted); + font-size: .72em; +} + +.slidev-layout .compact, +.slidev-layout.compact { + font-size: 27px; +} + +.slidev-layout .compact li + li, +.slidev-layout.compact li + li { + margin-top: 6px; +} + +.slidev-layout .outline { + list-style: none; + margin: 22px 0 0; + padding: 0; +} + +.slidev-layout .outline > li { + margin: 12px 0; + padding-left: 22px; + border-left: 5px solid #ddd; +} + +.slidev-layout .outline .current { + border-left-color: var(--easy-accent); + color: var(--easy-accent); + font-weight: 600; +} + +.slidev-layout .source-figure { + width: 100%; + max-height: 56vh; + object-fit: contain; +} + +.slidev-layout .course-table { + font-size: 21px; + line-height: 1.2; +} + +.slidev-layout .course-table th, +.slidev-layout .course-table td { + padding: 6px 9px; +} + +.slidev-layout .v-word { + color: var(--easy-accent); + font-size: 1.22em; + font-weight: 600; +} + +.easy-layout-cover .cover-identity { + width: 68%; + height: 20vh; + margin: 22px 0 0; + object-fit: contain; + object-position: left center; +} diff --git a/dist-cli/theme/styles/index.ts b/dist-cli/theme/styles/index.ts new file mode 100644 index 0000000..e4c99bc --- /dev/null +++ b/dist-cli/theme/styles/index.ts @@ -0,0 +1,4 @@ +import './base.css' +import './content.css' +import './layouts.css' +import './presenter.css' diff --git a/dist-cli/theme/styles/layouts.css b/dist-cli/theme/styles/layouts.css new file mode 100644 index 0000000..b1ed0cb --- /dev/null +++ b/dist-cli/theme/styles/layouts.css @@ -0,0 +1,283 @@ +.easy-layout-center, +.easy-layout-section, +.easy-layout-cover { + display: flex; + flex-direction: column; + justify-content: center; +} + +.easy-layout-center { + align-items: center; + text-align: center; +} + +.easy-layout-center h1, +.easy-layout-center h2 { + text-align: center; +} + +.easy-layout-cover h1 { + margin-bottom: 28px; + font-size: 68px; +} + +.easy-layout-cover blockquote { + border: 0; + padding: 0; + color: var(--easy-accent); +} + +.easy-layout-section h1, +.easy-layout-section h2 { + max-width: 980px; +} + +.easy-layout-quote { + display: flex; + flex-direction: column; + justify-content: center; +} + +.easy-layout-quote blockquote { + border: 0; + padding: 0; + color: var(--easy-accent); + font-size: 46px; + line-height: 1.35; + text-align: center; +} + +.easy-layout-two-cols { + display: grid; + grid-template-rows: auto 1fr; +} + +.easy-layout-two-cols .easy-two-cols-grid { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); + gap: 46px; + min-height: 0; +} + +.easy-layout-image-split { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); + gap: 42px; +} + +.easy-layout-image-split.easy-image-left .easy-image-pane { order: -1; } + +.easy-layout-image-auto.easy-image-top, +.easy-layout-image-auto.easy-image-bottom { + grid-template-columns: minmax(0, 1fr); + grid-template-rows: auto minmax(0, 1fr); + gap: 22px; +} + +.easy-layout-image-auto.easy-image-top .easy-image-pane { order: -1; } + +.easy-image-pane { + min-width: 0; + min-height: 0; + display: grid; + grid-template-columns: minmax(0, 1fr); + grid-template-rows: minmax(0, 1fr); + place-items: center; + overflow: hidden; + border-radius: 8px; +} + +.easy-image-pane img { + min-width: 0; + min-height: 0; + width: 100%; + height: 100%; + max-width: 100%; + max-height: 100%; + margin: 0; +} + +.easy-content-scale-host { + position: relative; + min-width: 0; + min-height: 0; +} + +.easy-content-table-host { + width: 100%; + overflow: auto; +} + +.easy-content-code-host { + width: 100%; + margin-bottom: 0 !important; +} + +.easy-image-preview-trigger { + cursor: zoom-in; +} + +.easy-image-preview-trigger:focus-visible { + outline: 3px solid var(--easy-accent); + outline-offset: 4px; +} + +.easy-image-lightbox { + position: fixed; + inset: 0; + z-index: 2147483647; + display: grid; + grid-template-columns: minmax(0, 1fr); + grid-template-rows: minmax(0, 1fr); + place-items: center; + box-sizing: border-box; + min-width: 0; + min-height: 0; + padding: clamp(16px, 4vmin, 42px); + overflow: hidden; + overscroll-behavior: contain; + background: rgba(0, 0, 0, .92); +} + +.easy-image-lightbox-preview { + display: block; + place-self: center; + min-width: 0; + min-height: 0; + width: auto; + height: auto; + max-width: 100%; + max-height: 100%; + max-inline-size: 100%; + max-block-size: 100%; + margin: 0; + object-fit: contain; + object-position: center; +} + +.easy-image-lightbox-close { + position: absolute; + top: 18px; + right: 22px; + display: grid; + width: 46px; + height: 46px; + place-items: center; + border: 1px solid rgba(255, 255, 255, .5); + border-radius: 50%; + background: rgba(0, 0, 0, .55); + color: #fff; + padding: 0 0 4px; + font: 300 38px/1 Arial, sans-serif; + cursor: pointer; +} + +.easy-image-lightbox-close:hover, +.easy-image-lightbox-close:focus-visible { + border-color: #fff; + background: var(--easy-accent); + outline: none; +} + +.easy-content-scale-toolbar { + position: absolute; + top: 8px; + right: 8px; + z-index: 30; + display: flex; + gap: 3px; + padding: 4px; + border: 1px solid rgba(180, 180, 180, .9); + border-radius: 7px; + background: rgba(255, 255, 255, .94); + box-shadow: 0 4px 16px rgba(0, 0, 0, .12); + opacity: 0; + transition: opacity .14s ease; +} + +.easy-content-scale-host:hover > .easy-content-scale-toolbar, +.easy-content-scale-host:focus-within > .easy-content-scale-toolbar { + opacity: 1; +} + +.easy-content-scale-button { + min-width: 32px; + border: 0; + border-radius: 5px; + background: #eee; + color: #222; + padding: 6px 8px; + font: 600 14px/1 Lato, "Noto Sans SC", sans-serif; + cursor: pointer; +} + +.easy-content-scale-button:hover, +.easy-content-scale-button:focus-visible { + background: var(--easy-accent); + color: #fff; + outline: none; +} + +.easy-content-scale-reset { + min-width: 52px; +} + +.easy-content-code-host > .easy-content-scale-toolbar { + right: 48px; +} + +body.easy-slide-scroll-fallback .slidev-layout { + overflow-x: hidden; + overflow-y: auto; + overscroll-behavior-y: contain; + scrollbar-width: thin; + scrollbar-color: color-mix(in srgb, var(--easy-accent) 65%, transparent) transparent; +} + +.easy-image-content { + min-width: 0; + align-self: center; +} + +.easy-layout-image-full { + padding: 0; +} + +.easy-layout-image-full > img { + width: 100%; + height: 100%; + max-height: none; + margin: 0; +} + +.easy-layout-image-full .easy-image-overlay { + position: absolute; + inset: auto 0 0; + padding: 46px 54px; + background: linear-gradient(transparent, rgba(0, 0, 0, .78)); + color: #fff; +} + +.easy-layout-image-full .easy-image-overlay :is(h1, h2, h3, p) { + color: inherit; +} + +@media (max-aspect-ratio: 4 / 3) { + .easy-layout-two-cols .easy-two-cols-grid, + .easy-layout-image-split { + grid-template-columns: 1fr; + grid-template-rows: 1fr 1fr; + gap: 22px; + } +} + +@media (hover: none) { + .easy-content-scale-toolbar { opacity: .78; } +} + +@media print { + .easy-content-scale-toolbar, + .easy-image-lightbox { display: none !important; } + + body.easy-slide-scroll-fallback .slidev-layout { overflow: hidden !important; } +} diff --git a/dist-cli/theme/styles/presenter.css b/dist-cli/theme/styles/presenter.css new file mode 100644 index 0000000..b6d50a4 --- /dev/null +++ b/dist-cli/theme/styles/presenter.css @@ -0,0 +1,143 @@ +.easy-presenter-gate { + position: fixed; + inset: 0; + z-index: 2147483646; + display: none; + width: 100vw; + height: 100dvh; + max-width: none; + max-height: none; + margin: 0; + border: 0; + padding: 0; + place-items: center; + overflow: auto; + background: #f6f5f2; + color: #222; + font-family: Lato, "Noto Sans SC", "PingFang SC", sans-serif; +} + +.easy-presenter-gate[open] { + display: grid; +} + +.easy-presenter-gate::backdrop { + background: #f6f5f2; +} + +body.easy-presenter-locked { + overflow: hidden; +} + +.easy-presenter-dialog { + width: min(440px, calc(100vw - 40px)); + border: 1px solid #d8d4d7; + border-top: 4px solid var(--easy-accent); + border-radius: 9px; + background: #fff; + padding: 34px; + box-shadow: 0 20px 70px rgba(45, 26, 42, .14); +} + +.easy-presenter-dialog h1 { + margin: 0 0 10px; + font-size: 30px; +} + +.easy-presenter-dialog p { + color: #666; + line-height: 1.55; +} + +.easy-presenter-dialog form { + display: flex; + gap: 10px; + margin-top: 24px; +} + +.easy-presenter-dialog input { + min-width: 0; + flex: 1; + border: 1px solid #aaa; + border-radius: 6px; + padding: 11px 12px; + font: inherit; +} + +.easy-presenter-dialog button, +.easy-presenter-tools button, +.easy-presenter-launcher { + border: 0; + border-radius: 6px; + background: var(--easy-accent); + color: #fff; + padding: 10px 14px; + font: 600 14px/1.1 Lato, "Noto Sans SC", sans-serif; + cursor: pointer; +} + +.easy-presenter-error { + color: #a21d32 !important; + font-weight: 600; +} + +.easy-presenter-launcher { + position: fixed; + right: 18px; + bottom: 18px; + z-index: 60; + opacity: .22; + transition: opacity .16s ease; +} + +.easy-presenter-launcher:hover, +.easy-presenter-launcher:focus-visible { + opacity: 1; +} + +.easy-presenter-tools { + position: fixed; + top: 12px; + right: 12px; + z-index: 1000; + display: flex; + gap: 6px; + padding: 6px; + border: 1px solid #d4d0d3; + border-radius: 8px; + background: rgba(255, 255, 255, .94); + box-shadow: 0 5px 22px rgba(0, 0, 0, .12); +} + +.easy-presenter-tools button { + min-width: 34px; + background: #eee9ed; + color: #351231; + padding: 8px 10px; +} + +.easy-presenter-tools button:last-child { + background: #5d1357; + color: #fff; +} + +@media (max-width: 680px) { + .easy-presenter-tools { + right: auto; + left: 12px; + } +} + +body.easy-presenter-active :is(.presenter-notes, [class*="presenter"] [class*="notes"], [class*="presenter"] [class*="note"] p) { + font-size: var(--easy-presenter-note-size) !important; + line-height: 1.65 !important; +} + +body.easy-notes-contrast :is(.presenter-notes, [class*="presenter"] [class*="notes"], [class*="presenter"] [class*="note"]) { + background: #050505 !important; + color: #fff !important; +} + +body.easy-notes-contrast :is(.presenter-notes, [class*="presenter"] [class*="notes"], [class*="presenter"] [class*="note"]) * { + color: inherit !important; +} diff --git a/dist-cli/theme/utils/resolve-image.ts b/dist-cli/theme/utils/resolve-image.ts new file mode 100644 index 0000000..437049c --- /dev/null +++ b/dist-cli/theme/utils/resolve-image.ts @@ -0,0 +1,15 @@ +const deckBase = (import.meta as ImportMeta & { env: { BASE_URL: string } }).env.BASE_URL + +export function resolveImageSource(source: string | undefined, base = deckBase) { + if (!source || isAbsoluteSource(source)) + return source + + const normalizedBase = base.endsWith('/') ? base : `${base}/` + return `${normalizedBase}${source.replace(/^\.\//, '')}` +} + +function isAbsoluteSource(source: string) { + return source.startsWith('/') + || source.startsWith('#') + || /^[a-z][a-z\d+.-]*:/i.test(source) +}