Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 33 additions & 41 deletions website/en/book/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ If you need a new feature, open an [issue](https://github.com/openpatch/hyperboo
:::

<!--
## v0.41.0
## vNEXT

::::tabs

:::tab{title="New :rocket:" id="new"}

- Allow emojis in tab titles. E.g.: `:::tab{title="Hi :smile:"}`


:::

Expand All @@ -45,31 +45,31 @@ If you need a new feature, open an [issue](https://github.com/openpatch/hyperboo

:::tab{title="New :rocket:" id="new"}

**check**: A new `hyperbook check` command goes over a book without building it and reports links and images that point at nothing, two pages claiming the same `permaid`, and options in `hyperbook.json` that Hyperbook does not know about. A mistyped option is otherwise ignored in silence, and a broken link only shows up when a reader clicks it. It exits with an error, so it can run in CI ahead of `hyperbook build`.
**check**: A new `hyperbook check` command validates a book without building it: links and images that point at nothing, two pages claiming the same `permaid`, and unknown options in `hyperbook.json`. It exits with an error, so it can run in CI ahead of `hyperbook build`.

**print**: Books can be printed. There was no print stylesheet before, and because the reading layout is a fixed grid whose article pane scrolls, printing a chapter gave you roughly one sheet. Now the whole chapter comes out: the navigation and buttons are dropped, collapsed sections and every tab of a tab group are opened, dark mode is not carried onto paper, and an answer a reader has typed into a `::textinput` prints in full rather than being cut off at the edge of the box.
**print**: Books can be printed. A chapter now prints in full instead of on a single sheetnavigation and buttons are dropped, collapsed sections and every tab of a tab group are opened, dark mode is not carried onto paper, and answers typed into a `::textinput` print in full.

:::

:::tab{title="Improved :+1:" id="improved"}

**search**: Pages load a great deal faster. The search index was linked from every page whether or not the reader ever opened search — on this documentation that was 2.9 MB of the 3.1 MB of JavaScript each page pulled in. It is fetched the first time someone searches now, which leaves 284 KB. Search itself got quicker too, because the index is read once instead of on every keystroke, and it now searches as you type. Press `/` anywhere to open it.
**search**: Pages load a great deal faster, because the search index is fetched the first time someone searches instead of on every page view — on this documentation that is 284 KB of JavaScript per page instead of 3.1 MB. Search also runs as you type now, and `/` opens it from anywhere.

**diagnostics**: The build tells you when a directive is written with the wrong number of colons. Messages like `Unexpected "::alert" leaf directive, use three colons` were being worked out on every build and then thrown away. They now appear with the file and line while you build, in `hyperbook dev` both in the terminal and over the page in the browser, and as squiggles in the VS Code preview. `hyperbook dev` also shows build errors in the browser instead of only in the terminal, where they were easy to miss.
**diagnostics**: Mistakes in your markdown, such as writing `::alert` with two colons instead of three, are now reported with their file and line: during `hyperbook build`, in `hyperbook dev` (in the terminal and as an overlay in the browser), and as squiggles in the VS Code preview.

**directives**: Directives now accept every form they actually support. `geogebra`, `struktolab`, `p5` and the code editors `pyide`, `webide`, `typst` and `openscad` take either a body or an attribute — an editor with no body is how you set a blank exercise — and `archive` and `download` work inside a sentence as well as on their own. Each of those used to insist on one form and call the other a mistake.
**directives**: `geogebra`, `struktolab`, `p5` and the code editors `pyide`, `webide`, `typst` and `openscad` accept either a body or an attribute — an editor with no body is how you set a blank exercise. `archive` and `download` work inside a sentence as well as on their own. Each of these used to reject one of the two forms.

:::

:::tab{title="Fixed :bug:" id="fixed"}

**textinput and other interactive elements**: Editing a page no longer wipes what readers have written into it. The id an element stored its data under was worked out from a hash that included where the element sat in the file, so adding a paragraph anywhere above a `::textinput` gave it a new id and every answer already written into it was silently orphaned. Ids now come from the element itself, and books built with an earlier version are migrated the first time a reader opens them. Two elements on a page that are written exactly alike are the one case this cannot separate — they are told apart by their order — so the build now warns about them and asks you to give each an `id`.
**textinput and other interactive elements**: Editing a page no longer wipes what readers have written into it. Ids are derived from the element itself instead of its position in the file, and books built with an earlier version are migrated the first time a reader opens them. Two elements on a page that are written exactly alike still cannot be told apart, so the build now warns about them and asks you to give each an `id`.

**accessibility**: A book with no `language` set was announced as Spanish by screen readers. The search field also had no placeholder and no label.
**accessibility**: A book with no `language` set was announced as Spanish by screen readers, and the search field had no placeholder and no label.

**hyperbook.json**: A syntax error in `hyperbook.json` now names the line it is on. It used to say `Missing or invalid hyperbook.json/hyperlibray.json` and leave you to find it.
**hyperbook.json**: A syntax error now names the line it is on, instead of only reporting `Missing or invalid hyperbook.json/hyperlibray.json`.

**dev**: `hyperbook dev -p 3000` searched from port 30001 when 3000 was already taken. The notice telling you a new version of Hyperbook is available could never appear.
**dev**: `hyperbook dev -p 3000` moves to the next free port when 3000 is taken, rather than to 30001. The notice telling you a new version of Hyperbook is available appears again.

:::

Expand All @@ -81,9 +81,9 @@ If you need a new feature, open an [issue](https://github.com/openpatch/hyperboo

:::tab{title="New :rocket:" id="new"}

**protect**: Protected content is really protected now. It is encrypted while your book is built, with a key derived from the password, and the browser decrypts it once a reader enters that password. Neither the content nor the password is in the page any more — before, both were, and anyone could read them from the page source. Blocks can be nested: the inner one is encrypted first, so an outer password opens only the outer layer.
**protect**: Protected content is really protected now. It is encrypted while your book is built, with a key derived from the password, and the browser decrypts it once a reader enters that password. Until now both the content and the password sat in the page, readable by anyone who viewed its source. Blocks can be nested: the inner one is encrypted first, so an outer password opens only the outer layer.

**protect**: A whole page or a whole section can be protected, by putting `protect` in its frontmatter instead of wrapping the content in a block. A section passes it down to every page and subsection inside it, so pages you add to the folder later are covered without you having to remember. One password opens the whole section — readers enter it once, not on every page. Protected entries stay in the navigation and get a lock next to their name.
**protect**: A whole page or a whole section can be protected, by putting `protect` in its frontmatter instead of wrapping the content in a block. A section passes it down to every page and subsection inside it, so pages you add to the folder later are covered automatically. One password opens the whole section — readers enter it once, not on every page. Protected entries stay in the navigation and get a lock next to their name.

**passwords**: Passwords can live in a `passwords.json` next to your `hyperbook.json` and be used by name, with `use="chapter-3"` on a protect block or `protect: chapter-3` in frontmatter. You then change a password in one place, and the file can stay out of your repository: the values can come from `HYPERBOOK_PASSWORDS_FILE`, `HYPERBOOK_PASSWORDS` or `HYPERBOOK_PASSWORD_<KEY>` instead. A name with no value stops the build rather than falling back to an empty password.

Expand All @@ -95,15 +95,15 @@ If you need a new feature, open an [issue](https://github.com/openpatch/hyperboo

:::tab{title="Improved :+1:" id="improved"}

**protect**: Unlocking is now an explicit step — an Unlock button, or Enter — and a wrong password says so. Deriving the key from the password takes a moment, which is what makes guessing passwords expensive, so it can no longer happen on every keystroke.
**protect**: Unlocking is now an explicit step — an Unlock button, or Enter — and a wrong password says so.

:::

:::tab{title="Fixed :bug:" id="fixed"}

**protect**: Protected content no longer reaches the search index. The index stores the full text of everything it covers, so until now the content of every protected block was sitting in `search.js`, readable without any password. It is also kept out of `llms.txt`, and headings inside a protected block no longer appear in the table of contents.
**protect**: Protected content no longer reaches the search index, where it was stored as full text and readable without any password. It is also kept out of `llms.txt`, and headings inside a protected block no longer appear in the table of contents.

**emoji**: Emoji shortcodes no longer fall back to the reader's own emoji font when you use the `twemoji` style. 616 of the 1913 shortcodes did, so a page mixed two different emoji styles — flags, keycaps and emoji like `:comet:`, `:asterisk:` and `:airplane:` were all affected. Every shortcode now has a Twemoji image. The names are unchanged, so nothing you have written needs to change.
**emoji**: Emoji shortcodes no longer fall back to the reader's own emoji font when you use the `twemoji` style, which made a page mix two emoji styles. 616 of the 1913 shortcodes were affected, among them flags, keycaps and emoji like `:comet:`, `:asterisk:` and `:airplane:`. The names are unchanged, so nothing you have written needs to change.

:::

Expand Down Expand Up @@ -139,7 +139,7 @@ If you need a new feature, open an [issue](https://github.com/openpatch/hyperboo

:::tab{title="Fixed :bug:" id="fixed"}

**webide**: The preview cut off the bottom of its content. The frame claimed the full height of its box instead of the space left below the title bar, so it hung over the lower edge and the part underneath was clipped — about 40 pixels, no matter which `height` you set on the block. Scrolling did not reach it either, because the frame did not know it was too tall. A preview now ends where its box ends.
**webide**: The preview no longer cuts off the bottom of its content. It overhung its box by about 40 pixels, whatever `height` you set on the block, and scrolling did not reach the clipped part.

:::

Expand All @@ -165,8 +165,7 @@ If you need a new feature, open an [issue](https://github.com/openpatch/hyperboo

:::tab{title="New :rocket:" id="new"}

**online-ide**: The IDE takes its theme from the book's dark mode toggle and follows it when a reader flips it.
**sql-ide**: The IDE takes its theme from the book's dark mode toggle and follows it when a reader flips it.
**online-ide**, **sql-ide**: Both editors take their theme from the book's dark mode toggle and follow it when a reader flips it.

:::

Expand Down Expand Up @@ -261,7 +260,7 @@ If you need a new feature, open an [issue](https://github.com/openpatch/hyperboo

:::tab{title="Improved :+1:" id="improved"}

**cloud**: The sync indicator tells its states apart by shape, not only by color. Every state previously drew the same person icon in a different shade, which made "unsynced" and "synced" indistinguishable for red-green color blind readers. The toolbar button now also carries the current state as its accessible name, and the status line is announced when it changes.
**cloud**: The sync indicator tells its states apart by shape, not only by color — "unsynced" and "synced" used to be the same icon in a different shade, and so were indistinguishable for red-green color blind readers. The toolbar button now also carries the current state as its accessible name, and the status line is announced when it changes.

**cloud**: States you can act on are surfaced outside the user drawer. A failed save, being offline, or a merge with another session now appear in a notice at the bottom of the page — with a retry button for a failed save, and a count of how much is still waiting while offline. Successful saves stay silent.

Expand All @@ -273,17 +272,15 @@ If you need a new feature, open an [issue](https://github.com/openpatch/hyperboo

:::tab{title="Fixed :bug:" id="fixed"}

**cloud**: Loading from the cloud failed whenever the server held events but no snapshot yet. The failure was silent, so work synced up but never came back down — on a second device, after clearing browser data, or during a conflict merge — until something happened to upload a full snapshot.

**cloud**: A sync conflict no longer discards local work. The client fetches the server state, replays its pending changes on top of it both locally and on the server, and only then reloads.
**cloud**: Work synced up but never came back down whenever the server held events but no snapshot yet — on a second device, after clearing browser data, or during a conflict merge. The failure was silent.

**cloud**: Changes made offline are no longer lost on reconnect. Every queued batch after the first carried an event ID recorded before the flush, so the server rejected it and the whole queue was discarded.
**cloud**: A sync conflict no longer discards local work. Pending changes are replayed on top of the server state before the page reloads.

**cloud**: Closing the tab no longer loses changes made in the last few seconds. Saves are debounced by up to two seconds, and nothing was sent when the page went away — it only warned. Pending changes are now flushed with a request that outlives the page.
**cloud**: Changes made offline are no longer lost on reconnect, and closing the tab no longer loses the last few seconds of work. Saves are debounced by up to two seconds, and were previously not sent when the page went away.

**cloud**: Two hyperbooks served from the same domain no longer share one sync counter, which put both into a permanent conflict loop.

**cloud**: The server keys rows by each table's own primary key. Tables not keyed by `id` — bookmarks, online IDE scripts, SQL IDE databases — were rewritten with a bogus `id` field, and updates and deletes against them silently missed.
**cloud**: Bookmarks, online IDE scripts and SQL IDE databases sync correctly. They are not keyed by `id`, and updates and deletes against them silently missed.

**cloud**: Replaying the same events twice no longer duplicates rows, and updates to nested fields (such as a saved zoom level) are no longer dropped.

Expand Down Expand Up @@ -355,7 +352,7 @@ The output panel reads like a terminal too: the prompt, the answer that was type

**turtle**: `turtle.numinput()` and `turtle.textinput()` use the same field, and follow CPython in asking again when the answer is not a number or falls outside `minval`/`maxval`.

**navigation**: A section that links to its own page is now easy to tell apart from one that only expands. Sections with an empty `index.md` are set in italics, and the title of a section that has its own page underlines on hover to show that it is a link. Subsections are judged on their own content, not on their parent's. The highlight for the section you are currently on works again — the stylesheet was still looking for `active` on the `<summary>` element, which moved to the surrounding `<details>` when sections became collapsible.
**navigation**: A section that links to its own page is now easy to tell apart from one that only expands. Sections with an empty `index.md` are set in italics, and the title of a section that has its own page underlines on hover to show that it is a link. Subsections are judged on their own content, not on their parent's. The highlight for the section you are currently on works again.

**dev**: `hyperbook dev` now knows which files each page pulls in, so saving a file rebuilds exactly the pages that used it. Editing a script referenced by a directive's `src=` attribute used to reload the browser without rebuilding the page, which brought back the old content; a file under `book/` did nothing at all. Snippets and templates now rebuild only the pages that include them rather than the whole book. Renaming a page also refreshes the navigation everywhere instead of only on the page you edited, and the search index no longer goes stale between full builds.

Expand Down Expand Up @@ -397,7 +394,7 @@ Directive icons are now drawn as SVG throughout — the download icons in **down

:::tab{title="New :rocket:" id="new"}

**links*: Links now support extensions:
**links**: Links now support extensions:

• `[Hallo](./hallo.md)` → resolves to /hallo
• `[Hallo](./hallo)` → resolves to /hallo
Expand Down Expand Up @@ -1502,6 +1499,8 @@ Add shareable URL builder with sections filter

:::

::::

## v0.70.0

::::tabs
Expand All @@ -1517,6 +1516,8 @@ next: ./next-page.md

:::

::::

## v0.69.0

::::tabs
Expand All @@ -1532,6 +1533,8 @@ next:

:::

::::

## v0.68.2

::::tabs
Expand All @@ -1542,6 +1545,8 @@ next:

:::

::::

## v0.68.1

::::tabs
Expand Down Expand Up @@ -2374,19 +2379,6 @@ Styling Improvements:

::::

## v0.46.1

::::tabs

:::tab{title="Fixed :bug:" id="fixed"}

- Resolved an issue where interactive elements failed to initialize correctly after being revealed within the protect element.
- Fixed an issue where collapsibles with the same ID were not synchronized.

:::

::::

## v0.46.0

::::tabs
Expand Down