Skip to content

Commit

Permalink
[Playground] Click to Copy (#1177)
Browse files Browse the repository at this point in the history
Co-authored-by: Stacy Kvernmo <stacy@oddbird.net>
Co-authored-by: Jonny Gerig Meyer <jonny@oddbird.net>
  • Loading branch information
3 people authored Sep 20, 2024
1 parent ff96bb7 commit f8811a7
Show file tree
Hide file tree
Showing 9 changed files with 179 additions and 14 deletions.
1 change: 1 addition & 0 deletions source/_includes/icons/circle-check.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM369 209c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0l-111 111-47-47c-9.4-9.4-24.6-9.4-33.9 0s-9.4 24.6 0 33.9l64 64c9.4 9.4 24.6 9.4 33.9 0L369 209z"/></svg>
1 change: 1 addition & 0 deletions source/_includes/icons/copy.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M208 0L332.1 0c12.7 0 24.9 5.1 33.9 14.1l67.9 67.9c9 9 14.1 21.2 14.1 33.9L448 336c0 26.5-21.5 48-48 48l-192 0c-26.5 0-48-21.5-48-48l0-288c0-26.5 21.5-48 48-48zM48 128l80 0 0 64-64 0 0 256 192 0 0-32 64 0 0 48c0 26.5-21.5 48-48 48L48 512c-26.5 0-48-21.5-48-48L0 176c0-26.5 21.5-48 48-48z"/></svg>
11 changes: 10 additions & 1 deletion source/_includes/playground/header.liquid
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,16 @@
<button
type="button"
id="playground-copy-url"
class="sl-c-button">Copy URL</button>
class="sl-c-button sl-c-button--copy sl-c-button--icon-text">
<div class="sl-c-playground-button--copy--copy">
{%- render 'icons/copy' -%}
</div>
<div class="sl-c-playground-button--copy--copied">
{%- render 'icons/circle-check' -%}
<span class="visuallyhidden">URL is Copied</span>
</div>
<span class="sl-c-button--icon-text--text">Copy URL</span>
</button>
</div>
<div class="sl-c-alert sl-r-banner__playground-alert" id="playground-copied-alert">
Copied to clipboard
Expand Down
56 changes: 50 additions & 6 deletions source/assets/js/playground.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ import {
serializeState,
} from './playground/utils.js';

// The timer id result from the last call to `setTimeout`, if one has been made.
type Timer = undefined | number;

// The time before a microinteraction like a toast or icon change resets.
const MICROINTERACTION_RESET_TIME = 3000;

function setupPlayground(): void {
const hash = location.hash.slice(1);
const hashState = deserializeState(hash);
Expand All @@ -35,6 +41,7 @@ function setupPlayground(): void {
inputValue: hashState.inputValue || defaultContents[inputFormat],
debugOutput: [],
selection: hashState.selection || null,
outputValue: '',
};

// Proxy intercepts setters and triggers side effects
Expand Down Expand Up @@ -199,15 +206,51 @@ function setupPlayground(): void {
const copyURLButton = document.getElementById('playground-copy-url');
const copiedAlert = document.getElementById('playground-copied-alert');

let timer: undefined | number;
let alertTimer: Timer;
const buttonTimers: {input: Timer; output: Timer; url: Timer} = {
input: undefined,
output: undefined,
url: undefined,
};

function showCopiedAlert(msg: string): void {
if (!copiedAlert) return;
copiedAlert.innerText = msg;
copiedAlert.classList.add('show');
if (alertTimer) clearTimeout(alertTimer);
alertTimer = window.setTimeout(() => {
copiedAlert.classList.remove('show');
}, MICROINTERACTION_RESET_TIME);
}

function showCopiedIcon(button: 'input' | 'output' | 'url'): void {
const buttonEl = $(`#playground-copy-${button}`);
if (!buttonEl) return;
buttonEl.addClass('copied');
if (buttonTimers[button]) clearTimeout(buttonTimers[button]);
buttonTimers[button] = window.setTimeout(() => {
buttonEl.removeClass('copied');
}, MICROINTERACTION_RESET_TIME);
}

copyURLButton?.addEventListener('click', () => {
void navigator.clipboard.writeText(location.href);
copiedAlert?.classList.add('show');
if (timer) clearTimeout(timer);
timer = window.setTimeout(() => {
copiedAlert?.classList.remove('show');
}, 3000);
showCopiedAlert('Copied URL to clipboard');
showCopiedIcon('url');
});

// Copy content handlers
const copyInputButton = document.getElementById('playground-copy-input');
copyInputButton?.addEventListener('click', () => {
void navigator.clipboard.writeText(playgroundState.inputValue);
showCopiedAlert('Copied input to clipboard');
showCopiedIcon('input');
});
const copyOutputButton = document.getElementById('playground-copy-output');
copyOutputButton?.addEventListener('click', () => {
void navigator.clipboard.writeText(playgroundState.outputValue);
showCopiedAlert('Copied output to clipboard');
showCopiedIcon('output');
});
}
/**
Expand Down Expand Up @@ -301,6 +344,7 @@ function setupPlayground(): void {
},
});
playgroundState.compilerHasError = false;
playgroundState.outputValue = result.css;
} else {
playgroundState.compilerHasError = true;
playgroundState.debugOutput = [
Expand Down
1 change: 1 addition & 0 deletions source/assets/js/playground/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export interface PlaygroundState {
inputValue: string;
compilerHasError: boolean;
debugOutput: ConsoleLog[];
outputValue: string;
selection: PlaygroundSelection;
}

Expand Down
36 changes: 33 additions & 3 deletions source/assets/sass/components/_buttons.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,14 @@
font-weight: var(--sl-font-weight--button);
justify-content: center;
margin: 0;
padding: var(--sl-gutter--minus) var(--sl-gutter);
padding: var(
--sl-padding--button,
var(--sl-block-padding--button, var(--sl-gutter--minus))
)
var(
--sl-padding--button,
var(--sl-inline-padding--button, var(--sl-gutter))
);

&:hover,
&:focus {
Expand Down Expand Up @@ -45,12 +52,35 @@
--sl-background--button: var(--sl-color--code-background-darker);
--sl-background--button-active: var(--sl-background--button-state);
--sl-background--button-state: transparent;
--sl-color--button: var(--sl-color--highlight);
--sl-color--button-active: var(--sl-color--midnight-blue);
--sl-color--button: var(
--sl-color--button--tab,
var(--sl-color--highlight)
);
--sl-color--button-active: var(
--sl-color--button--tab-active,
var(--sl-color--midnight-blue)
);
--sl-color--button-state: var(--sl-color--midnight-blue);
--sl-font-weight--button: #{var(--sl-font-weight--bold)};
--sl-radius--button: 0;

box-shadow: none;
}

&--icon {
--sl-display--button: flex;

svg {
flex: 1;
}
}

&--icon-text {
--sl-display--button: flex;
gap: var(--sl-gutter--half);

svg {
flex: 1;
}
}
}
51 changes: 47 additions & 4 deletions source/assets/sass/components/_playground.scss
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ $playground-base-colors: (
}

.sl-r-banner__playground-button {
--sl-color--button: var(--sl-color--action-dark);
grid-area: copy;
justify-self: flex-end;
padding-right: var(--sl-gutter);
text-align: right;

Expand All @@ -94,19 +96,19 @@ $playground-base-colors: (
.sl-r-banner__playground-alert {
--sl-padding-block--alert: 0;

align-items: center;
display: flex;
grid-area: alert;
height: 0;
justify-content: center;
opacity: 0;
padding-left: var(--sl-gutter--half);
padding-right: var(--sl-gutter--half);
padding-inline: var(--sl-gutter--half);
transition:
opacity 0.3s 0.05s,
visibility 0.3s;
visibility: hidden;

&.show {
--sl-padding-block--alert: var(--sl-gutter--minus);

height: 100%;
opacity: 1;
visibility: visible;
Expand All @@ -117,6 +119,7 @@ $playground-base-colors: (
.sl-c-playground {
--sl-block-margin--callout: 0;
--sl-block-padding--callout: var(--sl-gutter--quarter);
--sl-color--button--tab: var(--sl-color--action-dark);

display: grid;
gap: var(--sl-gutter);
Expand Down Expand Up @@ -329,6 +332,7 @@ $playground-base-colors: (
// Playground Tab Bar & Buttons
.sl-c-playground__editor-tabbar {
background-color: var(--sl-color--code-background-darker);
color: var(--sl-color--text-medium-dark);
display: flex;
grid-area: editor-tabbar;

Expand All @@ -351,6 +355,45 @@ $playground-base-colors: (
}
}

.sl-c-button--copy {
--sl-display--button: flex;

&.sl-c-button--icon {
--sl-background--button: transparent;
--sl-background--button-state: transparent;
--sl-block-padding--button: 0;
--sl-color--button: var(--sl-color--text-medium-dark);
--sl-color--button-state: var(--sl-color--action-dark);

box-shadow: none;

&.copied {
--sl-color--button-state: var(--sl-color--text-medium-dark);
}
}
}

[class^='sl-c-playground-button--copy'] {
display: var(--sl-display--playground-button--copy);
width: 0.9em;
}

.sl-c-playground-button--copy--copy {
--sl-display--playground-button--copy: flex;

.copied & {
--sl-display--playground-button--copy: none;
}
}

.sl-c-playground-button--copy--copied {
--sl-display--playground-button--copy: none;

.copied & {
--sl-display--playground-button--copy: flex;
}
}

// Make sure all tab bar buttons and text get the same padding
[data-tabbar~='item'] {
padding: var(--sl-gutter--half) var(--sl-gutter);
Expand Down
10 changes: 10 additions & 0 deletions source/assets/sass/config/color/_content.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ $sl-color--highlight: color.adjust(brand.$sl-color--hopbush, $lightness: -10%);
$sl-color--link-action: rgba(218, 219, 223, 25%);
$sl-color--shadow: rgba(brand.$sl-color--midnight-blue, 0.125);

// Darker Shades of existing colors for use on a light gray background
$sl-color--text-medium-dark: color.adjust(
brand.$sl-color--pale-sky,
$lightness: -5%
);
$sl-color--action-dark: color.adjust(
brand.$sl-color--bouquet,
$lightness: -11.647%
);

// Callouts/Info Panels
$sl-color--warning-light: color.adjust(
brand.$sl-color--hopbush,
Expand Down
26 changes: 26 additions & 0 deletions source/playground.liquid
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,19 @@ is_playground: true
class="sl-c-button sl-c-button--tab"
data-setting="inputFormat">Sass</button>
<span data-tabbar="item" class="sl-c-playground__tabbar-title tabbar-title sl-c-playground__tabbar-version"></span>
<button
type="button"
id="playground-copy-input"
class="sl-c-button sl-c-button--copy sl-c-button--icon">
<div class="sl-c-playground-button--copy--copy">
{%- render 'icons/copy' -%}
<span class="visuallyhidden">Select to Copy</span>
</div>
<div class="sl-c-playground-button--copy--copied">
{%- render 'icons/circle-check' -%}
<span class="visuallyhidden">Code is Copied</span>
</div>
</button>
</div>
<div class="sl-c-playground__panel-content sl-code-is-source"></div>
</div>
Expand All @@ -45,6 +58,19 @@ is_playground: true
<strong>CSS</strong>
(Compiled)
</span>
<button
type="button"
id="playground-copy-output"
class="sl-c-button sl-c-button--copy sl-c-button--icon">
<div class="sl-c-playground-button--copy--copy">
{%- render 'icons/copy' -%}
<span class="visuallyhidden">Select to Copy</span>
</div>
<div class="sl-c-playground-button--copy--copied">
{%- render 'icons/circle-check' -%}
<span class="visuallyhidden">Code is Copied</span>
</div>
</button>
</div>
<div class="sl-c-callout sl-c-callout--warning sl-c-playground__error">Please resolve error to view compiled CSS.</div>
<div class="sl-c-playground__panel-content sl-code-is-compiled"></div>
Expand Down

0 comments on commit f8811a7

Please sign in to comment.