diff --git a/site/src/assets/stackblitz.js b/site/src/assets/stackblitz.js index ddb3d32cb80f..ffc8abcc6183 100644 --- a/site/src/assets/stackblitz.js +++ b/site/src/assets/stackblitz.js @@ -23,12 +23,14 @@ export default () => { document.querySelectorAll('.btn-edit').forEach(btn => { btn.addEventListener('click', event => { const codeSnippet = event.target.closest('.bd-code-snippet') - const exampleEl = codeSnippet.querySelector('.bd-example') + // The preview markup and any author-supplied classes live on the inner + // content wrapper. Fall back to `.bd-example` for older markup. + const exampleEl = codeSnippet.querySelector('.bd-example-content') || codeSnippet.querySelector('.bd-example') const htmlSnippet = exampleEl.innerHTML const jsSnippet = codeSnippet.querySelector('.btn-edit').getAttribute('data-sb-js-snippet') - // Get extra classes for this example - const classes = [...exampleEl.classList].join(' ') + // Get extra classes for this example, minus the docs-only wrapper class + const classes = [...exampleEl.classList].filter(cls => cls !== 'bd-example-content').join(' ') openBootstrapSnippet(htmlSnippet, jsSnippet, classes) }) diff --git a/site/src/components/shortcodes/Example.astro b/site/src/components/shortcodes/Example.astro index f74dfe22d91d..276c7ec2a779 100644 --- a/site/src/components/shortcodes/Example.astro +++ b/site/src/components/shortcodes/Example.astro @@ -86,8 +86,10 @@ const simplifiedMarkup = sourceMarkup
{ showPreview && ( -
- +
+
+ +
) } diff --git a/site/src/scss/_component-examples.scss b/site/src/scss/_component-examples.scss index d2d114302465..baf44f88c07e 100644 --- a/site/src/scss/_component-examples.scss +++ b/site/src/scss/_component-examples.scss @@ -51,8 +51,13 @@ } .bd-example { + --bd-example-min-height: 12rem; + position: relative; - display: flow-root; + display: flex; + flex-direction: column; + justify-content: center; // vertically center the content wrapper + min-height: var(--bd-example-min-height); padding: var(--bd-example-padding); font-size: var(--body-font-size); line-height: var(--body-line-height); @@ -66,6 +71,59 @@ margin-top: 2rem; } + // Navbars + .fixed-top, + .sticky-top { + position: static !important; // stylelint-disable-line + margin: calc(-1 * var(--bd-example-padding)) calc(-1 * var(--bd-example-padding)) var(--bd-example-padding); + } + + .fixed-bottom, + .sticky-bottom { + position: static !important; // stylelint-disable-line + margin: var(--bd-example-padding) calc(-1 * var(--bd-example-padding)) calc(-1 * var(--bd-example-padding)); + + } + + // Pagination + .pagination { + margin-bottom: 0; + } + } + + // Preview content wrapper. It keeps normal flow so loose inline items (buttons, + // badges, links) stay on one centered line, while block components keep full + // width. The frame centers this wrapper vertically. + .bd-example-content { + display: flow-root; + // Inert in normal flow. When an example sets `d-flex`/`d-grid`/`vstack` on + // the wrapper, this centers the row on the main axis. Utilities still win. + justify-content: center; + width: 100%; + text-align: center; + + // When an example turns the wrapper into a flexbox (`d-flex`, `vstack`, + // `hstack`), center its items on the cross axis too, so column layouts do + // not sit left in the tall min-height frame. Grid wrappers are excluded so + // grid items keep stretching to equal heights. + &:not([class*="grid"]) { + align-items: center; + } + + // Keep block-level components left-aligned inside. Only loose inline items + // (buttons, badges, links, icons) pick up the centered text-align above. + // Utilities still win via layer order, so `.text-center` etc. is unaffected. + > * { + text-align: start; + } + + // Center width-constrained block components (cards, wrappers). Full-width + // blocks (alerts, forms) are unaffected. Grid rows keep their negative + // gutters, so exclude `.row` and grid containers. + > *:not(.row, [class*="grid"]) { + margin-inline: auto; + } + > .tab-content { min-height: 120px; padding: var(--bs-spacer); @@ -75,9 +133,9 @@ > .menu.position-static { max-width: fit-content; + margin-inline: auto; } - // > :last-child, > nav:last-child .breadcrumb { margin-bottom: 0; } @@ -95,30 +153,12 @@ // List groups > .list-group { max-width: 400px; + margin-inline: auto; } > [class*="list-group-horizontal"] { max-width: 100%; } - - // Navbars - .fixed-top, - .sticky-top { - position: static !important; // stylelint-disable-line - margin: calc(-1 * var(--bd-example-padding)) calc(-1 * var(--bd-example-padding)) var(--bd-example-padding); - } - - .fixed-bottom, - .sticky-bottom { - position: static !important; // stylelint-disable-line - margin: var(--bd-example-padding) calc(-1 * var(--bd-example-padding)) calc(-1 * var(--bd-example-padding)); - - } - - // Pagination - .pagination { - margin-bottom: 0; - } } //