[Archived] Archived WIP of vielle.dev
at master 3.4 kB view raw
1--- 2import Copy from "@/assets/copy.svg"; 3 4interface Props { 5 colours: { text: string; border: string }; 6} 7 8const { colours } = Astro.props; 9--- 10 11<template id="code-heading"> 12 <span class="lang"><slot is:inline>.txt</slot></span> 13 <span id="copied" style="visibility:hidden" role="alert">Copied!</span> 14 <button id="copy"><Copy /></button> 15 16 <!-- define:vars didnt work :( --> 17 <style 18 set:html={` 19 :host { 20 --text: ${colours.text}; 21 --border: ${colours.border}; 22 } 23 `} 24 ></style> 25 26 <style> 27 @keyframes teeter { 28 from, 29 to { 30 rotate: 0deg; 31 } 32 25% { 33 rotate: 15deg; 34 } 35 75% { 36 rotate: -15deg; 37 } 38 } 39 40 .lang { 41 color: var(--text); 42 } 43 44 button { 45 border: none; 46 background: none; 47 aspect-ratio: 1; 48 border-radius: 100%; 49 50 display: flex; 51 align-items: center; 52 justify-content: center; 53 54 &:hover, 55 &:focus { 56 scale: 1.2; 57 outline: none; 58 background-color: #ffffff20; 59 } 60 61 &:active { 62 scale: 1.4; 63 animation: teeter 0.2s; 64 } 65 66 & svg { 67 stroke: var(--text); 68 margin: 2px; 69 } 70 } 71 72 :host { 73 display: flex block; 74 justify-content: space-between; 75 align-items: center; 76 /* gets overridden by * because why not ig */ 77 padding: 5px 15px !important; 78 position: sticky; 79 top: 0; 80 left: 0; 81 border-bottom: 4px solid var(--border); 82 user-select: none; 83 } 84 </style> 85</template> 86 87<script> 88 class CodeHeading extends HTMLElement { 89 contents = ""; 90 static observedAttributes = ["contents"]; 91 92 template: HTMLTemplateElement; 93 content: DocumentFragment; 94 shadowRoot: ShadowRoot; 95 96 constructor() { 97 super(); 98 const template = document.getElementById("code-heading"); 99 if (!template || !(template instanceof HTMLTemplateElement)) 100 throw new Error("Could not get #code-heading"); 101 this.template = template; 102 this.content = template.content; 103 104 this.shadowRoot = this.attachShadow({ mode: "open" }); 105 this.shadowRoot.appendChild(this.content.cloneNode(true)); 106 107 const copy = this.shadowRoot.getElementById("copy"); 108 if (!copy) throw new Error("No #copy in #code-heading"); 109 110 const copied = this.shadowRoot.getElementById("copied"); 111 if (!copied) throw new Error("No #copied in #code-heading"); 112 113 const copied_animation = { 114 opacity: [0, 1], 115 visibility: ["hidden", "visible"], 116 }; 117 118 copy.addEventListener("click", () => { 119 navigator.clipboard 120 .writeText(this.contents) 121 .catch((e) => { 122 console.error("Encountered error copying to clipboard;", e); 123 }) 124 .then(async () => { 125 await copied.animate(copied_animation, { 126 duration: 200, 127 fill: "forwards", 128 }).finished; 129 130 copied.animate(copied_animation, { 131 duration: 200, 132 delay: 2000, 133 fill: "forwards", 134 direction: "reverse", 135 }); 136 }); 137 }); 138 } 139 140 attributeChangedCallback(name: string, _: any, newV?: string) { 141 if (name == "contents") { 142 this.contents = newV ?? ""; 143 } 144 } 145 } 146 147 customElements.define("code-heading", CodeHeading); 148</script>