mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-12 14:16:28 +03:00
Add site copy feedback and command block fixes (#200)
* Add copy confirmation animation * Add live mode copy confirmation * Add Neo Mirai copy confirmation * Fix Neo Mirai command overflow on narrow screens * Link footer logo to homepage * Fix copy feedback helper --------- Co-authored-by: Paul Bakaus <43004+pbakaus@users.noreply.github.com>
This commit is contained in:
co-authored by
Paul Bakaus
parent
08d50f215b
commit
397d3cb4b7
@@ -3,7 +3,7 @@
|
||||
|
||||
<footer class="site-footer">
|
||||
<div class="footer-row">
|
||||
<span class="footer-logo">Impeccable</span>
|
||||
<a class="footer-logo" href="/">Impeccable</a>
|
||||
<nav class="footer-links" aria-label="Footer">
|
||||
<a href="/changelog">Changelog</a>
|
||||
<a href="/faq">FAQ</a>
|
||||
|
||||
@@ -87,21 +87,22 @@ import '../../styles/sub-pages.css';
|
||||
<h2>Use craft when the output has to feel designed.</h2>
|
||||
<p><code>/impeccable craft</code> is the right command when a feature needs shaping, visual direction, implementation, and browser iteration in one run.</p>
|
||||
</div>
|
||||
<div class="code-block-wrap"><pre class="code-block"><code>/impeccable craft retro-futurist AI design conference website</code></pre><button class="code-block-copy" type="button" data-copy="/impeccable craft retro-futurist AI design conference website" aria-label="Copy to clipboard"></button></div>
|
||||
<div class="code-block-wrap"><pre class="code-block"><code>/impeccable craft retro-futurist AI design conference website</code></pre><button class="code-block-copy" type="button" data-copy="/impeccable craft retro-futurist AI design conference website" aria-label="Copy to clipboard">
|
||||
<svg class="code-block-copy-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true">
|
||||
<rect x="9" y="9" width="13" height="13" rx="2"></rect>
|
||||
<path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"></path>
|
||||
</svg>
|
||||
<svg class="code-block-check-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
<path d="M20 6 9 17l-5-5"></path>
|
||||
</svg>
|
||||
</button></div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<script is:inline>
|
||||
document.addEventListener('click', (event) => {
|
||||
const button = event.target.closest('[data-copy]');
|
||||
if (!button) return;
|
||||
const text = button.getAttribute('data-copy');
|
||||
if (!text) return;
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
button.classList.add('is-copied');
|
||||
setTimeout(() => button.classList.remove('is-copied'), 1500);
|
||||
}).catch(() => {});
|
||||
});
|
||||
<script>
|
||||
import { initCopyFeedback } from "../../scripts/utils/copy-feedback.js";
|
||||
|
||||
initCopyFeedback();
|
||||
</script>
|
||||
|
||||
</Base>
|
||||
|
||||
+16
-4
@@ -597,10 +597,13 @@ import '../styles/testimonials.css';
|
||||
<span class="downloads-rebuild-prompt" aria-hidden="true">$</span>
|
||||
<code>npx impeccable skills install</code>
|
||||
<button class="downloads-rebuild-copy" type="button" aria-label="Copy install command" data-copy="npx impeccable skills install">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true">
|
||||
<svg class="downloads-rebuild-copy-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true">
|
||||
<rect x="9" y="9" width="13" height="13" rx="2"/>
|
||||
<path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/>
|
||||
</svg>
|
||||
<svg class="downloads-rebuild-check-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
<path d="M20 6 9 17l-5-5"/>
|
||||
</svg>
|
||||
<span>Copy</span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -612,10 +615,13 @@ import '../styles/testimonials.css';
|
||||
<span class="downloads-rebuild-prompt" aria-hidden="true">$</span>
|
||||
<code>npx impeccable skills update</code>
|
||||
<button class="downloads-rebuild-copy" type="button" aria-label="Copy update command" data-copy="npx impeccable skills update">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true">
|
||||
<svg class="downloads-rebuild-copy-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true">
|
||||
<rect x="9" y="9" width="13" height="13" rx="2"/>
|
||||
<path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/>
|
||||
</svg>
|
||||
<svg class="downloads-rebuild-check-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
<path d="M20 6 9 17l-5-5"/>
|
||||
</svg>
|
||||
<span>Copy</span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -634,10 +640,13 @@ import '../styles/testimonials.css';
|
||||
<div class="downloads-rebuild-cmd downloads-rebuild-cmd--alt">
|
||||
<code>/plugin marketplace add pbakaus/impeccable</code>
|
||||
<button class="downloads-rebuild-copy" type="button" aria-label="Copy Claude Code plugin command" data-copy="/plugin marketplace add pbakaus/impeccable">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true">
|
||||
<svg class="downloads-rebuild-copy-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true">
|
||||
<rect x="9" y="9" width="13" height="13" rx="2"/>
|
||||
<path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/>
|
||||
</svg>
|
||||
<svg class="downloads-rebuild-check-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
<path d="M20 6 9 17l-5-5"/>
|
||||
</svg>
|
||||
<span>Copy</span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -649,10 +658,13 @@ import '../styles/testimonials.css';
|
||||
<div class="downloads-rebuild-cmd downloads-rebuild-cmd--alt">
|
||||
<code>npx skills add pbakaus/impeccable</code>
|
||||
<button class="downloads-rebuild-copy" type="button" aria-label="Copy npx skills command" data-copy="npx skills add pbakaus/impeccable">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true">
|
||||
<svg class="downloads-rebuild-copy-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true">
|
||||
<rect x="9" y="9" width="13" height="13" rx="2"/>
|
||||
<path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/>
|
||||
</svg>
|
||||
<svg class="downloads-rebuild-check-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
<path d="M20 6 9 17l-5-5"/>
|
||||
</svg>
|
||||
<span>Copy</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -24,10 +24,13 @@ import '../../styles/live-mode-kinpaku.css';
|
||||
<span class="live-mode-start-prompt">$</span>
|
||||
<code class="live-mode-start-cmd">/impeccable live</code>
|
||||
<button class="live-mode-start-copy" type="button" aria-label="Copy command" data-copy="/impeccable live">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<svg class="live-mode-start-copy-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
|
||||
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
|
||||
<path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"></path>
|
||||
</svg>
|
||||
<svg class="live-mode-start-check-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
<path d="M20 6 9 17l-5-5"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<p class="live-mode-page-alpha-note"><strong>Why beta:</strong> works end-to-end across the common frameworks and is ready for daily use. Uncommon setups may still hit rough edges. Please report what breaks.</p>
|
||||
@@ -223,24 +226,16 @@ import '../../styles/live-mode-kinpaku.css';
|
||||
|
||||
<script>
|
||||
import { initLiveDemo, initGbarPageChat } from "../../scripts/components/live-demo.js";
|
||||
import { initCopyFeedback } from "../../scripts/utils/copy-feedback.js";
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
initLiveDemo();
|
||||
initGbarPageChat();
|
||||
initCopyFeedback();
|
||||
});
|
||||
</script>
|
||||
|
||||
<script is:inline>
|
||||
document.addEventListener('click', (e) => {
|
||||
const btn = e.target.closest('[data-copy]');
|
||||
if (!btn) return;
|
||||
const text = btn.getAttribute('data-copy');
|
||||
if (!text) return;
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
btn.classList.add('is-copied');
|
||||
setTimeout(() => btn.classList.remove('is-copied'), 1500);
|
||||
}).catch(() => {});
|
||||
});
|
||||
|
||||
document.addEventListener('click', (e) => {
|
||||
const toggle = e.target.closest('.skills-sidebar-toggle');
|
||||
if (!toggle) return;
|
||||
|
||||
+2
-20
@@ -5,6 +5,7 @@ import {
|
||||
import { initFrameworkViz } from "./components/framework-viz.js";
|
||||
import { initScrollReveal } from "./utils/reveal.js";
|
||||
import { initAnchorScroll, initHashTracking } from "./utils/scroll.js";
|
||||
import { initCopyFeedback } from "./utils/copy-feedback.js";
|
||||
import { initSectionNav } from "./components/section-nav.js";
|
||||
import { initFoundationGrid } from "./components/foundation-grid.js";
|
||||
import { initLiveDemo, initGbarPageChat } from "./components/live-demo.js";
|
||||
@@ -208,26 +209,6 @@ document.addEventListener("click", (e) => {
|
||||
const bundleName = bundleBtn.dataset.bundle;
|
||||
window.location.href = `/api/download/bundle/${bundleName}`;
|
||||
}
|
||||
|
||||
// Handle copy button clicks
|
||||
const copyBtn = e.target.closest("[data-copy]");
|
||||
if (copyBtn) {
|
||||
const textToCopy = copyBtn.dataset.copy;
|
||||
const onCopied = () => {
|
||||
copyBtn.classList.add('copied');
|
||||
setTimeout(() => copyBtn.classList.remove('copied'), 1500);
|
||||
};
|
||||
if (navigator.clipboard?.writeText) {
|
||||
navigator.clipboard.writeText(textToCopy).then(onCopied).catch(() => {});
|
||||
} else {
|
||||
// Fallback for non-HTTPS or older browsers
|
||||
const ta = Object.assign(document.createElement('textarea'), { value: textToCopy, style: 'position:fixed;left:-9999px' });
|
||||
document.body.appendChild(ta);
|
||||
ta.select();
|
||||
try { document.execCommand('copy'); onCopied(); } catch {}
|
||||
ta.remove();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -261,6 +242,7 @@ function initHeaderScroll() {
|
||||
function init() {
|
||||
initAnchorScroll();
|
||||
initHashTracking();
|
||||
initCopyFeedback();
|
||||
initHeaderScroll();
|
||||
initScrollReveal();
|
||||
initGlassTerminal();
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
const copyResetTimers = new WeakMap();
|
||||
|
||||
function copyWithTextareaFallback(text) {
|
||||
const ta = Object.assign(document.createElement('textarea'), {
|
||||
value: text,
|
||||
style: 'position:fixed;left:-9999px',
|
||||
});
|
||||
|
||||
document.body.appendChild(ta);
|
||||
ta.focus();
|
||||
ta.select();
|
||||
|
||||
try {
|
||||
return document.execCommand('copy');
|
||||
} catch {
|
||||
return false;
|
||||
} finally {
|
||||
ta.remove();
|
||||
}
|
||||
}
|
||||
|
||||
function showCopiedState(button, { copiedClass = 'copied', resetMs = 1200 } = {}) {
|
||||
window.clearTimeout(copyResetTimers.get(button));
|
||||
button.classList.remove(copiedClass);
|
||||
void button.offsetWidth;
|
||||
button.classList.add(copiedClass);
|
||||
copyResetTimers.set(
|
||||
button,
|
||||
window.setTimeout(() => button.classList.remove(copiedClass), resetMs),
|
||||
);
|
||||
}
|
||||
|
||||
async function copyText(text) {
|
||||
if (navigator.clipboard?.writeText) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(text);
|
||||
return true;
|
||||
} catch {}
|
||||
}
|
||||
|
||||
return copyWithTextareaFallback(text);
|
||||
}
|
||||
|
||||
export function initCopyFeedback({
|
||||
selector = '[data-copy]',
|
||||
copiedClass = 'copied',
|
||||
resetMs = 1200,
|
||||
} = {}) {
|
||||
document.addEventListener('click', async (event) => {
|
||||
if (!(event.target instanceof Element)) return;
|
||||
|
||||
const button = event.target.closest(selector);
|
||||
if (!(button instanceof HTMLElement)) return;
|
||||
|
||||
const text = button.getAttribute('data-copy');
|
||||
if (!text) return;
|
||||
|
||||
if (await copyText(text)) {
|
||||
showCopiedState(button, { copiedClass, resetMs });
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -3327,6 +3327,10 @@
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.neon-case-command > * {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.neon-case-command h2 {
|
||||
color: var(--ks-champagne);
|
||||
}
|
||||
@@ -3341,12 +3345,28 @@
|
||||
}
|
||||
|
||||
.neon-case-command .code-block-wrap {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
max-width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.neon-case-command .code-block-wrap::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
right: 1px;
|
||||
bottom: 31px;
|
||||
width: 142px;
|
||||
pointer-events: none;
|
||||
background: linear-gradient(90deg, transparent, var(--ks-code-block-bg) 74%);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.neon-case-command .code-block {
|
||||
max-width: 100%;
|
||||
margin: 0;
|
||||
padding: var(--spacing-md);
|
||||
padding: var(--spacing-md) 96px var(--spacing-md) var(--spacing-md);
|
||||
background: var(--ks-code-block-bg);
|
||||
color: var(--ks-code-block-fg);
|
||||
border: 1px solid var(--ks-code-block-border);
|
||||
@@ -3365,10 +3385,101 @@
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
.neon-case-command .code-block-copy.is-copied {
|
||||
background: var(--ks-kinpaku);
|
||||
color: var(--ks-lacquer-deep);
|
||||
border-color: var(--ks-kinpaku);
|
||||
.neon-case-command .code-block-copy {
|
||||
top: 0;
|
||||
right: 14px;
|
||||
bottom: 17px;
|
||||
margin: auto 0;
|
||||
z-index: 2;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
padding: 0;
|
||||
opacity: 1;
|
||||
background: oklch(5% 0.004 95 / 0.94);
|
||||
border: 1px solid var(--ks-code-block-border);
|
||||
border-radius: 3px;
|
||||
color: var(--ks-kinpaku);
|
||||
transform: none;
|
||||
transition:
|
||||
background 180ms var(--ks-ease),
|
||||
border-color 180ms var(--ks-ease),
|
||||
color 180ms var(--ks-ease),
|
||||
transform 120ms var(--ks-ease);
|
||||
}
|
||||
|
||||
.neon-case-command .code-block-copy::before {
|
||||
content: none;
|
||||
}
|
||||
|
||||
.neon-case-command .code-block-copy:hover {
|
||||
background: oklch(8% 0.006 95);
|
||||
border-color: currentColor;
|
||||
color: var(--ks-kinpaku);
|
||||
}
|
||||
|
||||
.neon-case-command .code-block-copy:active {
|
||||
transform: scale(0.96);
|
||||
}
|
||||
|
||||
.neon-case-command .code-block-copy-icon,
|
||||
.neon-case-command .code-block-check-icon {
|
||||
grid-area: 1 / 1;
|
||||
transition:
|
||||
opacity 140ms var(--ks-ease),
|
||||
transform 180ms var(--ks-ease);
|
||||
}
|
||||
|
||||
.neon-case-command .code-block-copy-icon {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
.neon-case-command .code-block-check-icon {
|
||||
opacity: 0;
|
||||
transform: scale(0.86);
|
||||
}
|
||||
|
||||
.neon-case-command .code-block-check-icon path {
|
||||
stroke-dasharray: 24;
|
||||
stroke-dashoffset: 24;
|
||||
}
|
||||
|
||||
.neon-case-command .code-block-copy.copied {
|
||||
background: oklch(8% 0.006 95);
|
||||
border-color: currentColor;
|
||||
}
|
||||
|
||||
.neon-case-command .code-block-copy.copied .code-block-copy-icon {
|
||||
opacity: 0;
|
||||
transform: scale(0.82);
|
||||
}
|
||||
|
||||
.neon-case-command .code-block-copy.copied .code-block-check-icon {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
.neon-case-command .code-block-copy.copied .code-block-check-icon path {
|
||||
animation: neon-case-check-draw 260ms var(--ks-ease) forwards;
|
||||
}
|
||||
|
||||
@keyframes neon-case-check-draw {
|
||||
to { stroke-dashoffset: 0; }
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.neon-case-command .code-block-copy,
|
||||
.neon-case-command .code-block-copy-icon,
|
||||
.neon-case-command .code-block-check-icon {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.neon-case-command .code-block-copy.copied .code-block-check-icon path {
|
||||
animation: none;
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 980px) {
|
||||
|
||||
@@ -738,6 +738,7 @@
|
||||
/* Compact icon-only copy button nested inside the cmd box, on the right. */
|
||||
.home-kinpaku .downloads-rebuild-copy {
|
||||
flex: none;
|
||||
position: relative;
|
||||
display: inline-grid;
|
||||
place-items: center;
|
||||
width: 40px;
|
||||
@@ -747,7 +748,74 @@
|
||||
color: var(--card-copy-fg);
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
transition: background 180ms var(--ks-ease), border-color 180ms var(--ks-ease);
|
||||
transition:
|
||||
background 180ms var(--ks-ease),
|
||||
border-color 180ms var(--ks-ease),
|
||||
color 180ms var(--ks-ease),
|
||||
transform 120ms var(--ks-ease);
|
||||
}
|
||||
|
||||
.home-kinpaku .downloads-rebuild-copy:active {
|
||||
transform: scale(0.96);
|
||||
}
|
||||
|
||||
.home-kinpaku .downloads-rebuild-copy-icon,
|
||||
.home-kinpaku .downloads-rebuild-check-icon {
|
||||
grid-area: 1 / 1;
|
||||
transition:
|
||||
opacity 140ms var(--ks-ease),
|
||||
transform 180ms var(--ks-ease);
|
||||
}
|
||||
|
||||
.home-kinpaku .downloads-rebuild-copy-icon {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
.home-kinpaku .downloads-rebuild-check-icon {
|
||||
opacity: 0;
|
||||
transform: scale(0.86);
|
||||
}
|
||||
|
||||
.home-kinpaku .downloads-rebuild-check-icon path {
|
||||
stroke-dasharray: 24;
|
||||
stroke-dashoffset: 24;
|
||||
}
|
||||
|
||||
.home-kinpaku .downloads-rebuild-copy.copied {
|
||||
background: var(--card-copy-hover-bg);
|
||||
border-color: currentColor;
|
||||
}
|
||||
|
||||
.home-kinpaku .downloads-rebuild-copy.copied .downloads-rebuild-copy-icon {
|
||||
opacity: 0;
|
||||
transform: scale(0.82);
|
||||
}
|
||||
|
||||
.home-kinpaku .downloads-rebuild-copy.copied .downloads-rebuild-check-icon {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
.home-kinpaku .downloads-rebuild-copy.copied .downloads-rebuild-check-icon path {
|
||||
animation: downloads-check-draw 260ms var(--ks-ease) forwards;
|
||||
}
|
||||
|
||||
@keyframes downloads-check-draw {
|
||||
to { stroke-dashoffset: 0; }
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.home-kinpaku .downloads-rebuild-copy,
|
||||
.home-kinpaku .downloads-rebuild-copy-icon,
|
||||
.home-kinpaku .downloads-rebuild-check-icon {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.home-kinpaku .downloads-rebuild-copy.copied .downloads-rebuild-check-icon path {
|
||||
animation: none;
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.home-kinpaku .downloads-rebuild-copy span {
|
||||
|
||||
@@ -163,17 +163,77 @@
|
||||
place-items: center;
|
||||
padding: 4px;
|
||||
border-radius: 2px;
|
||||
transition: color 160ms var(--ks-ease);
|
||||
transition:
|
||||
color 160ms var(--ks-ease),
|
||||
transform 120ms var(--ks-ease);
|
||||
}
|
||||
|
||||
.live-mode-kinpaku .live-mode-start-copy:hover {
|
||||
color: var(--ks-kinpaku);
|
||||
}
|
||||
|
||||
.live-mode-kinpaku .live-mode-start-copy.is-copied {
|
||||
.live-mode-kinpaku .live-mode-start-copy:active {
|
||||
transform: scale(0.96);
|
||||
}
|
||||
|
||||
.live-mode-kinpaku .live-mode-start-copy-icon,
|
||||
.live-mode-kinpaku .live-mode-start-check-icon {
|
||||
grid-area: 1 / 1;
|
||||
transition:
|
||||
opacity 140ms var(--ks-ease),
|
||||
transform 180ms var(--ks-ease);
|
||||
}
|
||||
|
||||
.live-mode-kinpaku .live-mode-start-copy-icon {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
.live-mode-kinpaku .live-mode-start-check-icon {
|
||||
opacity: 0;
|
||||
transform: scale(0.86);
|
||||
}
|
||||
|
||||
.live-mode-kinpaku .live-mode-start-check-icon path {
|
||||
stroke-dasharray: 24;
|
||||
stroke-dashoffset: 24;
|
||||
}
|
||||
|
||||
.live-mode-kinpaku .live-mode-start-copy.copied {
|
||||
color: var(--ks-kinpaku);
|
||||
}
|
||||
|
||||
.live-mode-kinpaku .live-mode-start-copy.copied .live-mode-start-copy-icon {
|
||||
opacity: 0;
|
||||
transform: scale(0.82);
|
||||
}
|
||||
|
||||
.live-mode-kinpaku .live-mode-start-copy.copied .live-mode-start-check-icon {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
.live-mode-kinpaku .live-mode-start-copy.copied .live-mode-start-check-icon path {
|
||||
animation: live-mode-check-draw 260ms var(--ks-ease) forwards;
|
||||
}
|
||||
|
||||
@keyframes live-mode-check-draw {
|
||||
to { stroke-dashoffset: 0; }
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.live-mode-kinpaku .live-mode-start-copy,
|
||||
.live-mode-kinpaku .live-mode-start-copy-icon,
|
||||
.live-mode-kinpaku .live-mode-start-check-icon {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.live-mode-kinpaku .live-mode-start-copy.copied .live-mode-start-check-icon path {
|
||||
animation: none;
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ============================================================================
|
||||
3. INTERACTIVE DEMO — frame chrome + Impeccable picker bar re-skin
|
||||
|
||||
Reference in New Issue
Block a user