├── src ├── utils │ ├── noop.ts │ ├── spacing.ts │ ├── readFileAsBase64.ts │ ├── getCurrentGeolocation.ts │ └── getCurrentWeather.ts ├── vite-env.d.ts ├── components │ ├── Box.styled.ts │ ├── Box.tsx │ ├── Panel.tsx │ ├── IconButton.tsx │ ├── settings │ │ ├── background │ │ │ ├── SettingsBackground.styled.ts │ │ │ └── SettingsBackground.tsx │ │ ├── Settings.styled.ts │ │ ├── search │ │ │ ├── SettingsSearch.styled.ts │ │ │ └── SettingsSearch.tsx │ │ └── Settings.tsx │ ├── FormSection.styled.ts │ ├── IconTab.styled.ts │ ├── FormSection.tsx │ ├── Panel.styled.ts │ ├── IconButton.styled.ts │ ├── Clock.styled.ts │ ├── IconTab.tsx │ ├── Clock.tsx │ ├── SearchBar.styled.ts │ ├── BackgroundCanvas.styled.ts │ ├── SearchBar.tsx │ └── BackgroundCanvas.tsx ├── emotion.d.ts ├── main.tsx ├── stores │ ├── session-app.ts │ └── app.ts ├── constants │ ├── searchEngines.ts │ └── weather.ts ├── App.styled.ts └── App.tsx ├── public ├── img.png ├── SUITE-Variable.woff2 └── vite.svg ├── README.md ├── res └── screenshot.png ├── .prettierrc ├── tsconfig.json ├── vite.config.ts ├── .gitignore ├── .dockerignore ├── Dockerfile ├── tsconfig.node.json ├── index.html ├── tsconfig.app.json ├── eslint.config.js ├── package.json └── pnpm-lock.yaml /src/utils/noop.ts: -------------------------------------------------------------------------------- 1 | export function noop() {} 2 | -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /public/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/async3619/startpage/HEAD/public/img.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # startpage, with some raindrops 2 | 3 | ![screenshot](./res/screenshot.png) 4 | -------------------------------------------------------------------------------- /res/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/async3619/startpage/HEAD/res/screenshot.png -------------------------------------------------------------------------------- /public/SUITE-Variable.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/async3619/startpage/HEAD/public/SUITE-Variable.woff2 -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "singleAttributePerLine": true, 4 | "semi": false, 5 | "singleQuote": true 6 | } 7 | -------------------------------------------------------------------------------- /src/components/Box.styled.ts: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled' 2 | 3 | export const Root = styled.div` 4 | border-radius: 4px; 5 | 6 | background-color: rgba(255, 255, 255, 0.3); 7 | ` 8 | -------------------------------------------------------------------------------- /src/emotion.d.ts: -------------------------------------------------------------------------------- 1 | import spacing from './utils/spacing' 2 | 3 | declare module '@emotion/react' { 4 | export interface Theme { 5 | spacing: typeof spacing 6 | contrastText: string 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "types": [ 4 | "vite-plugin-glsl/ext" 5 | ], 6 | }, 7 | "files": [], 8 | "references": [ 9 | { "path": "./tsconfig.app.json" }, 10 | { "path": "./tsconfig.node.json" } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /src/components/Box.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import * as Styled from './Box.styled' 4 | 5 | interface BoxProps extends React.HTMLAttributes {} 6 | 7 | function Box(props: BoxProps) { 8 | return 9 | } 10 | 11 | export default Box 12 | -------------------------------------------------------------------------------- /src/main.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | 4 | import 'normalize.css' 5 | 6 | import App from './App' 7 | 8 | createRoot(document.getElementById('root')!).render( 9 | 10 | 11 | , 12 | ) 13 | -------------------------------------------------------------------------------- /src/components/Panel.tsx: -------------------------------------------------------------------------------- 1 | import * as Styled from './Panel.styled' 2 | 3 | interface PanelProps { 4 | open: boolean 5 | children: React.ReactNode 6 | } 7 | 8 | function Panel({ open, children }: PanelProps) { 9 | return {children} 10 | } 11 | 12 | export default Panel 13 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import glsl from 'vite-plugin-glsl' 3 | import react from '@vitejs/plugin-react' 4 | import tsconfigPaths from 'vite-tsconfig-paths' 5 | 6 | // https://vite.dev/config/ 7 | export default defineConfig({ 8 | plugins: [react(), glsl(), tsconfigPaths()], 9 | }) 10 | -------------------------------------------------------------------------------- /src/components/IconButton.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import * as Styled from './IconButton.styled' 3 | 4 | type ButtonProps = React.HTMLAttributes 5 | 6 | function IconButton({ children, ...rest }: ButtonProps) { 7 | return {children} 8 | } 9 | 10 | export default IconButton 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /src/stores/session-app.ts: -------------------------------------------------------------------------------- 1 | import { create } from 'zustand' 2 | 3 | interface SessionAppStore { 4 | isReady: boolean 5 | setIsReady: (isReady: boolean) => void 6 | } 7 | 8 | const useSessionAppStore = create((set) => ({ 9 | isReady: false, 10 | setIsReady: (isReady: boolean) => set({ isReady }), 11 | })) 12 | 13 | export default useSessionAppStore 14 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | # Node modules 2 | node_modules 3 | 4 | # Build artifacts 5 | dist 6 | 7 | # Local configuration files 8 | *.tsbuildinfo 9 | 10 | # Environment variables 11 | .env 12 | .env.local 13 | .env.*.local 14 | 15 | # IDE/editor files 16 | .vscode 17 | .idea 18 | *.sublime-project 19 | *.sublime-workspace 20 | 21 | # Logs 22 | *.log 23 | 24 | # Other unnecessary files 25 | .DS_Store 26 | Thumbs.db 27 | README.md 28 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Stage 1: Build 2 | 3 | FROM node:20-alpine AS build 4 | 5 | RUN npm install -g pnpm 6 | 7 | WORKDIR /app 8 | COPY . . 9 | 10 | RUN pnpm install --frozen-lockfile 11 | 12 | # TODO Add checks 13 | 14 | RUN pnpm run build 15 | 16 | 17 | # Stage 2: Serve 18 | 19 | FROM caddy:alpine 20 | 21 | COPY --from=build /app/dist /usr/share/caddy 22 | 23 | EXPOSE 80 24 | CMD ["caddy", "file-server", "--root", "/usr/share/caddy"] 25 | -------------------------------------------------------------------------------- /src/utils/spacing.ts: -------------------------------------------------------------------------------- 1 | function spacing( 2 | top: number, 3 | right: number, 4 | bottom: number, 5 | left: number, 6 | ): string 7 | function spacing(top: number, leftRight: number, bottom: number): string 8 | function spacing(vertical: number, horizontal: number): string 9 | function spacing(all: number): string 10 | 11 | function spacing(...args: number[]): string { 12 | return args.map((value) => `${value * 8}px`).join(' ') 13 | } 14 | 15 | export default spacing 16 | -------------------------------------------------------------------------------- /src/components/settings/background/SettingsBackground.styled.ts: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled' 2 | import IconButton from '@components/IconButton' 3 | 4 | export const FileInput = styled.input` 5 | display: none; 6 | ` 7 | 8 | export const RangeInput = styled.input` 9 | width: 100%; 10 | ` 11 | 12 | export const UploadButton = styled.button` 13 | width: 100%; 14 | 15 | padding: ${({ theme }) => theme.spacing(1)}; 16 | 17 | display: block; 18 | ` 19 | 20 | export const Button = styled(IconButton)`` 21 | -------------------------------------------------------------------------------- /src/components/FormSection.styled.ts: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled' 2 | 3 | export const Title = styled.h6` 4 | margin: 0 0 ${({ theme }) => theme.spacing(1)}; 5 | font-size: 1rem; 6 | ` 7 | 8 | export const Description = styled.p` 9 | margin: 0 0 ${({ theme }) => theme.spacing(1)}; 10 | font-size: 0.875rem; 11 | ` 12 | 13 | export const Content = styled.div`` 14 | 15 | export const Root = styled.section` 16 | &:not(:last-of-type) { 17 | margin: 0 0 ${({ theme }) => theme.spacing(2)}; 18 | } 19 | ` 20 | -------------------------------------------------------------------------------- /src/utils/readFileAsBase64.ts: -------------------------------------------------------------------------------- 1 | function readFileAsBase64(file: File): Promise { 2 | return new Promise((resolve, reject) => { 3 | const reader = new FileReader() 4 | reader.onload = () => { 5 | const result = reader.result 6 | if (typeof result === 'string') { 7 | resolve(result) 8 | } else { 9 | reject(new Error('Failed to read file as base64')) 10 | } 11 | } 12 | reader.onerror = reject 13 | reader.readAsDataURL(file) 14 | }) 15 | } 16 | 17 | export default readFileAsBase64 18 | -------------------------------------------------------------------------------- /src/components/IconTab.styled.ts: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled' 2 | 3 | export const Root = styled.div` 4 | display: flex; 5 | ` 6 | 7 | export const Item = styled.button<{ selected: boolean }>` 8 | margin: 0; 9 | padding: ${({ theme }) => theme.spacing(0.75)}; 10 | border: 0; 11 | 12 | background-color: rgba(255, 255, 255, 0.3); 13 | 14 | cursor: pointer; 15 | opacity: ${({ selected }) => (selected ? 1 : 0.5)}; 16 | 17 | > svg { 18 | width: 20px; 19 | height: 20px; 20 | 21 | display: block; 22 | 23 | fill: white; 24 | } 25 | ` 26 | -------------------------------------------------------------------------------- /src/components/FormSection.tsx: -------------------------------------------------------------------------------- 1 | import * as Styled from './FormSection.styled' 2 | 3 | interface FormSectionProps { 4 | title: string 5 | description?: string 6 | children?: React.ReactNode 7 | } 8 | 9 | function FormSection({ description, title, children }: FormSectionProps) { 10 | return ( 11 | 12 | {title} 13 | {description && {description}} 14 | {children} 15 | 16 | ) 17 | } 18 | 19 | export default FormSection 20 | -------------------------------------------------------------------------------- /src/constants/searchEngines.ts: -------------------------------------------------------------------------------- 1 | export const SEARCH_ENGINES: Record< 2 | string, 3 | { 4 | name: string 5 | url: string 6 | } 7 | > = { 8 | google: { 9 | name: 'Google', 10 | url: 'https://www.google.com/search?q={}', 11 | }, 12 | duckduckgo: { 13 | name: 'DuckDuckGo', 14 | url: 'https://duckduckgo.com/?q={}', 15 | }, 16 | 'searx.be': { 17 | name: 'Searx.be', 18 | url: 'https://searx.be/?q={}', 19 | }, 20 | custom: { 21 | name: 'Custom', 22 | url: '', 23 | }, 24 | } 25 | 26 | export type SearchEngineOption = keyof typeof SEARCH_ENGINES 27 | -------------------------------------------------------------------------------- /src/utils/getCurrentGeolocation.ts: -------------------------------------------------------------------------------- 1 | export interface LatLng { 2 | lat: number 3 | lng: number 4 | } 5 | 6 | function getCurrentGeolocation() { 7 | return new Promise((resolve, reject) => { 8 | navigator.geolocation.getCurrentPosition( 9 | (position) => { 10 | resolve({ 11 | lat: position.coords.latitude, 12 | lng: position.coords.longitude, 13 | }) 14 | }, 15 | (error) => { 16 | reject(error) 17 | }, 18 | { enableHighAccuracy: true }, 19 | ) 20 | }) 21 | } 22 | 23 | export default getCurrentGeolocation 24 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "lib": ["ES2023"], 5 | "module": "ESNext", 6 | "skipLibCheck": true, 7 | 8 | /* Bundler mode */ 9 | "moduleResolution": "Bundler", 10 | "allowImportingTsExtensions": true, 11 | "isolatedModules": true, 12 | "moduleDetection": "force", 13 | "noEmit": true, 14 | 15 | /* Linting */ 16 | "strict": true, 17 | "noUnusedLocals": true, 18 | "noUnusedParameters": true, 19 | "noFallthroughCasesInSwitch": true, 20 | "noUncheckedSideEffectImports": true 21 | }, 22 | "include": ["vite.config.ts"] 23 | } 24 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | New Tab 13 | 14 | 15 |
16 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/components/Panel.styled.ts: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled' 2 | 3 | export const Root = styled.div<{ visible: boolean }>` 4 | padding: ${({ theme }) => theme.spacing(2)}; 5 | border-radius: 4px; 6 | 7 | position: absolute; 8 | top: 0; 9 | right: 0; 10 | 11 | visibility: ${({ visible }) => (visible ? 'visible' : 'hidden')}; 12 | 13 | color: #fff; 14 | background-color: rgba(255, 255, 255, 0.3); 15 | 16 | opacity: ${({ visible }) => (visible ? 1 : 0)}; 17 | transform: translateY(-100%) 18 | translateY(${({ theme, visible }) => theme.spacing(visible ? -1 : 0)}); 19 | backdrop-filter: blur(16px); 20 | 21 | transition: 22 | background-color 0.2s ease, 23 | opacity 0.2s ease, 24 | transform 0.2s ease; 25 | ` 26 | -------------------------------------------------------------------------------- /src/components/IconButton.styled.ts: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled' 2 | 3 | export const Root = styled.button` 4 | margin: 0; 5 | padding: ${({ theme }) => theme.spacing(1)}; 6 | border: none; 7 | border-radius: 4px; 8 | 9 | background-color: rgba(255, 255, 255, 0.3); 10 | 11 | transition: background-color 0.2s ease; 12 | 13 | outline: none; 14 | cursor: pointer; 15 | 16 | backdrop-filter: blur(16px); 17 | 18 | &:hover, 19 | &:focus-visible { 20 | background-color: rgba(255, 255, 255, 0.5); 21 | } 22 | 23 | &:active { 24 | background-color: rgba(255, 255, 255, 0.3); 25 | } 26 | 27 | > svg { 28 | width: ${({ theme }) => theme.spacing(3)}; 29 | height: ${({ theme }) => theme.spacing(3)}; 30 | 31 | display: block; 32 | 33 | fill: #fff; 34 | } 35 | ` 36 | -------------------------------------------------------------------------------- /src/components/Clock.styled.ts: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled' 2 | 3 | export const Root = styled.div` 4 | display: flex; 5 | flex-direction: column; 6 | 7 | user-select: none; 8 | ` 9 | 10 | export const Date = styled.span` 11 | display: block; 12 | 13 | font-size: 28px; 14 | font-family: 'Azeret Mono', monospace; 15 | font-optical-sizing: auto; 16 | font-weight: 400; 17 | font-style: normal; 18 | text-align: center; 19 | 20 | color: rgba(255, 255, 255, 0.5); 21 | ` 22 | 23 | export const Weather = styled(Date)` 24 | margin-top: 8px; 25 | 26 | font-size: 18px; 27 | ` 28 | 29 | export const Time = styled.span` 30 | display: block; 31 | 32 | font-size: 94px; 33 | font-family: 'Azeret Mono', monospace; 34 | font-optical-sizing: auto; 35 | font-weight: 400; 36 | font-style: normal; 37 | 38 | color: rgba(255, 255, 255, 0.75); 39 | ` 40 | -------------------------------------------------------------------------------- /src/components/IconTab.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import * as Styled from './IconTab.styled' 4 | 5 | export interface IconTabItem { 6 | value: TValue 7 | icon: React.ComponentType 8 | } 9 | 10 | interface IconTabProps { 11 | value: TValue 12 | onChange: (value: TValue) => void 13 | items: IconTabItem[] 14 | } 15 | 16 | function IconTab({ 17 | value: currentValue, 18 | items, 19 | onChange, 20 | }: IconTabProps) { 21 | return ( 22 | 23 | {items.map(({ icon: Icon, value }) => ( 24 | onChange(value)} 27 | selected={value === currentValue} 28 | > 29 | 30 | 31 | ))} 32 | 33 | ) 34 | } 35 | 36 | export default IconTab 37 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | "baseUrl": ".", 9 | 10 | /* Bundler mode */ 11 | "moduleResolution": "Bundler", 12 | "allowImportingTsExtensions": false, 13 | "isolatedModules": true, 14 | "moduleDetection": "force", 15 | "noEmit": true, 16 | "jsx": "react-jsx", 17 | 18 | /* Linting */ 19 | "strict": true, 20 | "noUnusedLocals": true, 21 | "noUnusedParameters": true, 22 | "noFallthroughCasesInSwitch": true, 23 | "noUncheckedSideEffectImports": true, 24 | 25 | "paths": { 26 | "@components/*": ["src/components/*"], 27 | "@utils/*": ["src/utils/*"], 28 | "@stores/*": ["src/stores/*"], 29 | "@constants/*": ["src/constants/*"], 30 | } 31 | }, 32 | "include": ["src"] 33 | } 34 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import js from '@eslint/js' 2 | import globals from 'globals' 3 | import reactHooks from 'eslint-plugin-react-hooks' 4 | import reactRefresh from 'eslint-plugin-react-refresh' 5 | import tseslint from 'typescript-eslint' 6 | 7 | export default tseslint.config( 8 | { ignores: ['dist'] }, 9 | { 10 | extends: [js.configs.recommended, ...tseslint.configs.recommended], 11 | files: ['**/*.{ts,tsx}'], 12 | languageOptions: { 13 | ecmaVersion: 2020, 14 | globals: globals.browser, 15 | }, 16 | plugins: { 17 | 'react-hooks': reactHooks, 18 | 'react-refresh': reactRefresh, 19 | }, 20 | rules: { 21 | ...reactHooks.configs.recommended.rules, 22 | 'no-empty-pattern': 'off', 23 | '@typescript-eslint/no-empty-object-type': 'off', 24 | 'react-refresh/only-export-components': [ 25 | 'warn', 26 | { allowConstantExport: true }, 27 | ], 28 | }, 29 | }, 30 | ) 31 | -------------------------------------------------------------------------------- /src/components/Clock.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react' 2 | 3 | import dayjs from 'dayjs' 4 | 5 | import useAppStore from '@stores/app' 6 | 7 | import * as Styled from './Clock.styled' 8 | 9 | function Clock() { 10 | const [time, setTime] = useState(() => dayjs()) 11 | const weather = useAppStore((store) => store.weather?.weather) 12 | 13 | useEffect(() => { 14 | const interval = setInterval(() => { 15 | setTime(dayjs()) 16 | }, 500) 17 | 18 | return () => { 19 | clearInterval(interval) 20 | } 21 | }, []) 22 | 23 | return ( 24 | 25 | {time.format('HH·mm·ss')} 26 | {time.format('YYYY·MM·DD')} 27 | {weather && ( 28 | 29 | {weather.weatherName} {Math.round(weather.temperature * 10) / 10}°C 30 | 31 | )} 32 | 33 | ) 34 | } 35 | 36 | export default Clock 37 | -------------------------------------------------------------------------------- /src/components/SearchBar.styled.ts: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled' 2 | 3 | import Box from '@components/Box' 4 | 5 | export const Root = styled(Box)` 6 | width: 100%; 7 | max-width: 764px; 8 | 9 | margin-top: ${({ theme }) => theme.spacing(6)}; 10 | border-top-left-radius: 0; 11 | 12 | position: relative; 13 | ` 14 | 15 | export const Input = styled.input` 16 | width: 100%; 17 | 18 | margin: 0; 19 | padding: ${({ theme }) => theme.spacing(1.5, 2)}; 20 | border: 0; 21 | 22 | display: block; 23 | box-sizing: border-box; 24 | 25 | font-family: 'SUITE Variable', sans-serif; 26 | 27 | color: white; 28 | background-color: transparent; 29 | 30 | outline: none; 31 | 32 | ::placeholder { 33 | color: rgba(255, 255, 255, 0.5); 34 | } 35 | ` 36 | 37 | export const IconTabWrapper = styled.div` 38 | border-top-left-radius: 4px; 39 | border-top-right-radius: 4px; 40 | 41 | position: absolute; 42 | top: 0; 43 | left: 0; 44 | 45 | overflow: hidden; 46 | 47 | transform: translateY(-100%); 48 | ` 49 | -------------------------------------------------------------------------------- /src/App.styled.ts: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled' 2 | import { css } from '@emotion/react' 3 | 4 | export const GlobalStyles = css` 5 | @font-face { 6 | font-family: 'SUITE Variable'; 7 | font-weight: 300 900; 8 | src: url('/SUITE-Variable.woff2') format('woff2-variations'); 9 | } 10 | 11 | * { 12 | font-family: 'SUITE Variable', sans-serif; 13 | } 14 | 15 | html, 16 | body { 17 | color: white; 18 | } 19 | ` 20 | 21 | export const Root = styled.main`` 22 | 23 | export const Content = styled.div<{ isReady: boolean }>` 24 | width: 100%; 25 | 26 | padding: ${({ theme }) => theme.spacing(2)}; 27 | box-sizing: border-box; 28 | 29 | display: flex; 30 | flex-direction: column; 31 | justify-content: center; 32 | align-items: center; 33 | 34 | position: fixed; 35 | top: 0; 36 | left: 0; 37 | 38 | opacity: ${({ isReady }) => (isReady ? 1 : 0)}; 39 | 40 | transition: opacity 1s; 41 | 42 | @supports (height: 100svh) { 43 | height: 100svh; 44 | } 45 | 46 | @supports not (height: 100svh) { 47 | height: 100vh; 48 | } 49 | ` 50 | -------------------------------------------------------------------------------- /src/components/BackgroundCanvas.styled.ts: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled' 2 | 3 | export const Root = styled.div` 4 | width: 100%; 5 | height: 100%; 6 | 7 | position: fixed; 8 | top: 0; 9 | left: 0; 10 | 11 | background-color: #000; 12 | 13 | z-index: -1; 14 | ` 15 | 16 | export const Viewport = styled.canvas<{ isReady: boolean }>` 17 | width: 100%; 18 | height: 100%; 19 | 20 | display: block; 21 | position: absolute; 22 | top: 0; 23 | left: 0; 24 | z-index: 1; 25 | 26 | opacity: ${({ isReady }) => (isReady ? 1 : 0)}; 27 | 28 | transition: opacity 1s; 29 | ` 30 | 31 | export const Image = styled.img` 32 | width: 100%; 33 | height: 100%; 34 | 35 | display: block; 36 | position: absolute; 37 | top: 0; 38 | left: 0; 39 | z-index: 0; 40 | 41 | object-fit: cover; 42 | ` 43 | 44 | export const Overlay = styled.div<{ isReady: boolean; isChanging: boolean }>` 45 | width: 100%; 46 | height: 100%; 47 | 48 | position: absolute; 49 | top: 0; 50 | left: 0; 51 | z-index: 2; 52 | 53 | transition: ${({ isChanging }) => 54 | isChanging ? 'none' : 'backdrop-filter 1s'}; 55 | ` 56 | -------------------------------------------------------------------------------- /src/components/settings/Settings.styled.ts: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled' 2 | import IconButton from '@components/IconButton' 3 | 4 | export const Button = styled(IconButton)`` 5 | 6 | export const Root = styled.div` 7 | position: absolute; 8 | right: ${({ theme }) => theme.spacing(2)}; 9 | bottom: ${({ theme }) => theme.spacing(2)}; 10 | 11 | z-index: 3; 12 | ` 13 | 14 | export const Content = styled.div` 15 | width: 300px; 16 | height: 300px; 17 | ` 18 | 19 | export const TabHeader = styled.div` 20 | display: flex; 21 | justify-content: space-around; 22 | margin-bottom: 16px; 23 | gap: 8px; 24 | border-radius: 4px; 25 | ` 26 | 27 | export const TabButton = styled.button<{ isActive?: boolean }>` 28 | flex: 1; 29 | padding: 10px 0; 30 | background-color: ${({ isActive }) => (isActive ? '#444' : 'transparent')}; 31 | color: ${({ isActive }) => (isActive ? '#fff' : '#ccc')}; 32 | border: ${() => '1px solid #969696'}; 33 | border-radius: 4px; 34 | cursor: pointer; 35 | transition: 36 | color 0.3s, 37 | background-color 0.3s; 38 | 39 | &:hover { 40 | color: #fff; 41 | background-color: #444; 42 | } 43 | ` 44 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rainy-newtab", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc -b && vite build", 9 | "lint": "eslint .", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@emotion/css": "^11.13.4", 14 | "@emotion/react": "^11.13.3", 15 | "@emotion/styled": "^11.13.0", 16 | "dayjs": "^1.11.13", 17 | "lodash": "^4.17.21", 18 | "normalize.css": "^8.0.1", 19 | "openmeteo": "^1.1.4", 20 | "raindrop-fx": "^1.0.8", 21 | "react": "^18.3.1", 22 | "react-dom": "^18.3.1", 23 | "react-icons": "^5.3.0", 24 | "zustand": "^5.0.0" 25 | }, 26 | "devDependencies": { 27 | "@eslint/js": "^9.13.0", 28 | "@types/lodash": "^4.17.12", 29 | "@types/react": "^18.3.11", 30 | "@types/react-dom": "^18.3.1", 31 | "@vitejs/plugin-react": "^4.3.3", 32 | "eslint": "^9.13.0", 33 | "eslint-plugin-react-hooks": "^5.0.0", 34 | "eslint-plugin-react-refresh": "^0.4.13", 35 | "globals": "^15.11.0", 36 | "prettier": "^3.3.3", 37 | "typescript": "~5.6.2", 38 | "typescript-eslint": "^8.10.0", 39 | "vite": "^5.4.9", 40 | "vite-plugin-glsl": "^1.3.0", 41 | "vite-tsconfig-paths": "^5.0.1" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/components/settings/search/SettingsSearch.styled.ts: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled' 2 | 3 | export const Container = styled.div` 4 | position: relative; 5 | width: 200px; 6 | ` 7 | 8 | export const ToggleButton = styled.button` 9 | width: 100%; 10 | padding: 10px; 11 | background-color: #444; 12 | color: #fff; 13 | border: 0; 14 | border-radius: 4px; 15 | text-align: left; 16 | cursor: pointer; 17 | font-size: 16px; 18 | 19 | &:hover { 20 | background-color: #444; 21 | } 22 | 23 | &:after { 24 | content: '▼'; 25 | float: right; 26 | font-size: 12px; 27 | } 28 | ` 29 | 30 | export const Menu = styled.div<{ isOpen?: boolean }>` 31 | position: absolute; 32 | top: 100%; 33 | left: 0; 34 | width: 100%; 35 | background-color: #444; 36 | border-radius: 4px; 37 | margin-top: 4px; 38 | overflow: hidden; 39 | max-height: ${({ isOpen }) => (isOpen ? '200px' : '0')}; 40 | transition: max-height 0.1s ease; 41 | z-index: 1000; 42 | ` 43 | 44 | export const MenuItem = styled.div` 45 | padding: 10px; 46 | color: #fff; 47 | cursor: pointer; 48 | transition: background-color 0.2s; 49 | 50 | &:hover { 51 | background-color: #555; 52 | } 53 | ` 54 | 55 | export const Input = styled.input` 56 | padding: 10px; 57 | background-color: #444; 58 | color: #fff; 59 | border: 0; 60 | border-radius: 4px; 61 | font-size: 16px; 62 | margin-top: 4px; 63 | ` -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/settings/Settings.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | import { MdSettings } from 'react-icons/md' 3 | 4 | import Panel from '@components/Panel' 5 | 6 | import * as Styled from './Settings.styled' 7 | import SettingsBackground from './background/SettingsBackground' 8 | import SettingsSearch from './search/SettingsSearch' 9 | 10 | type Tabs = 'background' | 'search' 11 | 12 | function Settings() { 13 | const [open, setOpen] = useState(false) 14 | const [tab, setTab] = useState('background') 15 | 16 | const handleButtonClick = () => { 17 | setOpen((prev) => !prev) 18 | } 19 | 20 | const renderTabContent = () => { 21 | if (tab === 'search') { 22 | return 23 | } 24 | 25 | return 26 | } 27 | 28 | return ( 29 | 30 | 31 | 32 | setTab('background')} 34 | isActive={tab === 'background'} 35 | > 36 | Background 37 | 38 | setTab('search')} 40 | isActive={tab === 'search'} 41 | > 42 | Search 43 | 44 | 45 | {renderTabContent()} 46 | 47 | 48 | 49 | 50 | 51 | ) 52 | } 53 | 54 | export default Settings 55 | -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import { Global, ThemeProvider } from '@emotion/react' 3 | 4 | import BackgroundCanvas from '@components/BackgroundCanvas' 5 | import Settings from '@components/settings/Settings' 6 | import Clock from '@components/Clock' 7 | 8 | import spacing from '@utils/spacing' 9 | import getCurrentGeolocation from '@utils/getCurrentGeolocation' 10 | import getCurrentWeather from '@utils/getCurrentWeather' 11 | 12 | import useSessionAppStore from '@stores/session-app' 13 | import useAppStore from '@stores/app' 14 | 15 | import * as Styled from './App.styled' 16 | import SearchBar from '@components/SearchBar' 17 | 18 | function App() { 19 | const isReady = useSessionAppStore((store) => store.isReady) 20 | 21 | const geolocation = useAppStore((store) => store.geolocation) 22 | const setGeolocation = useAppStore((store) => store.setGeolocation) 23 | 24 | const weather = useAppStore((store) => store.weather) 25 | const setWeather = useAppStore((store) => store.setWeather) 26 | 27 | useEffect(() => { 28 | if (geolocation) { 29 | return 30 | } 31 | 32 | getCurrentGeolocation().then(setGeolocation).catch() 33 | }, [geolocation, setGeolocation]) 34 | 35 | useEffect(() => { 36 | if (!geolocation) { 37 | return 38 | } 39 | 40 | if (weather && weather.expiresAt > Date.now()) { 41 | return 42 | } 43 | 44 | getCurrentWeather(geolocation).then(setWeather).catch() 45 | }, [geolocation, setWeather, weather]) 46 | 47 | return ( 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | ) 60 | } 61 | 62 | export default App 63 | -------------------------------------------------------------------------------- /src/utils/getCurrentWeather.ts: -------------------------------------------------------------------------------- 1 | import { fetchWeatherApi } from 'openmeteo' 2 | 3 | import WMO_WEATHER_CODES from '@constants/weather' 4 | 5 | import { LatLng } from '@utils/getCurrentGeolocation' 6 | 7 | export interface Weather { 8 | rain: number 9 | snowfall: number 10 | humidity: number 11 | temperature: number 12 | weatherCode: number 13 | weatherName: string 14 | } 15 | 16 | async function getCurrentWeather(geolocation: LatLng): Promise { 17 | const params = { 18 | latitude: geolocation.lat, 19 | longitude: geolocation.lng, 20 | current: [ 21 | 'temperature_2m', 22 | 'relative_humidity_2m', 23 | 'rain', 24 | 'showers', 25 | 'snowfall', 26 | 'weather_code', 27 | 'is_day', 28 | ], 29 | } 30 | 31 | const url = 'https://api.open-meteo.com/v1/forecast' 32 | const [response] = await fetchWeatherApi(url, params) 33 | const utcOffsetSeconds = response.utcOffsetSeconds() 34 | const current = response.current()! 35 | 36 | const weatherData = { 37 | current: { 38 | time: new Date((Number(current.time()) + utcOffsetSeconds) * 1000), 39 | temperature2m: current.variables(0)!.value(), 40 | relativeHumidity2m: current.variables(1)!.value(), 41 | rain: current.variables(2)!.value(), 42 | showers: current.variables(3)!.value(), 43 | snowfall: current.variables(4)!.value(), 44 | weatherCode: current.variables(5)!.value(), 45 | isDay: current.variables(6)!.value(), 46 | }, 47 | } 48 | 49 | return { 50 | rain: weatherData.current.rain, 51 | snowfall: weatherData.current.snowfall, 52 | humidity: weatherData.current.relativeHumidity2m, 53 | temperature: weatherData.current.temperature2m, 54 | weatherCode: weatherData.current.weatherCode, 55 | weatherName: 56 | WMO_WEATHER_CODES[weatherData.current.weatherCode][ 57 | weatherData.current.isDay ? 'day' : 'night' 58 | ], 59 | } 60 | } 61 | 62 | export default getCurrentWeather 63 | -------------------------------------------------------------------------------- /src/components/settings/search/SettingsSearch.tsx: -------------------------------------------------------------------------------- 1 | import FormSection from '@components/FormSection' 2 | 3 | import * as Styled from './SettingsSearch.styled' 4 | import { useState } from 'react' 5 | import useAppStore from '@stores/app' 6 | import { SEARCH_ENGINES, SearchEngineOption } from '@constants/searchEngines' 7 | 8 | function SettingsSearch() { 9 | const { 10 | searchEngine, 11 | setSearchEngine, 12 | customSearchEngineURL, 13 | setCustomSearchEngineURL, 14 | } = useAppStore() 15 | 16 | const [isMenuOpen, setIsMenuOpen] = useState(false) 17 | 18 | const handleToggle = () => setIsMenuOpen(!isMenuOpen) 19 | const handleSelect = (item: SearchEngineOption) => { 20 | setIsMenuOpen(false) 21 | setSearchEngine(item) 22 | } 23 | 24 | return ( 25 | <> 26 | 27 | 28 | 29 | {SEARCH_ENGINES[searchEngine].name} 30 | 31 | 32 | {Object.keys(SEARCH_ENGINES).map((engine) => ( 33 | handleSelect(engine)} 36 | > 37 | {SEARCH_ENGINES[engine].name} 38 | 39 | ))} 40 | 41 | 42 | 43 | 44 | {searchEngine === 'custom' && ( 45 | 49 | setCustomSearchEngineURL(e.target.value)} 54 | /> 55 | 56 | )} 57 | 58 | ) 59 | } 60 | 61 | export default SettingsSearch 62 | -------------------------------------------------------------------------------- /src/components/SearchBar.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { RiOpenaiFill, RiSearch2Line } from 'react-icons/ri' 3 | 4 | import IconTab, { IconTabItem } from '@components/IconTab' 5 | 6 | import * as Styled from './SearchBar.styled' 7 | import useAppStore from '@stores/app' 8 | import { SEARCH_ENGINES } from '@constants/searchEngines' 9 | 10 | type QueryMode = 'websearch' | 'chatgpt' 11 | 12 | const SEARCH_ENGiNE_ITEMS: IconTabItem[] = [ 13 | { 14 | value: 'websearch', 15 | icon: RiSearch2Line, 16 | }, 17 | { 18 | value: 'chatgpt', 19 | icon: RiOpenaiFill, 20 | }, 21 | ] 22 | 23 | const PLACEHOLDER_TEXT: Record = { 24 | websearch: 'Search the web...', 25 | chatgpt: 'Ask ChatGPT...', 26 | } 27 | 28 | function SearchBar() { 29 | const [query, setQuery] = React.useState('') 30 | const [queryMode, setQueryMode] = React.useState('websearch') 31 | const { searchEngine, customSearchEngineURL } = useAppStore() 32 | 33 | const handleChange = (event: React.ChangeEvent) => { 34 | setQuery(event.target.value) 35 | } 36 | 37 | const handleKeyDown = (event: React.KeyboardEvent) => { 38 | if (event.key !== 'Enter') return 39 | 40 | if (queryMode === 'chatgpt') { 41 | location.href = `https://chat.openai.com/?q=${query}` 42 | return 43 | } 44 | 45 | if (queryMode === 'websearch') { 46 | const searchUrl = 47 | searchEngine === 'custom' 48 | ? customSearchEngineURL 49 | : SEARCH_ENGINES[searchEngine].url 50 | 51 | if (!searchUrl) return alert('Please set a custom search engine URL.') 52 | 53 | location.href = searchUrl.replace('{}', encodeURIComponent(query)) 54 | } 55 | } 56 | 57 | return ( 58 | 59 | 66 | 67 | 72 | 73 | 74 | ) 75 | } 76 | 77 | export default SearchBar 78 | -------------------------------------------------------------------------------- /src/constants/weather.ts: -------------------------------------------------------------------------------- 1 | const WMO_WEATHER_CODES: Record> = { 2 | '0': { 3 | day: 'Sunny', 4 | night: 'Clear', 5 | }, 6 | '1': { 7 | day: 'Mainly Sunny', 8 | night: 'Mainly Clear', 9 | }, 10 | '2': { 11 | day: 'Partly Cloudy', 12 | night: 'Partly Cloudy', 13 | }, 14 | '3': { 15 | day: 'Cloudy', 16 | night: 'Cloudy', 17 | }, 18 | '45': { 19 | day: 'Foggy', 20 | night: 'Foggy', 21 | }, 22 | '48': { 23 | day: 'Rime Fog', 24 | night: 'Rime Fog', 25 | }, 26 | '51': { 27 | day: 'Light Drizzle', 28 | night: 'Light Drizzle', 29 | }, 30 | '53': { 31 | day: 'Drizzle', 32 | night: 'Drizzle', 33 | }, 34 | '55': { 35 | day: 'Heavy Drizzle', 36 | night: 'Heavy Drizzle', 37 | }, 38 | '56': { 39 | day: 'Light Freezing Drizzle', 40 | night: 'Light Freezing Drizzle', 41 | }, 42 | '57': { 43 | day: 'Freezing Drizzle', 44 | night: 'Freezing Drizzle', 45 | }, 46 | '61': { 47 | day: 'Light Rain', 48 | night: 'Light Rain', 49 | }, 50 | '63': { 51 | day: 'Rain', 52 | night: 'Rain', 53 | }, 54 | '65': { 55 | day: 'Heavy Rain', 56 | night: 'Heavy Rain', 57 | }, 58 | '66': { 59 | day: 'Light Freezing Rain', 60 | night: 'Light Freezing Rain', 61 | }, 62 | '67': { 63 | day: 'Freezing Rain', 64 | night: 'Freezing Rain', 65 | }, 66 | '71': { 67 | day: 'Light Snow', 68 | night: 'Light Snow', 69 | }, 70 | '73': { 71 | day: 'Snow', 72 | night: 'Snow', 73 | }, 74 | '75': { 75 | day: 'Heavy Snow', 76 | night: 'Heavy Snow', 77 | }, 78 | '77': { 79 | day: 'Snow Grains', 80 | night: 'Snow Grains', 81 | }, 82 | '80': { 83 | day: 'Light Showers', 84 | night: 'Light Showers', 85 | }, 86 | '81': { 87 | day: 'Showers', 88 | night: 'Showers', 89 | }, 90 | '82': { 91 | day: 'Heavy Showers', 92 | night: 'Heavy Showers', 93 | }, 94 | '85': { 95 | day: 'Light Snow Showers', 96 | night: 'Light Snow Showers', 97 | }, 98 | '86': { 99 | day: 'Snow Showers', 100 | night: 'Snow Showers', 101 | }, 102 | '95': { 103 | day: 'Thunderstorm', 104 | night: 'Thunderstorm', 105 | }, 106 | '96': { 107 | day: 'Light Thunderstorms With Hail', 108 | night: 'Light Thunderstorms With Hail', 109 | }, 110 | '99': { 111 | day: 'Thunderstorm With Hail', 112 | night: 'Thunderstorm With Hail', 113 | }, 114 | } 115 | 116 | export default WMO_WEATHER_CODES 117 | -------------------------------------------------------------------------------- /src/stores/app.ts: -------------------------------------------------------------------------------- 1 | import { create } from 'zustand' 2 | import { createJSONStorage, persist } from 'zustand/middleware' 3 | 4 | import { Weather } from '@utils/getCurrentWeather' 5 | import { SearchEngineOption } from '@constants/searchEngines' 6 | 7 | interface WeatherHolder { 8 | weather: Weather 9 | expiresAt: number 10 | } 11 | 12 | interface LatLng { 13 | lat: number 14 | lng: number 15 | } 16 | 17 | interface AppStore { 18 | backgroundImage: string | null 19 | setBackgroundImage: (backgroundImage: string) => void 20 | clearBackgroundImage: () => void 21 | 22 | dimmingAmount: number 23 | setDimmingAmount: (dimmingAmount: number) => void 24 | 25 | blurAmount: number 26 | setBlurAmount: (blurAmount: number) => void 27 | 28 | isPropertyChanging: boolean 29 | setPropertyChanging: (isPropertyChanging: boolean) => void 30 | 31 | geolocation: LatLng | null 32 | setGeolocation: (geolocation: LatLng) => void 33 | 34 | weather: WeatherHolder | null 35 | setWeather: (weather: Weather) => void 36 | 37 | searchEngine: SearchEngineOption 38 | setSearchEngine: (searchEngine: SearchEngineOption) => void 39 | 40 | customSearchEngineURL: string | null 41 | setCustomSearchEngineURL: (customSearchEngineURL: string) => void 42 | } 43 | 44 | const useAppStore = create( 45 | persist( 46 | (set) => ({ 47 | backgroundImage: null, 48 | setBackgroundImage: (backgroundImage: string) => set({ backgroundImage }), 49 | clearBackgroundImage: () => set({ backgroundImage: null }), 50 | 51 | dimmingAmount: 0.5, 52 | setDimmingAmount: (dimmingAmount: number) => set({ dimmingAmount }), 53 | 54 | blurAmount: 4, 55 | setBlurAmount: (blurAmount: number) => set({ blurAmount }), 56 | 57 | isPropertyChanging: false, 58 | setPropertyChanging: (isPropertyChanging: boolean) => 59 | set({ isPropertyChanging }), 60 | 61 | geolocation: null, 62 | setGeolocation: (geolocation: LatLng) => set({ geolocation }), 63 | 64 | weather: null, 65 | setWeather: (weather: Weather) => { 66 | const expiresAt = Date.now() + 1000 * 60 * 60 // 1 hour 67 | set({ weather: { weather, expiresAt } }) 68 | }, 69 | 70 | searchEngine: 'google', 71 | setSearchEngine: (searchEngine: SearchEngineOption) => set({ searchEngine }), 72 | 73 | customSearchEngineURL: null, 74 | setCustomSearchEngineURL: (customSearchEngineURL: string) => 75 | set({ customSearchEngineURL }), 76 | }), 77 | { 78 | name: 'app-store', 79 | storage: createJSONStorage(() => localStorage), 80 | }, 81 | ), 82 | ) 83 | 84 | export default useAppStore 85 | -------------------------------------------------------------------------------- /src/components/BackgroundCanvas.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef } from 'react' 2 | import RaindropFX from 'raindrop-fx' 3 | 4 | import useAppStore from '@stores/app' 5 | import useSessionAppStore from '@stores/session-app' 6 | 7 | import * as Styled from './BackgroundCanvas.styled' 8 | 9 | function BackgroundCanvas() { 10 | const isReady = useSessionAppStore((store) => store.isReady) 11 | const isPropertyChanging = useAppStore((store) => store.isPropertyChanging) 12 | const dimmingAmount = useAppStore((store) => store.dimmingAmount) 13 | const blurAmount = useAppStore((store) => store.blurAmount) 14 | const backgroundImage = 15 | useAppStore((store) => store.backgroundImage) ?? '/img.png' 16 | 17 | const setIsReady = useSessionAppStore((store) => store.setIsReady) 18 | 19 | const viewportRef = useRef(null) 20 | const raindropsRef = useRef(null) 21 | 22 | const initialBlurAmount = useRef(blurAmount) 23 | 24 | useEffect(() => { 25 | if (!raindropsRef.current) { 26 | return 27 | } 28 | 29 | raindropsRef.current.options.backgroundBlurSteps = blurAmount 30 | raindropsRef.current.options.mistBlurStep = blurAmount + 1 31 | raindropsRef.current.renderer.reloadBackground() 32 | }, [blurAmount]) 33 | 34 | useEffect(() => { 35 | const viewport = viewportRef.current 36 | if (!viewport) { 37 | return 38 | } 39 | 40 | const { width, height } = viewport.getBoundingClientRect() 41 | viewport.width = width 42 | viewport.height = height 43 | 44 | raindropsRef.current = new RaindropFX({ 45 | canvas: viewport, 46 | backgroundBlurSteps: initialBlurAmount.current, 47 | mistBlurStep: initialBlurAmount.current + 1, 48 | }) 49 | 50 | raindropsRef.current.start() 51 | raindropsRef.current.setBackground(backgroundImage).then(() => { 52 | setIsReady(true) 53 | }) 54 | 55 | return () => { 56 | raindropsRef.current?.stop() 57 | } 58 | }, [backgroundImage, setIsReady]) 59 | 60 | useEffect(() => { 61 | const onResize = () => { 62 | const viewport = viewportRef.current 63 | const raindrops = raindropsRef.current 64 | if (!viewport || !raindrops) { 65 | return 66 | } 67 | 68 | const { width, height } = viewport.getBoundingClientRect() 69 | raindrops.resize(width, height) 70 | } 71 | 72 | window.addEventListener('resize', onResize) 73 | 74 | return () => { 75 | window.removeEventListener('resize', onResize) 76 | } 77 | }, []) 78 | 79 | return ( 80 | 81 | 82 | 86 | 93 | 94 | ) 95 | } 96 | 97 | export default BackgroundCanvas 98 | -------------------------------------------------------------------------------- /src/components/settings/background/SettingsBackground.tsx: -------------------------------------------------------------------------------- 1 | import React, { useRef } from 'react' 2 | 3 | import FormSection from '@components/FormSection' 4 | 5 | import useAppStore from '@stores/app' 6 | import readFileAsBase64 from '@utils/readFileAsBase64' 7 | 8 | import * as Styled from './SettingsBackground.styled' 9 | 10 | const MAX_FILE_SIZE = 5 * 1024 * 1024 // 5MB 11 | 12 | function SettingsBackground() { 13 | const fileInputRef = useRef(null) 14 | const changingTimeout = useRef(null) 15 | 16 | const dimmingAmount = useAppStore((store) => store.dimmingAmount) 17 | const blurAmount = useAppStore((store) => store.blurAmount) 18 | 19 | const setPropertyChanging = useAppStore((store) => store.setPropertyChanging) 20 | const setDimmingAmount = useAppStore((store) => store.setDimmingAmount) 21 | const setBlurAmount = useAppStore((store) => store.setBlurAmount) 22 | const setBackgroundImage = useAppStore((store) => store.setBackgroundImage) 23 | 24 | const doChange = (callback: () => void) => { 25 | if (changingTimeout.current) { 26 | clearTimeout(changingTimeout.current) 27 | changingTimeout.current = null 28 | } 29 | 30 | setPropertyChanging(true) 31 | 32 | callback() 33 | 34 | changingTimeout.current = setTimeout(() => { 35 | setPropertyChanging(false) 36 | changingTimeout.current = null 37 | }, 500) 38 | } 39 | 40 | const handleUploadClick = () => { 41 | fileInputRef.current?.click() 42 | } 43 | 44 | const handleFileChange = async ( 45 | event: React.ChangeEvent, 46 | ) => { 47 | const file = event.target.files?.[0] 48 | if (!file) { 49 | return 50 | } 51 | 52 | if (file.size > MAX_FILE_SIZE) { 53 | alert('File size exceeds the limit of 5MB.') 54 | return 55 | } 56 | 57 | const base64 = await readFileAsBase64(file) 58 | setBackgroundImage(base64) 59 | } 60 | 61 | const handleDimmingAmountChange = ( 62 | event: React.ChangeEvent, 63 | ) => { 64 | const value = parseFloat(event.target.value) 65 | doChange(() => setDimmingAmount(value)) 66 | } 67 | 68 | const handleBlurAmountChange = ( 69 | event: React.ChangeEvent, 70 | ) => { 71 | const value = parseFloat(event.target.value) 72 | doChange(() => setBlurAmount(value)) 73 | } 74 | 75 | return ( 76 | <> 77 | 81 | 86 | 90 | Upload Image 91 | 92 | 93 | 94 | 102 | 103 | 104 | 112 | 113 | 114 | ) 115 | } 116 | 117 | export default SettingsBackground 118 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | dependencies: 8 | '@emotion/css': 9 | specifier: ^11.13.4 10 | version: 11.13.4 11 | '@emotion/react': 12 | specifier: ^11.13.3 13 | version: 11.13.3(@types/react@18.3.12)(react@18.3.1) 14 | '@emotion/styled': 15 | specifier: ^11.13.0 16 | version: 11.13.0(@emotion/react@11.13.3)(@types/react@18.3.12)(react@18.3.1) 17 | dayjs: 18 | specifier: ^1.11.13 19 | version: 1.11.13 20 | lodash: 21 | specifier: ^4.17.21 22 | version: 4.17.21 23 | normalize.css: 24 | specifier: ^8.0.1 25 | version: 8.0.1 26 | openmeteo: 27 | specifier: ^1.1.4 28 | version: 1.1.4 29 | raindrop-fx: 30 | specifier: ^1.0.8 31 | version: 1.0.8 32 | react: 33 | specifier: ^18.3.1 34 | version: 18.3.1 35 | react-dom: 36 | specifier: ^18.3.1 37 | version: 18.3.1(react@18.3.1) 38 | react-icons: 39 | specifier: ^5.3.0 40 | version: 5.3.0(react@18.3.1) 41 | zustand: 42 | specifier: ^5.0.0 43 | version: 5.0.0(@types/react@18.3.12)(react@18.3.1) 44 | 45 | devDependencies: 46 | '@eslint/js': 47 | specifier: ^9.13.0 48 | version: 9.13.0 49 | '@types/lodash': 50 | specifier: ^4.17.12 51 | version: 4.17.12 52 | '@types/react': 53 | specifier: ^18.3.11 54 | version: 18.3.12 55 | '@types/react-dom': 56 | specifier: ^18.3.1 57 | version: 18.3.1 58 | '@vitejs/plugin-react': 59 | specifier: ^4.3.3 60 | version: 4.3.3(vite@5.4.10) 61 | eslint: 62 | specifier: ^9.13.0 63 | version: 9.13.0 64 | eslint-plugin-react-hooks: 65 | specifier: ^5.0.0 66 | version: 5.0.0(eslint@9.13.0) 67 | eslint-plugin-react-refresh: 68 | specifier: ^0.4.13 69 | version: 0.4.14(eslint@9.13.0) 70 | globals: 71 | specifier: ^15.11.0 72 | version: 15.11.0 73 | prettier: 74 | specifier: ^3.3.3 75 | version: 3.3.3 76 | typescript: 77 | specifier: ~5.6.2 78 | version: 5.6.3 79 | typescript-eslint: 80 | specifier: ^8.10.0 81 | version: 8.11.0(eslint@9.13.0)(typescript@5.6.3) 82 | vite: 83 | specifier: ^5.4.9 84 | version: 5.4.10 85 | vite-plugin-glsl: 86 | specifier: ^1.3.0 87 | version: 1.3.0(vite@5.4.10) 88 | vite-tsconfig-paths: 89 | specifier: ^5.0.1 90 | version: 5.0.1(typescript@5.6.3)(vite@5.4.10) 91 | 92 | packages: 93 | 94 | /@ampproject/remapping@2.3.0: 95 | resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} 96 | engines: {node: '>=6.0.0'} 97 | dependencies: 98 | '@jridgewell/gen-mapping': 0.3.5 99 | '@jridgewell/trace-mapping': 0.3.25 100 | dev: true 101 | 102 | /@babel/code-frame@7.26.0: 103 | resolution: {integrity: sha512-INCKxTtbXtcNbUZ3YXutwMpEleqttcswhAdee7dhuoVrD2cnuc3PqtERBtxkX5nziX9vnBL8WXmSGwv8CuPV6g==} 104 | engines: {node: '>=6.9.0'} 105 | dependencies: 106 | '@babel/helper-validator-identifier': 7.25.9 107 | js-tokens: 4.0.0 108 | picocolors: 1.1.1 109 | 110 | /@babel/compat-data@7.26.0: 111 | resolution: {integrity: sha512-qETICbZSLe7uXv9VE8T/RWOdIE5qqyTucOt4zLYMafj2MRO271VGgLd4RACJMeBO37UPWhXiKMBk7YlJ0fOzQA==} 112 | engines: {node: '>=6.9.0'} 113 | dev: true 114 | 115 | /@babel/core@7.26.0: 116 | resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==} 117 | engines: {node: '>=6.9.0'} 118 | dependencies: 119 | '@ampproject/remapping': 2.3.0 120 | '@babel/code-frame': 7.26.0 121 | '@babel/generator': 7.26.0 122 | '@babel/helper-compilation-targets': 7.25.9 123 | '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) 124 | '@babel/helpers': 7.26.0 125 | '@babel/parser': 7.26.1 126 | '@babel/template': 7.25.9 127 | '@babel/traverse': 7.25.9 128 | '@babel/types': 7.26.0 129 | convert-source-map: 2.0.0 130 | debug: 4.3.7 131 | gensync: 1.0.0-beta.2 132 | json5: 2.2.3 133 | semver: 6.3.1 134 | transitivePeerDependencies: 135 | - supports-color 136 | dev: true 137 | 138 | /@babel/generator@7.26.0: 139 | resolution: {integrity: sha512-/AIkAmInnWwgEAJGQr9vY0c66Mj6kjkE2ZPB1PurTRaRAh3U+J45sAQMjQDJdh4WbR3l0x5xkimXBKyBXXAu2w==} 140 | engines: {node: '>=6.9.0'} 141 | dependencies: 142 | '@babel/parser': 7.26.1 143 | '@babel/types': 7.26.0 144 | '@jridgewell/gen-mapping': 0.3.5 145 | '@jridgewell/trace-mapping': 0.3.25 146 | jsesc: 3.0.2 147 | 148 | /@babel/helper-compilation-targets@7.25.9: 149 | resolution: {integrity: sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==} 150 | engines: {node: '>=6.9.0'} 151 | dependencies: 152 | '@babel/compat-data': 7.26.0 153 | '@babel/helper-validator-option': 7.25.9 154 | browserslist: 4.24.2 155 | lru-cache: 5.1.1 156 | semver: 6.3.1 157 | dev: true 158 | 159 | /@babel/helper-module-imports@7.25.9: 160 | resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} 161 | engines: {node: '>=6.9.0'} 162 | dependencies: 163 | '@babel/traverse': 7.25.9 164 | '@babel/types': 7.26.0 165 | transitivePeerDependencies: 166 | - supports-color 167 | 168 | /@babel/helper-module-transforms@7.26.0(@babel/core@7.26.0): 169 | resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} 170 | engines: {node: '>=6.9.0'} 171 | peerDependencies: 172 | '@babel/core': ^7.0.0 173 | dependencies: 174 | '@babel/core': 7.26.0 175 | '@babel/helper-module-imports': 7.25.9 176 | '@babel/helper-validator-identifier': 7.25.9 177 | '@babel/traverse': 7.25.9 178 | transitivePeerDependencies: 179 | - supports-color 180 | dev: true 181 | 182 | /@babel/helper-plugin-utils@7.25.9: 183 | resolution: {integrity: sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==} 184 | engines: {node: '>=6.9.0'} 185 | dev: true 186 | 187 | /@babel/helper-string-parser@7.25.9: 188 | resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} 189 | engines: {node: '>=6.9.0'} 190 | 191 | /@babel/helper-validator-identifier@7.25.9: 192 | resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} 193 | engines: {node: '>=6.9.0'} 194 | 195 | /@babel/helper-validator-option@7.25.9: 196 | resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} 197 | engines: {node: '>=6.9.0'} 198 | dev: true 199 | 200 | /@babel/helpers@7.26.0: 201 | resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==} 202 | engines: {node: '>=6.9.0'} 203 | dependencies: 204 | '@babel/template': 7.25.9 205 | '@babel/types': 7.26.0 206 | dev: true 207 | 208 | /@babel/parser@7.26.1: 209 | resolution: {integrity: sha512-reoQYNiAJreZNsJzyrDNzFQ+IQ5JFiIzAHJg9bn94S3l+4++J7RsIhNMoB+lgP/9tpmiAQqspv+xfdxTSzREOw==} 210 | engines: {node: '>=6.0.0'} 211 | hasBin: true 212 | dependencies: 213 | '@babel/types': 7.26.0 214 | 215 | /@babel/plugin-transform-react-jsx-self@7.25.9(@babel/core@7.26.0): 216 | resolution: {integrity: sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==} 217 | engines: {node: '>=6.9.0'} 218 | peerDependencies: 219 | '@babel/core': ^7.0.0-0 220 | dependencies: 221 | '@babel/core': 7.26.0 222 | '@babel/helper-plugin-utils': 7.25.9 223 | dev: true 224 | 225 | /@babel/plugin-transform-react-jsx-source@7.25.9(@babel/core@7.26.0): 226 | resolution: {integrity: sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==} 227 | engines: {node: '>=6.9.0'} 228 | peerDependencies: 229 | '@babel/core': ^7.0.0-0 230 | dependencies: 231 | '@babel/core': 7.26.0 232 | '@babel/helper-plugin-utils': 7.25.9 233 | dev: true 234 | 235 | /@babel/runtime@7.26.0: 236 | resolution: {integrity: sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==} 237 | engines: {node: '>=6.9.0'} 238 | dependencies: 239 | regenerator-runtime: 0.14.1 240 | dev: false 241 | 242 | /@babel/template@7.25.9: 243 | resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==} 244 | engines: {node: '>=6.9.0'} 245 | dependencies: 246 | '@babel/code-frame': 7.26.0 247 | '@babel/parser': 7.26.1 248 | '@babel/types': 7.26.0 249 | 250 | /@babel/traverse@7.25.9: 251 | resolution: {integrity: sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==} 252 | engines: {node: '>=6.9.0'} 253 | dependencies: 254 | '@babel/code-frame': 7.26.0 255 | '@babel/generator': 7.26.0 256 | '@babel/parser': 7.26.1 257 | '@babel/template': 7.25.9 258 | '@babel/types': 7.26.0 259 | debug: 4.3.7 260 | globals: 11.12.0 261 | transitivePeerDependencies: 262 | - supports-color 263 | 264 | /@babel/types@7.26.0: 265 | resolution: {integrity: sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==} 266 | engines: {node: '>=6.9.0'} 267 | dependencies: 268 | '@babel/helper-string-parser': 7.25.9 269 | '@babel/helper-validator-identifier': 7.25.9 270 | 271 | /@emotion/babel-plugin@11.12.0: 272 | resolution: {integrity: sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==} 273 | dependencies: 274 | '@babel/helper-module-imports': 7.25.9 275 | '@babel/runtime': 7.26.0 276 | '@emotion/hash': 0.9.2 277 | '@emotion/memoize': 0.9.0 278 | '@emotion/serialize': 1.3.2 279 | babel-plugin-macros: 3.1.0 280 | convert-source-map: 1.9.0 281 | escape-string-regexp: 4.0.0 282 | find-root: 1.1.0 283 | source-map: 0.5.7 284 | stylis: 4.2.0 285 | transitivePeerDependencies: 286 | - supports-color 287 | dev: false 288 | 289 | /@emotion/cache@11.13.1: 290 | resolution: {integrity: sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw==} 291 | dependencies: 292 | '@emotion/memoize': 0.9.0 293 | '@emotion/sheet': 1.4.0 294 | '@emotion/utils': 1.4.1 295 | '@emotion/weak-memoize': 0.4.0 296 | stylis: 4.2.0 297 | dev: false 298 | 299 | /@emotion/css@11.13.4: 300 | resolution: {integrity: sha512-CthbOD5EBw+iN0rfM96Tuv5kaZN4nxPyYDvGUs0bc7wZBBiU/0mse+l+0O9RshW2d+v5HH1cme+BAbLJ/3Folw==} 301 | dependencies: 302 | '@emotion/babel-plugin': 11.12.0 303 | '@emotion/cache': 11.13.1 304 | '@emotion/serialize': 1.3.2 305 | '@emotion/sheet': 1.4.0 306 | '@emotion/utils': 1.4.1 307 | transitivePeerDependencies: 308 | - supports-color 309 | dev: false 310 | 311 | /@emotion/hash@0.9.2: 312 | resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} 313 | dev: false 314 | 315 | /@emotion/is-prop-valid@1.3.1: 316 | resolution: {integrity: sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==} 317 | dependencies: 318 | '@emotion/memoize': 0.9.0 319 | dev: false 320 | 321 | /@emotion/memoize@0.9.0: 322 | resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} 323 | dev: false 324 | 325 | /@emotion/react@11.13.3(@types/react@18.3.12)(react@18.3.1): 326 | resolution: {integrity: sha512-lIsdU6JNrmYfJ5EbUCf4xW1ovy5wKQ2CkPRM4xogziOxH1nXxBSjpC9YqbFAP7circxMfYp+6x676BqWcEiixg==} 327 | peerDependencies: 328 | '@types/react': '*' 329 | react: '>=16.8.0' 330 | peerDependenciesMeta: 331 | '@types/react': 332 | optional: true 333 | dependencies: 334 | '@babel/runtime': 7.26.0 335 | '@emotion/babel-plugin': 11.12.0 336 | '@emotion/cache': 11.13.1 337 | '@emotion/serialize': 1.3.2 338 | '@emotion/use-insertion-effect-with-fallbacks': 1.1.0(react@18.3.1) 339 | '@emotion/utils': 1.4.1 340 | '@emotion/weak-memoize': 0.4.0 341 | '@types/react': 18.3.12 342 | hoist-non-react-statics: 3.3.2 343 | react: 18.3.1 344 | transitivePeerDependencies: 345 | - supports-color 346 | dev: false 347 | 348 | /@emotion/serialize@1.3.2: 349 | resolution: {integrity: sha512-grVnMvVPK9yUVE6rkKfAJlYZgo0cu3l9iMC77V7DW6E1DUIrU68pSEXRmFZFOFB1QFo57TncmOcvcbMDWsL4yA==} 350 | dependencies: 351 | '@emotion/hash': 0.9.2 352 | '@emotion/memoize': 0.9.0 353 | '@emotion/unitless': 0.10.0 354 | '@emotion/utils': 1.4.1 355 | csstype: 3.1.3 356 | dev: false 357 | 358 | /@emotion/sheet@1.4.0: 359 | resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==} 360 | dev: false 361 | 362 | /@emotion/styled@11.13.0(@emotion/react@11.13.3)(@types/react@18.3.12)(react@18.3.1): 363 | resolution: {integrity: sha512-tkzkY7nQhW/zC4hztlwucpT8QEZ6eUzpXDRhww/Eej4tFfO0FxQYWRyg/c5CCXa4d/f174kqeXYjuQRnhzf6dA==} 364 | peerDependencies: 365 | '@emotion/react': ^11.0.0-rc.0 366 | '@types/react': '*' 367 | react: '>=16.8.0' 368 | peerDependenciesMeta: 369 | '@types/react': 370 | optional: true 371 | dependencies: 372 | '@babel/runtime': 7.26.0 373 | '@emotion/babel-plugin': 11.12.0 374 | '@emotion/is-prop-valid': 1.3.1 375 | '@emotion/react': 11.13.3(@types/react@18.3.12)(react@18.3.1) 376 | '@emotion/serialize': 1.3.2 377 | '@emotion/use-insertion-effect-with-fallbacks': 1.1.0(react@18.3.1) 378 | '@emotion/utils': 1.4.1 379 | '@types/react': 18.3.12 380 | react: 18.3.1 381 | transitivePeerDependencies: 382 | - supports-color 383 | dev: false 384 | 385 | /@emotion/unitless@0.10.0: 386 | resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==} 387 | dev: false 388 | 389 | /@emotion/use-insertion-effect-with-fallbacks@1.1.0(react@18.3.1): 390 | resolution: {integrity: sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==} 391 | peerDependencies: 392 | react: '>=16.8.0' 393 | dependencies: 394 | react: 18.3.1 395 | dev: false 396 | 397 | /@emotion/utils@1.4.1: 398 | resolution: {integrity: sha512-BymCXzCG3r72VKJxaYVwOXATqXIZ85cuvg0YOUDxMGNrKc1DJRZk8MgV5wyXRyEayIMd4FuXJIUgTBXvDNW5cA==} 399 | dev: false 400 | 401 | /@emotion/weak-memoize@0.4.0: 402 | resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} 403 | dev: false 404 | 405 | /@esbuild/aix-ppc64@0.21.5: 406 | resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} 407 | engines: {node: '>=12'} 408 | cpu: [ppc64] 409 | os: [aix] 410 | requiresBuild: true 411 | dev: true 412 | optional: true 413 | 414 | /@esbuild/android-arm64@0.21.5: 415 | resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} 416 | engines: {node: '>=12'} 417 | cpu: [arm64] 418 | os: [android] 419 | requiresBuild: true 420 | dev: true 421 | optional: true 422 | 423 | /@esbuild/android-arm@0.21.5: 424 | resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} 425 | engines: {node: '>=12'} 426 | cpu: [arm] 427 | os: [android] 428 | requiresBuild: true 429 | dev: true 430 | optional: true 431 | 432 | /@esbuild/android-x64@0.21.5: 433 | resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} 434 | engines: {node: '>=12'} 435 | cpu: [x64] 436 | os: [android] 437 | requiresBuild: true 438 | dev: true 439 | optional: true 440 | 441 | /@esbuild/darwin-arm64@0.21.5: 442 | resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} 443 | engines: {node: '>=12'} 444 | cpu: [arm64] 445 | os: [darwin] 446 | requiresBuild: true 447 | dev: true 448 | optional: true 449 | 450 | /@esbuild/darwin-x64@0.21.5: 451 | resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} 452 | engines: {node: '>=12'} 453 | cpu: [x64] 454 | os: [darwin] 455 | requiresBuild: true 456 | dev: true 457 | optional: true 458 | 459 | /@esbuild/freebsd-arm64@0.21.5: 460 | resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} 461 | engines: {node: '>=12'} 462 | cpu: [arm64] 463 | os: [freebsd] 464 | requiresBuild: true 465 | dev: true 466 | optional: true 467 | 468 | /@esbuild/freebsd-x64@0.21.5: 469 | resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} 470 | engines: {node: '>=12'} 471 | cpu: [x64] 472 | os: [freebsd] 473 | requiresBuild: true 474 | dev: true 475 | optional: true 476 | 477 | /@esbuild/linux-arm64@0.21.5: 478 | resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} 479 | engines: {node: '>=12'} 480 | cpu: [arm64] 481 | os: [linux] 482 | requiresBuild: true 483 | dev: true 484 | optional: true 485 | 486 | /@esbuild/linux-arm@0.21.5: 487 | resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} 488 | engines: {node: '>=12'} 489 | cpu: [arm] 490 | os: [linux] 491 | requiresBuild: true 492 | dev: true 493 | optional: true 494 | 495 | /@esbuild/linux-ia32@0.21.5: 496 | resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} 497 | engines: {node: '>=12'} 498 | cpu: [ia32] 499 | os: [linux] 500 | requiresBuild: true 501 | dev: true 502 | optional: true 503 | 504 | /@esbuild/linux-loong64@0.21.5: 505 | resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} 506 | engines: {node: '>=12'} 507 | cpu: [loong64] 508 | os: [linux] 509 | requiresBuild: true 510 | dev: true 511 | optional: true 512 | 513 | /@esbuild/linux-mips64el@0.21.5: 514 | resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} 515 | engines: {node: '>=12'} 516 | cpu: [mips64el] 517 | os: [linux] 518 | requiresBuild: true 519 | dev: true 520 | optional: true 521 | 522 | /@esbuild/linux-ppc64@0.21.5: 523 | resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} 524 | engines: {node: '>=12'} 525 | cpu: [ppc64] 526 | os: [linux] 527 | requiresBuild: true 528 | dev: true 529 | optional: true 530 | 531 | /@esbuild/linux-riscv64@0.21.5: 532 | resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} 533 | engines: {node: '>=12'} 534 | cpu: [riscv64] 535 | os: [linux] 536 | requiresBuild: true 537 | dev: true 538 | optional: true 539 | 540 | /@esbuild/linux-s390x@0.21.5: 541 | resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} 542 | engines: {node: '>=12'} 543 | cpu: [s390x] 544 | os: [linux] 545 | requiresBuild: true 546 | dev: true 547 | optional: true 548 | 549 | /@esbuild/linux-x64@0.21.5: 550 | resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} 551 | engines: {node: '>=12'} 552 | cpu: [x64] 553 | os: [linux] 554 | requiresBuild: true 555 | dev: true 556 | optional: true 557 | 558 | /@esbuild/netbsd-x64@0.21.5: 559 | resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} 560 | engines: {node: '>=12'} 561 | cpu: [x64] 562 | os: [netbsd] 563 | requiresBuild: true 564 | dev: true 565 | optional: true 566 | 567 | /@esbuild/openbsd-x64@0.21.5: 568 | resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} 569 | engines: {node: '>=12'} 570 | cpu: [x64] 571 | os: [openbsd] 572 | requiresBuild: true 573 | dev: true 574 | optional: true 575 | 576 | /@esbuild/sunos-x64@0.21.5: 577 | resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} 578 | engines: {node: '>=12'} 579 | cpu: [x64] 580 | os: [sunos] 581 | requiresBuild: true 582 | dev: true 583 | optional: true 584 | 585 | /@esbuild/win32-arm64@0.21.5: 586 | resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} 587 | engines: {node: '>=12'} 588 | cpu: [arm64] 589 | os: [win32] 590 | requiresBuild: true 591 | dev: true 592 | optional: true 593 | 594 | /@esbuild/win32-ia32@0.21.5: 595 | resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} 596 | engines: {node: '>=12'} 597 | cpu: [ia32] 598 | os: [win32] 599 | requiresBuild: true 600 | dev: true 601 | optional: true 602 | 603 | /@esbuild/win32-x64@0.21.5: 604 | resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} 605 | engines: {node: '>=12'} 606 | cpu: [x64] 607 | os: [win32] 608 | requiresBuild: true 609 | dev: true 610 | optional: true 611 | 612 | /@eslint-community/eslint-utils@4.4.1(eslint@9.13.0): 613 | resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==} 614 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 615 | peerDependencies: 616 | eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 617 | dependencies: 618 | eslint: 9.13.0 619 | eslint-visitor-keys: 3.4.3 620 | dev: true 621 | 622 | /@eslint-community/regexpp@4.11.2: 623 | resolution: {integrity: sha512-2WwyTYNVaMNUWPZTOJdkax9iqTdirrApgTbk+Qoq5EPX6myqZvG8QGFRgdKmkjKVG6/G/a565vpPauHk0+hpBA==} 624 | engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} 625 | dev: true 626 | 627 | /@eslint/config-array@0.18.0: 628 | resolution: {integrity: sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==} 629 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 630 | dependencies: 631 | '@eslint/object-schema': 2.1.4 632 | debug: 4.3.7 633 | minimatch: 3.1.2 634 | transitivePeerDependencies: 635 | - supports-color 636 | dev: true 637 | 638 | /@eslint/core@0.7.0: 639 | resolution: {integrity: sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==} 640 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 641 | dev: true 642 | 643 | /@eslint/eslintrc@3.1.0: 644 | resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==} 645 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 646 | dependencies: 647 | ajv: 6.12.6 648 | debug: 4.3.7 649 | espree: 10.2.0 650 | globals: 14.0.0 651 | ignore: 5.3.2 652 | import-fresh: 3.3.0 653 | js-yaml: 4.1.0 654 | minimatch: 3.1.2 655 | strip-json-comments: 3.1.1 656 | transitivePeerDependencies: 657 | - supports-color 658 | dev: true 659 | 660 | /@eslint/js@9.13.0: 661 | resolution: {integrity: sha512-IFLyoY4d72Z5y/6o/BazFBezupzI/taV8sGumxTAVw3lXG9A6md1Dc34T9s1FoD/an9pJH8RHbAxsaEbBed9lA==} 662 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 663 | dev: true 664 | 665 | /@eslint/object-schema@2.1.4: 666 | resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==} 667 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 668 | dev: true 669 | 670 | /@eslint/plugin-kit@0.2.1: 671 | resolution: {integrity: sha512-HFZ4Mp26nbWk9d/BpvP0YNL6W4UoZF0VFcTw/aPPA8RpOxeFQgK+ClABGgAUXs9Y/RGX/l1vOmrqz1MQt9MNuw==} 672 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 673 | dependencies: 674 | levn: 0.4.1 675 | dev: true 676 | 677 | /@humanfs/core@0.19.0: 678 | resolution: {integrity: sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw==} 679 | engines: {node: '>=18.18.0'} 680 | dev: true 681 | 682 | /@humanfs/node@0.16.5: 683 | resolution: {integrity: sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg==} 684 | engines: {node: '>=18.18.0'} 685 | dependencies: 686 | '@humanfs/core': 0.19.0 687 | '@humanwhocodes/retry': 0.3.1 688 | dev: true 689 | 690 | /@humanwhocodes/module-importer@1.0.1: 691 | resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} 692 | engines: {node: '>=12.22'} 693 | dev: true 694 | 695 | /@humanwhocodes/retry@0.3.1: 696 | resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} 697 | engines: {node: '>=18.18'} 698 | dev: true 699 | 700 | /@jridgewell/gen-mapping@0.3.5: 701 | resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} 702 | engines: {node: '>=6.0.0'} 703 | dependencies: 704 | '@jridgewell/set-array': 1.2.1 705 | '@jridgewell/sourcemap-codec': 1.5.0 706 | '@jridgewell/trace-mapping': 0.3.25 707 | 708 | /@jridgewell/resolve-uri@3.1.2: 709 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 710 | engines: {node: '>=6.0.0'} 711 | 712 | /@jridgewell/set-array@1.2.1: 713 | resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} 714 | engines: {node: '>=6.0.0'} 715 | 716 | /@jridgewell/sourcemap-codec@1.5.0: 717 | resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} 718 | 719 | /@jridgewell/trace-mapping@0.3.25: 720 | resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} 721 | dependencies: 722 | '@jridgewell/resolve-uri': 3.1.2 723 | '@jridgewell/sourcemap-codec': 1.5.0 724 | 725 | /@nodelib/fs.scandir@2.1.5: 726 | resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} 727 | engines: {node: '>= 8'} 728 | dependencies: 729 | '@nodelib/fs.stat': 2.0.5 730 | run-parallel: 1.2.0 731 | dev: true 732 | 733 | /@nodelib/fs.stat@2.0.5: 734 | resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} 735 | engines: {node: '>= 8'} 736 | dev: true 737 | 738 | /@nodelib/fs.walk@1.2.8: 739 | resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} 740 | engines: {node: '>= 8'} 741 | dependencies: 742 | '@nodelib/fs.scandir': 2.1.5 743 | fastq: 1.17.1 744 | dev: true 745 | 746 | /@openmeteo/sdk@1.18.0: 747 | resolution: {integrity: sha512-rcx3dY4kC3KHndHi4gETJi3QpETf/GriaktoG47YVEMbZ0lXm8G9Ki8qWasXWogSP15F6REET4Z+E/aPw86Crw==} 748 | engines: {node: '>=12.0'} 749 | dependencies: 750 | flatbuffers: 24.3.25 751 | dev: false 752 | 753 | /@rollup/pluginutils@5.1.3: 754 | resolution: {integrity: sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==} 755 | engines: {node: '>=14.0.0'} 756 | peerDependencies: 757 | rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 758 | peerDependenciesMeta: 759 | rollup: 760 | optional: true 761 | dependencies: 762 | '@types/estree': 1.0.6 763 | estree-walker: 2.0.2 764 | picomatch: 4.0.2 765 | dev: true 766 | 767 | /@rollup/rollup-android-arm-eabi@4.24.0: 768 | resolution: {integrity: sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==} 769 | cpu: [arm] 770 | os: [android] 771 | requiresBuild: true 772 | dev: true 773 | optional: true 774 | 775 | /@rollup/rollup-android-arm64@4.24.0: 776 | resolution: {integrity: sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==} 777 | cpu: [arm64] 778 | os: [android] 779 | requiresBuild: true 780 | dev: true 781 | optional: true 782 | 783 | /@rollup/rollup-darwin-arm64@4.24.0: 784 | resolution: {integrity: sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==} 785 | cpu: [arm64] 786 | os: [darwin] 787 | requiresBuild: true 788 | dev: true 789 | optional: true 790 | 791 | /@rollup/rollup-darwin-x64@4.24.0: 792 | resolution: {integrity: sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==} 793 | cpu: [x64] 794 | os: [darwin] 795 | requiresBuild: true 796 | dev: true 797 | optional: true 798 | 799 | /@rollup/rollup-linux-arm-gnueabihf@4.24.0: 800 | resolution: {integrity: sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==} 801 | cpu: [arm] 802 | os: [linux] 803 | requiresBuild: true 804 | dev: true 805 | optional: true 806 | 807 | /@rollup/rollup-linux-arm-musleabihf@4.24.0: 808 | resolution: {integrity: sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==} 809 | cpu: [arm] 810 | os: [linux] 811 | requiresBuild: true 812 | dev: true 813 | optional: true 814 | 815 | /@rollup/rollup-linux-arm64-gnu@4.24.0: 816 | resolution: {integrity: sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==} 817 | cpu: [arm64] 818 | os: [linux] 819 | requiresBuild: true 820 | dev: true 821 | optional: true 822 | 823 | /@rollup/rollup-linux-arm64-musl@4.24.0: 824 | resolution: {integrity: sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==} 825 | cpu: [arm64] 826 | os: [linux] 827 | requiresBuild: true 828 | dev: true 829 | optional: true 830 | 831 | /@rollup/rollup-linux-powerpc64le-gnu@4.24.0: 832 | resolution: {integrity: sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==} 833 | cpu: [ppc64] 834 | os: [linux] 835 | requiresBuild: true 836 | dev: true 837 | optional: true 838 | 839 | /@rollup/rollup-linux-riscv64-gnu@4.24.0: 840 | resolution: {integrity: sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==} 841 | cpu: [riscv64] 842 | os: [linux] 843 | requiresBuild: true 844 | dev: true 845 | optional: true 846 | 847 | /@rollup/rollup-linux-s390x-gnu@4.24.0: 848 | resolution: {integrity: sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==} 849 | cpu: [s390x] 850 | os: [linux] 851 | requiresBuild: true 852 | dev: true 853 | optional: true 854 | 855 | /@rollup/rollup-linux-x64-gnu@4.24.0: 856 | resolution: {integrity: sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==} 857 | cpu: [x64] 858 | os: [linux] 859 | requiresBuild: true 860 | dev: true 861 | optional: true 862 | 863 | /@rollup/rollup-linux-x64-musl@4.24.0: 864 | resolution: {integrity: sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==} 865 | cpu: [x64] 866 | os: [linux] 867 | requiresBuild: true 868 | dev: true 869 | optional: true 870 | 871 | /@rollup/rollup-win32-arm64-msvc@4.24.0: 872 | resolution: {integrity: sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==} 873 | cpu: [arm64] 874 | os: [win32] 875 | requiresBuild: true 876 | dev: true 877 | optional: true 878 | 879 | /@rollup/rollup-win32-ia32-msvc@4.24.0: 880 | resolution: {integrity: sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==} 881 | cpu: [ia32] 882 | os: [win32] 883 | requiresBuild: true 884 | dev: true 885 | optional: true 886 | 887 | /@rollup/rollup-win32-x64-msvc@4.24.0: 888 | resolution: {integrity: sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==} 889 | cpu: [x64] 890 | os: [win32] 891 | requiresBuild: true 892 | dev: true 893 | optional: true 894 | 895 | /@sardinefish/zogra-renderer@1.2.0: 896 | resolution: {integrity: sha512-0wbAzhi5AAtbHMF6zzVx3ISFPsqLmaJLhkZfm3dFbnThXDqGf/6Gj71nmXBPtzcV0oQOWm8bFpu1a0S7/pGLQg==} 897 | dependencies: 898 | gl-matrix: 3.4.3 899 | reflect-metadata: 0.1.14 900 | dev: false 901 | 902 | /@types/babel__core@7.20.5: 903 | resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} 904 | dependencies: 905 | '@babel/parser': 7.26.1 906 | '@babel/types': 7.26.0 907 | '@types/babel__generator': 7.6.8 908 | '@types/babel__template': 7.4.4 909 | '@types/babel__traverse': 7.20.6 910 | dev: true 911 | 912 | /@types/babel__generator@7.6.8: 913 | resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} 914 | dependencies: 915 | '@babel/types': 7.26.0 916 | dev: true 917 | 918 | /@types/babel__template@7.4.4: 919 | resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} 920 | dependencies: 921 | '@babel/parser': 7.26.1 922 | '@babel/types': 7.26.0 923 | dev: true 924 | 925 | /@types/babel__traverse@7.20.6: 926 | resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} 927 | dependencies: 928 | '@babel/types': 7.26.0 929 | dev: true 930 | 931 | /@types/estree@1.0.6: 932 | resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} 933 | dev: true 934 | 935 | /@types/json-schema@7.0.15: 936 | resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} 937 | dev: true 938 | 939 | /@types/lodash@4.17.12: 940 | resolution: {integrity: sha512-sviUmCE8AYdaF/KIHLDJBQgeYzPBI0vf/17NaYehBJfYD1j6/L95Slh07NlyK2iNyBNaEkb3En2jRt+a8y3xZQ==} 941 | dev: true 942 | 943 | /@types/parse-json@4.0.2: 944 | resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} 945 | dev: false 946 | 947 | /@types/prop-types@15.7.13: 948 | resolution: {integrity: sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==} 949 | 950 | /@types/react-dom@18.3.1: 951 | resolution: {integrity: sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==} 952 | dependencies: 953 | '@types/react': 18.3.12 954 | dev: true 955 | 956 | /@types/react@18.3.12: 957 | resolution: {integrity: sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==} 958 | dependencies: 959 | '@types/prop-types': 15.7.13 960 | csstype: 3.1.3 961 | 962 | /@typescript-eslint/eslint-plugin@8.11.0(@typescript-eslint/parser@8.11.0)(eslint@9.13.0)(typescript@5.6.3): 963 | resolution: {integrity: sha512-KhGn2LjW1PJT2A/GfDpiyOfS4a8xHQv2myUagTM5+zsormOmBlYsnQ6pobJ8XxJmh6hnHwa2Mbe3fPrDJoDhbA==} 964 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 965 | peerDependencies: 966 | '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 967 | eslint: ^8.57.0 || ^9.0.0 968 | typescript: '*' 969 | peerDependenciesMeta: 970 | typescript: 971 | optional: true 972 | dependencies: 973 | '@eslint-community/regexpp': 4.11.2 974 | '@typescript-eslint/parser': 8.11.0(eslint@9.13.0)(typescript@5.6.3) 975 | '@typescript-eslint/scope-manager': 8.11.0 976 | '@typescript-eslint/type-utils': 8.11.0(eslint@9.13.0)(typescript@5.6.3) 977 | '@typescript-eslint/utils': 8.11.0(eslint@9.13.0)(typescript@5.6.3) 978 | '@typescript-eslint/visitor-keys': 8.11.0 979 | eslint: 9.13.0 980 | graphemer: 1.4.0 981 | ignore: 5.3.2 982 | natural-compare: 1.4.0 983 | ts-api-utils: 1.3.0(typescript@5.6.3) 984 | typescript: 5.6.3 985 | transitivePeerDependencies: 986 | - supports-color 987 | dev: true 988 | 989 | /@typescript-eslint/parser@8.11.0(eslint@9.13.0)(typescript@5.6.3): 990 | resolution: {integrity: sha512-lmt73NeHdy1Q/2ul295Qy3uninSqi6wQI18XwSpm8w0ZbQXUpjCAWP1Vlv/obudoBiIjJVjlztjQ+d/Md98Yxg==} 991 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 992 | peerDependencies: 993 | eslint: ^8.57.0 || ^9.0.0 994 | typescript: '*' 995 | peerDependenciesMeta: 996 | typescript: 997 | optional: true 998 | dependencies: 999 | '@typescript-eslint/scope-manager': 8.11.0 1000 | '@typescript-eslint/types': 8.11.0 1001 | '@typescript-eslint/typescript-estree': 8.11.0(typescript@5.6.3) 1002 | '@typescript-eslint/visitor-keys': 8.11.0 1003 | debug: 4.3.7 1004 | eslint: 9.13.0 1005 | typescript: 5.6.3 1006 | transitivePeerDependencies: 1007 | - supports-color 1008 | dev: true 1009 | 1010 | /@typescript-eslint/scope-manager@8.11.0: 1011 | resolution: {integrity: sha512-Uholz7tWhXmA4r6epo+vaeV7yjdKy5QFCERMjs1kMVsLRKIrSdM6o21W2He9ftp5PP6aWOVpD5zvrvuHZC0bMQ==} 1012 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 1013 | dependencies: 1014 | '@typescript-eslint/types': 8.11.0 1015 | '@typescript-eslint/visitor-keys': 8.11.0 1016 | dev: true 1017 | 1018 | /@typescript-eslint/type-utils@8.11.0(eslint@9.13.0)(typescript@5.6.3): 1019 | resolution: {integrity: sha512-ItiMfJS6pQU0NIKAaybBKkuVzo6IdnAhPFZA/2Mba/uBjuPQPet/8+zh5GtLHwmuFRShZx+8lhIs7/QeDHflOg==} 1020 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 1021 | peerDependencies: 1022 | typescript: '*' 1023 | peerDependenciesMeta: 1024 | typescript: 1025 | optional: true 1026 | dependencies: 1027 | '@typescript-eslint/typescript-estree': 8.11.0(typescript@5.6.3) 1028 | '@typescript-eslint/utils': 8.11.0(eslint@9.13.0)(typescript@5.6.3) 1029 | debug: 4.3.7 1030 | ts-api-utils: 1.3.0(typescript@5.6.3) 1031 | typescript: 5.6.3 1032 | transitivePeerDependencies: 1033 | - eslint 1034 | - supports-color 1035 | dev: true 1036 | 1037 | /@typescript-eslint/types@8.11.0: 1038 | resolution: {integrity: sha512-tn6sNMHf6EBAYMvmPUaKaVeYvhUsrE6x+bXQTxjQRp360h1giATU0WvgeEys1spbvb5R+VpNOZ+XJmjD8wOUHw==} 1039 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 1040 | dev: true 1041 | 1042 | /@typescript-eslint/typescript-estree@8.11.0(typescript@5.6.3): 1043 | resolution: {integrity: sha512-yHC3s1z1RCHoCz5t06gf7jH24rr3vns08XXhfEqzYpd6Hll3z/3g23JRi0jM8A47UFKNc3u/y5KIMx8Ynbjohg==} 1044 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 1045 | peerDependencies: 1046 | typescript: '*' 1047 | peerDependenciesMeta: 1048 | typescript: 1049 | optional: true 1050 | dependencies: 1051 | '@typescript-eslint/types': 8.11.0 1052 | '@typescript-eslint/visitor-keys': 8.11.0 1053 | debug: 4.3.7 1054 | fast-glob: 3.3.2 1055 | is-glob: 4.0.3 1056 | minimatch: 9.0.5 1057 | semver: 7.6.3 1058 | ts-api-utils: 1.3.0(typescript@5.6.3) 1059 | typescript: 5.6.3 1060 | transitivePeerDependencies: 1061 | - supports-color 1062 | dev: true 1063 | 1064 | /@typescript-eslint/utils@8.11.0(eslint@9.13.0)(typescript@5.6.3): 1065 | resolution: {integrity: sha512-CYiX6WZcbXNJV7UNB4PLDIBtSdRmRI/nb0FMyqHPTQD1rMjA0foPLaPUV39C/MxkTd/QKSeX+Gb34PPsDVC35g==} 1066 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 1067 | peerDependencies: 1068 | eslint: ^8.57.0 || ^9.0.0 1069 | dependencies: 1070 | '@eslint-community/eslint-utils': 4.4.1(eslint@9.13.0) 1071 | '@typescript-eslint/scope-manager': 8.11.0 1072 | '@typescript-eslint/types': 8.11.0 1073 | '@typescript-eslint/typescript-estree': 8.11.0(typescript@5.6.3) 1074 | eslint: 9.13.0 1075 | transitivePeerDependencies: 1076 | - supports-color 1077 | - typescript 1078 | dev: true 1079 | 1080 | /@typescript-eslint/visitor-keys@8.11.0: 1081 | resolution: {integrity: sha512-EaewX6lxSjRJnc+99+dqzTeoDZUfyrA52d2/HRrkI830kgovWsmIiTfmr0NZorzqic7ga+1bS60lRBUgR3n/Bw==} 1082 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 1083 | dependencies: 1084 | '@typescript-eslint/types': 8.11.0 1085 | eslint-visitor-keys: 3.4.3 1086 | dev: true 1087 | 1088 | /@vitejs/plugin-react@4.3.3(vite@5.4.10): 1089 | resolution: {integrity: sha512-NooDe9GpHGqNns1i8XDERg0Vsg5SSYRhRxxyTGogUdkdNt47jal+fbuYi+Yfq6pzRCKXyoPcWisfxE6RIM3GKA==} 1090 | engines: {node: ^14.18.0 || >=16.0.0} 1091 | peerDependencies: 1092 | vite: ^4.2.0 || ^5.0.0 1093 | dependencies: 1094 | '@babel/core': 7.26.0 1095 | '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0) 1096 | '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0) 1097 | '@types/babel__core': 7.20.5 1098 | react-refresh: 0.14.2 1099 | vite: 5.4.10 1100 | transitivePeerDependencies: 1101 | - supports-color 1102 | dev: true 1103 | 1104 | /acorn-jsx@5.3.2(acorn@8.13.0): 1105 | resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} 1106 | peerDependencies: 1107 | acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 1108 | dependencies: 1109 | acorn: 8.13.0 1110 | dev: true 1111 | 1112 | /acorn@8.13.0: 1113 | resolution: {integrity: sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==} 1114 | engines: {node: '>=0.4.0'} 1115 | hasBin: true 1116 | dev: true 1117 | 1118 | /ajv@6.12.6: 1119 | resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} 1120 | dependencies: 1121 | fast-deep-equal: 3.1.3 1122 | fast-json-stable-stringify: 2.1.0 1123 | json-schema-traverse: 0.4.1 1124 | uri-js: 4.4.1 1125 | dev: true 1126 | 1127 | /ansi-styles@4.3.0: 1128 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 1129 | engines: {node: '>=8'} 1130 | dependencies: 1131 | color-convert: 2.0.1 1132 | dev: true 1133 | 1134 | /argparse@2.0.1: 1135 | resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} 1136 | dev: true 1137 | 1138 | /babel-plugin-macros@3.1.0: 1139 | resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} 1140 | engines: {node: '>=10', npm: '>=6'} 1141 | dependencies: 1142 | '@babel/runtime': 7.26.0 1143 | cosmiconfig: 7.1.0 1144 | resolve: 1.22.8 1145 | dev: false 1146 | 1147 | /balanced-match@1.0.2: 1148 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 1149 | dev: true 1150 | 1151 | /brace-expansion@1.1.11: 1152 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 1153 | dependencies: 1154 | balanced-match: 1.0.2 1155 | concat-map: 0.0.1 1156 | dev: true 1157 | 1158 | /brace-expansion@2.0.1: 1159 | resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} 1160 | dependencies: 1161 | balanced-match: 1.0.2 1162 | dev: true 1163 | 1164 | /braces@3.0.3: 1165 | resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} 1166 | engines: {node: '>=8'} 1167 | dependencies: 1168 | fill-range: 7.1.1 1169 | dev: true 1170 | 1171 | /browserslist@4.24.2: 1172 | resolution: {integrity: sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==} 1173 | engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} 1174 | hasBin: true 1175 | dependencies: 1176 | caniuse-lite: 1.0.30001671 1177 | electron-to-chromium: 1.5.47 1178 | node-releases: 2.0.18 1179 | update-browserslist-db: 1.1.1(browserslist@4.24.2) 1180 | dev: true 1181 | 1182 | /callsites@3.1.0: 1183 | resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} 1184 | engines: {node: '>=6'} 1185 | 1186 | /caniuse-lite@1.0.30001671: 1187 | resolution: {integrity: sha512-jocyVaSSfXg2faluE6hrWkMgDOiULBMca4QLtDT39hw1YxaIPHWc1CcTCKkPmHgGH6tKji6ZNbMSmUAvENf2/A==} 1188 | dev: true 1189 | 1190 | /chalk@4.1.2: 1191 | resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 1192 | engines: {node: '>=10'} 1193 | dependencies: 1194 | ansi-styles: 4.3.0 1195 | supports-color: 7.2.0 1196 | dev: true 1197 | 1198 | /color-convert@2.0.1: 1199 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 1200 | engines: {node: '>=7.0.0'} 1201 | dependencies: 1202 | color-name: 1.1.4 1203 | dev: true 1204 | 1205 | /color-name@1.1.4: 1206 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 1207 | dev: true 1208 | 1209 | /concat-map@0.0.1: 1210 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} 1211 | dev: true 1212 | 1213 | /convert-source-map@1.9.0: 1214 | resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} 1215 | dev: false 1216 | 1217 | /convert-source-map@2.0.0: 1218 | resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} 1219 | dev: true 1220 | 1221 | /cosmiconfig@7.1.0: 1222 | resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} 1223 | engines: {node: '>=10'} 1224 | dependencies: 1225 | '@types/parse-json': 4.0.2 1226 | import-fresh: 3.3.0 1227 | parse-json: 5.2.0 1228 | path-type: 4.0.0 1229 | yaml: 1.10.2 1230 | dev: false 1231 | 1232 | /cross-spawn@7.0.3: 1233 | resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} 1234 | engines: {node: '>= 8'} 1235 | dependencies: 1236 | path-key: 3.1.1 1237 | shebang-command: 2.0.0 1238 | which: 2.0.2 1239 | dev: true 1240 | 1241 | /csstype@3.1.3: 1242 | resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} 1243 | 1244 | /dayjs@1.11.13: 1245 | resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} 1246 | dev: false 1247 | 1248 | /debug@4.3.7: 1249 | resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} 1250 | engines: {node: '>=6.0'} 1251 | peerDependencies: 1252 | supports-color: '*' 1253 | peerDependenciesMeta: 1254 | supports-color: 1255 | optional: true 1256 | dependencies: 1257 | ms: 2.1.3 1258 | 1259 | /deep-is@0.1.4: 1260 | resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} 1261 | dev: true 1262 | 1263 | /electron-to-chromium@1.5.47: 1264 | resolution: {integrity: sha512-zS5Yer0MOYw4rtK2iq43cJagHZ8sXN0jDHDKzB+86gSBSAI4v07S97mcq+Gs2vclAxSh1j7vOAHxSVgduiiuVQ==} 1265 | dev: true 1266 | 1267 | /error-ex@1.3.2: 1268 | resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} 1269 | dependencies: 1270 | is-arrayish: 0.2.1 1271 | dev: false 1272 | 1273 | /esbuild@0.21.5: 1274 | resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} 1275 | engines: {node: '>=12'} 1276 | hasBin: true 1277 | requiresBuild: true 1278 | optionalDependencies: 1279 | '@esbuild/aix-ppc64': 0.21.5 1280 | '@esbuild/android-arm': 0.21.5 1281 | '@esbuild/android-arm64': 0.21.5 1282 | '@esbuild/android-x64': 0.21.5 1283 | '@esbuild/darwin-arm64': 0.21.5 1284 | '@esbuild/darwin-x64': 0.21.5 1285 | '@esbuild/freebsd-arm64': 0.21.5 1286 | '@esbuild/freebsd-x64': 0.21.5 1287 | '@esbuild/linux-arm': 0.21.5 1288 | '@esbuild/linux-arm64': 0.21.5 1289 | '@esbuild/linux-ia32': 0.21.5 1290 | '@esbuild/linux-loong64': 0.21.5 1291 | '@esbuild/linux-mips64el': 0.21.5 1292 | '@esbuild/linux-ppc64': 0.21.5 1293 | '@esbuild/linux-riscv64': 0.21.5 1294 | '@esbuild/linux-s390x': 0.21.5 1295 | '@esbuild/linux-x64': 0.21.5 1296 | '@esbuild/netbsd-x64': 0.21.5 1297 | '@esbuild/openbsd-x64': 0.21.5 1298 | '@esbuild/sunos-x64': 0.21.5 1299 | '@esbuild/win32-arm64': 0.21.5 1300 | '@esbuild/win32-ia32': 0.21.5 1301 | '@esbuild/win32-x64': 0.21.5 1302 | dev: true 1303 | 1304 | /escalade@3.2.0: 1305 | resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} 1306 | engines: {node: '>=6'} 1307 | dev: true 1308 | 1309 | /escape-string-regexp@4.0.0: 1310 | resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} 1311 | engines: {node: '>=10'} 1312 | 1313 | /eslint-plugin-react-hooks@5.0.0(eslint@9.13.0): 1314 | resolution: {integrity: sha512-hIOwI+5hYGpJEc4uPRmz2ulCjAGD/N13Lukkh8cLV0i2IRk/bdZDYjgLVHj+U9Z704kLIdIO6iueGvxNur0sgw==} 1315 | engines: {node: '>=10'} 1316 | peerDependencies: 1317 | eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 1318 | dependencies: 1319 | eslint: 9.13.0 1320 | dev: true 1321 | 1322 | /eslint-plugin-react-refresh@0.4.14(eslint@9.13.0): 1323 | resolution: {integrity: sha512-aXvzCTK7ZBv1e7fahFuR3Z/fyQQSIQ711yPgYRj+Oj64tyTgO4iQIDmYXDBqvSWQ/FA4OSCsXOStlF+noU0/NA==} 1324 | peerDependencies: 1325 | eslint: '>=7' 1326 | dependencies: 1327 | eslint: 9.13.0 1328 | dev: true 1329 | 1330 | /eslint-scope@8.1.0: 1331 | resolution: {integrity: sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==} 1332 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 1333 | dependencies: 1334 | esrecurse: 4.3.0 1335 | estraverse: 5.3.0 1336 | dev: true 1337 | 1338 | /eslint-visitor-keys@3.4.3: 1339 | resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} 1340 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 1341 | dev: true 1342 | 1343 | /eslint-visitor-keys@4.1.0: 1344 | resolution: {integrity: sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==} 1345 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 1346 | dev: true 1347 | 1348 | /eslint@9.13.0: 1349 | resolution: {integrity: sha512-EYZK6SX6zjFHST/HRytOdA/zE72Cq/bfw45LSyuwrdvcclb/gqV8RRQxywOBEWO2+WDpva6UZa4CcDeJKzUCFA==} 1350 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 1351 | hasBin: true 1352 | peerDependencies: 1353 | jiti: '*' 1354 | peerDependenciesMeta: 1355 | jiti: 1356 | optional: true 1357 | dependencies: 1358 | '@eslint-community/eslint-utils': 4.4.1(eslint@9.13.0) 1359 | '@eslint-community/regexpp': 4.11.2 1360 | '@eslint/config-array': 0.18.0 1361 | '@eslint/core': 0.7.0 1362 | '@eslint/eslintrc': 3.1.0 1363 | '@eslint/js': 9.13.0 1364 | '@eslint/plugin-kit': 0.2.1 1365 | '@humanfs/node': 0.16.5 1366 | '@humanwhocodes/module-importer': 1.0.1 1367 | '@humanwhocodes/retry': 0.3.1 1368 | '@types/estree': 1.0.6 1369 | '@types/json-schema': 7.0.15 1370 | ajv: 6.12.6 1371 | chalk: 4.1.2 1372 | cross-spawn: 7.0.3 1373 | debug: 4.3.7 1374 | escape-string-regexp: 4.0.0 1375 | eslint-scope: 8.1.0 1376 | eslint-visitor-keys: 4.1.0 1377 | espree: 10.2.0 1378 | esquery: 1.6.0 1379 | esutils: 2.0.3 1380 | fast-deep-equal: 3.1.3 1381 | file-entry-cache: 8.0.0 1382 | find-up: 5.0.0 1383 | glob-parent: 6.0.2 1384 | ignore: 5.3.2 1385 | imurmurhash: 0.1.4 1386 | is-glob: 4.0.3 1387 | json-stable-stringify-without-jsonify: 1.0.1 1388 | lodash.merge: 4.6.2 1389 | minimatch: 3.1.2 1390 | natural-compare: 1.4.0 1391 | optionator: 0.9.4 1392 | text-table: 0.2.0 1393 | transitivePeerDependencies: 1394 | - supports-color 1395 | dev: true 1396 | 1397 | /espree@10.2.0: 1398 | resolution: {integrity: sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==} 1399 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 1400 | dependencies: 1401 | acorn: 8.13.0 1402 | acorn-jsx: 5.3.2(acorn@8.13.0) 1403 | eslint-visitor-keys: 4.1.0 1404 | dev: true 1405 | 1406 | /esquery@1.6.0: 1407 | resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} 1408 | engines: {node: '>=0.10'} 1409 | dependencies: 1410 | estraverse: 5.3.0 1411 | dev: true 1412 | 1413 | /esrecurse@4.3.0: 1414 | resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} 1415 | engines: {node: '>=4.0'} 1416 | dependencies: 1417 | estraverse: 5.3.0 1418 | dev: true 1419 | 1420 | /estraverse@5.3.0: 1421 | resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} 1422 | engines: {node: '>=4.0'} 1423 | dev: true 1424 | 1425 | /estree-walker@2.0.2: 1426 | resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} 1427 | dev: true 1428 | 1429 | /esutils@2.0.3: 1430 | resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} 1431 | engines: {node: '>=0.10.0'} 1432 | dev: true 1433 | 1434 | /fast-deep-equal@3.1.3: 1435 | resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 1436 | dev: true 1437 | 1438 | /fast-glob@3.3.2: 1439 | resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} 1440 | engines: {node: '>=8.6.0'} 1441 | dependencies: 1442 | '@nodelib/fs.stat': 2.0.5 1443 | '@nodelib/fs.walk': 1.2.8 1444 | glob-parent: 5.1.2 1445 | merge2: 1.4.1 1446 | micromatch: 4.0.8 1447 | dev: true 1448 | 1449 | /fast-json-stable-stringify@2.1.0: 1450 | resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} 1451 | dev: true 1452 | 1453 | /fast-levenshtein@2.0.6: 1454 | resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} 1455 | dev: true 1456 | 1457 | /fastq@1.17.1: 1458 | resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} 1459 | dependencies: 1460 | reusify: 1.0.4 1461 | dev: true 1462 | 1463 | /file-entry-cache@8.0.0: 1464 | resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} 1465 | engines: {node: '>=16.0.0'} 1466 | dependencies: 1467 | flat-cache: 4.0.1 1468 | dev: true 1469 | 1470 | /fill-range@7.1.1: 1471 | resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} 1472 | engines: {node: '>=8'} 1473 | dependencies: 1474 | to-regex-range: 5.0.1 1475 | dev: true 1476 | 1477 | /find-root@1.1.0: 1478 | resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} 1479 | dev: false 1480 | 1481 | /find-up@5.0.0: 1482 | resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} 1483 | engines: {node: '>=10'} 1484 | dependencies: 1485 | locate-path: 6.0.0 1486 | path-exists: 4.0.0 1487 | dev: true 1488 | 1489 | /flat-cache@4.0.1: 1490 | resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} 1491 | engines: {node: '>=16'} 1492 | dependencies: 1493 | flatted: 3.3.1 1494 | keyv: 4.5.4 1495 | dev: true 1496 | 1497 | /flatbuffers@24.3.25: 1498 | resolution: {integrity: sha512-3HDgPbgiwWMI9zVB7VYBHaMrbOO7Gm0v+yD2FV/sCKj+9NDeVL7BOBYUuhWAQGKWOzBo8S9WdMvV0eixO233XQ==} 1499 | dev: false 1500 | 1501 | /flatted@3.3.1: 1502 | resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} 1503 | dev: true 1504 | 1505 | /fsevents@2.3.3: 1506 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 1507 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 1508 | os: [darwin] 1509 | requiresBuild: true 1510 | dev: true 1511 | optional: true 1512 | 1513 | /function-bind@1.1.2: 1514 | resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 1515 | dev: false 1516 | 1517 | /gensync@1.0.0-beta.2: 1518 | resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} 1519 | engines: {node: '>=6.9.0'} 1520 | dev: true 1521 | 1522 | /gl-matrix@3.4.3: 1523 | resolution: {integrity: sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==} 1524 | dev: false 1525 | 1526 | /glob-parent@5.1.2: 1527 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 1528 | engines: {node: '>= 6'} 1529 | dependencies: 1530 | is-glob: 4.0.3 1531 | dev: true 1532 | 1533 | /glob-parent@6.0.2: 1534 | resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} 1535 | engines: {node: '>=10.13.0'} 1536 | dependencies: 1537 | is-glob: 4.0.3 1538 | dev: true 1539 | 1540 | /globals@11.12.0: 1541 | resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} 1542 | engines: {node: '>=4'} 1543 | 1544 | /globals@14.0.0: 1545 | resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} 1546 | engines: {node: '>=18'} 1547 | dev: true 1548 | 1549 | /globals@15.11.0: 1550 | resolution: {integrity: sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw==} 1551 | engines: {node: '>=18'} 1552 | dev: true 1553 | 1554 | /globrex@0.1.2: 1555 | resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} 1556 | dev: true 1557 | 1558 | /graphemer@1.4.0: 1559 | resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} 1560 | dev: true 1561 | 1562 | /has-flag@4.0.0: 1563 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 1564 | engines: {node: '>=8'} 1565 | dev: true 1566 | 1567 | /hasown@2.0.2: 1568 | resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} 1569 | engines: {node: '>= 0.4'} 1570 | dependencies: 1571 | function-bind: 1.1.2 1572 | dev: false 1573 | 1574 | /hoist-non-react-statics@3.3.2: 1575 | resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} 1576 | dependencies: 1577 | react-is: 16.13.1 1578 | dev: false 1579 | 1580 | /ignore@5.3.2: 1581 | resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} 1582 | engines: {node: '>= 4'} 1583 | dev: true 1584 | 1585 | /import-fresh@3.3.0: 1586 | resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} 1587 | engines: {node: '>=6'} 1588 | dependencies: 1589 | parent-module: 1.0.1 1590 | resolve-from: 4.0.0 1591 | 1592 | /imurmurhash@0.1.4: 1593 | resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} 1594 | engines: {node: '>=0.8.19'} 1595 | dev: true 1596 | 1597 | /is-arrayish@0.2.1: 1598 | resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} 1599 | dev: false 1600 | 1601 | /is-core-module@2.15.1: 1602 | resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} 1603 | engines: {node: '>= 0.4'} 1604 | dependencies: 1605 | hasown: 2.0.2 1606 | dev: false 1607 | 1608 | /is-extglob@2.1.1: 1609 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 1610 | engines: {node: '>=0.10.0'} 1611 | dev: true 1612 | 1613 | /is-glob@4.0.3: 1614 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 1615 | engines: {node: '>=0.10.0'} 1616 | dependencies: 1617 | is-extglob: 2.1.1 1618 | dev: true 1619 | 1620 | /is-number@7.0.0: 1621 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 1622 | engines: {node: '>=0.12.0'} 1623 | dev: true 1624 | 1625 | /isexe@2.0.0: 1626 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 1627 | dev: true 1628 | 1629 | /js-tokens@4.0.0: 1630 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} 1631 | 1632 | /js-yaml@4.1.0: 1633 | resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} 1634 | hasBin: true 1635 | dependencies: 1636 | argparse: 2.0.1 1637 | dev: true 1638 | 1639 | /jsesc@3.0.2: 1640 | resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} 1641 | engines: {node: '>=6'} 1642 | hasBin: true 1643 | 1644 | /json-buffer@3.0.1: 1645 | resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} 1646 | dev: true 1647 | 1648 | /json-parse-even-better-errors@2.3.1: 1649 | resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} 1650 | dev: false 1651 | 1652 | /json-schema-traverse@0.4.1: 1653 | resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} 1654 | dev: true 1655 | 1656 | /json-stable-stringify-without-jsonify@1.0.1: 1657 | resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} 1658 | dev: true 1659 | 1660 | /json5@2.2.3: 1661 | resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} 1662 | engines: {node: '>=6'} 1663 | hasBin: true 1664 | dev: true 1665 | 1666 | /keyv@4.5.4: 1667 | resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} 1668 | dependencies: 1669 | json-buffer: 3.0.1 1670 | dev: true 1671 | 1672 | /levn@0.4.1: 1673 | resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} 1674 | engines: {node: '>= 0.8.0'} 1675 | dependencies: 1676 | prelude-ls: 1.2.1 1677 | type-check: 0.4.0 1678 | dev: true 1679 | 1680 | /lines-and-columns@1.2.4: 1681 | resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} 1682 | dev: false 1683 | 1684 | /locate-path@6.0.0: 1685 | resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} 1686 | engines: {node: '>=10'} 1687 | dependencies: 1688 | p-locate: 5.0.0 1689 | dev: true 1690 | 1691 | /lodash.merge@4.6.2: 1692 | resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} 1693 | dev: true 1694 | 1695 | /lodash@4.17.21: 1696 | resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} 1697 | dev: false 1698 | 1699 | /loose-envify@1.4.0: 1700 | resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} 1701 | hasBin: true 1702 | dependencies: 1703 | js-tokens: 4.0.0 1704 | dev: false 1705 | 1706 | /lru-cache@5.1.1: 1707 | resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} 1708 | dependencies: 1709 | yallist: 3.1.1 1710 | dev: true 1711 | 1712 | /merge2@1.4.1: 1713 | resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} 1714 | engines: {node: '>= 8'} 1715 | dev: true 1716 | 1717 | /micromatch@4.0.8: 1718 | resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} 1719 | engines: {node: '>=8.6'} 1720 | dependencies: 1721 | braces: 3.0.3 1722 | picomatch: 2.3.1 1723 | dev: true 1724 | 1725 | /minimatch@3.1.2: 1726 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} 1727 | dependencies: 1728 | brace-expansion: 1.1.11 1729 | dev: true 1730 | 1731 | /minimatch@9.0.5: 1732 | resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} 1733 | engines: {node: '>=16 || 14 >=14.17'} 1734 | dependencies: 1735 | brace-expansion: 2.0.1 1736 | dev: true 1737 | 1738 | /ms@2.1.3: 1739 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 1740 | 1741 | /nanoid@3.3.7: 1742 | resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} 1743 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 1744 | hasBin: true 1745 | dev: true 1746 | 1747 | /natural-compare@1.4.0: 1748 | resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} 1749 | dev: true 1750 | 1751 | /node-releases@2.0.18: 1752 | resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} 1753 | dev: true 1754 | 1755 | /normalize.css@8.0.1: 1756 | resolution: {integrity: sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==} 1757 | dev: false 1758 | 1759 | /openmeteo@1.1.4: 1760 | resolution: {integrity: sha512-TalTDl0M7JJoeRTf+rWiFZ9SLvoxm7KkFLOQqcSjCiYs+bVMhax1qtryJqeZ1RF4W4Xfsgcl9x+VC1z39ULCxA==} 1761 | engines: {node: '>=12.0'} 1762 | dependencies: 1763 | '@openmeteo/sdk': 1.18.0 1764 | flatbuffers: 24.3.25 1765 | dev: false 1766 | 1767 | /optionator@0.9.4: 1768 | resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} 1769 | engines: {node: '>= 0.8.0'} 1770 | dependencies: 1771 | deep-is: 0.1.4 1772 | fast-levenshtein: 2.0.6 1773 | levn: 0.4.1 1774 | prelude-ls: 1.2.1 1775 | type-check: 0.4.0 1776 | word-wrap: 1.2.5 1777 | dev: true 1778 | 1779 | /p-limit@3.1.0: 1780 | resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} 1781 | engines: {node: '>=10'} 1782 | dependencies: 1783 | yocto-queue: 0.1.0 1784 | dev: true 1785 | 1786 | /p-locate@5.0.0: 1787 | resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} 1788 | engines: {node: '>=10'} 1789 | dependencies: 1790 | p-limit: 3.1.0 1791 | dev: true 1792 | 1793 | /parent-module@1.0.1: 1794 | resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} 1795 | engines: {node: '>=6'} 1796 | dependencies: 1797 | callsites: 3.1.0 1798 | 1799 | /parse-json@5.2.0: 1800 | resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} 1801 | engines: {node: '>=8'} 1802 | dependencies: 1803 | '@babel/code-frame': 7.26.0 1804 | error-ex: 1.3.2 1805 | json-parse-even-better-errors: 2.3.1 1806 | lines-and-columns: 1.2.4 1807 | dev: false 1808 | 1809 | /path-exists@4.0.0: 1810 | resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} 1811 | engines: {node: '>=8'} 1812 | dev: true 1813 | 1814 | /path-key@3.1.1: 1815 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 1816 | engines: {node: '>=8'} 1817 | dev: true 1818 | 1819 | /path-parse@1.0.7: 1820 | resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} 1821 | dev: false 1822 | 1823 | /path-type@4.0.0: 1824 | resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} 1825 | engines: {node: '>=8'} 1826 | dev: false 1827 | 1828 | /picocolors@1.1.1: 1829 | resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 1830 | 1831 | /picomatch@2.3.1: 1832 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 1833 | engines: {node: '>=8.6'} 1834 | dev: true 1835 | 1836 | /picomatch@4.0.2: 1837 | resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} 1838 | engines: {node: '>=12'} 1839 | dev: true 1840 | 1841 | /postcss@8.4.47: 1842 | resolution: {integrity: sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==} 1843 | engines: {node: ^10 || ^12 || >=14} 1844 | dependencies: 1845 | nanoid: 3.3.7 1846 | picocolors: 1.1.1 1847 | source-map-js: 1.2.1 1848 | dev: true 1849 | 1850 | /prelude-ls@1.2.1: 1851 | resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} 1852 | engines: {node: '>= 0.8.0'} 1853 | dev: true 1854 | 1855 | /prettier@3.3.3: 1856 | resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} 1857 | engines: {node: '>=14'} 1858 | hasBin: true 1859 | dev: true 1860 | 1861 | /punycode@2.3.1: 1862 | resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} 1863 | engines: {node: '>=6'} 1864 | dev: true 1865 | 1866 | /queue-microtask@1.2.3: 1867 | resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} 1868 | dev: true 1869 | 1870 | /raindrop-fx@1.0.8: 1871 | resolution: {integrity: sha512-KcCeENGsFN70jVpdmRTxUJiU012oUhrHdR0n6XmMy2euJu95QcB2Uv5Om/mzzZGoyRcD650+H5yP/Q54mdi1Pw==} 1872 | dependencies: 1873 | '@sardinefish/zogra-renderer': 1.2.0 1874 | dev: false 1875 | 1876 | /react-dom@18.3.1(react@18.3.1): 1877 | resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} 1878 | peerDependencies: 1879 | react: ^18.3.1 1880 | dependencies: 1881 | loose-envify: 1.4.0 1882 | react: 18.3.1 1883 | scheduler: 0.23.2 1884 | dev: false 1885 | 1886 | /react-icons@5.3.0(react@18.3.1): 1887 | resolution: {integrity: sha512-DnUk8aFbTyQPSkCfF8dbX6kQjXA9DktMeJqfjrg6cK9vwQVMxmcA3BfP4QoiztVmEHtwlTgLFsPuH2NskKT6eg==} 1888 | peerDependencies: 1889 | react: '*' 1890 | dependencies: 1891 | react: 18.3.1 1892 | dev: false 1893 | 1894 | /react-is@16.13.1: 1895 | resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} 1896 | dev: false 1897 | 1898 | /react-refresh@0.14.2: 1899 | resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} 1900 | engines: {node: '>=0.10.0'} 1901 | dev: true 1902 | 1903 | /react@18.3.1: 1904 | resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} 1905 | engines: {node: '>=0.10.0'} 1906 | dependencies: 1907 | loose-envify: 1.4.0 1908 | dev: false 1909 | 1910 | /reflect-metadata@0.1.14: 1911 | resolution: {integrity: sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==} 1912 | dev: false 1913 | 1914 | /regenerator-runtime@0.14.1: 1915 | resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} 1916 | dev: false 1917 | 1918 | /resolve-from@4.0.0: 1919 | resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} 1920 | engines: {node: '>=4'} 1921 | 1922 | /resolve@1.22.8: 1923 | resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} 1924 | hasBin: true 1925 | dependencies: 1926 | is-core-module: 2.15.1 1927 | path-parse: 1.0.7 1928 | supports-preserve-symlinks-flag: 1.0.0 1929 | dev: false 1930 | 1931 | /reusify@1.0.4: 1932 | resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} 1933 | engines: {iojs: '>=1.0.0', node: '>=0.10.0'} 1934 | dev: true 1935 | 1936 | /rollup@4.24.0: 1937 | resolution: {integrity: sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==} 1938 | engines: {node: '>=18.0.0', npm: '>=8.0.0'} 1939 | hasBin: true 1940 | dependencies: 1941 | '@types/estree': 1.0.6 1942 | optionalDependencies: 1943 | '@rollup/rollup-android-arm-eabi': 4.24.0 1944 | '@rollup/rollup-android-arm64': 4.24.0 1945 | '@rollup/rollup-darwin-arm64': 4.24.0 1946 | '@rollup/rollup-darwin-x64': 4.24.0 1947 | '@rollup/rollup-linux-arm-gnueabihf': 4.24.0 1948 | '@rollup/rollup-linux-arm-musleabihf': 4.24.0 1949 | '@rollup/rollup-linux-arm64-gnu': 4.24.0 1950 | '@rollup/rollup-linux-arm64-musl': 4.24.0 1951 | '@rollup/rollup-linux-powerpc64le-gnu': 4.24.0 1952 | '@rollup/rollup-linux-riscv64-gnu': 4.24.0 1953 | '@rollup/rollup-linux-s390x-gnu': 4.24.0 1954 | '@rollup/rollup-linux-x64-gnu': 4.24.0 1955 | '@rollup/rollup-linux-x64-musl': 4.24.0 1956 | '@rollup/rollup-win32-arm64-msvc': 4.24.0 1957 | '@rollup/rollup-win32-ia32-msvc': 4.24.0 1958 | '@rollup/rollup-win32-x64-msvc': 4.24.0 1959 | fsevents: 2.3.3 1960 | dev: true 1961 | 1962 | /run-parallel@1.2.0: 1963 | resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} 1964 | dependencies: 1965 | queue-microtask: 1.2.3 1966 | dev: true 1967 | 1968 | /scheduler@0.23.2: 1969 | resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} 1970 | dependencies: 1971 | loose-envify: 1.4.0 1972 | dev: false 1973 | 1974 | /semver@6.3.1: 1975 | resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} 1976 | hasBin: true 1977 | dev: true 1978 | 1979 | /semver@7.6.3: 1980 | resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} 1981 | engines: {node: '>=10'} 1982 | hasBin: true 1983 | dev: true 1984 | 1985 | /shebang-command@2.0.0: 1986 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 1987 | engines: {node: '>=8'} 1988 | dependencies: 1989 | shebang-regex: 3.0.0 1990 | dev: true 1991 | 1992 | /shebang-regex@3.0.0: 1993 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 1994 | engines: {node: '>=8'} 1995 | dev: true 1996 | 1997 | /source-map-js@1.2.1: 1998 | resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 1999 | engines: {node: '>=0.10.0'} 2000 | dev: true 2001 | 2002 | /source-map@0.5.7: 2003 | resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} 2004 | engines: {node: '>=0.10.0'} 2005 | dev: false 2006 | 2007 | /strip-json-comments@3.1.1: 2008 | resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} 2009 | engines: {node: '>=8'} 2010 | dev: true 2011 | 2012 | /stylis@4.2.0: 2013 | resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} 2014 | dev: false 2015 | 2016 | /supports-color@7.2.0: 2017 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 2018 | engines: {node: '>=8'} 2019 | dependencies: 2020 | has-flag: 4.0.0 2021 | dev: true 2022 | 2023 | /supports-preserve-symlinks-flag@1.0.0: 2024 | resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} 2025 | engines: {node: '>= 0.4'} 2026 | dev: false 2027 | 2028 | /text-table@0.2.0: 2029 | resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} 2030 | dev: true 2031 | 2032 | /to-regex-range@5.0.1: 2033 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 2034 | engines: {node: '>=8.0'} 2035 | dependencies: 2036 | is-number: 7.0.0 2037 | dev: true 2038 | 2039 | /ts-api-utils@1.3.0(typescript@5.6.3): 2040 | resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} 2041 | engines: {node: '>=16'} 2042 | peerDependencies: 2043 | typescript: '>=4.2.0' 2044 | dependencies: 2045 | typescript: 5.6.3 2046 | dev: true 2047 | 2048 | /tsconfck@3.1.4(typescript@5.6.3): 2049 | resolution: {integrity: sha512-kdqWFGVJqe+KGYvlSO9NIaWn9jT1Ny4oKVzAJsKii5eoE9snzTJzL4+MMVOMn+fikWGFmKEylcXL710V/kIPJQ==} 2050 | engines: {node: ^18 || >=20} 2051 | hasBin: true 2052 | peerDependencies: 2053 | typescript: ^5.0.0 2054 | peerDependenciesMeta: 2055 | typescript: 2056 | optional: true 2057 | dependencies: 2058 | typescript: 5.6.3 2059 | dev: true 2060 | 2061 | /type-check@0.4.0: 2062 | resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} 2063 | engines: {node: '>= 0.8.0'} 2064 | dependencies: 2065 | prelude-ls: 1.2.1 2066 | dev: true 2067 | 2068 | /typescript-eslint@8.11.0(eslint@9.13.0)(typescript@5.6.3): 2069 | resolution: {integrity: sha512-cBRGnW3FSlxaYwU8KfAewxFK5uzeOAp0l2KebIlPDOT5olVi65KDG/yjBooPBG0kGW/HLkoz1c/iuBFehcS3IA==} 2070 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 2071 | peerDependencies: 2072 | typescript: '*' 2073 | peerDependenciesMeta: 2074 | typescript: 2075 | optional: true 2076 | dependencies: 2077 | '@typescript-eslint/eslint-plugin': 8.11.0(@typescript-eslint/parser@8.11.0)(eslint@9.13.0)(typescript@5.6.3) 2078 | '@typescript-eslint/parser': 8.11.0(eslint@9.13.0)(typescript@5.6.3) 2079 | '@typescript-eslint/utils': 8.11.0(eslint@9.13.0)(typescript@5.6.3) 2080 | typescript: 5.6.3 2081 | transitivePeerDependencies: 2082 | - eslint 2083 | - supports-color 2084 | dev: true 2085 | 2086 | /typescript@5.6.3: 2087 | resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} 2088 | engines: {node: '>=14.17'} 2089 | hasBin: true 2090 | dev: true 2091 | 2092 | /update-browserslist-db@1.1.1(browserslist@4.24.2): 2093 | resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} 2094 | hasBin: true 2095 | peerDependencies: 2096 | browserslist: '>= 4.21.0' 2097 | dependencies: 2098 | browserslist: 4.24.2 2099 | escalade: 3.2.0 2100 | picocolors: 1.1.1 2101 | dev: true 2102 | 2103 | /uri-js@4.4.1: 2104 | resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} 2105 | dependencies: 2106 | punycode: 2.3.1 2107 | dev: true 2108 | 2109 | /vite-plugin-glsl@1.3.0(vite@5.4.10): 2110 | resolution: {integrity: sha512-SzEoLet9Bp5VSozjrhUiSc3xX1+u7rCTjXAsq4qWM3u8UjilI76A9ucX/T+CRGQCe25j50GSY+9mKSGUVPET1w==} 2111 | engines: {node: '>= 16.15.1', npm: '>= 8.11.0'} 2112 | peerDependencies: 2113 | vite: ^3.0.0 || ^4.0.0 || ^5.0.0 2114 | dependencies: 2115 | '@rollup/pluginutils': 5.1.3 2116 | vite: 5.4.10 2117 | transitivePeerDependencies: 2118 | - rollup 2119 | dev: true 2120 | 2121 | /vite-tsconfig-paths@5.0.1(typescript@5.6.3)(vite@5.4.10): 2122 | resolution: {integrity: sha512-yqwv+LstU7NwPeNqajZzLEBVpUFU6Dugtb2P84FXuvaoYA+/70l9MHE+GYfYAycVyPSDYZ7mjOFuYBRqlEpTig==} 2123 | peerDependencies: 2124 | vite: '*' 2125 | peerDependenciesMeta: 2126 | vite: 2127 | optional: true 2128 | dependencies: 2129 | debug: 4.3.7 2130 | globrex: 0.1.2 2131 | tsconfck: 3.1.4(typescript@5.6.3) 2132 | vite: 5.4.10 2133 | transitivePeerDependencies: 2134 | - supports-color 2135 | - typescript 2136 | dev: true 2137 | 2138 | /vite@5.4.10: 2139 | resolution: {integrity: sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==} 2140 | engines: {node: ^18.0.0 || >=20.0.0} 2141 | hasBin: true 2142 | peerDependencies: 2143 | '@types/node': ^18.0.0 || >=20.0.0 2144 | less: '*' 2145 | lightningcss: ^1.21.0 2146 | sass: '*' 2147 | sass-embedded: '*' 2148 | stylus: '*' 2149 | sugarss: '*' 2150 | terser: ^5.4.0 2151 | peerDependenciesMeta: 2152 | '@types/node': 2153 | optional: true 2154 | less: 2155 | optional: true 2156 | lightningcss: 2157 | optional: true 2158 | sass: 2159 | optional: true 2160 | sass-embedded: 2161 | optional: true 2162 | stylus: 2163 | optional: true 2164 | sugarss: 2165 | optional: true 2166 | terser: 2167 | optional: true 2168 | dependencies: 2169 | esbuild: 0.21.5 2170 | postcss: 8.4.47 2171 | rollup: 4.24.0 2172 | optionalDependencies: 2173 | fsevents: 2.3.3 2174 | dev: true 2175 | 2176 | /which@2.0.2: 2177 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 2178 | engines: {node: '>= 8'} 2179 | hasBin: true 2180 | dependencies: 2181 | isexe: 2.0.0 2182 | dev: true 2183 | 2184 | /word-wrap@1.2.5: 2185 | resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} 2186 | engines: {node: '>=0.10.0'} 2187 | dev: true 2188 | 2189 | /yallist@3.1.1: 2190 | resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} 2191 | dev: true 2192 | 2193 | /yaml@1.10.2: 2194 | resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} 2195 | engines: {node: '>= 6'} 2196 | dev: false 2197 | 2198 | /yocto-queue@0.1.0: 2199 | resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} 2200 | engines: {node: '>=10'} 2201 | dev: true 2202 | 2203 | /zustand@5.0.0(@types/react@18.3.12)(react@18.3.1): 2204 | resolution: {integrity: sha512-LE+VcmbartOPM+auOjCCLQOsQ05zUTp8RkgwRzefUk+2jISdMMFnxvyTjA4YNWr5ZGXYbVsEMZosttuxUBkojQ==} 2205 | engines: {node: '>=12.20.0'} 2206 | peerDependencies: 2207 | '@types/react': '>=18.0.0' 2208 | immer: '>=9.0.6' 2209 | react: '>=18.0.0' 2210 | use-sync-external-store: '>=1.2.0' 2211 | peerDependenciesMeta: 2212 | '@types/react': 2213 | optional: true 2214 | immer: 2215 | optional: true 2216 | react: 2217 | optional: true 2218 | use-sync-external-store: 2219 | optional: true 2220 | dependencies: 2221 | '@types/react': 18.3.12 2222 | react: 18.3.1 2223 | dev: false 2224 | --------------------------------------------------------------------------------