Skip to content

Commit 87ed64c

Browse files
committed
feat: make variables copyable
1 parent 5a44db8 commit 87ed64c

File tree

6 files changed

+104
-8
lines changed

6 files changed

+104
-8
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
# Changelog
44

5+
## 0.10.0
6+
7+
- Variables in code panels are now copyable.
8+
59
## 0.9.0
610

711
- Updated the script rewrite logic.

components/Code.vue

Lines changed: 85 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script setup lang="ts">
22
import { useCopy } from '@/composables'
3+
import { transformHTML } from '@/utils/dom'
34
45
import IconButton from './IconButton.vue'
56
import Copy from './icons/Copy.vue'
@@ -12,7 +13,7 @@ const props = defineProps<{
1213
}>()
1314
1415
const prismAlias: Record<string, string> = {
15-
vue: 'html',
16+
vue: 'html'
1617
}
1718
1819
const lang = computed(() => {
@@ -29,11 +30,36 @@ const highlighted = computed(() => {
2930
return props.code
3031
}
3132
32-
return Prism.highlight(props.code, Prism.languages[lang.value], lang.value)
33+
const html = Prism.highlight(props.code, Prism.languages[lang.value], lang.value)
34+
35+
return transformHTML(html, (tpl) => {
36+
tpl.querySelectorAll<HTMLElement>('.token.variable, .token.constant').forEach((el) => {
37+
el.setAttribute('tabindex', '0')
38+
el.classList.add('copyable')
39+
el.dataset.tooltipType = 'text'
40+
el.dataset.tooltip = 'Copy'
41+
el.innerHTML = `<span>${el.innerHTML}</span>`
42+
})
43+
44+
tpl.querySelectorAll('.token.number + .token.unit').forEach((el) => {
45+
const span = document.createElement('span')
46+
span.className = 'token dimension'
47+
el.parentNode!.insertBefore(span, el.nextElementSibling)
48+
span.appendChild(el.previousElementSibling!)
49+
span.appendChild(el)
50+
})
51+
})
3352
})
3453
3554
const code = computed(() => props.code)
3655
const copy = useCopy(code)
56+
57+
function handleClick(event: MouseEvent) {
58+
const target = event.target as HTMLElement
59+
if (target.closest('.token.copyable')) {
60+
copy(target)
61+
}
62+
}
3763
</script>
3864

3965
<template>
@@ -47,7 +73,7 @@ const copy = useCopy(code)
4773
</IconButton>
4874
</div>
4975
</header>
50-
<pre class="tp-code-content"><code v-html="highlighted"/></pre>
76+
<pre class="tp-code-content"><code v-html="highlighted" @click="handleClick"/></pre>
5177
</section>
5278
</template>
5379

@@ -100,6 +126,14 @@ const copy = useCopy(code)
100126
color: var(--color-text);
101127
}
102128
129+
.tp-code-content .token.property {
130+
color: var(--color-text);
131+
}
132+
133+
.tp-code-content .token.plain {
134+
color: var(--color-codevalue);
135+
}
136+
103137
.tp-code-content .token.selector {
104138
color: var(--color-codeclassname);
105139
}
@@ -144,4 +178,52 @@ const copy = useCopy(code)
144178
.highlight .token.number {
145179
color: var(--color-codevalue);
146180
}
181+
182+
.tp-code-content .token.number,
183+
.tp-code-content .token.unit {
184+
color: var(--color-codevalue);
185+
}
186+
187+
.tp-code-content .token.copyable {
188+
text-decoration-line: underline;
189+
text-decoration-color: color-mix(in srgb, var(--color-codevariable) 50%, transparent);
190+
text-decoration-style: dashed;
191+
text-decoration-thickness: 1px;
192+
text-underline-offset: 2px;
193+
cursor: pointer;
194+
-webkit-user-select: text;
195+
user-select: text;
196+
background: transparent;
197+
display: unset;
198+
}
199+
200+
.tp-code-content .token.copyable > span {
201+
line-height: 130%;
202+
background: transparent;
203+
border-radius: 4px;
204+
padding: 0 2px;
205+
margin: -2px;
206+
}
207+
208+
.tp-code-content .token.copyable:hover > span {
209+
background: color-mix(in srgb, var(--color-codevariable) 15%, transparent);
210+
}
211+
212+
.tp-code-content .token.copyable {
213+
outline: 2px solid transparent;
214+
}
215+
216+
.tp-code-content .token.copyable:focus-visible {
217+
outline: 2px solid var(--color-border-selected);
218+
outline-offset: -2px;
219+
}
220+
221+
.tp-code-content .token.variable:focus {
222+
outline: 2px solid var(--color-border-selected);
223+
outline-offset: -2px;
224+
}
225+
226+
.tp-code-content .token.variable:focus:not(:focus-visible) {
227+
outline: 2px solid transparent;
228+
}
147229
</style>

composables/copy.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import { useToast } from '@/composables'
22
import { useClipboard } from '@vueuse/core'
33

4-
export function useCopy(content: MaybeRefOrGetter<HTMLElement | string | null | undefined>) {
4+
type CopySource = HTMLElement | string | null | undefined
5+
6+
export function useCopy(content?: MaybeRefOrGetter<CopySource>) {
57
const { copy } = useClipboard()
68
const { show } = useToast()
79

8-
return () => {
10+
return (source?: CopySource) => {
911
try {
10-
const value = toValue(content)
12+
const value = toValue(source ?? content)
1113
copy(typeof value === 'string' ? value : value?.dataset?.copy || value?.textContent || '')
1214
show('Copied to clipboard')
1315
} catch (e) {

entrypoints/ui/prism.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { evaluate } from '@/utils'
22
import waitFor from 'p-wait-for'
33

4-
const EXTRA_LANGS = ['sass', 'scss', 'less', 'stylus'] as const
4+
const EXTRA_LANGS = ['sass', 'scss', 'less', 'stylus', 'css-extras'] as const
55

66
// We are importing this in this way is because if we use
77
// `import('prismjs/components/prism-sass')` Rollup will not resolve it correctly

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "tempad-dev",
33
"description": "Inspect panel on Figma, for everyone.",
44
"private": true,
5-
"version": "0.9.0",
5+
"version": "0.10.0",
66
"type": "module",
77
"scripts": {
88
"dev": "wxt",

utils/dom.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export function transformHTML(html: string, transform: (frag: DocumentFragment) => void): string {
2+
const template = document.createElement('template')
3+
template.innerHTML = html
4+
5+
transform(template.content)
6+
7+
return template.innerHTML
8+
}

0 commit comments

Comments
 (0)