[Archived] Archived WIP of vielle.dev
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>