Skip to content

Commit bdb832a

Browse files
Vilsolmircearoata
andauthored
feat: thumbhash (#177)
* feat: thumbhash * fix: add some delay to fade * fix: only render thumbnail once loaded * fix: add thumbhash default * fix: ultra smooth * fix: thumbnail logo transition on chrome * fix: display thumbnail when changing mod list page * fix: restore thumbnail load event --------- Co-authored-by: Mircea Roata <mircearoatapalade@gmail.com>
1 parent c929f35 commit bdb832a

File tree

6 files changed

+66
-4
lines changed

6 files changed

+66
-4
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ $RECYCLE.BIN/
302302
/functions
303303
/.graphqlconfig
304304
/schema.graphql
305-
/graphql.schema.json
305+
/graphql.schema.*
306306
/.svelte-kit
307307
/.pnpm-store
308308
.direnv

bun.lockb

344 Bytes
Binary file not shown.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
"semver": "^7.6.3",
4848
"socket.io-client": "^4.7.5",
4949
"tslib": "^2.6.3",
50+
"thumbhash": "^0.1.1",
5051
"wonka": "^6.3.4",
5152
"zod": "^3.23.8"
5253
},

src/gql/home/mods.graphql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ query GetMods($offset: Int!, $limit: Int!, $search: String, $order: Order, $orde
88
mod_reference
99
name
1010
logo
11+
logo_thumbhash
1112
views
1213
downloads
1314
short_description

src/lib/components/general/FicsitCard.svelte

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,33 @@
11
<script lang="ts">
22
import { assets } from '$app/paths';
33
import { goto, preloadData } from '$app/navigation';
4+
import { thumbHashToDataURL } from 'thumbhash';
5+
import { fade } from 'svelte/transition';
46
57
export let name = '';
68
export let logo = assets + '/images/no_image.webp';
79
export let description = '';
810
export let link = '/';
911
export let fake = false;
12+
export let thumbhash = '';
1013
1114
$: renderedLogo = logo || assets + '/images/no_image.webp';
1215
$: renderedName = name || (fake && 'Card Name');
1316
$: renderedDescription = description || (fake && 'Short card description');
17+
$: renderedThumbhash = thumbhash || '2/eFDQIsFmh9h4BreKeAeQqYBxd3d3J4Jw';
18+
$: thumbHashData = (() => {
19+
try {
20+
return thumbHashToDataURL(
21+
new Uint8Array(
22+
atob(renderedThumbhash)
23+
.split('')
24+
.map((x) => x.charCodeAt(0))
25+
)
26+
);
27+
} catch (e) {
28+
console.error(e);
29+
}
30+
})();
1431
1532
let preloaded = false;
1633
let timeoutHandle: number;
@@ -34,6 +51,19 @@
3451
};
3552
3653
let actionButtons: HTMLElement;
54+
55+
let imageLoaded = false;
56+
let thumbnailLoaded = false;
57+
58+
$: {
59+
renderedLogo;
60+
imageLoaded = false;
61+
}
62+
63+
$: {
64+
renderedThumbhash;
65+
thumbnailLoaded = false;
66+
}
3767
</script>
3868

3969
<div
@@ -48,11 +78,31 @@
4878
class:font-flow={fake}
4979
class="grid-max-auto grid grid-cols-1 justify-items-center sm:grid-cols-2">
5080
<div class="card-image-container cursor-pointer">
51-
<a href={link} on:keypress={() => goto(link)} tabindex="0">
81+
<a
82+
href={link}
83+
on:keypress={() => goto(link)}
84+
tabindex="0"
85+
class="relative block max-h-full min-h-full min-w-full max-w-full">
5286
{#if fake}
5387
<div class="logo max-h-full min-h-full min-w-full max-w-full bg-neutral-500" />
5488
{:else}
55-
<img src={renderedLogo} alt="{renderedName} Logo" class="logo max-h-full min-h-full min-w-full max-w-full" />
89+
<img
90+
class="logo absolute max-h-full min-h-full min-w-full max-w-full transition-opacity delay-100 duration-200 ease-linear"
91+
class:invisible={!imageLoaded}
92+
class:opacity-0={!imageLoaded}
93+
src={renderedLogo}
94+
alt="{renderedName} Logo"
95+
on:load={() => (imageLoaded = true)} />
96+
{#if !imageLoaded && thumbHashData}
97+
<img
98+
class="logo absolute max-h-full min-h-full min-w-full max-w-full"
99+
class:invisible={!thumbnailLoaded}
100+
src={thumbHashData}
101+
alt="{renderedName} Logo"
102+
on:load={() => (thumbnailLoaded = true)}
103+
in:fade={{ duration: 200 }}
104+
out:fade={{ duration: 200, delay: 100 }} />
105+
{/if}
56106
{/if}
57107
</a>
58108
</div>

src/lib/components/mods/ModCard.svelte

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,16 @@
1010
1111
export let mod: Pick<
1212
Mod,
13-
'id' | 'mod_reference' | 'name' | 'logo' | 'views' | 'downloads' | 'short_description' | 'compatibility' | 'tags'
13+
| 'id'
14+
| 'mod_reference'
15+
| 'name'
16+
| 'logo'
17+
| 'views'
18+
| 'downloads'
19+
| 'short_description'
20+
| 'compatibility'
21+
| 'tags'
22+
| 'logo_thumbhash'
1423
> & {
1524
latestVersions: {
1625
alpha?: Maybe<Pick<Version, 'id'>>;
@@ -27,6 +36,7 @@
2736
name={mod.name}
2837
link={base + '/mod/' + mod.mod_reference}
2938
logo={mod.logo}
39+
thumbhash={mod.logo_thumbhash}
3040
description={mod.short_description}>
3141
<div slot="stats" class="flex flex-row items-center gap-2">
3242
<span><span class="material-icons mr-1 align-middle text-sm">visibility</span>{prettyNumber(mod.views)}</span>

0 commit comments

Comments
 (0)