Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix StackBlitz examples by embedding snippets.js when needed #36352

Merged
46 changes: 38 additions & 8 deletions site/assets/js/snippets.js
@@ -1,5 +1,7 @@
// NOTICE!! DO NOT USE ANY OF THIS JAVASCRIPT
// IT'S ALL JUST JUNK FOR OUR DOCS!
// NOTICE!!! Initially embedded in our docs this JavaScript
// file contains elements that can help you create reproducible
// use cases in StackBlitz for instance.
// In a real project please adapt this content to your needs.
// ++++++++++++++++++++++++++++++++++++++++++

/*!
Expand All @@ -15,18 +17,28 @@
(() => {
'use strict'

// Tooltip and popover demos
// Tooltip and popover demos
// --------
// Tooltips
// --------
// Instanciate all tooltips in a docs or StackBlitz page
document.querySelectorAll('[data-bs-toggle="tooltip"]')
.forEach(tooltip => {
new bootstrap.Tooltip(tooltip)
})

// --------
// Popovers
// --------
// Instanciate all popovers in a docs or StackBlitz page
document.querySelectorAll('[data-bs-toggle="popover"]')
.forEach(popover => {
new bootstrap.Popover(popover)
})

// -------------------------------
// Toasts
// -------------------------------
// Used by 'Placement' example in docs or StackBlitz
const toastPlacement = document.getElementById('toastPlacement')
if (toastPlacement) {
document.getElementById('selectToastPlacement').addEventListener('change', function () {
Expand All @@ -38,6 +50,7 @@
})
}

// Instanciate all toasts in a docs page only
document.querySelectorAll('.bd-example .toast')
.forEach(toastNode => {
const toast = new bootstrap.Toast(toastNode, {
Expand All @@ -47,6 +60,7 @@
toast.show()
})

// Instanciate all toasts in a docs page only
const toastTrigger = document.getElementById('liveToastBtn')
const toastLiveExample = document.getElementById('liveToast')
if (toastTrigger) {
Expand All @@ -57,6 +71,10 @@
})
}

// -------------------------------
// Alerts
// -------------------------------
// Used in 'Show live toast' example in docs or StackBlitz
const alertPlaceholder = document.getElementById('liveAlertPlaceholder')
const alertTrigger = document.getElementById('liveAlertBtn')

Expand All @@ -78,21 +96,30 @@
})
}

// Indeterminate checkbox example
// -------------------------------
// Checks & Radios
// -------------------------------
// Indeterminate checkbox example in docs and StackBlitz
document.querySelectorAll('.bd-example-indeterminate [type="checkbox"]')
.forEach(checkbox => {
checkbox.indeterminate = true
})

// Disable empty links in docs examples
// -------------------------------
// Links
// -------------------------------
// Disable empty links in docs examples only
document.querySelectorAll('.bd-content [href="#"]')
.forEach(link => {
link.addEventListener('click', event => {
event.preventDefault()
})
})

// Modal relatedTarget demo
// -------------------------------
// Modal
// -------------------------------
// Modal 'Varying modal content' example in docs and StackBlitz
const exampleModal = document.getElementById('exampleModal')
if (exampleModal) {
exampleModal.addEventListener('show.bs.modal', event => {
Expand All @@ -110,7 +137,10 @@
})
}

// Offcanvas demo
// -------------------------------
// Offcanvas
// -------------------------------
// 'Offcanvas components' example in docs only
const myOffcanvas = document.querySelector('.bd-example-offcanvas #offcanvas')
if (myOffcanvas) {
myOffcanvas.addEventListener('show.bs.offcanvas', event => {
Expand Down
2 changes: 1 addition & 1 deletion site/content/docs/5.2/components/alerts.md
Expand Up @@ -27,7 +27,7 @@ Alerts are available for any length of text, as well as an optional close button

Click the button below to show an alert (hidden with inline styles to start), then dismiss (and destroy) it with the built-in close button.

{{< example >}}
{{< example js_snippet="true" >}}
<div id="liveAlertPlaceholder"></div>
<button type="button" class="btn btn-primary" id="liveAlertBtn">Show live alert</button>
{{< /example >}}
Expand Down
2 changes: 1 addition & 1 deletion site/content/docs/5.2/components/modal.md
Expand Up @@ -444,7 +444,7 @@ Have a bunch of buttons that all trigger the same modal with slightly different

Below is a live demo followed by example HTML and JavaScript. For more information, [read the modal events docs](#events) for details on `relatedTarget`.

{{< example >}}
{{< example js_snippet="true" >}}
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#exampleModal" data-bs-whatever="@mdo">Open modal for @mdo</button>
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#exampleModal" data-bs-whatever="@fat">Open modal for @fat</button>
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#exampleModal" data-bs-whatever="@getbootstrap">Open modal for @getbootstrap</button>
Expand Down
10 changes: 5 additions & 5 deletions site/content/docs/5.2/components/popovers.md
Expand Up @@ -46,15 +46,15 @@ const popoverList = [...popoverTriggerList].map(popoverTriggerEl => new bootstra

We use JavaScript similar to the snippet above to render the following live popover. Titles are set via `title` attribute and body content is set via `data-bs-content`.

{{< example >}}
{{< example js_snippet="true" >}}
<button type="button" class="btn btn-lg btn-danger" data-bs-toggle="popover" title="Popover title" data-bs-content="And here's some amazing content. It's very engaging. Right?">Click to toggle popover</button>
{{< /example >}}

### Four directions

Four options are available: top, right, bottom, and left. Directions are mirrored when using Bootstrap in RTL. Set `data-bs-placement` to change the direction.

{{< example >}}
{{< example js_snippet="true" >}}
<button type="button" class="btn btn-secondary" data-bs-container="body" data-bs-toggle="popover" data-bs-placement="top" data-bs-content="Top popover">
Popover on top
</button>
Expand Down Expand Up @@ -87,7 +87,7 @@ You can customize the appearance of popovers using [CSS variables](#variables).

{{< scss-docs name="custom-popovers" file="site/assets/scss/_component-examples.scss" >}}

{{< example class="custom-popover-demo" >}}
{{< example class="custom-popover-demo" js_snippet="true" >}}
<button type="button" class="btn btn-secondary"
data-bs-toggle="popover" data-bs-placement="right"
data-bs-custom-class="custom-popover"
Expand All @@ -107,7 +107,7 @@ Use the `focus` trigger to dismiss popovers on the user's next click of a differ
For proper cross-browser and cross-platform behavior, you must use the `<a>` tag, _not_ the `<button>` tag, and you also must include a [`tabindex`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex) attribute.
{{< /callout >}}

{{< example >}}
{{< example js_snippet="true" >}}
<a tabindex="0" class="btn btn-lg btn-danger" role="button" data-bs-toggle="popover" data-bs-trigger="focus" title="Dismissible popover" data-bs-content="And here's some amazing content. It's very engaging. Right?">Dismissible popover</a>
{{< /example >}}

Expand All @@ -123,7 +123,7 @@ Elements with the `disabled` attribute aren't interactive, meaning users cannot

For disabled popover triggers, you may also prefer `data-bs-trigger="hover focus"` so that the popover appears as immediate visual feedback to your users as they may not expect to _click_ on a disabled element.

{{< example >}}
{{< example js_snippet="true" >}}
<span class="d-inline-block" tabindex="0" data-bs-toggle="popover" data-bs-trigger="hover focus" data-bs-content="Disabled popover">
<button class="btn btn-primary" type="button" disabled>Disabled button</button>
</span>
Expand Down
2 changes: 1 addition & 1 deletion site/content/docs/5.2/components/toasts.md
Expand Up @@ -197,7 +197,7 @@ Building on the above example, you can create different toast color schemes with

Place toasts with custom CSS as you need them. The top right is often used for notifications, as is the top middle. If you're only ever going to show one toast at a time, put the positioning styles right on the `.toast`.

{{< example >}}
{{< example js_snippet="true" >}}
<form>
<div class="mb-3">
<label for="selectToastPlacement">Toast placement</label>
Expand Down
4 changes: 2 additions & 2 deletions site/content/docs/5.2/components/tooltips.md
Expand Up @@ -45,7 +45,7 @@ const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstra

Hover over the links below to see tooltips:

{{< example class="tooltip-demo" >}}
{{< example class="tooltip-demo" js_snippet="true" >}}
<p class="muted">Placeholder text to demonstrate some <a href="#" data-bs-toggle="tooltip" title="Default tooltip">inline links</a> with tooltips. This is now just filler, no killer. Content placed here just to mimic the presence of <a href="#" data-bs-toggle="tooltip" title="Another tooltip">real text</a>. And all that just to give you an idea of how tooltips would look when used in real-world situations. So hopefully you've now seen how <a href="#" data-bs-toggle="tooltip" title="Another one here too">these tooltips on links</a> can work in practice, once you use them on <a href="#" data-bs-toggle="tooltip" title="The last tip!">your own</a> site or project.
</p>
{{< /example >}}
Expand All @@ -59,7 +59,7 @@ You can customize the appearance of tooltips using [CSS variables](#variables).
{{< scss-docs name="custom-tooltip" file="site/assets/scss/_component-examples.scss" >}}


{{< example class="tooltip-demo" >}}
{{< example class="tooltip-demo" js_snippet="true" >}}
<button type="button" class="btn btn-secondary"
data-bs-toggle="tooltip" data-bs-placement="top"
data-bs-custom-class="custom-tooltip"
Expand Down
2 changes: 1 addition & 1 deletion site/content/docs/5.2/forms/checks-radios.md
Expand Up @@ -36,7 +36,7 @@ Our checks use custom Bootstrap icons to indicate checked or indeterminate state

Checkboxes can utilize the `:indeterminate` pseudo class when manually set via JavaScript (there is no available HTML attribute for specifying it).

{{< example class="bd-example-indeterminate">}}
{{< example class="bd-example-indeterminate" js_snippet="true" >}}
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="flexCheckIndeterminate">
<label class="form-check-label" for="flexCheckIndeterminate">
Expand Down
22 changes: 14 additions & 8 deletions site/layouts/partials/scripts.html
Expand Up @@ -26,36 +26,42 @@
document.querySelectorAll('.btn-edit').forEach(btn => {
btn.addEventListener('click', event => {
const htmlSnippet = event.target.closest('.bd-code-snippet').querySelector('.bd-example').innerHTML
StackBlitzSDK.openBootstrapSnippet(htmlSnippet)

// Get extra classes for this example except '.bd-example'
const classes = Array.from(event.target.closest('.bd-code-snippet').querySelector('.bd-example').classList).filter(x => x !== 'bd-example').join(' ')
GeoSot marked this conversation as resolved.
Show resolved Hide resolved

const jsSnippet = event.target.closest('.bd-code-snippet').querySelector('.btn-edit').getAttribute('data-js-snippet')
StackBlitzSDK.openBootstrapSnippet(htmlSnippet, jsSnippet, classes)
})
})

StackBlitzSDK.openBootstrapSnippet = snippet => {
StackBlitzSDK.openBootstrapSnippet = (htmlSnippet, jsSnippet, classes) => {
const markup = `<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="{{ .Site.Params.cdn.css }}" rel="stylesheet">
<title>Bootstrap Example</title>
<${'script'} src="{{ .Site.Params.cdn.js_bundle }}"></${'script'}>
</head>
<body>
<body class="p-3 ${classes}">

<!-- Example Code -->
${snippet.replace(/^/gm, ' ')}
${htmlSnippet.replace(/^/gm, ' ')}
<!-- End Example Code -->

<${'script'} src="{{ .Site.Params.cdn.js_bundle }}"></${'script'}>
</body>
</html>`

const jsSnippetContent = jsSnippet ? '{{ os.ReadFile "site/assets/js/snippets.js" }}' : null
const project = {
files: {
'index.html': markup
'index.html': markup,
'index.js': jsSnippetContent
},
title: 'Bootstrap Example',
description: `Official example from ${window.location.href}`,
template: 'html',
template: jsSnippet ? 'javascript' : 'html',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't it ok just use javascript template?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've used the appropriate template in function of the context but javascript would work in both cases yes if we want to simplify. But in this case we would need to create an empty index.js file. The advantage with the html template is that this extra empty index.js file isn't mandatory.

However in https://developer.stackblitz.com/docs/platform/javascript-sdk/#sdkopenprojectproject-opts I don't see any tags options. Since html (as template) is not mentioned neither maybe I don't have the latest doc reference 🤷

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we may (at least for start) leave it with javascript template, and include examples.js by default

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made the exercise in this PR to include js_snippet="true" only when needed in {{< example >}}. Only few examples really need a javascript template just to show the impact.

tags: ['bootstrap']
}

Expand Down
4 changes: 3 additions & 1 deletion site/layouts/shortcodes/example.html
Expand Up @@ -4,6 +4,7 @@
`args` are all optional and can be one of the following:
* id: the `div`'s id - default: ""
* class: any extra class(es) to be added to the `div` - default: ""
* js_snippet: add extra JS snippet to StackBlitz - default: `false`
* show_preview: if the preview should be output in the HTML - default: `true`
* show_markup: if the markup should be output in the HTML - default: `true`
*/ -}}
Expand All @@ -13,6 +14,7 @@
{{- $lang := .Get "lang" | default "html" -}}
{{- $show_preview := .Get "show_preview" | default true -}}
{{- $show_markup := .Get "show_markup" | default true -}}
{{- $js_snippet := .Get "js_snippet" | default false -}}
{{- $input := .Inner -}}

<div class="bd-example-snippet bd-code-snippet">
Expand All @@ -27,7 +29,7 @@
<div class="d-flex align-items-center highlight-toolbar bg-light ps-3 pe-2 py-1">
<small class="font-monospace text-muted text-uppercase">{{- $lang -}}</small>
<div class="d-flex ms-auto">
<button type="button" class="btn-edit text-nowrap" title="Try it on StackBlitz">
<button type="button" class="btn-edit text-nowrap"{{ with $js_snippet }} data-js-snippet="{{ $js_snippet }}"{{ end }} title="Try it on StackBlitz">
<svg class="bi" role="img" aria-label="Try it"><use xlink:href="#lightning-charge-fill"/></svg>
</button>
<button type="button" class="btn-clipboard mt-0 me-0" title="Copy to clipboard">
Expand Down