From f3d7c7abf27ad14f5dcf30d47af42596efd6e7b8 Mon Sep 17 00:00:00 2001 From: Sheldon Lee Date: Fri, 24 Nov 2023 19:24:40 +0800 Subject: [PATCH] Implement basic placeholder skeleton when loading --- src/App.css | 9 ++++++ src/App.tsx | 1 - src/Gallery/index.tsx | 61 +++++++++++++++++++++++++++++------- src/Gallery/placeholder.png | Bin 0 -> 8405 bytes 4 files changed, 59 insertions(+), 12 deletions(-) create mode 100644 src/Gallery/placeholder.png diff --git a/src/App.css b/src/App.css index 7d3d4e8..a60bc9b 100644 --- a/src/App.css +++ b/src/App.css @@ -63,7 +63,16 @@ body { background-color: #0056b3; } +.PlaceholderItem > button, .ParentDirectoryItem > button { background-color: #4D4F5D; } +.PlaceholderItem > a { + height: 1em; +} + +.PlaceholderItem > button { + height: calc(16px + 10px * 2); + width: 6em; +} diff --git a/src/App.tsx b/src/App.tsx index d1fd70a..f2c6c4e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import './App.css'; import Gallery from './Gallery/index'; diff --git a/src/Gallery/index.tsx b/src/Gallery/index.tsx index 8366394..78c71b3 100644 --- a/src/Gallery/index.tsx +++ b/src/Gallery/index.tsx @@ -1,5 +1,6 @@ import React from 'react'; import '../App.css'; +import placeholderPng from './placeholder.png'; import { useState, useEffect } from 'react'; function Gallery() { @@ -13,7 +14,7 @@ function Gallery() { }, [category]); const updateCategory = (category: string) => { - setData([]); + setData(getPlaceholderData); setCategory(category); }; @@ -33,6 +34,8 @@ interface galleryItemInfo { is_dir: boolean; url: string; thumbnail_url: string; + + isPlaceholder: boolean; } function Contents( @@ -61,6 +64,7 @@ function Contents( thumbnail_url: item.thumbnail_url === null ? item.url : item.thumbnail_url, onClick: () => {}, + isPlaceholder: item.isPlaceholder, }; if (item.is_dir) { @@ -87,11 +91,13 @@ interface galleryItem { url: string; thumbnail_url: string; onClick: () => void; + isPlaceholder: boolean; } -function ImageItem({ thumbnail_url, url }: galleryItem) { +function ImageItem({ thumbnail_url, url, isPlaceholder }: galleryItem) { + const placeholderClass = isPlaceholder ? 'PlaceholderItem' : ''; return ( -
+
{getFileName(url)} @@ -113,16 +119,15 @@ function VideoItem({ url }: galleryItem) { ); } -function DirectoryItem({ url, onClick }: galleryItem) { +function DirectoryItem({ url, onClick, isPlaceholder }: galleryItem) { let buttonText = getFileName(url); const isBackButton = buttonText === '..'; - buttonText = isBackButton ? 'Back' : `Category: ${buttonText}`; + const placeholderClass = isPlaceholder ? 'PlaceholderItem' : ''; + buttonText = isBackButton ? 'Back' : `${buttonText}`; const backButtonClass = isBackButton ? 'ParentDirectoryItem' : ''; return ( -
- +
+
); } @@ -131,14 +136,40 @@ function getFileName(string: string): string { return string.split('/').at(-1) as unknown as string; } +function getPlaceholderData(): galleryItemInfo[] { + const placeholderDir = (): galleryItemInfo => { + return { + is_dir: true, + url: '', + thumbnail_url: '', + isPlaceholder: true, + }; + }; + const placeholderImg = (): galleryItemInfo => { + return { + is_dir: false, + url: '', + thumbnail_url: `${placeholderPng}`, + isPlaceholder: true, + }; + }; + + return [ + placeholderDir(), + placeholderDir(), + placeholderImg(), + placeholderImg(), + placeholderImg(), + ]; +} async function post( category: string, setDataCallback: (data: galleryItemInfo[]) => void ) { try { const response = await fetch( - 'http://localhost/photo-viewer-backend/php/get.php', - //'https://dundun.ddns.net/photo-viewer/photo-viewer-backend/php/get.php', + //'http://localhost/photo-viewer-backend/php/get.php', + 'https://dundun.ddns.net/photo-viewer/photo-viewer-backend/php/get.php', { method: 'POST', headers: { @@ -152,6 +183,14 @@ async function post( setDataCallback(await response.json()); } catch (error) { console.error('Error fetching data: ', error); + setDataCallback([ + { + is_dir: false, + url: 'error_fetching', + thumbnail_url: '', + isPlaceholder: false, + }, + ]); } } diff --git a/src/Gallery/placeholder.png b/src/Gallery/placeholder.png new file mode 100644 index 0000000000000000000000000000000000000000..008244672802b1fa17d2ea482ec878576e22ce04 GIT binary patch literal 8405 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