diff --git a/.gitignore b/.gitignore index 86193736c..97d5d5323 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ publish .nohup */lib */dist +*/dev-dist */yarn-error.log test-results */nohup.out diff --git a/CHANGELOG.md b/CHANGELOG.md index 43027ef57..58339d431 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This changelog covers all three packages, as they are (for now) updated as a who - Add folders with list & grid views, allow drag & drop uploads #228 - Show icons in sidebar - Add scoped search, funded by NGI NLnet Discovery #245 +- Make web app installable #30 - Add cookie based authentication #241 ## v0.32.1 diff --git a/data-browser/index.html b/data-browser/index.html index 0247496ce..bc9ef6893 100644 --- a/data-browser/index.html +++ b/data-browser/index.html @@ -9,13 +9,15 @@ - - + - - + + + + Atomic Data Browser @@ -89,23 +91,6 @@ .setProperty('--background-color', 'black'); } - - - diff --git a/data-browser/package.json b/data-browser/package.json index 2b726f1ae..5bcc853cf 100644 --- a/data-browser/package.json +++ b/data-browser/package.json @@ -25,8 +25,8 @@ "react-intersection-observer": "^8.31.1", "react-is": "^18", "react-markdown": "^8.0.3", - "react-router-dom": "^6.0.0", "react-router": "^6.0.0", + "react-router-dom": "^6.0.0", "remark-gfm": "^3.0.1", "styled-components": "^5.3.3", "yamde": "^1.7.1" @@ -42,6 +42,8 @@ "gh-pages": "^3.1.0", "lint-staged": "^10.5.4", "types-wm": "^1.1.0", + "vite": "^3.0.5", + "vite-plugin-pwa": "^0.13.1", "workbox-cli": "^6.4.1" }, "homepage": "https://atomicdata.dev/", diff --git a/data-browser/public/safari-pinned-tab.svg b/data-browser/public/mask-icon.svg similarity index 100% rename from data-browser/public/safari-pinned-tab.svg rename to data-browser/public/mask-icon.svg diff --git a/data-browser/public/maskable_icon.png b/data-browser/public/maskable_icon.png new file mode 100644 index 000000000..b5f4c2642 Binary files /dev/null and b/data-browser/public/maskable_icon.png differ diff --git a/data-browser/public/maskable_icon_x128.png b/data-browser/public/maskable_icon_x128.png new file mode 100644 index 000000000..647954c2a Binary files /dev/null and b/data-browser/public/maskable_icon_x128.png differ diff --git a/data-browser/public/maskable_icon_x192.png b/data-browser/public/maskable_icon_x192.png new file mode 100644 index 000000000..0d4673142 Binary files /dev/null and b/data-browser/public/maskable_icon_x192.png differ diff --git a/data-browser/public/maskable_icon_x384.png b/data-browser/public/maskable_icon_x384.png new file mode 100644 index 000000000..a6cc0828f Binary files /dev/null and b/data-browser/public/maskable_icon_x384.png differ diff --git a/data-browser/public/maskable_icon_x512.png b/data-browser/public/maskable_icon_x512.png new file mode 100644 index 000000000..334875576 Binary files /dev/null and b/data-browser/public/maskable_icon_x512.png differ diff --git a/data-browser/public/robots.txt b/data-browser/public/robots.txt new file mode 100644 index 000000000..c2a49f4fb --- /dev/null +++ b/data-browser/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Allow: / diff --git a/data-browser/public/site.webmanifest b/data-browser/public/site.webmanifest deleted file mode 100644 index 9728ac76f..000000000 --- a/data-browser/public/site.webmanifest +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "Atomic Data Browser", - "short_name": "Atomic", - "start_url": "/", - "icons": [ - { - "src": "/android-chrome-192x192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "/android-chrome-512x512.png", - "sizes": "512x512", - "type": "image/png" - } - ], - "theme_color": "#ffffff", - "background_color": "#ffffff", - "display": "standalone" -} diff --git a/data-browser/public/sw.js b/data-browser/public/sw.js deleted file mode 100644 index 49284b905..000000000 --- a/data-browser/public/sw.js +++ /dev/null @@ -1,3 +0,0 @@ -self.addEventListener('install', () => { - // TODO: Do something. -}); diff --git a/data-browser/src/App.tsx b/data-browser/src/App.tsx index 61e012581..98acf996e 100644 --- a/data-browser/src/App.tsx +++ b/data-browser/src/App.tsx @@ -22,6 +22,15 @@ import toast from 'react-hot-toast'; import { DialogContainer } from './components/Dialog/DialogContainer'; import { registerHandlers } from './handlers'; import { ErrorBoundary } from './views/ErrorPage'; +import { NetworkIndicator } from './components/NetworkIndicator'; + +function fixDevUrl(url: string) { + if (isDev()) { + return url.replace('5173', '9883'); + } + + return url; +} /** Initialize the store */ const store = new Store(); @@ -30,11 +39,8 @@ const store = new Store(); * In dev envs, we want to default to port 9883 */ const currentOrigin = window.location.origin; -store.setServerUrl( - currentOrigin === 'http://localhost:5173' - ? 'http://localhost:9883' - : currentOrigin, -); + +store.setServerUrl(fixDevUrl(currentOrigin)); /** Show an error when things go wrong */ store.errorHandler = e => { @@ -86,16 +92,17 @@ function App(): JSX.Element { + {/* @ts-ignore TODO: Check if types are fixed or upgrade styled-components to 6.0.0 */} + {/* @ts-ignore fallback component type too strict */} - {/* @ts-ignore TODO: Check if types are fixed or upgrade styled-components to 6.0.0 */} - + diff --git a/data-browser/src/components/ErrorLook.ts b/data-browser/src/components/ErrorLook.ts deleted file mode 100644 index aac007685..000000000 --- a/data-browser/src/components/ErrorLook.ts +++ /dev/null @@ -1,6 +0,0 @@ -import styled from 'styled-components'; - -export const ErrorLook = styled.span` - color: ${props => props.theme.colors.alert}; - font-family: monospace; -`; diff --git a/data-browser/src/components/ErrorLook.tsx b/data-browser/src/components/ErrorLook.tsx new file mode 100644 index 000000000..efacc8694 --- /dev/null +++ b/data-browser/src/components/ErrorLook.tsx @@ -0,0 +1,62 @@ +import { lighten } from 'polished'; +import styled from 'styled-components'; +import React from 'react'; +import { Details } from './Details'; +import { FaExclamationTriangle } from 'react-icons/fa'; + +export const ErrorLook = styled.span` + color: ${props => props.theme.colors.alert}; + font-family: monospace; +`; + +export interface ErrorBlockProps { + error: Error; + showTrace?: boolean; +} + +export function ErrorBlock({ error, showTrace }: ErrorBlockProps): JSX.Element { + return ( + + + + Something went wrong + +
Show Details}> +
+          {error.message}
+        
+ {showTrace && ( + <> + Stack trace: +
+              {error.stack}
+            
+ + )} +
+
+ ); +} + +const ErrorLookBig = styled.div` + background-color: ${p => lighten(0.4, p.theme.colors.alert)}; + color: ${p => p.theme.colors.alert}; + font-size: 1rem; + padding: ${p => p.theme.margin}rem; + border-radius: ${p => p.theme.radius}; + border: 1px solid ${p => lighten(0.2, p.theme.colors.alert)}; +`; + +const CodeBlock = styled.code` + white-space: pre-wrap; + border-radius: ${p => p.theme.radius}; + padding: ${p => p.theme.margin}rem; + background-color: ${p => p.theme.colors.bg}; +`; + +const BiggerText = styled.p` + font-size: 1.3rem; + display: flex; + align-items: center; + gap: 1ch; +`; diff --git a/data-browser/src/components/Navigation.tsx b/data-browser/src/components/Navigation.tsx index 80dc0e35b..35986a936 100644 --- a/data-browser/src/components/Navigation.tsx +++ b/data-browser/src/components/Navigation.tsx @@ -14,6 +14,7 @@ import { shortcuts } from './HotKeyWrapper'; import { MenuBarDropdownTrigger } from './ResourceContextMenu/MenuBarDropdownTrigger'; import { NavBarSpacer } from './NavBarSpacer'; import { Searchbar } from './Searchbar'; +import { useMediaQuery } from '../hooks/useMediaQuery'; interface NavWrapperProps { children: React.ReactNode; @@ -60,20 +61,26 @@ const Content = styled.div` `; /** Persistently shown navigation bar */ -function NavBar() { +function NavBar(): JSX.Element { const [subject] = useCurrentSubject(); const navigate = useNavigate(); const { navbarTop, navbarFloating, sideBarLocked, setSideBarLocked } = useSettings(); const [showButtons, setShowButtons] = React.useState(true); - /** Checks if the app is running in PWA / stand alone mode or in a browser */ - const isInStandaloneMode = () => - window.matchMedia('(display-mode: standalone)').matches || - // @ts-ignore standalone doesn't exist, but it does - window.navigator.standalone || - document.referrer.includes('android-app://') || - isRunningInTauri(); + const machesStandalone = useMediaQuery( + '(display-mode: standalone) or (display-mode: fullscreen)', + ); + + const isInStandaloneMode = React.useMemo( + () => + machesStandalone || + //@ts-ignore + window.navigator.standalone || + document.referrer.includes('android-app://') || + isRunningInTauri(), + [machesStandalone], + ); /** Hide buttons if the input element is quite small */ function maybeHideButtons(event: React.FocusEvent) { @@ -101,19 +108,19 @@ function NavBar() { > - {isInStandaloneMode() && ( + {isInStandaloneMode && ( <> navigate(1)} + onClick={() => navigate(-1)} > {' '} navigate(-1)} + onClick={() => navigate(1)} > diff --git a/data-browser/src/components/NetworkIndicator.tsx b/data-browser/src/components/NetworkIndicator.tsx new file mode 100644 index 000000000..f9e032bff --- /dev/null +++ b/data-browser/src/components/NetworkIndicator.tsx @@ -0,0 +1,63 @@ +import React, { useEffect } from 'react'; +import styled, { keyframes } from 'styled-components'; +import { MdSignalWifiOff } from 'react-icons/md'; +import { useOnline } from '../hooks/useOnline'; +import { lighten } from 'polished'; +import toast from 'react-hot-toast'; + +export function NetworkIndicator() { + const isOnline = useOnline(); + + useEffect(() => { + if (!isOnline) { + toast.error('You are offline, changes might not be persisted.'); + } + }, [isOnline]); + + return ( + + + + ); +} + +interface WrapperProps { + shown: boolean; +} + +const pulse = keyframes` + 0% { + opacity: 1; + filter: drop-shadow(0 0 5px var(--shadow-color)); + } + 100% { + opacity: 0.8; + filter: drop-shadow(0 0 0 var(--shadow-color)); + } +`; + +const Wrapper = styled.div` + --shadow-color: ${p => lighten(0.15, p.theme.colors.alert)}; + position: fixed; + bottom: 1.2rem; + right: 2rem; + z-index: ${({ theme }) => theme.zIndex.networkIndicator}; + font-size: 1.5rem; + color: ${p => p.theme.colors.alert}; + pointer-events: ${p => (p.shown ? 'auto' : 'none')}; + transition: opacity 0.1s ease-in-out; + opacity: ${p => (p.shown ? 1 : 0)}; + + background-color: ${p => p.theme.colors.bg}; + border: 1px solid ${p => p.theme.colors.alert}; + border-radius: 50%; + display: grid; + place-items: center; + box-shadow: ${p => p.theme.boxShadowSoft}; + padding: 0.5rem; + + svg { + animation: ${pulse} 1.5s alternate ease-in-out infinite; + animation-play-state: ${p => (p.shown ? 'running' : 'paused')}; + } +`; diff --git a/data-browser/src/components/Searchbar.tsx b/data-browser/src/components/Searchbar.tsx index 8fd0618fa..a792be217 100644 --- a/data-browser/src/components/Searchbar.tsx +++ b/data-browser/src/components/Searchbar.tsx @@ -97,8 +97,11 @@ export function Searchbar({ ); useEffect(() => { - setInput(query?.toString()); - setInputFocus(); + setInput(query ?? ''); + + if (query || scope) { + setInputFocus(); + } }, [query, scope]); return ( diff --git a/data-browser/src/components/SideBar/AppMenu.tsx b/data-browser/src/components/SideBar/AppMenu.tsx new file mode 100644 index 000000000..ac74bcddd --- /dev/null +++ b/data-browser/src/components/SideBar/AppMenu.tsx @@ -0,0 +1,85 @@ +import React, { + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from 'react'; +import { FaPlusCircle } from 'react-icons/fa'; +import { constructOpenURL } from '../../helpers/navigation'; +import { useCurrentSubject } from '../../helpers/useCurrentSubject'; +import { appMenuItems } from './menuItems'; +import { SideBarHeader } from './SideBarHeader'; +import { SideBarMenuItem } from './SideBarMenuItem'; + +// Non standard event type so we have to type it ourselfs for now. +type BeforeInstallPromptEvent = { + preventDefault: () => void; + prompt: () => Promise<{ outcome: 'accepted' | 'dismissed' }>; +}; + +export interface AppMenuProps { + onItemClick: () => void; +} + +export function AppMenu({ onItemClick }: AppMenuProps): JSX.Element { + const event = useRef(null); + const [subject] = useCurrentSubject(); + const [showInstallButton, setShowInstallButton] = useState(false); + + const install = useCallback(() => { + if (!event.current) { + return; + } + + event.current.prompt().then(result => { + if (result.outcome === 'accepted') { + setShowInstallButton(false); + } + }); + }, [event.current]); + + useEffect(() => { + const listener = (e: BeforeInstallPromptEvent) => { + e.preventDefault(); + setShowInstallButton(true); + event.current = e; + }; + + //@ts-ignore + window.addEventListener('beforeinstallprompt', listener); + + //@ts-ignore + return () => window.removeEventListener('beforeinstallprompt', listener); + }, []); + + const items = useMemo(() => { + if (!showInstallButton) { + return appMenuItems; + } + + return [ + { + icon: , + label: 'Install App', + helper: 'Install app to desktop', + handleClickItem: install, + path: constructOpenURL(subject ?? window.location.href), + }, + ...appMenuItems, + ]; + }, [appMenuItems, showInstallButton, subject]); + + return ( + <> + App + {items.map(p => ( + + ))} + + ); +} diff --git a/data-browser/src/components/SideBar/index.tsx b/data-browser/src/components/SideBar/index.tsx index d2172129c..42ab31cf9 100644 --- a/data-browser/src/components/SideBar/index.tsx +++ b/data-browser/src/components/SideBar/index.tsx @@ -3,14 +3,12 @@ import * as React from 'react'; import { useHover } from '../../helpers/useHover'; import { useSettings } from '../../helpers/AppSettings'; import { useWindowSize } from '../../helpers/useWindowSize'; -import { appMenuItems } from './menuItems'; -import { SideBarMenuItem } from './SideBarMenuItem'; import { SideBarDrive } from './SideBarDrive'; -import { SideBarHeader } from './SideBarHeader'; import { DragAreaBase, useResizable } from '../../hooks/useResizable'; import { useCombineRefs } from '../../hooks/useCombineRefs'; -import { About } from './About'; import { NavBarSpacer } from '../NavBarSpacer'; +import { AppMenu } from './AppMenu'; +import { About } from './About'; /** Amount of pixels where the sidebar automatically shows */ export const SIDEBAR_TOGGLE_WIDTH = 600; @@ -57,17 +55,10 @@ export function SideBar(): JSX.Element { {/* The key is set to make sure the component is re-loaded when the baseURL changes */} - - App - {appMenuItems.map(p => ( - - ))}{' '} + + - + @@ -112,7 +103,7 @@ const SideBarStyled = styled('nav').attrs(p => ({ overflow-x: hidden; `; -const SideBarBottom = styled('div')` +const MenuWrapper = styled.div` margin-top: auto; flex-direction: column; justify-items: flex-end; diff --git a/data-browser/src/components/SideBar/menuItems.tsx b/data-browser/src/components/SideBar/menuItems.tsx index e4fb6c552..83073f54b 100644 --- a/data-browser/src/components/SideBar/menuItems.tsx +++ b/data-browser/src/components/SideBar/menuItems.tsx @@ -6,25 +6,25 @@ import { SideBarMenuItemProps } from './SideBarMenuItem'; export const appMenuItems: SideBarMenuItemProps[] = [ { icon: , - label: 'user settings', + label: 'User Settings', helper: 'See and edit the current Agent / User (u)', path: paths.agentSettings, }, { icon: , - label: 'theme settings', + label: 'Theme Settings', helper: 'Edit the theme, current Agent, and more. (t)', path: paths.themeSettings, }, { icon: , - label: 'keyboard shortcuts', + label: 'Keyboard Shortcuts', helper: 'View the keyboard shortcuts (?)', path: paths.shortcuts, }, { icon: , - label: 'about', + label: 'About', helper: 'Welcome page, tells about this app', path: paths.about, }, diff --git a/data-browser/src/components/forms/FileDropzone/useUpload.ts b/data-browser/src/components/forms/FileDropzone/useUpload.ts index b57e7ae2e..7acac3d7d 100644 --- a/data-browser/src/components/forms/FileDropzone/useUpload.ts +++ b/data-browser/src/components/forms/FileDropzone/useUpload.ts @@ -14,6 +14,10 @@ export interface UseUploadResult { error: Error | undefined; } +const opts = { + commit: true, +}; + export function useUpload(parentResource: Resource): UseUploadResult { const store = useStore(); const [isUploading, setIsUploading] = useState(false); @@ -21,6 +25,7 @@ export function useUpload(parentResource: Resource): UseUploadResult { const [subResources, setSubResources] = useArray( parentResource, properties.subResources, + opts, ); const upload = useCallback( diff --git a/data-browser/src/hooks/useMediaQuery.ts b/data-browser/src/hooks/useMediaQuery.ts new file mode 100644 index 000000000..d9f07f90c --- /dev/null +++ b/data-browser/src/hooks/useMediaQuery.ts @@ -0,0 +1,25 @@ +import { useEffect, useState } from 'react'; + +/** Watches a media query and returns a statefull result. */ +export function useMediaQuery(query: string): boolean { + const [matches, setMatches] = useState(false); + + useEffect(() => { + if (!window.matchMedia) { + return; + } + + const listener = (e: MediaQueryListEvent) => { + setMatches(e.matches); + }; + + const queryList = window.matchMedia(query); + setMatches(queryList.matches); + + queryList.addEventListener('change', listener); + + return () => queryList.removeEventListener('change', listener); + }, []); + + return matches; +} diff --git a/data-browser/src/hooks/useOnline.ts b/data-browser/src/hooks/useOnline.ts new file mode 100644 index 000000000..e806fcba5 --- /dev/null +++ b/data-browser/src/hooks/useOnline.ts @@ -0,0 +1,21 @@ +import { useEffect, useState } from 'react'; + +/** Returns true when the users device is connected to a network. */ +export function useOnline(): boolean { + const [online, setOnline] = useState(navigator.onLine); + + useEffect(() => { + const handleOnline = () => setOnline(true); + const handleOffline = () => setOnline(false); + + window.addEventListener('online', handleOnline); + window.addEventListener('offline', handleOffline); + + return () => { + window.removeEventListener('online', handleOnline); + window.removeEventListener('offline', handleOffline); + }; + }, []); + + return online; +} diff --git a/data-browser/src/styling.tsx b/data-browser/src/styling.tsx index f36f7dc03..f63e57667 100644 --- a/data-browser/src/styling.tsx +++ b/data-browser/src/styling.tsx @@ -39,7 +39,8 @@ export const zIndex = { sidebar: 10, dialog: 100, dropdown: 200, - toast: 300, + networkIndicator: 300, + toast: 400, }; /** Default animation duration in ms */ diff --git a/data-browser/src/views/CrashPage.tsx b/data-browser/src/views/CrashPage.tsx index 0b4cdeb6f..520f82586 100644 --- a/data-browser/src/views/CrashPage.tsx +++ b/data-browser/src/views/CrashPage.tsx @@ -1,9 +1,10 @@ import * as React from 'react'; import { Resource } from '@tomic/react'; -import { ContainerNarrow } from '../components/Containers'; -import { ErrorLook } from '../components/ErrorLook'; +import { ContainerWide } from '../components/Containers'; +import { ErrorBlock } from '../components/ErrorLook'; import { Button } from '../components/Button'; +import { Column, Row } from '../components/Row'; type ErrorPageProps = { resource?: Resource; @@ -21,22 +22,24 @@ function CrashPage({ clearError, }: ErrorPageProps): JSX.Element { return ( - - - {children ? children :

{JSON.stringify(error?.message)}

} - {error?.stack} -
-
- {clearError && } - -
-
+ + + {children ? children : } + + {clearError && } + + + + ); } diff --git a/data-browser/src/views/ErrorPage.tsx b/data-browser/src/views/ErrorPage.tsx index ec24136ee..c1f91e4e3 100644 --- a/data-browser/src/views/ErrorPage.tsx +++ b/data-browser/src/views/ErrorPage.tsx @@ -1,12 +1,12 @@ import * as React from 'react'; import { isUnauthorized, useStore } from '@tomic/react'; -import { ContainerNarrow } from '../components/Containers'; -import { ErrorLook } from '../components/ErrorLook'; +import { ContainerWide } from '../components/Containers'; +import { ErrorBlock } from '../components/ErrorLook'; import { Button } from '../components/Button'; import { SignInButton } from '../components/SignInButton'; import { useSettings } from '../helpers/AppSettings'; import { ResourcePageProps } from './ResourcePage'; -import { Row } from '../components/Row'; +import { Column, Row } from '../components/Row'; import CrashPage from './CrashPage'; /** @@ -20,43 +20,54 @@ function ErrorPage({ resource }: ResourcePageProps): JSX.Element { if (isUnauthorized(resource.error)) { return ( - -

Unauthorized

- {agent ? ( - <> -

{resource.error?.message}

- - - ) : ( - <> -

{"You don't have access to this, try signing in:"}

- - - )} -
+ + +

Unauthorized

+ {agent ? ( + <> + + + + + + ) : ( + <> +

{"You don't have access to this, try signing in:"}

+ + + )} +
+
); } return ( - -

⚠️ Error opening {resource.getSubject()}

- {resource.error?.message} - - - - -
+ + +

Could not open {resource.getSubject()}

+ + + + + +
+
); } diff --git a/data-browser/vite.config.js b/data-browser/vite.config.js index 3c65048e7..c4f7ed8cc 100644 --- a/data-browser/vite.config.js +++ b/data-browser/vite.config.js @@ -1,5 +1,6 @@ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; +import { VitePWA } from 'vite-plugin-pwa'; export default defineConfig({ plugins: [ @@ -15,6 +16,94 @@ export default defineConfig({ ], }, }), + VitePWA({ + registerType: 'autoUpdate', + devOptions: { + enabled: true + }, + manifest: { + name: 'Atomic Data Browser', + short_name: 'Atomic', + description: 'The easiest way to create, share and model Linked Atomic Data.', + theme_color: '#ffffff', + icons: [ + { + src: 'android-chrome-192x192.png', + sizes: '192x192', + type: 'image/png', + purpose: 'any', + }, + { + src: 'android-chrome-512x512.png', + sizes: '512x512', + type: 'image/png', + purpose: 'any', + }, + { + src: 'maskable_icon.png', + sizes: '1024x1024', + type: 'image/png', + purpose: 'maskable', + }, + { + src: 'maskable_icon_x512.png', + sizes: '512x512', + type: 'image/png', + purpose: 'maskable', + }, + { + src: 'maskable_icon_x384.png', + sizes: '384x384', + type: 'image/png', + purpose: 'maskable', + }, + { + src: 'maskable_icon_x192.png', + sizes: '192x192', + type: 'image/png', + purpose: 'maskable', + }, + { + src: 'maskable_icon_x128.png', + sizes: '128x128', + type: 'image/png', + purpose: 'maskable', + }, + ] + }, + workbox: { + runtimeCaching: [ + { + urlPattern: /^https:\/\/fonts\.googleapis\.com\/.*/i, + handler: 'CacheFirst', + options: { + cacheName: 'google-fonts-cache', + expiration: { + maxEntries: 10, + maxAgeSeconds: 60 * 60 * 24 * 365 // <== 365 days + }, + cacheableResponse: { + statuses: [0, 200] + } + } + }, + { + urlPattern: /^https:\/\/fonts\.gstatic\.com\/.*/i, + handler: 'CacheFirst', + options: { + cacheName: 'gstatic-fonts-cache', + expiration: { + maxEntries: 10, + maxAgeSeconds: 60 * 60 * 24 * 365 // <== 365 days + }, + cacheableResponse: { + statuses: [0, 200] + }, + } + } + ] + } + }), ], references: [{ path: 'lib' }, { path: 'react' }], optimizeDeps: { diff --git a/data-browser/workbox-config.js b/data-browser/workbox-config.js deleted file mode 100644 index 7320ef078..000000000 --- a/data-browser/workbox-config.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = { - globDirectory: './', - globPatterns: [ - '**/*.{ts,png,xml,ico,html,css,svg,webmanifest,js,jsx,tsx,log}', - ], - ignoreURLParametersMatching: [/^utm_/, /^fbclid$/], - swDest: 'publish/sw.js', -}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4ccebc2e8..a4dfd1cdb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -106,6 +106,8 @@ importers: remark-gfm: ^3.0.1 styled-components: ^5.3.3 types-wm: ^1.1.0 + vite: ^3.0.5 + vite-plugin-pwa: ^0.13.1 workbox-cli: ^6.4.1 yamde: ^1.7.1 dependencies: @@ -146,6 +148,8 @@ importers: gh-pages: 3.2.3 lint-staged: 10.5.4 types-wm: 1.1.0 + vite: 3.0.5 + vite-plugin-pwa: 0.13.1_vite@3.0.5 workbox-cli: 6.4.1 lib: @@ -227,6 +231,18 @@ packages: leven: 3.1.0 dev: true + /@apideck/better-ajv-errors/0.3.6_ajv@8.8.0: + resolution: {integrity: sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==} + engines: {node: '>=10'} + peerDependencies: + ajv: '>=8' + dependencies: + ajv: 8.8.0 + json-schema: 0.4.0 + jsonpointer: 5.0.0 + leven: 3.1.0 + dev: true + /@babel/code-frame/7.18.6: resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} engines: {node: '>=6.9.0'} @@ -1919,6 +1935,23 @@ packages: playwright-core: 1.26.0 dev: true + /@rollup/plugin-babel/5.3.0_loko3dyoqyfrad2b2tv6icqcai: + resolution: {integrity: sha512-9uIC8HZOnVLrLHxayq/PTzw+uS25E14KPUBh5ktF+18Mjo5yK0ToMMx6epY0uEgkjwJw0aBW4x2horYXh8juWw==} + engines: {node: '>= 10.0.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@types/babel__core': ^7.1.9 + rollup: ^1.20.0||^2.0.0 + peerDependenciesMeta: + '@types/babel__core': + optional: true + dependencies: + '@babel/core': 7.19.0 + '@babel/helper-module-imports': 7.18.6 + '@rollup/pluginutils': 3.1.0_rollup@2.79.1 + rollup: 2.79.1 + dev: true + /@rollup/plugin-babel/5.3.0_yzwiwxlebv3rv47aimfjn4byyu: resolution: {integrity: sha512-9uIC8HZOnVLrLHxayq/PTzw+uS25E14KPUBh5ktF+18Mjo5yK0ToMMx6epY0uEgkjwJw0aBW4x2horYXh8juWw==} engines: {node: '>= 10.0.0'} @@ -1944,13 +1977,28 @@ packages: dependencies: '@rollup/pluginutils': 3.1.0_rollup@2.77.2 '@types/resolve': 1.17.1 - builtin-modules: 3.2.0 + builtin-modules: 3.3.0 deepmerge: 4.2.2 is-module: 1.0.0 resolve: 1.22.1 rollup: 2.77.2 dev: true + /@rollup/plugin-node-resolve/11.2.1_rollup@2.79.1: + resolution: {integrity: sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==} + engines: {node: '>= 10.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0 + dependencies: + '@rollup/pluginutils': 3.1.0_rollup@2.79.1 + '@types/resolve': 1.17.1 + builtin-modules: 3.3.0 + deepmerge: 4.2.2 + is-module: 1.0.0 + resolve: 1.22.1 + rollup: 2.79.1 + dev: true + /@rollup/plugin-node-resolve/13.3.0_rollup@2.77.2: resolution: {integrity: sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==} engines: {node: '>= 10.0.0'} @@ -1976,6 +2024,16 @@ packages: rollup: 2.77.2 dev: true + /@rollup/plugin-replace/2.4.2_rollup@2.79.1: + resolution: {integrity: sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==} + peerDependencies: + rollup: ^1.20.0 || ^2.0.0 + dependencies: + '@rollup/pluginutils': 3.1.0_rollup@2.79.1 + magic-string: 0.25.7 + rollup: 2.79.1 + dev: true + /@rollup/pluginutils/3.1.0_rollup@2.77.2: resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} engines: {node: '>= 8.0.0'} @@ -1988,6 +2046,18 @@ packages: rollup: 2.77.2 dev: true + /@rollup/pluginutils/3.1.0_rollup@2.79.1: + resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} + engines: {node: '>= 8.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0 + dependencies: + '@types/estree': 0.0.39 + estree-walker: 1.0.1 + picomatch: 2.3.1 + rollup: 2.79.1 + dev: true + /@rollup/pluginutils/4.2.1: resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} engines: {node: '>= 8.0.0'} @@ -2393,8 +2463,8 @@ packages: '@types/yargs-parser': 20.2.1 dev: true - /@types/yauzl/2.9.2: - resolution: {integrity: sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==} + /@types/yauzl/2.10.0: + resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==} requiresBuild: true dependencies: '@types/node': 16.11.4 @@ -3247,7 +3317,7 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001335 + caniuse-lite: 1.0.30001425 electron-to-chromium: 1.4.131 escalade: 3.1.1 node-releases: 2.0.4 @@ -3282,11 +3352,6 @@ packages: ieee754: 1.2.1 dev: true - /builtin-modules/3.2.0: - resolution: {integrity: sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==} - engines: {node: '>=6'} - dev: true - /builtin-modules/3.3.0: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} engines: {node: '>=6'} @@ -3354,8 +3419,8 @@ packages: /camelize/1.0.0: resolution: {integrity: sha512-W2lPwkBkMZwFlPCXhIlYgxu+7gC/NUlCtdK652DAJ1JdgV0sTrvuPFshNPrFa1TY2JOkLhgdeEBplB4ezEa+xg==} - /caniuse-lite/1.0.30001335: - resolution: {integrity: sha512-ddP1Tgm7z2iIxu6QTtbZUv6HJxSaV/PZeSrWFZtbY4JZ69tOeNhBCl3HyRQgeNZKE5AOn1kpV7fhljigy0Ty3w==} + /caniuse-lite/1.0.30001425: + resolution: {integrity: sha512-/pzFv0OmNG6W0ym80P3NtapU0QEiDS3VuYAZMGoLLqiC7f6FJFe1MjpQDREGApeenD9wloeytmVDj+JLXPC6qw==} dev: true /ccount/2.0.1: @@ -4671,7 +4736,7 @@ packages: get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: - '@types/yauzl': 2.9.2 + '@types/yauzl': 2.10.0 transitivePeerDependencies: - supports-color dev: true @@ -5218,6 +5283,10 @@ packages: resolution: {integrity: sha512-IJtugpKkiVXQn5Y+LteyBCNk1N8xpGV3wWZk9EVtZWH8DYkjBn0bX1XnGP9RkyZF0sAcywa6unHqSWKe7q4LGw==} dev: true + /idb/7.1.0: + resolution: {integrity: sha512-Wsk07aAxDsntgYJY4h0knZJuTxM73eQ4reRAO+Z1liOh8eMCJ/MoDS8fCui1vGT9mnjtl1sOu3I2i/W1swPYZg==} + dev: true + /ieee754/1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} dev: true @@ -6110,6 +6179,10 @@ packages: resolution: {integrity: sha512-TYfxx36xfl52Rf1LU9HyWSLGPdYLL+SQ8/E/0yVyKG8wCCDaSrhPap0vEdlsZWRaS6tnKKLPGiEJGiREVC8kxQ==} dev: true + /json-schema/0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + dev: true + /json-stable-stringify-without-jsonify/1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -7589,6 +7662,11 @@ packages: engines: {node: '>=6'} dev: true + /pretty-bytes/6.0.0: + resolution: {integrity: sha512-6UqkYefdogmzqAZWzJ7laYeJnaXDy2/J+ZqiiMtS7t7OfpXWTlaeGMwX8U6EFvPV/YWWEKRkS8hKS4k60WHTOg==} + engines: {node: ^14.13.1 || >=16.0.0} + dev: true + /pretty-format/27.3.1: resolution: {integrity: sha512-DR/c+pvFc52nLimLROYjnXPtolawm+uWDxr4FjuLDLUn+ktWnSN851KoHwHzzqq6rfCOjkzN8FLgDrSub6UDuA==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -8174,6 +8252,18 @@ packages: terser: 5.10.0 dev: true + /rollup-plugin-terser/7.0.2_rollup@2.79.1: + resolution: {integrity: sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==} + peerDependencies: + rollup: ^2.0.0 + dependencies: + '@babel/code-frame': 7.18.6 + jest-worker: 26.6.2 + rollup: 2.79.1 + serialize-javascript: 4.0.0 + terser: 5.10.0 + dev: true + /rollup/2.77.2: resolution: {integrity: sha512-m/4YzYgLcpMQbxX3NmAqDvwLATZzxt8bIegO78FZLl+lAgKJBd1DRAOeEiZcKOIOPjxE6ewHWHNgGEalFXuz1g==} engines: {node: '>=10.0.0'} @@ -8182,6 +8272,14 @@ packages: fsevents: 2.3.2 dev: true + /rollup/2.79.1: + resolution: {integrity: sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==} + engines: {node: '>=10.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.2 + dev: true + /run-async/2.4.1: resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} engines: {node: '>=0.12.0'} @@ -8381,6 +8479,11 @@ packages: engines: {node: '>= 8'} dev: true + /source-map/0.7.4: + resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} + engines: {node: '>= 8'} + dev: true + /source-map/0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} @@ -8715,7 +8818,7 @@ packages: dependencies: acorn: 8.8.0 commander: 2.20.3 - source-map: 0.7.3 + source-map: 0.7.4 source-map-support: 0.5.20 dev: true @@ -9194,6 +9297,23 @@ packages: vfile-message: 3.1.2 dev: false + /vite-plugin-pwa/0.13.1_vite@3.0.5: + resolution: {integrity: sha512-NR3dIa+o2hzlzo4lF4Gu0cYvoMjSw2DdRc6Epw1yjmCqWaGuN86WK9JqZie4arNlE1ZuWT3CLiMdiX5wcmmUmg==} + peerDependencies: + vite: ^3.1.0 + dependencies: + debug: 4.3.4 + fast-glob: 3.2.12 + pretty-bytes: 6.0.0 + rollup: 2.79.1 + vite: 3.0.5 + workbox-build: 6.5.4 + workbox-window: 6.5.4 + transitivePeerDependencies: + - '@types/babel__core' + - supports-color + dev: true + /vite/3.0.5: resolution: {integrity: sha512-bRvrt9Tw8EGW4jj64aYFTnVg134E8hgDxyl/eEHnxiGqYk7/pTPss6CWlurqPOUzqvEoZkZ58Ws+Iu8MB87iMA==} engines: {node: ^14.18.0 || >=16.0.0} @@ -9216,7 +9336,7 @@ packages: esbuild: 0.14.54 postcss: 8.4.16 resolve: 1.22.1 - rollup: 2.77.2 + rollup: 2.79.1 optionalDependencies: fsevents: 2.3.2 dev: true @@ -9327,12 +9447,25 @@ packages: workbox-core: 6.4.1 dev: true + /workbox-background-sync/6.5.4: + resolution: {integrity: sha512-0r4INQZMyPky/lj4Ou98qxcThrETucOde+7mRGJl13MPJugQNKeZQOdIJe/1AchOP23cTqHcN/YVpD6r8E6I8g==} + dependencies: + idb: 7.1.0 + workbox-core: 6.5.4 + dev: true + /workbox-broadcast-update/6.4.1: resolution: {integrity: sha512-oz1WAEppIatucgIc49zXPsyQG6004eoKsyiJVGDyN94LIFpUDfGa+cykN32X0PaqOC9bdlj+4EjVBi0OuwkIHA==} dependencies: workbox-core: 6.4.1 dev: true + /workbox-broadcast-update/6.5.4: + resolution: {integrity: sha512-I/lBERoH1u3zyBosnpPEtcAVe5lwykx9Yg1k6f8/BGEPGaMMgZrwVrqL1uA9QZ1NGGFoyE6t9i7lBjOlDhFEEw==} + dependencies: + workbox-core: 6.5.4 + dev: true + /workbox-build/6.4.1: resolution: {integrity: sha512-cvH74tEO8SrziFrCntZ/35B0uaMZFKG+gnk3vZmKLSUTab/6MlhL+UwYXf1sMV5SD/W/v7pnFKZbdAOAg5Ne2w==} engines: {node: '>=10.0.0'} @@ -9380,12 +9513,64 @@ packages: - supports-color dev: true + /workbox-build/6.5.4: + resolution: {integrity: sha512-kgRevLXEYvUW9WS4XoziYqZ8Q9j/2ziJYEtTrjdz5/L/cTUa2XfyMP2i7c3p34lgqJ03+mTiz13SdFef2POwbA==} + engines: {node: '>=10.0.0'} + dependencies: + '@apideck/better-ajv-errors': 0.3.6_ajv@8.8.0 + '@babel/core': 7.19.0 + '@babel/preset-env': 7.16.0_@babel+core@7.19.0 + '@babel/runtime': 7.19.0 + '@rollup/plugin-babel': 5.3.0_loko3dyoqyfrad2b2tv6icqcai + '@rollup/plugin-node-resolve': 11.2.1_rollup@2.79.1 + '@rollup/plugin-replace': 2.4.2_rollup@2.79.1 + '@surma/rollup-plugin-off-main-thread': 2.2.3 + ajv: 8.8.0 + common-tags: 1.8.1 + fast-json-stable-stringify: 2.1.0 + fs-extra: 9.1.0 + glob: 7.2.0 + lodash: 4.17.21 + pretty-bytes: 5.6.0 + rollup: 2.79.1 + rollup-plugin-terser: 7.0.2_rollup@2.79.1 + source-map: 0.8.0-beta.0 + stringify-object: 3.3.0 + strip-comments: 2.0.1 + tempy: 0.6.0 + upath: 1.2.0 + workbox-background-sync: 6.5.4 + workbox-broadcast-update: 6.5.4 + workbox-cacheable-response: 6.5.4 + workbox-core: 6.5.4 + workbox-expiration: 6.5.4 + workbox-google-analytics: 6.5.4 + workbox-navigation-preload: 6.5.4 + workbox-precaching: 6.5.4 + workbox-range-requests: 6.5.4 + workbox-recipes: 6.5.4 + workbox-routing: 6.5.4 + workbox-strategies: 6.5.4 + workbox-streams: 6.5.4 + workbox-sw: 6.5.4 + workbox-window: 6.5.4 + transitivePeerDependencies: + - '@types/babel__core' + - supports-color + dev: true + /workbox-cacheable-response/6.4.1: resolution: {integrity: sha512-omXplP3miJhQwx+jfFnqO9xWgNc8CLG6EWRvTyc8R81cA/4zhqh87yj9UVH+fGUmuIXOUBPAuulSazXUsvKFWg==} dependencies: workbox-core: 6.4.1 dev: true + /workbox-cacheable-response/6.5.4: + resolution: {integrity: sha512-DCR9uD0Fqj8oB2TSWQEm1hbFs/85hXXoayVwFKLVuIuxwJaihBsLsp4y7J9bvZbqtPJ1KlCkmYVGQKrBU4KAug==} + dependencies: + workbox-core: 6.5.4 + dev: true + /workbox-cli/6.4.1: resolution: {integrity: sha512-br8uzjbL0I04Dhq17QlJy72RSKlv1o554bSUvuIYuR8EZmxHS6ZzXrYSorw/imZgBKZzmOVb2JL8zOe0f94dng==} engines: {node: '>=10.0.0'} @@ -9413,6 +9598,10 @@ packages: resolution: {integrity: sha512-5hosqpSK+48jHlj+5EHN5dtH1Ade4fqTe4+xX3U9wWK1SDaXEqXpVxdHuBqYfg75UE1PUINA0rhMZWTqeGoLFg==} dev: true + /workbox-core/6.5.4: + resolution: {integrity: sha512-OXYb+m9wZm8GrORlV2vBbE5EC1FKu71GGp0H4rjmxmF4/HLbMCoTFws87M3dFwgpmg0v00K++PImpNQ6J5NQ6Q==} + dev: true + /workbox-expiration/6.4.1: resolution: {integrity: sha512-N912AGhi95vhf2vebE3wPhnGjnR+t5W4yALDY7Pl6bcuhySNbwkkp2RjQcBB+dxrdiX2rOvavvdcf/q1LSnEyg==} dependencies: @@ -9420,6 +9609,13 @@ packages: workbox-core: 6.4.1 dev: true + /workbox-expiration/6.5.4: + resolution: {integrity: sha512-jUP5qPOpH1nXtjGGh1fRBa1wJL2QlIb5mGpct3NzepjGG2uFFBn4iiEBiI9GUmfAFR2ApuRhDydjcRmYXddiEQ==} + dependencies: + idb: 7.1.0 + workbox-core: 6.5.4 + dev: true + /workbox-google-analytics/6.4.1: resolution: {integrity: sha512-L1JQISg1CxMAlqw3HXpWB2gRYsmJ9F9OgC2/UNAZLyOJTFk1faZziPS4eXe+UaHevZ+Ma66Z2zfYxPUTr5znjQ==} dependencies: @@ -9429,12 +9625,27 @@ packages: workbox-strategies: 6.4.1 dev: true + /workbox-google-analytics/6.5.4: + resolution: {integrity: sha512-8AU1WuaXsD49249Wq0B2zn4a/vvFfHkpcFfqAFHNHwln3jK9QUYmzdkKXGIZl9wyKNP+RRX30vcgcyWMcZ9VAg==} + dependencies: + workbox-background-sync: 6.5.4 + workbox-core: 6.5.4 + workbox-routing: 6.5.4 + workbox-strategies: 6.5.4 + dev: true + /workbox-navigation-preload/6.4.1: resolution: {integrity: sha512-npgZYoeaE+teQvpWqZLgJDJ6I3qxwqAfnSIa8yrNQ2sLR1A88uWGGsiRzfUsIdKjVCLPQVZ+clwb6XU1vyW9Lw==} dependencies: workbox-core: 6.4.1 dev: true + /workbox-navigation-preload/6.5.4: + resolution: {integrity: sha512-IIwf80eO3cr8h6XSQJF+Hxj26rg2RPFVUmJLUlM0+A2GzB4HFbQyKkrgD5y2d84g2IbJzP4B4j5dPBRzamHrng==} + dependencies: + workbox-core: 6.5.4 + dev: true + /workbox-precaching/6.4.1: resolution: {integrity: sha512-Sq8d+/wfcXFjwuVwKe2VxD4QddRBgkO6pJVgpHbk5WFynR8dc8Zj3BlJ38e4nMlRuBZ8996TIgAmk/U6Rr5YHQ==} dependencies: @@ -9443,12 +9654,26 @@ packages: workbox-strategies: 6.4.1 dev: true + /workbox-precaching/6.5.4: + resolution: {integrity: sha512-hSMezMsW6btKnxHB4bFy2Qfwey/8SYdGWvVIKFaUm8vJ4E53JAY+U2JwLTRD8wbLWoP6OVUdFlXsTdKu9yoLTg==} + dependencies: + workbox-core: 6.5.4 + workbox-routing: 6.5.4 + workbox-strategies: 6.5.4 + dev: true + /workbox-range-requests/6.4.1: resolution: {integrity: sha512-X/asYHeuWIKg5Tk+dfmiEOo9hlkQ1K737dnENj8zL97kZDdcfokPT5CuXgM2xqX7NMoahONq1Eo2UoFfJNjZzg==} dependencies: workbox-core: 6.4.1 dev: true + /workbox-range-requests/6.5.4: + resolution: {integrity: sha512-Je2qR1NXCFC8xVJ/Lux6saH6IrQGhMpDrPXWZWWS8n/RD+WZfKa6dSZwU+/QksfEadJEr/NfY+aP/CXFFK5JFg==} + dependencies: + workbox-core: 6.5.4 + dev: true + /workbox-recipes/6.4.1: resolution: {integrity: sha512-Yu9tLmgD25NorZPO3FHJUii/Y2ghrx2jD2QKMaWBBplshw1MFokqlmr3Dz3O6NI8jBBUnK5Dtbl0+SCwVGSCqg==} dependencies: @@ -9460,18 +9685,41 @@ packages: workbox-strategies: 6.4.1 dev: true + /workbox-recipes/6.5.4: + resolution: {integrity: sha512-QZNO8Ez708NNwzLNEXTG4QYSKQ1ochzEtRLGaq+mr2PyoEIC1xFW7MrWxrONUxBFOByksds9Z4//lKAX8tHyUA==} + dependencies: + workbox-cacheable-response: 6.5.4 + workbox-core: 6.5.4 + workbox-expiration: 6.5.4 + workbox-precaching: 6.5.4 + workbox-routing: 6.5.4 + workbox-strategies: 6.5.4 + dev: true + /workbox-routing/6.4.1: resolution: {integrity: sha512-FIy27mwM3WdDASOTMX10OZ8q3Un47ULeDtDrDAKfWYIP/oTF2xoA1/HtXpOjBlyg5VP/poPX5GDojXHXAXpfzQ==} dependencies: workbox-core: 6.4.1 dev: true + /workbox-routing/6.5.4: + resolution: {integrity: sha512-apQswLsbrrOsBUWtr9Lf80F+P1sHnQdYodRo32SjiByYi36IDyL2r7BH1lJtFX8fwNHDa1QOVY74WKLLS6o5Pg==} + dependencies: + workbox-core: 6.5.4 + dev: true + /workbox-strategies/6.4.1: resolution: {integrity: sha512-2UQ+7Siy4Z5QG2LebbVhDLmPG3M7bVo/tZqN4LNUGXS6fDlpbTTK6A3Hu0W8gCVwIX0tSg7U3mVhDntH4qt3Dg==} dependencies: workbox-core: 6.4.1 dev: true + /workbox-strategies/6.5.4: + resolution: {integrity: sha512-DEtsxhx0LIYWkJBTQolRxG4EI0setTJkqR4m7r4YpBdxtWJH1Mbg01Cj8ZjNOO8etqfA3IZaOPHUxCs8cBsKLw==} + dependencies: + workbox-core: 6.5.4 + dev: true + /workbox-streams/6.4.1: resolution: {integrity: sha512-0t3QKBml3Qi37JniDfEn0FfN4JRgMK6sEcjGxvmMGwlHAyKukZr0Gj58ax1o1KYGGJr72RDBK+YXI9Sk9cKifw==} dependencies: @@ -9479,10 +9727,21 @@ packages: workbox-routing: 6.4.1 dev: true + /workbox-streams/6.5.4: + resolution: {integrity: sha512-FXKVh87d2RFXkliAIheBojBELIPnWbQdyDvsH3t74Cwhg0fDheL1T8BqSM86hZvC0ZESLsznSYWw+Va+KVbUzg==} + dependencies: + workbox-core: 6.5.4 + workbox-routing: 6.5.4 + dev: true + /workbox-sw/6.4.1: resolution: {integrity: sha512-IJNYcNbjugMB9v+Yx7uswohjOaYoimw5dI0Gcaj2zrJHKjV0bom+BPRCdijmttN/3uVbX57jhNe8SMzWMj7fHw==} dev: true + /workbox-sw/6.5.4: + resolution: {integrity: sha512-vo2RQo7DILVRoH5LjGqw3nphavEjK4Qk+FenXeUsknKn14eCNedHOXWbmnvP4ipKhlE35pvJ4yl4YYf6YsJArA==} + dev: true + /workbox-window/6.4.1: resolution: {integrity: sha512-v5G1U+NN0sHErvE9fzHRA75FrfRFj/0dihFnvno5yqHZZIb9G4U2AarodSDRBC3t6CsnLO68l1Bj1gsHqsM9Qw==} dependencies: @@ -9490,6 +9749,13 @@ packages: workbox-core: 6.4.1 dev: true + /workbox-window/6.5.4: + resolution: {integrity: sha512-HnLZJDwYBE+hpG25AQBO8RUWBJRaCsI9ksQJEp3aCOFCaG5kqaToAYXFRAHxzRluM2cQbGzdQF5rjKPWPA1fug==} + dependencies: + '@types/trusted-types': 2.0.2 + workbox-core: 6.5.4 + dev: true + /wrap-ansi/5.1.0: resolution: {integrity: sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==} engines: {node: '>=6'} diff --git a/react/src/useServerURL.ts b/react/src/useServerURL.ts index 0a1ee41b0..e361f6722 100644 --- a/react/src/useServerURL.ts +++ b/react/src/useServerURL.ts @@ -1,16 +1,7 @@ import { isValidURL } from '@tomic/lib'; import { useCallback } from 'react'; -import { isDev } from './helpers/isDev'; import { useLocalStorage, useStore } from './index'; -function fixDevUrl(url: string) { - if (isDev()) { - return url.replace('5173', '9883'); - } - - return url; -} - /** * A hook for using and adjusting the Server URL. Also saves to localStorage. If * the URL is wrong, an error is thrown using the store's handler @@ -20,7 +11,7 @@ export const useServerURL = (): [string, (serverUrl: string) => void] => { const store = useStore(); const [serverUrl, setServerUrl] = useLocalStorage( 'serverUrl', - store.getServerUrl() ?? fixDevUrl(window?.location.origin), + store.getServerUrl(), ); const set = useCallback(