fix: make it work with new vite
12
static/.gitignore
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
data/
|
||||
data-dev/
|
||||
_fresh/
|
||||
node_modules/
|
||||
mise.toml
|
||||
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 27 KiB |
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square150x150logo src="/mstile-150x150.png" />
|
||||
<TileColor>#da532c</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 15 KiB |
@@ -39,12 +39,7 @@ body {
|
||||
font-family: "Work Sans", monospace;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: "Work Sans", monospace;
|
||||
}
|
||||
|
||||
a {
|
||||
color: cadetblue;
|
||||
a, pre {
|
||||
font-family: "Work Sans", monospace;
|
||||
}
|
||||
|
||||
@@ -53,7 +48,6 @@ a {
|
||||
}
|
||||
|
||||
@keyframes hover {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
transform: translateY(-15%);
|
||||
@@ -98,11 +92,11 @@ a {
|
||||
fill: #dcdbdc;
|
||||
}
|
||||
|
||||
.items-52>* {
|
||||
.items-52 > * {
|
||||
height: 52px;
|
||||
}
|
||||
|
||||
.highlight>pre {
|
||||
.highlight > pre {
|
||||
text-wrap: wrap;
|
||||
}
|
||||
|
||||
@@ -118,24 +112,24 @@ main.loading {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.markdown-body>h1 {
|
||||
.markdown-body > h1 {
|
||||
font-size: 2.25rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown-body>h2 {
|
||||
.markdown-body > h2 {
|
||||
font-size: 1.75rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown-body>h3 {
|
||||
.markdown-body > h3 {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown-body>h1>.anchor,
|
||||
.markdown-body>h2>.anchor,
|
||||
.markdown-body>h3>.anchor {
|
||||
.markdown-body > h1 > .anchor,
|
||||
.markdown-body > h2 > .anchor,
|
||||
.markdown-body > h3 > .anchor {
|
||||
display: inline-flex;
|
||||
margin-left: -26px;
|
||||
margin-right: 12px;
|
||||
@@ -143,9 +137,9 @@ main.loading {
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
.markdown-body>h1:hover .anchor,
|
||||
.markdown-body>h2:hover .anchor,
|
||||
.markdown-body>h3:hover .anchor {
|
||||
.markdown-body > h1:hover .anchor,
|
||||
.markdown-body > h2:hover .anchor,
|
||||
.markdown-body > h3:hover .anchor {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
<svg width="40" height="40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M34.092 8.845C38.929 20.652 34.092 27 30 30.5c1 3.5-2.986 4.222-4.5 2.5-4.457 1.537-13.512 1.487-20-5C2 24.5 4.73 16.714 14 11.5c8-4.5 16-7 20.092-2.655Z"
|
||||
fill="#FFDB1E"
|
||||
/>
|
||||
<path
|
||||
d="M14 11.5c6.848-4.497 15.025-6.38 18.368-3.47C37.5 12.5 21.5 22.612 15.5 25c-6.5 2.587-3 8.5-6.5 8.5-3 0-2.5-4-5.183-7.75C2.232 23.535 6.16 16.648 14 11.5Z"
|
||||
fill="#fff"
|
||||
stroke="#FFDB1E"
|
||||
/>
|
||||
<path
|
||||
d="M28.535 8.772c4.645 1.25-.365 5.695-4.303 8.536-3.732 2.692-6.606 4.21-7.923 4.83-.366.173-1.617-2.252-1.617-1 0 .417-.7 2.238-.934 2.326-1.365.512-4.223 1.29-5.835 1.29-3.491 0-1.923-4.754 3.014-9.122.892-.789 1.478-.645 2.283-.645-.537-.773-.534-.917.403-1.546C17.79 10.64 23 8.77 25.212 8.42c.366.014.82.35.82.629.41-.14 2.095-.388 2.503-.278Z"
|
||||
fill="#FFE600"
|
||||
/>
|
||||
<path
|
||||
d="M14.297 16.49c.985-.747 1.644-1.01 2.099-2.526.566.121.841-.08 1.29-.701.324.466 1.657.608 2.453.701-.715.451-1.057.852-1.452 2.106-1.464-.611-3.167-.302-4.39.42Z"
|
||||
fill="#fff"
|
||||
/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 14 KiB |
BIN
static/noise.png
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 185 KiB |
@@ -1,177 +0,0 @@
|
||||
/**
|
||||
* prism.js Twilight theme
|
||||
* Based (more or less) on the Twilight theme originally of Textmate fame.
|
||||
* @author Remy Bach
|
||||
*/
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
color: white;
|
||||
background: none;
|
||||
font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
|
||||
font-size: 1em;
|
||||
text-align: left;
|
||||
text-shadow: 0 -0.1em 0.2em black;
|
||||
white-space: pre;
|
||||
word-spacing: normal;
|
||||
word-break: normal;
|
||||
word-wrap: normal;
|
||||
line-height: 1.5;
|
||||
|
||||
-moz-tab-size: 4;
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
|
||||
-webkit-hyphens: none;
|
||||
-moz-hyphens: none;
|
||||
-ms-hyphens: none;
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
pre[class*="language-"],
|
||||
:not(pre) > code[class*="language-"] {
|
||||
background: hsl(0, 0%, 8%); /* #141414 */
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
pre[class*="language-"] {
|
||||
border-radius: 0.5em;
|
||||
border: 0.3em solid hsl(0, 0%, 33%); /* #282A2B */
|
||||
box-shadow: 1px 1px 0.5em black inset;
|
||||
margin: 0.5em 0;
|
||||
overflow: auto;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::-moz-selection {
|
||||
/* Firefox */
|
||||
background: hsl(200, 4%, 16%); /* #282A2B */
|
||||
}
|
||||
|
||||
pre[class*="language-"]::selection {
|
||||
/* Safari */
|
||||
background: hsl(200, 4%, 16%); /* #282A2B */
|
||||
}
|
||||
|
||||
/* Text Selection colour */
|
||||
pre[class*="language-"]::-moz-selection,
|
||||
pre[class*="language-"] ::-moz-selection,
|
||||
code[class*="language-"]::-moz-selection,
|
||||
code[class*="language-"] ::-moz-selection {
|
||||
text-shadow: none;
|
||||
background: hsla(0, 0%, 93%, 0.15); /* #EDEDED */
|
||||
}
|
||||
|
||||
pre[class*="language-"]::selection,
|
||||
pre[class*="language-"] ::selection,
|
||||
code[class*="language-"]::selection,
|
||||
code[class*="language-"] ::selection {
|
||||
text-shadow: none;
|
||||
background: hsla(0, 0%, 93%, 0.15); /* #EDEDED */
|
||||
}
|
||||
|
||||
/* Inline code */
|
||||
:not(pre) > code[class*="language-"] {
|
||||
border-radius: 0.3em;
|
||||
border: 0.13em solid hsl(0, 0%, 33%); /* #545454 */
|
||||
box-shadow: 1px 1px 0.3em -0.1em black inset;
|
||||
padding: 0.15em 0.2em 0.05em;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.token.comment,
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata {
|
||||
color: hsl(0, 0%, 47%); /* #777777 */
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.token.namespace {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.token.tag,
|
||||
.token.boolean,
|
||||
.token.number,
|
||||
.token.deleted {
|
||||
color: hsl(14, 58%, 55%); /* #CF6A4C */
|
||||
}
|
||||
|
||||
.token.keyword,
|
||||
.token.property,
|
||||
.token.selector,
|
||||
.token.constant,
|
||||
.token.symbol,
|
||||
.token.builtin {
|
||||
color: hsl(53, 89%, 79%); /* #F9EE98 */
|
||||
}
|
||||
|
||||
.token.attr-name,
|
||||
.token.attr-value,
|
||||
.token.string,
|
||||
.token.char,
|
||||
.token.operator,
|
||||
.token.entity,
|
||||
.token.url,
|
||||
.language-css .token.string,
|
||||
.style .token.string,
|
||||
.token.variable,
|
||||
.token.inserted {
|
||||
color: hsl(76, 21%, 52%); /* #8F9D6A */
|
||||
}
|
||||
|
||||
.token.atrule {
|
||||
color: hsl(218, 22%, 55%); /* #7587A6 */
|
||||
}
|
||||
|
||||
.token.regex,
|
||||
.token.important {
|
||||
color: hsl(42, 75%, 65%); /* #E9C062 */
|
||||
}
|
||||
|
||||
.token.important,
|
||||
.token.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
.token.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.token.entity {
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
/* Markup */
|
||||
.language-markup .token.tag,
|
||||
.language-markup .token.attr-name,
|
||||
.language-markup .token.punctuation {
|
||||
color: hsl(33, 33%, 52%); /* #AC885B */
|
||||
}
|
||||
|
||||
/* Make the tokens sit above the line highlight so the colours don't look faded. */
|
||||
.token {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.line-highlight.line-highlight {
|
||||
background: hsla(0, 0%, 33%, 0.25); /* #545454 */
|
||||
background: linear-gradient(
|
||||
to right,
|
||||
hsla(0, 0%, 33%, 0.1) 70%,
|
||||
hsla(0, 0%, 33%, 0)
|
||||
); /* #545454 */
|
||||
border-bottom: 1px dashed hsl(0, 0%, 33%); /* #545454 */
|
||||
border-top: 1px dashed hsl(0, 0%, 33%); /* #545454 */
|
||||
margin-top: 0.75em; /* Same as .prism’s padding-top */
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.line-highlight.line-highlight:before,
|
||||
.line-highlight.line-highlight[data-end]:after {
|
||||
background-color: hsl(215, 15%, 59%); /* #8794A6 */
|
||||
color: hsl(24, 20%, 95%); /* #F5F2F0 */
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg
|
||||
version="1.0"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="256.000000pt"
|
||||
height="256.000000pt"
|
||||
viewBox="0 0 256.000000 256.000000"
|
||||
preserveAspectRatio="xMidYMid meet"
|
||||
>
|
||||
<metadata
|
||||
>
|
||||
Created by potrace 1.14, written by Peter Selinger 2001-2017
|
||||
</metadata>
|
||||
<g
|
||||
transform="translate(0.000000,256.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000"
|
||||
stroke="none"
|
||||
>
|
||||
<path
|
||||
d="M1404 2075 c-16 -7 -75 -60 -131 -116 -55 -57 -130 -133 -166 -167
|
||||
l-64 -64 0 122 c0 91 -3 124 -13 130 -19 12 -192 12 -210 0 -11 -7 -15 -34
|
||||
-16 -117 -1 -59 -3 -110 -3 -113 -1 -3 -20 -11 -43 -17 -67 -18 -126 -76 -164
|
||||
-160 -33 -72 -34 -73 -108 -108 -41 -19 -87 -50 -102 -68 -64 -76 -82 -169
|
||||
-50 -264 20 -61 16 -81 -27 -130 -108 -123 -68 -323 81 -393 41 -20 65 -23
|
||||
182 -25 l135 -1 2 -127 3 -127 -58 0 c-140 -2 -358 -8 -373 -12 -51 -12 -109
|
||||
-80 -109 -128 l0 -25 1110 0 1110 0 0 24 c0 46 -40 99 -89 118 -25 10 -52 16
|
||||
-59 15 -9 -2 -12 10 -9 45 6 72 -17 145 -62 196 -13 16 -16 60 -16 318 0 164
|
||||
3 299 6 299 3 0 18 -13 34 -30 39 -41 75 -52 113 -33 36 18 53 57 40 93 -5 14
|
||||
-82 96 -171 183 -89 87 -282 277 -429 423 -146 145 -270 264 -275 265 -4 0
|
||||
-15 2 -24 4 -8 1 -29 -3 -45 -10z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB |
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"name": "",
|
||||
"short_name": "",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/android-chrome-256x256.png",
|
||||
"sizes": "256x256",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#141218",
|
||||
"display": "standalone"
|
||||
}
|
||||
|
Before Width: | Height: | Size: 394 KiB |
|
Before Width: | Height: | Size: 407 KiB |
|
Before Width: | Height: | Size: 390 KiB |
@@ -1,271 +0,0 @@
|
||||
// deno-lint-ignore-file
|
||||
function thumbHashToApproximateAspectRatio(hash) {
|
||||
let header = hash[3];
|
||||
let hasAlpha = hash[2] & 0x80;
|
||||
let isLandscape = hash[4] & 0x80;
|
||||
let lx = isLandscape ? hasAlpha ? 5 : 7 : header & 7;
|
||||
let ly = isLandscape ? header & 7 : hasAlpha ? 5 : 7;
|
||||
return lx / ly;
|
||||
}
|
||||
|
||||
function thumbHashToRGBA(hash) {
|
||||
let { PI, min, max, cos, round } = Math;
|
||||
|
||||
// Read the constants
|
||||
let header24 = hash[0] | (hash[1] << 8) | (hash[2] << 16);
|
||||
let header16 = hash[3] | (hash[4] << 8);
|
||||
let l_dc = (header24 & 63) / 63;
|
||||
let p_dc = ((header24 >> 6) & 63) / 31.5 - 1;
|
||||
let q_dc = ((header24 >> 12) & 63) / 31.5 - 1;
|
||||
let l_scale = ((header24 >> 18) & 31) / 31;
|
||||
let hasAlpha = header24 >> 23;
|
||||
let p_scale = ((header16 >> 3) & 63) / 63;
|
||||
let q_scale = ((header16 >> 9) & 63) / 63;
|
||||
let isLandscape = header16 >> 15;
|
||||
let lx = max(3, isLandscape ? hasAlpha ? 5 : 7 : header16 & 7);
|
||||
let ly = max(3, isLandscape ? header16 & 7 : hasAlpha ? 5 : 7);
|
||||
let a_dc = hasAlpha ? (hash[5] & 15) / 15 : 1;
|
||||
let a_scale = (hash[5] >> 4) / 15;
|
||||
|
||||
// Read the varying factors (boost saturation by 1.25x to compensate for quantization)
|
||||
let ac_start = hasAlpha ? 6 : 5;
|
||||
let ac_index = 0;
|
||||
let decodeChannel = (nx, ny, scale) => {
|
||||
let ac = [];
|
||||
for (let cy = 0; cy < ny; cy++) {
|
||||
for (let cx = cy ? 0 : 1; cx * ny < nx * (ny - cy); cx++) {
|
||||
ac.push(
|
||||
(((hash[ac_start + (ac_index >> 1)] >> ((ac_index++ & 1) << 2)) &
|
||||
15) / 7.5 - 1) * scale,
|
||||
);
|
||||
}
|
||||
}
|
||||
return ac;
|
||||
};
|
||||
const l_ac = decodeChannel(lx, ly, l_scale);
|
||||
const p_ac = decodeChannel(3, 3, p_scale * 1.25);
|
||||
const q_ac = decodeChannel(3, 3, q_scale * 1.25);
|
||||
const a_ac = hasAlpha && decodeChannel(5, 5, a_scale);
|
||||
|
||||
// Decode using the DCT into RGB
|
||||
const ratio = thumbHashToApproximateAspectRatio(hash);
|
||||
const w = round(ratio > 1 ? 32 : 32 * ratio);
|
||||
const h = round(ratio > 1 ? 32 / ratio : 32);
|
||||
const rgba = new Uint8Array(w * h * 4), fx = [], fy = [];
|
||||
for (let y = 0, i = 0; y < h; y++) {
|
||||
for (let x = 0; x < w; x++, i += 4) {
|
||||
let l = l_dc, p = p_dc, q = q_dc, a = a_dc;
|
||||
|
||||
// Precompute the coefficients
|
||||
for (let cx = 0, n = max(lx, hasAlpha ? 5 : 3); cx < n; cx++) {
|
||||
fx[cx] = cos(PI / w * (x + 0.5) * cx);
|
||||
}
|
||||
for (let cy = 0, n = max(ly, hasAlpha ? 5 : 3); cy < n; cy++) {
|
||||
fy[cy] = cos(PI / h * (y + 0.5) * cy);
|
||||
}
|
||||
|
||||
// Decode L
|
||||
for (let cy = 0, j = 0; cy < ly; cy++) {
|
||||
for (
|
||||
let cx = cy ? 0 : 1, fy2 = fy[cy] * 2;
|
||||
cx * ly < lx * (ly - cy);
|
||||
cx++, j++
|
||||
) {
|
||||
l += l_ac[j] * fx[cx] * fy2;
|
||||
}
|
||||
}
|
||||
|
||||
// Decode P and Q
|
||||
for (let cy = 0, j = 0; cy < 3; cy++) {
|
||||
for (let cx = cy ? 0 : 1, fy2 = fy[cy] * 2; cx < 3 - cy; cx++, j++) {
|
||||
const f = fx[cx] * fy2;
|
||||
p += p_ac[j] * f;
|
||||
q += q_ac[j] * f;
|
||||
}
|
||||
}
|
||||
|
||||
// Decode A
|
||||
if (hasAlpha) {
|
||||
for (let cy = 0, j = 0; cy < 5; cy++) {
|
||||
for (let cx = cy ? 0 : 1, fy2 = fy[cy] * 2; cx < 5 - cy; cx++, j++) {
|
||||
a += a_ac[j] * fx[cx] * fy2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert to RGB
|
||||
const b = l - 2 / 3 * p;
|
||||
const r = (3 * l - b + q) / 2;
|
||||
const g = r - q;
|
||||
rgba[i] = max(0, 255 * min(1, r));
|
||||
rgba[i + 1] = max(0, 255 * min(1, g));
|
||||
rgba[i + 2] = max(0, 255 * min(1, b));
|
||||
rgba[i + 3] = max(0, 255 * min(1, a));
|
||||
}
|
||||
}
|
||||
return { w, h, rgba };
|
||||
}
|
||||
|
||||
function rgbaToDataURL(w, h, rgba) {
|
||||
const row = w * 4 + 1;
|
||||
const idat = 6 + h * (5 + row);
|
||||
const bytes = [
|
||||
137,
|
||||
80,
|
||||
78,
|
||||
71,
|
||||
13,
|
||||
10,
|
||||
26,
|
||||
10,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
13,
|
||||
73,
|
||||
72,
|
||||
68,
|
||||
82,
|
||||
0,
|
||||
0,
|
||||
w >> 8,
|
||||
w & 255,
|
||||
0,
|
||||
0,
|
||||
h >> 8,
|
||||
h & 255,
|
||||
8,
|
||||
6,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
idat >>> 24,
|
||||
(idat >> 16) & 255,
|
||||
(idat >> 8) & 255,
|
||||
idat & 255,
|
||||
73,
|
||||
68,
|
||||
65,
|
||||
84,
|
||||
120,
|
||||
1,
|
||||
];
|
||||
const table = [
|
||||
0,
|
||||
498536548,
|
||||
997073096,
|
||||
651767980,
|
||||
1994146192,
|
||||
1802195444,
|
||||
1303535960,
|
||||
1342533948,
|
||||
-306674912,
|
||||
-267414716,
|
||||
-690576408,
|
||||
-882789492,
|
||||
-1687895376,
|
||||
-2032938284,
|
||||
-1609899400,
|
||||
-1111625188,
|
||||
];
|
||||
let a = 1, b = 0;
|
||||
for (let y = 0, i = 0, end = row - 1; y < h; y++, end += row - 1) {
|
||||
bytes.push(
|
||||
y + 1 < h ? 0 : 1,
|
||||
row & 255,
|
||||
row >> 8,
|
||||
~row & 255,
|
||||
(row >> 8) ^ 255,
|
||||
0,
|
||||
);
|
||||
for (b = (b + a) % 65521; i < end; i++) {
|
||||
let u = rgba[i] & 255;
|
||||
bytes.push(u);
|
||||
a = (a + u) % 65521;
|
||||
b = (b + a) % 65521;
|
||||
}
|
||||
}
|
||||
bytes.push(
|
||||
b >> 8,
|
||||
b & 255,
|
||||
a >> 8,
|
||||
a & 255,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
73,
|
||||
69,
|
||||
78,
|
||||
68,
|
||||
174,
|
||||
66,
|
||||
96,
|
||||
130,
|
||||
);
|
||||
for (let [start, end] of [[12, 29], [37, 41 + idat]]) {
|
||||
let c = ~0;
|
||||
for (let i = start; i < end; i++) {
|
||||
c ^= bytes[i];
|
||||
c = (c >>> 4) ^ table[c & 15];
|
||||
c = (c >>> 4) ^ table[c & 15];
|
||||
}
|
||||
c = ~c;
|
||||
bytes[end++] = c >>> 24;
|
||||
bytes[end++] = (c >> 16) & 255;
|
||||
bytes[end++] = (c >> 8) & 255;
|
||||
bytes[end++] = c & 255;
|
||||
}
|
||||
return "data:image/png;base64," + btoa(String.fromCharCode(...bytes));
|
||||
}
|
||||
|
||||
function updateThumbhashImages() {
|
||||
document.querySelectorAll("[data-thumb]").forEach((entry) => {
|
||||
const hash = entry.getAttribute("data-thumb");
|
||||
if (entry.getAttribute("data-thumb-decoded")) return;
|
||||
if (!hash) return;
|
||||
entry.setAttribute("data-thumb-decoded", true);
|
||||
|
||||
const decodedString = atob(hash);
|
||||
|
||||
// Create Uint8Array from decoded string
|
||||
const buffer = new Uint8Array(decodedString.length);
|
||||
for (let i = 0; i < decodedString.length; i++) {
|
||||
buffer[i] = decodedString.charCodeAt(i);
|
||||
}
|
||||
|
||||
const image = thumbHashToRGBA(buffer);
|
||||
const dataURL = rgbaToDataURL(image.w, image.h, image.rgba);
|
||||
|
||||
entry.style.background = `url(${dataURL})`;
|
||||
entry.style.backgroundSize = "cover";
|
||||
|
||||
const child = entry.querySelector("img[data-thumb-img]");
|
||||
setTimeout(() => {
|
||||
const isLoaded = child && child.complete && child.naturalHeight !== 0;
|
||||
if (child && !isLoaded) {
|
||||
child.style.opacity = 0;
|
||||
child.style.filter = "blur(5px)";
|
||||
child.addEventListener("load", () => {
|
||||
child.style.transition = "opacity 0.3s ease, filter 0.6s ease";
|
||||
child.style.opacity = 1;
|
||||
child.style.filter = "blur(0px)";
|
||||
setTimeout(() => {
|
||||
//entry.style.background = "";
|
||||
}, 400);
|
||||
});
|
||||
}
|
||||
}, 50);
|
||||
});
|
||||
}
|
||||
|
||||
globalThis.addEventListener("load", updateThumbhashImages);
|
||||
globalThis.addEventListener("loading-finished", updateThumbhashImages);
|
||||