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

[Playground] Click to Copy #1177

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -21,6 +21,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 @@ -34,6 +40,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 @@ -193,15 +200,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 @@ -281,6 +324,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 @@ -13,6 +13,7 @@ export interface PlaygroundState {
inputValue: string;
compilerHasError: boolean;
debugOutput: ConsoleLog[];
outputValue: string;

/**
* `[fromLine, fromColumn, toLine, toColumn]`; all 1-indexed. If this is null,
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 @@ -75,7 +75,9 @@
}

.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 @@ -88,19 +90,19 @@
.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 @@ -111,6 +113,7 @@
.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 @@ -289,6 +292,7 @@
// 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 @@ -311,6 +315,45 @@
}
}

.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 @@ -31,3 +31,13 @@ $sl-color--info-lighter: color.adjust(brand.$sl-color--patina, $lightness: 47%);
$sl-color--error: #cf0254;
$sl-color--warn: #c14e00;
$sl-color--success: #168073;

// 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%
);
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