├── .env.example ├── .eslintrc.json ├── .gitignore ├── LICENSE ├── README.md ├── cfbackend ├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── src │ └── index.ts ├── tsconfig.json ├── worker-configuration.d.ts └── wrangler.toml ├── next.config.mjs ├── package-lock.json ├── package.json ├── postcss.config.mjs ├── public ├── fallback-Nmugk_Zyk-6l0kLaNJUk1.js ├── favicon.ico ├── fonts │ ├── comfortaa.ttf │ └── roboto_mono.ttf ├── logo.png ├── next.svg ├── og.png ├── preview.png ├── sw.js ├── vercel.svg ├── wallpaper1.jpg ├── wallpaper2.jpg ├── wallpaper3.jpg ├── wallpaper4.jpg ├── wallpaper5.jpg └── workbox-4754cb34.js ├── src ├── components │ ├── Chat.tsx │ ├── Icons │ │ ├── BackupIcon.tsx │ │ ├── BingIcon.tsx │ │ ├── CrossIcon.tsx │ │ ├── DiceIcon.tsx │ │ ├── DiscordIcon.tsx │ │ ├── DuckDuckGoIcon.tsx │ │ ├── EditIcon.tsx │ │ ├── GeneralIcon.tsx │ │ ├── GithubIcon.tsx │ │ ├── GoogleIcon.tsx │ │ ├── Humidity.tsx │ │ ├── LocationIcon.tsx │ │ ├── MinusIcon.tsx │ │ ├── PalleteIcon.tsx │ │ ├── PerplexityIcon.tsx │ │ ├── PlusIcon.tsx │ │ ├── SettingIcon.tsx │ │ ├── SparkleIcon.tsx │ │ ├── WidgetIcon.tsx │ │ └── WindIcon.tsx │ ├── Nav.tsx │ ├── SettingSections │ │ ├── AppearanceSection.tsx │ │ ├── BackupSection.tsx │ │ ├── GeneralSection.tsx │ │ └── WidgetSection.tsx │ ├── Settings.tsx │ ├── WidgetLayout.tsx │ └── Widgets │ │ ├── Countdown.tsx │ │ ├── Note.tsx │ │ ├── Search.tsx │ │ ├── Tile.tsx │ │ ├── Time.tsx │ │ ├── Todo.tsx │ │ └── Weather.tsx ├── contexts │ ├── SettingsContext.tsx │ └── WidgetsContext.tsx ├── hooks │ └── useBackground.ts ├── pages │ ├── _app.tsx │ ├── _document.tsx │ ├── api │ │ ├── hello.ts │ │ └── test │ │ │ └── route.ts │ └── index.tsx ├── styles │ └── globals.css ├── types │ └── colorthief.d.ts └── utils │ └── colorUtils.ts ├── tailwind.config.ts └── tsconfig.json /.env.example: -------------------------------------------------------------------------------- 1 | WEATHER_KEY="" # Get your API key from https://www.weatherapi.com/ 2 | AI_API_ENDPOINT="" -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals", 3 | "rules": { 4 | "@next/next/no-img-element": "off" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Saksham Kushwaha 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Odash 2 | 3 | Odash is a customizable new tab page that allows users to personalize their browsing experience. With various widgets, users can arrange and customize their new tab page to suit their needs and preferences. 4 | 5 | ![og](https://odash.lirena.in/og.png) 6 | ![preview](https://odash.lirena.in/preview.png) 7 | 8 | ## Features 9 | 10 | - **Customizable Layout**: Arrange widgets however and wherever you want. 11 | - **Multiple Widgets**: Choose from a variety of widgets to add to your new tab page. 12 | - **Themes and Colors**: Change themes, accent colors, and text colors to match your style. 13 | - **Background Images**: Select and customize your background images with blur effects. 14 | - **Export and Import Settings**: Backup your settings and widgets to a file and restore them whenever needed. 15 | - **Responsive Design**: Enjoy a seamless experience across different screen sizes and devices. 16 | - **Privacy Focused**: Everything is done locally, so your data is safe and secure. Nothing leaves your browser. 17 | 18 | ## Widgets 19 | 20 | - **Time**: Displays the current time in your preferred format. 21 | - **Search**: A search bar that uses your chosen search engine. 22 | - **Todo**: Keep track of tasks with a todo list. 23 | - **Notes**: Write and save notes with markdown support. 24 | - **Weather**: Shows the current weather and forecast for your selected city. 25 | - **Countdown**: Set countdown timers for important events. 26 | - **Tile**: Quick links to your favorite websites. 27 | 28 | _... and more to come!_ (Contributions are welcome! espeically if you have a cool widget to add) 29 | 30 | ## Installation 31 | 32 | - clone the repository 33 | - install the dependencies 34 | - create a `.env` file with your weather API key 35 | - run the development server 36 | 37 | ## License 38 | 39 | Odash is licensed under the MIT License. See the [LICENSE](https://github.com/LiReNa00/Odash/blob/master/LICENSE) file for more information. 40 | -------------------------------------------------------------------------------- /cfbackend/.gitignore: -------------------------------------------------------------------------------- 1 | # prod 2 | dist/ 3 | 4 | # dev 5 | .yarn/ 6 | !.yarn/releases 7 | .vscode/* 8 | !.vscode/launch.json 9 | !.vscode/*.code-snippets 10 | .idea/workspace.xml 11 | .idea/usage.statistics.xml 12 | .idea/shelf 13 | 14 | # deps 15 | node_modules/ 16 | .wrangler 17 | 18 | # env 19 | .env 20 | .env.production 21 | .dev.vars 22 | 23 | # logs 24 | logs/ 25 | *.log 26 | npm-debug.log* 27 | yarn-debug.log* 28 | yarn-error.log* 29 | pnpm-debug.log* 30 | lerna-debug.log* 31 | 32 | # misc 33 | .DS_Store 34 | -------------------------------------------------------------------------------- /cfbackend/README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | npm install 3 | npm run dev 4 | ``` 5 | 6 | ``` 7 | npm run deploy 8 | ``` 9 | -------------------------------------------------------------------------------- /cfbackend/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cfbackend-odash", 3 | "lockfileVersion": 3, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "dependencies": { 8 | "hono": "^4.4.6" 9 | }, 10 | "devDependencies": { 11 | "@cloudflare/workers-types": "^4.20240614.0", 12 | "wrangler": "^3.57.2" 13 | } 14 | }, 15 | "node_modules/@cloudflare/kv-asset-handler": { 16 | "version": "0.3.2", 17 | "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.2.tgz", 18 | "integrity": "sha512-EeEjMobfuJrwoctj7FA1y1KEbM0+Q1xSjobIEyie9k4haVEBB7vkDvsasw1pM3rO39mL2akxIAzLMUAtrMHZhA==", 19 | "dev": true, 20 | "dependencies": { 21 | "mime": "^3.0.0" 22 | }, 23 | "engines": { 24 | "node": ">=16.13" 25 | } 26 | }, 27 | "node_modules/@cloudflare/workerd-darwin-64": { 28 | "version": "1.20240610.1", 29 | "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20240610.1.tgz", 30 | "integrity": "sha512-YanZ1iXgMGaUWlleB5cswSE6qbzyjQ8O7ENWZcPAcZZ6BfuL7q3CWi0t9iM1cv2qx92rRztsRTyjcfq099++XQ==", 31 | "cpu": [ 32 | "x64" 33 | ], 34 | "dev": true, 35 | "optional": true, 36 | "os": [ 37 | "darwin" 38 | ], 39 | "engines": { 40 | "node": ">=16" 41 | } 42 | }, 43 | "node_modules/@cloudflare/workerd-darwin-arm64": { 44 | "version": "1.20240610.1", 45 | "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20240610.1.tgz", 46 | "integrity": "sha512-bRe/y/LKjIgp3L2EHjc+CvoCzfHhf4aFTtOBkv2zW+VToNJ4KlXridndf7LvR9urfsFRRo9r4TXCssuKaU+ypQ==", 47 | "cpu": [ 48 | "arm64" 49 | ], 50 | "dev": true, 51 | "optional": true, 52 | "os": [ 53 | "darwin" 54 | ], 55 | "engines": { 56 | "node": ">=16" 57 | } 58 | }, 59 | "node_modules/@cloudflare/workerd-linux-64": { 60 | "version": "1.20240610.1", 61 | "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20240610.1.tgz", 62 | "integrity": "sha512-2zDcadR7+Gs9SjcMXmwsMji2Xs+yASGNA2cEHDuFc4NMUup+eL1mkzxc/QzvFjyBck98e92rBjMZt2dVscpGKg==", 63 | "cpu": [ 64 | "x64" 65 | ], 66 | "dev": true, 67 | "optional": true, 68 | "os": [ 69 | "linux" 70 | ], 71 | "engines": { 72 | "node": ">=16" 73 | } 74 | }, 75 | "node_modules/@cloudflare/workerd-linux-arm64": { 76 | "version": "1.20240610.1", 77 | "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20240610.1.tgz", 78 | "integrity": "sha512-7y41rPi5xmIYJN8CY+t3RHnjLL0xx/WYmaTd/j552k1qSr02eTE2o/TGyWZmGUC+lWnwdPQJla0mXbvdqgRdQg==", 79 | "cpu": [ 80 | "arm64" 81 | ], 82 | "dev": true, 83 | "optional": true, 84 | "os": [ 85 | "linux" 86 | ], 87 | "engines": { 88 | "node": ">=16" 89 | } 90 | }, 91 | "node_modules/@cloudflare/workerd-windows-64": { 92 | "version": "1.20240610.1", 93 | "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20240610.1.tgz", 94 | "integrity": "sha512-B0LyT3DB6rXHWNptnntYHPaoJIy0rXnGfeDBM3nEVV8JIsQrx8MEFn2F2jYioH1FkUVavsaqKO/zUosY3tZXVA==", 95 | "cpu": [ 96 | "x64" 97 | ], 98 | "dev": true, 99 | "optional": true, 100 | "os": [ 101 | "win32" 102 | ], 103 | "engines": { 104 | "node": ">=16" 105 | } 106 | }, 107 | "node_modules/@cloudflare/workers-types": { 108 | "version": "4.20240614.0", 109 | "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240614.0.tgz", 110 | "integrity": "sha512-fnV3uXD1Hpq5EWnY7XYb+smPcjzIoUFiZpTSV/Tk8qKL3H+w6IqcngZwXQBZ/2U/DwYkDilXHW3FfPhnyD7FZA==", 111 | "dev": true 112 | }, 113 | "node_modules/@cspotcode/source-map-support": { 114 | "version": "0.8.1", 115 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", 116 | "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", 117 | "dev": true, 118 | "dependencies": { 119 | "@jridgewell/trace-mapping": "0.3.9" 120 | }, 121 | "engines": { 122 | "node": ">=12" 123 | } 124 | }, 125 | "node_modules/@esbuild-plugins/node-globals-polyfill": { 126 | "version": "0.2.3", 127 | "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-globals-polyfill/-/node-globals-polyfill-0.2.3.tgz", 128 | "integrity": "sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==", 129 | "dev": true, 130 | "peerDependencies": { 131 | "esbuild": "*" 132 | } 133 | }, 134 | "node_modules/@esbuild-plugins/node-modules-polyfill": { 135 | "version": "0.2.2", 136 | "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-modules-polyfill/-/node-modules-polyfill-0.2.2.tgz", 137 | "integrity": "sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA==", 138 | "dev": true, 139 | "dependencies": { 140 | "escape-string-regexp": "^4.0.0", 141 | "rollup-plugin-node-polyfills": "^0.2.1" 142 | }, 143 | "peerDependencies": { 144 | "esbuild": "*" 145 | } 146 | }, 147 | "node_modules/@esbuild/android-arm": { 148 | "version": "0.17.19", 149 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", 150 | "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", 151 | "cpu": [ 152 | "arm" 153 | ], 154 | "dev": true, 155 | "optional": true, 156 | "os": [ 157 | "android" 158 | ], 159 | "engines": { 160 | "node": ">=12" 161 | } 162 | }, 163 | "node_modules/@esbuild/android-arm64": { 164 | "version": "0.17.19", 165 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", 166 | "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", 167 | "cpu": [ 168 | "arm64" 169 | ], 170 | "dev": true, 171 | "optional": true, 172 | "os": [ 173 | "android" 174 | ], 175 | "engines": { 176 | "node": ">=12" 177 | } 178 | }, 179 | "node_modules/@esbuild/android-x64": { 180 | "version": "0.17.19", 181 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", 182 | "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", 183 | "cpu": [ 184 | "x64" 185 | ], 186 | "dev": true, 187 | "optional": true, 188 | "os": [ 189 | "android" 190 | ], 191 | "engines": { 192 | "node": ">=12" 193 | } 194 | }, 195 | "node_modules/@esbuild/darwin-arm64": { 196 | "version": "0.17.19", 197 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", 198 | "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", 199 | "cpu": [ 200 | "arm64" 201 | ], 202 | "dev": true, 203 | "optional": true, 204 | "os": [ 205 | "darwin" 206 | ], 207 | "engines": { 208 | "node": ">=12" 209 | } 210 | }, 211 | "node_modules/@esbuild/darwin-x64": { 212 | "version": "0.17.19", 213 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", 214 | "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", 215 | "cpu": [ 216 | "x64" 217 | ], 218 | "dev": true, 219 | "optional": true, 220 | "os": [ 221 | "darwin" 222 | ], 223 | "engines": { 224 | "node": ">=12" 225 | } 226 | }, 227 | "node_modules/@esbuild/freebsd-arm64": { 228 | "version": "0.17.19", 229 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", 230 | "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", 231 | "cpu": [ 232 | "arm64" 233 | ], 234 | "dev": true, 235 | "optional": true, 236 | "os": [ 237 | "freebsd" 238 | ], 239 | "engines": { 240 | "node": ">=12" 241 | } 242 | }, 243 | "node_modules/@esbuild/freebsd-x64": { 244 | "version": "0.17.19", 245 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", 246 | "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", 247 | "cpu": [ 248 | "x64" 249 | ], 250 | "dev": true, 251 | "optional": true, 252 | "os": [ 253 | "freebsd" 254 | ], 255 | "engines": { 256 | "node": ">=12" 257 | } 258 | }, 259 | "node_modules/@esbuild/linux-arm": { 260 | "version": "0.17.19", 261 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", 262 | "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", 263 | "cpu": [ 264 | "arm" 265 | ], 266 | "dev": true, 267 | "optional": true, 268 | "os": [ 269 | "linux" 270 | ], 271 | "engines": { 272 | "node": ">=12" 273 | } 274 | }, 275 | "node_modules/@esbuild/linux-arm64": { 276 | "version": "0.17.19", 277 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", 278 | "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", 279 | "cpu": [ 280 | "arm64" 281 | ], 282 | "dev": true, 283 | "optional": true, 284 | "os": [ 285 | "linux" 286 | ], 287 | "engines": { 288 | "node": ">=12" 289 | } 290 | }, 291 | "node_modules/@esbuild/linux-ia32": { 292 | "version": "0.17.19", 293 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", 294 | "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", 295 | "cpu": [ 296 | "ia32" 297 | ], 298 | "dev": true, 299 | "optional": true, 300 | "os": [ 301 | "linux" 302 | ], 303 | "engines": { 304 | "node": ">=12" 305 | } 306 | }, 307 | "node_modules/@esbuild/linux-loong64": { 308 | "version": "0.17.19", 309 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", 310 | "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", 311 | "cpu": [ 312 | "loong64" 313 | ], 314 | "dev": true, 315 | "optional": true, 316 | "os": [ 317 | "linux" 318 | ], 319 | "engines": { 320 | "node": ">=12" 321 | } 322 | }, 323 | "node_modules/@esbuild/linux-mips64el": { 324 | "version": "0.17.19", 325 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", 326 | "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", 327 | "cpu": [ 328 | "mips64el" 329 | ], 330 | "dev": true, 331 | "optional": true, 332 | "os": [ 333 | "linux" 334 | ], 335 | "engines": { 336 | "node": ">=12" 337 | } 338 | }, 339 | "node_modules/@esbuild/linux-ppc64": { 340 | "version": "0.17.19", 341 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", 342 | "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", 343 | "cpu": [ 344 | "ppc64" 345 | ], 346 | "dev": true, 347 | "optional": true, 348 | "os": [ 349 | "linux" 350 | ], 351 | "engines": { 352 | "node": ">=12" 353 | } 354 | }, 355 | "node_modules/@esbuild/linux-riscv64": { 356 | "version": "0.17.19", 357 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", 358 | "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", 359 | "cpu": [ 360 | "riscv64" 361 | ], 362 | "dev": true, 363 | "optional": true, 364 | "os": [ 365 | "linux" 366 | ], 367 | "engines": { 368 | "node": ">=12" 369 | } 370 | }, 371 | "node_modules/@esbuild/linux-s390x": { 372 | "version": "0.17.19", 373 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", 374 | "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", 375 | "cpu": [ 376 | "s390x" 377 | ], 378 | "dev": true, 379 | "optional": true, 380 | "os": [ 381 | "linux" 382 | ], 383 | "engines": { 384 | "node": ">=12" 385 | } 386 | }, 387 | "node_modules/@esbuild/linux-x64": { 388 | "version": "0.17.19", 389 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", 390 | "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", 391 | "cpu": [ 392 | "x64" 393 | ], 394 | "dev": true, 395 | "optional": true, 396 | "os": [ 397 | "linux" 398 | ], 399 | "engines": { 400 | "node": ">=12" 401 | } 402 | }, 403 | "node_modules/@esbuild/netbsd-x64": { 404 | "version": "0.17.19", 405 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", 406 | "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", 407 | "cpu": [ 408 | "x64" 409 | ], 410 | "dev": true, 411 | "optional": true, 412 | "os": [ 413 | "netbsd" 414 | ], 415 | "engines": { 416 | "node": ">=12" 417 | } 418 | }, 419 | "node_modules/@esbuild/openbsd-x64": { 420 | "version": "0.17.19", 421 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", 422 | "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", 423 | "cpu": [ 424 | "x64" 425 | ], 426 | "dev": true, 427 | "optional": true, 428 | "os": [ 429 | "openbsd" 430 | ], 431 | "engines": { 432 | "node": ">=12" 433 | } 434 | }, 435 | "node_modules/@esbuild/sunos-x64": { 436 | "version": "0.17.19", 437 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", 438 | "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", 439 | "cpu": [ 440 | "x64" 441 | ], 442 | "dev": true, 443 | "optional": true, 444 | "os": [ 445 | "sunos" 446 | ], 447 | "engines": { 448 | "node": ">=12" 449 | } 450 | }, 451 | "node_modules/@esbuild/win32-arm64": { 452 | "version": "0.17.19", 453 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", 454 | "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", 455 | "cpu": [ 456 | "arm64" 457 | ], 458 | "dev": true, 459 | "optional": true, 460 | "os": [ 461 | "win32" 462 | ], 463 | "engines": { 464 | "node": ">=12" 465 | } 466 | }, 467 | "node_modules/@esbuild/win32-ia32": { 468 | "version": "0.17.19", 469 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", 470 | "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", 471 | "cpu": [ 472 | "ia32" 473 | ], 474 | "dev": true, 475 | "optional": true, 476 | "os": [ 477 | "win32" 478 | ], 479 | "engines": { 480 | "node": ">=12" 481 | } 482 | }, 483 | "node_modules/@esbuild/win32-x64": { 484 | "version": "0.17.19", 485 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", 486 | "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", 487 | "cpu": [ 488 | "x64" 489 | ], 490 | "dev": true, 491 | "optional": true, 492 | "os": [ 493 | "win32" 494 | ], 495 | "engines": { 496 | "node": ">=12" 497 | } 498 | }, 499 | "node_modules/@fastify/busboy": { 500 | "version": "2.1.1", 501 | "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", 502 | "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", 503 | "dev": true, 504 | "engines": { 505 | "node": ">=14" 506 | } 507 | }, 508 | "node_modules/@jridgewell/resolve-uri": { 509 | "version": "3.1.2", 510 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", 511 | "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", 512 | "dev": true, 513 | "engines": { 514 | "node": ">=6.0.0" 515 | } 516 | }, 517 | "node_modules/@jridgewell/sourcemap-codec": { 518 | "version": "1.4.15", 519 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", 520 | "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", 521 | "dev": true 522 | }, 523 | "node_modules/@jridgewell/trace-mapping": { 524 | "version": "0.3.9", 525 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", 526 | "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", 527 | "dev": true, 528 | "dependencies": { 529 | "@jridgewell/resolve-uri": "^3.0.3", 530 | "@jridgewell/sourcemap-codec": "^1.4.10" 531 | } 532 | }, 533 | "node_modules/@types/node": { 534 | "version": "20.14.2", 535 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.2.tgz", 536 | "integrity": "sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==", 537 | "dev": true, 538 | "dependencies": { 539 | "undici-types": "~5.26.4" 540 | } 541 | }, 542 | "node_modules/@types/node-forge": { 543 | "version": "1.3.11", 544 | "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", 545 | "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", 546 | "dev": true, 547 | "dependencies": { 548 | "@types/node": "*" 549 | } 550 | }, 551 | "node_modules/acorn": { 552 | "version": "8.12.0", 553 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", 554 | "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", 555 | "dev": true, 556 | "bin": { 557 | "acorn": "bin/acorn" 558 | }, 559 | "engines": { 560 | "node": ">=0.4.0" 561 | } 562 | }, 563 | "node_modules/acorn-walk": { 564 | "version": "8.3.3", 565 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", 566 | "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", 567 | "dev": true, 568 | "dependencies": { 569 | "acorn": "^8.11.0" 570 | }, 571 | "engines": { 572 | "node": ">=0.4.0" 573 | } 574 | }, 575 | "node_modules/anymatch": { 576 | "version": "3.1.3", 577 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 578 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 579 | "dev": true, 580 | "dependencies": { 581 | "normalize-path": "^3.0.0", 582 | "picomatch": "^2.0.4" 583 | }, 584 | "engines": { 585 | "node": ">= 8" 586 | } 587 | }, 588 | "node_modules/as-table": { 589 | "version": "1.0.55", 590 | "resolved": "https://registry.npmjs.org/as-table/-/as-table-1.0.55.tgz", 591 | "integrity": "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==", 592 | "dev": true, 593 | "dependencies": { 594 | "printable-characters": "^1.0.42" 595 | } 596 | }, 597 | "node_modules/binary-extensions": { 598 | "version": "2.3.0", 599 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", 600 | "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", 601 | "dev": true, 602 | "engines": { 603 | "node": ">=8" 604 | }, 605 | "funding": { 606 | "url": "https://github.com/sponsors/sindresorhus" 607 | } 608 | }, 609 | "node_modules/blake3-wasm": { 610 | "version": "2.1.5", 611 | "resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz", 612 | "integrity": "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==", 613 | "dev": true 614 | }, 615 | "node_modules/braces": { 616 | "version": "3.0.3", 617 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", 618 | "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", 619 | "dev": true, 620 | "dependencies": { 621 | "fill-range": "^7.1.1" 622 | }, 623 | "engines": { 624 | "node": ">=8" 625 | } 626 | }, 627 | "node_modules/capnp-ts": { 628 | "version": "0.7.0", 629 | "resolved": "https://registry.npmjs.org/capnp-ts/-/capnp-ts-0.7.0.tgz", 630 | "integrity": "sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g==", 631 | "dev": true, 632 | "dependencies": { 633 | "debug": "^4.3.1", 634 | "tslib": "^2.2.0" 635 | } 636 | }, 637 | "node_modules/chokidar": { 638 | "version": "3.6.0", 639 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", 640 | "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", 641 | "dev": true, 642 | "dependencies": { 643 | "anymatch": "~3.1.2", 644 | "braces": "~3.0.2", 645 | "glob-parent": "~5.1.2", 646 | "is-binary-path": "~2.1.0", 647 | "is-glob": "~4.0.1", 648 | "normalize-path": "~3.0.0", 649 | "readdirp": "~3.6.0" 650 | }, 651 | "engines": { 652 | "node": ">= 8.10.0" 653 | }, 654 | "funding": { 655 | "url": "https://paulmillr.com/funding/" 656 | }, 657 | "optionalDependencies": { 658 | "fsevents": "~2.3.2" 659 | } 660 | }, 661 | "node_modules/consola": { 662 | "version": "3.2.3", 663 | "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz", 664 | "integrity": "sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==", 665 | "dev": true, 666 | "engines": { 667 | "node": "^14.18.0 || >=16.10.0" 668 | } 669 | }, 670 | "node_modules/cookie": { 671 | "version": "0.5.0", 672 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", 673 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", 674 | "dev": true, 675 | "engines": { 676 | "node": ">= 0.6" 677 | } 678 | }, 679 | "node_modules/data-uri-to-buffer": { 680 | "version": "2.0.2", 681 | "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-2.0.2.tgz", 682 | "integrity": "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==", 683 | "dev": true 684 | }, 685 | "node_modules/debug": { 686 | "version": "4.3.5", 687 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", 688 | "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", 689 | "dev": true, 690 | "dependencies": { 691 | "ms": "2.1.2" 692 | }, 693 | "engines": { 694 | "node": ">=6.0" 695 | }, 696 | "peerDependenciesMeta": { 697 | "supports-color": { 698 | "optional": true 699 | } 700 | } 701 | }, 702 | "node_modules/defu": { 703 | "version": "6.1.4", 704 | "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", 705 | "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", 706 | "dev": true 707 | }, 708 | "node_modules/esbuild": { 709 | "version": "0.17.19", 710 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", 711 | "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", 712 | "dev": true, 713 | "hasInstallScript": true, 714 | "bin": { 715 | "esbuild": "bin/esbuild" 716 | }, 717 | "engines": { 718 | "node": ">=12" 719 | }, 720 | "optionalDependencies": { 721 | "@esbuild/android-arm": "0.17.19", 722 | "@esbuild/android-arm64": "0.17.19", 723 | "@esbuild/android-x64": "0.17.19", 724 | "@esbuild/darwin-arm64": "0.17.19", 725 | "@esbuild/darwin-x64": "0.17.19", 726 | "@esbuild/freebsd-arm64": "0.17.19", 727 | "@esbuild/freebsd-x64": "0.17.19", 728 | "@esbuild/linux-arm": "0.17.19", 729 | "@esbuild/linux-arm64": "0.17.19", 730 | "@esbuild/linux-ia32": "0.17.19", 731 | "@esbuild/linux-loong64": "0.17.19", 732 | "@esbuild/linux-mips64el": "0.17.19", 733 | "@esbuild/linux-ppc64": "0.17.19", 734 | "@esbuild/linux-riscv64": "0.17.19", 735 | "@esbuild/linux-s390x": "0.17.19", 736 | "@esbuild/linux-x64": "0.17.19", 737 | "@esbuild/netbsd-x64": "0.17.19", 738 | "@esbuild/openbsd-x64": "0.17.19", 739 | "@esbuild/sunos-x64": "0.17.19", 740 | "@esbuild/win32-arm64": "0.17.19", 741 | "@esbuild/win32-ia32": "0.17.19", 742 | "@esbuild/win32-x64": "0.17.19" 743 | } 744 | }, 745 | "node_modules/escape-string-regexp": { 746 | "version": "4.0.0", 747 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 748 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 749 | "dev": true, 750 | "engines": { 751 | "node": ">=10" 752 | }, 753 | "funding": { 754 | "url": "https://github.com/sponsors/sindresorhus" 755 | } 756 | }, 757 | "node_modules/estree-walker": { 758 | "version": "0.6.1", 759 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", 760 | "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", 761 | "dev": true 762 | }, 763 | "node_modules/exit-hook": { 764 | "version": "2.2.1", 765 | "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz", 766 | "integrity": "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==", 767 | "dev": true, 768 | "engines": { 769 | "node": ">=6" 770 | }, 771 | "funding": { 772 | "url": "https://github.com/sponsors/sindresorhus" 773 | } 774 | }, 775 | "node_modules/fill-range": { 776 | "version": "7.1.1", 777 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", 778 | "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", 779 | "dev": true, 780 | "dependencies": { 781 | "to-regex-range": "^5.0.1" 782 | }, 783 | "engines": { 784 | "node": ">=8" 785 | } 786 | }, 787 | "node_modules/fsevents": { 788 | "version": "2.3.3", 789 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 790 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 791 | "dev": true, 792 | "hasInstallScript": true, 793 | "optional": true, 794 | "os": [ 795 | "darwin" 796 | ], 797 | "engines": { 798 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 799 | } 800 | }, 801 | "node_modules/function-bind": { 802 | "version": "1.1.2", 803 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", 804 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", 805 | "dev": true, 806 | "funding": { 807 | "url": "https://github.com/sponsors/ljharb" 808 | } 809 | }, 810 | "node_modules/get-source": { 811 | "version": "2.0.12", 812 | "resolved": "https://registry.npmjs.org/get-source/-/get-source-2.0.12.tgz", 813 | "integrity": "sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==", 814 | "dev": true, 815 | "dependencies": { 816 | "data-uri-to-buffer": "^2.0.0", 817 | "source-map": "^0.6.1" 818 | } 819 | }, 820 | "node_modules/glob-parent": { 821 | "version": "5.1.2", 822 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 823 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 824 | "dev": true, 825 | "dependencies": { 826 | "is-glob": "^4.0.1" 827 | }, 828 | "engines": { 829 | "node": ">= 6" 830 | } 831 | }, 832 | "node_modules/glob-to-regexp": { 833 | "version": "0.4.1", 834 | "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", 835 | "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", 836 | "dev": true 837 | }, 838 | "node_modules/hasown": { 839 | "version": "2.0.2", 840 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", 841 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", 842 | "dev": true, 843 | "dependencies": { 844 | "function-bind": "^1.1.2" 845 | }, 846 | "engines": { 847 | "node": ">= 0.4" 848 | } 849 | }, 850 | "node_modules/hono": { 851 | "version": "4.4.6", 852 | "resolved": "https://registry.npmjs.org/hono/-/hono-4.4.6.tgz", 853 | "integrity": "sha512-XGRnoH8WONv60+PPvP9Sn067A9r/8JdHDJ5bgon0DVEHeR1cJPkWjv2aT+DBfMH9/mEkYa1+VEVFp1DT1lIwjw==", 854 | "engines": { 855 | "node": ">=16.0.0" 856 | } 857 | }, 858 | "node_modules/is-binary-path": { 859 | "version": "2.1.0", 860 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 861 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 862 | "dev": true, 863 | "dependencies": { 864 | "binary-extensions": "^2.0.0" 865 | }, 866 | "engines": { 867 | "node": ">=8" 868 | } 869 | }, 870 | "node_modules/is-core-module": { 871 | "version": "2.13.1", 872 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", 873 | "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", 874 | "dev": true, 875 | "dependencies": { 876 | "hasown": "^2.0.0" 877 | }, 878 | "funding": { 879 | "url": "https://github.com/sponsors/ljharb" 880 | } 881 | }, 882 | "node_modules/is-extglob": { 883 | "version": "2.1.1", 884 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 885 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 886 | "dev": true, 887 | "engines": { 888 | "node": ">=0.10.0" 889 | } 890 | }, 891 | "node_modules/is-glob": { 892 | "version": "4.0.3", 893 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 894 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 895 | "dev": true, 896 | "dependencies": { 897 | "is-extglob": "^2.1.1" 898 | }, 899 | "engines": { 900 | "node": ">=0.10.0" 901 | } 902 | }, 903 | "node_modules/is-number": { 904 | "version": "7.0.0", 905 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 906 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 907 | "dev": true, 908 | "engines": { 909 | "node": ">=0.12.0" 910 | } 911 | }, 912 | "node_modules/magic-string": { 913 | "version": "0.25.9", 914 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", 915 | "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", 916 | "dev": true, 917 | "dependencies": { 918 | "sourcemap-codec": "^1.4.8" 919 | } 920 | }, 921 | "node_modules/mime": { 922 | "version": "3.0.0", 923 | "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", 924 | "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", 925 | "dev": true, 926 | "bin": { 927 | "mime": "cli.js" 928 | }, 929 | "engines": { 930 | "node": ">=10.0.0" 931 | } 932 | }, 933 | "node_modules/miniflare": { 934 | "version": "3.20240610.0", 935 | "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20240610.0.tgz", 936 | "integrity": "sha512-J6aXmkII5gcq+kC4TurxKiR4rC++apPST/K8P/YjqoQQgrJ+NRPacBhf6iVh8R3ujnXYXaq+Ae+gm+LM0XHK/w==", 937 | "dev": true, 938 | "dependencies": { 939 | "@cspotcode/source-map-support": "0.8.1", 940 | "acorn": "^8.8.0", 941 | "acorn-walk": "^8.2.0", 942 | "capnp-ts": "^0.7.0", 943 | "exit-hook": "^2.2.1", 944 | "glob-to-regexp": "^0.4.1", 945 | "stoppable": "^1.1.0", 946 | "undici": "^5.28.2", 947 | "workerd": "1.20240610.1", 948 | "ws": "^8.11.0", 949 | "youch": "^3.2.2", 950 | "zod": "^3.20.6" 951 | }, 952 | "bin": { 953 | "miniflare": "bootstrap.js" 954 | }, 955 | "engines": { 956 | "node": ">=16.13" 957 | } 958 | }, 959 | "node_modules/ms": { 960 | "version": "2.1.2", 961 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 962 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 963 | "dev": true 964 | }, 965 | "node_modules/mustache": { 966 | "version": "4.2.0", 967 | "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", 968 | "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", 969 | "dev": true, 970 | "bin": { 971 | "mustache": "bin/mustache" 972 | } 973 | }, 974 | "node_modules/nanoid": { 975 | "version": "3.3.7", 976 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", 977 | "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", 978 | "dev": true, 979 | "funding": [ 980 | { 981 | "type": "github", 982 | "url": "https://github.com/sponsors/ai" 983 | } 984 | ], 985 | "bin": { 986 | "nanoid": "bin/nanoid.cjs" 987 | }, 988 | "engines": { 989 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 990 | } 991 | }, 992 | "node_modules/node-fetch-native": { 993 | "version": "1.6.4", 994 | "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.4.tgz", 995 | "integrity": "sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==", 996 | "dev": true 997 | }, 998 | "node_modules/node-forge": { 999 | "version": "1.3.1", 1000 | "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", 1001 | "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", 1002 | "dev": true, 1003 | "engines": { 1004 | "node": ">= 6.13.0" 1005 | } 1006 | }, 1007 | "node_modules/normalize-path": { 1008 | "version": "3.0.0", 1009 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 1010 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 1011 | "dev": true, 1012 | "engines": { 1013 | "node": ">=0.10.0" 1014 | } 1015 | }, 1016 | "node_modules/path-parse": { 1017 | "version": "1.0.7", 1018 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 1019 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 1020 | "dev": true 1021 | }, 1022 | "node_modules/path-to-regexp": { 1023 | "version": "6.2.2", 1024 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz", 1025 | "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==", 1026 | "dev": true 1027 | }, 1028 | "node_modules/pathe": { 1029 | "version": "1.1.2", 1030 | "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", 1031 | "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", 1032 | "dev": true 1033 | }, 1034 | "node_modules/picomatch": { 1035 | "version": "2.3.1", 1036 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1037 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1038 | "dev": true, 1039 | "engines": { 1040 | "node": ">=8.6" 1041 | }, 1042 | "funding": { 1043 | "url": "https://github.com/sponsors/jonschlinkert" 1044 | } 1045 | }, 1046 | "node_modules/printable-characters": { 1047 | "version": "1.0.42", 1048 | "resolved": "https://registry.npmjs.org/printable-characters/-/printable-characters-1.0.42.tgz", 1049 | "integrity": "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==", 1050 | "dev": true 1051 | }, 1052 | "node_modules/readdirp": { 1053 | "version": "3.6.0", 1054 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 1055 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 1056 | "dev": true, 1057 | "dependencies": { 1058 | "picomatch": "^2.2.1" 1059 | }, 1060 | "engines": { 1061 | "node": ">=8.10.0" 1062 | } 1063 | }, 1064 | "node_modules/resolve": { 1065 | "version": "1.22.8", 1066 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", 1067 | "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", 1068 | "dev": true, 1069 | "dependencies": { 1070 | "is-core-module": "^2.13.0", 1071 | "path-parse": "^1.0.7", 1072 | "supports-preserve-symlinks-flag": "^1.0.0" 1073 | }, 1074 | "bin": { 1075 | "resolve": "bin/resolve" 1076 | }, 1077 | "funding": { 1078 | "url": "https://github.com/sponsors/ljharb" 1079 | } 1080 | }, 1081 | "node_modules/resolve.exports": { 1082 | "version": "2.0.2", 1083 | "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", 1084 | "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", 1085 | "dev": true, 1086 | "engines": { 1087 | "node": ">=10" 1088 | } 1089 | }, 1090 | "node_modules/rollup-plugin-inject": { 1091 | "version": "3.0.2", 1092 | "resolved": "https://registry.npmjs.org/rollup-plugin-inject/-/rollup-plugin-inject-3.0.2.tgz", 1093 | "integrity": "sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==", 1094 | "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject.", 1095 | "dev": true, 1096 | "dependencies": { 1097 | "estree-walker": "^0.6.1", 1098 | "magic-string": "^0.25.3", 1099 | "rollup-pluginutils": "^2.8.1" 1100 | } 1101 | }, 1102 | "node_modules/rollup-plugin-node-polyfills": { 1103 | "version": "0.2.1", 1104 | "resolved": "https://registry.npmjs.org/rollup-plugin-node-polyfills/-/rollup-plugin-node-polyfills-0.2.1.tgz", 1105 | "integrity": "sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==", 1106 | "dev": true, 1107 | "dependencies": { 1108 | "rollup-plugin-inject": "^3.0.0" 1109 | } 1110 | }, 1111 | "node_modules/rollup-pluginutils": { 1112 | "version": "2.8.2", 1113 | "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", 1114 | "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", 1115 | "dev": true, 1116 | "dependencies": { 1117 | "estree-walker": "^0.6.1" 1118 | } 1119 | }, 1120 | "node_modules/selfsigned": { 1121 | "version": "2.4.1", 1122 | "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", 1123 | "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", 1124 | "dev": true, 1125 | "dependencies": { 1126 | "@types/node-forge": "^1.3.0", 1127 | "node-forge": "^1" 1128 | }, 1129 | "engines": { 1130 | "node": ">=10" 1131 | } 1132 | }, 1133 | "node_modules/source-map": { 1134 | "version": "0.6.1", 1135 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1136 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 1137 | "dev": true, 1138 | "engines": { 1139 | "node": ">=0.10.0" 1140 | } 1141 | }, 1142 | "node_modules/sourcemap-codec": { 1143 | "version": "1.4.8", 1144 | "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", 1145 | "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", 1146 | "deprecated": "Please use @jridgewell/sourcemap-codec instead", 1147 | "dev": true 1148 | }, 1149 | "node_modules/stacktracey": { 1150 | "version": "2.1.8", 1151 | "resolved": "https://registry.npmjs.org/stacktracey/-/stacktracey-2.1.8.tgz", 1152 | "integrity": "sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==", 1153 | "dev": true, 1154 | "dependencies": { 1155 | "as-table": "^1.0.36", 1156 | "get-source": "^2.0.12" 1157 | } 1158 | }, 1159 | "node_modules/stoppable": { 1160 | "version": "1.1.0", 1161 | "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", 1162 | "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", 1163 | "dev": true, 1164 | "engines": { 1165 | "node": ">=4", 1166 | "npm": ">=6" 1167 | } 1168 | }, 1169 | "node_modules/supports-preserve-symlinks-flag": { 1170 | "version": "1.0.0", 1171 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 1172 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 1173 | "dev": true, 1174 | "engines": { 1175 | "node": ">= 0.4" 1176 | }, 1177 | "funding": { 1178 | "url": "https://github.com/sponsors/ljharb" 1179 | } 1180 | }, 1181 | "node_modules/to-regex-range": { 1182 | "version": "5.0.1", 1183 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1184 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1185 | "dev": true, 1186 | "dependencies": { 1187 | "is-number": "^7.0.0" 1188 | }, 1189 | "engines": { 1190 | "node": ">=8.0" 1191 | } 1192 | }, 1193 | "node_modules/tslib": { 1194 | "version": "2.6.3", 1195 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", 1196 | "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", 1197 | "dev": true 1198 | }, 1199 | "node_modules/ufo": { 1200 | "version": "1.5.3", 1201 | "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.3.tgz", 1202 | "integrity": "sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==", 1203 | "dev": true 1204 | }, 1205 | "node_modules/undici": { 1206 | "version": "5.28.4", 1207 | "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", 1208 | "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", 1209 | "dev": true, 1210 | "dependencies": { 1211 | "@fastify/busboy": "^2.0.0" 1212 | }, 1213 | "engines": { 1214 | "node": ">=14.0" 1215 | } 1216 | }, 1217 | "node_modules/undici-types": { 1218 | "version": "5.26.5", 1219 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", 1220 | "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", 1221 | "dev": true 1222 | }, 1223 | "node_modules/unenv": { 1224 | "name": "unenv-nightly", 1225 | "version": "1.10.0-1717606461.a117952", 1226 | "resolved": "https://registry.npmjs.org/unenv-nightly/-/unenv-nightly-1.10.0-1717606461.a117952.tgz", 1227 | "integrity": "sha512-u3TfBX02WzbHTpaEfWEKwDijDSFAHcgXkayUZ+MVDrjhLFvgAJzFGTSTmwlEhwWi2exyRQey23ah9wELMM6etg==", 1228 | "dev": true, 1229 | "dependencies": { 1230 | "consola": "^3.2.3", 1231 | "defu": "^6.1.4", 1232 | "mime": "^3.0.0", 1233 | "node-fetch-native": "^1.6.4", 1234 | "pathe": "^1.1.2", 1235 | "ufo": "^1.5.3" 1236 | } 1237 | }, 1238 | "node_modules/workerd": { 1239 | "version": "1.20240610.1", 1240 | "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20240610.1.tgz", 1241 | "integrity": "sha512-Rtut5GrsODQMh6YU43b9WZ980Wd05Ov1/ds88pT/SoetmXFBvkBzdRfiHiATv+azmGX8KveE0i/Eqzk/yI01ug==", 1242 | "dev": true, 1243 | "hasInstallScript": true, 1244 | "bin": { 1245 | "workerd": "bin/workerd" 1246 | }, 1247 | "engines": { 1248 | "node": ">=16" 1249 | }, 1250 | "optionalDependencies": { 1251 | "@cloudflare/workerd-darwin-64": "1.20240610.1", 1252 | "@cloudflare/workerd-darwin-arm64": "1.20240610.1", 1253 | "@cloudflare/workerd-linux-64": "1.20240610.1", 1254 | "@cloudflare/workerd-linux-arm64": "1.20240610.1", 1255 | "@cloudflare/workerd-windows-64": "1.20240610.1" 1256 | } 1257 | }, 1258 | "node_modules/wrangler": { 1259 | "version": "3.60.3", 1260 | "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.60.3.tgz", 1261 | "integrity": "sha512-a6zn/KFnYaYp3nxJR/aP0TeaBvJDkrrfI89KoxUtx28H7zpya/5/VLu3CxQ3PRspEojJGF0s6f3/pddRy3F+BQ==", 1262 | "dev": true, 1263 | "dependencies": { 1264 | "@cloudflare/kv-asset-handler": "0.3.2", 1265 | "@esbuild-plugins/node-globals-polyfill": "^0.2.3", 1266 | "@esbuild-plugins/node-modules-polyfill": "^0.2.2", 1267 | "blake3-wasm": "^2.1.5", 1268 | "chokidar": "^3.5.3", 1269 | "esbuild": "0.17.19", 1270 | "miniflare": "3.20240610.0", 1271 | "nanoid": "^3.3.3", 1272 | "path-to-regexp": "^6.2.0", 1273 | "resolve": "^1.22.8", 1274 | "resolve.exports": "^2.0.2", 1275 | "selfsigned": "^2.0.1", 1276 | "source-map": "0.6.1", 1277 | "unenv": "npm:unenv-nightly@1.10.0-1717606461.a117952", 1278 | "xxhash-wasm": "^1.0.1" 1279 | }, 1280 | "bin": { 1281 | "wrangler": "bin/wrangler.js", 1282 | "wrangler2": "bin/wrangler.js" 1283 | }, 1284 | "engines": { 1285 | "node": ">=16.17.0" 1286 | }, 1287 | "optionalDependencies": { 1288 | "fsevents": "~2.3.2" 1289 | }, 1290 | "peerDependencies": { 1291 | "@cloudflare/workers-types": "^4.20240605.0" 1292 | }, 1293 | "peerDependenciesMeta": { 1294 | "@cloudflare/workers-types": { 1295 | "optional": true 1296 | } 1297 | } 1298 | }, 1299 | "node_modules/ws": { 1300 | "version": "8.17.1", 1301 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", 1302 | "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", 1303 | "dev": true, 1304 | "engines": { 1305 | "node": ">=10.0.0" 1306 | }, 1307 | "peerDependencies": { 1308 | "bufferutil": "^4.0.1", 1309 | "utf-8-validate": ">=5.0.2" 1310 | }, 1311 | "peerDependenciesMeta": { 1312 | "bufferutil": { 1313 | "optional": true 1314 | }, 1315 | "utf-8-validate": { 1316 | "optional": true 1317 | } 1318 | } 1319 | }, 1320 | "node_modules/xxhash-wasm": { 1321 | "version": "1.0.2", 1322 | "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.0.2.tgz", 1323 | "integrity": "sha512-ibF0Or+FivM9lNrg+HGJfVX8WJqgo+kCLDc4vx6xMeTce7Aj+DLttKbxxRR/gNLSAelRc1omAPlJ77N/Jem07A==", 1324 | "dev": true 1325 | }, 1326 | "node_modules/youch": { 1327 | "version": "3.3.3", 1328 | "resolved": "https://registry.npmjs.org/youch/-/youch-3.3.3.tgz", 1329 | "integrity": "sha512-qSFXUk3UZBLfggAW3dJKg0BMblG5biqSF8M34E06o5CSsZtH92u9Hqmj2RzGiHDi64fhe83+4tENFP2DB6t6ZA==", 1330 | "dev": true, 1331 | "dependencies": { 1332 | "cookie": "^0.5.0", 1333 | "mustache": "^4.2.0", 1334 | "stacktracey": "^2.1.8" 1335 | } 1336 | }, 1337 | "node_modules/zod": { 1338 | "version": "3.23.8", 1339 | "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", 1340 | "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", 1341 | "dev": true, 1342 | "funding": { 1343 | "url": "https://github.com/sponsors/colinhacks" 1344 | } 1345 | } 1346 | } 1347 | } 1348 | -------------------------------------------------------------------------------- /cfbackend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "dev": "wrangler dev", 4 | "deploy": "wrangler deploy --minify", 5 | "cf-typegen": "wrangler types --env-interface CloudflareBindings" 6 | }, 7 | "dependencies": { 8 | "hono": "^4.4.6" 9 | }, 10 | "devDependencies": { 11 | "@cloudflare/workers-types": "^4.20240614.0", 12 | "wrangler": "^3.57.2" 13 | } 14 | } -------------------------------------------------------------------------------- /cfbackend/src/index.ts: -------------------------------------------------------------------------------- 1 | import { Hono } from "hono"; 2 | import { cors } from "hono/cors"; 3 | 4 | type Bindings = { 5 | [key in keyof CloudflareBindings]: CloudflareBindings[key]; 6 | }; 7 | 8 | const app = new Hono<{ Bindings: Bindings }>(); 9 | 10 | app.use("/*", cors()); 11 | 12 | app.get("/", async (c) => { 13 | const message = c.req.query("message"); 14 | 15 | if (!message) { 16 | return c.json({ error: "Message query parameter is required" }, 400); 17 | } 18 | 19 | try { 20 | const response = await c.env.AI.run( 21 | "@cf/mistral/mistral-7b-instruct-v0.1", 22 | { 23 | prompt: `Welcome to Odash, your customizable new tab page designed to personalize your browsing experience. With a variety of widgets, you can arrange and tailor your new tab page to fit your preferences and needs. Add notes, a search bar, clock widget, and your favorite website links effortlessly. 24 | In the settings, you'll find options for themes and background images. Choose from three themes: Dark and Light, featuring a glassmorphic design, and Solid, offering a solid color theme. Customize your layout using the edit button (pencil icon) located next to the settings icon. You can also export and import your personalized settings. 25 | Odash supports multiple search engines including Google, Bing, DuckDuckGo, and Perplexity. Additionally, it acts as a productivity manager, providing task suggestions to help you stay organized. 26 | Also help users with completeing their tasks by providing them with relevant websites to visit. 27 | You will answer questions related to Odash with clarity and relevance. Ask away: ${message}`, 28 | } 29 | ); 30 | return c.json(response); 31 | } catch (error) { 32 | return c.json({ error }, 500); 33 | } 34 | }); 35 | 36 | app.get("/websites", async (c) => { 37 | const profession = c.req.query("profession"); 38 | if (!profession) { 39 | return c.json({ error: "profession query parameter is required" }, 400); 40 | } 41 | try { 42 | const response = await c.env.AI.run( 43 | "@cf/mistral/mistral-7b-instruct-v0.1", 44 | { 45 | prompt: `Suggest 5 relevant websites for ${profession} that they might use in their day-to-day life to enhance their online experience. Respond only in the following format:{"websites": [{"title":"example1", "url":"https://example1.com/"}, {"title":"example2", "url":"https://example2.com/"}, {"title":"example3", "url":"https://example3.com/"}, {"title":"example4", "url":"https://example4.com/"}, {"title":"example5", "url":"https://example5.com/"}]} Do not include any additional text or explanation.`, 46 | } 47 | ); 48 | return c.json(response); 49 | } catch (error) { 50 | return c.json({ error }, 500); 51 | } 52 | }); 53 | 54 | export default app; 55 | -------------------------------------------------------------------------------- /cfbackend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "moduleResolution": "Bundler", 6 | "strict": true, 7 | "skipLibCheck": true, 8 | "lib": ["ESNext"], 9 | "types": ["@cloudflare/workers-types/2023-07-01"], 10 | "jsx": "react-jsx", 11 | "jsxImportSource": "hono/jsx" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /cfbackend/worker-configuration.d.ts: -------------------------------------------------------------------------------- 1 | // Generated by Wrangler 2 | // After adding bindings to `wrangler.toml`, regenerate this interface via `npm run cf-typegen` 3 | interface CloudflareBindings { 4 | AI: Ai; 5 | } 6 | -------------------------------------------------------------------------------- /cfbackend/wrangler.toml: -------------------------------------------------------------------------------- 1 | #:schema node_modules/wrangler/config-schema.json 2 | name = "cfbackend-odash" 3 | main = "src/index.ts" 4 | compatibility_date = "2024-06-14" 5 | 6 | [ai] 7 | binding = "AI" 8 | 9 | # Automatically place your workloads in an optimal location to minimize latency. 10 | # If you are running back-end logic in a Worker, running it closer to your back-end infrastructure 11 | # rather than the end user may result in better performance. 12 | # Docs: https://developers.cloudflare.com/workers/configuration/smart-placement/#smart-placement 13 | # [placement] 14 | # mode = "smart" 15 | 16 | # Variable bindings. These are arbitrary, plaintext strings (similar to environment variables) 17 | # Docs: 18 | # - https://developers.cloudflare.com/workers/wrangler/configuration/#environment-variables 19 | # Note: Use secrets to store sensitive data. 20 | # - https://developers.cloudflare.com/workers/configuration/secrets/ 21 | # [vars] 22 | # MY_VARIABLE = "production_value" 23 | 24 | # Bind the Workers AI model catalog. Run machine learning models, powered by serverless GPUs, on Cloudflare’s global network 25 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#workers-ai 26 | # [ai] 27 | # binding = "AI" 28 | 29 | # Bind an Analytics Engine dataset. Use Analytics Engine to write analytics within your Pages Function. 30 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#analytics-engine-datasets 31 | # [[analytics_engine_datasets]] 32 | # binding = "MY_DATASET" 33 | 34 | # Bind a headless browser instance running on Cloudflare's global network. 35 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#browser-rendering 36 | # [browser] 37 | # binding = "MY_BROWSER" 38 | 39 | # Bind a D1 database. D1 is Cloudflare’s native serverless SQL database. 40 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#d1-databases 41 | # [[d1_databases]] 42 | # binding = "MY_DB" 43 | # database_name = "my-database" 44 | # database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" 45 | 46 | # Bind a dispatch namespace. Use Workers for Platforms to deploy serverless functions programmatically on behalf of your customers. 47 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#dispatch-namespace-bindings-workers-for-platforms 48 | # [[dispatch_namespaces]] 49 | # binding = "MY_DISPATCHER" 50 | # namespace = "my-namespace" 51 | 52 | # Bind a Durable Object. Durable objects are a scale-to-zero compute primitive based on the actor model. 53 | # Durable Objects can live for as long as needed. Use these when you need a long-running "server", such as in realtime apps. 54 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#durable-objects 55 | # [[durable_objects.bindings]] 56 | # name = "MY_DURABLE_OBJECT" 57 | # class_name = "MyDurableObject" 58 | 59 | # Durable Object migrations. 60 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#migrations 61 | # [[migrations]] 62 | # tag = "v1" 63 | # new_classes = ["MyDurableObject"] 64 | 65 | # Bind a Hyperdrive configuration. Use to accelerate access to your existing databases from Cloudflare Workers. 66 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#hyperdrive 67 | # [[hyperdrive]] 68 | # binding = "MY_HYPERDRIVE" 69 | # id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 70 | 71 | # Bind a KV Namespace. Use KV as persistent storage for small key-value pairs. 72 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#kv-namespaces 73 | # [[kv_namespaces]] 74 | # binding = "MY_KV_NAMESPACE" 75 | # id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 76 | 77 | # Bind an mTLS certificate. Use to present a client certificate when communicating with another service. 78 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#mtls-certificates 79 | # [[mtls_certificates]] 80 | # binding = "MY_CERTIFICATE" 81 | # certificate_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" 82 | 83 | # Bind a Queue producer. Use this binding to schedule an arbitrary task that may be processed later by a Queue consumer. 84 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#queues 85 | # [[queues.producers]] 86 | # binding = "MY_QUEUE" 87 | # queue = "my-queue" 88 | 89 | # Bind a Queue consumer. Queue Consumers can retrieve tasks scheduled by Producers to act on them. 90 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#queues 91 | # [[queues.consumers]] 92 | # queue = "my-queue" 93 | 94 | # Bind an R2 Bucket. Use R2 to store arbitrarily large blobs of data, such as files. 95 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#r2-buckets 96 | # [[r2_buckets]] 97 | # binding = "MY_BUCKET" 98 | # bucket_name = "my-bucket" 99 | 100 | # Bind another Worker service. Use this binding to call another Worker without network overhead. 101 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#service-bindings 102 | # [[services]] 103 | # binding = "MY_SERVICE" 104 | # service = "my-service" 105 | 106 | # Bind a Vectorize index. Use to store and query vector embeddings for semantic search, classification and other vector search use-cases. 107 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#vectorize-indexes 108 | # [[vectorize]] 109 | # binding = "MY_INDEX" 110 | # index_name = "my-index" 111 | -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | images: { 5 | unoptimized: true, 6 | }, 7 | env: { 8 | WEATHER_KEY: process.env.WEATHER_KEY, 9 | AI_URL: process.env.AI_URL, 10 | }, 11 | }; 12 | 13 | export default nextConfig; 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "odash", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@radix-ui/react-icons": "^1.3.0", 13 | "@radix-ui/react-select": "^2.0.0", 14 | "@radix-ui/react-slider": "^1.1.2", 15 | "@tailwindcss/typography": "^0.5.13", 16 | "axios": "^1.7.2", 17 | "chroma-js": "^2.4.2", 18 | "colorthief": "^2.4.0", 19 | "framer-motion": "^11.2.6", 20 | "hono": "^4.4.6", 21 | "lodash": "^4.17.21", 22 | "next": "14.2.14", 23 | "next-pwa": "^5.6.0", 24 | "react": "^18", 25 | "react-dom": "^18", 26 | "react-grid-layout": "^1.4.4", 27 | "react-markdown": "^9.0.1", 28 | "remark-gfm": "^4.0.0", 29 | "styled-components": "^6.1.11", 30 | "uuid": "^9.0.1" 31 | }, 32 | "devDependencies": { 33 | "@types/chroma-js": "^2.4.4", 34 | "@types/lodash": "^4.17.4", 35 | "@types/node": "^20.14.8", 36 | "@types/react": "^18", 37 | "@types/react-dom": "^18", 38 | "@types/react-grid-layout": "^1.3.5", 39 | "@types/uuid": "^9.0.8", 40 | "eslint": "^8", 41 | "eslint-config-next": "14.2.3", 42 | "postcss": "^8", 43 | "tailwindcss": "^3.4.1", 44 | "typescript": "^5" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /public/fallback-Nmugk_Zyk-6l0kLaNJUk1.js: -------------------------------------------------------------------------------- 1 | (()=>{"use strict";self.fallback=async e=>"document"===e.destination?caches.match("/_offline",{ignoreSearch:!0}):Response.error()})(); -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lirena00/Odash/9579dcff46e7dbc5658cc3b80513452db2738072/public/favicon.ico -------------------------------------------------------------------------------- /public/fonts/comfortaa.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lirena00/Odash/9579dcff46e7dbc5658cc3b80513452db2738072/public/fonts/comfortaa.ttf -------------------------------------------------------------------------------- /public/fonts/roboto_mono.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lirena00/Odash/9579dcff46e7dbc5658cc3b80513452db2738072/public/fonts/roboto_mono.ttf -------------------------------------------------------------------------------- /public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lirena00/Odash/9579dcff46e7dbc5658cc3b80513452db2738072/public/logo.png -------------------------------------------------------------------------------- /public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/og.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lirena00/Odash/9579dcff46e7dbc5658cc3b80513452db2738072/public/og.png -------------------------------------------------------------------------------- /public/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lirena00/Odash/9579dcff46e7dbc5658cc3b80513452db2738072/public/preview.png -------------------------------------------------------------------------------- /public/sw.js: -------------------------------------------------------------------------------- 1 | if(!self.define){let e,s={};const a=(a,n)=>(a=new URL(a+".js",n).href,s[a]||new Promise((s=>{if("document"in self){const e=document.createElement("script");e.src=a,e.onload=s,document.head.appendChild(e)}else e=a,importScripts(a),s()})).then((()=>{let e=s[a];if(!e)throw new Error(`Module ${a} didn’t register its module`);return e})));self.define=(n,r)=>{const c=e||("document"in self?document.currentScript.src:"")||location.href;if(s[c])return;let i={};const t=e=>a(e,c),o={module:{uri:c},exports:i,require:t};s[c]=Promise.all(n.map((e=>o[e]||t(e)))).then((e=>(r(...e),i)))}}define(["./workbox-4754cb34"],(function(e){"use strict";importScripts("fallback-Nmugk_Zyk-6l0kLaNJUk1.js"),self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"/_next/static/Nmugk_Zyk-6l0kLaNJUk1/_buildManifest.js",revision:"bb4e2c58c59bc8ecbc42c426f7fb55b4"},{url:"/_next/static/Nmugk_Zyk-6l0kLaNJUk1/_ssgManifest.js",revision:"b6652df95db52feb4daf4eca35380933"},{url:"/_next/static/chunks/147.2dec711728767ed2.js",revision:"2dec711728767ed2"},{url:"/_next/static/chunks/181.58d47296695bc127.js",revision:"58d47296695bc127"},{url:"/_next/static/chunks/550-4f6300797aa02006.js",revision:"4f6300797aa02006"},{url:"/_next/static/chunks/ee9ce975-168cb2d64e15e285.js",revision:"168cb2d64e15e285"},{url:"/_next/static/chunks/framework-ecc4130bc7a58a64.js",revision:"ecc4130bc7a58a64"},{url:"/_next/static/chunks/main-58fef9cbb954efe4.js",revision:"58fef9cbb954efe4"},{url:"/_next/static/chunks/pages/_app-afea05a4d7feed0b.js",revision:"afea05a4d7feed0b"},{url:"/_next/static/chunks/pages/_error-77823ddac6993d35.js",revision:"77823ddac6993d35"},{url:"/_next/static/chunks/pages/_offline-bbb064c6ce6a75f6.js",revision:"bbb064c6ce6a75f6"},{url:"/_next/static/chunks/pages/index-fdd9cc26b5e5d4aa.js",revision:"fdd9cc26b5e5d4aa"},{url:"/_next/static/chunks/polyfills-78c92fac7aa8fdd8.js",revision:"79330112775102f91e1010318bae2bd3"},{url:"/_next/static/chunks/webpack-a8631ce0286687d4.js",revision:"a8631ce0286687d4"},{url:"/_next/static/css/9f27f9f172b8ee6f.css",revision:"9f27f9f172b8ee6f"},{url:"/_next/static/css/da97de403f6afbc1.css",revision:"da97de403f6afbc1"},{url:"/_offline",revision:"Nmugk_Zyk-6l0kLaNJUk1"},{url:"/favicon.ico",revision:"7ae82b5fe36094b44e4eef267501c7ce"},{url:"/fonts/comfortaa.ttf",revision:"b14da82fd326fb23ada0b4df443cda25"},{url:"/fonts/roboto_mono.ttf",revision:"336102a48d996db3d945a346b1790b1f"},{url:"/logo.png",revision:"5c7ef0337e8717d49192c14d14f7645e"},{url:"/next.svg",revision:"8e061864f388b47f33a1c3780831193e"},{url:"/og.png",revision:"a6b35937a400af1a10bd793faa0d4777"},{url:"/preview.png",revision:"48f5bdd37e1040b7df80b61f465f84d4"},{url:"/vercel.svg",revision:"12854fc11fdc3d498acbb4892fc90fbb"},{url:"/wallpaper1.jpg",revision:"9a14b8b2c9494052fab98e31e76bb929"},{url:"/wallpaper2.jpg",revision:"fc31a4991e5b4d9c1949e8c69883d3e6"},{url:"/wallpaper3.jpg",revision:"dc333fd9505a10d27b3edffd364ac48f"},{url:"/wallpaper4.jpg",revision:"9ef317ff15a417d4efef582ee6104d93"},{url:"/wallpaper5.jpg",revision:"5a361f76408122ccf73fc496bcd26ff1"}],{ignoreURLParametersMatching:[]}),e.cleanupOutdatedCaches(),e.registerRoute("/",new e.NetworkFirst({cacheName:"start-url",plugins:[{cacheWillUpdate:async({request:e,response:s,event:a,state:n})=>s&&"opaqueredirect"===s.type?new Response(s.body,{status:200,statusText:"OK",headers:s.headers}):s},{handlerDidError:async({request:e})=>self.fallback(e)}]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:gstatic)\.com\/.*/i,new e.CacheFirst({cacheName:"google-fonts-webfonts",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:31536e3}),{handlerDidError:async({request:e})=>self.fallback(e)}]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:googleapis)\.com\/.*/i,new e.StaleWhileRevalidate({cacheName:"google-fonts-stylesheets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800}),{handlerDidError:async({request:e})=>self.fallback(e)}]}),"GET"),e.registerRoute(/\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,new e.StaleWhileRevalidate({cacheName:"static-font-assets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800}),{handlerDidError:async({request:e})=>self.fallback(e)}]}),"GET"),e.registerRoute(/\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,new e.StaleWhileRevalidate({cacheName:"static-image-assets",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>self.fallback(e)}]}),"GET"),e.registerRoute(/\/_next\/image\?url=.+$/i,new e.StaleWhileRevalidate({cacheName:"next-image",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>self.fallback(e)}]}),"GET"),e.registerRoute(/\.(?:mp3|wav|ogg)$/i,new e.CacheFirst({cacheName:"static-audio-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>self.fallback(e)}]}),"GET"),e.registerRoute(/\.(?:mp4)$/i,new e.CacheFirst({cacheName:"static-video-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>self.fallback(e)}]}),"GET"),e.registerRoute(/\.(?:js)$/i,new e.StaleWhileRevalidate({cacheName:"static-js-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>self.fallback(e)}]}),"GET"),e.registerRoute(/\.(?:css|less)$/i,new e.StaleWhileRevalidate({cacheName:"static-style-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>self.fallback(e)}]}),"GET"),e.registerRoute(/\/_next\/data\/.+\/.+\.json$/i,new e.StaleWhileRevalidate({cacheName:"next-data",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>self.fallback(e)}]}),"GET"),e.registerRoute(/\.(?:json|xml|csv)$/i,new e.NetworkFirst({cacheName:"static-data-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>self.fallback(e)}]}),"GET"),e.registerRoute((({url:e})=>{if(!(self.origin===e.origin))return!1;const s=e.pathname;return!s.startsWith("/api/auth/")&&!!s.startsWith("/api/")}),new e.NetworkFirst({cacheName:"apis",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:16,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>self.fallback(e)}]}),"GET"),e.registerRoute((({url:e})=>{if(!(self.origin===e.origin))return!1;return!e.pathname.startsWith("/api/")}),new e.NetworkFirst({cacheName:"others",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>self.fallback(e)}]}),"GET"),e.registerRoute((({url:e})=>!(self.origin===e.origin)),new e.NetworkFirst({cacheName:"cross-origin",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:3600}),{handlerDidError:async({request:e})=>self.fallback(e)}]}),"GET")})); 2 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/wallpaper1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lirena00/Odash/9579dcff46e7dbc5658cc3b80513452db2738072/public/wallpaper1.jpg -------------------------------------------------------------------------------- /public/wallpaper2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lirena00/Odash/9579dcff46e7dbc5658cc3b80513452db2738072/public/wallpaper2.jpg -------------------------------------------------------------------------------- /public/wallpaper3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lirena00/Odash/9579dcff46e7dbc5658cc3b80513452db2738072/public/wallpaper3.jpg -------------------------------------------------------------------------------- /public/wallpaper4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lirena00/Odash/9579dcff46e7dbc5658cc3b80513452db2738072/public/wallpaper4.jpg -------------------------------------------------------------------------------- /public/wallpaper5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lirena00/Odash/9579dcff46e7dbc5658cc3b80513452db2738072/public/wallpaper5.jpg -------------------------------------------------------------------------------- /public/workbox-4754cb34.js: -------------------------------------------------------------------------------- 1 | define(["exports"],(function(t){"use strict";try{self["workbox:core:6.5.4"]&&_()}catch(t){}const e=(t,...e)=>{let s=t;return e.length>0&&(s+=` :: ${JSON.stringify(e)}`),s};class s extends Error{constructor(t,s){super(e(t,s)),this.name=t,this.details=s}}try{self["workbox:routing:6.5.4"]&&_()}catch(t){}const n=t=>t&&"object"==typeof t?t:{handle:t};class r{constructor(t,e,s="GET"){this.handler=n(e),this.match=t,this.method=s}setCatchHandler(t){this.catchHandler=n(t)}}class i extends r{constructor(t,e,s){super((({url:e})=>{const s=t.exec(e.href);if(s&&(e.origin===location.origin||0===s.index))return s.slice(1)}),e,s)}}class a{constructor(){this.t=new Map,this.i=new Map}get routes(){return this.t}addFetchListener(){self.addEventListener("fetch",(t=>{const{request:e}=t,s=this.handleRequest({request:e,event:t});s&&t.respondWith(s)}))}addCacheListener(){self.addEventListener("message",(t=>{if(t.data&&"CACHE_URLS"===t.data.type){const{payload:e}=t.data,s=Promise.all(e.urlsToCache.map((e=>{"string"==typeof e&&(e=[e]);const s=new Request(...e);return this.handleRequest({request:s,event:t})})));t.waitUntil(s),t.ports&&t.ports[0]&&s.then((()=>t.ports[0].postMessage(!0)))}}))}handleRequest({request:t,event:e}){const s=new URL(t.url,location.href);if(!s.protocol.startsWith("http"))return;const n=s.origin===location.origin,{params:r,route:i}=this.findMatchingRoute({event:e,request:t,sameOrigin:n,url:s});let a=i&&i.handler;const o=t.method;if(!a&&this.i.has(o)&&(a=this.i.get(o)),!a)return;let c;try{c=a.handle({url:s,request:t,event:e,params:r})}catch(t){c=Promise.reject(t)}const h=i&&i.catchHandler;return c instanceof Promise&&(this.o||h)&&(c=c.catch((async n=>{if(h)try{return await h.handle({url:s,request:t,event:e,params:r})}catch(t){t instanceof Error&&(n=t)}if(this.o)return this.o.handle({url:s,request:t,event:e});throw n}))),c}findMatchingRoute({url:t,sameOrigin:e,request:s,event:n}){const r=this.t.get(s.method)||[];for(const i of r){let r;const a=i.match({url:t,sameOrigin:e,request:s,event:n});if(a)return r=a,(Array.isArray(r)&&0===r.length||a.constructor===Object&&0===Object.keys(a).length||"boolean"==typeof a)&&(r=void 0),{route:i,params:r}}return{}}setDefaultHandler(t,e="GET"){this.i.set(e,n(t))}setCatchHandler(t){this.o=n(t)}registerRoute(t){this.t.has(t.method)||this.t.set(t.method,[]),this.t.get(t.method).push(t)}unregisterRoute(t){if(!this.t.has(t.method))throw new s("unregister-route-but-not-found-with-method",{method:t.method});const e=this.t.get(t.method).indexOf(t);if(!(e>-1))throw new s("unregister-route-route-not-registered");this.t.get(t.method).splice(e,1)}}let o;const c=()=>(o||(o=new a,o.addFetchListener(),o.addCacheListener()),o);function h(t,e,n){let a;if("string"==typeof t){const s=new URL(t,location.href);a=new r((({url:t})=>t.href===s.href),e,n)}else if(t instanceof RegExp)a=new i(t,e,n);else if("function"==typeof t)a=new r(t,e,n);else{if(!(t instanceof r))throw new s("unsupported-route-type",{moduleName:"workbox-routing",funcName:"registerRoute",paramName:"capture"});a=t}return c().registerRoute(a),a}try{self["workbox:strategies:6.5.4"]&&_()}catch(t){}const u={cacheWillUpdate:async({response:t})=>200===t.status||0===t.status?t:null},l={googleAnalytics:"googleAnalytics",precache:"precache-v2",prefix:"workbox",runtime:"runtime",suffix:"undefined"!=typeof registration?registration.scope:""},f=t=>[l.prefix,t,l.suffix].filter((t=>t&&t.length>0)).join("-"),w=t=>t||f(l.precache),d=t=>t||f(l.runtime);function p(t,e){const s=new URL(t);for(const t of e)s.searchParams.delete(t);return s.href}class y{constructor(){this.promise=new Promise(((t,e)=>{this.resolve=t,this.reject=e}))}}const g=new Set;function m(t){return"string"==typeof t?new Request(t):t}class R{constructor(t,e){this.h={},Object.assign(this,e),this.event=e.event,this.u=t,this.l=new y,this.p=[],this.m=[...t.plugins],this.R=new Map;for(const t of this.m)this.R.set(t,{});this.event.waitUntil(this.l.promise)}async fetch(t){const{event:e}=this;let n=m(t);if("navigate"===n.mode&&e instanceof FetchEvent&&e.preloadResponse){const t=await e.preloadResponse;if(t)return t}const r=this.hasCallback("fetchDidFail")?n.clone():null;try{for(const t of this.iterateCallbacks("requestWillFetch"))n=await t({request:n.clone(),event:e})}catch(t){if(t instanceof Error)throw new s("plugin-error-request-will-fetch",{thrownErrorMessage:t.message})}const i=n.clone();try{let t;t=await fetch(n,"navigate"===n.mode?void 0:this.u.fetchOptions);for(const s of this.iterateCallbacks("fetchDidSucceed"))t=await s({event:e,request:i,response:t});return t}catch(t){throw r&&await this.runCallbacks("fetchDidFail",{error:t,event:e,originalRequest:r.clone(),request:i.clone()}),t}}async fetchAndCachePut(t){const e=await this.fetch(t),s=e.clone();return this.waitUntil(this.cachePut(t,s)),e}async cacheMatch(t){const e=m(t);let s;const{cacheName:n,matchOptions:r}=this.u,i=await this.getCacheKey(e,"read"),a=Object.assign(Object.assign({},r),{cacheName:n});s=await caches.match(i,a);for(const t of this.iterateCallbacks("cachedResponseWillBeUsed"))s=await t({cacheName:n,matchOptions:r,cachedResponse:s,request:i,event:this.event})||void 0;return s}async cachePut(t,e){const n=m(t);var r;await(r=0,new Promise((t=>setTimeout(t,r))));const i=await this.getCacheKey(n,"write");if(!e)throw new s("cache-put-with-no-response",{url:(a=i.url,new URL(String(a),location.href).href.replace(new RegExp(`^${location.origin}`),""))});var a;const o=await this.v(e);if(!o)return!1;const{cacheName:c,matchOptions:h}=this.u,u=await self.caches.open(c),l=this.hasCallback("cacheDidUpdate"),f=l?await async function(t,e,s,n){const r=p(e.url,s);if(e.url===r)return t.match(e,n);const i=Object.assign(Object.assign({},n),{ignoreSearch:!0}),a=await t.keys(e,i);for(const e of a)if(r===p(e.url,s))return t.match(e,n)}(u,i.clone(),["__WB_REVISION__"],h):null;try{await u.put(i,l?o.clone():o)}catch(t){if(t instanceof Error)throw"QuotaExceededError"===t.name&&await async function(){for(const t of g)await t()}(),t}for(const t of this.iterateCallbacks("cacheDidUpdate"))await t({cacheName:c,oldResponse:f,newResponse:o.clone(),request:i,event:this.event});return!0}async getCacheKey(t,e){const s=`${t.url} | ${e}`;if(!this.h[s]){let n=t;for(const t of this.iterateCallbacks("cacheKeyWillBeUsed"))n=m(await t({mode:e,request:n,event:this.event,params:this.params}));this.h[s]=n}return this.h[s]}hasCallback(t){for(const e of this.u.plugins)if(t in e)return!0;return!1}async runCallbacks(t,e){for(const s of this.iterateCallbacks(t))await s(e)}*iterateCallbacks(t){for(const e of this.u.plugins)if("function"==typeof e[t]){const s=this.R.get(e),n=n=>{const r=Object.assign(Object.assign({},n),{state:s});return e[t](r)};yield n}}waitUntil(t){return this.p.push(t),t}async doneWaiting(){let t;for(;t=this.p.shift();)await t}destroy(){this.l.resolve(null)}async v(t){let e=t,s=!1;for(const t of this.iterateCallbacks("cacheWillUpdate"))if(e=await t({request:this.request,response:e,event:this.event})||void 0,s=!0,!e)break;return s||e&&200!==e.status&&(e=void 0),e}}class v{constructor(t={}){this.cacheName=d(t.cacheName),this.plugins=t.plugins||[],this.fetchOptions=t.fetchOptions,this.matchOptions=t.matchOptions}handle(t){const[e]=this.handleAll(t);return e}handleAll(t){t instanceof FetchEvent&&(t={event:t,request:t.request});const e=t.event,s="string"==typeof t.request?new Request(t.request):t.request,n="params"in t?t.params:void 0,r=new R(this,{event:e,request:s,params:n}),i=this.q(r,s,e);return[i,this.D(i,r,s,e)]}async q(t,e,n){let r;await t.runCallbacks("handlerWillStart",{event:n,request:e});try{if(r=await this.U(e,t),!r||"error"===r.type)throw new s("no-response",{url:e.url})}catch(s){if(s instanceof Error)for(const i of t.iterateCallbacks("handlerDidError"))if(r=await i({error:s,event:n,request:e}),r)break;if(!r)throw s}for(const s of t.iterateCallbacks("handlerWillRespond"))r=await s({event:n,request:e,response:r});return r}async D(t,e,s,n){let r,i;try{r=await t}catch(i){}try{await e.runCallbacks("handlerDidRespond",{event:n,request:s,response:r}),await e.doneWaiting()}catch(t){t instanceof Error&&(i=t)}if(await e.runCallbacks("handlerDidComplete",{event:n,request:s,response:r,error:i}),e.destroy(),i)throw i}}function b(t){t.then((()=>{}))}function q(){return q=Object.assign?Object.assign.bind():function(t){for(var e=1;ee.some((e=>t instanceof e));let U,x;const L=new WeakMap,I=new WeakMap,C=new WeakMap,E=new WeakMap,N=new WeakMap;let O={get(t,e,s){if(t instanceof IDBTransaction){if("done"===e)return I.get(t);if("objectStoreNames"===e)return t.objectStoreNames||C.get(t);if("store"===e)return s.objectStoreNames[1]?void 0:s.objectStore(s.objectStoreNames[0])}return B(t[e])},set:(t,e,s)=>(t[e]=s,!0),has:(t,e)=>t instanceof IDBTransaction&&("done"===e||"store"===e)||e in t};function T(t){return t!==IDBDatabase.prototype.transaction||"objectStoreNames"in IDBTransaction.prototype?(x||(x=[IDBCursor.prototype.advance,IDBCursor.prototype.continue,IDBCursor.prototype.continuePrimaryKey])).includes(t)?function(...e){return t.apply(P(this),e),B(L.get(this))}:function(...e){return B(t.apply(P(this),e))}:function(e,...s){const n=t.call(P(this),e,...s);return C.set(n,e.sort?e.sort():[e]),B(n)}}function k(t){return"function"==typeof t?T(t):(t instanceof IDBTransaction&&function(t){if(I.has(t))return;const e=new Promise(((e,s)=>{const n=()=>{t.removeEventListener("complete",r),t.removeEventListener("error",i),t.removeEventListener("abort",i)},r=()=>{e(),n()},i=()=>{s(t.error||new DOMException("AbortError","AbortError")),n()};t.addEventListener("complete",r),t.addEventListener("error",i),t.addEventListener("abort",i)}));I.set(t,e)}(t),D(t,U||(U=[IDBDatabase,IDBObjectStore,IDBIndex,IDBCursor,IDBTransaction]))?new Proxy(t,O):t)}function B(t){if(t instanceof IDBRequest)return function(t){const e=new Promise(((e,s)=>{const n=()=>{t.removeEventListener("success",r),t.removeEventListener("error",i)},r=()=>{e(B(t.result)),n()},i=()=>{s(t.error),n()};t.addEventListener("success",r),t.addEventListener("error",i)}));return e.then((e=>{e instanceof IDBCursor&&L.set(e,t)})).catch((()=>{})),N.set(e,t),e}(t);if(E.has(t))return E.get(t);const e=k(t);return e!==t&&(E.set(t,e),N.set(e,t)),e}const P=t=>N.get(t);const M=["get","getKey","getAll","getAllKeys","count"],W=["put","add","delete","clear"],j=new Map;function S(t,e){if(!(t instanceof IDBDatabase)||e in t||"string"!=typeof e)return;if(j.get(e))return j.get(e);const s=e.replace(/FromIndex$/,""),n=e!==s,r=W.includes(s);if(!(s in(n?IDBIndex:IDBObjectStore).prototype)||!r&&!M.includes(s))return;const i=async function(t,...e){const i=this.transaction(t,r?"readwrite":"readonly");let a=i.store;return n&&(a=a.index(e.shift())),(await Promise.all([a[s](...e),r&&i.done]))[0]};return j.set(e,i),i}O=(t=>q({},t,{get:(e,s,n)=>S(e,s)||t.get(e,s,n),has:(e,s)=>!!S(e,s)||t.has(e,s)}))(O);try{self["workbox:expiration:6.5.4"]&&_()}catch(t){}const K="cache-entries",A=t=>{const e=new URL(t,location.href);return e.hash="",e.href};class F{constructor(t){this._=null,this.L=t}I(t){const e=t.createObjectStore(K,{keyPath:"id"});e.createIndex("cacheName","cacheName",{unique:!1}),e.createIndex("timestamp","timestamp",{unique:!1})}C(t){this.I(t),this.L&&function(t,{blocked:e}={}){const s=indexedDB.deleteDatabase(t);e&&s.addEventListener("blocked",(t=>e(t.oldVersion,t))),B(s).then((()=>{}))}(this.L)}async setTimestamp(t,e){const s={url:t=A(t),timestamp:e,cacheName:this.L,id:this.N(t)},n=(await this.getDb()).transaction(K,"readwrite",{durability:"relaxed"});await n.store.put(s),await n.done}async getTimestamp(t){const e=await this.getDb(),s=await e.get(K,this.N(t));return null==s?void 0:s.timestamp}async expireEntries(t,e){const s=await this.getDb();let n=await s.transaction(K).store.index("timestamp").openCursor(null,"prev");const r=[];let i=0;for(;n;){const s=n.value;s.cacheName===this.L&&(t&&s.timestamp=e?r.push(n.value):i++),n=await n.continue()}const a=[];for(const t of r)await s.delete(K,t.id),a.push(t.url);return a}N(t){return this.L+"|"+A(t)}async getDb(){return this._||(this._=await function(t,e,{blocked:s,upgrade:n,blocking:r,terminated:i}={}){const a=indexedDB.open(t,e),o=B(a);return n&&a.addEventListener("upgradeneeded",(t=>{n(B(a.result),t.oldVersion,t.newVersion,B(a.transaction),t)})),s&&a.addEventListener("blocked",(t=>s(t.oldVersion,t.newVersion,t))),o.then((t=>{i&&t.addEventListener("close",(()=>i())),r&&t.addEventListener("versionchange",(t=>r(t.oldVersion,t.newVersion,t)))})).catch((()=>{})),o}("workbox-expiration",1,{upgrade:this.C.bind(this)})),this._}}class H{constructor(t,e={}){this.O=!1,this.T=!1,this.k=e.maxEntries,this.B=e.maxAgeSeconds,this.P=e.matchOptions,this.L=t,this.M=new F(t)}async expireEntries(){if(this.O)return void(this.T=!0);this.O=!0;const t=this.B?Date.now()-1e3*this.B:0,e=await this.M.expireEntries(t,this.k),s=await self.caches.open(this.L);for(const t of e)await s.delete(t,this.P);this.O=!1,this.T&&(this.T=!1,b(this.expireEntries()))}async updateTimestamp(t){await this.M.setTimestamp(t,Date.now())}async isURLExpired(t){if(this.B){const e=await this.M.getTimestamp(t),s=Date.now()-1e3*this.B;return void 0===e||er||e&&e<0)throw new s("range-not-satisfiable",{size:r,end:n,start:e});let i,a;return void 0!==e&&void 0!==n?(i=e,a=n+1):void 0!==e&&void 0===n?(i=e,a=r):void 0!==n&&void 0===e&&(i=r-n,a=r),{start:i,end:a}}(i,r.start,r.end),o=i.slice(a.start,a.end),c=o.size,h=new Response(o,{status:206,statusText:"Partial Content",headers:e.headers});return h.headers.set("Content-Length",String(c)),h.headers.set("Content-Range",`bytes ${a.start}-${a.end-1}/${i.size}`),h}catch(t){return new Response("",{status:416,statusText:"Range Not Satisfiable"})}}function z(t,e){const s=e();return t.waitUntil(s),s}try{self["workbox:precaching:6.5.4"]&&_()}catch(t){}function G(t){if(!t)throw new s("add-to-cache-list-unexpected-type",{entry:t});if("string"==typeof t){const e=new URL(t,location.href);return{cacheKey:e.href,url:e.href}}const{revision:e,url:n}=t;if(!n)throw new s("add-to-cache-list-unexpected-type",{entry:t});if(!e){const t=new URL(n,location.href);return{cacheKey:t.href,url:t.href}}const r=new URL(n,location.href),i=new URL(n,location.href);return r.searchParams.set("__WB_REVISION__",e),{cacheKey:r.href,url:i.href}}class V{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerWillStart=async({request:t,state:e})=>{e&&(e.originalRequest=t)},this.cachedResponseWillBeUsed=async({event:t,state:e,cachedResponse:s})=>{if("install"===t.type&&e&&e.originalRequest&&e.originalRequest instanceof Request){const t=e.originalRequest.url;s?this.notUpdatedURLs.push(t):this.updatedURLs.push(t)}return s}}}class J{constructor({precacheController:t}){this.cacheKeyWillBeUsed=async({request:t,params:e})=>{const s=(null==e?void 0:e.cacheKey)||this.W.getCacheKeyForURL(t.url);return s?new Request(s,{headers:t.headers}):t},this.W=t}}let Q,X;async function Y(t,e){let n=null;if(t.url){n=new URL(t.url).origin}if(n!==self.location.origin)throw new s("cross-origin-copy-response",{origin:n});const r=t.clone(),i={headers:new Headers(r.headers),status:r.status,statusText:r.statusText},a=e?e(i):i,o=function(){if(void 0===Q){const t=new Response("");if("body"in t)try{new Response(t.body),Q=!0}catch(t){Q=!1}Q=!1}return Q}()?r.body:await r.blob();return new Response(o,a)}class Z extends v{constructor(t={}){t.cacheName=w(t.cacheName),super(t),this.j=!1!==t.fallbackToNetwork,this.plugins.push(Z.copyRedirectedCacheableResponsesPlugin)}async U(t,e){const s=await e.cacheMatch(t);return s||(e.event&&"install"===e.event.type?await this.S(t,e):await this.K(t,e))}async K(t,e){let n;const r=e.params||{};if(!this.j)throw new s("missing-precache-entry",{cacheName:this.cacheName,url:t.url});{const s=r.integrity,i=t.integrity,a=!i||i===s;n=await e.fetch(new Request(t,{integrity:"no-cors"!==t.mode?i||s:void 0})),s&&a&&"no-cors"!==t.mode&&(this.A(),await e.cachePut(t,n.clone()))}return n}async S(t,e){this.A();const n=await e.fetch(t);if(!await e.cachePut(t,n.clone()))throw new s("bad-precaching-response",{url:t.url,status:n.status});return n}A(){let t=null,e=0;for(const[s,n]of this.plugins.entries())n!==Z.copyRedirectedCacheableResponsesPlugin&&(n===Z.defaultPrecacheCacheabilityPlugin&&(t=s),n.cacheWillUpdate&&e++);0===e?this.plugins.push(Z.defaultPrecacheCacheabilityPlugin):e>1&&null!==t&&this.plugins.splice(t,1)}}Z.defaultPrecacheCacheabilityPlugin={cacheWillUpdate:async({response:t})=>!t||t.status>=400?null:t},Z.copyRedirectedCacheableResponsesPlugin={cacheWillUpdate:async({response:t})=>t.redirected?await Y(t):t};class tt{constructor({cacheName:t,plugins:e=[],fallbackToNetwork:s=!0}={}){this.F=new Map,this.H=new Map,this.$=new Map,this.u=new Z({cacheName:w(t),plugins:[...e,new J({precacheController:this})],fallbackToNetwork:s}),this.install=this.install.bind(this),this.activate=this.activate.bind(this)}get strategy(){return this.u}precache(t){this.addToCacheList(t),this.G||(self.addEventListener("install",this.install),self.addEventListener("activate",this.activate),this.G=!0)}addToCacheList(t){const e=[];for(const n of t){"string"==typeof n?e.push(n):n&&void 0===n.revision&&e.push(n.url);const{cacheKey:t,url:r}=G(n),i="string"!=typeof n&&n.revision?"reload":"default";if(this.F.has(r)&&this.F.get(r)!==t)throw new s("add-to-cache-list-conflicting-entries",{firstEntry:this.F.get(r),secondEntry:t});if("string"!=typeof n&&n.integrity){if(this.$.has(t)&&this.$.get(t)!==n.integrity)throw new s("add-to-cache-list-conflicting-integrities",{url:r});this.$.set(t,n.integrity)}if(this.F.set(r,t),this.H.set(r,i),e.length>0){const t=`Workbox is precaching URLs without revision info: ${e.join(", ")}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(t)}}}install(t){return z(t,(async()=>{const e=new V;this.strategy.plugins.push(e);for(const[e,s]of this.F){const n=this.$.get(s),r=this.H.get(e),i=new Request(e,{integrity:n,cache:r,credentials:"same-origin"});await Promise.all(this.strategy.handleAll({params:{cacheKey:s},request:i,event:t}))}const{updatedURLs:s,notUpdatedURLs:n}=e;return{updatedURLs:s,notUpdatedURLs:n}}))}activate(t){return z(t,(async()=>{const t=await self.caches.open(this.strategy.cacheName),e=await t.keys(),s=new Set(this.F.values()),n=[];for(const r of e)s.has(r.url)||(await t.delete(r),n.push(r.url));return{deletedURLs:n}}))}getURLsToCacheKeys(){return this.F}getCachedURLs(){return[...this.F.keys()]}getCacheKeyForURL(t){const e=new URL(t,location.href);return this.F.get(e.href)}getIntegrityForCacheKey(t){return this.$.get(t)}async matchPrecache(t){const e=t instanceof Request?t.url:t,s=this.getCacheKeyForURL(e);if(s){return(await self.caches.open(this.strategy.cacheName)).match(s)}}createHandlerBoundToURL(t){const e=this.getCacheKeyForURL(t);if(!e)throw new s("non-precached-url",{url:t});return s=>(s.request=new Request(t),s.params=Object.assign({cacheKey:e},s.params),this.strategy.handle(s))}}const et=()=>(X||(X=new tt),X);class st extends r{constructor(t,e){super((({request:s})=>{const n=t.getURLsToCacheKeys();for(const r of function*(t,{ignoreURLParametersMatching:e=[/^utm_/,/^fbclid$/],directoryIndex:s="index.html",cleanURLs:n=!0,urlManipulation:r}={}){const i=new URL(t,location.href);i.hash="",yield i.href;const a=function(t,e=[]){for(const s of[...t.searchParams.keys()])e.some((t=>t.test(s)))&&t.searchParams.delete(s);return t}(i,e);if(yield a.href,s&&a.pathname.endsWith("/")){const t=new URL(a.href);t.pathname+=s,yield t.href}if(n){const t=new URL(a.href);t.pathname+=".html",yield t.href}if(r){const t=r({url:i});for(const e of t)yield e.href}}(s.url,e)){const e=n.get(r);if(e){return{cacheKey:e,integrity:t.getIntegrityForCacheKey(e)}}}}),t.strategy)}}t.CacheFirst=class extends v{async U(t,e){let n,r=await e.cacheMatch(t);if(!r)try{r=await e.fetchAndCachePut(t)}catch(t){t instanceof Error&&(n=t)}if(!r)throw new s("no-response",{url:t.url,error:n});return r}},t.ExpirationPlugin=class{constructor(t={}){this.cachedResponseWillBeUsed=async({event:t,request:e,cacheName:s,cachedResponse:n})=>{if(!n)return null;const r=this.V(n),i=this.J(s);b(i.expireEntries());const a=i.updateTimestamp(e.url);if(t)try{t.waitUntil(a)}catch(t){}return r?n:null},this.cacheDidUpdate=async({cacheName:t,request:e})=>{const s=this.J(t);await s.updateTimestamp(e.url),await s.expireEntries()},this.X=t,this.B=t.maxAgeSeconds,this.Y=new Map,t.purgeOnQuotaError&&function(t){g.add(t)}((()=>this.deleteCacheAndMetadata()))}J(t){if(t===d())throw new s("expire-custom-caches-only");let e=this.Y.get(t);return e||(e=new H(t,this.X),this.Y.set(t,e)),e}V(t){if(!this.B)return!0;const e=this.Z(t);if(null===e)return!0;return e>=Date.now()-1e3*this.B}Z(t){if(!t.headers.has("date"))return null;const e=t.headers.get("date"),s=new Date(e).getTime();return isNaN(s)?null:s}async deleteCacheAndMetadata(){for(const[t,e]of this.Y)await self.caches.delete(t),await e.delete();this.Y=new Map}},t.NetworkFirst=class extends v{constructor(t={}){super(t),this.plugins.some((t=>"cacheWillUpdate"in t))||this.plugins.unshift(u),this.tt=t.networkTimeoutSeconds||0}async U(t,e){const n=[],r=[];let i;if(this.tt){const{id:s,promise:a}=this.et({request:t,logs:n,handler:e});i=s,r.push(a)}const a=this.st({timeoutId:i,request:t,logs:n,handler:e});r.push(a);const o=await e.waitUntil((async()=>await e.waitUntil(Promise.race(r))||await a)());if(!o)throw new s("no-response",{url:t.url});return o}et({request:t,logs:e,handler:s}){let n;return{promise:new Promise((e=>{n=setTimeout((async()=>{e(await s.cacheMatch(t))}),1e3*this.tt)})),id:n}}async st({timeoutId:t,request:e,logs:s,handler:n}){let r,i;try{i=await n.fetchAndCachePut(e)}catch(t){t instanceof Error&&(r=t)}return t&&clearTimeout(t),!r&&i||(i=await n.cacheMatch(e)),i}},t.RangeRequestsPlugin=class{constructor(){this.cachedResponseWillBeUsed=async({request:t,cachedResponse:e})=>e&&t.headers.has("range")?await $(t,e):e}},t.StaleWhileRevalidate=class extends v{constructor(t={}){super(t),this.plugins.some((t=>"cacheWillUpdate"in t))||this.plugins.unshift(u)}async U(t,e){const n=e.fetchAndCachePut(t).catch((()=>{}));e.waitUntil(n);let r,i=await e.cacheMatch(t);if(i);else try{i=await n}catch(t){t instanceof Error&&(r=t)}if(!i)throw new s("no-response",{url:t.url,error:r});return i}},t.cleanupOutdatedCaches=function(){self.addEventListener("activate",(t=>{const e=w();t.waitUntil((async(t,e="-precache-")=>{const s=(await self.caches.keys()).filter((s=>s.includes(e)&&s.includes(self.registration.scope)&&s!==t));return await Promise.all(s.map((t=>self.caches.delete(t)))),s})(e).then((t=>{})))}))},t.clientsClaim=function(){self.addEventListener("activate",(()=>self.clients.claim()))},t.precacheAndRoute=function(t,e){!function(t){et().precache(t)}(t),function(t){const e=et();h(new st(e,t))}(e)},t.registerRoute=h})); 2 | -------------------------------------------------------------------------------- /src/components/Chat.tsx: -------------------------------------------------------------------------------- 1 | import { motion } from "framer-motion"; 2 | import { useState, useRef, useEffect, ChangeEvent, KeyboardEvent } from "react"; 3 | import axios from "axios"; 4 | 5 | interface Message { 6 | text: string; 7 | sender: "user" | "bot"; 8 | } 9 | 10 | const Chat = () => { 11 | const [messages, setMessages] = useState([]); 12 | const [input, setInput] = useState(""); 13 | const inputRef = useRef(null); 14 | const [error, setError] = useState(null); 15 | const [loading, setLoading] = useState(false); 16 | 17 | useEffect(() => { 18 | if (inputRef.current) { 19 | inputRef.current.focus(); 20 | } 21 | }, []); 22 | 23 | const sendMessage = async () => { 24 | if (!input.trim()) return; 25 | 26 | const newMessage: Message = { text: input, sender: "user" }; 27 | setMessages((prevMessages) => [...prevMessages, newMessage]); 28 | setInput(""); 29 | 30 | try { 31 | setLoading(true); 32 | const response = await axios.get(process.env.AI_URL || "", { 33 | params: { 34 | message: input, 35 | }, 36 | }); 37 | const reply: Message = { text: response.data.response, sender: "bot" }; 38 | setMessages((prevMessages) => [...prevMessages, reply]); 39 | setError(null); 40 | setLoading(false); 41 | } catch (error) { 42 | console.error("Error sending message:", error); 43 | setError("Failed to send message. Please try again."); 44 | setLoading(false); 45 | } 46 | }; 47 | 48 | const handleInputChange = (e: ChangeEvent) => { 49 | setInput(e.target.value); 50 | }; 51 | 52 | const handleKeyPress = (e: KeyboardEvent) => { 53 | if (e.key === "Enter") sendMessage(); 54 | }; 55 | 56 | return ( 57 | 65 |
66 |
AI Assistance
67 |
68 | {messages.map((msg, index) => ( 69 |
77 | {msg.text} 78 |
79 | ))} 80 | {loading && ( 81 |
82 | Loading... 83 |
84 | )} 85 |
86 | {error &&
{error}
} 87 |
88 | 96 | 102 |
103 |
104 | AI can provide total BS response too, because ... it's AI :D 105 |
106 |
107 |
108 | ); 109 | }; 110 | 111 | export default Chat; 112 | -------------------------------------------------------------------------------- /src/components/Icons/BackupIcon.tsx: -------------------------------------------------------------------------------- 1 | import { SVGProps } from "react"; 2 | 3 | export function BackupIcon(props: SVGProps) { 4 | return ( 5 | 12 | 17 | 22 | 27 | 28 | 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /src/components/Icons/BingIcon.tsx: -------------------------------------------------------------------------------- 1 | import { SVGProps } from "react"; 2 | 3 | export function BingIcon(props: SVGProps) { 4 | return ( 5 | 12 | 13 | 22 | 23 | 24 | 25 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 46 | 50 | 54 | 55 | ); 56 | } 57 | -------------------------------------------------------------------------------- /src/components/Icons/CrossIcon.tsx: -------------------------------------------------------------------------------- 1 | import { SVGProps } from "react"; 2 | 3 | export function CrossIcon(props: SVGProps) { 4 | return ( 5 | 12 | 18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /src/components/Icons/DiceIcon.tsx: -------------------------------------------------------------------------------- 1 | import { SVGProps } from "react"; 2 | 3 | export function DiceIcon(props: SVGProps) { 4 | return ( 5 | 12 | 13 | 17 | 18 | 19 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /src/components/Icons/DiscordIcon.tsx: -------------------------------------------------------------------------------- 1 | import { SVGProps } from "react"; 2 | 3 | export function DiscordIcon(props: SVGProps) { 4 | return ( 5 | 12 | 16 | 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/components/Icons/DuckDuckGoIcon.tsx: -------------------------------------------------------------------------------- 1 | import { SVGProps } from "react"; 2 | 3 | export function DuckDuckGoIcon(props: SVGProps) { 4 | return ( 5 | 12 | 13 | 20 | 21 | 22 | 23 | 24 | 28 | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 61 | 65 | 69 | 73 | 77 | 78 | ); 79 | } 80 | -------------------------------------------------------------------------------- /src/components/Icons/EditIcon.tsx: -------------------------------------------------------------------------------- 1 | import { SVGProps } from "react"; 2 | export function EditIcon(props: SVGProps) { 3 | return ( 4 | 11 | 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /src/components/Icons/GeneralIcon.tsx: -------------------------------------------------------------------------------- 1 | import { SVGProps } from "react"; 2 | export function GeneralIcon(props: SVGProps) { 3 | return ( 4 | 11 | 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /src/components/Icons/GithubIcon.tsx: -------------------------------------------------------------------------------- 1 | import { SVGProps } from "react"; 2 | 3 | export function GithubIcon(props: SVGProps) { 4 | return ( 5 | 12 | 16 | 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/components/Icons/GoogleIcon.tsx: -------------------------------------------------------------------------------- 1 | import { SVGProps } from "react"; 2 | 3 | export function GoogleIcon(props: SVGProps) { 4 | return ( 5 | 12 | 16 | 20 | 24 | 28 | 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /src/components/Icons/Humidity.tsx: -------------------------------------------------------------------------------- 1 | import { SVGProps } from "react"; 2 | 3 | export function HumidityIcon(props: SVGProps) { 4 | return ( 5 | 12 | 16 | 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/components/Icons/LocationIcon.tsx: -------------------------------------------------------------------------------- 1 | import { SVGProps } from "react"; 2 | 3 | export function LocationIcon(props: SVGProps) { 4 | return ( 5 | 12 | 16 | 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/components/Icons/MinusIcon.tsx: -------------------------------------------------------------------------------- 1 | import { SVGProps } from "react"; 2 | 3 | export function MinusIcon(props: SVGProps) { 4 | return ( 5 | 12 | 13 | 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /src/components/Icons/PalleteIcon.tsx: -------------------------------------------------------------------------------- 1 | import { SVGProps } from "react"; 2 | 3 | export function PalleteIcon(props: SVGProps) { 4 | return ( 5 | 12 | 18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /src/components/Icons/PerplexityIcon.tsx: -------------------------------------------------------------------------------- 1 | import { SVGProps } from "react"; 2 | 3 | export function PerplexityIcon(props: SVGProps) { 4 | return ( 5 | 12 | 16 | 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/components/Icons/PlusIcon.tsx: -------------------------------------------------------------------------------- 1 | import { SVGProps } from "react"; 2 | 3 | export function PlusIcon(props: SVGProps) { 4 | return ( 5 | 12 | 20 | 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /src/components/Icons/SettingIcon.tsx: -------------------------------------------------------------------------------- 1 | import { SVGProps } from "react"; 2 | 3 | export function SettingIcon(props: SVGProps) { 4 | return ( 5 | 12 | 18 | 19 | 20 | 21 | 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /src/components/Icons/SparkleIcon.tsx: -------------------------------------------------------------------------------- 1 | import { SVGProps } from "react"; 2 | export function SparkleIcon(props: SVGProps) { 3 | return ( 4 | 11 | 19 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /src/components/Icons/WidgetIcon.tsx: -------------------------------------------------------------------------------- 1 | import { SVGProps } from "react"; 2 | 3 | export function WidgetIcon(props: SVGProps) { 4 | return ( 5 | 12 | 18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /src/components/Icons/WindIcon.tsx: -------------------------------------------------------------------------------- 1 | import { SVGProps } from "react"; 2 | 3 | export function WindIcon(props: SVGProps) { 4 | return ( 5 | 12 | 16 | 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/components/Nav.tsx: -------------------------------------------------------------------------------- 1 | import Settings from "@/components/Settings"; 2 | import Chat from "@/components/Chat"; 3 | 4 | import { useState, useRef, useEffect } from "react"; 5 | import { AnimatePresence } from "framer-motion"; 6 | 7 | import { SettingIcon } from "@/components/Icons/SettingIcon"; 8 | import { EditIcon } from "@/components/Icons/EditIcon"; 9 | import { SparkleIcon } from "@/components/Icons/SparkleIcon"; 10 | 11 | interface NavProps { 12 | edit: boolean; 13 | setEdit: (edit: boolean) => void; 14 | } 15 | 16 | const Nav: React.FC = ({ edit, setEdit }) => { 17 | const [tab, setTab] = useState(""); 18 | const settingsRef = useRef(null); 19 | 20 | const handleClickOutside = (event: MouseEvent) => { 21 | if ( 22 | settingsRef.current && 23 | !settingsRef.current.contains(event.target as Node) 24 | ) { 25 | setTab(""); 26 | } 27 | }; 28 | 29 | useEffect(() => { 30 | document.addEventListener("mousedown", handleClickOutside); 31 | return () => { 32 | document.removeEventListener("mousedown", handleClickOutside); 33 | }; 34 | }, []); 35 | 36 | return ( 37 |
38 |
39 |
40 | 41 |
42 | 47 | 50 | 57 |
58 |
59 | 60 | {tab === "settings" && } 61 | {tab === "ai" && } 62 |
63 | ); 64 | }; 65 | 66 | export default Nav; 67 | -------------------------------------------------------------------------------- /src/components/SettingSections/AppearanceSection.tsx: -------------------------------------------------------------------------------- 1 | import { useSettings } from "@/contexts/SettingsContext"; 2 | import { useEffect, useState } from "react"; 3 | import { getContrastingColor, getPalette } from "@/utils/colorUtils"; 4 | import { debounce } from "lodash"; 5 | 6 | import * as Select from "@radix-ui/react-select"; 7 | import * as Slider from "@radix-ui/react-slider"; 8 | import { 9 | ChevronDownIcon, 10 | ChevronUpIcon, 11 | CheckIcon, 12 | } from "@radix-ui/react-icons"; 13 | 14 | const AppearanceSection = () => { 15 | const { settings, updateSettings } = useSettings(); 16 | const [backgroundBlur, setBackgroundBlur] = useState( 17 | settings.backgroundBlur 18 | ); 19 | 20 | const [customColor, setCustomColor] = useState(settings.accent_color); 21 | 22 | const themeOptions = [ 23 | { value: "dark", label: "Dark" }, 24 | { value: "light", label: "Light" }, 25 | { value: "solid", label: "Solid" }, 26 | ]; 27 | 28 | const wallpapers = [ 29 | "/wallpaper1.jpg", 30 | "/wallpaper2.jpg", 31 | "/wallpaper3.jpg", 32 | "/wallpaper4.jpg", 33 | "/wallpaper5.jpg", 34 | ]; 35 | 36 | const handleThemeChange = (value: string) => { 37 | updateSettings({ theme: value as "light" | "dark" | "solid" }); 38 | }; 39 | 40 | const handleWallpaperChange = async (url: string) => { 41 | const palette = await getPalette(url); 42 | const accentColor = palette[0]; 43 | const textColor = getContrastingColor(palette[0]); 44 | updateSettings({ 45 | backgroundImage: url, 46 | theme_colors: palette, 47 | accent_color: accentColor, 48 | text_color: textColor, 49 | }); 50 | }; 51 | 52 | const handleBlurChange = (value: number[]) => { 53 | const newBlur = value[0]; 54 | setBackgroundBlur(newBlur); 55 | updateSettings({ ...settings, backgroundBlur: newBlur }); 56 | }; 57 | 58 | const isValidUrl = (url: string): boolean => { 59 | try { 60 | new URL(url); 61 | const imagePattern = /\.(jpg|jpeg|png|gif|bmp|webp)$/i; 62 | return imagePattern.test(url); 63 | } catch (e) { 64 | return false; 65 | } 66 | }; 67 | 68 | const handleWallpaperURLChange = ( 69 | e: React.ChangeEvent 70 | ): void => { 71 | const inputValue = e.target.value; 72 | 73 | if (isValidUrl(inputValue)) { 74 | handleWallpaperChange(inputValue); 75 | } 76 | }; 77 | 78 | const handleCustomColorChange = ( 79 | event: React.ChangeEvent 80 | ) => { 81 | const color = event.target.value; 82 | setCustomColor(color); 83 | 84 | document.documentElement.style.setProperty("--accent-color", color); 85 | const contrastingColor = getContrastingColor(color); 86 | document.documentElement.style.setProperty( 87 | "--solid-text-color", 88 | contrastingColor 89 | ); 90 | }; 91 | 92 | useEffect(() => { 93 | const handleDebounce = debounce(() => { 94 | const contrastingColor = getContrastingColor(customColor); 95 | updateSettings({ 96 | accent_color: customColor, 97 | text_color: contrastingColor, 98 | }); 99 | }, 2000); 100 | 101 | handleDebounce(); 102 | 103 | return () => { 104 | handleDebounce.cancel(); 105 | }; 106 | }, [customColor, updateSettings]); 107 | 108 | const handleColorChange = (color: string) => { 109 | setCustomColor(color); 110 | const contrastingColor = getContrastingColor(color); 111 | 112 | updateSettings({ 113 | accent_color: color, 114 | text_color: contrastingColor, 115 | }); 116 | }; 117 | 118 | return ( 119 |
120 |
121 | Theme 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | {themeOptions.map((option) => ( 136 | 141 | {option.label} 142 | 143 | 144 | 145 | 146 | ))} 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 |
155 | 156 |
157 | Wallpaper 158 |
159 | Wallpaper 164 |
165 | Current wallpaper 166 |
167 |
168 |
169 | {wallpapers.map((wallpaper, index) => ( 170 | {`wallpaper${index handleWallpaperChange(wallpaper)} 178 | /> 179 | ))} 180 |
181 | 186 |
187 | 188 |
189 | Colors 190 |
191 | {settings.theme_colors.map((color, index) => ( 192 |
handleColorChange(color)} 197 | /> 198 | ))} 199 | 206 |
207 |
208 | 209 |
210 | Background Blur 211 | 219 | 220 | 221 | 222 | 223 | 224 |
225 |
226 | ); 227 | }; 228 | 229 | export default AppearanceSection; 230 | -------------------------------------------------------------------------------- /src/components/SettingSections/BackupSection.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useRef } from "react"; 2 | import { useSettings } from "@/contexts/SettingsContext"; 3 | import { useWidgets } from "@/contexts/WidgetsContext"; 4 | 5 | const BackupSection = () => { 6 | const { settings, updateSettings } = useSettings(); 7 | const { widgets, setWidgets } = useWidgets(); 8 | const [importMessage, setImportMessage] = useState(null); 9 | const fileInputRef = useRef(null); 10 | 11 | const exportData = () => { 12 | const data = { 13 | settings, 14 | widgets, 15 | }; 16 | const json = JSON.stringify(data, null, 2); 17 | const blob = new Blob([json], { type: "application/json" }); 18 | const url = URL.createObjectURL(blob); 19 | const link = document.createElement("a"); 20 | link.href = url; 21 | link.download = "backup.json"; 22 | link.click(); 23 | }; 24 | 25 | const importData = (event: React.ChangeEvent) => { 26 | const file = event.target.files?.[0]; 27 | if (!file) return; 28 | 29 | const reader = new FileReader(); 30 | reader.onload = (e) => { 31 | const json = e.target?.result; 32 | if (typeof json === "string") { 33 | const data = JSON.parse(json); 34 | if (data.settings && data.widgets) { 35 | updateSettings(data.settings); 36 | setWidgets(data.widgets); 37 | setImportMessage("Items imported successfully!"); 38 | } 39 | } 40 | }; 41 | reader.readAsText(file); 42 | }; 43 | 44 | const triggerFileInput = () => { 45 | if (fileInputRef.current) { 46 | fileInputRef.current.click(); 47 | } 48 | }; 49 | 50 | return ( 51 |
52 |
53 | 59 | 65 | 72 | {importMessage && ( 73 |

{importMessage}

74 | )} 75 |
76 |
77 | ); 78 | }; 79 | 80 | export default BackupSection; 81 | -------------------------------------------------------------------------------- /src/components/SettingSections/GeneralSection.tsx: -------------------------------------------------------------------------------- 1 | import { useSettings } from "@/contexts/SettingsContext"; 2 | import * as Select from "@radix-ui/react-select"; 3 | import { 4 | ChevronDownIcon, 5 | ChevronUpIcon, 6 | CheckIcon, 7 | } from "@radix-ui/react-icons"; 8 | import { debounce } from "lodash"; 9 | import { useCallback } from "react"; 10 | 11 | const GeneralSection = () => { 12 | const { settings, updateSettings } = useSettings(); 13 | 14 | const searchEngineOptions = [ 15 | { value: "google", label: "Google" }, 16 | { value: "bing", label: "Bing" }, 17 | { value: "duckduckgo", label: "Duckduckgo" }, 18 | { value: "perplexity", label: "Perplexity" }, 19 | ]; 20 | 21 | const timeFormatOptions = ["24hr", "12hr"]; 22 | const temperatureFormatOptions = ["Fahrenheit", "Celsius"]; 23 | 24 | const handleSearchEngineChange = (value: string) => { 25 | updateSettings({ 26 | searchEngine: value as "google" | "bing" | "duckduckgo" | "perplexity", 27 | }); 28 | }; 29 | 30 | const handleTimeFormatChange = (value: string) => { 31 | updateSettings({ timeFormat: value as "24hr" | "12hr" }); 32 | }; 33 | 34 | const handleTemperatureFormatChange = (value: string) => { 35 | updateSettings({ 36 | temperatureFormat: value as "Fahrenheit" | "Celsius", 37 | }); 38 | }; 39 | 40 | const handleCityChange = useCallback( 41 | debounce((event: React.ChangeEvent) => { 42 | updateSettings({ 43 | city: event.target.value, 44 | }); 45 | }, 2000), 46 | [] 47 | ); 48 | 49 | return ( 50 |
51 |
52 | Search Engine 53 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | {searchEngineOptions.map((option) => ( 70 | 75 | {option.label} 76 | 77 | 78 | 79 | 80 | ))} 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 |
89 | 90 |
91 | Time Format 92 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | {timeFormatOptions.map((option) => ( 109 | 114 | {option} 115 | 116 | 117 | 118 | 119 | ))} 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 |
128 | 129 |
130 | Temperature Format 131 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | {temperatureFormatOptions.map((option) => ( 148 | 153 | {option} 154 | 155 | 156 | 157 | 158 | ))} 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 |
167 | 168 |
169 | City 170 | 175 |
176 |
177 | ); 178 | }; 179 | export default GeneralSection; 180 | -------------------------------------------------------------------------------- /src/components/SettingSections/WidgetSection.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import { useWidgets } from "@/contexts/WidgetsContext"; 3 | 4 | import Search from "@/components/Widgets/Search"; 5 | import Time from "@/components/Widgets/Time"; 6 | import Tile from "@/components/Widgets/Tile"; 7 | import { NotePreview } from "@/components/Widgets/Note"; 8 | import { TodoPreview } from "@/components/Widgets/Todo"; 9 | import Weather from "@/components/Widgets/Weather"; 10 | import Countdown from "@/components/Widgets/Countdown"; 11 | import { SearchDimensions } from "@/components/Widgets/Search"; 12 | import { TodoDimensions } from "@/components/Widgets/Todo"; 13 | import { TimeDimensions } from "@/components/Widgets/Time"; 14 | import { TileDimensions } from "@/components/Widgets/Tile"; 15 | import { WeatherDimensions } from "@/components/Widgets/Weather"; 16 | import { CountdownDimensions } from "@/components/Widgets/Countdown"; 17 | import { NoteDimensions } from "@/components/Widgets/Note"; 18 | 19 | const WidgetSection = () => { 20 | const [url, setUrl] = useState(""); 21 | const [title, setTitle] = useState(""); 22 | const [countdown_title, setCountdown_title] = useState(""); 23 | const [countdown_date, setCountdown_date] = useState(new Date()); 24 | const { addWidget } = useWidgets(); 25 | return ( 26 |
27 | Widgets 28 |
29 |
30 |
31 |
32 | 33 |
34 |
35 |
36 | setUrl(e.target.value)} 41 | /> 42 | setTitle(e.target.value)} 47 | /> 48 | 59 |
60 | 61 |
62 |
63 | 64 |
65 | setCountdown_title(e.target.value)} 70 | /> 71 | setCountdown_date(new Date(e.target.value))} 76 | /> 77 | 88 |
89 | 90 |
91 | 92 |
93 | 104 |
105 |
106 | 107 |
108 | 109 |
110 | 118 |
119 |
120 | 121 |
122 | 123 |
124 | 130 |
131 |
132 | 133 |
134 |
144 | 145 |
146 | 147 |
148 | 154 |
155 |
156 |
157 |
158 | ); 159 | }; 160 | 161 | export default WidgetSection; 162 | -------------------------------------------------------------------------------- /src/components/Settings.tsx: -------------------------------------------------------------------------------- 1 | import { motion } from "framer-motion"; 2 | import { useState } from "react"; 3 | import Link from "next/link"; 4 | 5 | import { GithubIcon } from "@/components/Icons/GithubIcon"; 6 | import { DiscordIcon } from "@/components/Icons/DiscordIcon"; 7 | import { BackupIcon } from "@/components/Icons/BackupIcon"; 8 | import { WidgetIcon } from "@/components/Icons/WidgetIcon"; 9 | import { GeneralIcon } from "@/components/Icons/GeneralIcon"; 10 | import { PalleteIcon } from "@/components/Icons/PalleteIcon"; 11 | 12 | import GeneralSection from "@/components/SettingSections/GeneralSection"; 13 | import AppearanceSection from "@/components/SettingSections/AppearanceSection"; 14 | import WidgetSection from "@/components/SettingSections/WidgetSection"; 15 | import BackupSection from "@/components/SettingSections/BackupSection"; 16 | 17 | const Settings = () => { 18 | const [active, setActive] = useState("general"); 19 | 20 | return ( 21 | 29 |
30 | Settings 31 |
    32 |
  • setActive("general")} 34 | className={`cursor-pointer py-1.5 px-2 text-sm rounded-sm flex gap-2 items-center ${ 35 | active === "general" 36 | ? "bg-gray-800/60 border-l-2" 37 | : "hover:bg-gray-600/30" 38 | }`} 39 | > 40 | 41 | 42 | 43 | General 44 |
  • 45 |
  • setActive("appearance")} 47 | className={`cursor-pointer py-1.5 px-2 text-sm rounded-sm flex gap-2 items-center ${ 48 | active === "appearance" 49 | ? "bg-gray-800/60 border-l-2" 50 | : "hover:bg-gray-600/30" 51 | }`} 52 | > 53 | 54 | 55 | 56 | Appearance 57 |
  • 58 |
  • setActive("widgets")} 60 | className={`cursor-pointer py-1.5 px-2 text-sm rounded-sm flex gap-2 items-center ${ 61 | active === "widgets" 62 | ? "bg-gray-800/60 border-l-2" 63 | : "hover:bg-gray-600/30" 64 | }`} 65 | > 66 | 67 | 68 | 69 | Widgets 70 |
  • 71 |
  • setActive("backup")} 73 | className={`cursor-pointer py-1.5 px-2 text-sm rounded-sm flex gap-2 items-center ${ 74 | active === "backup" 75 | ? "bg-gray-800/60 border-l-2" 76 | : "hover:bg-gray-600/30" 77 | }`} 78 | > 79 | 80 | 81 | 82 | Backup 83 |
  • 84 |
85 | 86 |
87 |
88 | 89 | 90 | 91 | 92 | 93 | 94 |
95 |
96 | Odash 97 |
98 |
99 |
100 |
101 | {active === "general" && } 102 | {active === "appearance" && } 103 | {active === "widgets" && } 104 | {active === "backup" && } 105 |
106 |
107 | ); 108 | }; 109 | 110 | export default Settings; 111 | -------------------------------------------------------------------------------- /src/components/WidgetLayout.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import { useWidgets } from "@/contexts/WidgetsContext"; 3 | import "react-grid-layout/css/styles.css"; 4 | import "react-resizable/css/styles.css"; 5 | import { Responsive, WidthProvider, Layout } from "react-grid-layout"; 6 | import { CrossIcon } from "@/components/Icons/CrossIcon"; 7 | import Time from "@/components/Widgets/Time"; 8 | import Tile from "@/components/Widgets/Tile"; 9 | import Search from "@/components/Widgets/Search"; 10 | import Todo from "@/components/Widgets/Todo"; 11 | import Weather from "@/components/Widgets/Weather"; 12 | import Countdown from "@/components/Widgets/Countdown"; 13 | import Note from "@/components/Widgets/Note"; 14 | 15 | const ResponsiveGridLayout = WidthProvider(Responsive); 16 | 17 | interface Widget { 18 | i: string; 19 | component: string; 20 | dimensions: Layout; 21 | props?: { [key: string]: any }; 22 | } 23 | 24 | interface WidgetLayout { 25 | edit: boolean; 26 | } 27 | 28 | const componentMap: { [key: string]: React.ComponentType } = { 29 | Time, 30 | Search, 31 | Todo, 32 | Weather, 33 | Tile, 34 | Countdown, 35 | Note, 36 | }; 37 | 38 | const WidgetLayout = ({ edit }: WidgetLayout) => { 39 | const { widgets, setWidgets } = useWidgets(); 40 | const handleNoteUpdate = (id: string, title: string, description: string) => { 41 | const updatedWidgets = widgets.map((widget: Widget) => 42 | widget.i === id 43 | ? { ...widget, props: { ...widget.props, title, description } } 44 | : widget 45 | ); 46 | setWidgets(updatedWidgets); 47 | }; 48 | 49 | const handleTodoUpdate = ( 50 | id: string, 51 | title: string, 52 | todos: { text: string; completed: boolean }[] 53 | ) => { 54 | const updatedWidgets = widgets.map((widget: Widget) => 55 | widget.i === id 56 | ? { ...widget, props: { ...widget.props, title, todos } } 57 | : widget 58 | ); 59 | setWidgets(updatedWidgets); 60 | }; 61 | return ( 62 | { 73 | const updatedWidgets = layout 74 | .map((l) => { 75 | const widget = widgets.find((w: Widget) => w.i === l.i); 76 | return widget ? { ...widget, dimensions: l } : null; 77 | }) 78 | .filter(Boolean); 79 | setWidgets(updatedWidgets as any); 80 | }} 81 | > 82 | {widgets.map((widget: Widget) => { 83 | const Component = componentMap[widget.component]; 84 | 85 | return ( 86 |
91 | {edit && ( 92 | 100 | )} 101 | {widget.component === "Note" ? ( 102 | 103 | ) : widget.component === "Todo" ? ( 104 | 105 | ) : widget.component === "Tile" ? ( 106 | 107 | ) : ( 108 | 109 | )} 110 |
111 | ); 112 | })} 113 |
114 | ); 115 | }; 116 | 117 | export default WidgetLayout; 118 | -------------------------------------------------------------------------------- /src/components/Widgets/Countdown.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import { useSettings } from "@/contexts/SettingsContext"; 3 | 4 | export const CountdownDimensions = { 5 | x: 0, 6 | y: 0, 7 | w: 3, 8 | h: 5, 9 | maxW: 4, 10 | maxH: 5, 11 | minW: 3, 12 | minH: 5, 13 | }; 14 | 15 | interface CountdownProps { 16 | title: string; 17 | date: Date; 18 | id: string; 19 | } 20 | 21 | const Countdown: React.FC = ({ title, date, id }) => { 22 | const { settings } = useSettings(); 23 | const theme = settings.theme; 24 | const themeClass = 25 | theme === "dark" 26 | ? "dark" 27 | : theme === "light" 28 | ? "light" 29 | : "bg-accent text-solid-text"; 30 | 31 | // Function to calculate days left 32 | const calculateDaysLeft = (targetDate: Date) => { 33 | const currentDate = new Date(); 34 | targetDate = new Date(targetDate); 35 | const timeDiff = targetDate.getTime() - currentDate.getTime(); 36 | return Math.round(Math.abs(timeDiff / (1000 * 3600 * 24))); 37 | }; 38 | 39 | const [daysLeft, setDaysLeft] = useState(1); 40 | 41 | // Update days left when the component mounts or when the date prop changes 42 | useEffect(() => { 43 | setDaysLeft(calculateDaysLeft(date)); 44 | }, [date]); 45 | 46 | return ( 47 |
50 |
51 | {title} 52 |
53 |
54 | {daysLeft} 55 | {daysLeft === 1 ? "day" : "days"} left 56 |
57 |
58 | ); 59 | }; 60 | 61 | export default Countdown; 62 | -------------------------------------------------------------------------------- /src/components/Widgets/Note.tsx: -------------------------------------------------------------------------------- 1 | import { useSettings } from "@/contexts/SettingsContext"; 2 | import React, { useState, useEffect, useCallback } from "react"; 3 | import { debounce } from "lodash"; 4 | import { PlusIcon } from "@/components/Icons/PlusIcon"; 5 | import { MinusIcon } from "@/components/Icons/MinusIcon"; 6 | import Markdown from "react-markdown"; 7 | import remarkGfm from "remark-gfm"; 8 | 9 | export const NoteDimensions = { 10 | x: 0, 11 | y: 0, 12 | w: 5, 13 | h: 12, 14 | minW: 4, 15 | minH: 2, 16 | maxW: 7, 17 | maxH: 13, 18 | }; 19 | 20 | export const NotePreview = () => { 21 | const { settings } = useSettings(); 22 | const theme = settings.theme; 23 | return ( 24 |
33 |
34 | 38 | 41 |
42 | 43 |
44 | 48 | It *supports* ~~markdown~~ 49 | 50 |
51 |
52 | ); 53 | }; 54 | 55 | interface NoteProps { 56 | title: string; 57 | description: string; 58 | id: string; 59 | onUpdate: (id: string, title: string, description: string) => void; 60 | } 61 | 62 | const Note: React.FC = ({ title, description, id, onUpdate }) => { 63 | const { settings } = useSettings(); 64 | const theme = settings.theme; 65 | 66 | const [noteContent, setNoteContent] = useState(description); 67 | const [noteTitle, setNotetitle] = useState(title); 68 | const [isEditing, setIsEditing] = useState(false); 69 | 70 | useEffect(() => { 71 | // Create a debounced version of the onUpdate function 72 | const debouncedUpdate = debounce((id, title, description) => { 73 | onUpdate(id, title, description); 74 | }, 500); // Adjust the debounce delay as needed 75 | 76 | debouncedUpdate(id, noteTitle, noteContent); 77 | 78 | // Cleanup function to cancel debounced calls on unmount 79 | return () => { 80 | debouncedUpdate.cancel(); 81 | }; 82 | }, [noteTitle, noteContent, id, onUpdate]); 83 | 84 | const handleTitleChange = (event: React.ChangeEvent) => { 85 | setNotetitle(event.target.value); 86 | }; 87 | 88 | const handleContentChange = ( 89 | event: React.ChangeEvent 90 | ) => { 91 | setNoteContent(event.target.value); 92 | }; 93 | 94 | const toggleEditMode = () => { 95 | setIsEditing(!isEditing); 96 | }; 97 | 98 | return ( 99 |
108 |
109 | 114 | 117 |
118 | 119 |
120 | {isEditing ? ( 121 |