History

fix(marketing): inline graph paper SVG, swap copy link for icon button

The /pattern-graph-paper.svg public asset was 404ing in production, so the hero grid pattern never rendered. Inline the SVG as a data URI in the mask so it can never miss. While here, turn the "$ npx executor web" hero link into a button that copies the command to the clipboard, with a copy icon that crossfades to a check on success.

Rhys Sullivan committed 6 months ago

Commit 880c1261 parent d1d7c992 files · +60 −4Browse files

Unified · Split

2 files
  1. apps/marketing/src/pages/index.astro +26 −2
  2. apps/marketing/src/styles/global.css +34 −2
apps/marketing/src/pages/index.astro+26−2
@@ -43,10 +43,14 @@ import { AnimatedBeamDemo } from '../components/animated-beam-demo' · 42 unmodified lines
43 </p>43 </p>
44 <div class="rise-4 flex flex-wrap items-center justify-center gap-5">44 <div class="rise-4 flex flex-wrap items-center justify-center gap-5">
45 <a href="/cloud" class="btn-primary">Try Cloud →</a>45 <a href="/cloud" class="btn-primary">Try Cloud →</a>
46 <a href="#install" class="btn-link">46 <button type="button" class="btn-link copy-btn" data-copy="npx executor web" aria-label="Copy npx executor web to clipboard">
47 <span class="font-mono text-[13px] text-ink-3">$</span>47 <span class="font-mono text-[13px] text-ink-3">$</span>
48 <span>npx executor web</span>48 <span>npx executor web</span>
49 </a>49 <span class="copy-icons text-ink-3" aria-hidden="true">
50 <svg class="copy-icon-copy" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
51 <svg class="copy-icon-check" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
52 </span>
53 </button>
50 </div>54 </div>
51 </div>55 </div>
52 </div>56 </div>
@@ -291,3 +295,23 @@ import { AnimatedBeamDemo } from '../components/animated-beam-demo' · 238 unmodified lines
291 </div>295 </div>
292 </main>296 </main>
293</Layout>297</Layout>
298
299<script>
300 document.querySelectorAll<HTMLButtonElement>('button[data-copy]').forEach((btn) => {
301 let timer: ReturnType<typeof setTimeout> | null = null
302
303 btn.addEventListener('click', async () => {
304 const text = btn.dataset.copy ?? ''
305 try {
306 await navigator.clipboard.writeText(text)
307 btn.dataset.copied = 'true'
308 } catch {
309 btn.dataset.copied = 'false'
310 }
311 if (timer) clearTimeout(timer)
312 timer = setTimeout(() => {
313 delete btn.dataset.copied
314 }, 1500)
315 })
316 })
317</script>
apps/marketing/src/styles/global.css+34−2
@@ -55,8 +55,9 @@ body { · 54 unmodified lines
55 z-index: 1;55 z-index: 1;
56}56}
57.pattern-graph {57.pattern-graph {
58 -webkit-mask-image: url("/pattern-graph-paper.svg");58 --pattern-graph: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='100'%20height='100'%20viewBox='0%200%20100%20100'%3E%3Cg%20fill-rule='evenodd'%3E%3Cg%20fill='%23000'%3E%3Cpath%20opacity='.5'%20d='M96%2095h4v1h-4v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9zm-1%200v-9h-9v9h9zm-10%200v-9h-9v9h9zm-10%200v-9h-9v9h9zm-10%200v-9h-9v9h9zm-10%200v-9h-9v9h9zm-10%200v-9h-9v9h9zm-10%200v-9h-9v9h9zm-10%200v-9h-9v9h9zm-9-10h9v-9h-9v9zm10%200h9v-9h-9v9zm10%200h9v-9h-9v9zm10%200h9v-9h-9v9zm10%200h9v-9h-9v9zm10%200h9v-9h-9v9zm10%200h9v-9h-9v9zm10%200h9v-9h-9v9zm9-10v-9h-9v9h9zm-10%200v-9h-9v9h9zm-10%200v-9h-9v9h9zm-10%200v-9h-9v9h9zm-10%200v-9h-9v9h9zm-10%200v-9h-9v9h9zm-10%200v-9h-9v9h9zm-10%200v-9h-9v9h9zm-9-10h9v-9h-9v9zm10%200h9v-9h-9v9zm10%200h9v-9h-9v9zm10%200h9v-9h-9v9zm10%200h9v-9h-9v9zm10%200h9v-9h-9v9zm10%200h9v-9h-9v9zm10%200h9v-9h-9v9zm9-10v-9h-9v9h9zm-10%200v-9h-9v9h9zm-10%200v-9h-9v9h9zm-10%200v-9h-9v9h9zm-10%200v-9h-9v9h9zm-10%200v-9h-9v9h9zm-10%200v-9h-9v9h9zm-10%200v-9h-9v9h9zm-9-10h9v-9h-9v9zm10%200h9v-9h-9v9zm10%200h9v-9h-9v9zm10%200h9v-9h-9v9zm10%200h9v-9h-9v9zm10%200h9v-9h-9v9zm10%200h9v-9h-9v9zm10%200h9v-9h-9v9zm9-10v-9h-9v9h9zm-10%200v-9h-9v9h9zm-10%200v-9h-9v9h9zm-10%200v-9h-9v9h9zm-10%200v-9h-9v9h9zm-10%200v-9h-9v9h9zm-10%200v-9h-9v9h9zm-10%200v-9h-9v9h9zm-9-10h9v-9h-9v9zm10%200h9v-9h-9v9zm10%200h9v-9h-9v9zm10%200h9v-9h-9v9zm10%200h9v-9h-9v9zm10%200h9v-9h-9v9zm10%200h9v-9h-9v9zm10%200h9v-9h-9v9z'/%3E%3Cpath%20d='M6%205V0H5v5H0v1h5v94h1V6h94V5H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
59 mask-image: url("/pattern-graph-paper.svg");59 -webkit-mask-image: var(--pattern-graph);
60 mask-image: var(--pattern-graph);
60 -webkit-mask-size: 100px 100px;61 -webkit-mask-size: 100px 100px;
61 mask-size: 100px 100px;62 mask-size: 100px 100px;
62 opacity: 0.08;63 opacity: 0.08;
@@ -141,11 +142,42 @@ body { · 78 unmodified lines
141 align-items: center;142 align-items: center;
142 gap: 0.4rem;143 gap: 0.4rem;
143 transition: color 0.15s ease;144 transition: color 0.15s ease;
145 background: transparent;
146 border: 0;
147 padding: 0;
148 font-family: inherit;
149 cursor: pointer;
144}150}
145.btn-link:hover {151.btn-link:hover {
146 color: var(--color-ink);152 color: var(--color-ink);
147}153}
148 154
155.copy-icons {
156 position: relative;
157 display: inline-flex;
158 width: 14px;
159 height: 14px;
160 margin-left: 0.15rem;
161}
162.copy-icons > svg {
163 position: absolute;
164 inset: 0;
165 transition: opacity 0.15s ease, transform 0.15s ease;
166}
167.copy-icon-check {
168 opacity: 0;
169 transform: scale(0.8);
170 color: var(--color-accent);
171}
172.copy-btn[data-copied="true"] .copy-icon-copy {
173 opacity: 0;
174 transform: scale(0.8);
175}
176.copy-btn[data-copied="true"] .copy-icon-check {
177 opacity: 1;
178 transform: scale(1);
179}
180
149/* Legal pages */181/* Legal pages */
150.legal-prose {182.legal-prose {
151 color: color-mix(in srgb, var(--color-ink) 85%, transparent);183 color: color-mix(in srgb, var(--color-ink) 85%, transparent);