diff --git a/docs/.eleventy.js b/docs/.eleventy.js index af42e2d21e..19693a6e7f 100644 --- a/docs/.eleventy.js +++ b/docs/.eleventy.js @@ -6,6 +6,7 @@ const highlightPlugin = require("./plugins/highlight"); const iconPlugin = require("./plugins/icons"); const tipPlugin = require("./plugins/tip"); const markdownPlugin = require("./plugins/markdown"); +const copyButtonPlugin = require("./plugins/copy-button"); module.exports = function(eleventyConfig) { eleventyConfig.setQuietMode(true); // Reduce the console output @@ -15,6 +16,7 @@ module.exports = function(eleventyConfig) { eleventyConfig.addPlugin(iconPlugin); eleventyConfig.addPlugin(headerPlugin); eleventyConfig.addPlugin(tipPlugin); + eleventyConfig.addPlugin(copyButtonPlugin); // Version shortcode eleventyConfig.addLiquidShortcode("version", function() { diff --git a/docs/assets/js/controllers/clipboard.ts b/docs/assets/js/controllers/clipboard.ts new file mode 100644 index 0000000000..d1f2d7f751 --- /dev/null +++ b/docs/assets/js/controllers/clipboard.ts @@ -0,0 +1,39 @@ +import * as Stacks from '../../../../lib/ts/stacks'; + +Stacks.application.register("clipboard", class extends Stacks.StacksController { + static targets = ["source"]; + sourceTarget!: HTMLElement; + + connect() { + super.connect(); + }; + + copy() { + const text = this.sourceTarget.innerText; + navigator.clipboard.writeText(text); + this.handleVisible(); + } + + private handleVisible() { + const { scope } = this.targets; + + const hideElements = scope.findAllElements('[data-hide-on-copy]'); + const showElements = scope.findAllElements('[data-show-on-copy]'); + + hideElements.forEach(el => { + el.classList.add("d-none"); + }); + showElements.forEach(el => { + el.classList.remove("d-none"); + }); + + setTimeout(function () { + hideElements.forEach(el => { + el.classList.remove("d-none"); + }); + showElements.forEach(el => { + el.classList.add("d-none"); + }); + }, 3000); + } +}); diff --git a/docs/assets/js/index.ts b/docs/assets/js/index.ts index c8b10faf6b..7976761cec 100644 --- a/docs/assets/js/index.ts +++ b/docs/assets/js/index.ts @@ -1,5 +1,6 @@ import "../../../lib/ts/index"; import "../less/stacks-documentation.less"; +import "./controllers/clipboard"; import "./controllers/docs-resizer"; import * as Stacks from "../../../lib/ts/index"; diff --git a/docs/assets/less/stacks-documentation.less b/docs/assets/less/stacks-documentation.less index 5273b68af8..020203744d 100644 --- a/docs/assets/less/stacks-documentation.less +++ b/docs/assets/less/stacks-documentation.less @@ -231,6 +231,20 @@ white-space: normal; } +// ============================================================================ +// $ CODE COPY BUTTON +// ---------------------------------------------------------------------------- +.stacks-copy-btn { + .svg-icon, + .svg-icon * { + pointer-events: none; + } + + .iconCheckmark { + color: var(--green-500); + } +} + // ============================================================================ // $ LISTS @@ -255,11 +269,26 @@ box-shadow: none; }); - > pre.s-code-block { + .stacks-copy-btn { + right: var(--su-static8); + top: var(--su-static8); + } + + > pre.s-code-block, + > .stacks-clipboard-content pre.s-code-block { border-radius: var(--br-md) var(--br-md) 0 0; border: 1px solid var(--bc-medium); + display: flex; // flex layout for scroll padding max-height: 24rem; - + padding-right: var(--su32); + + // pseudo element to pad scrollable region to compensate for copy button + &:after { + content: ""; + display: block; + height: var(--su-static1); + width: var(--su-static128); + } .dark-mode({ border-color: var(--bc-lighter); }); diff --git a/docs/plugins/copy-button.js b/docs/plugins/copy-button.js new file mode 100644 index 0000000000..98885795ee --- /dev/null +++ b/docs/plugins/copy-button.js @@ -0,0 +1,36 @@ +const { default: Icons } = require("@stackoverflow/stacks-icons"); + +module.exports = { + configFunction(eleventyConfig) { + eleventyConfig.addPairedShortcode("copybutton", function(content, classes, btnClasses) { + var tooltipId = "tooltip-" + Math.floor(Math.random() * 1000); + + var output = ` +
+ + +
+ ${content} +
+
+`; + + return output; + }); + } +} \ No newline at end of file diff --git a/docs/product/components/cards.html b/docs/product/components/cards.html index f58ffdd769..8662cb800c 100644 --- a/docs/product/components/cards.html +++ b/docs/product/components/cards.html @@ -9,6 +9,7 @@

The base card styling applies a border and padding to the card.

Cards can be any size and it’s ok to increase the body text size for larger cards.

+{% copybutton %} {% highlight html %}

@@ -16,6 +17,7 @@

{% endhighlight %} +{% endcopybutton %}

Base card title

@@ -41,12 +43,14 @@

Base card title

{% header "h2", "Box shadows" %}

Applying a .bs-* class adds a box shadow to a card. Useful when giving users the impression they can interact with the card.

+{% copybutton %} {% highlight html %}
{% endhighlight %} -
+{% endcopybutton %} +

Small box shadow

@@ -70,6 +74,7 @@

Large box shadow

The .s-card class can be applied to an <a> tag for instances where a whole card should link somewhere. If possible, linked cards should visually indication that they’re interactive (ex. including an .s-btn or .s-link somewhere).

A :hover style for border color is automatically added to all linked cards. For linked cards with a box shadow (.bs-*), adding a .h:bs-* class will apply a hover style to the box shadow as well. Increasing the .bs- size by a factor of one is usually best.

+{% copybutton %} {% highlight html %}

@@ -83,6 +88,7 @@

{% endhighlight %} +{% endcopybutton %}
@@ -122,12 +128,14 @@

Large box shadow on :hover

{% header "h2", "Muted" %}

When a card is disabled or considered completed, apply the muted modifier to visually dim the card.

+{% copybutton %} {% highlight html %}

{% endhighlight %} +{% endcopybutton %}
@@ -147,6 +155,7 @@

Linked card title

{% header "h2", "Stacked" %}

First introduced for our collections feature in Teams, cards can also be stacked to imply multiple sections or items. No need to overthink it, we can just nest our cards. Note: You’ll need to compensate for the 4px of nesting on that right edge to keep things equidistant.

+{% copybutton %} {% highlight html %}
@@ -154,6 +163,7 @@

Linked card title

{% endhighlight %} +{% endcopybutton %}
diff --git a/docs/product/components/checkbox.html b/docs/product/components/checkbox.html index e3c2ee8d6c..36ca5c9817 100644 --- a/docs/product/components/checkbox.html +++ b/docs/product/components/checkbox.html @@ -7,6 +7,7 @@
{% header "h2", "Base style" %}
+{% copybutton %} {% highlight html %}
@@ -28,6 +29,7 @@
{% endhighlight %} +{% endcopybutton %}
@@ -87,6 +89,7 @@ {% header "h2", "Examples" %} {% header "h3", "Vertical group" %}
+{% copybutton %} {% highlight html %}
Which types of fruit do you like? (Check all that apply) @@ -116,6 +119,7 @@
{% endhighlight %} +{% endcopybutton %}
Which types of fruit do you like? (Check all that apply) @@ -149,6 +153,7 @@ {% header "h3", "Horizontal group" %}
+{% copybutton %} {% highlight html %}
Which types of fruit do you like? (Check all that apply) @@ -182,6 +187,7 @@
{% endhighlight %} +{% endcopybutton %}
Which types of fruit do you like? (Check all that apply) @@ -219,6 +225,7 @@ {% header "h3", "With description copy" %}
+{% copybutton %} {% highlight html %}
Which types of fruit do you like? (Check all that apply) @@ -263,6 +270,7 @@
{% endhighlight %} +{% endcopybutton %}
Which types of fruit do you like? (Check all that apply) @@ -341,6 +349,7 @@ {% header "h3", "Validation examples" %}
+{% copybutton %} {% highlight html %}
Which types of fruit do you like? (Check all that apply) @@ -385,6 +394,7 @@
{% endhighlight %} +{% endcopybutton %}
Which types of fruit do you like? (Check all that apply)