From c0ec9dcf3ecc1fc95bff0e898e4df4ac333e9882 Mon Sep 17 00:00:00 2001 From: pearmini Date: Sat, 8 Nov 2025 16:27:40 -0500 Subject: [PATCH 1/7] Split API page --- app/docs/api-echo-clear.recho.js | 20 +++ app/docs/api-echo.recho.js | 38 ++++ app/docs/api-inspect.recho.js | 42 +++++ app/docs/api-interval.recho.js | 21 +++ app/docs/api-invalidation.recho.js | 30 ++++ app/docs/api-now.recho.js | 20 +++ app/docs/api-number.recho.js | 65 +++++++ app/docs/api-radio.recho.js | 25 +++ app/docs/api-reference.recho.js | 273 ++++------------------------- app/docs/api-require.recho.js | 36 ++++ app/docs/api-toggle.recho.js | 29 +++ 11 files changed, 362 insertions(+), 237 deletions(-) create mode 100644 app/docs/api-echo-clear.recho.js create mode 100644 app/docs/api-echo.recho.js create mode 100644 app/docs/api-inspect.recho.js create mode 100644 app/docs/api-interval.recho.js create mode 100644 app/docs/api-invalidation.recho.js create mode 100644 app/docs/api-now.recho.js create mode 100644 app/docs/api-number.recho.js create mode 100644 app/docs/api-radio.recho.js create mode 100644 app/docs/api-require.recho.js create mode 100644 app/docs/api-toggle.recho.js diff --git a/app/docs/api-echo-clear.recho.js b/app/docs/api-echo-clear.recho.js new file mode 100644 index 0000000..964ff55 --- /dev/null +++ b/app/docs/api-echo-clear.recho.js @@ -0,0 +1,20 @@ +/** + * @title echo.clear() + * @order 11 + */ + +/** + * ============================================================================ + * = echo.clear() = + * ============================================================================ + * + * Clear the output of the current block. + * + * @returns {void} + */ + +{ + echo("Hello, World!"); + setTimeout(() => echo.clear(), 1000); +} + diff --git a/app/docs/api-echo.recho.js b/app/docs/api-echo.recho.js new file mode 100644 index 0000000..ddd7a85 --- /dev/null +++ b/app/docs/api-echo.recho.js @@ -0,0 +1,38 @@ +/** + * @title echo(...values) + * @order 10 + */ + +/** + * ============================================================================ + * = echo(...values) = + * ============================================================================ + * + * Echos one or more values inline with your code as comments. If only one + * value is provided, return the value itself. If multiple values are provided, + * return all the values as an array. + * + * @param {...any} values - The values to echo. + * @returns {any} The values if multiple values are provided, or the single value. + */ + +//➜ "Hello, World!" +echo("Hello, World!"); + +//➜ 1 2 3 +echo(1, 2, 3); + +//➜ Peter: Age = 20 +//➜ Height = 180 +echo("Peter: ", "Age = 20\nHeight = 180"); + +const a = echo(1 + 2); + +//➜ 3 +echo(a); + +const numbers = echo(1, 2, 3); + +//➜ [ 1, 2, 3 ] +echo(numbers); + diff --git a/app/docs/api-inspect.recho.js b/app/docs/api-inspect.recho.js new file mode 100644 index 0000000..6f70fce --- /dev/null +++ b/app/docs/api-inspect.recho.js @@ -0,0 +1,42 @@ +/** + * @title recho.inspect(value[, options]) + * @order 12 + */ + +/** + * ============================================================================ + * = recho.inspect(value[, options]) = + * ============================================================================ + * + * Formats a value for inspection with customizable options. + * + * @param {any} value - The value to inspect. + * @param {Object} [options] - The options to format the output. + * @param {string} [options.quote="double"] - The quote style of the output ("single", "double", or false). + * @param {number} [options.indent=null] - The indentation of the output (null, "\t", or a positive integer). + * @param {number} [options.limit=200] - The character limit of the output. + * @returns {string} The formatted string representation of the value. + */ + +//➜ "Hello, World!" +const defaultQuotedString = echo("Hello, World!"); + +//➜ 'Hello, World!' +const singleQuotedString = echo(recho.inspect("Hello, World!", {quote: "single"})); + +//➜ "Hello, World!" +const doubleQuotedString = echo(recho.inspect("Hello, World!", {quote: "double"})); + +//➜ Hello, World! +const unquotedString = echo(recho.inspect("Hello, World!", {quote: false})); + +//➜ { +//➜ a: 1, +//➜ b: 2, +//➜ c: 3 +//➜ } +const indentedObject = echo(recho.inspect({a: 1, b: 2, c: 3}, {indent: 2})); + +//➜ [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, … +const array1000 = echo(recho.inspect(new Array(1000).fill(0), {limit: Infinity})); + diff --git a/app/docs/api-interval.recho.js b/app/docs/api-interval.recho.js new file mode 100644 index 0000000..6e5c6fb --- /dev/null +++ b/app/docs/api-interval.recho.js @@ -0,0 +1,21 @@ +/** + * @title recho.interval(milliseconds) + * @order 15 + */ + +/** + * ============================================================================ + * = recho.interval(milliseconds) = + * ============================================================================ + * + * Returns a generator that yields values at a specified interval. + * + * @param {number} milliseconds - The interval in milliseconds. + * @returns {Generator} + */ + +const interval = recho.interval(1000); + +//➜ 1 +echo(interval); + diff --git a/app/docs/api-invalidation.recho.js b/app/docs/api-invalidation.recho.js new file mode 100644 index 0000000..8f9db5b --- /dev/null +++ b/app/docs/api-invalidation.recho.js @@ -0,0 +1,30 @@ +/** + * @title invalidation() + * @order 13 + */ + +/** + * ============================================================================ + * = invalidation() = + * ============================================================================ + * + * Returns a promise that resolves before re-running the current block. + * + * @returns {Promise} + */ + +//➜ 9 +{ + let count = echo(10); + + const timer = setInterval(() => { + if (count-- <= 0) clearInterval(timer); + else { + echo.clear(); + echo(count); + } + }, 1000); + + invalidation.then(() => clearInterval(timer)); +} + diff --git a/app/docs/api-now.recho.js b/app/docs/api-now.recho.js new file mode 100644 index 0000000..e5a79a6 --- /dev/null +++ b/app/docs/api-now.recho.js @@ -0,0 +1,20 @@ +/** + * @title recho.now() + * @order 14 + */ + +/** + * ============================================================================ + * = recho.now() = + * ============================================================================ + * + * Returns a generator that yields the current time continuously. + * + * @returns {Generator} + */ + +const now = recho.now(); + +//➜ 1757422825350 +echo(now); + diff --git a/app/docs/api-number.recho.js b/app/docs/api-number.recho.js new file mode 100644 index 0000000..c427aa2 --- /dev/null +++ b/app/docs/api-number.recho.js @@ -0,0 +1,65 @@ +/** + * @title recho.number(value[, options]) + * @order 19 + */ + +/** + * ============================================================================ + * = recho.number(value[, options]) = + * ============================================================================ + * + * Creates an interactive number input control that returns a constrained number. + * In the editor, this renders as increment and decrement buttons around the + * number value. + * + * @param {number} value - The initial number value. + * @param {Object} [options] - The options to constrain the number. + * @param {number} [options.min=-Infinity] - The minimum allowed value. + * @param {number} [options.max=Infinity] - The maximum allowed value. + * @param {number} [options.step=1] - The step size for increment/decrement operations. + * @returns {number} The number value, constrained to the specified range. + */ + +const count = recho.number(5); + +const volume = recho.number(5.5, {min: 0, max: 10, step: 0.1}); + +//➜ "Volume ▓▓▓▓▓▒▒▒▒▒ 55%" +{ + const filled = "▓".repeat(Math.floor(volume)); + const empty = "▒".repeat(Math.ceil(10 - volume)); + echo(`Volume ${filled}${empty} ${volume * 10}%`); +} + +const signal = recho.number(0b1010101010101010, {min: 0, max: 0xffff}); + +//➜ ╶┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐ +//➜ └┘└┘└┘└┘└┘└┘└┘└ +{ + let upper = ""; + let lower = ""; + let lastBit = null; + for (const bit of signal.toString(2)) { + if (lastBit === null) { + upper += bit == "1" ? "╶" : " "; + lower += bit == "1" ? " " : "╶"; + } else if (lastBit === bit) { + upper += bit == "1" ? "─" : " "; + lower += bit == "1" ? " " : "─"; + } else { + upper += bit == "1" ? "┌" : "┐"; + lower += bit == "1" ? "┘" : "└"; + } + lastBit = bit; + } + echo(upper + "\n" + lower); +} + +const temperature = recho.number(24, {min: -10, max: 40, step: 0.5}); + +//➜ "The room temperature is 24 °C (75.2 °F)." +{ + const fahrenheit = (temperature * 9) / 5 + 32; + echo(`The room temperature is ${temperature} °C (${fahrenheit} °F).`); +} + diff --git a/app/docs/api-radio.recho.js b/app/docs/api-radio.recho.js new file mode 100644 index 0000000..959a1ff --- /dev/null +++ b/app/docs/api-radio.recho.js @@ -0,0 +1,25 @@ +/** + * @title recho.radio(index, options) + * @order 18 + */ + +/** + * ============================================================================ + * = recho.radio(index, options) = + * ============================================================================ + * + * Creates an interactive radio button group that returns the selected option. + * In the editor, this renders as radio buttons next to each option in the array. + * + * @param {number} index - The index of the selected option (0-based). + * @param {Array} options - The array of options to choose from. + * @returns {any} The selected option from the options array. + */ + +const size = recho.radio(1, ["small", "medium", "large"]); + +const color = recho.radio(0, ["red", "green", "blue"]); + +//➜ "This is a red medium button." +echo(`This is a ${color} ${size} button.`); + diff --git a/app/docs/api-reference.recho.js b/app/docs/api-reference.recho.js index 9f9e4a5..5db449f 100644 --- a/app/docs/api-reference.recho.js +++ b/app/docs/api-reference.recho.js @@ -5,284 +5,83 @@ /** * ============================================================================ - * = API Reference = + * = API Reference = * ============================================================================ * - * Recho Notebook provides a set of APIs to help you create notebooks. - */ - -/** - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * echo(...values) - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Recho Notebook provides a set of APIs to help you create reactive notebooks + * and interactive visualizations. This page provides an overview of all + * available APIs. * - * Echos one or more values inline with your code as comments. If only one - * value is provided, return the value itself. If multiple values are provided, - * return all the values as an array. - * - * @param {...any} values - The values to echo. - * @returns {any} The values if multiple values are provided, or the single value. + * Click on any API below to see detailed documentation and examples. */ -//➜ "Hello, World!" -echo("Hello, World!"); - -//➜ 1 2 3 -echo(1, 2, 3); - -//➜ Peter: Age = 20 -//➜ Height = 180 -echo("Peter: ", "Age = 20\nHeight = 180"); - -const a = echo(1 + 2); - -//➜ 3 -echo(a); - -const numbers = echo(1, 2, 3); - -//➜ [ 1, 2, 3 ] -echo(numbers); - /** * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * recho.inspect(value[, options]) + * Core APIs * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Formats a value for inspection with customizable options. - * - * @param {any} value - The value to inspect. - * @param {Object} [options] - The options to format the output. - * @param {string} [options.quote="double"] - The quote style of the output ("single", "double", or false). - * @param {number} [options.indent=null] - The indentation of the output (null, "\t", or a positive integer). - * @param {number} [options.limit=200] - The character limit of the output. - * @returns {string} The formatted string representation of the value. */ -//➜ "Hello, World!" -const defaultQuotedString = echo("Hello, World!"); - -//➜ 'Hello, World!' -const singleQuotedString = echo(recho.inspect("Hello, World!", {quote: "single"})); - -//➜ "Hello, World!" -const doubleQuotedString = echo(recho.inspect("Hello, World!", {quote: "double"})); +// echo(...values) - Echo values inline with your code as comments +// See: https://recho.dev/notebook/docs/api-echo -//➜ Hello, World! -const unquotedString = echo(recho.inspect("Hello, World!", {quote: false})); +// recho.inspect(value[, options]) - Format values for inspection +// See: https://recho.dev/notebook/docs/api-inspect -//➜ { -//➜ a: 1, -//➜ b: 2, -//➜ c: 3 -//➜ } -const indentedObject = echo(recho.inspect({a: 1, b: 2, c: 3}, {indent: 2})); +// echo.clear() - Clear the output of the current block +// See: https://recho.dev/notebook/docs/api-echo-clear -//➜ [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, … -const array1000 = echo(recho.inspect(new Array(1000).fill(0), {limit: Infinity})); +// invalidation() - Promise that resolves before re-running the current block +// See: https://recho.dev/notebook/docs/api-invalidation /** * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * echo.clear() + * Reactive APIs * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Clear the output of the current block. - * - * @returns {void} */ -{ - echo("Hello, World!"); - setTimeout(() => echo.clear(), 1000); -} - -/** - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * invalidation() - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Returns a promise that resolves before re-running the current block. - * - * @returns {Promise} - */ +// recho.now() - Generator that yields the current time continuously +// See: https://recho.dev/notebook/docs/api-now -//➜ 9 -{ - let count = echo(10); - - const timer = setInterval(() => { - if (count-- <= 0) clearInterval(timer); - else { - echo.clear(); - echo(count); - } - }, 1000); - - invalidation.then(() => clearInterval(timer)); -} +// recho.interval(milliseconds) - Generator that yields values at intervals +// See: https://recho.dev/notebook/docs/api-interval /** * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * recho.now() + * Import APIs * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Returns a generator that yields the current time continuously. - * - * @returns {Generator} */ -const now = recho.now(); - -//➜ 1757422825350 -echo(now); +// recho.require(...names) - Import JavaScript packages from npm +// See: https://recho.dev/notebook/docs/api-require /** * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * recho.interval(milliseconds) + * Interactive Controls * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Returns a generator that yields values at a specified interval. - * - * @param {number} milliseconds - The interval in milliseconds. - * @returns {Generator} */ -const interval = recho.interval(1000); +// recho.toggle(value) - Interactive toggle (checkbox) control +// See: https://recho.dev/notebook/docs/api-toggle -//➜ 1 -echo(interval); +// recho.radio(index, options) - Interactive radio button group +// See: https://recho.dev/notebook/docs/api-radio -/** - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * recho.require(...names) - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Imports one or more JavaScript packages. The import specifiers must be valid - * npm package names with optional version specifiers. It use `d3-require` - * under the hood. - * - * @param {string} ...names - The names of the packages to import. - * @returns {any} The imported package. - * @see https://github.com/d3/d3-require - */ - -const Noise = recho.require("perlin-noise-3d"); - -//➜ [ 0.5428002520733116, 0.5424832952636395, 0.5414633391270067, 0.5397183031066122… -{ - const noise = new Noise(); - const values = []; - for (let i = 0; i < 100; i++) { - values.push(noise.get(i / 100, i / 100, i / 100)); - } - echo(recho.inspect(values, {limit: 80})); -} - -const d3 = recho.require("d3-array", "d3-random"); - -//➜ [ 6, 4, 1, 2, 5, 3, 3, 0, 6, 2 ] -echo(d3.range(10).map(d3.randomInt(0, 10))); +// recho.number(value[, options]) - Interactive number input control +// See: https://recho.dev/notebook/docs/api-number /** * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * recho.toggle(value) + * Quick Example * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Creates an interactive toggle (checkbox) control that returns the boolean - * value. In the editor, this renders as a clickable checkbox that updates the - * code when toggled. - * - * @param {boolean} value - The initial boolean value. - * @returns {boolean} The boolean value. */ -const isEnabled = recho.toggle(true); - -const isVisible = recho.toggle(false); - -//➜ "The button is enabled." -//➜ "The button is hidden." -{ - echo(`The button is ${isEnabled ? "enabled" : "disabled"}.`); - echo(`The button is ${isVisible ? "visible" : "hidden"}.`); -} - -/** - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * recho.radio(index, options) - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Creates an interactive radio button group that returns the selected option. - * In the editor, this renders as radio buttons next to each option in the array. - * - * @param {number} index - The index of the selected option (0-based). - * @param {Array} options - The array of options to choose from. - * @returns {any} The selected option from the options array. - */ - -const size = recho.radio(1, ["small", "medium", "large"]); - -const color = recho.radio(0, ["red", "green", "blue"]); - -//➜ "This is a red medium button." -echo(`This is a ${color} ${size} button.`); - -/** - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * recho.number(value[, options]) - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Creates an interactive number input control that returns a constrained number. - * In the editor, this renders as increment and decrement buttons around the - * number value. - * - * @param {number} value - The initial number value. - * @param {Object} [options] - The options to constrain the number. - * @param {number} [options.min=-Infinity] - The minimum allowed value. - * @param {number} [options.max=Infinity] - The maximum allowed value. - * @param {number} [options.step=1] - The step size for increment/decrement operations. - * @returns {number} The number value, constrained to the specified range. - */ - -const count = recho.number(5); - -const volume = recho.number(5.5, {min: 0, max: 10, step: 0.1}); - -//➜ "Volume ▓▓▓▓▓▒▒▒▒▒ 55%" -{ - const filled = "▓".repeat(Math.floor(volume)); - const empty = "▒".repeat(Math.ceil(10 - volume)); - echo(`Volume ${filled}${empty} ${volume * 10}%`); -} +// Here's a quick example combining multiple APIs: -const signal = recho.number(0b1010101010101010, {min: 0, max: 0xffff}); +const count = recho.number(0, {min: 0, max: 10, step: 1}); -//➜ ╶┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐ -//➜ └┘└┘└┘└┘└┘└┘└┘└ -{ - let upper = ""; - let lower = ""; - let lastBit = null; - for (const bit of signal.toString(2)) { - if (lastBit === null) { - upper += bit == "1" ? "╶" : " "; - lower += bit == "1" ? " " : "╶"; - } else if (lastBit === bit) { - upper += bit == "1" ? "─" : " "; - lower += bit == "1" ? " " : "─"; - } else { - upper += bit == "1" ? "┌" : "┐"; - lower += bit == "1" ? "┘" : "└"; - } - lastBit = bit; - } - echo(upper + "\n" + lower); -} +const isRunning = recho.toggle(false); -const temperature = recho.number(24, {min: -10, max: 40, step: 0.5}); +const speed = recho.radio(1, ["slow", "medium", "fast"]); -//➜ "The room temperature is 24 °C (75.2 °F)." -{ - const fahrenheit = (temperature * 9) / 5 + 32; - echo(`The room temperature is ${temperature} °C (${fahrenheit} °F).`); -} +//➜ "Count: 0, Status: stopped, Speed: medium" +echo(`Count: ${count}, Status: ${isRunning ? "running" : "stopped"}, Speed: ${speed}`); diff --git a/app/docs/api-require.recho.js b/app/docs/api-require.recho.js new file mode 100644 index 0000000..30b3bbc --- /dev/null +++ b/app/docs/api-require.recho.js @@ -0,0 +1,36 @@ +/** + * @title recho.require(...names) + * @order 16 + */ + +/** + * ============================================================================ + * = recho.require(...names) = + * ============================================================================ + * + * Imports one or more JavaScript packages. The import specifiers must be valid + * npm package names with optional version specifiers. It use `d3-require` + * under the hood. + * + * @param {string} ...names - The names of the packages to import. + * @returns {any} The imported package. + * @see https://github.com/d3/d3-require + */ + +const Noise = recho.require("perlin-noise-3d"); + +//➜ [ 0.5428002520733116, 0.5424832952636395, 0.5414633391270067, 0.5397183031066122… +{ + const noise = new Noise(); + const values = []; + for (let i = 0; i < 100; i++) { + values.push(noise.get(i / 100, i / 100, i / 100)); + } + echo(recho.inspect(values, {limit: 80})); +} + +const d3 = recho.require("d3-array", "d3-random"); + +//➜ [ 6, 4, 1, 2, 5, 3, 3, 0, 6, 2 ] +echo(d3.range(10).map(d3.randomInt(0, 10))); + diff --git a/app/docs/api-toggle.recho.js b/app/docs/api-toggle.recho.js new file mode 100644 index 0000000..a9be23e --- /dev/null +++ b/app/docs/api-toggle.recho.js @@ -0,0 +1,29 @@ +/** + * @title recho.toggle(value) + * @order 17 + */ + +/** + * ============================================================================ + * = recho.toggle(value) = + * ============================================================================ + * + * Creates an interactive toggle (checkbox) control that returns the boolean + * value. In the editor, this renders as a clickable checkbox that updates the + * code when toggled. + * + * @param {boolean} value - The initial boolean value. + * @returns {boolean} The boolean value. + */ + +const isEnabled = recho.toggle(true); + +const isVisible = recho.toggle(false); + +//➜ "The button is enabled." +//➜ "The button is hidden." +{ + echo(`The button is ${isEnabled ? "enabled" : "disabled"}.`); + echo(`The button is ${isVisible ? "visible" : "hidden"}.`); +} + From 98cb324763f70723209cecb9a0af07f671ec2697 Mon Sep 17 00:00:00 2001 From: pearmini Date: Sat, 8 Nov 2025 16:37:16 -0500 Subject: [PATCH 2/7] Update API index --- app/docs/api-reference.recho.js | 66 ++++++++------------------------- 1 file changed, 15 insertions(+), 51 deletions(-) diff --git a/app/docs/api-reference.recho.js b/app/docs/api-reference.recho.js index 5db449f..3e33e01 100644 --- a/app/docs/api-reference.recho.js +++ b/app/docs/api-reference.recho.js @@ -17,71 +17,35 @@ /** * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * Core APIs + * Core APIs * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * - echo(...values) - Echo values inline with your code as comments (https://recho.dev/notebook/docs/api-echo) + * - echo.clear() - Clear the output of the current block (https://recho.dev/notebook/docs/api-echo-clear) + * - invalidation() - Promise that resolves before re-running the current block (https://recho.dev/notebook/docs/api-invalidation) + * - recho.inspect(value[, options]) - Format values for inspection (https://recho.dev/notebook/docs/api-inspect) */ -// echo(...values) - Echo values inline with your code as comments -// See: https://recho.dev/notebook/docs/api-echo - -// recho.inspect(value[, options]) - Format values for inspection -// See: https://recho.dev/notebook/docs/api-inspect - -// echo.clear() - Clear the output of the current block -// See: https://recho.dev/notebook/docs/api-echo-clear - -// invalidation() - Promise that resolves before re-running the current block -// See: https://recho.dev/notebook/docs/api-invalidation - /** * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * Reactive APIs + * Inputs * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * - recho.toggle(value) - Interactive toggle (checkbox) control (https://recho.dev/notebook/docs/api-toggle) + * - recho.radio(index, options) - Interactive radio button group (https://recho.dev/notebook/docs/api-radio) + * - recho.number(value[, options]) - Interactive number input control (https://recho.dev/notebook/docs/api-number) */ -// recho.now() - Generator that yields the current time continuously -// See: https://recho.dev/notebook/docs/api-now - -// recho.interval(milliseconds) - Generator that yields values at intervals -// See: https://recho.dev/notebook/docs/api-interval - /** * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * Import APIs + * Generators * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * - recho.now() - Generator that yields the current time continuously (https://recho.dev/notebook/docs/api-now) + * - recho.interval(milliseconds) - Generator that yields values at intervals (https://recho.dev/notebook/docs/api-interval) */ -// recho.require(...names) - Import JavaScript packages from npm -// See: https://recho.dev/notebook/docs/api-require - /** * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * Interactive Controls + * Helpers * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * - recho.require(...names) - Import JavaScript packages from npm (https://recho.dev/notebook/docs/api-require) */ - -// recho.toggle(value) - Interactive toggle (checkbox) control -// See: https://recho.dev/notebook/docs/api-toggle - -// recho.radio(index, options) - Interactive radio button group -// See: https://recho.dev/notebook/docs/api-radio - -// recho.number(value[, options]) - Interactive number input control -// See: https://recho.dev/notebook/docs/api-number - -/** - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * Quick Example - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -// Here's a quick example combining multiple APIs: - -const count = recho.number(0, {min: 0, max: 10, step: 1}); - -const isRunning = recho.toggle(false); - -const speed = recho.radio(1, ["slow", "medium", "fast"]); - -//➜ "Count: 0, Status: stopped, Speed: medium" -echo(`Count: ${count}, Status: ${isRunning ? "running" : "stopped"}, Speed: ${speed}`); From f0f0b967194a56281d53649c06a357b87314203f Mon Sep 17 00:00:00 2001 From: pearmini Date: Sat, 8 Nov 2025 16:41:29 -0500 Subject: [PATCH 3/7] Update API reference --- app/docs/api-reference.recho.js | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/app/docs/api-reference.recho.js b/app/docs/api-reference.recho.js index 3e33e01..7a026dc 100644 --- a/app/docs/api-reference.recho.js +++ b/app/docs/api-reference.recho.js @@ -13,9 +13,7 @@ * available APIs. * * Click on any API below to see detailed documentation and examples. - */ - -/** + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Core APIs * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -24,26 +22,20 @@ * - echo.clear() - Clear the output of the current block (https://recho.dev/notebook/docs/api-echo-clear) * - invalidation() - Promise that resolves before re-running the current block (https://recho.dev/notebook/docs/api-invalidation) * - recho.inspect(value[, options]) - Format values for inspection (https://recho.dev/notebook/docs/api-inspect) - */ - -/** + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Inputs * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * - recho.toggle(value) - Interactive toggle (checkbox) control (https://recho.dev/notebook/docs/api-toggle) * - recho.radio(index, options) - Interactive radio button group (https://recho.dev/notebook/docs/api-radio) * - recho.number(value[, options]) - Interactive number input control (https://recho.dev/notebook/docs/api-number) - */ - -/** + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Generators * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * - recho.now() - Generator that yields the current time continuously (https://recho.dev/notebook/docs/api-now) * - recho.interval(milliseconds) - Generator that yields values at intervals (https://recho.dev/notebook/docs/api-interval) - */ - -/** + * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Helpers * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From b63f49425211d9aead75757e61c3b083f4b1dccf Mon Sep 17 00:00:00 2001 From: pearmini Date: Sat, 8 Nov 2025 16:57:37 -0500 Subject: [PATCH 4/7] Group APIs --- app/Sidebar.js | 78 +++++++++++++++++++++++++------ app/docs/DocsLayoutClient.jsx | 6 +-- app/docs/layout.jsx | 14 +++++- app/docs/nav.config.js | 86 +++++++++++++++++++++++++++++++++++ 4 files changed, 167 insertions(+), 17 deletions(-) create mode 100644 app/docs/nav.config.js diff --git a/app/Sidebar.js b/app/Sidebar.js index 2cd2860..178037b 100644 --- a/app/Sidebar.js +++ b/app/Sidebar.js @@ -2,8 +2,54 @@ import Link from "next/link"; import {usePathname} from "next/navigation"; import {cn} from "./cn.js"; +import {useState} from "react"; +import {ChevronRight} from "lucide-react"; -export function Sidebar({docs, onLinkClick}) { +function NavItem({doc, isActive, onClick}) { + return ( + +
  • {doc.title}
  • + + ); +} + +function NavGroup({group, docsMap, isActive, onClick}) { + const pathname = usePathname(); + const isGroupActive = group.slug === pathname.split("/docs/")[1] || group.items.some((item) => isActive(item.slug)); + const [isOpen, setIsOpen] = useState(isGroupActive); + + return ( +
    +
    + + {group.title} + + +
    + {isOpen && ( +
      + {group.items.map((item) => { + const doc = docsMap[item.slug]; + if (!doc) return null; + return ; + })} +
    + )} +
    + ); +} + +export function Sidebar({navStructure, docsMap, onLinkClick}) { const pathname = usePathname(); const isActive = (slug) => pathname.startsWith(`/docs/${slug}`); const handleLinkClick = () => { @@ -11,20 +57,26 @@ export function Sidebar({docs, onLinkClick}) { onLinkClick(); } }; + return (
      - {docs - .sort((a, b) => a.order - b.order) - .map((doc) => ( - -
    • {doc.title}
    • - - ))} + {navStructure.map((item, index) => { + if (item.type === "group") { + return ( + + ); + } else { + const doc = docsMap[item.slug]; + if (!doc) return null; + return ; + } + })}
    ); } diff --git a/app/docs/DocsLayoutClient.jsx b/app/docs/DocsLayoutClient.jsx index b3556b8..f6bb14a 100644 --- a/app/docs/DocsLayoutClient.jsx +++ b/app/docs/DocsLayoutClient.jsx @@ -4,7 +4,7 @@ import {cn} from "../cn.js"; import {useState, useEffect, useRef} from "react"; import {TableOfContents} from "lucide-react"; -export function DocsLayoutClient({docs, children}) { +export function DocsLayoutClient({navStructure, docsMap, children}) { const [overlayOpen, setOverlayOpen] = useState(false); const overlayRef = useRef(null); @@ -32,7 +32,7 @@ export function DocsLayoutClient({docs, children}) {
    - +
    @@ -54,7 +54,7 @@ export function DocsLayoutClient({docs, children}) {
    - setOverlayOpen(false)} /> + setOverlayOpen(false)} />
    diff --git a/app/docs/layout.jsx b/app/docs/layout.jsx index 6ff841c..77561ac 100644 --- a/app/docs/layout.jsx +++ b/app/docs/layout.jsx @@ -1,5 +1,6 @@ import {getAllJSDocs} from "../utils.js"; import {DocsLayoutClient} from "./DocsLayoutClient.jsx"; +import {docsNavConfig} from "./nav.config.js"; export const metadata = { title: "Docs | Recho Notebook", @@ -8,5 +9,16 @@ export const metadata = { export default function Layout({children}) { const docs = getAllJSDocs(); - return {children}; + + // Create a map of slug -> doc for easy lookup + const docsMap = docs.reduce((acc, doc) => { + acc[doc.slug] = doc; + return acc; + }, {}); + + return ( + + {children} + + ); } diff --git a/app/docs/nav.config.js b/app/docs/nav.config.js new file mode 100644 index 0000000..120e49a --- /dev/null +++ b/app/docs/nav.config.js @@ -0,0 +1,86 @@ +/** + * Navigation configuration for the docs section. + * Defines the structure and grouping of documentation pages. + */ + +export const docsNavConfig = [ + { + type: "page", + slug: "introduction", + }, + { + type: "page", + slug: "getting-started", + }, + { + type: "page", + slug: "inline-echoing", + }, + { + type: "page", + slug: "reactive-blocks", + }, + { + type: "page", + slug: "animations-authoring", + }, + { + type: "page", + slug: "aynchronous-operations", + }, + { + type: "page", + slug: "libraries-imports", + }, + { + type: "page", + slug: "errors-handling", + }, + { + type: "group", + title: "API Reference", + slug: "api-reference", + items: [ + { + type: "page", + slug: "api-echo", + }, + { + type: "page", + slug: "api-echo-clear", + }, + { + type: "page", + slug: "api-inspect", + }, + { + type: "page", + slug: "api-invalidation", + }, + { + type: "page", + slug: "api-now", + }, + { + type: "page", + slug: "api-interval", + }, + { + type: "page", + slug: "api-require", + }, + { + type: "page", + slug: "api-toggle", + }, + { + type: "page", + slug: "api-radio", + }, + { + type: "page", + slug: "api-number", + }, + ], + }, +]; From 397d15cc34392d8bcea121c172d28f11af368ae2 Mon Sep 17 00:00:00 2001 From: pearmini Date: Sat, 8 Nov 2025 17:03:17 -0500 Subject: [PATCH 5/7] Make API open by default --- app/Sidebar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Sidebar.js b/app/Sidebar.js index 178037b..6d6b23e 100644 --- a/app/Sidebar.js +++ b/app/Sidebar.js @@ -20,7 +20,7 @@ function NavItem({doc, isActive, onClick}) { function NavGroup({group, docsMap, isActive, onClick}) { const pathname = usePathname(); const isGroupActive = group.slug === pathname.split("/docs/")[1] || group.items.some((item) => isActive(item.slug)); - const [isOpen, setIsOpen] = useState(isGroupActive); + const [isOpen, setIsOpen] = useState(group.slug === "api-reference" || isGroupActive); return (
    From a881e787b2f57e6bc26b92aa102ae1014219dd80 Mon Sep 17 00:00:00 2001 From: pearmini Date: Sat, 8 Nov 2025 17:05:19 -0500 Subject: [PATCH 6/7] Remove oder attribute --- app/docs/animations-authoring.recho.js | 1 - app/docs/api-echo-clear.recho.js | 1 - app/docs/api-echo.recho.js | 1 - app/docs/api-inspect.recho.js | 1 - app/docs/api-interval.recho.js | 1 - app/docs/api-invalidation.recho.js | 1 - app/docs/api-now.recho.js | 1 - app/docs/api-number.recho.js | 1 - app/docs/api-radio.recho.js | 1 - app/docs/api-reference.recho.js | 1 - app/docs/api-require.recho.js | 1 - app/docs/api-toggle.recho.js | 1 - app/docs/aynchronous-operations.recho.js | 1 - app/docs/errors-handling.recho.js | 1 - app/docs/getting-started.recho.js | 1 - app/docs/inline-echoing.recho.js | 1 - app/docs/introduction.recho.js | 1 - app/docs/libraries-imports.recho.js | 1 - app/docs/reactive-blocks.recho.js | 1 - 19 files changed, 19 deletions(-) diff --git a/app/docs/animations-authoring.recho.js b/app/docs/animations-authoring.recho.js index 1e60c81..22e97a8 100644 --- a/app/docs/animations-authoring.recho.js +++ b/app/docs/animations-authoring.recho.js @@ -1,6 +1,5 @@ /** * @title Animations Authoring - * @order 5 */ /** diff --git a/app/docs/api-echo-clear.recho.js b/app/docs/api-echo-clear.recho.js index 964ff55..6bd9b64 100644 --- a/app/docs/api-echo-clear.recho.js +++ b/app/docs/api-echo-clear.recho.js @@ -1,6 +1,5 @@ /** * @title echo.clear() - * @order 11 */ /** diff --git a/app/docs/api-echo.recho.js b/app/docs/api-echo.recho.js index ddd7a85..c8514ae 100644 --- a/app/docs/api-echo.recho.js +++ b/app/docs/api-echo.recho.js @@ -1,6 +1,5 @@ /** * @title echo(...values) - * @order 10 */ /** diff --git a/app/docs/api-inspect.recho.js b/app/docs/api-inspect.recho.js index 6f70fce..6452689 100644 --- a/app/docs/api-inspect.recho.js +++ b/app/docs/api-inspect.recho.js @@ -1,6 +1,5 @@ /** * @title recho.inspect(value[, options]) - * @order 12 */ /** diff --git a/app/docs/api-interval.recho.js b/app/docs/api-interval.recho.js index 6e5c6fb..d9b13e9 100644 --- a/app/docs/api-interval.recho.js +++ b/app/docs/api-interval.recho.js @@ -1,6 +1,5 @@ /** * @title recho.interval(milliseconds) - * @order 15 */ /** diff --git a/app/docs/api-invalidation.recho.js b/app/docs/api-invalidation.recho.js index 8f9db5b..6fcc3a1 100644 --- a/app/docs/api-invalidation.recho.js +++ b/app/docs/api-invalidation.recho.js @@ -1,6 +1,5 @@ /** * @title invalidation() - * @order 13 */ /** diff --git a/app/docs/api-now.recho.js b/app/docs/api-now.recho.js index e5a79a6..5053e99 100644 --- a/app/docs/api-now.recho.js +++ b/app/docs/api-now.recho.js @@ -1,6 +1,5 @@ /** * @title recho.now() - * @order 14 */ /** diff --git a/app/docs/api-number.recho.js b/app/docs/api-number.recho.js index c427aa2..56d83dd 100644 --- a/app/docs/api-number.recho.js +++ b/app/docs/api-number.recho.js @@ -1,6 +1,5 @@ /** * @title recho.number(value[, options]) - * @order 19 */ /** diff --git a/app/docs/api-radio.recho.js b/app/docs/api-radio.recho.js index 959a1ff..8ce69ab 100644 --- a/app/docs/api-radio.recho.js +++ b/app/docs/api-radio.recho.js @@ -1,6 +1,5 @@ /** * @title recho.radio(index, options) - * @order 18 */ /** diff --git a/app/docs/api-reference.recho.js b/app/docs/api-reference.recho.js index 7a026dc..b1d75f2 100644 --- a/app/docs/api-reference.recho.js +++ b/app/docs/api-reference.recho.js @@ -1,6 +1,5 @@ /** * @title API Reference - * @order 9 */ /** diff --git a/app/docs/api-require.recho.js b/app/docs/api-require.recho.js index 30b3bbc..484e95f 100644 --- a/app/docs/api-require.recho.js +++ b/app/docs/api-require.recho.js @@ -1,6 +1,5 @@ /** * @title recho.require(...names) - * @order 16 */ /** diff --git a/app/docs/api-toggle.recho.js b/app/docs/api-toggle.recho.js index a9be23e..39464a5 100644 --- a/app/docs/api-toggle.recho.js +++ b/app/docs/api-toggle.recho.js @@ -1,6 +1,5 @@ /** * @title recho.toggle(value) - * @order 17 */ /** diff --git a/app/docs/aynchronous-operations.recho.js b/app/docs/aynchronous-operations.recho.js index d5ff0cf..4af3518 100644 --- a/app/docs/aynchronous-operations.recho.js +++ b/app/docs/aynchronous-operations.recho.js @@ -1,6 +1,5 @@ /** * @title Asynchronous Operations - * @order 6 */ /** diff --git a/app/docs/errors-handling.recho.js b/app/docs/errors-handling.recho.js index bd36571..fa4ced9 100644 --- a/app/docs/errors-handling.recho.js +++ b/app/docs/errors-handling.recho.js @@ -1,6 +1,5 @@ /** * @title Errors Handling - * @order 8 */ //➜ { [SyntaxError: Identifier directly after number (17:9)] pos: 611, loc: Position { line: 17, column: 9 }, raisedAt: 611, [Symbol(next.console.error.digest)]: "NEXT_CONSOLE_ERROR" } diff --git a/app/docs/getting-started.recho.js b/app/docs/getting-started.recho.js index 622be99..d98b049 100644 --- a/app/docs/getting-started.recho.js +++ b/app/docs/getting-started.recho.js @@ -1,6 +1,5 @@ /** * @title Getting Started - * @order 2 */ /** diff --git a/app/docs/inline-echoing.recho.js b/app/docs/inline-echoing.recho.js index 646f531..eb4d2db 100644 --- a/app/docs/inline-echoing.recho.js +++ b/app/docs/inline-echoing.recho.js @@ -1,6 +1,5 @@ /** * @title Inline Echoing - * @order 3 */ /** diff --git a/app/docs/introduction.recho.js b/app/docs/introduction.recho.js index 4ff0289..3a03d21 100644 --- a/app/docs/introduction.recho.js +++ b/app/docs/introduction.recho.js @@ -1,6 +1,5 @@ /** * @title Introduction - * @order 1 */ /** diff --git a/app/docs/libraries-imports.recho.js b/app/docs/libraries-imports.recho.js index 95ecfde..8b12094 100644 --- a/app/docs/libraries-imports.recho.js +++ b/app/docs/libraries-imports.recho.js @@ -1,6 +1,5 @@ /** * @title Libraries Imports - * @order 7 */ /** diff --git a/app/docs/reactive-blocks.recho.js b/app/docs/reactive-blocks.recho.js index c002b7d..dc0e909 100644 --- a/app/docs/reactive-blocks.recho.js +++ b/app/docs/reactive-blocks.recho.js @@ -1,6 +1,5 @@ /** * @title Reactive Blocks - * @order 4 */ /** From e77ec3b2c231563e74f70291b8e8486e3c5c2ef8 Mon Sep 17 00:00:00 2001 From: pearmini Date: Sat, 8 Nov 2025 17:17:51 -0500 Subject: [PATCH 7/7] Add features --- app/Sidebar.js | 19 ++++++++++------ app/docs/nav.config.js | 50 +++++++++++++++++++++++------------------- 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/app/Sidebar.js b/app/Sidebar.js index 6d6b23e..d9bcb36 100644 --- a/app/Sidebar.js +++ b/app/Sidebar.js @@ -20,14 +20,20 @@ function NavItem({doc, isActive, onClick}) { function NavGroup({group, docsMap, isActive, onClick}) { const pathname = usePathname(); const isGroupActive = group.slug === pathname.split("/docs/")[1] || group.items.some((item) => isActive(item.slug)); - const [isOpen, setIsOpen] = useState(group.slug === "api-reference" || isGroupActive); + const [isOpen, setIsOpen] = useState(true); return (
    - - {group.title} - + {group.slug ? ( + + {group.title} + + ) : ( + setIsOpen(!isOpen)}> + {group.title} + + )}