Compare commits

...

7 Commits

Author SHA1 Message Date
Edward 1a7786b458 make grid 2023-11-13 20:45:24 +00:00
sheldonmlee 098777bb02 Use hosted backend 2023-11-14 03:51:09 +08:00
sheldonmlee 2c31cf8820 Change title to Photos 2023-11-14 00:32:09 +08:00
sheldonmlee 9d3d3530ea Fix handling of thumbnail urls, so that original url is still linked on
the top of image.
2023-11-14 00:31:10 +08:00
sheldonmlee a0b85dfbca Implement use of thumbnails if available, and open original image if
file name clicked
2023-11-13 02:10:10 +08:00
sheldonmlee 039c2948c4 Move backend related code to new repository 2023-11-12 17:48:46 +08:00
sheldonmlee a26dd9741a Update .gitignore 2023-11-09 20:39:23 +08:00
5 changed files with 92 additions and 80 deletions
+1
View File
@@ -1,5 +1,6 @@
{ {
"name": "react-photo-viewer", "name": "react-photo-viewer",
"homepage": "https://dundun.ddns.net/photos",
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
-52
View File
@@ -1,52 +0,0 @@
<?php
define("ROOT_URL", "http://localhost/react-photo-viewer/");
define("RELATIVE_IMG", "../img/");
define("ABSOLUTE_IMG", "img/");
main();
function main(): void {
$data = json_decode(file_get_contents('php://input'), true);
$array = [];
$category = $data["category"];
$directory = RELATIVE_IMG.$category;
if (!is_dir($directory)) return;
foreach (scandir($directory) as $file) {
if ($file === ".") continue;
if ($category === "" && $file === "..") continue;
if ($category != "") $file = $category.'/'.$file;
$is_dir = is_dir(RELATIVE_IMG.$file);
if (!$is_dir && !is_valid_file_type($file)) continue;
$file_item = [];
$file_item["is_dir"] = $is_dir;
$file_item["url"] = ROOT_URL.ABSOLUTE_IMG.$file;
array_push($array, $file_item);
}
echo json_encode($array);
}
function is_valid_file_type(string $filename): bool {
$file_extensions = [
// Image extensions
'jpg',
'jpeg',
'png',
'gif',
'tiff',
'bmp',
'webp',
'svg',
// Video extensions
'mp4',
];
foreach ($file_extensions as $file_extension) {
if (str_ends_with($filename, $file_extension)) return true;
}
return false;
}
?>
+1 -1
View File
@@ -24,7 +24,7 @@
work correctly both with client-side routing and a non-root public URL. work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`. Learn how to configure a non-root public URL by running `npm run build`.
--> -->
<title>React App</title> <title>Photos</title>
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
+40 -8
View File
@@ -1,7 +1,7 @@
body { body {
min-height: 100vh; min-height: 100vh;
background-color: #282c34; background-color: #282c34;
color: #B9B8D6; color: #b9b8d6;
} }
.Header { .Header {
@@ -24,7 +24,7 @@ body {
flex-direction: column; flex-direction: column;
text-align: center; text-align: center;
background-color: #3B3E49; background-color: #3b3e49;
border-radius: 10px 10px 0px 0px; border-radius: 10px 10px 0px 0px;
margin: 0 0 1em 0; margin: 0 0 1em 0;
@@ -32,17 +32,21 @@ body {
max-width: calc(100vw - 2em); max-width: calc(100vw - 2em);
} }
.GalleryItem > p { .GalleryItem > a {
margin: 0.5em; color: inherit;
margin: 0;
overflow: clip;
} }
.GalleryItem > img, video { .GalleryItem > img,
video {
max-height: 80vh; max-height: 80vh;
} }
.DirectoryItem > button { .DirectoryItem > button {
background-color: #44655D; background-color: #44655d;
color: #B9B8D6; color: #b9b8d6;
border: none; border: none;
padding: 10px 20px; padding: 10px 20px;
text-align: center; text-align: center;
@@ -60,6 +64,34 @@ body {
} }
.ParentDirectoryItem > button { .ParentDirectoryItem > button {
background-color: #4D4F5D; background-color: #4d4f5d;
} }
@media (min-width: 62em) {
.GalleryItem {
margin: 1em;
border-radius: 1em;
overflow: hidden;
}
.Contents {
display: flex;
flex-direction: row;
align-items: start;
align-content: center;
flex-wrap: wrap;
}
.GalleryImg {
object-fit: cover;
width: 12em;
height: 9em;
}
.GalleryVid {
object-fit: cover;
width: 12em;
height: 9em;
}
}
+50 -19
View File
@@ -28,6 +28,7 @@ function App() {
interface galleryItemInfo { interface galleryItemInfo {
is_dir: boolean; is_dir: boolean;
url: string; url: string;
thumbnail_url: string;
} }
function getContents( function getContents(
@@ -60,6 +61,8 @@ function getContents(
}) })
.map((item: galleryItemInfo, index: number) => { .map((item: galleryItemInfo, index: number) => {
const url = item.url; const url = item.url;
const thumbnail_url =
item.thumbnail_url === null ? item.url : item.thumbnail_url;
let onClick = () => {}; let onClick = () => {};
if (item.is_dir) { if (item.is_dir) {
onClick = () => { onClick = () => {
@@ -72,25 +75,48 @@ function getContents(
setCategory(category); setCategory(category);
}; };
return <DirectoryItem key={index} url={url} onClick={onClick} />; return (
<DirectoryItem
key={index}
thumbnail_url={thumbnail_url}
url={url}
onClick={onClick}
/>
);
} }
if (url.endsWith('.mp4')) { if (url.endsWith('.mp4')) {
return <VideoItem key={index} url={url} onClick={onClick} />; return (
<VideoItem
key={index}
thumbnail_url={thumbnail_url}
url={url}
onClick={onClick}
/>
);
} }
return <ImageItem key={index} url={url} onClick={onClick} />; return (
<ImageItem
key={index}
thumbnail_url={thumbnail_url}
url={url}
onClick={onClick}
/>
);
}); });
} }
interface galleryItem { interface galleryItem {
url: string; url: string;
thumbnail_url: string;
onClick: () => void; onClick: () => void;
} }
function ImageItem({ url }: galleryItem) { function ImageItem({ thumbnail_url, url }: galleryItem) {
return ( return (
<div className="GalleryItem"> <div className="GalleryItem">
<p>{getFileName(url)}</p> <a href={url} target="_blank">
<img src={url} loading="lazy" /> <img className="GalleryImg" src={thumbnail_url} loading="lazy" />
</a>
</div> </div>
); );
} }
@@ -98,10 +124,11 @@ function ImageItem({ url }: galleryItem) {
function VideoItem({ url }: galleryItem) { function VideoItem({ url }: galleryItem) {
return ( return (
<div className="GalleryItem"> <div className="GalleryItem">
<p>{getFileName(url)}</p> <a href={url} target="_blank">
<video controls> <video controls>
<source src={url} type="video/mp4" /> <source className="GalleryVid" src={url} type="video/mp4" />
</video> </video>
</a>
</div> </div>
); );
} }
@@ -125,15 +152,19 @@ function getFileName(string: string): string {
} }
function post(category: string, callback: (text: string) => void) { function post(category: string, callback: (text: string) => void) {
fetch('http://localhost/react-photo-viewer/php/get.php', { fetch(
method: 'POST', //'http://localhost/photo-viewer-backend/php/get.php',
headers: { 'https://dundun.ddns.net/photo-viewer/photo-viewer-backend/php/get.php',
'Content-Type': 'application/json', {
}, method: 'POST',
body: JSON.stringify({ headers: {
category: category, 'Content-Type': 'application/json',
}), },
}) body: JSON.stringify({
category: category,
}),
}
)
.then((response) => { .then((response) => {
if (!response.ok) { if (!response.ok) {
throw new Error('Network response was not ok'); throw new Error('Network response was not ok');