Skip to content

Commit

Permalink
fix: preload images to prevent content jumping and visuals in strange…
Browse files Browse the repository at this point in the history
… spots
  • Loading branch information
cecilia-sanare committed Sep 1, 2024
1 parent ac8a046 commit 31ef2be
Show file tree
Hide file tree
Showing 9 changed files with 49 additions and 10 deletions.
2 changes: 1 addition & 1 deletion src/components/Pill.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AppSettingStatus } from '@/service/protontweaks';
import { AppSettingStatus } from '@/service/protontweaks.service';
import { cn } from '@/utils/cn';
import type { FC, ReactNode } from 'react';

Expand Down
2 changes: 1 addition & 1 deletion src/pages/apps/AppPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Label } from '../../components/Label';
import { Pill, appSettingStatustoVariant } from '../../components/Pill';
import { Card } from '../../components/Card';
import { Code } from '../../components/Code';
import { getApp, getAppSettingStatus, toLaunchOptions } from '@/service/protontweaks';
import { getApp, getAppSettingStatus, toLaunchOptions } from '@/service/protontweaks.service';
import type { App } from '@/types';
import { Button } from '@/components/Button';
import { ButtonGroup } from '@/components/ButtonGroup';
Expand Down
10 changes: 8 additions & 2 deletions src/pages/apps/SearchPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { Button } from '@/components/Button';
import { ButtonGroup } from '@/components/ButtonGroup';
import type { App } from '@/types';
import { PageSpinner } from '@/components/PageSpinner';
import { SearchService } from '@/service/search';
import { SearchService } from '@/service/search.service';
import { ImageService } from '@/service/image.service';

export const Component: FC = () => {
const search = useSearch();
Expand All @@ -16,7 +17,12 @@ export const Component: FC = () => {
setLoading(true);

SearchService.query(search)
.then((apps) => setFilteredApps(apps))
.then(async (apps) => {
// Preload the images to prevent content from jumping
await ImageService.preload(...apps.map((app) => app.image_url));

setFilteredApps(apps);
})
.catch(() => console.log('debounced...'))
.finally(() => {
setLoading(false);
Expand Down
24 changes: 24 additions & 0 deletions src/service/image.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export class ImageService {
static async preload(...srcs: string[]): Promise<void[]> {
return Promise.all(
srcs.map((src) => {
const image = new Image();

const promise = new Promise<void>((resolve, reject) => {
image.addEventListener('load', () => resolve(), {
once: true,
});

image.addEventListener('error', reject, {
once: true,
});
});

// Set the SRC here to prevent race conditions
image.src = src;

return promise;
})
);
}
}
File renamed without changes.
13 changes: 9 additions & 4 deletions src/service/search.ts → src/service/search.service.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { App } from '@/types';
import type { App, ComputedApp } from '@/types';
import SearchWorker from '@/workers/search.worker?worker';

let previousWorker: Worker;

export class SearchService {
static async query(value: string): Promise<App[]> {
static async query(value: string): Promise<ComputedApp[]> {
if (previousWorker) {
previousWorker.terminate();
}
Expand All @@ -14,8 +14,13 @@ export class SearchService {
return new Promise((resolve, reject) => {
previousWorker.addEventListener(
'message',
(event) => {
resolve(event.data);
(event: MessageEvent<App[]>) => {
resolve(
event.data.map((app) => ({
...app,
image_url: `https://steamcdn-a.akamaihd.net/steam/apps/${app.id}/header.jpg`,
}))
);
},
{
once: true,
Expand Down
4 changes: 4 additions & 0 deletions src/types/apps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@ export type App = {
created_at: string;
updated_at: string;
};

export type ComputedApp = App & {
image_url: string;
};
2 changes: 1 addition & 1 deletion src/workers/search.worker.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getApps } from '@/service/protontweaks';
import { getApps } from '@/service/protontweaks.service';
import { delay } from '@ribbon-studios/js-utils';

self.onmessage = async (event) => {
Expand Down
2 changes: 1 addition & 1 deletion vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Sitemap from 'vite-plugin-sitemap';
import { viteStaticCopy } from 'vite-plugin-static-copy';
import path from 'path';
import { defineConfig } from 'vitest/config';
import { getAppRoutes } from './src/service/protontweaks';
import { getAppRoutes } from './src/service/protontweaks.service';

// https://vitejs.dev/config/
export default defineConfig(async () => {
Expand Down

0 comments on commit 31ef2be

Please sign in to comment.