1
Fork 0

Update UI deps + replace create-react-app with vite

This commit is contained in:
viktorstrate 2022-07-08 00:33:35 +02:00
parent a5d152f0c0
commit fdcf0cfd05
No known key found for this signature in database
GPG Key ID: 3F855605109C1E8A
28 changed files with 14413 additions and 22269 deletions

View File

@ -1,7 +0,0 @@
module.exports = {
style: {
postcss: {
plugins: [require('tailwindcss'), require('autoprefixer')],
},
},
}

22
ui/index.html Normal file
View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="/photoview-logo.svg" type="image/svg+xml" />
<link rel="apple-touch-icon" href="/logo192.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="manifest" href="/manifest.json" />
<meta name="apple-mobile-web-app-title" content="Photoview" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="white" />
</head>
<body>
<noscript>You need to enable JavaScript to run Photoview.</noscript>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>

36324
ui/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -8,78 +8,70 @@
},
"license": "GPL-3.0",
"description": "UI app for Photoview",
"dependencies": {
"@apollo/client": "^3.5.8",
"@babel/preset-typescript": "^7.16.7",
"@craco/craco": "^6.4.3",
"@headlessui/react": "^1.4.3",
"@react-aria/focus": "^3.5.0",
"@rollup/plugin-babel": "^5.3.0",
"@types/geojson": "^7946.0.8",
"@types/jest": "^27.4.0",
"@types/mapbox-gl": "^2.6.0",
"@types/react": "^17.0.38",
"@types/react-dom": "^17.0.11",
"@types/react-helmet": "^6.1.5",
"@types/react-router-dom": "^5.3.3",
"@types/styled-components": "^5.1.21",
"@types/url-join": "^4.0.1",
"autoprefixer": "^9.8.6",
"babel-plugin-graphql-tag": "^3.3.0",
"blurhash": "^1.1.4",
"classnames": "^2.3.1",
"connect-history-api-fallback": "^1.6.0",
"copy-to-clipboard": "^3.3.1",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-jest-dom": "^4.0.1",
"fs-extra": "^10.0.0",
"i18next": "^21.6.10",
"mapbox-gl": "^2.6.1",
"postcss": "^7.0.36",
"prettier": "^2.5.1",
"prop-types": "^15.8.1",
"react": "^17.0.2",
"react-blurhash": "^0.1.3",
"react-dom": "^17.0.2",
"react-helmet": "^6.1.0",
"react-hook-form": "^7.25.3",
"react-i18next": "^11.15.3",
"react-router-dom": "^6.2.1",
"react-router-prop-types": "^1.0.5",
"react-scripts": "^4.0.3",
"react-spring": "^8.0.27",
"react-test-renderer": "^17.0.2",
"styled-components": "^5.3.3",
"subscriptions-transport-ws": "^0.11.0",
"tailwind-override": "^0.6.1",
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.2.17",
"typescript": "^4.5.5",
"url-join": "^4.0.1"
},
"scripts": {
"start": "BROWSER=none PORT=1234 craco start",
"build": "craco build",
"start": "vite",
"build": "vite build",
"test": "npm run lint && npm run jest -- --watchAll=false",
"test:ci": "npm run lint && npm run jest:ci",
"lint": "npm run lint:types & npm run lint:eslint",
"lint:eslint": "eslint ./src --max-warnings 0 --cache --config .eslintrc.js",
"lint:types": "tsc --noemit",
"lint": "eslint ./src --max-warnings 0 --cache --config .eslintrc.js",
"jest": "craco test --setupFilesAfterEnv ./testing/setupTests.ts",
"jest:ci": "CI=true craco test --setupFilesAfterEnv ./testing/setupTests.ts --verbose --ci --coverage",
"genSchemaTypes": "apollo client:codegen --target=typescript --globalTypesFile=src/__generated__/globalTypes.ts && prettier --write */**/__generated__/*.ts",
"extractTranslations": "i18next -c i18next-parser.config.js",
"prepare": "(cd .. && npx husky install)"
},
"dependencies": {
"@apollo/client": "^3.6.9",
"@babel/preset-typescript": "^7.18.6",
"@headlessui/react": "^1.6.6",
"@types/geojson": "^7946.0.8",
"@types/jest": "^28.1.4",
"@types/mapbox-gl": "^2.7.3",
"@types/react": "^18.0.15",
"@types/react-dom": "^18.0.6",
"@types/react-helmet": "^6.1.5",
"@types/react-router-dom": "^5.3.3",
"@types/styled-components": "^5.1.25",
"@types/url-join": "^4.0.1",
"@vitejs/plugin-react": "^1.3.2",
"autoprefixer": "^10.4.7",
"blurhash": "^1.1.5",
"classnames": "^2.3.1",
"connect-history-api-fallback": "^2.0.0",
"copy-to-clipboard": "^3.3.1",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-jest-dom": "^4.0.2",
"i18next": "^21.8.13",
"mapbox-gl": "^2.9.1",
"postcss": "^8.4.14",
"prettier": "^2.7.1",
"react": "^18.2.0",
"react-blurhash": "^0.1.3",
"react-dom": "^18.2.0",
"react-helmet": "^6.1.0",
"react-hook-form": "^7.33.1",
"react-i18next": "^11.18.0",
"react-router-dom": "^6.3.0",
"react-scripts": "^5.0.1",
"react-test-renderer": "^18.2.0",
"styled-components": "^5.3.5",
"subscriptions-transport-ws": "^0.11.0",
"tailwind-override": "^0.6.1",
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.2.17",
"typescript": "^4.7.4",
"url-join": "^5.0.0",
"vite": "^2.9.13",
"vite-plugin-svgr": "^2.2.0"
},
"devDependencies": {
"@testing-library/jest-dom": "^5.16.1",
"@testing-library/react": "^12.1.2",
"@testing-library/user-event": "^13.5.0",
"apollo": "2.33.9",
"apollo-language-server": "1.26.7",
"husky": "^7.0.4",
"i18next-parser": "^5.4.0",
"lint-staged": "^12.3.2",
"tsc-files": "1.1.2"
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^14.2.1",
"apollo": "2.34.0",
"apollo-language-server": "1.26.9",
"husky": "^8.0.1",
"i18next-parser": "^6.5.0",
"lint-staged": "^13.0.3"
},
"overrides": {
"graphql": "^15.0.0"
@ -93,8 +85,7 @@
},
"lint-staged": {
"*.{ts,tsx,js,json,css,md,graphql}": "prettier --write",
"*.{js,ts,tsx}": "eslint --cache --fix --max-warnings 0",
"*.{ts,tsx}": "tsc-files --noEmit"
"*.{js,ts,tsx}": "eslint --cache --fix --max-warnings 0"
},
"browserslist": {
"production": [

6
ui/postcss.config.js Normal file
View File

@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

View File

@ -1,42 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/photoview-logo.svg" type="image/svg+xml" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<!--
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/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<meta name="apple-mobile-web-app-title" content="Photoview" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="white" />
<!--
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`.
-->
</head>
<body>
<noscript>You need to enable JavaScript to run Photoview.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

View File

@ -100,7 +100,7 @@ function AlbumPage() {
})
const toggleFavorites = useCallback(
onlyFavorites => {
(onlyFavorites: boolean) => {
if (
(refetchNeededAll && !onlyFavorites) ||
(refetchNeededFavorites && onlyFavorites)

View File

@ -29,7 +29,7 @@ const LogoHeader = () => {
<div className="flex justify-center flex-col mb-14 mt-20">
<img
className="h-24"
src={process.env.PUBLIC_URL + '/photoview-logo.svg'}
src={import.meta.env.BASE_URL + 'photoview-logo.svg'}
alt="photoview logo"
/>
<h1 className="text-3xl text-center mt-4">

View File

@ -40,7 +40,7 @@ const ChangePasswordModal = ({
title={t('settings.users.password_reset.title', 'Change password')}
description={
<Trans t={t} i18nKey="settings.users.password_reset.description">
Change password for <b>{{ username: user.username }}</b>
Change password for <b>{user.username}</b>
</Trans>
}
actions={[

View File

@ -7,10 +7,12 @@ import {
SectionTitle,
} from './SettingsPage'
const VERSION = process.env.REACT_APP_BUILD_VERSION ?? 'undefined'
const BUILD_DATE = process.env.REACT_APP_BUILD_DATE ?? 'undefined'
const VERSION = import.meta.env.REACT_APP_BUILD_VERSION ?? 'undefined'
const BUILD_DATE = import.meta.env.REACT_APP_BUILD_DATE ?? 'undefined'
const COMMIT_SHA = process.env.REACT_APP_BUILD_COMMIT_SHA as string | undefined
const COMMIT_SHA = import.meta.env.REACT_APP_BUILD_COMMIT_SHA as
| string
| undefined
let commitLink: ReactElement
if (COMMIT_SHA) {

View File

@ -35,7 +35,7 @@ const PasswordProtectedShare = ({
'share_page.wrong_password',
'Wrong password, please try again.'
)
} else if (errors.password?.type === 'required') {
} else if (errors.password) {
errorMessage = t(
'share_page.protected_share.password_required_error',
'Password is required'

View File

@ -17,8 +17,8 @@ import { MessageState } from './components/messages/Messages'
import { Message } from './components/messages/SubscriptionsHook'
import { NotificationType } from './__generated__/globalTypes'
export const API_ENDPOINT = process.env.REACT_APP_API_ENDPOINT
? (process.env.REACT_APP_API_ENDPOINT as string)
export const API_ENDPOINT = import.meta.env.REACT_APP_API_ENDPOINT
? (import.meta.env.REACT_APP_API_ENDPOINT as string)
: urlJoin(location.origin, '/api')
export const GRAPHQL_ENDPOINT = urlJoin(API_ENDPOINT, '/graphql')

View File

@ -18,7 +18,7 @@ const Header = () => {
<h1 className="mr-4 lg:mr-8 flex-shrink-0 flex items-center">
<img
className="h-12 lg:h-10"
src={process.env.PUBLIC_URL + '/photoview-logo.svg'}
src={import.meta.env.BASE_URL + 'photoview-logo.svg'}
alt="logo"
/>
<span className="hidden lg:block ml-2 text-2xl font-light">

View File

@ -1,5 +1,4 @@
import { gql } from '@apollo/client'
import PropTypes from 'prop-types'
import React, { useContext } from 'react'
import { Helmet } from 'react-helmet'
import Header from '../header/Header'
@ -50,9 +49,4 @@ const Layout = ({ children, title, ...otherProps }: LayoutProps) => {
)
}
Layout.propTypes = {
children: PropTypes.any.isRequired,
title: PropTypes.string,
}
export default Layout

View File

@ -1,5 +1,4 @@
import React, { useState } from 'react'
import { animated, useTransition } from 'react-spring'
import styled from 'styled-components'
import { authToken } from '../../helpers/authentication'
import MessageProgress from './MessageProgress'
@ -83,29 +82,30 @@ const Messages = () => {
}
}
const transitions = useTransition(messages.slice().reverse(), x => x.key, {
from: {
opacity: 0,
height: '0px',
},
enter: {
opacity: 1,
height: `100px`,
},
leave: { opacity: 0, height: '0px' },
// const transitions = useTransition(messages.slice().reverse(), x => x.key, {
// from: {
// opacity: 0,
// height: '0px',
// },
// enter: {
// opacity: 1,
// height: `100px`,
// },
// leave: { opacity: 0, height: '0px' },
// })
const messageElems = messages.map(msg => {
const Elem = getMessageElement(msg)
return (
<div key={msg.key}>
<Elem />
</div>
)
})
return (
<Container>
{transitions.map(({ item, props: style, key }) => {
const MessageElement = getMessageElement(item)
return (
<animated.div key={key} style={style}>
<MessageElement />
</animated.div>
)
})}
{messageElems}
{authToken() && (
<SubscriptionsHook messages={messages} setMessages={setMessages} />
)}

View File

@ -1,5 +1,4 @@
import { notificationSubscription } from './__generated__/notificationSubscription'
import PropTypes from 'prop-types'
import { useEffect } from 'react'
import { useSubscription, gql } from '@apollo/client'
import { authToken } from '../../helpers/authentication'
@ -122,9 +121,4 @@ const SubscriptionsHook = ({
return null
}
SubscriptionsHook.propTypes = {
messages: PropTypes.array.isRequired,
setMessages: PropTypes.func.isRequired,
}
export default SubscriptionsHook

View File

@ -2,7 +2,7 @@ import React from 'react'
import PresentNavigationOverlay from './PresentNavigationOverlay'
import { fireEvent, render, screen, act } from '@testing-library/react'
jest.useFakeTimers('modern')
jest.useFakeTimers()
describe('PresentNavigationOverlay component', () => {
test('simple render', () => {

View File

@ -67,7 +67,7 @@ const PresentView = ({
})
return (
<StyledContainer {...className}>
<StyledContainer className={className}>
<PreventScroll />
<PresentNavigationOverlay
dispatchMedia={dispatchMedia}

View File

@ -1,5 +1,4 @@
import React, { useRef, useEffect, useReducer } from 'react'
import PropTypes from 'prop-types'
import { useQuery, gql } from '@apollo/client'
import TimelineGroupDate from './TimelineGroupDate'
import PresentView from '../photoGallery/presentView/PresentView'
@ -197,9 +196,4 @@ const TimelineGallery = () => {
)
}
TimelineGallery.propTypes = {
favorites: PropTypes.bool,
setFavorites: PropTypes.func,
}
export default TimelineGallery

View File

@ -1,7 +1,7 @@
import 'regenerator-runtime/runtime'
import React from 'react'
import ReactDOM from 'react-dom'
import { createRoot } from 'react-dom/client'
import App from './App'
import client from './apolloClient'
import { ApolloProvider } from '@apollo/client'
@ -26,6 +26,7 @@ const Main = () => (
</ApolloProvider>
)
ReactDOM.render(<Main />, document.getElementById('root'))
const root = createRoot(document.getElementById('root')!)
root.render(<Main />)
serviceWorkerRegistration.register()

View File

@ -21,7 +21,7 @@ export function setupLocalization(): void {
},
react: {
useSuspense: process.env.NODE_ENV == 'production',
useSuspense: import.meta.env.PROD,
},
})
}

View File

@ -1 +0,0 @@
/// <reference types="react-scripts" />

View File

@ -55,7 +55,7 @@ registerRoute(
// Return true to signal that we want to use the handler.
return true
},
createHandlerBoundToURL(process.env.PUBLIC_URL + '/index.html')
createHandlerBoundToURL(import.meta.env.BASE_URL + 'index.html')
)
// An example runtime caching route for requests that aren't handled by the

View File

@ -26,9 +26,9 @@ type Config = {
}
export function register(config?: Config) {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
if (import.meta.env.PROD && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href)
const publicUrl = new URL(import.meta.env.BASE_URL, window.location.href)
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
@ -37,7 +37,7 @@ export function register(config?: Config) {
}
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`
const swUrl = `${import.meta.env.BASE_URL}service-worker.js`
if (isLocalhost) {
// This is running on localhost. Let's check if a service worker still exists or not.

1
ui/src/vite.env.d.ts vendored Normal file
View File

@ -0,0 +1 @@
/// <reference types="vite/client" />

View File

@ -1,5 +1,6 @@
module.exports = {
mode: 'jit',
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
purge: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
darkMode: 'class',
theme: {

View File

@ -1,21 +1,20 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"target": "ESNext",
"useDefineForClassFields": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": true,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"module": "ESNext",
"moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": ["src"],
"exclude": ["./node_modules", "./build"]
"include": ["src", "vite.config.ts"]
}

11
ui/vite.config.js Normal file
View File

@ -0,0 +1,11 @@
import { defineConfig } from 'vite'
import svgr from 'vite-plugin-svgr'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react(), svgr()],
envPrefix: ['VITE_', 'REACT_APP_'],
server: {
port: 1234,
},
})