diff --git a/README.md b/README.md new file mode 100644 index 0000000..538a881 --- /dev/null +++ b/README.md @@ -0,0 +1,81 @@ +# auto-reveal + +Create Reveal.js presentations from markdown files. + +## Installation + +```bash +# Create an empty node project +npm init +# Add auto-reveal +npm add auto-reveal +``` + +Add this to your `package.json`: + +```json +{ + "scripts": { + "start": "auto-reveal", + "build": "auto-reveal build" + } +} +``` + +## Usage + +In it's current iteration, `auto-reveal` expects markdown files in `/slides` and +will output the presentation to `/dist` when running `npm run build`. + +To get a live-reloading preview of your presentation, run `npm run start`. + +### Slides + +Markdown files are sorted by filename. `001-slide.md` will be the first slide, +`002-slide.md` the second, and so on. + +Each Markdown file will generate a horizontal slide. If you want to create +vertical slides, use `\n---\n` inside your Markdown files to separate them. + +### Themes + +If you install any package prefixed with `auto-reveal-theme-`, it will +automatically be used for your presentation. For example, to use the +`auto-reveal-theme-mainmatter` theme, run: + +```bash +npm add auto-reveal-theme-mainmatter +``` + +If no theme is installed, the default Reveal.js `simple` theme will be used +instead. + +### Document Title + +If your root folder contains a `README.md` and it starts with a first level +headline, it will be used as the document title of the presentation. It falls +back to the `name` field in `package.json` if no `README.md` is found. + +### Assets + +Any assets you want to use in your presentation should be places inside +`/public`. `/public/images/foo.jpg` can be referenced in your markdown as +`![foo](images/foo.jpg)`. + +### Speaker notes + +Any content after `Note:\n` will be treated as speaker notes and will be hidden +from the presentation. + +### Additional Configuration + +There is none. + +## Development + +This project uses Vite under the hood. Linting and formatting is handled by +Biome. + +### Roadmap + +- [ ] Add configuration options diff --git a/bin/auto-reveal.js b/bin/auto-reveal.js index 65aafc2..87cf4f2 100755 --- a/bin/auto-reveal.js +++ b/bin/auto-reveal.js @@ -2,7 +2,7 @@ import path from 'node:path'; import { fileURLToPath } from 'url'; -import { createServer, build } from 'vite'; +import { build, createServer } from 'vite'; import { ViteEjsPlugin as viteEjsPlugin } from 'vite-plugin-ejs'; import { getTheme, getTitle } from '../lib/utils.js'; @@ -12,44 +12,43 @@ const cwd = process.cwd(); const themeFolder = path.dirname(getTheme()); const config = { - configFile: false, - root: path.join(__dirname, '..', 'src'), - publicDir: path.join(cwd, 'public'), - server: { - port: 1337, - fs: { - allow: [themeFolder, '.'] - } - }, - plugins: [ - viteEjsPlugin({ - title: getTitle(), - }), - ], - resolve: { - alias: { - slides: path.join(cwd, 'slides'), - '@theme': themeFolder, - }, - }, - build: { - outDir: path.join(cwd, 'dist') - } + configFile: false, + root: path.join(__dirname, '..', 'src'), + publicDir: path.join(cwd, 'public'), + server: { + port: 1337, + fs: { + allow: [themeFolder, '.'], + }, + }, + plugins: [ + viteEjsPlugin({ + title: getTitle(), + }), + ], + resolve: { + alias: { + slides: path.join(cwd, 'slides'), + '@theme': themeFolder, + }, + }, + build: { + outDir: path.join(cwd, 'dist'), + }, }; async function start() { - - const server = await createServer(config); + const server = await createServer(config); - server.watcher.add(path.join(cwd, 'slides')); + server.watcher.add(path.join(cwd, 'slides')); - await server.listen(); - server.printUrls(); - server.bindCLIShortcuts({ print: true }); + await server.listen(); + server.printUrls(); + server.bindCLIShortcuts({ print: true }); } if (!argv[0] || argv[0] === 'start') { - start(); + start(); } else if (argv[0] === 'build') { - build(config) + build(config); } diff --git a/biome.json b/biome.json index 75d95c7..4cca190 100644 --- a/biome.json +++ b/biome.json @@ -15,5 +15,14 @@ "formatter": { "quoteStyle": "single" } + }, + "files": { + "ignore": [ + "node_modules", + "dist", + ".release-plan.json", + "CHANGELOG.md", + "pnpm-lock.yaml" + ] } } diff --git a/lib/common-utils.cjs b/lib/common-utils.cjs index 32c3ce2..ac5155f 100644 --- a/lib/common-utils.cjs +++ b/lib/common-utils.cjs @@ -4,45 +4,45 @@ const path = require('node:path'); let packageJson; function getPackageJson(cwd = process.cwd()) { - if (packageJson) { - return packageJson; - } + if (packageJson) { + return packageJson; + } - try { - packageJson = JSON.parse( - fs.readFileSync(path.join(cwd, 'package.json'), 'utf-8') - ); + try { + packageJson = JSON.parse( + fs.readFileSync(path.join(cwd, 'package.json'), 'utf-8'), + ); - return packageJson; - } catch { - console.error('No package.json found'); - } + return packageJson; + } catch { + console.error('No package.json found'); + } - return { name: '', dependencies: {} }; + return { name: '', dependencies: {} }; } function getThemePackage() { - const packageJson = getPackageJson(); - return Object.keys(packageJson.dependencies).find((name) => - name.startsWith('auto-reveal-theme-') - ); + const packageJson = getPackageJson(); + return Object.keys(packageJson.dependencies).find((name) => + name.startsWith('auto-reveal-theme-'), + ); } function getTheme() { - const theme = getThemePackage(); + const theme = getThemePackage(); - if (!theme) { - return 'reveal.js/dist/theme/simple.css'; - } + if (!theme) { + return 'reveal.js/dist/theme/simple.css'; + } - // This can't be done with `import.meta.resolve` because it doesn't support a parent as of Node.js 20, - // which is the reason why this whole file is a CommonJS module. - return require.resolve(path.join(theme, 'package.json'), { - paths: [process.cwd()], - }); + // This can't be done with `import.meta.resolve` because it doesn't support a parent as of Node.js 20, + // which is the reason why this whole file is a CommonJS module. + return require.resolve(path.join(theme, 'package.json'), { + paths: [process.cwd()], + }); } module.exports = { - getTheme, - getThemePackage, + getTheme, + getThemePackage, }; diff --git a/lib/utils.js b/lib/utils.js index a057afc..b1a7a00 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -3,21 +3,21 @@ import path from 'node:path'; import * as utils from './common-utils.cjs'; export function getTitle(defaultTitle = 'auto-reveal') { - try { - const README = fs.readFileSync( - path.join(process.cwd(), 'README.md'), - 'utf-8' - ); - const match = /^# (.*)$/gm.exec(README); + try { + const README = fs.readFileSync( + path.join(process.cwd(), 'README.md'), + 'utf-8', + ); + const match = /^# (.*)$/gm.exec(README); - if (match) { - return match[1]; - } - } catch { - console.error('No README.md found, falling back to `name` in package.json'); - } + if (match) { + return match[1]; + } + } catch { + console.error('No README.md found, falling back to `name` in package.json'); + } - return process.env.npm_package_name ?? defaultTitle; + return process.env.npm_package_name ?? defaultTitle; } const { getTheme, getThemePackage } = utils; diff --git a/src/main.js b/src/main.js index 0d139be..5a0c344 100644 --- a/src/main.js +++ b/src/main.js @@ -3,24 +3,24 @@ import Highlight from 'reveal.js/plugin/highlight/highlight.esm.js'; import Markdown from 'reveal.js/plugin/markdown/markdown.esm.js'; import Notes from 'reveal.js/plugin/notes/notes.esm.js'; -import 'reveal.js/dist/reveal.css'; import '@theme'; +import 'reveal.js/dist/reveal.css'; const markdownFiles = import.meta.glob('slides/*.md', { - as: 'raw', - eager: true, + as: 'raw', + eager: true, }); const sortedMarkdownFiles = Object.entries(markdownFiles).sort(([a], [b]) => { - const regex = /slides\/(\d+)-/; - const [, aNumb] = regex.exec(a); - const [, bNumb] = regex.exec(b); + const regex = /slides\/(\d+)-/; + const [, aNumb] = regex.exec(a); + const [, bNumb] = regex.exec(b); - return Number(aNumb) - Number(bNumb); + return Number(aNumb) - Number(bNumb); }); const sections = sortedMarkdownFiles.map( - ([, content]) => ` + ([, content]) => `
-` +`, ); document.querySelector('.slides').innerHTML = sections.join(''); @@ -37,10 +37,10 @@ document.querySelector('.slides').innerHTML = sections.join(''); const deck = new Reveal(); deck.initialize({ - hash: true, - width: 1280, - height: 960, - margin: 0.1, - highlight: {}, - plugins: [Markdown, Highlight, Notes], + hash: true, + width: 1280, + height: 960, + margin: 0.1, + highlight: {}, + plugins: [Markdown, Highlight, Notes], });