From 40774ab8b5e563253380e23e3c73761cff07fc1c Mon Sep 17 00:00:00 2001
From: "a.nvlkv" <2813794+anvlkv@users.noreply.github.com>
Date: Sat, 11 May 2024 22:12:35 +0300
Subject: [PATCH] Add custom admonition for code sandbox (#95)
---
CodeSandbox-Square-Logo.svg | 3 ++
book.toml | 14 ++++++++--
mdbook-admonish-custom.css | 20 ++++++++++++++
sandbox.css | 43 +++++++++++++++++++++++++++++
sandbox.js | 13 +++++++++
src/15_global_state.md | 12 +++++++-
src/async/10_resources.md | 12 +++++++-
src/async/11_suspense.md | 12 +++++++-
src/async/12_transition.md | 12 +++++++-
src/async/13_actions.md | 12 +++++++-
src/reactivity/14_create_effect.md | 12 +++++++-
src/router/17_nested_routing.md | 12 +++++++-
src/router/18_params_and_queries.md | 12 +++++++-
src/router/19_a.md | 11 +++++++-
src/router/20_form.md | 12 +++++++-
src/view/01_basic_component.md | 20 +++++++++++---
src/view/02_dynamic_attributes.md | 12 +++++++-
src/view/03_components.md | 12 +++++++-
src/view/04_iteration.md | 12 +++++++-
src/view/05_forms.md | 12 ++++++--
src/view/06_control_flow.md | 12 +++++++-
src/view/07_errors.md | 11 +++++++-
src/view/08_parent_child.md | 15 ++++++++--
src/view/09_component_children.md | 12 +++++++-
24 files changed, 303 insertions(+), 27 deletions(-)
create mode 100644 CodeSandbox-Square-Logo.svg
create mode 100644 mdbook-admonish-custom.css
create mode 100644 sandbox.css
create mode 100644 sandbox.js
diff --git a/CodeSandbox-Square-Logo.svg b/CodeSandbox-Square-Logo.svg
new file mode 100644
index 0000000..7ac3d39
--- /dev/null
+++ b/CodeSandbox-Square-Logo.svg
@@ -0,0 +1,3 @@
+
diff --git a/book.toml b/book.toml
index d3ab98c..c9a854f 100644
--- a/book.toml
+++ b/book.toml
@@ -1,5 +1,10 @@
[output.html]
-additional-css = ["./mdbook-admonish.css"]
+additional-css = [
+ "./mdbook-admonish.css",
+ "./mdbook-admonish-custom.css",
+ "./sandbox.css",
+]
+additional-js = ["./sandbox.js"]
git-repository-url = "https://github.com/leptos-rs/book"
edit-url-template = "https://github.com/leptos-rs/book/edit/main/{path}"
[output.html.playground]
@@ -9,4 +14,9 @@ runnable = false
[preprocessor.admonish]
command = "mdbook-admonish"
-assets_version = "3.0.1" # do not edit: managed by `mdbook-admonish install`
+assets_version = "3.0.1" # do not edit: managed by `mdbook-admonish install`
+
+[[preprocessor.admonish.custom]]
+directive = "sandbox"
+color = "#DCFF50"
+icon = "./CodeSandbox-Square-Logo.svg"
diff --git a/mdbook-admonish-custom.css b/mdbook-admonish-custom.css
new file mode 100644
index 0000000..77c1473
--- /dev/null
+++ b/mdbook-admonish-custom.css
@@ -0,0 +1,20 @@
+:root {
+ --md-admonition-icon--admonish-sandbox: url("data:image/svg+xml;charset=utf-8,");
+}
+
+:is(.admonition):is(.admonish-sandbox) {
+ border-color: #dcff50;
+}
+
+:is(.admonish-sandbox) > :is(.admonition-title, summary.admonition-title) {
+ background-color: rgba(220, 255, 80, 0.1);
+}
+:is(.admonish-sandbox) > :is(.admonition-title, summary.admonition-title)::before {
+ background-color: #dcff50;
+ mask-image: var(--md-admonition-icon--admonish-sandbox);
+ -webkit-mask-image: var(--md-admonition-icon--admonish-sandbox);
+ mask-repeat: no-repeat;
+ -webkit-mask-repeat: no-repeat;
+ mask-size: contain;
+ -webkit-mask-repeat: no-repeat;
+}
diff --git a/sandbox.css b/sandbox.css
new file mode 100644
index 0000000..c0e3405
--- /dev/null
+++ b/sandbox.css
@@ -0,0 +1,43 @@
+:is(.admonition):is(.admonish-sandbox) {
+ transition-property: width, margin-left;
+ transition-duration: 300ms;
+ transition-timing-function: ease-out;
+ margin-left: 0;
+ position: relative;
+ box-sizing: border-box;
+ max-width: 1380px;
+}
+
+@media only screen and (min-width: 1081px) {
+ :is(.admonition):is(.admonish-sandbox):is([open]) {
+ --sandbox-width: calc(
+ 100vw - var(--sidebar-width) - calc(var(--page-padding) + 1.2rem) *
+ 2 - 6px - 4px
+ );
+
+ width: var(--sandbox-width);
+ margin-left: calc(calc(min(var(--sandbox-width), 1380px) - 100%) / 2 * -1 + 4px);
+ z-index: 10;
+ }
+
+ body.sidebar-hidden :is(.admonition):is(.admonish-sandbox):is([open]) {
+ --sandbox-width: calc(
+ 100vw - calc(var(--page-padding) + 1.2rem) * 2 - 4px
+ );
+ }
+}
+
+@media only screen and (min-width: 1380px) {
+ :is(.admonition):is(.admonish-sandbox):is([open]) {
+ --sandbox-width: calc(
+ 100vw - var(--sidebar-width) -
+ calc(var(--page-padding) + 1.2rem + 90px) * 2 - 6px - 4px
+ );
+ }
+
+ body.sidebar-hidden :is(.admonition):is(.admonish-sandbox):is([open]) {
+ --sandbox-width: calc(
+ 100vw - calc(var(--page-padding) + 1.2rem + 90px) * 2 - 4px
+ );
+ }
+}
diff --git a/sandbox.js b/sandbox.js
new file mode 100644
index 0000000..6206ee9
--- /dev/null
+++ b/sandbox.js
@@ -0,0 +1,13 @@
+(() => {
+ const boxes = document.querySelectorAll("details.admonish-sandbox");
+ boxes.forEach((box) => {
+ const once = () => {
+ const template = box.querySelector("template");
+ const sandbox = template.content.cloneNode(true);
+ template.after(sandbox);
+
+ box.removeEventListener("toggle", once);
+ };
+ box.addEventListener("toggle", once);
+ });
+})();
diff --git a/src/15_global_state.md b/src/15_global_state.md
index b106d2e..0017e19 100644
--- a/src/15_global_state.md
+++ b/src/15_global_state.md
@@ -180,9 +180,19 @@ data flow and of fine-grained reactive updates.
> **Note**: There are some significant drawbacks to this approach. Both signals and memos need to own their values, so a memo will need to clone the field’s value on every change. The most natural way to manage state in a framework like Leptos is always to provide signals that are as locally-scoped and fine-grained as they can be, not to hoist everything up into global state. But when you _do_ need some kind of global state, `create_slice` can be a useful tool.
+```admonish sandbox title="Live example" collapsible=true
+
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/15-global-state-0-5-8c2ff6?file=%2Fsrc%2Fmain.rs%3A1%2C2)
-
+
+
+
+
+
+
+```
CodeSandbox Source
diff --git a/src/async/10_resources.md b/src/async/10_resources.md
index 08a6ad3..073befa 100644
--- a/src/async/10_resources.md
+++ b/src/async/10_resources.md
@@ -47,9 +47,19 @@ view! {
Resources also provide a `refetch()` method that allows you to manually reload the data (for example, in response to a button click) and a `loading()` method that returns a `ReadSignal` indicating whether the resource is currently loading or not.
+```admonish sandbox title="Live example" collapsible=true
+
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/10-resources-0-5-x6h5j6?file=%2Fsrc%2Fmain.rs%3A2%2C3)
-
+
+
+
+
+
+
+```
CodeSandbox Source
diff --git a/src/async/11_suspense.md b/src/async/11_suspense.md
index e880e52..c991be2 100644
--- a/src/async/11_suspense.md
+++ b/src/async/11_suspense.md
@@ -97,9 +97,19 @@ view! {
}
```
+```admonish sandbox title="Live example" collapsible=true
+
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/11-suspense-0-5-qzpgqs?file=%2Fsrc%2Fmain.rs%3A1%2C1)
-
+
+
+
+
+
+
+```
CodeSandbox Source
diff --git a/src/async/12_transition.md b/src/async/12_transition.md
index 85db85b..f62202e 100644
--- a/src/async/12_transition.md
+++ b/src/async/12_transition.md
@@ -6,9 +6,19 @@ You’ll notice in the `` example that if you keep reloading the data
This example shows how you can create a simple tabbed contact list with ``. When you select a new tab, it continues showing the current contact until the new data loads. This can be a much better user experience than constantly falling back to a loading message.
+```admonish sandbox title="Live example" collapsible=true
+
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/12-transition-0-5-2jg5lz?file=%2Fsrc%2Fmain.rs%3A1%2C1)
-
+
+
+
+
+
+
+```
CodeSandbox Source
diff --git a/src/async/13_actions.md b/src/async/13_actions.md
index 625dc33..ff55c6e 100644
--- a/src/async/13_actions.md
+++ b/src/async/13_actions.md
@@ -91,9 +91,19 @@ view! {
Now, there’s a chance this all seems a little over-complicated, or maybe too restricted. I wanted to include actions here, alongside resources, as the missing piece of the puzzle. In a real Leptos app, you’ll actually most often use actions alongside server functions, [`create_server_action`](https://docs.rs/leptos/latest/leptos/fn.create_server_action.html), and the [``](https://docs.rs/leptos_router/latest/leptos_router/fn.ActionForm.html) component to create really powerful progressively-enhanced forms. So if this primitive seems useless to you... Don’t worry! Maybe it will make sense later. (Or check out our [`todo_app_sqlite`](https://github.com/leptos-rs/leptos/blob/main/examples/todo_app_sqlite/src/todo.rs) example now.)
+```admonish sandbox title="Live example" collapsible=true
+
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/13-actions-0-5-8xk35v?file=%2Fsrc%2Fmain.rs%3A1%2C1)
-
+
+
+
+
+
+
+```
CodeSandbox Source
diff --git a/src/reactivity/14_create_effect.md b/src/reactivity/14_create_effect.md
index ed21475..8f86a58 100644
--- a/src/reactivity/14_create_effect.md
+++ b/src/reactivity/14_create_effect.md
@@ -149,9 +149,19 @@ stop(); // stop watching
set_num.set(2); // (nothing happens)
```
+```admonish sandbox title="Live example" collapsible=true
+
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/14-effect-0-5-d6hkch?file=%2Fsrc%2Fmain.rs%3A1%2C1)
-
+
+
+
+
+
+
+```
CodeSandbox Source
diff --git a/src/router/17_nested_routing.md b/src/router/17_nested_routing.md
index 88444cc..7610b37 100644
--- a/src/router/17_nested_routing.md
+++ b/src/router/17_nested_routing.md
@@ -204,9 +204,19 @@ In fact, in this case, we don’t even need to rerender the `` compone
> This sandbox includes a couple features (like nested routing) discussed in this section and the previous one, and a couple we’ll cover in the rest of this chapter. The router is such an integrated system that it makes sense to provide a single example, so don’t be surprised if there’s anything you don’t understand.
+```admonish sandbox title="Live example" collapsible=true
+
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/16-router-0-5-4xp4zz?file=%2Fsrc%2Fmain.rs%3A102%2C2)
-
+
+
+
+
+
+
+```
CodeSandbox Source
diff --git a/src/router/18_params_and_queries.md b/src/router/18_params_and_queries.md
index a783fff..acf2195 100644
--- a/src/router/18_params_and_queries.md
+++ b/src/router/18_params_and_queries.md
@@ -82,9 +82,19 @@ This can get a little messy: deriving a signal that wraps an `Option<_>` or `Res
> This is the same example from the previous section. The router is such an integrated system that it makes sense to provide a single example highlighting multiple features, even if we haven’t explained them all yet.
+```admonish sandbox title="Live example" collapsible=true
+
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/16-router-0-5-4xp4zz?file=%2Fsrc%2Fmain.rs%3A102%2C2)
-
+
+
+
+
+
+
+```
CodeSandbox Source
diff --git a/src/router/19_a.md b/src/router/19_a.md
index ea38438..ecbe834 100644
--- a/src/router/19_a.md
+++ b/src/router/19_a.md
@@ -35,9 +35,18 @@ The second argument here is a set of [`NavigateOptions`](https://docs.rs/leptos_
> Once again, this is the same example. Check out the relative `` components, and take a look at the CSS in `index.html` to see the ARIA-based styling.
+```admonish sandbox title="Live example" collapsible=true
+
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/16-router-0-5-4xp4zz?file=%2Fsrc%2Fmain.rs%3A102%2C2)
-
+
+
+
+
+
+```
CodeSandbox Source
diff --git a/src/router/20_form.md b/src/router/20_form.md
index 58e2b4e..dfaeb82 100644
--- a/src/router/20_form.md
+++ b/src/router/20_form.md
@@ -62,9 +62,19 @@ view! {
You’ll notice that this version drops the `Submit` button. Instead, we add an `oninput` attribute to the input. Note that this is _not_ `on:input`, which would listen for the `input` event and run some Rust code. Without the colon, `oninput` is the plain HTML attribute. So the string is actually a JavaScript string. `this.form` gives us the form the input is attached to. `requestSubmit()` fires the `submit` event on the `` just as if we had clicked a `Submit` button. Now the form will “navigate” on every keystroke or input to keep the URL (and therefore the search) perfectly in sync with the user’s input as they type.
+```admonish sandbox title="Live example" collapsible=true
+
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/20-form-0-5-9g7v9p?file=%2Fsrc%2Fmain.rs%3A1%2C1)
-
+
+
+
+
+
+
+```
CodeSandbox Source
diff --git a/src/view/01_basic_component.md b/src/view/01_basic_component.md
index 0d917b0..be210c7 100644
--- a/src/view/01_basic_component.md
+++ b/src/view/01_basic_component.md
@@ -152,14 +152,26 @@ move |_| {
You can see here that while `set_count` just sets the value, `set_count.update()` gives us a mutable reference and mutates the value in place. Either one will trigger a reactive update in our UI.
-> Throughout this tutorial, we’ll use CodeSandbox to show interactive examples. To
-> show the browser in the sandbox, you may need to click `Add DevTools >
-Other Previews > 8080.` Hover over any of the variables to show Rust-Analyzer details
+> Throughout this tutorial, we’ll use CodeSandbox to show interactive examples.
+> Hover over any of the variables to show Rust-Analyzer details
> and docs for what’s going on. Feel free to fork the examples to play with them yourself!
+```admonish sandbox title="Live example" collapsible=true
+
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/1-basic-component-3d74p3?file=%2Fsrc%2Fmain.rs%3A1%2C1)
-
+
+
+> To show the browser in the sandbox, you may need to click `Add DevTools >
+Other Previews > 8080.`
+
+
+
+
+
+```
CodeSandbox Source
diff --git a/src/view/02_dynamic_attributes.md b/src/view/02_dynamic_attributes.md
index 7478f2c..c522744 100644
--- a/src/view/02_dynamic_attributes.md
+++ b/src/view/02_dynamic_attributes.md
@@ -186,9 +186,19 @@ for expensive calculations.
>
> [Click here for the full `view` macros docs](https://docs.rs/leptos/latest/leptos/macro.view.html).
+```admonish sandbox title="Live example" collapsible=true
+
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/2-dynamic-attributes-0-5-lwdrpm?file=%2Fsrc%2Fmain.rs%3A1%2C1)
-
+
+
+
+
+
+
+```
CodeSandbox Source
diff --git a/src/view/03_components.md b/src/view/03_components.md
index 5807711..bcc16cc 100644
--- a/src/view/03_components.md
+++ b/src/view/03_components.md
@@ -420,9 +420,19 @@ and see the power of the `#[component]` macro combined with rust-analyzer here.
> In general, you should not need to use transparent components unless you are
> creating custom wrapping components that fall into one of these two categories.
+```admonish sandbox title="Live example" collapsible=true
+
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/3-components-0-5-5vvl69?file=%2Fsrc%2Fmain.rs%3A1%2C1)
-
+
+
+
+
+
+
+```
CodeSandbox Source
diff --git a/src/view/04_iteration.md b/src/view/04_iteration.md
index 4756500..f08d07e 100644
--- a/src/view/04_iteration.md
+++ b/src/view/04_iteration.md
@@ -104,9 +104,19 @@ it is generated, and using that as an ID for the key function.
Check out the `` component below for an example.
+```admonish sandbox title="Live example" collapsible=true
+
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/4-iteration-0-5-pwdn2y?file=%2Fsrc%2Fmain.rs%3A1%2C1)
-
+
+
+
+
+
+
+```
CodeSandbox Source
diff --git a/src/view/05_forms.md b/src/view/05_forms.md
index 8f40279..7de39f1 100644
--- a/src/view/05_forms.md
+++ b/src/view/05_forms.md
@@ -236,11 +236,19 @@ pub fn SelectOption(is: &'static str, value: ReadSignal) -> impl IntoVie
> This is expected to be made consistent in the next major version of Leptos; see [this issue](https://github.com/leptos-rs/leptos/issues/2196)
> for more details.
-**Controlled vs uncontrolled forms CodeSandbox:**
+```admonish sandbox title="Controlled vs uncontrolled forms CodeSandbox" collapsible=true
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/5-forms-0-5-rf2t7c?file=%2Fsrc%2Fmain.rs%3A1%2C1)
-
+
+
+
+
+
+
+```
CodeSandbox Source
diff --git a/src/view/06_control_flow.md b/src/view/06_control_flow.md
index b3f1af6..45ab480 100644
--- a/src/view/06_control_flow.md
+++ b/src/view/06_control_flow.md
@@ -283,9 +283,19 @@ view! {
}
```
+```admonish sandbox title="Live example" collapsible=true
+
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/6-control-flow-0-5-4yn7qz?file=%2Fsrc%2Fmain.rs%3A1%2C1)
-
+
+
+
+
+
+
+```
CodeSandbox Source
diff --git a/src/view/07_errors.md b/src/view/07_errors.md
index 61575a7..e26ea73 100644
--- a/src/view/07_errors.md
+++ b/src/view/07_errors.md
@@ -110,9 +110,18 @@ Not a number! Errors:
If you fix the error, the error message will disappear and the content you’re wrapping in
an `` will appear again.
+```admonish sandbox title="Live example" collapsible=true
+
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/7-errors-0-5-5mptv9?file=%2Fsrc%2Fmain.rs%3A1%2C1)
-
+
+
+
+
+
+```
CodeSandbox Source
diff --git a/src/view/08_parent_child.md b/src/view/08_parent_child.md
index b9c7789..f0a4fae 100644
--- a/src/view/08_parent_child.md
+++ b/src/view/08_parent_child.md
@@ -91,7 +91,7 @@ are real trade-offs, not a simple right-or-wrong choice.
> Note the way we use the `Callback` type. This is basically a
> wrapper around a closure `Fn(In) -> Out` that is also `Copy` and makes it
> easy to pass around.
->
+>
> We also used the `#[prop(into)]` attribute so we can pass a normal closure into
> `on_click`. Please see the [chapter "`into` Props"](./03_components.md#into-props) for more details.
@@ -130,7 +130,6 @@ closure might require some cloning compared to using a `Callback`.
> confused, look back at the [generic props](./03_components.html#generic-props) section
> of the chapter on components.
-
## 3. Use an Event Listener
You can actually write Option 2 in a slightly different way. If the callback maps directly onto
@@ -320,9 +319,19 @@ in `` and a single text node in ``. It’s as if the components
themselves don’t exist at all. And, well... at runtime, they don’t. It’s just
signals and effects, all the way down.
+```admonish sandbox title="Live example" collapsible=true
+
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/8-parent-child-0-5-7rz7qd?file=%2Fsrc%2Fmain.rs%3A1%2C2)
-
+
+
+
+
+
+
+```
CodeSandbox Source
diff --git a/src/view/09_component_children.md b/src/view/09_component_children.md
index 0da9e64..3875d98 100644
--- a/src/view/09_component_children.md
+++ b/src/view/09_component_children.md
@@ -122,9 +122,19 @@ view! {
}
```
+```admonish sandbox title="Live example" collapsible=true
+
[Click to open CodeSandbox.](https://codesandbox.io/p/sandbox/9-component-children-0-5-m4jwhp?file=%2Fsrc%2Fmain.rs%3A1%2C1)
-
+
+
+
+
+
+
+```
CodeSandbox Source