[Archived] Archived WIP of vielle.dev
at master 227 lines 5.2 kB view raw
1--- 2import type { InferEntrySchema } from "astro:content"; 3import { Image } from "astro:assets"; 4 5import { blog, utils } from "@/config"; 6import Balloon from "./Balloon.astro"; 7 8interface Props { 9 id: string; 10 data: InferEntrySchema<"blog">; 11 layer: number; 12} 13 14const { id, data, layer } = Astro.props; 15 16const image = await (async () => { 17 if (!data.image) return; 18 const img = data.image.match(/.*(?=\.png)/gm); 19 if (img === null) return; 20 return await import(`../../content/posts/assets/${img[0]}.png`).then( 21 (x) => x.default, 22 ); 23})(); 24 25const date = (() => { 26 const year = data.date.getFullYear() + ""; 27 const month = data.date.getMonth() + 1 + ""; 28 const date = data.date.getDate() + ""; 29 30 return { 31 year: "0".repeat(4 - year.length) + year, 32 month: "0".repeat(2 - month.length) + month, 33 date: "0".repeat(2 - date.length) + date, 34 }; 35})(); 36 37const positions: [number, number] = [Math.random(), Math.random()]; 38const offsets: [number, number][] = [ 39 [0, 0], 40 [ 41 Math.random() * blog.post.drift[0] - blog.post.drift[0] / 2, 42 Math.random() * 0.5 * blog.post.drift[1] - blog.post.drift[1] / 2, 43 ], 44 [ 45 Math.random() * blog.post.drift[0] - blog.post.drift[0] / 2, 46 Math.random() * 0.5 * blog.post.drift[1] - blog.post.drift[1] / 2, 47 ], 48 [ 49 Math.random() * blog.post.drift[0] - blog.post.drift[0] / 2, 50 Math.random() * 0.5 * blog.post.drift[1] - blog.post.drift[1] / 2, 51 ], 52]; 53--- 54 55<section 56 style={`--colour: ${data.colour}; 57 --layer: ${layer}; 58 59 /* generated */ 60 61 ${offsets 62 .map( 63 (x, i) => 64 `--x-offset-${i}: calc((100svw - ${blog.post.width + 2 * blog.post.xPadding}px) * ${positions[0] + x[0]} + ${blog.post.xPadding}px); 65 --y-offset-${i}: ${blog.post.yLeeway * 2 * (positions[1] + x[1]) - blog.post.yLeeway}px;`, 66 ) 67 .join("\n")} 68 69 --timing: ${ 70 blog.post.timing[0] + 71 Math.random() * (blog.post.timing[1] - blog.post.timing[0]) 72 }s; 73 74 /* config */ 75 76 --width: ${blog.post.width}px; 77 --y-gap: ${blog.post.yGap}px; 78 `} 79> 80 { 81 // new Array(Math.floor(utils.getRandom(blog.balloons.numBalloons))) 82 // .fill(0) 83 // .map((_, i) => <Balloon id={i} of={this?.length} />) 84 85 (() => { 86 const len = Math.round(utils.getRandom(blog.balloons.numBalloons)); 87 const arr = new Array(len).fill(0); 88 return arr.map((_, i) => <Balloon id={i} of={len} />); 89 })() 90 } 91 <Image src={image} alt="" /> 92 <div> 93 <a href={`/blog/${id}/`}>({id}) {data.title}</a> 94 <br /> 95 <time datetime={`${date.year}-${date.month}-${date.date}`} 96 >{date.date}-{date.month}-{date.year}</time 97 > 98 </div> 99</section> 100 101<style> 102 @property --x-offset-0 { 103 syntax: "<length>"; 104 inherits: false; 105 initial-value: 0px; 106 } 107 108 @property --x-offset-1 { 109 syntax: "<length>"; 110 inherits: false; 111 initial-value: 0px; 112 } 113 114 @property --x-offset-2 { 115 syntax: "<length>"; 116 inherits: false; 117 initial-value: 0px; 118 } 119 120 @property --x-offset-3 { 121 syntax: "<length>"; 122 inherits: false; 123 initial-value: 0px; 124 } 125 126 @property --y-offset-0 { 127 syntax: "<length>"; 128 inherits: false; 129 initial-value: 0px; 130 } 131 132 @property --y-offset-1 { 133 syntax: "<length>"; 134 inherits: false; 135 initial-value: 0px; 136 } 137 138 @property --y-offset-2 { 139 syntax: "<length>"; 140 inherits: false; 141 initial-value: 0px; 142 } 143 144 @property --y-offset-3 { 145 syntax: "<length>"; 146 inherits: false; 147 initial-value: 0px; 148 } 149 150 @keyframes bob { 151 0%, 152 100% { 153 top: var(--y-offset-0); 154 left: var(--x-offset-0); 155 } 156 157 25% { 158 top: var(--y-offset-1); 159 left: var(--x-offset-1); 160 } 161 162 50% { 163 top: var(--y-offset-2); 164 left: var(--x-offset-2); 165 } 166 167 75% { 168 top: var(--y-offset-3); 169 left: var(--x-offset-3); 170 } 171 } 172 173 section { 174 width: var(--width); 175 padding: 10px; 176 margin-bottom: var(--y-gap); 177 178 position: relative; 179 z-index: var(--layer); 180 181 /* ::before used so that <Balloon /> can render behind 182 (new stacking context for root, so cant 183 render behind the white unless a before) */ 184 &::before { 185 content: "" / ""; 186 display: block; 187 position: absolute; 188 top: -5px; 189 left: -5px; 190 z-index: -2; 191 192 width: calc(var(--width) + 10px); 193 height: calc(100% + 10px); 194 195 background-color: white; 196 border: 5px solid var(--colour, dodgerblue); 197 border-radius: 25px; 198 199 box-shadow: 0 0 75px var(--box-shadow-colour, #00000080); 200 } 201 202 /* default, overridden by reduced motion */ 203 top: var(--x-offset-0); 204 left: var(--y-offset-0); 205 206 @media (prefers-reduced-motion: no-preference) { 207 animation: infinite var(--timing) bob; 208 } 209 210 &:has(a:focus) { 211 animation-play-state: paused; 212 --box-shadow-colour: var(--colour); 213 & a:focus { 214 text-decoration: none; 215 outline: none; 216 } 217 } 218 219 & > img { 220 border-radius: 15px; 221 222 width: 300px; 223 height: 200px; 224 object-fit: cover; 225 } 226 } 227</style>