From 6aabacadf0c407ad056015387b3b73c4fb74543f Mon Sep 17 00:00:00 2001 From: Adam Whitlock <8332986+adamwhitlock1@users.noreply.github.com> Date: Fri, 8 Nov 2024 01:14:08 -0700 Subject: [PATCH 1/7] update syntax highlighting styles for using vads tokens, add copy to clipboard button, config rouge for highlighting --- _config.yml | 16 +- .../javascripts/components/code-snippets.js | 43 ++- .../_layout/_content-wrappers.scss | 273 +++++++++++++----- 3 files changed, 244 insertions(+), 88 deletions(-) diff --git a/_config.yml b/_config.yml index e340c47df..ecc8e0384 100644 --- a/_config.yml +++ b/_config.yml @@ -9,7 +9,7 @@ example_library_name: "VADS Example Library" resource_library_name: "VADS Templates, Patterns, and Forms" # Common links -figma_example_library: https://www.figma.com/file/JDFpGLIojfuQwANXScQjqe/VADS-Component-Examples?type=design&node-id=0%3A1&mode=design&t=c29j3xBxzMAyLWxu-1 +figma_example_library: https://www.figma.com/file/JDFpGLIojfuQwANXScQjqe/VADS-Component-Examples?type=design&node-id=0%3A1&mode=design&t=c29j3xBxzMAyLWxu-1 figma_component_library: https://www.figma.com/file/afurtw4iqQe6y4gXfNfkkk/VADS-Component-Library?type=design&node-id=121%3A1484&mode=design&t=ygQCLqlAL5VdSPil-1 figma_templates_library: https://www.figma.com/file/4A3O3mVx4xDAKfHE7fPF1U/VADS-Templates%2C-Patterns%2C-and-Forms?type=design&node-id=2988%3A29744&mode=design&t=A89mK0w9KGp2uWIR-1 figma_annotations_library: https://www.figma.com/file/CZcnWfQOwtLqPm4WA5paYG/VADS-Web-Annotation-Kit?type=design&node-id=415%3A1135&mode=design&t=V0V5YZrcbM7VnWa6-1 @@ -34,16 +34,20 @@ new_pattern_template_raw_link: https://raw.githubusercontent.com/department-of-v update_documentation_link: https://github.com/department-of-veterans-affairs/vets-design-system-documentation/issues/new?assignees=&labels=vsp-design-system-team&template=2_documentation_request_form.yml uswds_link: https://designsystem.digital.gov/ - # People -sketch_for_teams_admin: "Kevin Hoffman" +sketch_for_teams_admin: "Kevin Hoffman" sketch_library_owner: "Lillian Boot, Barb Denney" experimental_reviewer_1: "Matthew Dingee" - # Build settings markdown: kramdown -highlighter: none +highlighter: rouge +kramdown: + syntax_highlighter: rouge + syntax_highlighter_opts: + block: + line_numbers: false + start_line: 1 plugins: - jekyll-last-modified-at - jekyll-redirect-from @@ -91,7 +95,7 @@ exclude: - _foundation/layout/html - _foundation/utilities/html -# Default for building locally. +# Default for building locally. # See configuration files in jekyll-configs/ for environment overrides. storybook_path: "http://127.0.0.1:6006" storybook_prod_uswds_path: "https://design.va.gov/storybook/?path=/docs/uswds" diff --git a/src/assets/javascripts/components/code-snippets.js b/src/assets/javascripts/components/code-snippets.js index f226025f9..4b99a30c2 100644 --- a/src/assets/javascripts/components/code-snippets.js +++ b/src/assets/javascripts/components/code-snippets.js @@ -5,7 +5,7 @@ if (showSnippetButton.length) { } for (var i = 0; i < showSnippetButton.length; i++) { - showSnippetButton[i].addEventListener("click", function(e) { + showSnippetButton[i].addEventListener("click", function (e) { if (this.innerHTML == original_text) { this.innerHTML = ' Hide HTML'; } @@ -13,4 +13,43 @@ for (var i = 0; i < showSnippetButton.length; i++) { this.innerHTML = original_text; } }); -} \ No newline at end of file +} + +// allow markdown code blocks ``` to be copied to clipboard via va-button +document.addEventListener('DOMContentLoaded', function () { + const codeBlocks = document.querySelectorAll('pre.highlight'); + + codeBlocks.forEach(function (codeBlock) { + // Create container for proper button positioning + const container = document.createElement('div'); + container.className = 'highlight-container'; + + // Create VA button + const copyButton = document.createElement('va-button'); + copyButton.setAttribute('secondary', ''); + copyButton.setAttribute('text', 'Copy'); + copyButton.className = 'copy-button'; + + // Wrap code block + codeBlock.parentNode.insertBefore(container, codeBlock); + container.appendChild(codeBlock); + container.appendChild(copyButton); + + // Add click handler + copyButton.addEventListener('click', async function () { + try { + const code = codeBlock.textContent; + await navigator.clipboard.writeText(code); + + // Show success state + copyButton.setAttribute('text', 'Copied!'); + setTimeout(() => { + copyButton.setAttribute('text', 'Copy'); + }, 2000); + } catch (err) { + console.error('Failed to copy:', err); + copyButton.setAttribute('text', 'Error'); + } + }); + }); +}); \ No newline at end of file diff --git a/src/assets/stylesheets/_layout/_content-wrappers.scss b/src/assets/stylesheets/_layout/_content-wrappers.scss index 68e24d542..df697b663 100644 --- a/src/assets/stylesheets/_layout/_content-wrappers.scss +++ b/src/assets/stylesheets/_layout/_content-wrappers.scss @@ -10,74 +10,200 @@ // Put syntax highlighter here to avoid conflicts with // Formation base styles - .highlight .hll { background-color: #ffffcc } - .highlight { background: #ffffff; } - .highlight .c { color: #999988; font-style: italic } /* Comment */ - .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ - .highlight .k { font-weight: bold } /* Keyword */ - .highlight .o { font-weight: bold } /* Operator */ - .highlight .ch { color: #999988; font-style: italic } /* Comment.Hashbang */ - .highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */ - .highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */ - .highlight .cpf { color: #999988; font-style: italic } /* Comment.PreprocFile */ - .highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */ - .highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ - .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ - .highlight .ge { font-style: italic } /* Generic.Emph */ - .highlight .gr { color: #aa0000 } /* Generic.Error */ - .highlight .gh { color: #999999 } /* Generic.Heading */ - .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ - .highlight .go { color: #888888 } /* Generic.Output */ - .highlight .gp { color: #555555 } /* Generic.Prompt */ - .highlight .gs { font-weight: bold } /* Generic.Strong */ - .highlight .gu { color: #aaaaaa } /* Generic.Subheading */ - .highlight .gt { color: #aa0000 } /* Generic.Traceback */ - .highlight .kc { font-weight: bold } /* Keyword.Constant */ - .highlight .kd { font-weight: bold } /* Keyword.Declaration */ - .highlight .kn { font-weight: bold } /* Keyword.Namespace */ - .highlight .kp { font-weight: bold } /* Keyword.Pseudo */ - .highlight .kr { font-weight: bold } /* Keyword.Reserved */ - .highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */ - .highlight .m { color: #009999 } /* Literal.Number */ - .highlight .s { color: $color-green } /* Literal.String */ - .highlight .na { color: $color-secondary } /* Name.Attribute */ - .highlight .nb { color: #999999 } /* Name.Builtin */ - .highlight .nc { color: #445588; font-weight: bold } /* Name.Class */ - .highlight .no { color: $color-secondary } /* Name.Constant */ - .highlight .ni { color: #800080 } /* Name.Entity */ - .highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */ - .highlight .nf { color: #990000; font-weight: bold } /* Name.Function */ - .highlight .nn { color: #555555 } /* Name.Namespace */ - .highlight .nt { color: #2c4a4e } /* Name.Tag */ - .highlight .nv { color: $color-secondary } /* Name.Variable */ - .highlight .ow { font-weight: bold } /* Operator.Word */ - .highlight .w { color: #bbbbbb } /* Text.Whitespace */ - .highlight .mb { color: #009999 } /* Literal.Number.Bin */ - .highlight .mf { color: #009999 } /* Literal.Number.Float */ - .highlight .mh { color: #009999 } /* Literal.Number.Hex */ - .highlight .mi { color: #009999 } /* Literal.Number.Integer */ - .highlight .mo { color: #009999 } /* Literal.Number.Oct */ - .highlight .sa { color: $color-green } /* Literal.String.Affix */ - .highlight .sb { color: $color-green } /* Literal.String.Backtick */ - .highlight .sc { color: $color-green } /* Literal.String.Char */ - .highlight .dl { color: $color-green } /* Literal.String.Delimiter */ - .highlight .sd { color: $color-green } /* Literal.String.Doc */ - .highlight .s2 { color: $color-green } /* Literal.String.Double */ - .highlight .se { color: $color-green } /* Literal.String.Escape */ - .highlight .sh { color: $color-green } /* Literal.String.Heredoc */ - .highlight .si { color: $color-green } /* Literal.String.Interpol */ - .highlight .sx { color: $color-green } /* Literal.String.Other */ - .highlight .sr { color: #808000 } /* Literal.String.Regex */ - .highlight .s1 { color: $color-green } /* Literal.String.Single */ - .highlight .ss { color: $color-green } /* Literal.String.Symbol */ - .highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */ - .highlight .fm { color: #990000; font-weight: bold } /* Name.Function.Magic */ - .highlight .vc { color: $color-secondary } /* Name.Variable.Class */ - .highlight .vg { color: $color-secondary } /* Name.Variable.Global */ - .highlight .vi { color: $color-secondary } /* Name.Variable.Instance */ - .highlight .vm { color: $color-secondary } /* Name.Variable.Magic */ - .highlight .il { color: #009999 } /* Literal.Number.Integer.Long */ + .highlight { + margin: $units-2 0; + } + + .highlight .table-wrapper { + display: flex; + } + + /* Line numbers styling */ + .highlight .gutter { + padding: $units-2 $units-1; + border-right: 1px solid $vads-color-base-lighter; + background: $vads-color-base-lightest; + color: $vads-color-base-dark; + user-select: none; + text-align: right; + min-width: 3em; + } + + /* Code content */ + .highlight .code { + padding: $units-2; + overflow-x: auto; + } + + /* Base styles */ + .highlight pre { + margin: 0; + color: $vads-color-base; + font-size: $font-size-base; + line-height: 1.5; + } + + /* Comments */ + .highlight .c, + .highlight .ch, + .highlight .cd, + .highlight .cm, + .highlight .cpf, + .highlight .c1, + .highlight .cs { + color: $vads-color-gray-medium; + font-style: $font-style-italic; + } + + /* Keywords */ + .highlight .k, + .highlight .kd, + .highlight .kn, + .highlight .kp, + .highlight .kr, + .highlight .kt { + color: $vads-color-primary-darker; + font-weight: $font-weight-bold; + } + + /* Functions and Classes */ + .highlight .nc, + .highlight .nf, + .highlight .fm { + color: $vads-color-hub-education; + font-weight: $font-weight-bold; + } + + /* Strings */ + .highlight .s, + .highlight .sa, + .highlight .sb, + .highlight .sc, + .highlight .dl, + .highlight .sd, + .highlight .s2, + .highlight .sh, + .highlight .sx, + .highlight .s1, + .highlight .sr { + color: $vads-color-secondary; + } + + /* Numbers */ + .highlight .m, + .highlight .mb, + .highlight .mf, + .highlight .mh, + .highlight .mi, + .highlight .mo, + .highlight .il { + color: $vads-color-hub-careers; + } + + /* Variables */ + .highlight .n, + .highlight .nv, + .highlight .vc, + .highlight .vg, + .highlight .vi, + .highlight .vm { + color: $vads-color-primary; + } + + /* Constants */ + .highlight .no, + .highlight .bp { + color: $vads-color-hub-health-care; + font-weight: $font-weight-bold; + } + + /* Tags (HTML/JSX) */ + .highlight .nt { + color: $vads-color-hub-health-care; + } + + /* Attributes (HTML/JSX) */ + .highlight .na { + color: $vads-color-hub-burials; + } + + /* Punctuation */ + .highlight .p, + .highlight .pi { + color: $vads-color-base; + } + + /* Operators */ + .highlight .o, + .highlight .ow { + color: $vads-color-base; + font-weight: $font-weight-bold; + } + + /* JSX/JavaScript specific */ + .highlight .nx { + color: $vads-color-primary-dark; + } + + /* Import/Export keywords */ + .highlight .kd { + color: $vads-color-primary-darker; + font-weight: $font-weight-bold; + } + + /* Template literals */ + .highlight .template-string { + color: $vads-color-secondary; + } + + /* Property names */ + .highlight .property { + color: $vads-color-base; + } + + /* Error highlighting */ + .highlight .err { + color: $vads-color-error; + background-color: $vads-color-error-lighter; + } + + /* Changes and modifications */ + .highlight .gi { /* Git insertion */ + background-color: $vads-color-success-lighter; + } + + .highlight .gd { /* Git deletion */ + background-color: $vads-color-error-lighter; + } + + .highlight .gh { /* Git header */ + color: $vads-color-primary-darker; + font-weight: $font-weight-bold; + } + + /* Line highlights */ + .highlight .line-numbers .highlighted { + color: $vads-color-error; + font-weight: $font-weight-bold; + } + + /* Container for highlight and button */ + .highlight-container { + position: relative; + } + + /* Copy button positioning */ + .highlight-container .copy-button { + position: absolute; + top: 0.5em; + right: 0; + } + + /* Ensure code doesn't overlap button */ + .highlight pre { + padding-right: 7em; + } // Overrides .highlight { @@ -186,16 +312,3 @@ margin: units(3) 0; } } - -.code { - background-color: rgba(0,0,0,.05) !important; - font-family: $font-monospace; - padding-left: 0 !important; - padding-right: 0 !important; - - &:before, - &:after { - letter-spacing: -0.2em; - content: '\00a0'; - } -} From 95dc585ed0e57fd0f79c5bb8e8b53d62f9b849af Mon Sep 17 00:00:00 2001 From: Adam Whitlock <8332986+adamwhitlock1@users.noreply.github.com> Date: Fri, 8 Nov 2024 12:31:52 -0700 Subject: [PATCH 2/7] clean up code styling, add syntax tags for content --- _config.yml | 4 --- src/_about/naming.md | 12 ++++----- .../_layout/_content-wrappers.scss | 27 +++++++++---------- 3 files changed, 18 insertions(+), 25 deletions(-) diff --git a/_config.yml b/_config.yml index ecc8e0384..2c10723e2 100644 --- a/_config.yml +++ b/_config.yml @@ -44,10 +44,6 @@ markdown: kramdown highlighter: rouge kramdown: syntax_highlighter: rouge - syntax_highlighter_opts: - block: - line_numbers: false - start_line: 1 plugins: - jekyll-last-modified-at - jekyll-redirect-from diff --git a/src/_about/naming.md b/src/_about/naming.md index 59b6bff32..3a71dfe41 100644 --- a/src/_about/naming.md +++ b/src/_about/naming.md @@ -22,8 +22,8 @@ It consists of three required parts. When put together, the structure is `[global namespace]-[class prefix]-[BEM syntax]`, or: -``` -vads-c-component-name +```css +.vads-c-component-name ``` There are other variants on the naming convention as well. @@ -53,26 +53,26 @@ While the BEM syntax typically results in longer class names, it is excellent fo For example, an alert can be considered a **block** (for brevity, we will not use the full naming convention here). -``` +```css .alert {} ``` The alert might have several child **elements** unique to that block, perhaps a header or a body. Element names are the block + the element name, separated by two underscores (`__`). -``` +```css .alert__header {} .alert__body {} ``` There can be different types of alerts, such as success or error. These are _types_ are known as **modifiers**. Modifier names are the block + modifier name, separated by two hyphens (`--`). Modifier selectors are secondary class names that contain only the modified properties. -``` +```css .alert--success {} .alert--error {} ``` When put together, we can have something like: -``` +```html

This is the alert heading

diff --git a/src/assets/stylesheets/_layout/_content-wrappers.scss b/src/assets/stylesheets/_layout/_content-wrappers.scss index df697b663..93d083a1b 100644 --- a/src/assets/stylesheets/_layout/_content-wrappers.scss +++ b/src/assets/stylesheets/_layout/_content-wrappers.scss @@ -191,18 +191,19 @@ /* Container for highlight and button */ .highlight-container { position: relative; + display: grid; + grid-template-columns: 10fr 1fr; + padding: units(2); } /* Copy button positioning */ .highlight-container .copy-button { - position: absolute; - top: 0.5em; - right: 0; + justify-self: end; } - /* Ensure code doesn't overlap button */ - .highlight pre { - padding-right: 7em; + /* make sure code is vertically centered */ + pre.highlight { + align-self: center; } // Overrides @@ -213,6 +214,11 @@ line-height: 1.6; } + .rouge-table, .rouge-table td { + margin: 0; + border: none; + } + .highlighter-rouge { background: #fff; } @@ -297,15 +303,6 @@ } } - > .highlighter-rouge { - border: 1px solid $color-gray-lighter; - padding: units(2); - - .highlight { - font-size: 1.0625rem; - } - } - > .va-introtext { font-family: $font-sans; font-size: 1.375rem; From cab4bafe74bc388a150e4767fa197f6ee944d11c Mon Sep 17 00:00:00 2001 From: Adam Whitlock <8332986+adamwhitlock1@users.noreply.github.com> Date: Fri, 8 Nov 2024 12:39:31 -0700 Subject: [PATCH 3/7] styling cleanup, remove line number styles, fix ending script tag --- src/_about/developers/using-web-components.md | 2 +- .../_layout/_content-wrappers.scss | 24 +------------------ 2 files changed, 2 insertions(+), 24 deletions(-) diff --git a/src/_about/developers/using-web-components.md b/src/_about/developers/using-web-components.md index 2e1819d4e..aa35a9cb1 100644 --- a/src/_about/developers/using-web-components.md +++ b/src/_about/developers/using-web-components.md @@ -148,7 +148,7 @@ If the Web Component has a custom event that you need to use and you're **not** const element = document.querySelector('va-example-component'); const exampleCallback = event => { console.log(event.detail) } element.addEventListener('vaChange', exampleCallback) - ``` diff --git a/src/assets/stylesheets/_layout/_content-wrappers.scss b/src/assets/stylesheets/_layout/_content-wrappers.scss index 93d083a1b..f49ab3231 100644 --- a/src/assets/stylesheets/_layout/_content-wrappers.scss +++ b/src/assets/stylesheets/_layout/_content-wrappers.scss @@ -15,27 +15,6 @@ margin: $units-2 0; } - .highlight .table-wrapper { - display: flex; - } - - /* Line numbers styling */ - .highlight .gutter { - padding: $units-2 $units-1; - border-right: 1px solid $vads-color-base-lighter; - background: $vads-color-base-lightest; - color: $vads-color-base-dark; - user-select: none; - text-align: right; - min-width: 3em; - } - - /* Code content */ - .highlight .code { - padding: $units-2; - overflow-x: auto; - } - /* Base styles */ .highlight pre { margin: 0; @@ -194,6 +173,7 @@ display: grid; grid-template-columns: 10fr 1fr; padding: units(2); + border: 1px solid $vads-color-base-lighter; } /* Copy button positioning */ @@ -231,10 +211,8 @@ p .highlighter-rouge, li .highlighter-rouge { - padding: $units-0_5; margin: 0; border: 0; - border-radius: 2px; } // From 180fa93f06c630947cfdeb63a292063480331d02 Mon Sep 17 00:00:00 2001 From: Adam Whitlock <8332986+adamwhitlock1@users.noreply.github.com> Date: Fri, 8 Nov 2024 13:44:21 -0700 Subject: [PATCH 4/7] hide copy button visually --- src/assets/stylesheets/_layout/_content-wrappers.scss | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/assets/stylesheets/_layout/_content-wrappers.scss b/src/assets/stylesheets/_layout/_content-wrappers.scss index f49ab3231..7bc4b0207 100644 --- a/src/assets/stylesheets/_layout/_content-wrappers.scss +++ b/src/assets/stylesheets/_layout/_content-wrappers.scss @@ -179,6 +179,12 @@ /* Copy button positioning */ .highlight-container .copy-button { justify-self: end; + opacity: 0; + transition: all 0.2s ease-in-out; + } + + .highlight-container:hover .copy-button { + opacity: 1; } /* make sure code is vertically centered */ From 211a9c757a4ee578eb92db82ce5677a47f80ac7f Mon Sep 17 00:00:00 2001 From: Adam Whitlock <8332986+adamwhitlock1@users.noreply.github.com> Date: Tue, 12 Nov 2024 10:38:50 -0700 Subject: [PATCH 5/7] add focus styles for copy button --- src/assets/stylesheets/_components/_code-snippets.scss | 4 ++++ src/assets/stylesheets/_layout/_content-wrappers.scss | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/assets/stylesheets/_components/_code-snippets.scss b/src/assets/stylesheets/_components/_code-snippets.scss index a801029c8..5260f57f3 100644 --- a/src/assets/stylesheets/_components/_code-snippets.scss +++ b/src/assets/stylesheets/_components/_code-snippets.scss @@ -30,6 +30,10 @@ border-top-color: $color-gray-lightest !important; } +.site-code-snippet__content .highlight-container { + border: 0px !important; +} + .site-code-snippet__content[aria-hidden="true"] { display: block !important; max-height: 96px; diff --git a/src/assets/stylesheets/_layout/_content-wrappers.scss b/src/assets/stylesheets/_layout/_content-wrappers.scss index 7bc4b0207..e0dc17037 100644 --- a/src/assets/stylesheets/_layout/_content-wrappers.scss +++ b/src/assets/stylesheets/_layout/_content-wrappers.scss @@ -183,7 +183,9 @@ transition: all 0.2s ease-in-out; } - .highlight-container:hover .copy-button { + .highlight-container:hover .copy-button, + .highlight-container:focus-within .copy-button, + .copy-button:focus { opacity: 1; } From 73bb31742c125faee7c88c51ca21a6879ec2de4f Mon Sep 17 00:00:00 2001 From: Adam Whitlock <8332986+adamwhitlock1@users.noreply.github.com> Date: Tue, 12 Nov 2024 13:09:16 -0700 Subject: [PATCH 6/7] add code class styling back in for --- .../stylesheets/_layout/_content-wrappers.scss | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/assets/stylesheets/_layout/_content-wrappers.scss b/src/assets/stylesheets/_layout/_content-wrappers.scss index e0dc17037..f02f7b3f2 100644 --- a/src/assets/stylesheets/_layout/_content-wrappers.scss +++ b/src/assets/stylesheets/_layout/_content-wrappers.scss @@ -295,3 +295,16 @@ margin: units(3) 0; } } + +.code { + background-color: rgba(0,0,0,.05) !important; + font-family: $font-monospace; + padding-left: 0 !important; + padding-right: 0 !important; + + &:before, + &:after { + letter-spacing: -0.2em; + content: '\00a0'; + } +} \ No newline at end of file From 7bcce3385815e3362ca40ef536900153eee615d1 Mon Sep 17 00:00:00 2001 From: Adam Whitlock <8332986+adamwhitlock1@users.noreply.github.com> Date: Tue, 12 Nov 2024 13:36:22 -0700 Subject: [PATCH 7/7] fix va-button clickable area from being entire column in code block --- src/assets/javascripts/components/code-snippets.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/assets/javascripts/components/code-snippets.js b/src/assets/javascripts/components/code-snippets.js index 4b99a30c2..ba0b6493d 100644 --- a/src/assets/javascripts/components/code-snippets.js +++ b/src/assets/javascripts/components/code-snippets.js @@ -24,16 +24,21 @@ document.addEventListener('DOMContentLoaded', function () { const container = document.createElement('div'); container.className = 'highlight-container'; + // Create wrapper div copy button + const copyButtonWrapper = document.createElement('div'); + // Create VA button const copyButton = document.createElement('va-button'); copyButton.setAttribute('secondary', ''); copyButton.setAttribute('text', 'Copy'); copyButton.className = 'copy-button'; + copyButtonWrapper.appendChild(copyButton); + // Wrap code block codeBlock.parentNode.insertBefore(container, codeBlock); container.appendChild(codeBlock); - container.appendChild(copyButton); + container.appendChild(copyButtonWrapper); // Add click handler copyButton.addEventListener('click', async function () {