@exor404/mdslides 0.1.0 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,32 +12,78 @@ dev server or builds a self-contained `dist/` you can host anywhere static.
12
12
  ## Quick start
13
13
 
14
14
  ```bash
15
- mdslides ./chemistry # scaffolds a project, then presents it
15
+ npx @exor404/mdslides@latest
16
16
  ```
17
17
 
18
- Point `mdslides` at a folder and it scaffolds a project: it **asks for a
19
- name**, writes `<name>.md` (e.g. `chemistry.md`) with three sample slides a
20
- title page, a list, and a help slide plus a `mdslides.config.js`, then opens
21
- the dev server. The name defaults to the folder, so pressing Enter at
22
- `Name your presentation (chemistry):` gives you `chemistry/chemistry.md`. That
23
- file *is* your deck — edit it and the slides live-reload.
18
+ No install step. It **asks for a name**, scaffolds `<name>/<name>.md` (three
19
+ sample slides a title page, a list, and a help slide) plus a
20
+ `mdslides.config.js`, and opens the dev server. The name defaults to the current
21
+ folder, so pressing Enter at `Name your presentation (chemistry):` gives you
22
+ `chemistry/chemistry.md`. That file *is* your deck edit it and the slides
23
+ live-reload.
24
+
25
+ Point it at a folder for the other commands:
24
26
 
25
27
  ```bash
26
- mdslides ./chemistry # present (dev server, live-reload)
27
- mdslides build ./chemistry # static build → ./chemistry/dist/
28
- mdslides preview ./chemistry # serve the built dist/
29
- mdslides export ./chemistry # → chemistry.pdf (one page per slide)
28
+ npx @exor404/mdslides ./chemistry # present (dev server, live-reload)
29
+ npx @exor404/mdslides build ./chemistry # static build → ./chemistry/dist/
30
+ npx @exor404/mdslides preview ./chemistry # serve the built dist/
31
+ npx @exor404/mdslides export ./chemistry # → chemistry.pdf (one page per slide)
30
32
  ```
31
33
 
32
- Already have a deck? Point straight at the file: `mdslides ./chemistry.md`.
34
+ Already have a deck? Point straight at the file: `npx @exor404/mdslides ./chemistry.md`.
35
+
36
+ > **Heads-up:** `npm install @exor404/mdslides` only *installs* the package —
37
+ > running the CLI (via `npx`, as above) is what scaffolds and presents. Using
38
+ > `npx` also keeps the engine's dependencies in npx's cache instead of bloating
39
+ > a project's `node_modules`.
33
40
 
34
- Try the bundled example:
41
+ Prefer a global command? `npm i -g @exor404/mdslides` makes `mdslides` available
42
+ directly (`mdslides ./chemistry`).
43
+
44
+ Try the bundled example from a clone:
35
45
 
36
46
  ```bash
37
47
  npm install
38
48
  npm run dev # opens ./example
39
49
  ```
40
50
 
51
+ ## Install
52
+
53
+ The package is published on the public npm registry as
54
+ [`@exor404/mdslides`](https://www.npmjs.com/package/@exor404/mdslides). Pick the
55
+ option that suits you:
56
+
57
+ **No install (recommended).** `npx` fetches and caches the latest version, then
58
+ runs it — nothing is added to your project:
59
+
60
+ ```bash
61
+ npx @exor404/mdslides@latest # prompts for a name, scaffolds + presents
62
+ ```
63
+
64
+ **Global install.** Puts an `mdslides` command on your `PATH`:
65
+
66
+ ```bash
67
+ npm install -g @exor404/mdslides
68
+ mdslides ./chemistry # then use it anywhere
69
+ mdslides --help # (or run with no folder to start fresh)
70
+ ```
71
+
72
+ Update later with `npm update -g @exor404/mdslides`; remove with
73
+ `npm uninstall -g @exor404/mdslides`.
74
+
75
+ **As a project dependency.** Add it to a repo so collaborators get the same
76
+ version via `npm install`:
77
+
78
+ ```bash
79
+ npm install -D @exor404/mdslides
80
+ npx mdslides ./chemistry # resolves from local node_modules
81
+ ```
82
+
83
+ > Requires **Node 18+**. Installing the package pulls in its rendering engine
84
+ > (Astro, Shiki, KaTeX) — that's why `npx` is the lightest way to try it: those
85
+ > dependencies stay in npx's cache instead of your project's `node_modules`.
86
+
41
87
  ## The deck model
42
88
 
43
89
  **One markdown file is the whole deck.** Every `#` (H1) heading starts a new
@@ -147,33 +193,66 @@ fragments shown). It uses [Playwright](https://playwright.dev) if installed
147
193
  Releases go to the **public npm registry** (npmjs.com), so anyone can
148
194
  `npx @exor404/mdslides`. A tag-triggered GitHub Actions pipeline
149
195
  ([`.github/workflows/package-publish.yml`](.github/workflows/package-publish.yml))
150
- publishes via **OIDC Trusted Publishing** GitHub mints a one-time identity
151
- token for the run, so **no npm token or secret is ever stored**.
196
+ does the publishing for you: it runs **only when you push a `v*` tag**, verifies
197
+ the tag matches `package.json`, and runs `npm publish` against npmjs.com using an
198
+ automation token stored as the `NPM_TOKEN` repository secret.
152
199
 
153
- **One-time setup** (needed once, because Trusted Publishing attaches to an
154
- existing package):
200
+ ### How the pipeline works
155
201
 
156
- ```bash
157
- npm login # browser sign-in to npmjs.com
158
- npm publish --access public # publish the first version by hand
159
202
  ```
203
+ push tag v0.1.3 ──► GitHub Actions ──► checkout ──► setup Node 22
204
+
205
+ ├─ guard: tag (v0.1.3) must equal
206
+ │ package.json "version" (0.1.3),
207
+ │ else the run fails
208
+
209
+ └─ npm publish (auth: NPM_TOKEN)
210
+ └──► npmjs.com
211
+ ```
212
+
213
+ The version guard means the git tag and the published version can never drift —
214
+ if they disagree, the run stops before publishing.
160
215
 
161
- Then on npmjs.com open the package → **Settings → Trusted Publisher → GitHub
162
- Actions** and register:
216
+ ### One-time setup
163
217
 
164
- - **Repository:** `eXor404/mdslides`
165
- - **Workflow filename:** `package-publish.yml`
218
+ You only do this once. It wires an npm token into the repo so Actions can publish
219
+ on your behalf.
166
220
 
167
- After that, every release is automatic:
221
+ 1. **Create an npm automation token.** On npmjs.com: avatar → **Access Tokens** →
222
+ **Generate New Token** → **Automation** (or a **Granular** token scoped to the
223
+ `@exor404/mdslides` package with **Read and write**). Copy the value — npm
224
+ shows it only once.
225
+ 2. **Add it to GitHub as a secret.** Repo → **Settings** → **Secrets and
226
+ variables** → **Actions** → **New repository secret**. Name it exactly
227
+ `NPM_TOKEN`, paste the token, **Add secret**. (It's a *secret*, not a
228
+ *variable* — secrets are encrypted and hidden from logs.)
229
+
230
+ > The very first version must exist on npm before automation can update it.
231
+ > If the package isn't published yet, do one manual publish first:
232
+ > `npm login && npm publish --access public`.
233
+
234
+ ### Cutting a release
235
+
236
+ Once the secret is in place, every release is three commands:
168
237
 
169
238
  ```bash
170
- npm version patch # bumps package.json (0.1.0 → 0.1.1) and tags v0.1.1
239
+ npm version patch # bumps package.json (0.1.2 → 0.1.3) and commits + tags v0.1.3
171
240
  git push origin main # push the version-bump commit
172
- git push origin v0.1.1 # push the tag → the pipeline publishes, tokenlessly
241
+ git push origin v0.1.3 # push the tag → the pipeline publishes
173
242
  ```
174
243
 
175
- `npm version` creates the matching `vX.Y.Z` tag for you. The workflow refuses
176
- to publish if the tag and `package.json` version disagree, so they can't drift.
244
+ `npm version patch` (or `minor` / `major`) bumps `package.json`, makes the commit,
245
+ and creates the matching `vX.Y.Z` tag in one step. Pushing that tag is what
246
+ triggers the workflow. Watch it run under the repo's **Actions** tab; when it goes
247
+ green the new version is live on npm.
248
+
249
+ **Prefer to bump by hand?** Edit `"version"` in `package.json`, then:
250
+
251
+ ```bash
252
+ git commit -am "🔖 Release 0.1.3"
253
+ git tag v0.1.3 # must match package.json exactly, or the guard fails
254
+ git push && git push --tags
255
+ ```
177
256
 
178
257
  ## Requirements
179
258
 
@@ -23,7 +23,15 @@ const MIME = {
23
23
  };
24
24
 
25
25
  const EXCLUDED_TOP = new Set(['dist', 'node_modules', '.git', '.astro', '.vscode', '.idea']);
26
- const EXCLUDED_FILES = new Set(['mdslides.config.js']);
26
+ const EXCLUDED_FILES = new Set([
27
+ 'mdslides.config.js',
28
+ // Project scaffolding that lives alongside the deck (npm create … layout) —
29
+ // never part of the presentation, so keep it out of the built dist/.
30
+ 'package.json',
31
+ 'package-lock.json',
32
+ 'yarn.lock',
33
+ 'pnpm-lock.yaml',
34
+ ]);
27
35
 
28
36
  function isExcludedRel(rel) {
29
37
  if (!rel || rel === '.' || rel === '..') return true;
package/bin/cli.js CHANGED
@@ -60,7 +60,10 @@ function parseArgs(argv) {
60
60
  }
61
61
  }
62
62
 
63
- if (!file) {
63
+ // No target + the default `dev` command → start a brand-new project: we'll
64
+ // prompt for a name and scaffold it. Any other command needs an explicit
65
+ // target (there's nothing to build/preview/export yet).
66
+ if (!file && cmd !== 'dev') {
64
67
  fail('Missing target.\nUsage: mdslides [dev|build|preview|export] [--theme <name>] <folder|file.md>');
65
68
  }
66
69
 
@@ -130,6 +133,21 @@ async function scaffoldProject(dir) {
130
133
  return scaffoldDeck(resolve(dir, `${stem}.md`));
131
134
  }
132
135
 
136
+ // Start a project from scratch when `mdslides` is run with no target (e.g.
137
+ // `npx @exor404/mdslides`): ask for a name, then create `<name>/<name>.md` in
138
+ // the current directory and present it. No install or extra command needed.
139
+ async function scaffoldNewProject() {
140
+ const fallback = slugify(basename(process.cwd())) || 'presentation';
141
+ const answer = await ask(`Name your presentation (${fallback}): `, fallback);
142
+ const stem = slugify(answer.replace(/\.md$/i, '')) || fallback;
143
+ const dir = resolve(process.cwd(), stem);
144
+ if (existsSync(dir) && statSync(dir).isDirectory() && findDeckInDir(dir)) {
145
+ // A deck already lives here — open it instead of clobbering anything.
146
+ return findDeckInDir(dir);
147
+ }
148
+ return scaffoldDeck(resolve(dir, `${stem}.md`));
149
+ }
150
+
133
151
  function scaffoldDeck(deckPath) {
134
152
  const templatePath = resolve(__dirname, 'templates', 'slides.md');
135
153
  try {
@@ -169,7 +187,7 @@ async function loadUserConfig(source) {
169
187
  }
170
188
 
171
189
  const { cmd, theme: cliTheme, file } = parseArgs(process.argv);
172
- const deckFile = await resolveDeck(file);
190
+ const deckFile = file ? await resolveDeck(file) : await scaffoldNewProject();
173
191
  const source = dirname(deckFile);
174
192
 
175
193
  ensureDefaultConfig(source);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exor404/mdslides",
3
- "version": "0.1.0",
3
+ "version": "0.1.3",
4
4
  "description": "Markdown in, presentation out.",
5
5
  "type": "module",
6
6
  "bin": {