migrate to vite + update dependencies
This commit is contained in:
parent
5b3f77c794
commit
210cd74155
|
|
@ -14,14 +14,14 @@ docker run -p 3005:3001 -v /mnt/data/pictures:/usr/src/app/public --name my-pict
|
||||||
Create an environment file `.env`:
|
Create an environment file `.env`:
|
||||||
|
|
||||||
```properties
|
```properties
|
||||||
REACT_APP_TITLE=My Gallery
|
VITE_TITLE=My Gallery
|
||||||
REACT_APP_APPBAR_COLOR=#F8AB2D
|
VITE_APPBAR_COLOR=#F8AB2D
|
||||||
```
|
```
|
||||||
|
|
||||||
Other properties:
|
Other properties:
|
||||||
|
|
||||||
```properties
|
```properties
|
||||||
REACT_APP_FAVICON_HREF=<URL to your favicon>
|
VITE_FAVICON_HREF=<URL to your favicon>
|
||||||
```
|
```
|
||||||
|
|
||||||
And run docker with `--env-file .env`
|
And run docker with `--env-file .env`
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
# Set user specific variables
|
# Set user specific variables
|
||||||
REACT_APP_TITLE=Simple Picture Gallery
|
VITE_TITLE=Simple Picture Gallery
|
||||||
REACT_APP_APPBAR_COLOR=#1976D2
|
VITE_APPBAR_COLOR=#1976D2
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
{
|
{
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true,
|
"browser": true,
|
||||||
"es2021": true,
|
"es2021": true
|
||||||
"jest/globals": true
|
|
||||||
},
|
},
|
||||||
"extends": [
|
"extends": [
|
||||||
"plugin:react/recommended",
|
"plugin:react/recommended",
|
||||||
|
|
@ -19,8 +18,7 @@
|
||||||
},
|
},
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"react",
|
"react",
|
||||||
"@typescript-eslint",
|
"@typescript-eslint"
|
||||||
"jest"
|
|
||||||
],
|
],
|
||||||
"ignorePatterns": [
|
"ignorePatterns": [
|
||||||
"**/*.css"
|
"**/*.css"
|
||||||
|
|
@ -55,6 +53,9 @@
|
||||||
"import/resolver": {
|
"import/resolver": {
|
||||||
"typescript": {
|
"typescript": {
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"react": {
|
||||||
|
"version": "detect"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,28 +2,19 @@
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="icon" id="favicon" href="%PUBLIC_URL%/favicon.ico" />
|
<link rel="icon" id="favicon" href="/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta
|
<meta
|
||||||
name="description"
|
name="description"
|
||||||
content="Simple Picture Gallery"
|
content="Simple Picture Gallery"
|
||||||
/>
|
/>
|
||||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
<link rel="apple-touch-icon" href="/logo192.png" />
|
||||||
<!--
|
<!--
|
||||||
manifest.json provides metadata used when your web app is installed on a
|
manifest.json provides metadata used when your web app is installed on a
|
||||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||||
-->
|
-->
|
||||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
<link rel="manifest" href="/manifest.json" />
|
||||||
<!--
|
|
||||||
Notice the use of %PUBLIC_URL% in the tags above.
|
|
||||||
It will be replaced with the URL of the `public` folder during the build.
|
|
||||||
Only files inside the `public` folder can be referenced from the HTML.
|
|
||||||
|
|
||||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
|
||||||
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`.
|
|
||||||
-->
|
|
||||||
<title id="appTitle">Simple Picture Gallery</title>
|
<title id="appTitle">Simple Picture Gallery</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
@ -39,6 +30,7 @@
|
||||||
To begin the development, run `npm start` or `yarn start`.
|
To begin the development, run `npm start` or `yarn start`.
|
||||||
To create a production bundle, use `npm run build` or `yarn build`.
|
To create a production bundle, use `npm run build` or `yarn build`.
|
||||||
-->
|
-->
|
||||||
<script src='%PUBLIC_URL%/env.js'></script>
|
<script src='/env.js'></script>
|
||||||
|
<script type="module" src="/src/index.tsx"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -3,48 +3,60 @@
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"proxy": "http://localhost:3001",
|
"proxy": "http://localhost:3001",
|
||||||
"dependencies": {
|
"type": "module",
|
||||||
"@emotion/react": "11.9.0",
|
|
||||||
"@emotion/styled": "11.8.1",
|
|
||||||
"@mui/icons-material": "5.6.0",
|
|
||||||
"@mui/lab": "5.0.0-alpha.76",
|
|
||||||
"@mui/material": "5.6.0",
|
|
||||||
"@types/jest": "27.4.1",
|
|
||||||
"@types/node": "16.11.26",
|
|
||||||
"@types/react": "18.0.0",
|
|
||||||
"@types/react-dom": "18.0.0",
|
|
||||||
"eslint": "8.21.0",
|
|
||||||
"eslint-config-prettier": "8.5.0",
|
|
||||||
"eslint-import-resolver-typescript": "3.4.0",
|
|
||||||
"eslint-plugin-import": "2.26.0",
|
|
||||||
"eslint-plugin-jsx-a11y": "6.6.1",
|
|
||||||
"eslint-plugin-prettier": "4.2.1",
|
|
||||||
"eslint-plugin-react": "7.30.1",
|
|
||||||
"eslint-plugin-react-hooks": "4.4.0",
|
|
||||||
"eslint-plugin-jest": "26.5.3",
|
|
||||||
"react": "18.0.0",
|
|
||||||
"react-dom": "18.0.0",
|
|
||||||
"react-photo-album": "1.12.0",
|
|
||||||
"react-router-dom": "6.3.0",
|
|
||||||
"react-scripts": "5.0.0",
|
|
||||||
"react-inject-env": "2.1.0",
|
|
||||||
"typescript": "4.6.3",
|
|
||||||
"web-vitals": "2.1.4",
|
|
||||||
"yet-another-react-lightbox": "1.14.0"
|
|
||||||
},
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"format": "prettier --write \"**/*.+(ts|tsx)\"",
|
"format": "prettier --write \"**/*.+(ts|tsx)\"",
|
||||||
"format:check": "prettier --check \"**/*.+(ts|tsx)\"",
|
"format:check": "prettier --check \"**/*.+(ts|tsx)\"",
|
||||||
"lint": "eslint src/**",
|
"lint": "eslint src/**",
|
||||||
"lint:fix": "eslint --fix src/**",
|
"lint:fix": "eslint --fix src/**",
|
||||||
"client:build": "react-scripts build && npm run set-environment",
|
"client:build": "vite build && npm run set-environment",
|
||||||
"client:eject": "react-scripts eject",
|
|
||||||
"client:run": "npm run client:build && npm run client:start",
|
"client:run": "npm run client:build && npm run client:start",
|
||||||
"client:start": "react-scripts start",
|
"client:start": "vite",
|
||||||
"client:test": "react-scripts test",
|
"client:test": "TODO",
|
||||||
"set-environment": "npx react-inject-env set",
|
"set-environment": "npx react-inject-env set",
|
||||||
"test": "jest"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@emotion/react": "^11.13.0",
|
||||||
|
"@emotion/styled": "^11.13.0",
|
||||||
|
"@mui/icons-material": "^5.16.7",
|
||||||
|
"@mui/x-tree-view": "^7.12.1",
|
||||||
|
"@mui/material": "^5.16.7",
|
||||||
|
"@types/jest": "^29.5.12",
|
||||||
|
"@types/node": "^22.2.0",
|
||||||
|
"@types/react": "^18.3.3",
|
||||||
|
"@types/react-dom": "^18.3.0",
|
||||||
|
"eslint": "8.57.0",
|
||||||
|
"eslint-config-prettier": "^9.1.0",
|
||||||
|
"eslint-import-resolver-typescript": "^3.6.1",
|
||||||
|
"eslint-plugin-import": "^2.29.1",
|
||||||
|
"eslint-plugin-jsx-a11y": "^6.9.0",
|
||||||
|
"eslint-plugin-prettier": "^5.2.1",
|
||||||
|
"eslint-plugin-react": "^7.35.0",
|
||||||
|
"eslint-plugin-react-hooks": "^4.6.2",
|
||||||
|
"react": "^18.3.1",
|
||||||
|
"react-dom": "^18.3.1",
|
||||||
|
"react-photo-album": "^3.0.1",
|
||||||
|
"react-router-dom": "^6.26.0",
|
||||||
|
"react-inject-env": "^2.1.0",
|
||||||
|
"typescript": "^5.5.4",
|
||||||
|
"web-vitals": "^4.2.3",
|
||||||
|
"yet-another-react-lightbox": "^3.21.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@testing-library/jest-dom": "^6.4.8",
|
||||||
|
"@testing-library/react": "^16.0.0",
|
||||||
|
"@testing-library/user-event": "^14.5.2",
|
||||||
|
"@typescript-eslint/eslint-plugin": "8.0.1",
|
||||||
|
"@typescript-eslint/parser": "8.0.1",
|
||||||
|
"@vitejs/plugin-react":"^4.3.1",
|
||||||
|
"prettier": "^3.3.3",
|
||||||
|
"ts-jest": "^29.2.4",
|
||||||
|
"ts-node": "^10.9.2",
|
||||||
|
"vite": "^5.4.0",
|
||||||
|
"vite-plugin-eslint": "^1.8.1",
|
||||||
|
"vite-tsconfig-paths": "^5.0.1"
|
||||||
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"extends": [
|
"extends": [
|
||||||
"react-app",
|
"react-app",
|
||||||
|
|
@ -62,15 +74,5 @@
|
||||||
"last 1 firefox version",
|
"last 1 firefox version",
|
||||||
"last 1 safari version"
|
"last 1 safari version"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@testing-library/jest-dom": "5.16.5",
|
|
||||||
"@testing-library/react": "13.3.0",
|
|
||||||
"@testing-library/user-event": "14.4.2",
|
|
||||||
"@typescript-eslint/eslint-plugin": "5.32.0",
|
|
||||||
"@typescript-eslint/parser": "5.32.0",
|
|
||||||
"prettier": "2.7.1",
|
|
||||||
"ts-jest": "27.1.5",
|
|
||||||
"ts-node": "10.7.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
import { PhotoProps } from "react-photo-album";
|
|
||||||
import { ImageWithThumbnail } from "./models";
|
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
export const Image = <T extends ImageWithThumbnail>({
|
|
||||||
imageProps: { alt, style, src: _useSrcAndThumbnailFromPhoto, ...rest },
|
|
||||||
photo,
|
|
||||||
}: PhotoProps<T>): JSX.Element => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<img
|
|
||||||
alt={alt}
|
|
||||||
style={{
|
|
||||||
...style,
|
|
||||||
}}
|
|
||||||
{...rest}
|
|
||||||
src={photo.thumbnail}
|
|
||||||
loading={"lazy"}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
@ -1,15 +1,14 @@
|
||||||
import PhotoAlbum from "react-photo-album";
|
import PhotoAlbum from "react-photo-album";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { Image } from "./Image";
|
|
||||||
import { ImageWithThumbnail } from "./models";
|
import { ImageWithThumbnail } from "./models";
|
||||||
import { Lightbox } from "yet-another-react-lightbox";
|
import { Lightbox } from "yet-another-react-lightbox";
|
||||||
import "yet-another-react-lightbox/styles.css";
|
import "yet-another-react-lightbox/styles.css";
|
||||||
|
|
||||||
import { Fullscreen } from "yet-another-react-lightbox/plugins/fullscreen";
|
import Fullscreen from "yet-another-react-lightbox/plugins/fullscreen";
|
||||||
import { Slideshow } from "yet-another-react-lightbox/plugins/slideshow";
|
import Slideshow from "yet-another-react-lightbox/plugins/slideshow";
|
||||||
import { Thumbnails } from "yet-another-react-lightbox/plugins/thumbnails";
|
import Thumbnails from "yet-another-react-lightbox/plugins/thumbnails";
|
||||||
import "yet-another-react-lightbox/plugins/thumbnails.css";
|
import "yet-another-react-lightbox/plugins/thumbnails.css";
|
||||||
import { Zoom } from "yet-another-react-lightbox/plugins/zoom";
|
import Zoom from "yet-another-react-lightbox/plugins/zoom";
|
||||||
|
|
||||||
function ImageGallery({ images }: { images: ImageWithThumbnail[] }) {
|
function ImageGallery({ images }: { images: ImageWithThumbnail[] }) {
|
||||||
const [index, setIndex] = useState(-1);
|
const [index, setIndex] = useState(-1);
|
||||||
|
|
@ -30,8 +29,16 @@ function ImageGallery({ images }: { images: ImageWithThumbnail[] }) {
|
||||||
<PhotoAlbum
|
<PhotoAlbum
|
||||||
layout="masonry"
|
layout="masonry"
|
||||||
photos={images}
|
photos={images}
|
||||||
renderPhoto={Image}
|
componentsProps={{
|
||||||
onClick={(event, photo, index) => setIndex(index)}
|
image: {
|
||||||
|
loading: "lazy",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
onClick={(props) => {
|
||||||
|
// TODO: what is eslint complaining?
|
||||||
|
// eslint-disable-next-line react/prop-types
|
||||||
|
setIndex(props.index);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<Lightbox
|
<Lightbox
|
||||||
slides={images}
|
slides={images}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import Toolbar from "@mui/material/Toolbar";
|
import Toolbar from "@mui/material/Toolbar";
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import env from "../env";
|
|
||||||
import AppBar from "@mui/material/AppBar";
|
import AppBar from "@mui/material/AppBar";
|
||||||
import useMediaQuery from "@mui/material/useMediaQuery";
|
import useMediaQuery from "@mui/material/useMediaQuery";
|
||||||
import { IconButton } from "@mui/material";
|
import { IconButton } from "@mui/material";
|
||||||
|
|
@ -21,7 +20,9 @@ export const ImageGalleryAppBar = ({
|
||||||
<AppBar
|
<AppBar
|
||||||
position="fixed"
|
position="fixed"
|
||||||
sx={{ zIndex: (theme) => theme.zIndex.drawer + 1 }}
|
sx={{ zIndex: (theme) => theme.zIndex.drawer + 1 }}
|
||||||
style={{ backgroundColor: env.REACT_APP_APPBAR_COLOR ?? "#1976D2" }}
|
style={{
|
||||||
|
backgroundColor: import.meta.env.VITE_APPBAR_COLOR ?? "#1976D2",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
{smallScreen && (
|
{smallScreen && (
|
||||||
|
|
@ -36,7 +37,7 @@ export const ImageGalleryAppBar = ({
|
||||||
</IconButton>
|
</IconButton>
|
||||||
)}
|
)}
|
||||||
<Typography variant="h6" noWrap component="div">
|
<Typography variant="h6" noWrap component="div">
|
||||||
{env.REACT_APP_TITLE ?? "Simple Picture Gallery"}
|
{import.meta.env.VITE_TITLE ?? "Simple Picture Gallery"}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
</AppBar>
|
</AppBar>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import Drawer from "@mui/material/Drawer";
|
import Drawer from "@mui/material/Drawer";
|
||||||
import FolderIcon from "@mui/icons-material/Folder";
|
import FolderIcon from "@mui/icons-material/Folder";
|
||||||
import FolderOpenIcon from "@mui/icons-material/FolderOpen";
|
import FolderOpenIcon from "@mui/icons-material/FolderOpen";
|
||||||
import { TreeItem, TreeView } from "@mui/lab";
|
import { SimpleTreeView, TreeItem } from "@mui/x-tree-view";
|
||||||
import { useLocation, useNavigate } from "react-router-dom";
|
import { useLocation, useNavigate } from "react-router-dom";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { Folders } from "./models";
|
import { Folders } from "./models";
|
||||||
|
|
@ -13,7 +13,7 @@ import { getDefaultExpanded } from "./PathToExpaned";
|
||||||
|
|
||||||
function generateTreeViewChildren(
|
function generateTreeViewChildren(
|
||||||
folders: Folders[],
|
folders: Folders[],
|
||||||
navigateAndToggleExpand: (_path: string, _navigationAllowed: boolean) => void
|
navigateAndToggleExpand: (_path: string, _navigationAllowed: boolean) => void,
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -25,7 +25,7 @@ function generateTreeViewChildren(
|
||||||
return (
|
return (
|
||||||
<TreeItem
|
<TreeItem
|
||||||
key={f.fullPath}
|
key={f.fullPath}
|
||||||
nodeId={f.fullPath}
|
itemId={f.fullPath}
|
||||||
label={label}
|
label={label}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
navigateAndToggleExpand(f.fullPath, containsImages)
|
navigateAndToggleExpand(f.fullPath, containsImages)
|
||||||
|
|
@ -36,7 +36,7 @@ function generateTreeViewChildren(
|
||||||
return (
|
return (
|
||||||
<TreeItem
|
<TreeItem
|
||||||
key={f.fullPath}
|
key={f.fullPath}
|
||||||
nodeId={f.fullPath}
|
itemId={f.fullPath}
|
||||||
label={label}
|
label={label}
|
||||||
onClick={() => navigateAndToggleExpand(f.fullPath, containsImages)}
|
onClick={() => navigateAndToggleExpand(f.fullPath, containsImages)}
|
||||||
>
|
>
|
||||||
|
|
@ -51,21 +51,21 @@ function generateTreeViewChildren(
|
||||||
const GenerateTreeView = ({ root }: { root: Folders }) => {
|
const GenerateTreeView = ({ root }: { root: Folders }) => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [expanded, setExpanded] = useState<string[]>(
|
const [expandedItems, setExpandedItems] = useState<string[]>(
|
||||||
getDefaultExpanded(location.pathname)
|
getDefaultExpanded(location.pathname),
|
||||||
);
|
);
|
||||||
|
|
||||||
const toggleExpanded = (path: string) => {
|
const toggleExpanded = (path: string) => {
|
||||||
if (expanded.includes(path)) {
|
if (expandedItems.includes(path)) {
|
||||||
setExpanded(expanded.filter((p) => p !== path));
|
setExpandedItems(expandedItems.filter((p) => p !== path));
|
||||||
} else {
|
} else {
|
||||||
setExpanded([path, ...expanded]);
|
setExpandedItems([path, ...expandedItems]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const navigateAndToggleExpand = (
|
const navigateAndToggleExpand = (
|
||||||
path: string,
|
path: string,
|
||||||
navigationAllowed: boolean
|
navigationAllowed: boolean,
|
||||||
) => {
|
) => {
|
||||||
if (!navigationAllowed || location.pathname === path) {
|
if (!navigationAllowed || location.pathname === path) {
|
||||||
toggleExpanded(path);
|
toggleExpanded(path);
|
||||||
|
|
@ -76,15 +76,14 @@ const GenerateTreeView = ({ root }: { root: Folders }) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TreeView
|
<SimpleTreeView
|
||||||
disableSelection
|
disableSelection
|
||||||
defaultCollapseIcon={<FolderOpenIcon />}
|
slots={{ collapseIcon: FolderOpenIcon, expandIcon: FolderIcon }}
|
||||||
defaultExpandIcon={<FolderIcon />}
|
expandedItems={expandedItems}
|
||||||
expanded={expanded}
|
|
||||||
>
|
>
|
||||||
<TreeItem
|
<TreeItem
|
||||||
key={root.fullPath}
|
key={root.fullPath}
|
||||||
nodeId={root.fullPath}
|
itemId={root.fullPath}
|
||||||
label={`${root.name} - (${root.numberOfFiles})`}
|
label={`${root.name} - (${root.numberOfFiles})`}
|
||||||
onClick={() => navigate(root.fullPath)}
|
onClick={() => navigate(root.fullPath)}
|
||||||
/>
|
/>
|
||||||
|
|
@ -94,7 +93,7 @@ const GenerateTreeView = ({ root }: { root: Folders }) => {
|
||||||
// eslint-disable-next-line react/jsx-no-useless-fragment
|
// eslint-disable-next-line react/jsx-no-useless-fragment
|
||||||
<></>
|
<></>
|
||||||
)}
|
)}
|
||||||
</TreeView>
|
</SimpleTreeView>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
import { Pathname } from "history";
|
export const getDefaultExpanded = (pathname: string): string[] => {
|
||||||
|
|
||||||
export const getDefaultExpanded = (pathname: Pathname): string[] => {
|
|
||||||
const pathParts = [];
|
const pathParts = [];
|
||||||
let curPathname = pathname.startsWith("/") ? pathname.slice(1) : pathname;
|
let curPathname = pathname.startsWith("/") ? pathname.slice(1) : pathname;
|
||||||
while (curPathname.endsWith("/")) {
|
while (curPathname.endsWith("/")) {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
import env from "../env";
|
|
||||||
import { CircularProgress } from "@mui/material";
|
import { CircularProgress } from "@mui/material";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
export const Spinner = (): JSX.Element => {
|
export const Spinner = (): JSX.Element => {
|
||||||
return (
|
return (
|
||||||
<CircularProgress
|
<CircularProgress
|
||||||
style={{ color: env.REACT_APP_APPBAR_COLOR ?? "#1976D2" }}
|
style={{ color: import.meta.env.VITE_APPBAR_COLOR ?? "#1976D2" }}
|
||||||
size={100}
|
size={100}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,6 @@ describe("getDefaultExpanded", () => {
|
||||||
"should allow valid path: %s",
|
"should allow valid path: %s",
|
||||||
({ pathname, expanded }) => {
|
({ pathname, expanded }) => {
|
||||||
expect(getDefaultExpanded(pathname).sort()).toEqual(expanded.sort());
|
expect(getDefaultExpanded(pathname).sort()).toEqual(expanded.sort());
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import Box from "@mui/material/Box";
|
|
||||||
import CssBaseline from "@mui/material/CssBaseline";
|
import CssBaseline from "@mui/material/CssBaseline";
|
||||||
|
import Box from "@mui/material/Box";
|
||||||
import { useLocation, useNavigate } from "react-router-dom";
|
import { useLocation, useNavigate } from "react-router-dom";
|
||||||
import { Folders, ImageWithThumbnail } from "./ImageGallery/models";
|
import { Folders, ImageWithThumbnail } from "./ImageGallery/models";
|
||||||
import { ImageGalleryAppBar } from "./ImageGallery/ImageGalleryAppBar";
|
import { ImageGalleryAppBar } from "./ImageGallery/ImageGalleryAppBar";
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,3 @@
|
||||||
declare global {
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
interface Window {
|
|
||||||
env: any;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type EnvType = {
|
|
||||||
REACT_APP_TITLE: string;
|
|
||||||
REACT_APP_APPBAR_COLOR: string;
|
|
||||||
REACT_APP_FAVICON_HREF: string | undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
const env: EnvType = { ...process.env, ...window.env };
|
|
||||||
|
|
||||||
function getTitleElement() {
|
function getTitleElement() {
|
||||||
return document.getElementById("appTitle")!;
|
return document.getElementById("appTitle")!;
|
||||||
}
|
}
|
||||||
|
|
@ -22,13 +7,11 @@ function getFaviconElement() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const setGalleryTitleAndFavicon = () => {
|
export const setGalleryTitleAndFavicon = () => {
|
||||||
if (env.REACT_APP_FAVICON_HREF !== undefined) {
|
if (import.meta.env.VITE_FAVICON_HREF !== undefined) {
|
||||||
const favicon = getFaviconElement();
|
const favicon = getFaviconElement();
|
||||||
favicon.href = env.REACT_APP_FAVICON_HREF;
|
favicon.href = import.meta.env.VITE_FAVICON_HREF;
|
||||||
}
|
}
|
||||||
|
|
||||||
const title = getTitleElement();
|
const title = getTitleElement();
|
||||||
title.textContent = env.REACT_APP_TITLE;
|
title.textContent = import.meta.env.VITE_TITLE;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default env;
|
|
||||||
|
|
|
||||||
|
|
@ -9,14 +9,14 @@ import { setGalleryTitleAndFavicon } from "./env";
|
||||||
setGalleryTitleAndFavicon();
|
setGalleryTitleAndFavicon();
|
||||||
|
|
||||||
const root = ReactDOM.createRoot(
|
const root = ReactDOM.createRoot(
|
||||||
document.getElementById("root") as HTMLElement
|
document.getElementById("root") as HTMLElement,
|
||||||
);
|
);
|
||||||
root.render(
|
root.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<ImageGalleryLayout />
|
<ImageGalleryLayout />
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
</React.StrictMode>
|
</React.StrictMode>,
|
||||||
);
|
);
|
||||||
|
|
||||||
// If you want to start measuring performance in your app, pass a function
|
// If you want to start measuring performance in your app, pass a function
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
|
interface ImportMetaEnv {
|
||||||
|
readonly VITE_TITLE: string;
|
||||||
|
readonly VITE_APPBAR_COLOR: string;
|
||||||
|
readonly VITE_FAVICON_HREF: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
interface ImportMeta {
|
||||||
|
readonly env: ImportMetaEnv;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { defineConfig } from "vite";
|
||||||
|
import react from "@vitejs/plugin-react";
|
||||||
|
import eslint from "vite-plugin-eslint";
|
||||||
|
import viteTsconfigPaths from "vite-tsconfig-paths";
|
||||||
|
|
||||||
|
export default defineConfig(() => {
|
||||||
|
return {
|
||||||
|
build: {
|
||||||
|
outDir: "build",
|
||||||
|
sourcemap: true,
|
||||||
|
},
|
||||||
|
plugins: [react(), eslint(), viteTsconfigPaths()],
|
||||||
|
server: {
|
||||||
|
proxy: {
|
||||||
|
"/images": {
|
||||||
|
target: "http://localhost:3001",
|
||||||
|
changeOrigin: true,
|
||||||
|
secure: false,
|
||||||
|
},
|
||||||
|
"/directories": {
|
||||||
|
target: "http://localhost:3001",
|
||||||
|
changeOrigin: true,
|
||||||
|
secure: false,
|
||||||
|
},
|
||||||
|
"/staticImages": {
|
||||||
|
target: "http://localhost:3001",
|
||||||
|
changeOrigin: true,
|
||||||
|
secure: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
@ -15,7 +15,7 @@ const withCaching = {
|
||||||
setHeaders(res, _) {
|
setHeaders(res, _) {
|
||||||
res.setHeader(
|
res.setHeader(
|
||||||
"Expires",
|
"Expires",
|
||||||
new Date(Date.now() + 2592000000 * 30).toUTCString()
|
new Date(Date.now() + 2592000000 * 30).toUTCString(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -26,9 +26,7 @@ app.use(express.static("../picture-gallery-client/build"));
|
||||||
|
|
||||||
app.use(expressLogger);
|
app.use(expressLogger);
|
||||||
|
|
||||||
const imagesPath = "/images";
|
app.get(`/images(/*)?`, getImages);
|
||||||
|
|
||||||
app.get(`${imagesPath}(/*)?`, getImages);
|
|
||||||
|
|
||||||
app.get("/directories", async (req, res) => {
|
app.get("/directories", async (req, res) => {
|
||||||
res.json(await walk(""));
|
res.json(await walk(""));
|
||||||
|
|
@ -37,7 +35,7 @@ app.get("/directories", async (req, res) => {
|
||||||
// All other GET requests not handled before will return our React app
|
// All other GET requests not handled before will return our React app
|
||||||
app.get("*", (req, res) => {
|
app.get("*", (req, res) => {
|
||||||
res.sendFile(
|
res.sendFile(
|
||||||
path.resolve(__dirname, "../../picture-gallery-client/build/index.html")
|
path.resolve(__dirname, "../../picture-gallery-client/build/index.html"),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue