├── .github └── images │ ├── back-to-top.svg │ ├── logo.png │ ├── sep.png │ └── showcase.png ├── .gitignore ├── LICENSE ├── README.md ├── eslint.config.mjs ├── jsconfig.json ├── next.config.mjs ├── package-lock.json ├── package.json ├── public ├── favicon │ ├── 192.png │ ├── 512.png │ ├── 96.png │ ├── apple.png │ ├── favicon.ico │ ├── favicon.svg │ └── site.webmanifest ├── folder-assets │ ├── bigsur │ │ ├── 16 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ ├── mask.png │ │ │ └── shadow.png │ │ ├── 32 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ ├── mask.png │ │ │ └── shadow.png │ │ ├── 64 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ ├── mask.png │ │ │ └── shadow.png │ │ ├── 128 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ ├── mask.png │ │ │ └── shadow.png │ │ ├── 256 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ ├── mask.png │ │ │ └── shadow.png │ │ ├── 512 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ ├── mask.png │ │ │ └── shadow.png │ │ └── 1024 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ ├── mask.png │ │ │ └── shadow.png │ ├── mint-l │ │ ├── 16 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ └── mask.png │ │ ├── 24 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ └── mask.png │ │ ├── 32 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ └── mask.png │ │ ├── 48 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ └── mask.png │ │ ├── 64 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ └── mask.png │ │ ├── 96 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ └── mask.png │ │ ├── 128 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ └── mask.png │ │ ├── 256 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ └── mask.png │ │ └── 512 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ └── mask.png │ ├── previews │ │ ├── bigsur.png │ │ ├── icon-only.png │ │ ├── mint-l.png │ │ ├── win10.png │ │ └── win11.png │ ├── temp-icon.svg │ ├── win10 │ │ ├── 16 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ └── mask.png │ │ ├── 24 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ ├── icon-mask.png │ │ │ └── mask.png │ │ ├── 32 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ ├── icon-mask.png │ │ │ ├── mask.png │ │ │ └── shadow.png │ │ ├── 48 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ ├── icon-mask.png │ │ │ ├── mask.png │ │ │ └── shadow.png │ │ ├── 64 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ ├── icon-mask.png │ │ │ ├── mask.png │ │ │ └── shadow.png │ │ ├── 72 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ ├── icon-mask.png │ │ │ ├── mask.png │ │ │ └── shadow.png │ │ ├── 96 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ ├── icon-mask.png │ │ │ ├── mask.png │ │ │ └── shadow.png │ │ ├── 128 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ ├── icon-mask.png │ │ │ ├── mask.png │ │ │ └── shadow.png │ │ ├── 256 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ ├── icon-mask.png │ │ │ ├── mask.png │ │ │ └── shadow.png │ │ └── 512 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ ├── icon-mask.png │ │ │ ├── mask.png │ │ │ └── shadow.png │ ├── win11-box │ │ ├── 16 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ └── mask.png │ │ ├── 24 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ └── mask.png │ │ └── 32 │ │ │ ├── base.png │ │ │ ├── default.png │ │ │ ├── highlight.png │ │ │ └── mask.png │ └── win11 │ │ ├── 16 │ │ ├── base.png │ │ ├── default.png │ │ ├── highlight.png │ │ └── mask.png │ │ ├── 24 │ │ ├── base.png │ │ ├── default.png │ │ ├── highlight.png │ │ └── mask.png │ │ ├── 32 │ │ ├── base.png │ │ ├── default.png │ │ ├── highlight.png │ │ └── mask.png │ │ ├── 48 │ │ ├── base.png │ │ ├── default.png │ │ ├── highlight.png │ │ └── mask.png │ │ ├── 64 │ │ ├── base.png │ │ ├── default.png │ │ ├── highlight.png │ │ └── mask.png │ │ ├── 72 │ │ ├── base.png │ │ ├── default.png │ │ ├── highlight.png │ │ └── mask.png │ │ ├── 96 │ │ ├── base.png │ │ ├── default.png │ │ ├── highlight.png │ │ └── mask.png │ │ ├── 128 │ │ ├── base.png │ │ ├── default.png │ │ ├── highlight.png │ │ └── mask.png │ │ ├── 256 │ │ ├── base.png │ │ ├── default.png │ │ ├── highlight.png │ │ └── mask.png │ │ └── 512 │ │ ├── base.png │ │ ├── default.png │ │ ├── highlight.png │ │ └── mask.png ├── fonts │ ├── inter.woff2 │ ├── noto.woff2 │ └── syne.woff2 └── meta │ └── banner.png └── src ├── app ├── [locale] │ ├── layout.jsx │ └── page.jsx ├── api │ └── downloads │ │ └── route.jsx ├── robots.jsx └── sitemap.jsx ├── components ├── control-panels │ ├── folder-color.jsx │ ├── folder-icon.jsx │ ├── folder-small.jsx │ └── folder-style.jsx ├── credits.jsx ├── download-count.jsx ├── firefox.jsx ├── folder │ ├── folder-icon-preview.jsx │ └── folder-render.jsx ├── footer.jsx ├── header-buttons.jsx ├── header.jsx ├── inputs │ ├── checkbox.jsx │ ├── color.jsx │ ├── download.jsx │ ├── dropdown.jsx │ ├── folder-color-input.jsx │ ├── header-button.jsx │ ├── img-radio.jsx │ ├── locale-switcher-select.jsx │ ├── locale-switcher.jsx │ ├── offset-input.jsx │ ├── radio.jsx │ ├── range.jsx │ └── slug-input.jsx ├── logo.jsx ├── modal.jsx ├── theme-init.jsx └── view.jsx ├── credits.json ├── functions ├── fetch-browser-type.jsx ├── fetch-custom.jsx ├── fetch-lucide.jsx ├── fetch-simple.jsx ├── folder-generate.jsx ├── set-primary.jsx ├── theme-set.jsx └── theme-swap.jsx ├── i18n ├── navigation.jsx ├── request.jsx └── routing.jsx ├── lib └── supabase.jsx ├── locales ├── de.json ├── en.json ├── es.json └── pl.json ├── middleware.jsx ├── stores └── folder-config.jsx └── styles ├── credits.css ├── folder.css ├── footer.css ├── globals.css ├── header.css ├── inputs ├── checkbox.css ├── color.css ├── dropdown.css ├── header-button.css ├── img-radio.css ├── radio.css ├── range.css └── slug-input.css ├── modal.css └── view.css /.github/images/back-to-top.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/.github/images/logo.png -------------------------------------------------------------------------------- /.github/images/sep.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/.github/images/sep.png -------------------------------------------------------------------------------- /.github/images/showcase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/.github/images/showcase.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Node.js 2 | node_modules/ 3 | npm-debug.log* 4 | yarn-debug.log* 5 | yarn-error.log* 6 | 7 | # Next.js 8 | .next/ 9 | out/ 10 | *.log 11 | 12 | # macOS 13 | .DS_Store 14 | __MACOSX/ 15 | 16 | # Windows 17 | desktop.ini 18 | 19 | # IDEs and Editors 20 | .vscode/ 21 | .idea/ 22 | *.suo 23 | *.ntvs* 24 | *.njsproj 25 | *.sln 26 | *.sw? 27 | 28 | # Env variables 29 | .env 30 | .env.local -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

A Free, Open-Source Folder Customization Tool

4 |

Currently live at www.flaredfolders.com

5 | 6 |

7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |

16 | 17 | 18 | 19 | ## ✨ Features 20 | 21 | ### 🌍 Supported Styles 22 | 23 | - Windows 11 24 | - Windows 10 25 | - macOS Big Sur 26 | - Linux Mint L 27 | 28 | ### 🎚️ Customization Options 29 | 30 | - **Backgrounds**: 31 | - Gradient blends 32 | - Solid colors 33 | - Original folder color 34 | - **Icon Libraries**: 35 | - Generic icons via [Lucide](https://lucide.dev) 36 | - Brand icons via [Simple Icons](https://simpleicons.org/) 37 | - Custom icon upload 38 | - **Resolution Support**: 39 | `16x16 → 1024x1024` (Native scaling for all platforms) 40 | 41 | ### 📤 Export Formats 42 | 43 | | Format | Platform Support | 44 | | ------- | ---------------- | 45 | | `.ico` | Windows & Linux | 46 | | `.icns` | macOS | 47 | | `.png` | Cross-platform | 48 | 49 |
50 | 51 | ## 🚀 Quick Start 52 | 53 | 1. Clone the repository: 54 | 55 | ```bash 56 | git clone https://github.com/EthanHazel/flaredfolders.git 57 | ``` 58 | 59 | 2. Install dependencies: 60 | 61 | ```bash 62 | npm install 63 | ``` 64 | 65 | 3. Start development server: 66 | 67 | ```bash 68 | npm run dev 69 | ``` 70 | 71 |
72 | 73 | ## 🌐 Community Translations 74 | 75 | Help us make Flared Folders more accessible! Here's how to contribute translations: 76 | 77 | 1. Navigate to `src/locales` 78 | 2. Duplicate `en.json` 79 | 3. Rename to your [locale code](https://www.localeplanet.com/icu/) 80 | 4. Translate all string values 81 | 5. Submit a PR! 82 | 83 |
84 | 85 | ## 🤝 Contributing 86 | 87 | We welcome all contributions! Please: 88 | 89 | 1. Fork the repository 90 | 2. Create your feature branch 91 | 92 | - `git checkout -b feature/amazing-feature` 93 | 94 | 3. Commit your changes 95 | 96 | - `git commit -m 'Add some amazing feature'` 97 | 98 | 4. Push to the branch 99 | 100 | - `git push origin feature/amazing-feature` 101 | 102 | 5. Open a Pull Request 103 | 104 |
105 | 106 | ## 📄 License 107 | 108 | This project is licensed under the **GNU General Public License v3.0** - see the [LICENSE](https://www.gnu.org/licenses/gpl-3.0.en.html) file for details. 109 | 110 |
111 | 112 | ## 🙏 Acknowledgments 113 | 114 | - Icon sets provided by [Lucide](https://lucide.dev) and [Simple Icons](https://simpleicons.org/) 115 | - Built with [Next.js](https://nextjs.org/) 116 | - Community-driven translations 117 | 118 | --- 119 | 120 |

121 | 122 | 123 | 124 |

125 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { dirname } from "path"; 2 | import { fileURLToPath } from "url"; 3 | import { FlatCompat } from "@eslint/eslintrc"; 4 | 5 | const __filename = fileURLToPath(import.meta.url); 6 | const __dirname = dirname(__filename); 7 | 8 | const compat = new FlatCompat({ 9 | baseDirectory: __dirname, 10 | }); 11 | 12 | const eslintConfig = [...compat.extends("next/core-web-vitals")]; 13 | 14 | export default eslintConfig; 15 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "@/*": ["./src/*"] 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | import createNextIntlPlugin from "next-intl/plugin"; 2 | 3 | const withNextIntl = createNextIntlPlugin(); 4 | 5 | /** @type {import('next').NextConfig} */ 6 | const nextConfig = {}; 7 | 8 | export default withNextIntl(nextConfig); 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flared-folders", 3 | "version": "2.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev --turbopack", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@supabase/ssr": "^0.6.1", 13 | "@supabase/supabase-js": "^2.49.8", 14 | "@vercel/analytics": "^1.5.0", 15 | "dotenv": "^16.5.0", 16 | "fs": "^0.0.1-security", 17 | "jszip": "^3.10.1", 18 | "lucide-react": "^0.501.0", 19 | "next": "15.3.1", 20 | "next-intl": "^4.1.0", 21 | "react": "^19.0.0", 22 | "react-dom": "^19.0.0", 23 | "simple-icons": "^14.12.3", 24 | "zustand": "^5.0.3" 25 | }, 26 | "devDependencies": { 27 | "@eslint/eslintrc": "^3", 28 | "eslint": "^9", 29 | "eslint-config-next": "15.3.1" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /public/favicon/192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/favicon/192.png -------------------------------------------------------------------------------- /public/favicon/512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/favicon/512.png -------------------------------------------------------------------------------- /public/favicon/96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/favicon/96.png -------------------------------------------------------------------------------- /public/favicon/apple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/favicon/apple.png -------------------------------------------------------------------------------- /public/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/favicon/favicon.ico -------------------------------------------------------------------------------- /public/favicon/favicon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/favicon/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Flared Folders", 3 | "short_name": "Flared", 4 | "icons": [ 5 | { 6 | "src": "/favicon/192.png", 7 | "sizes": "192x192", 8 | "type": "image/png", 9 | "purpose": "maskable" 10 | }, 11 | { 12 | "src": "/favicon/512.png", 13 | "sizes": "512x512", 14 | "type": "image/png", 15 | "purpose": "maskable" 16 | } 17 | ], 18 | "theme_color": "#ffffff", 19 | "background_color": "#ffffff", 20 | "display": "standalone" 21 | } 22 | -------------------------------------------------------------------------------- /public/folder-assets/bigsur/1024/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/1024/base.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/1024/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/1024/default.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/1024/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/1024/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/1024/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/1024/mask.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/1024/shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/1024/shadow.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/128/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/128/base.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/128/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/128/default.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/128/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/128/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/128/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/128/mask.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/128/shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/128/shadow.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/16/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/16/base.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/16/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/16/default.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/16/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/16/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/16/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/16/mask.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/16/shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/16/shadow.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/256/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/256/base.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/256/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/256/default.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/256/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/256/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/256/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/256/mask.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/256/shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/256/shadow.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/32/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/32/base.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/32/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/32/default.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/32/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/32/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/32/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/32/mask.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/32/shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/32/shadow.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/512/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/512/base.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/512/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/512/default.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/512/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/512/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/512/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/512/mask.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/512/shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/512/shadow.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/64/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/64/base.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/64/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/64/default.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/64/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/64/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/64/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/64/mask.png -------------------------------------------------------------------------------- /public/folder-assets/bigsur/64/shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/bigsur/64/shadow.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/128/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/128/base.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/128/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/128/default.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/128/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/128/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/128/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/128/mask.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/16/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/16/base.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/16/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/16/default.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/16/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/16/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/16/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/16/mask.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/24/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/24/base.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/24/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/24/default.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/24/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/24/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/24/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/24/mask.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/256/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/256/base.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/256/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/256/default.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/256/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/256/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/256/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/256/mask.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/32/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/32/base.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/32/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/32/default.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/32/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/32/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/32/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/32/mask.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/48/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/48/base.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/48/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/48/default.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/48/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/48/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/48/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/48/mask.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/512/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/512/base.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/512/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/512/default.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/512/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/512/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/512/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/512/mask.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/64/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/64/base.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/64/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/64/default.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/64/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/64/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/64/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/64/mask.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/96/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/96/base.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/96/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/96/default.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/96/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/96/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/mint-l/96/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/mint-l/96/mask.png -------------------------------------------------------------------------------- /public/folder-assets/previews/bigsur.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/previews/bigsur.png -------------------------------------------------------------------------------- /public/folder-assets/previews/icon-only.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/previews/icon-only.png -------------------------------------------------------------------------------- /public/folder-assets/previews/mint-l.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/previews/mint-l.png -------------------------------------------------------------------------------- /public/folder-assets/previews/win10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/previews/win10.png -------------------------------------------------------------------------------- /public/folder-assets/previews/win11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/previews/win11.png -------------------------------------------------------------------------------- /public/folder-assets/temp-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/folder-assets/win10/128/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/128/base.png -------------------------------------------------------------------------------- /public/folder-assets/win10/128/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/128/default.png -------------------------------------------------------------------------------- /public/folder-assets/win10/128/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/128/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/win10/128/icon-mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/128/icon-mask.png -------------------------------------------------------------------------------- /public/folder-assets/win10/128/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/128/mask.png -------------------------------------------------------------------------------- /public/folder-assets/win10/128/shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/128/shadow.png -------------------------------------------------------------------------------- /public/folder-assets/win10/16/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/16/base.png -------------------------------------------------------------------------------- /public/folder-assets/win10/16/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/16/default.png -------------------------------------------------------------------------------- /public/folder-assets/win10/16/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/16/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/win10/16/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/16/mask.png -------------------------------------------------------------------------------- /public/folder-assets/win10/24/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/24/base.png -------------------------------------------------------------------------------- /public/folder-assets/win10/24/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/24/default.png -------------------------------------------------------------------------------- /public/folder-assets/win10/24/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/24/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/win10/24/icon-mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/24/icon-mask.png -------------------------------------------------------------------------------- /public/folder-assets/win10/24/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/24/mask.png -------------------------------------------------------------------------------- /public/folder-assets/win10/256/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/256/base.png -------------------------------------------------------------------------------- /public/folder-assets/win10/256/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/256/default.png -------------------------------------------------------------------------------- /public/folder-assets/win10/256/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/256/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/win10/256/icon-mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/256/icon-mask.png -------------------------------------------------------------------------------- /public/folder-assets/win10/256/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/256/mask.png -------------------------------------------------------------------------------- /public/folder-assets/win10/256/shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/256/shadow.png -------------------------------------------------------------------------------- /public/folder-assets/win10/32/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/32/base.png -------------------------------------------------------------------------------- /public/folder-assets/win10/32/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/32/default.png -------------------------------------------------------------------------------- /public/folder-assets/win10/32/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/32/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/win10/32/icon-mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/32/icon-mask.png -------------------------------------------------------------------------------- /public/folder-assets/win10/32/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/32/mask.png -------------------------------------------------------------------------------- /public/folder-assets/win10/32/shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/32/shadow.png -------------------------------------------------------------------------------- /public/folder-assets/win10/48/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/48/base.png -------------------------------------------------------------------------------- /public/folder-assets/win10/48/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/48/default.png -------------------------------------------------------------------------------- /public/folder-assets/win10/48/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/48/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/win10/48/icon-mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/48/icon-mask.png -------------------------------------------------------------------------------- /public/folder-assets/win10/48/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/48/mask.png -------------------------------------------------------------------------------- /public/folder-assets/win10/48/shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/48/shadow.png -------------------------------------------------------------------------------- /public/folder-assets/win10/512/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/512/base.png -------------------------------------------------------------------------------- /public/folder-assets/win10/512/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/512/default.png -------------------------------------------------------------------------------- /public/folder-assets/win10/512/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/512/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/win10/512/icon-mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/512/icon-mask.png -------------------------------------------------------------------------------- /public/folder-assets/win10/512/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/512/mask.png -------------------------------------------------------------------------------- /public/folder-assets/win10/512/shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/512/shadow.png -------------------------------------------------------------------------------- /public/folder-assets/win10/64/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/64/base.png -------------------------------------------------------------------------------- /public/folder-assets/win10/64/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/64/default.png -------------------------------------------------------------------------------- /public/folder-assets/win10/64/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/64/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/win10/64/icon-mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/64/icon-mask.png -------------------------------------------------------------------------------- /public/folder-assets/win10/64/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/64/mask.png -------------------------------------------------------------------------------- /public/folder-assets/win10/64/shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/64/shadow.png -------------------------------------------------------------------------------- /public/folder-assets/win10/72/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/72/base.png -------------------------------------------------------------------------------- /public/folder-assets/win10/72/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/72/default.png -------------------------------------------------------------------------------- /public/folder-assets/win10/72/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/72/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/win10/72/icon-mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/72/icon-mask.png -------------------------------------------------------------------------------- /public/folder-assets/win10/72/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/72/mask.png -------------------------------------------------------------------------------- /public/folder-assets/win10/72/shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/72/shadow.png -------------------------------------------------------------------------------- /public/folder-assets/win10/96/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/96/base.png -------------------------------------------------------------------------------- /public/folder-assets/win10/96/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/96/default.png -------------------------------------------------------------------------------- /public/folder-assets/win10/96/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/96/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/win10/96/icon-mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/96/icon-mask.png -------------------------------------------------------------------------------- /public/folder-assets/win10/96/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/96/mask.png -------------------------------------------------------------------------------- /public/folder-assets/win10/96/shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win10/96/shadow.png -------------------------------------------------------------------------------- /public/folder-assets/win11-box/16/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11-box/16/base.png -------------------------------------------------------------------------------- /public/folder-assets/win11-box/16/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11-box/16/default.png -------------------------------------------------------------------------------- /public/folder-assets/win11-box/16/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11-box/16/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/win11-box/16/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11-box/16/mask.png -------------------------------------------------------------------------------- /public/folder-assets/win11-box/24/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11-box/24/base.png -------------------------------------------------------------------------------- /public/folder-assets/win11-box/24/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11-box/24/default.png -------------------------------------------------------------------------------- /public/folder-assets/win11-box/24/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11-box/24/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/win11-box/24/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11-box/24/mask.png -------------------------------------------------------------------------------- /public/folder-assets/win11-box/32/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11-box/32/base.png -------------------------------------------------------------------------------- /public/folder-assets/win11-box/32/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11-box/32/default.png -------------------------------------------------------------------------------- /public/folder-assets/win11-box/32/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11-box/32/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/win11-box/32/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11-box/32/mask.png -------------------------------------------------------------------------------- /public/folder-assets/win11/128/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/128/base.png -------------------------------------------------------------------------------- /public/folder-assets/win11/128/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/128/default.png -------------------------------------------------------------------------------- /public/folder-assets/win11/128/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/128/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/win11/128/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/128/mask.png -------------------------------------------------------------------------------- /public/folder-assets/win11/16/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/16/base.png -------------------------------------------------------------------------------- /public/folder-assets/win11/16/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/16/default.png -------------------------------------------------------------------------------- /public/folder-assets/win11/16/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/16/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/win11/16/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/16/mask.png -------------------------------------------------------------------------------- /public/folder-assets/win11/24/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/24/base.png -------------------------------------------------------------------------------- /public/folder-assets/win11/24/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/24/default.png -------------------------------------------------------------------------------- /public/folder-assets/win11/24/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/24/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/win11/24/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/24/mask.png -------------------------------------------------------------------------------- /public/folder-assets/win11/256/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/256/base.png -------------------------------------------------------------------------------- /public/folder-assets/win11/256/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/256/default.png -------------------------------------------------------------------------------- /public/folder-assets/win11/256/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/256/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/win11/256/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/256/mask.png -------------------------------------------------------------------------------- /public/folder-assets/win11/32/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/32/base.png -------------------------------------------------------------------------------- /public/folder-assets/win11/32/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/32/default.png -------------------------------------------------------------------------------- /public/folder-assets/win11/32/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/32/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/win11/32/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/32/mask.png -------------------------------------------------------------------------------- /public/folder-assets/win11/48/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/48/base.png -------------------------------------------------------------------------------- /public/folder-assets/win11/48/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/48/default.png -------------------------------------------------------------------------------- /public/folder-assets/win11/48/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/48/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/win11/48/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/48/mask.png -------------------------------------------------------------------------------- /public/folder-assets/win11/512/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/512/base.png -------------------------------------------------------------------------------- /public/folder-assets/win11/512/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/512/default.png -------------------------------------------------------------------------------- /public/folder-assets/win11/512/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/512/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/win11/512/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/512/mask.png -------------------------------------------------------------------------------- /public/folder-assets/win11/64/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/64/base.png -------------------------------------------------------------------------------- /public/folder-assets/win11/64/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/64/default.png -------------------------------------------------------------------------------- /public/folder-assets/win11/64/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/64/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/win11/64/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/64/mask.png -------------------------------------------------------------------------------- /public/folder-assets/win11/72/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/72/base.png -------------------------------------------------------------------------------- /public/folder-assets/win11/72/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/72/default.png -------------------------------------------------------------------------------- /public/folder-assets/win11/72/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/72/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/win11/72/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/72/mask.png -------------------------------------------------------------------------------- /public/folder-assets/win11/96/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/96/base.png -------------------------------------------------------------------------------- /public/folder-assets/win11/96/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/96/default.png -------------------------------------------------------------------------------- /public/folder-assets/win11/96/highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/96/highlight.png -------------------------------------------------------------------------------- /public/folder-assets/win11/96/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/folder-assets/win11/96/mask.png -------------------------------------------------------------------------------- /public/fonts/inter.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/fonts/inter.woff2 -------------------------------------------------------------------------------- /public/fonts/noto.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/fonts/noto.woff2 -------------------------------------------------------------------------------- /public/fonts/syne.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/fonts/syne.woff2 -------------------------------------------------------------------------------- /public/meta/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthanHazel/flaredfolders/ab41be81fc28ca402adf1597f3857aed6752ac4b/public/meta/banner.png -------------------------------------------------------------------------------- /src/app/[locale]/layout.jsx: -------------------------------------------------------------------------------- 1 | import ThemeInitializer from "@/components/theme-init"; 2 | import { cookies } from "next/headers"; 3 | import { NextIntlClientProvider } from "next-intl"; 4 | import { routing } from "@/i18n/routing"; 5 | import { hasLocale } from "next-intl"; 6 | import { Analytics } from "@vercel/analytics/react"; 7 | import { redirect } from "next/navigation"; 8 | 9 | const description = 10 | "Generate custom folder designs for your favorite operating system. Free, open source, and no ads. Import your own icons, use Simple Icons, or use Lucide icons."; 11 | 12 | const title = "Flared Folders"; 13 | const url = "https://www.flaredfolders.com/"; 14 | 15 | const getLocales = () => { 16 | const context = require.context("../../locales", false, /\.json$/); 17 | const locales = context 18 | .keys() 19 | .map((key) => key.replace("./", "").replace(".json", "")); 20 | return locales; 21 | }; 22 | 23 | export const viewport = { 24 | width: "device-width", 25 | initialScale: 1, 26 | maximumScale: 1, 27 | userScalable: "no", 28 | themeColor: [ 29 | { media: "(prefers-color-scheme: light)", color: "white" }, 30 | { media: "(prefers-color-scheme: dark)", color: "black" }, 31 | ], 32 | }; 33 | 34 | export const metadata = { 35 | metadataBase: new URL(url), 36 | alternates: { 37 | canonical: "/", 38 | languages: { 39 | ...getLocales().reduce((obj, locale) => { 40 | obj[locale] = `/${locale}`; 41 | return obj; 42 | }, {}), 43 | }, 44 | }, 45 | title, 46 | description, 47 | links: [{ rel: "manifest", href: "../favicon/site.webmanifest" }], 48 | icons: { 49 | icon: "/favicon/favicon.svg", 50 | apple: "/favicon/apple.png", 51 | shortcut: "/favicon/favicon.ico", 52 | }, 53 | openGraph: { 54 | title, 55 | description, 56 | images: [ 57 | { 58 | url: "/meta/banner.png", 59 | alt: "Flared Folders Banner", 60 | width: 1200, 61 | height: 628, 62 | }, 63 | ], 64 | type: "website", 65 | authors: ["Ethan Hazel"], 66 | }, 67 | twitter: { 68 | card: "summary_large_image", 69 | title, 70 | creator: "@EthanHazelGD", 71 | description, 72 | images: [ 73 | { 74 | url: "/meta/banner.png", 75 | alt: "Flared Folders Banner", 76 | width: 1200, 77 | height: 628, 78 | }, 79 | ], 80 | app: { 81 | name: "flared_folders", 82 | url, 83 | }, 84 | }, 85 | appleMobileWebAppTitle: title, 86 | url, 87 | category: "technology", 88 | robots: { 89 | index: true, 90 | follow: true, 91 | nocache: false, 92 | googleBot: { 93 | index: true, 94 | follow: true, 95 | noimageindex: false, 96 | "max-image-preview": "large", 97 | "max-snippet": -1, 98 | }, 99 | }, 100 | }; 101 | 102 | export default async function RootLayout({ children, params }) { 103 | const { locale } = await params; 104 | if (!hasLocale(routing.locales, locale)) { 105 | return redirect(`/en`); 106 | } 107 | 108 | const cookiesInstance = await cookies(); 109 | const themeCookie = cookiesInstance.get("theme"); 110 | const theme = themeCookie?.value; 111 | 112 | return ( 113 | 114 | 115 | 116 | 117 | {children} 118 | 119 | 120 | ); 121 | } 122 | -------------------------------------------------------------------------------- /src/app/[locale]/page.jsx: -------------------------------------------------------------------------------- 1 | import Header from "@/components/header"; 2 | import Footer from "@/components/footer"; 3 | import ViewLayout from "@/components/view"; 4 | 5 | import FolderColor from "@/components/control-panels/folder-color"; 6 | import FolderStyle from "@/components/control-panels/folder-style"; 7 | import FolderIcon from "@/components/control-panels/folder-icon"; 8 | import FolderRender from "@/components/folder/folder-render"; 9 | 10 | export default function Home() { 11 | return ( 12 | <> 13 |
14 |
15 |
16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 |
24 | 25 | {[128, 96, 72].map((size) => ( 26 | 27 | ))} 28 |
29 |
30 | 31 | 32 | {[32, 24, 16].map((size) => ( 33 | 34 | ))} 35 |
36 |
37 |
38 |
39 | 40 | 41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /src/app/api/downloads/route.jsx: -------------------------------------------------------------------------------- 1 | import { NextResponse } from "next/server"; 2 | import { createSupabaseServerClient } from "@/lib/supabase"; 3 | 4 | export async function POST() { 5 | const supabase = createSupabaseServerClient(); 6 | 7 | try { 8 | const { data, error } = await supabase.rpc("increment_downloads"); 9 | 10 | if (error) { 11 | console.error("Supabase error:", error); 12 | return NextResponse.json( 13 | { error: "Database operation failed" }, 14 | { status: 500 } 15 | ); 16 | } 17 | 18 | return NextResponse.json({ count: data }); 19 | } catch (error) { 20 | console.error("Server error:", error); 21 | return NextResponse.json( 22 | { error: "Internal server error" }, 23 | { status: 500 } 24 | ); 25 | } 26 | } 27 | 28 | export async function GET() { 29 | const supabase = createSupabaseServerClient(); 30 | 31 | try { 32 | const { data, error } = await supabase 33 | .from("downloads") 34 | .select("count") 35 | .single(); 36 | 37 | if (error) throw error; 38 | 39 | return NextResponse.json({ count: data.count }); 40 | } catch (error) { 41 | console.error("Fetch error:", error); 42 | return NextResponse.json( 43 | { error: "Failed to retrieve download count" }, 44 | { status: 500 } 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/app/robots.jsx: -------------------------------------------------------------------------------- 1 | export default function robots() { 2 | return { 3 | rules: { 4 | userAgent: "*", 5 | allow: "/", 6 | }, 7 | sitemap: "https://www.flaredfolders.com/sitemap.xml", 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /src/app/sitemap.jsx: -------------------------------------------------------------------------------- 1 | export default function sitemap() { 2 | return [ 3 | { 4 | url: "https://www.flaredfolders.com/", 5 | lastModified: new Date(), 6 | changeFrequency: "yearly", 7 | priority: 1, 8 | }, 9 | ]; 10 | } 11 | -------------------------------------------------------------------------------- /src/components/control-panels/folder-color.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import Dropdown from "@/components/inputs/dropdown"; 4 | import Radio from "@/components/inputs/radio"; 5 | import FolderColorInput from "@/components/inputs/folder-color-input"; 6 | 7 | import { useTranslations } from "next-intl"; 8 | import { folderConfigStore } from "@/stores/folder-config"; 9 | import { setPrimary } from "@/functions/set-primary"; 10 | 11 | export default function FolderColor() { 12 | const colorType = folderConfigStore((state) => state.colorType); 13 | const folderType = folderConfigStore((state) => state.folderType); 14 | 15 | const changeType = (newType) => () => { 16 | folderConfigStore.getState().setColorType(newType); 17 | if (newType === "linear-gradient") { 18 | setPrimary([ 19 | folderConfigStore.getState().gradientStartColor, 20 | folderConfigStore.getState().gradientEndColor, 21 | ]); 22 | } else if (newType === "solid") { 23 | setPrimary([ 24 | folderConfigStore.getState().solidColor, 25 | folderConfigStore.getState().solidColor, 26 | ]); 27 | } else { 28 | if (folderType === "win11" || folderType === "win10") 29 | setPrimary(["#fee394", "#dfa52e"]); 30 | else if (folderType === "bigsur") setPrimary(["#82d0f8", "#0089cf"]); 31 | else setPrimary(["#8bb158", "#8bb158"]); 32 | } 33 | }; 34 | 35 | const t = useTranslations("panelTitles"); 36 | const tc = useTranslations("folderConfig"); 37 | 38 | if (folderType === "icon-only") return null; 39 | return ( 40 | 41 |
42 | 49 | 56 | 63 |
64 | {colorType === "linear-gradient" && ( 65 | <> 66 | 67 | 68 | 69 | )} 70 | {colorType === "solid" && ( 71 |
72 | 73 |
74 | )} 75 |
76 | ); 77 | } 78 | -------------------------------------------------------------------------------- /src/components/control-panels/folder-icon.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import Dropdown from "../inputs/dropdown"; 4 | import Checkbox from "../inputs/checkbox"; 5 | import Radio from "../inputs/radio"; 6 | import Color from "../inputs/color"; 7 | import Range from "../inputs/range"; 8 | import SlugInput from "../inputs/slug-input"; 9 | import OffsetInput from "../inputs/offset-input"; 10 | 11 | import { folderConfigStore } from "@/stores/folder-config"; 12 | import { useTranslations } from "next-intl"; 13 | import { loadCustom } from "@/functions/fetch-custom"; 14 | import { useEffect } from "react"; 15 | 16 | export default function FolderIcon() { 17 | const folderType = folderConfigStore((state) => state.folderType); 18 | const iconType = folderConfigStore((state) => state.iconType || "none"); // Ensure defined value 19 | const iconColor = folderConfigStore((state) => state.iconColor); 20 | const setIconType = folderConfigStore((state) => state.setIconType); 21 | const setIconColor = folderConfigStore((state) => state.setIconColor); 22 | const setIconOpacity = folderConfigStore((state) => state.setIconOpacity); 23 | const iconShadow = folderConfigStore((state) => state.iconShadow || false); // Ensure defined value 24 | const setIconShadow = folderConfigStore((state) => state.setIconShadow); 25 | const iconMasked = folderConfigStore((state) => state.iconMasked || false); // Ensure defined value 26 | const setIconMasked = folderConfigStore((state) => state.setIconMasked); 27 | const setLucideStrokeWidth = folderConfigStore( 28 | (state) => state.setLucideStrokeWidth 29 | ); 30 | 31 | useEffect(() => { 32 | if (folderType === "icon-only" && iconType === "none") { 33 | setIconType("lucide"); 34 | } 35 | }, [folderType, iconType, setIconType]); 36 | 37 | const types = 38 | folderType === "icon-only" 39 | ? ["lucide", "simple", "custom"] 40 | : ["lucide", "simple", "custom", "none"]; 41 | 42 | const t = useTranslations("panelTitles"); 43 | const tc = useTranslations("iconTypes"); 44 | const tcc = useTranslations("iconConfig"); 45 | 46 | return ( 47 | 48 |
49 | {types.map((type) => ( 50 | setIconType(type)} 55 | checked={type === iconType} 56 | key={type} 57 | label={tc(type)} 58 | /> 59 | ))} 60 |
61 | {iconType !== "none" && ( 62 | 63 | {iconType !== "custom" && } 64 |
65 | loadCustom()} 70 | accept="image/png, image/jpeg, image/webp, image/svg+xml, image/gif, image/bmp" 71 | /> 72 |
73 | {iconType === "lucide" && ( 74 | setLucideStrokeWidth(e.target.value)} 79 | defaultValue="1.5" 80 | min="0.1" 81 | max="3" 82 | step="0.1" 83 | /> 84 | )} 85 | {iconType !== "none" && ( 86 | setIconOpacity(e.target.value)} 91 | defaultValue="1" 92 | min="0" 93 | max="1" 94 | step="0.01" 95 | /> 96 | )} 97 | {iconType !== "none" && iconType !== "custom" && ( 98 | <> 99 |
100 | setIconColor(e.target.value)} 103 | label={tcc("color")} 104 | /> 105 | 106 | )} 107 |
108 | )} 109 | {iconType !== "none" && ( 110 | <> 111 | 112 | 113 | setIconShadow(!iconShadow)} 118 | checked={iconShadow} 119 | /> 120 | setIconMasked(!iconMasked)} 125 | checked={iconMasked} 126 | /> 127 | 128 | 129 | )} 130 |
131 | ); 132 | } 133 | -------------------------------------------------------------------------------- /src/components/control-panels/folder-small.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useEffect } from "react"; 4 | import Dropdown from "../inputs/dropdown"; 5 | import Radio from "../inputs/radio"; 6 | import { folderConfigStore } from "@/stores/folder-config"; 7 | import { useTranslations } from "next-intl"; 8 | 9 | export default function FolderSmall() { 10 | const folderType = folderConfigStore((state) => state.folderType); 11 | 12 | const folderSmallType = folderConfigStore((state) => state.folderSmallType); 13 | const setFolderSmallType = folderConfigStore( 14 | (state) => state.setFolderSmallType 15 | ); 16 | 17 | useEffect(() => { 18 | if (folderType === "win11") { 19 | setFolderSmallType("squareAndIcon"); 20 | } 21 | }, []); // Ducktape hack to fix a bug I'm not sure how to fix cause I can't find the origin. 22 | 23 | const t = useTranslations("panelTitles"); 24 | const tc = useTranslations("smallFolderConfig"); 25 | 26 | if (folderType !== "icon-only") 27 | return ( 28 | 29 |
30 | {folderType === "win11" && ( 31 | setFolderSmallType("squareAndIcon")} 35 | label={tc("squareAndIcon")} 36 | defaultChecked 37 | /> 38 | )} 39 | setFolderSmallType("folderAndIcon")} 43 | label={tc("folderAndIcon")} 44 | checked={folderSmallType === "folderAndIcon"} 45 | /> 46 | setFolderSmallType("iconOnly")} 50 | label={tc("iconOnly")} 51 | checked={folderSmallType === "iconOnly"} 52 | /> 53 | setFolderSmallType("folderOnly")} 57 | label={tc("folderOnly")} 58 | checked={folderSmallType === "folderOnly"} 59 | /> 60 |
61 |
62 | ); 63 | } 64 | -------------------------------------------------------------------------------- /src/components/control-panels/folder-style.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import FolderSmall from "./folder-small"; 4 | import Dropdown from "../inputs/dropdown"; 5 | import ImgRadio from "../inputs/img-radio"; 6 | import { folderConfigStore } from "@/stores/folder-config"; 7 | import { useTranslations } from "next-intl"; 8 | import { setPrimary } from "@/functions/set-primary"; 9 | 10 | export default function FolderStyle() { 11 | const folderType = folderConfigStore((state) => state.folderType); 12 | const colorType = folderConfigStore((state) => state.colorType); 13 | const setFolderSmallType = folderConfigStore( 14 | (state) => state.setFolderSmallType 15 | ); 16 | 17 | const changeType = (newType) => () => { 18 | if (colorType === "original") { 19 | if (folderType === "win11" || folderType === "win10") { 20 | setPrimary(["#fee394", "#dfa52e"]); 21 | } else if (folderType === "bigsur") { 22 | setPrimary(["#82d0f8", "#0089cf"]); 23 | } else { 24 | setPrimary(["#8bb158", "#8bb158"]); 25 | } 26 | } 27 | if (folderType === newType) return; 28 | folderConfigStore.getState().setFolderType(newType); 29 | // Immediate update instead of setTimeout 30 | setFolderSmallType(newType === "win11" ? "squareAndIcon" : "folderAndIcon"); 31 | }; 32 | 33 | const t = useTranslations("panelTitles"); 34 | 35 | return ( 36 | 37 |
38 | 46 | 53 | 60 | 67 | 74 |
75 | 76 |
77 | ); 78 | } 79 | -------------------------------------------------------------------------------- /src/components/credits.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import { useTranslations } from "next-intl"; 3 | import Credit from "@/credits.json"; 4 | import "@/styles/credits.css"; 5 | 6 | const getLocales = () => { 7 | const context = require.context("../locales", false, /\.json$/); 8 | return context 9 | .keys() 10 | .map((key) => key.replace("./", "").replace(".json", "")); 11 | }; 12 | 13 | export default function Credits() { 14 | const t = useTranslations("credits"); 15 | const [contributors, setContributors] = useState([]); 16 | const [translations, setTranslations] = useState([]); 17 | const [loading, setLoading] = useState(true); 18 | const [translationsLoading, setTranslationsLoading] = useState(true); 19 | const [error, setError] = useState(null); 20 | const [translationsError, setTranslationsError] = useState(null); 21 | 22 | useEffect(() => { 23 | const fetchContributors = async () => { 24 | try { 25 | let allContributors = []; 26 | let page = 1; 27 | let hasMore = true; 28 | 29 | while (hasMore) { 30 | const response = await fetch( 31 | `https://api.github.com/repos/EthanHazel/flaredfolders/contributors?per_page=100&page=${page}`, 32 | { 33 | headers: { 34 | Accept: "application/vnd.github+json", 35 | "X-GitHub-Api-Version": "2022-11-28", 36 | }, 37 | } 38 | ); 39 | 40 | if (!response.ok) 41 | throw new Error(`HTTP error! status: ${response.status}`); 42 | 43 | const data = await response.json(); 44 | allContributors = [...allContributors, ...data]; 45 | allContributors = allContributors.filter( 46 | (contributor) => contributor.login !== "EthanHazelSchool" 47 | ); 48 | hasMore = data.length === 100; 49 | page++; 50 | } 51 | 52 | setContributors(allContributors); 53 | } catch (err) { 54 | setError(err.message); 55 | } finally { 56 | setLoading(false); 57 | } 58 | }; 59 | 60 | fetchContributors(); 61 | 62 | const fetchTranslations = async () => { 63 | try { 64 | const locales = getLocales(); 65 | const translationsData = await Promise.all( 66 | locales.map((lang) => { 67 | try { 68 | const data = require(`../locales/${lang}.json`); 69 | return { 70 | code: lang, 71 | language: data.language, 72 | author: data.translator, 73 | }; 74 | } catch (err) { 75 | console.error(`Error loading ${lang} locale:`, err); 76 | return null; 77 | } 78 | }) 79 | ); 80 | 81 | const validTranslations = translationsData.filter(Boolean); 82 | setTranslations(validTranslations); 83 | } catch (err) { 84 | setTranslationsError(err.message); 85 | } finally { 86 | setTranslationsLoading(false); 87 | } 88 | }; 89 | 90 | fetchTranslations(); 91 | }, []); 92 | 93 | const translationStart = t("help").split("%")[0]; 94 | const translationEnd = t("help").split("%")[1]; 95 | 96 | return ( 97 | <> 98 |
99 |
{t("created")}
100 |
101 | 106 | {Credit.createdBy[0]} 107 | 108 |
109 |
110 |
111 |
{t("icons")}
112 |
113 | 118 | {Credit.iconsFrom.simple[0]} 119 | 120 | 125 | {Credit.iconsFrom.lucide[0]} 126 | 127 |
128 |
129 |
130 |
{t("fonts")}
131 |
132 | 137 | Syne 138 | 139 | 144 | Inter 145 | 146 |
147 |
148 |
149 |
{t("contributors")}
150 |
151 | {loading &&
Loading contributors...
} 152 | {error &&
Error loading contributors: {error}
} 153 | {!loading && !error && contributors.length > 0 154 | ? contributors.map((contributor) => ( 155 | 165 | )) 166 | : !loading && !error &&
No contributors found
} 167 |
168 |
169 |
170 |
{t("translations")}
171 |
172 | {translationsLoading &&
Loading translators...
} 173 | {translationsError && ( 174 |
175 | {t("error")}: {translationsError} 176 |
177 | )} 178 | {!translationsLoading && 179 | !translationsError && 180 | translations.map((translation) => ( 181 |
182 | 183 | {translation.language} ({translation.code.toUpperCase()}) 184 | 185 | 186 | {translation.author} 187 | 188 |
189 | ))} 190 | 191 | {translationStart} 192 | 196 | {translationEnd} 197 | 198 | 199 |
200 |
201 |
202 |
{t("donators")}
203 |
204 | {Credit.kofi.map((item, index) => ( 205 |
{item}
206 | ))} 207 |
208 |
209 |
210 |
{t("special")}
211 |
212 | {Credit.specialThanks.map((item, index) => ( 213 |
{item}
214 | ))} 215 |
216 |
217 | 218 | ); 219 | } 220 | -------------------------------------------------------------------------------- /src/components/download-count.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useState, useEffect } from "react"; 4 | import { useTranslations } from "next-intl"; 5 | 6 | export default function DownloadCounter() { 7 | const [count, setCount] = useState(null); 8 | const [loading, setLoading] = useState(true); 9 | const t = useTranslations("download"); 10 | 11 | useEffect(() => { 12 | const fetchCount = async () => { 13 | try { 14 | const response = await fetch("/api/downloads"); 15 | 16 | if (!response.ok) { 17 | throw new Error( 18 | `Failed to retrieve download count: ${response.status}` 19 | ); 20 | } 21 | 22 | const { count } = await response.json(); 23 | 24 | setCount(count); 25 | setLoading(false); 26 | } catch (error) { 27 | console.error("Fetch error:", error); 28 | setLoading(false); 29 | } 30 | }; 31 | 32 | if (process.env.NEXT_PUBLIC_SUPABASE_URL) { 33 | fetchCount(); 34 | } else { 35 | setLoading(false); 36 | } 37 | }, []); 38 | 39 | if (loading) return null; 40 | 41 | return ( 42 |
43 | {count?.toLocaleString() || "∞"} {t("counter")} 44 |
45 | ); 46 | } 47 | -------------------------------------------------------------------------------- /src/components/firefox.jsx: -------------------------------------------------------------------------------- 1 | import { useTranslations } from "next-intl"; 2 | import { useState } from "react"; 3 | import { siFirefoxbrowser } from "simple-icons"; 4 | import Modal from "./modal"; 5 | 6 | export default function Firefox() { 7 | const [isModalOpen, setIsModalOpen] = useState(false); 8 | 9 | const t = useTranslations("firefox"); 10 | 11 | return ( 12 | <> 13 | setIsModalOpen(false)} 17 | > 18 | {t("content1")} 19 | {t("content2")} 20 | {t("content3")} 21 | 22 |
setIsModalOpen(true)} 25 | style={{ cursor: "pointer" }} 26 | > 27 | 28 | 29 | 30 | 31 | 32 | {t("title")} 33 |
34 | 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /src/components/folder/folder-icon-preview.jsx: -------------------------------------------------------------------------------- 1 | import { loadLucide } from "@/functions/fetch-lucide"; 2 | import { loadSimple } from "@/functions/fetch-simple"; 3 | import { loadCustom } from "@/functions/fetch-custom"; 4 | import { useEffect, useRef } from "react"; 5 | 6 | export default function FolderIconPreview({ 7 | iconType, 8 | slug, 9 | color = "#000000", 10 | strokeWidth = "2", 11 | customFileName, 12 | }) { 13 | const canvasRef = useRef(null); 14 | 15 | useEffect(() => { 16 | const ctx = canvasRef.current.getContext("2d"); 17 | ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); 18 | if (iconType === "simple") { 19 | loadSimple(slug, color).then((img) => { 20 | ctx.drawImage(img, 0, 0, 48, 48); 21 | }); 22 | } else if (iconType === "lucide") { 23 | loadLucide(slug, color, strokeWidth).then((img) => { 24 | ctx.drawImage(img, 0, 0, 48, 48); 25 | }); 26 | } else if (iconType === "custom") { 27 | loadCustom(customFileName).then((img) => { 28 | ctx.drawImage(img, 0, 0, 48, 48); 29 | }); 30 | } 31 | }, [iconType, slug, color, strokeWidth, customFileName]); 32 | 33 | return ( 34 | 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /src/components/folder/folder-render.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useState, useEffect, useRef } from "react"; 4 | import { getIconAnchor } from "@/stores/folder-config"; 5 | import React from "react"; 6 | 7 | import { loadLucide } from "@/functions/fetch-lucide"; 8 | import { loadSimple } from "@/functions/fetch-simple"; 9 | import { loadCustom } from "@/functions/fetch-custom"; 10 | 11 | import { folderConfigStore } from "@/stores/folder-config"; 12 | 13 | import "@/styles/folder.css"; 14 | 15 | export default function FolderRender({ folderSize, key, id }) { 16 | // Configuration state from store 17 | const { 18 | colorType, 19 | gradientStartColor, 20 | gradientEndColor, 21 | solidColor, 22 | folderType, 23 | folderSmallType, 24 | iconType, 25 | iconScale, 26 | iconColor, 27 | iconOffset, 28 | iconOpacity, 29 | iconShadow, 30 | iconMasked, 31 | lucideSlug, 32 | lucideStrokeWidth, 33 | simpleSlug, 34 | customFileName, 35 | } = useFolderConfigState(); 36 | 37 | const colors = [gradientStartColor, gradientEndColor, solidColor]; 38 | const canvasRef = useRef(null); 39 | const [isLoading, setIsLoading] = useState(true); 40 | 41 | // Precomputed values 42 | const isIconOnly = 43 | folderType === "icon-only" || 44 | (folderSmallType === "iconOnly" && folderSize <= 32); 45 | const type = getFolderType(folderType, folderSmallType, folderSize); 46 | const iconMultiplier = getIconMultiplier( 47 | folderType, 48 | folderSmallType, 49 | folderSize 50 | ); 51 | const iconMask = getIconMaskType(folderType, folderSize); 52 | const iconShadowType = getIconShadowType(folderType, folderSize); 53 | const iconAnchor = 54 | (folderSmallType === "squareAndIcon" || folderSmallType === "iconOnly") && 55 | folderSize <= 32 56 | ? [0, 0] 57 | : getIconAnchor(folderType, folderSize); 58 | 59 | // Main effect for loading and drawing 60 | useEffect(() => { 61 | if (shouldSkipRender(folderType, folderSize)) return; 62 | 63 | const loadAndDraw = async () => { 64 | try { 65 | const images = await loadRequiredImages(); 66 | drawCanvas(images, colors); 67 | setIsLoading(false); 68 | } catch (error) { 69 | console.error("Error loading images:", error); 70 | } 71 | }; 72 | 73 | loadAndDraw(); 74 | }, [colors]); 75 | 76 | // Helper function to get all configuration state 77 | function useFolderConfigState() { 78 | return { 79 | colorType: folderConfigStore((state) => state.colorType), 80 | gradientStartColor: folderConfigStore( 81 | (state) => state.gradientStartColor 82 | ), 83 | gradientEndColor: folderConfigStore((state) => state.gradientEndColor), 84 | solidColor: folderConfigStore((state) => state.solidColor), 85 | folderType: folderConfigStore((state) => state.folderType), 86 | folderSmallType: folderConfigStore((state) => state.folderSmallType), 87 | iconType: folderConfigStore((state) => state.iconType), 88 | iconScale: folderConfigStore((state) => state.iconScale), 89 | iconColor: folderConfigStore((state) => state.iconColor), 90 | iconOffset: folderConfigStore((state) => state.iconOffset), 91 | iconOpacity: folderConfigStore((state) => state.iconOpacity), 92 | iconShadow: folderConfigStore((state) => state.iconShadow), 93 | iconMasked: folderConfigStore((state) => state.iconMasked), 94 | lucideSlug: folderConfigStore((state) => state.lucideSlug), 95 | lucideStrokeWidth: folderConfigStore((state) => state.lucideStrokeWidth), 96 | simpleSlug: folderConfigStore((state) => state.simpleSlug), 97 | customFileName: folderConfigStore((state) => state.customFileName), 98 | }; 99 | } 100 | 101 | // Determine folder type based on size and settings 102 | function getFolderType(folderType, folderSmallType, folderSize) { 103 | if ( 104 | folderSmallType === "squareAndIcon" && 105 | folderSize <= 32 && 106 | folderType === "win11" 107 | ) { 108 | return folderType + "-box"; 109 | } 110 | return folderType; 111 | } 112 | 113 | // Calculate icon multiplier based on folder settings 114 | function getIconMultiplier(folderType, folderSmallType, folderSize) { 115 | if (folderSmallType === "squareAndIcon" && folderSize <= 32) { 116 | return 1.5; 117 | } 118 | if ( 119 | folderType === "icon-only" || 120 | (folderSmallType === "iconOnly" && folderSize <= 32) 121 | ) { 122 | return 1.75; 123 | } 124 | return 1; 125 | } 126 | 127 | // Determine icon mask type 128 | function getIconMaskType(folderType, folderSize) { 129 | if (folderType === "win10" && folderSize !== 16) { 130 | return "icon-mask"; 131 | } 132 | return "mask"; 133 | } 134 | 135 | // Determine icon shadow type 136 | function getIconShadowType(folderType, folderSize) { 137 | if ( 138 | (folderType === "win10" && folderSize > 24) || 139 | folderType === "bigsur" 140 | ) { 141 | return "shadow"; 142 | } 143 | return "base"; 144 | } 145 | 146 | // Check if we should skip rendering for this size 147 | function shouldSkipRender(folderType, folderSize) { 148 | const bigsurSizes = [24, 48, 72, 96]; 149 | const otherSizes = [1024, 72]; 150 | 151 | return ( 152 | (folderType === "bigsur" && bigsurSizes.includes(folderSize)) || 153 | ((folderType === "win11" || 154 | folderType === "win10" || 155 | folderType === "mint-l") && 156 | otherSizes.includes(folderSize)) 157 | ); 158 | } 159 | 160 | // Load required images based on configuration 161 | async function loadRequiredImages() { 162 | const imagePaths = { 163 | base: isIconOnly ? null : `/folder-assets/${type}/${folderSize}/base.png`, 164 | highlight: isIconOnly 165 | ? null 166 | : `/folder-assets/${type}/${folderSize}/highlight.png`, 167 | iconMask: isIconOnly 168 | ? null 169 | : `/folder-assets/${type}/${folderSize}/${iconMask}.png`, 170 | mask: isIconOnly ? null : `/folder-assets/${type}/${folderSize}/mask.png`, 171 | default: isIconOnly 172 | ? null 173 | : `/folder-assets/${type}/${folderSize}/default.png`, 174 | shadow: isIconOnly 175 | ? null 176 | : `/folder-assets/${type}/${folderSize}/${iconShadowType}.png`, 177 | icon: await loadIcon(), 178 | }; 179 | 180 | return { 181 | baseImg: imagePaths.base ? await loadImage(imagePaths.base) : null, 182 | icon: imagePaths.icon, 183 | highlightImg: imagePaths.highlight 184 | ? await loadImage(imagePaths.highlight) 185 | : null, 186 | iconMaskImg: imagePaths.iconMask 187 | ? await loadImage(imagePaths.iconMask) 188 | : null, 189 | maskImg: imagePaths.mask ? await loadImage(imagePaths.mask) : null, 190 | defaultImg: imagePaths.default 191 | ? await loadImage(imagePaths.default) 192 | : null, 193 | shadowImg: imagePaths.shadow ? await loadImage(imagePaths.shadow) : null, 194 | }; 195 | } 196 | 197 | // Load icon based on type 198 | async function loadIcon() { 199 | if (iconType === "simple") { 200 | return await loadSimple(simpleSlug, iconColor); 201 | } 202 | if (iconType === "lucide") { 203 | return await loadLucide(lucideSlug, iconColor, lucideStrokeWidth); 204 | } 205 | if (iconType === "custom") { 206 | return await loadCustom(customFileName); 207 | } 208 | return null; 209 | } 210 | 211 | // Generic image loader 212 | async function loadImage(src) { 213 | return new Promise((resolve, reject) => { 214 | const img = new Image(); 215 | img.crossOrigin = "anonymous"; 216 | img.src = src; 217 | img.onload = () => resolve(img); 218 | img.onerror = reject; 219 | }); 220 | } 221 | 222 | // Main canvas drawing function 223 | function drawCanvas(images, colors) { 224 | const { 225 | baseImg, 226 | icon, 227 | highlightImg, 228 | iconMaskImg, 229 | maskImg, 230 | defaultImg, 231 | shadowImg, 232 | } = images; 233 | const canvas = canvasRef.current; 234 | if (!canvas) return; 235 | 236 | const ctx = canvas.getContext("2d"); 237 | const { width, height } = canvas; 238 | 239 | setupCanvasRendering(ctx); 240 | clearCanvas(ctx, width, height); 241 | 242 | if (shouldDrawBackground()) { 243 | drawBackground( 244 | ctx, 245 | baseImg, 246 | highlightImg, 247 | maskImg, 248 | shadowImg, 249 | colors, 250 | width, 251 | height 252 | ); 253 | } else if (!isIconOnly) { 254 | drawDefaultImage(ctx, defaultImg, width, height); 255 | } 256 | 257 | if (shouldDrawIcon()) { 258 | drawIcon(ctx, icon, iconMaskImg, width, height); 259 | } 260 | } 261 | 262 | // Set up canvas rendering quality 263 | function setupCanvasRendering(ctx) { 264 | ctx.imageSmoothingEnabled = true; 265 | ctx.imageSmoothingQuality = "high"; 266 | } 267 | 268 | // Clear the canvas 269 | function clearCanvas(ctx, width, height) { 270 | ctx.clearRect(0, 0, width, height); 271 | } 272 | 273 | // Determine if we should draw the background 274 | function shouldDrawBackground() { 275 | return !isIconOnly && colorType !== "original"; 276 | } 277 | 278 | // Draw background elements 279 | function drawBackground( 280 | ctx, 281 | baseImg, 282 | highlightImg, 283 | maskImg, 284 | shadowImg, 285 | colors, 286 | width, 287 | height 288 | ) { 289 | ctx.drawImage(baseImg, 0, 0, width, height); 290 | 291 | if (colorType === "solid") { 292 | applySolidColor(ctx, colors[2], width, height); 293 | } else if (colorType === "linear-gradient") { 294 | applyGradientColor(ctx, colors, width, height); 295 | } 296 | 297 | applyMask(ctx, maskImg, width, height); 298 | drawHighlight(ctx, highlightImg, width, height); 299 | drawShadow(ctx, shadowImg, width, height); 300 | } 301 | 302 | // Apply solid color effect 303 | function applySolidColor(ctx, color, width, height) { 304 | ctx.globalCompositeOperation = "multiply"; 305 | ctx.fillStyle = color; 306 | ctx.fillRect(0, 0, width, height); 307 | } 308 | 309 | // Apply gradient color effect 310 | function applyGradientColor(ctx, colors, width, height) { 311 | const gradient = ctx.createLinearGradient(width, height, 0, 0); 312 | gradient.addColorStop(0, colors[1]); 313 | gradient.addColorStop(1, colors[0]); 314 | 315 | ctx.globalCompositeOperation = "multiply"; 316 | ctx.fillStyle = gradient; 317 | ctx.fillRect(0, 0, width, height); 318 | } 319 | 320 | // Apply mask to canvas 321 | function applyMask(ctx, maskImg, width, height) { 322 | ctx.globalCompositeOperation = "destination-in"; 323 | ctx.drawImage(maskImg, 0, 0, width, height); 324 | } 325 | 326 | // Draw highlight effect 327 | function drawHighlight(ctx, highlightImg, width, height) { 328 | ctx.globalCompositeOperation = "lighter"; 329 | ctx.drawImage(highlightImg, 0, 0, width, height); 330 | } 331 | 332 | // Draw shadow effect 333 | function drawShadow(ctx, shadowImg, width, height) { 334 | if ( 335 | (folderType === "win10" && folderSize > 24) || 336 | folderType === "bigsur" 337 | ) { 338 | ctx.globalCompositeOperation = "darken"; 339 | ctx.drawImage(shadowImg, 0, 0, width, height); 340 | } 341 | } 342 | 343 | // Draw default folder image 344 | function drawDefaultImage(ctx, defaultImg, width, height) { 345 | ctx.drawImage(defaultImg, 0, 0, width, height); 346 | } 347 | 348 | // Determine if we should draw the icon 349 | function shouldDrawIcon() { 350 | return ( 351 | iconType !== "none" && 352 | !( 353 | folderType === "win10" && 354 | folderSize === 16 && 355 | folderSmallType !== "iconOnly" 356 | ) && 357 | (folderSmallType === "folderAndIcon" || 358 | folderSmallType === "squareAndIcon" || 359 | folderSize > 32 || 360 | isIconOnly) 361 | ); 362 | } 363 | 364 | // Draw icon on canvas 365 | function drawIcon(ctx, icon, iconMaskImg, width, height) { 366 | if (!icon) return; 367 | 368 | const aspectRatio = icon.width / icon.height || 1; 369 | const scaledWidth = width; 370 | const scaledHeight = scaledWidth / aspectRatio; 371 | 372 | const iconOffsetX = (iconOffset[0] / 100) * scaledWidth; 373 | const iconOffsetY = 374 | (iconOffset[1] / 100) * scaledHeight + (height - scaledHeight) / 4; 375 | 376 | const iconX = (width - width * iconScale * iconMultiplier) / 2; 377 | const iconY = (height - height * iconScale * iconMultiplier) / 2; 378 | 379 | if (iconMasked) { 380 | drawMaskedIcon( 381 | ctx, 382 | icon, 383 | iconMaskImg, 384 | width, 385 | height, 386 | iconX, 387 | iconY, 388 | iconOffsetX, 389 | iconOffsetY, 390 | aspectRatio 391 | ); 392 | } else { 393 | drawUnmaskedIcon( 394 | ctx, 395 | icon, 396 | width, 397 | height, 398 | iconX, 399 | iconY, 400 | iconOffsetX, 401 | iconOffsetY 402 | ); 403 | } 404 | } 405 | 406 | // Draw icon with mask applied 407 | function drawMaskedIcon( 408 | ctx, 409 | icon, 410 | iconMaskImg, 411 | width, 412 | height, 413 | iconX, 414 | iconY, 415 | iconOffsetX, 416 | iconOffsetY, 417 | aspectRatio 418 | ) { 419 | const tempCanvas = document.createElement("canvas"); 420 | tempCanvas.width = width; 421 | tempCanvas.height = height; 422 | const tempCtx = tempCanvas.getContext("2d"); 423 | 424 | const scaledWidth = width; 425 | const scaledHeight = scaledWidth / aspectRatio; 426 | 427 | applyIconEffects(tempCtx, iconOpacity, iconShadow, folderSize); 428 | drawIconImage( 429 | tempCtx, 430 | icon, 431 | iconX + iconAnchor[0] + iconOffsetX, 432 | iconY + iconAnchor[1] + iconOffsetY, 433 | scaledWidth * iconScale * iconMultiplier, 434 | scaledHeight * iconScale * iconMultiplier 435 | ); 436 | 437 | resetIconEffects(tempCtx); 438 | 439 | if (shouldApplyIconMask()) { 440 | tempCtx.globalCompositeOperation = "destination-in"; 441 | tempCtx.drawImage(iconMaskImg, 0, 0, width, height); 442 | } 443 | 444 | ctx.globalCompositeOperation = "source-over"; 445 | ctx.drawImage(tempCanvas, 0, 0); 446 | } 447 | 448 | // Draw icon without mask 449 | function drawUnmaskedIcon( 450 | ctx, 451 | icon, 452 | width, 453 | height, 454 | iconX, 455 | iconY, 456 | iconOffsetX, 457 | iconOffsetY 458 | ) { 459 | ctx.globalCompositeOperation = "source-over"; 460 | applyIconEffects(ctx, iconOpacity, iconShadow, folderSize); 461 | 462 | drawIconImage( 463 | ctx, 464 | icon, 465 | iconX + iconAnchor[0] + iconOffsetX, 466 | iconY + iconAnchor[1] + iconOffsetY, 467 | width * iconScale * iconMultiplier, 468 | height * iconScale * iconMultiplier 469 | ); 470 | 471 | resetIconEffects(ctx); 472 | } 473 | 474 | // Apply visual effects to icon 475 | function applyIconEffects(ctx, opacity, shadow, size) { 476 | ctx.globalAlpha = opacity; 477 | if (shadow) { 478 | ctx.shadowColor = "rgba(0, 0, 0, 0.15)"; 479 | ctx.shadowBlur = (10 * size) / 512; 480 | ctx.shadowOffsetX = 0; 481 | ctx.shadowOffsetY = 0; 482 | } 483 | } 484 | 485 | // Reset icon visual effects 486 | function resetIconEffects(ctx) { 487 | ctx.globalAlpha = 1; 488 | ctx.shadowColor = "transparent"; 489 | } 490 | 491 | // Draw icon image 492 | function drawIconImage(ctx, icon, x, y, width, height) { 493 | ctx.drawImage(icon, x, y, width, height); 494 | } 495 | 496 | // Determine if we should apply icon mask 497 | function shouldApplyIconMask() { 498 | return !isIconOnly; 499 | } 500 | 501 | // Skip render for unsupported sizes 502 | if (shouldSkipRender(folderType, folderSize)) { 503 | return null; 504 | } 505 | 506 | return ( 507 |
516 | {isLoading ? ( 517 |
Loading...
518 | ) : ( 519 | 525 | )} 526 | 527 | {folderSize} x {folderSize} 528 | 529 |
530 | ); 531 | } 532 | -------------------------------------------------------------------------------- /src/components/footer.jsx: -------------------------------------------------------------------------------- 1 | import { useTranslations } from "next-intl"; 2 | import { Heart } from "lucide-react"; 3 | 4 | import Download from "./inputs/download"; 5 | 6 | import "@/styles/footer.css"; 7 | 8 | export default function Footer() { 9 | const t = useTranslations("donation"); 10 | 11 | const user = "@unclecomrade"; 12 | 13 | return ( 14 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /src/components/header-buttons.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useState, useEffect } from "react"; 4 | import { siGithub, siKofi, siDiscord } from "simple-icons"; 5 | import { Info, Moon, Sun, Bug, Send } from "lucide-react"; 6 | 7 | import { swapTheme } from "@/functions/theme-swap"; 8 | import { useTranslations } from "next-intl"; 9 | import Firefox from "./firefox"; 10 | import Modal from "./modal"; 11 | import LocaleSwitcher from "./inputs/locale-switcher"; 12 | import Credits from "./credits"; 13 | import HeaderButton from "./inputs/header-button"; 14 | 15 | import { isFirefox } from "@/functions/fetch-browser-type"; 16 | 17 | export default function HeaderButtons() { 18 | const t = useTranslations("credits"); 19 | 20 | const [isModalOpen, setIsModalOpen] = useState(false); 21 | const [isFirefoxOpen, setIsFirefoxOpen] = useState(false); 22 | 23 | useEffect(() => { 24 | if (isFirefox()) { 25 | setIsFirefoxOpen(true); 26 | } 27 | }, []); 28 | 29 | return ( 30 | <> 31 | setIsModalOpen(false)} 35 | > 36 | 37 | 38 | 39 |
40 | swapTheme(document.body.classList.value)} 44 | icon={ 45 | <> 46 | 47 | 48 | 49 | } 50 | /> 51 | setIsModalOpen(true)} 55 | icon={} 56 | /> 57 | } 63 | /> 64 | } 70 | /> 71 |
72 | 79 | 80 | 81 | } 82 | /> 83 | 90 | 91 | 92 | } 93 | /> 94 | 101 | 102 | 103 | } 104 | /> 105 |
106 | 107 | {isFirefoxOpen && ( 108 | <> 109 |
110 | 111 | 112 | )} 113 |
114 | 115 | ); 116 | } 117 | -------------------------------------------------------------------------------- /src/components/header.jsx: -------------------------------------------------------------------------------- 1 | import Logo from "./logo"; 2 | import HeaderButtons from "./header-buttons"; 3 | 4 | import "@/styles/header.css"; 5 | 6 | export default function Header() { 7 | return ( 8 | <> 9 | 13 | 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /src/components/inputs/checkbox.jsx: -------------------------------------------------------------------------------- 1 | import { Check } from "lucide-react"; 2 | 3 | import "@/styles/inputs/checkbox.css"; 4 | 5 | export default function Checkbox({ 6 | onChange, 7 | defaultChecked, 8 | id, 9 | name, 10 | label, 11 | checked, 12 | }) { 13 | const handleClick = () => { 14 | onChange(); 15 | document.getElementById(id).checked = !document.getElementById(id).checked; 16 | }; 17 | return ( 18 | 19 | 28 | 29 | 30 | 31 | 32 | {label} 33 | 34 | 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /src/components/inputs/color.jsx: -------------------------------------------------------------------------------- 1 | import { useRef, useEffect, useState } from "react"; 2 | 3 | import "@/styles/inputs/color.css"; 4 | 5 | export default function Color({ defaultColor, onChange, id, name, label }) { 6 | const colorInput = useRef(null); 7 | const [fakeColor, setFakeColor] = useState(defaultColor); 8 | 9 | useEffect(() => { 10 | setFakeColor(defaultColor); 11 | }, [defaultColor]); 12 | 13 | const handleChange = (event) => { 14 | setFakeColor(event.target.value); 15 | onChange(event); 16 | }; 17 | 18 | const handleClick = () => { 19 | colorInput.current.click(); 20 | }; 21 | 22 | return ( 23 |
24 | 25 | 34 | 38 | {label} 39 | 40 | {fakeColor} 41 |
42 | ); 43 | } 44 | -------------------------------------------------------------------------------- /src/components/inputs/download.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import DownloadCounter from "../download-count"; 4 | 5 | import { useState, useEffect } from "react"; 6 | import { folderConfigStore } from "@/stores/folder-config"; 7 | import { useTranslations } from "next-intl"; 8 | import { FolderGenerate } from "@/functions/folder-generate"; 9 | 10 | export default function Download() { 11 | const folderType = folderConfigStore((state) => state.folderType); 12 | const [fileType, setFileType] = useState( 13 | folderType === "bigsur" ? "icns" : "ico" 14 | ); 15 | const [iconSize, setIconSize] = useState("all"); 16 | const [sessionDownload, setSessionDownload] = useState(false); 17 | 18 | const iconType = folderConfigStore((state) => state.iconType); 19 | const lucideSlug = folderConfigStore((state) => state.lucideSlug); 20 | const simpleSlug = folderConfigStore((state) => state.simpleSlug); 21 | const customFileName = folderConfigStore((state) => state.customFileName); 22 | 23 | const t = useTranslations("download"); 24 | 25 | useEffect(() => { 26 | if (folderType === "bigsur") { 27 | setFileType("icns"); 28 | } else { 29 | setFileType("ico"); 30 | } 31 | }, [folderType]); 32 | 33 | const getName = () => { 34 | let name = ""; 35 | if (iconType === "simple") { 36 | name = simpleSlug; 37 | } else if (iconType === "lucide") { 38 | name = lucideSlug; 39 | } else if (iconType === "custom") { 40 | name = customFileName.replace(/\.[^.]+$/, ""); 41 | } 42 | if (name === "") name = "folder"; 43 | return name; 44 | }; 45 | 46 | const handleDownload = async () => { 47 | FolderGenerate(fileType, iconSize, getName()); 48 | 49 | if (sessionDownload) return; 50 | try { 51 | const response = await fetch("/api/downloads", { 52 | method: "POST", 53 | headers: { 54 | "Content-Type": "application/json", 55 | }, 56 | }); 57 | 58 | if (!response.ok) { 59 | if (process.env.NEXT_PUBLIC_SUPABASE_URL) { 60 | throw new Error( 61 | "Failed to increment download count", 62 | response.status 63 | ); 64 | } else { 65 | console.log("Download increment triggered"); 66 | } 67 | } else { 68 | setSessionDownload(true); 69 | } 70 | } catch (error) { 71 | console.error("Download count error:", error); 72 | } 73 | }; 74 | 75 | return ( 76 |
77 | 78 | 88 | 89 | {fileType === "png" && ( 90 | 111 | )} 112 | 113 | 119 |
120 | ); 121 | } 122 | -------------------------------------------------------------------------------- /src/components/inputs/dropdown.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useState, useEffect } from "react"; 4 | import { ChevronRight } from "lucide-react"; 5 | import "@/styles/inputs/dropdown.css"; 6 | 7 | export default function Dropdown({ 8 | children, 9 | open = false, 10 | name, 11 | icon = "Image", 12 | }) { 13 | const [isOpen, setOpen] = useState(open); 14 | const [IconComponent, setIconComponent] = useState(null); 15 | 16 | const toggleDropdown = () => { 17 | setOpen(!isOpen); 18 | }; 19 | 20 | useEffect(() => { 21 | const loadIcon = async () => { 22 | try { 23 | const iconModule = await import(`lucide-react`); 24 | const DynamicIcon = iconModule[icon]; 25 | if (DynamicIcon) { 26 | setIconComponent(() => DynamicIcon); 27 | } else { 28 | console.warn(`Icon "${icon}" not found in lucide-react`); 29 | } 30 | } catch (err) { 31 | console.error("Error loading icon:", err); 32 | } 33 | }; 34 | 35 | loadIcon(); 36 | }, [icon]); 37 | 38 | return ( 39 |
40 |
41 | 42 | {IconComponent ? : null} 43 | 44 | {name} 45 |
46 | 47 | 51 | 52 |
53 |
54 | {children} 55 |
56 |
57 | ); 58 | } 59 | -------------------------------------------------------------------------------- /src/components/inputs/folder-color-input.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import Color from "./color"; 4 | 5 | import { setPrimary } from "@/functions/set-primary"; 6 | import { folderConfigStore } from "@/stores/folder-config"; 7 | import { useTranslations } from "next-intl"; 8 | import { useState } from "react"; 9 | 10 | export default function FolderColorInput({ colorId = 0 }) { 11 | const colors = [ 12 | folderConfigStore((state) => state.gradientStartColor), 13 | folderConfigStore((state) => state.gradientEndColor), 14 | folderConfigStore((state) => state.solidColor), 15 | ]; 16 | 17 | const t = useTranslations("folderConfig"); 18 | 19 | const colorNames = [t("gradientStart"), t("gradientEnd"), t("solidColor")]; 20 | 21 | const [color, setColor] = useState(colors[colorId]); 22 | 23 | const updateColor = (event) => { 24 | const newColor = event.target.value; 25 | setColor(newColor); 26 | switch (colorId) { 27 | case 0: 28 | folderConfigStore.getState().setGradientStartColor(newColor); 29 | setPrimary([ 30 | folderConfigStore.getState().gradientStartColor, 31 | folderConfigStore.getState().gradientEndColor, 32 | ]); 33 | break; 34 | case 1: 35 | folderConfigStore.getState().setGradientEndColor(newColor); 36 | setPrimary([ 37 | folderConfigStore.getState().gradientStartColor, 38 | folderConfigStore.getState().gradientEndColor, 39 | ]); 40 | break; 41 | case 2: 42 | folderConfigStore.getState().setSolidColor(newColor); 43 | setPrimary([ 44 | folderConfigStore.getState().solidColor, 45 | folderConfigStore.getState().solidColor, 46 | ]); 47 | break; 48 | default: 49 | break; 50 | } 51 | }; 52 | 53 | return ( 54 | 59 | ); 60 | } 61 | -------------------------------------------------------------------------------- /src/components/inputs/header-button.jsx: -------------------------------------------------------------------------------- 1 | import "@/styles/inputs/header-button.css"; 2 | 3 | export default function HeaderButton({ onClick, icon, href, target, label }) { 4 | return ( 5 | 6 | {icon} 7 | {label} 8 | 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /src/components/inputs/img-radio.jsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | import "@/styles/inputs/img-radio.css"; 3 | 4 | export default function ImgRadio({ 5 | onChange, 6 | defaultChecked, 7 | id, 8 | name, 9 | img, 10 | size = 48, 11 | }) { 12 | const handleClick = () => { 13 | onChange(); 14 | document.getElementById(id).checked = true; 15 | }; 16 | 17 | return ( 18 | 36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /src/components/inputs/locale-switcher-select.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { usePathname, useRouter } from "next/navigation"; 4 | import { useParams } from "next/navigation"; 5 | import { useTransition } from "react"; 6 | 7 | export default function LocaleSwitcherSelect({ 8 | children, 9 | defaultValue, 10 | label, 11 | }) { 12 | const router = useRouter(); 13 | const pathname = usePathname(); 14 | const params = useParams(); 15 | const [isPending, startTransition] = useTransition(); 16 | 17 | function onSelectChange(event) { 18 | const newLocale = event.target.value; 19 | startTransition(() => { 20 | router.push(`/${newLocale}`, undefined, { locale: newLocale }); 21 | }); 22 | } 23 | 24 | return ( 25 | 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /src/components/inputs/locale-switcher.jsx: -------------------------------------------------------------------------------- 1 | import { useLocale } from "next-intl"; 2 | import LocaleSwitcherSelect from "./locale-switcher-select"; 3 | 4 | const getLocales = () => { 5 | const context = require.context("../../locales", false, /\.json$/); 6 | return context 7 | .keys() 8 | .map((key) => key.replace("./", "").replace(".json", "")); 9 | }; 10 | 11 | const getLocaleName = (locale) => { 12 | const context = require.context("../../locales", false, /\.json$/); 13 | return context(`./${locale}.json`).language; 14 | }; 15 | 16 | export default function LocaleSwitcher() { 17 | const locale = useLocale(); 18 | 19 | return ( 20 | 21 | {[ 22 | { locale: "en", name: getLocaleName("en") }, 23 | ...getLocales() 24 | .filter((locale) => locale !== "en") 25 | .map((locale) => ({ locale, name: getLocaleName(locale) })), 26 | ].map(({ locale, name }) => ( 27 | 30 | ))} 31 | 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /src/components/inputs/offset-input.jsx: -------------------------------------------------------------------------------- 1 | import Dropdown from "./dropdown"; 2 | import Range from "./range"; 3 | 4 | import { folderConfigStore } from "@/stores/folder-config"; 5 | import { useTranslations } from "next-intl"; 6 | 7 | export default function OffsetInput() { 8 | const setOffset = folderConfigStore((state) => state.setIconOffset); 9 | const setIconScale = folderConfigStore((state) => state.setIconScale); 10 | 11 | const handleXChange = (event) => { 12 | const offsetX = event.target.value; 13 | const offsetY = document.getElementById("offset-y").value; 14 | setOffset([offsetX, offsetY]); 15 | }; 16 | 17 | const handleYChange = (event) => { 18 | const offsetX = document.getElementById("offset-x").value; 19 | const offsetY = event.target.value; 20 | setOffset([offsetX, offsetY]); 21 | }; 22 | 23 | const t = useTranslations("panelTitles"); 24 | const tc = useTranslations("iconConfig"); 25 | 26 | return ( 27 | 28 | 37 | 46 | setIconScale(e.target.value)} 51 | defaultValue="0.5" 52 | min="0.1" 53 | max="1" 54 | step="0.01" 55 | /> 56 | 57 | ); 58 | } 59 | -------------------------------------------------------------------------------- /src/components/inputs/radio.jsx: -------------------------------------------------------------------------------- 1 | import "@/styles/inputs/radio.css"; 2 | 3 | export default function Radio({ 4 | onChange, 5 | defaultChecked, 6 | id, 7 | name, 8 | label, 9 | checked, 10 | }) { 11 | const handleClick = () => { 12 | onChange(); 13 | document.getElementById(id).checked = true; 14 | }; 15 | return ( 16 | 17 | 26 | 27 | 28 | 29 | {label} 30 | 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /src/components/inputs/range.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import { RotateCcw } from "lucide-react"; 3 | 4 | import "@/styles/inputs/range.css"; 5 | 6 | export default function Range({ 7 | onChange, 8 | min, 9 | max, 10 | defaultValue, 11 | id, 12 | label, 13 | step, 14 | }) { 15 | const [value, setValue] = useState(defaultValue); 16 | 17 | const handleChange = (event) => { 18 | setValue(event.target.value); 19 | onChange(event); 20 | }; 21 | 22 | const handleReset = () => { 23 | setValue(defaultValue); 24 | onChange({ target: { value: defaultValue } }); 25 | }; 26 | 27 | return ( 28 |
29 | 32 | {value} 33 |
34 | 42 | 52 |
53 | 56 |
57 | ); 58 | } 59 | -------------------------------------------------------------------------------- /src/components/inputs/slug-input.jsx: -------------------------------------------------------------------------------- 1 | import { createRef } from "react"; 2 | 3 | import FolderIconPreview from "@/components/folder/folder-icon-preview"; 4 | import { folderConfigStore } from "@/stores/folder-config"; 5 | import { useTranslations } from "next-intl"; 6 | import { 7 | setLucideSlug, 8 | checkLucide, 9 | convertLucideSlug, 10 | } from "@/functions/fetch-lucide"; 11 | import { 12 | setSimpleSlug, 13 | checkSimple, 14 | convertSimpleSlug, 15 | } from "@/functions/fetch-simple"; 16 | 17 | import { Download } from "lucide-react"; 18 | 19 | import "@/styles/inputs/slug-input.css"; 20 | 21 | export default function SlugInput() { 22 | const iconType = folderConfigStore((state) => state.iconType); 23 | const lucideSlug = folderConfigStore((state) => state.lucideSlug); 24 | const simpleSlug = folderConfigStore((state) => state.simpleSlug); 25 | const inputRef = createRef(); 26 | const t = useTranslations("iconConfig"); 27 | 28 | const handleInput = async (event) => { 29 | if ( 30 | event.type === "click" || 31 | (event.type === "keyup" && event.key === "Enter") 32 | ) { 33 | const slugValue = inputRef.current.value; 34 | if (iconType === "simple") { 35 | if (checkSimple(convertSimpleSlug(slugValue)) === false) { 36 | inputRef.current.style.animation = "invalid 0.5s ease-out"; 37 | setTimeout(() => { 38 | inputRef.current.style.animation = ""; 39 | }, 1000); 40 | return; 41 | } else { 42 | setSimpleSlug(convertSimpleSlug(slugValue)); 43 | inputRef.current.value = ""; 44 | } 45 | } else { 46 | const slugCheck = await checkLucide(convertLucideSlug(slugValue)); 47 | if (slugCheck === false) { 48 | inputRef.current.style.animation = "invalid 0.5s ease-out"; 49 | setTimeout(() => { 50 | inputRef.current.style.animation = ""; 51 | }, 1000); 52 | return; 53 | } else { 54 | setLucideSlug(convertLucideSlug(slugValue)); 55 | inputRef.current.value = ""; 56 | return; 57 | } 58 | } 59 | } 60 | }; 61 | 62 | return ( 63 |
64 | 65 | 73 | 74 | 75 | {t("current")} {iconType === "lucide" ? lucideSlug : simpleSlug} 76 | 84 | {t("browse")} 85 | 86 | 87 | 88 | 96 | 99 | 100 | 101 | 102 |
103 | ); 104 | } 105 | -------------------------------------------------------------------------------- /src/components/logo.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useEffect } from "react"; 4 | import { folderConfigStore } from "@/stores/folder-config"; 5 | import packageJson from "../../package.json"; 6 | 7 | export default function Logo() { 8 | const colorType = folderConfigStore((state) => state.colorType); 9 | const gradientStartColor = folderConfigStore( 10 | (state) => state.gradientStartColor 11 | ); 12 | const gradientEndColor = folderConfigStore((state) => state.gradientEndColor); 13 | const solidColor = folderConfigStore((state) => state.solidColor); 14 | const folderType = folderConfigStore((state) => state.folderType); 15 | 16 | const getFill = () => { 17 | if (colorType === "linear-gradient") { 18 | return [gradientStartColor, gradientEndColor]; 19 | } else if (colorType === "solid") { 20 | return [solidColor, solidColor]; 21 | } else { 22 | if (folderType === "win11" || folderType === "win10") 23 | return ["#fee394", "#dfa52e"]; 24 | else if (folderType === "bigsur") return ["#82d0f8", "#0089cf"]; 25 | else return ["#8bb158", "#8bb158"]; 26 | } 27 | }; 28 | 29 | const version = packageJson.version; 30 | 31 | useEffect(() => { 32 | const updateFavicon = () => { 33 | const svgElement = document.querySelector("#a"); 34 | let svgData = new XMLSerializer().serializeToString(svgElement); 35 | // give white background only for the favicon 36 | svgData = svgData.replace(`fill="var(--text)"`, `fill="#1f2937"`); 37 | svgData = svgData.replace( 38 | `viewBox="0 0 149.74 124.78"`, 39 | `viewBox="-15 -27.5 180 180"> ` 47 | ); 48 | const svgBlob = new Blob([svgData], { 49 | type: "image/svg+xml;charset=utf-8", 50 | }); 51 | const url = URL.createObjectURL(svgBlob); 52 | const link = document.createElement("link"); 53 | link.rel = "icon"; 54 | link.href = url; 55 | document.head.appendChild(link); 56 | 57 | return () => { 58 | URL.revokeObjectURL(url); 59 | document.head.removeChild(link); 60 | }; 61 | }; 62 | 63 | const unsubscribe = folderConfigStore.subscribe(updateFavicon, (state) => [ 64 | state.colorType, 65 | state.gradientStartColor, 66 | state.gradientEndColor, 67 | state.solidColor, 68 | ]); 69 | 70 | updateFavicon(); 71 | 72 | return () => unsubscribe(); 73 | }, []); 74 | 75 | return ( 76 |
77 | 78 | 79 | 80 | 88 | 89 | 90 | 91 | 92 | 96 | 100 | 101 | 102 |

FlaredFolders

103 | {version} 104 |
105 | ); 106 | } 107 | -------------------------------------------------------------------------------- /src/components/modal.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useTranslations } from "next-intl"; 4 | 5 | import "@/styles/modal.css"; 6 | 7 | export default function Modal({ 8 | title = "Unnamed", 9 | children, 10 | isOpen, 11 | onClose, 12 | }) { 13 | if (!isOpen) { 14 | return null; 15 | } 16 | 17 | const t = useTranslations("modal"); 18 | 19 | return ( 20 |
21 |
22 |
23 |
{title}
24 |
25 |
{children}
26 |
27 | 30 |
31 |
32 |
33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /src/components/theme-init.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useEffect } from "react"; 4 | import { setTheme } from "@/functions/theme-set"; 5 | 6 | export default function ThemeInitializer({ serverTheme }) { 7 | useEffect(() => { 8 | if (!serverTheme) { 9 | const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)"); 10 | const userPref = mediaQuery.matches ? "dark" : "light"; 11 | 12 | setTheme(userPref); 13 | } 14 | }, [serverTheme]); 15 | 16 | return null; 17 | } 18 | -------------------------------------------------------------------------------- /src/components/view.jsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | 3 | import "@/styles/view.css"; 4 | 5 | export default function ViewLayout() { 6 | return ( 7 |
8 | Flared Folders 14 |

Flared Folders

15 |

A Free, Open-Source Folder Customization Tool

16 |

Please visit on a larger screen in order to use this tool.

17 |
18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /src/credits.json: -------------------------------------------------------------------------------- 1 | { 2 | "createdBy": ["EthanHazel", "https://github.com/EthanHazel"], 3 | "iconsFrom": { 4 | "simple": ["Simple Icons", "https://simpleicons.org/"], 5 | "lucide": ["Lucide", "https://lucide.dev/"] 6 | }, 7 | "specialThanks": [ 8 | "Von Caschy", 9 | "MigPro", 10 | "Kooky-Skill1250", 11 | "r/Windows_Redesign" 12 | ], 13 | 14 | "_comment": "Kofi donations are here temporarily and an API will be added soon", 15 | "kofi": ["unclecomrade"] 16 | } 17 | -------------------------------------------------------------------------------- /src/functions/fetch-browser-type.jsx: -------------------------------------------------------------------------------- 1 | export function isFirefox() { 2 | if (typeof window === "undefined") { 3 | return false; 4 | } 5 | return navigator.userAgent.toLowerCase().includes("firefox"); 6 | } 7 | -------------------------------------------------------------------------------- /src/functions/fetch-custom.jsx: -------------------------------------------------------------------------------- 1 | import { folderConfigStore } from "@/stores/folder-config"; 2 | 3 | export function loadCustom(customFileName) { 4 | return new Promise((resolve) => { 5 | const currentState = folderConfigStore.getState(); 6 | const customIconInput = document.getElementById("custom-icon"); 7 | 8 | const loadImageFromData = (data) => { 9 | return new Promise((resolveImage) => { 10 | const img = new Image(); 11 | img.onload = () => resolveImage(img); 12 | img.onerror = () => { 13 | console.error("Failed to load image"); 14 | resolveImage(null); 15 | }; 16 | img.src = data; 17 | }); 18 | }; 19 | 20 | // Handle case when no file is selected 21 | if (!customIconInput?.files?.[0]) { 22 | if (customFileName === "placeholder") { 23 | resolve(currentState.customData); 24 | return; 25 | } 26 | 27 | // Load temp-icon 28 | const tempIconPath = "/folder-assets/temp-icon.svg"; 29 | fetch(tempIconPath) 30 | .then((response) => response.blob()) 31 | .then((blob) => { 32 | const reader = new FileReader(); 33 | reader.onload = async () => { 34 | const data = reader.result; 35 | const img = await loadImageFromData(data); 36 | folderConfigStore.setState({ 37 | customData: img, // Store the Image object 38 | customFileName: "placeholder", 39 | }); 40 | resolve(img); 41 | }; 42 | reader.readAsDataURL(blob); 43 | }) 44 | .catch((error) => { 45 | console.error("Failed to load temp icon:", error); 46 | resolve(null); 47 | }); 48 | return; 49 | } 50 | 51 | // Handle case when file is selected 52 | if (customIconInput.files[0].name === customFileName) { 53 | resolve(currentState.customData); 54 | } else { 55 | const reader = new FileReader(); 56 | reader.onload = async () => { 57 | const data = reader.result; 58 | const img = await loadImageFromData(data); 59 | folderConfigStore.setState({ 60 | customData: img, // Store the Image object 61 | customFileName: customIconInput.files[0].name, 62 | }); 63 | resolve(img); 64 | }; 65 | reader.readAsDataURL(customIconInput.files[0]); 66 | } 67 | }); 68 | } 69 | -------------------------------------------------------------------------------- /src/functions/fetch-lucide.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOMServer from "react-dom/server"; 3 | 4 | import { folderConfigStore } from "../stores/folder-config"; 5 | 6 | export const convertLucideSlug = (slug) => { 7 | if (slug.includes("-")) { 8 | // Convert kebab-case to PascalCase 9 | return slug 10 | .toLowerCase() 11 | .split("-") 12 | .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) 13 | .join(""); 14 | } else { 15 | return slug.charAt(0).toUpperCase() + slug.slice(1).toLowerCase(); 16 | } 17 | }; 18 | 19 | export const checkLucide = async (slug) => { 20 | try { 21 | const module = await import("lucide-react"); 22 | const IconComponent = module.default?.[slug] ?? module[slug]; 23 | return !!IconComponent; 24 | } catch (error) { 25 | return false; 26 | } 27 | }; 28 | 29 | export const setLucideSlug = (slug) => { 30 | const setLucideSlug = folderConfigStore.getState().setLucideSlug; 31 | if (checkLucide(slug)) { 32 | setLucideSlug(slug); 33 | return true; 34 | } else { 35 | return false; 36 | } 37 | }; 38 | 39 | export const loadLucide = async (slug, color, strokeWidth) => { 40 | try { 41 | // Dynamically import the Lucide icon component 42 | const module = await import(`lucide-react`); 43 | const IconComponent = module[slug]; 44 | 45 | // Render the icon to a string 46 | const svgString = ReactDOMServer.renderToString( 47 | React.createElement(IconComponent, { 48 | style: { color: color, strokeWidth: strokeWidth }, 49 | }) 50 | ); 51 | 52 | // Create an image from the SVG string 53 | return new Promise((resolve) => { 54 | const img = new Image(); 55 | img.onload = () => resolve(img); 56 | img.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent( 57 | svgString 58 | )}`; 59 | }); 60 | } catch (error) { 61 | console.error("Error loading Lucide icon:", error); 62 | throw error; 63 | } 64 | }; 65 | -------------------------------------------------------------------------------- /src/functions/fetch-simple.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOMServer from "react-dom/server"; 3 | import * as icons from "simple-icons"; 4 | 5 | import { folderConfigStore } from "../stores/folder-config"; 6 | 7 | export const convertSimpleSlug = (slug) => { 8 | return slug 9 | .replace(/-/g, "") 10 | .replace(/^\S|\S$/g, function (s) { 11 | return s.toUpperCase(); 12 | }) 13 | .replace(/\B\w/g, function (s) { 14 | return s.toLowerCase(); 15 | }); 16 | }; 17 | 18 | export const checkSimple = (slug) => { 19 | const iconKey = `si${slug.charAt(0).toUpperCase() + slug.slice(1)}`; 20 | return icons[iconKey] ? true : false; 21 | }; 22 | 23 | export const setSimpleSlug = (slug) => { 24 | const setSimpleSlugStore = folderConfigStore.getState().setSimpleSlug; 25 | if (checkSimple(slug)) { 26 | setSimpleSlugStore(slug); 27 | return true; 28 | } else { 29 | return false; 30 | } 31 | }; 32 | 33 | export const loadSimple = async (slug, color) => { 34 | try { 35 | const iconKey = `si${slug.charAt(0).toUpperCase() + slug.slice(1)}`; 36 | const iconData = icons[iconKey]; 37 | 38 | const svgString = ReactDOMServer.renderToString( 39 | 44 | 45 | 46 | ); 47 | 48 | // Create an image from the SVG string 49 | return new Promise((resolve) => { 50 | const img = new Image(); 51 | img.onload = () => resolve(img); 52 | img.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent( 53 | svgString 54 | )}`; 55 | }); 56 | } catch (error) { 57 | console.error("Error loading Simple icon:", error); 58 | throw error; 59 | } 60 | }; 61 | -------------------------------------------------------------------------------- /src/functions/folder-generate.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import JSZip from "jszip"; 4 | 5 | const downloadIco = async (name = "folder") => { 6 | try { 7 | const canvasIds = [512, 256, 128, 96, 72, 64, 48, 32, 24, 16]; 8 | const canvases = canvasIds 9 | .map((id) => document.getElementById(`folder-${id}`)) 10 | .filter((canvas) => !!canvas); 11 | 12 | const images = await Promise.all( 13 | canvases.map(async (canvas) => { 14 | const blob = await new Promise((resolve) => 15 | canvas.toBlob(resolve, "image/png") 16 | ); 17 | const buffer = await blob.arrayBuffer(); 18 | return { 19 | data: new Uint8Array(buffer), 20 | width: canvas.width, 21 | height: canvas.height, 22 | }; 23 | }) 24 | ); 25 | 26 | const headerSize = 6; 27 | const directoryEntrySize = 16; 28 | const directoriesSize = images.length * directoryEntrySize; 29 | const totalImageSize = images.reduce( 30 | (sum, img) => sum + img.data.length, 31 | 0 32 | ); 33 | const totalSize = headerSize + directoriesSize + totalImageSize; 34 | 35 | const finalBuffer = new Uint8Array(totalSize); 36 | 37 | const header = new DataView(new ArrayBuffer(headerSize)); 38 | header.setUint16(0, 0, true); 39 | header.setUint16(2, 1, true); 40 | header.setUint16(4, images.length, true); 41 | finalBuffer.set(new Uint8Array(header.buffer), 0); 42 | 43 | let dataOffset = headerSize + directoriesSize; 44 | const dataOffsets = []; 45 | 46 | images.forEach((img, index) => { 47 | const entry = new DataView(new ArrayBuffer(directoryEntrySize)); 48 | entry.setUint8(0, img.width === 256 ? 0 : img.width); 49 | entry.setUint8(1, img.height === 256 ? 0 : img.height); 50 | entry.setUint8(2, 0); 51 | entry.setUint8(3, 0); 52 | entry.setUint16(4, 1, true); 53 | entry.setUint16(6, 32, true); 54 | entry.setUint32(8, img.data.length, true); 55 | entry.setUint32(12, dataOffset, true); 56 | 57 | finalBuffer.set( 58 | new Uint8Array(entry.buffer), 59 | headerSize + index * directoryEntrySize 60 | ); 61 | 62 | dataOffsets.push(dataOffset); 63 | dataOffset += img.data.length; 64 | }); 65 | 66 | images.forEach((img, index) => { 67 | finalBuffer.set(img.data, dataOffsets[index]); 68 | }); 69 | 70 | const blob = new Blob([finalBuffer], { type: "image/x-icon" }); 71 | const link = document.createElement("a"); 72 | link.download = `${name}.ico`; 73 | link.href = URL.createObjectURL(blob); 74 | link.style.display = "none"; 75 | 76 | document.body.appendChild(link); 77 | link.click(); 78 | 79 | setTimeout(() => { 80 | document.body.removeChild(link); 81 | URL.revokeObjectURL(link.href); 82 | }, 100); 83 | } catch (error) { 84 | console.error("ICO creation failed:", error); 85 | alert("Error generating ICO file - check console for details"); 86 | } 87 | }; 88 | 89 | const downloadIcns = async (name = "folder") => { 90 | try { 91 | const sizeToType = { 92 | 16: "icp3", // 16x16 93 | 32: "icp4", // 32x32 94 | 64: "icp6", // 64x64 95 | 128: "ic07", // 128x128 96 | 256: "ic08", // 256x256 97 | 512: "ic09", // 512x512 98 | 1024: "ic10", // 1024x1024 99 | }; 100 | 101 | const canvasIds = [1024, 512, 256, 128, 64, 32, 16]; 102 | const canvases = canvasIds 103 | .map((id) => document.getElementById(`folder-${id}`)) 104 | .filter((canvas) => !!canvas && sizeToType[canvas.width]); 105 | 106 | const images = await Promise.all( 107 | canvases.map(async (canvas) => { 108 | const blob = await new Promise((resolve) => 109 | canvas.toBlob(resolve, "image/png") 110 | ); 111 | const buffer = await blob.arrayBuffer(); 112 | return { 113 | data: new Uint8Array(buffer), 114 | size: canvas.width, 115 | type: sizeToType[canvas.width], 116 | }; 117 | }) 118 | ); 119 | 120 | const chunks = images.map((img) => { 121 | const typeBytes = new TextEncoder().encode(img.type); 122 | const dataLength = img.data.byteLength; 123 | const chunkLength = dataLength + 8; 124 | 125 | const chunk = new Uint8Array(chunkLength); 126 | const lengthView = new DataView(chunk.buffer, 4, 4); 127 | 128 | chunk.set(typeBytes, 0); 129 | lengthView.setUint32(0, chunkLength, false); 130 | chunk.set(img.data, 8); 131 | 132 | return chunk; 133 | }); 134 | 135 | const totalSize = chunks.reduce((sum, chunk) => sum + chunk.length, 8); 136 | const header = new Uint8Array(8); 137 | const headerView = new DataView(header.buffer); 138 | 139 | header.set(new TextEncoder().encode("icns"), 0); 140 | headerView.setUint32(4, totalSize, false); 141 | 142 | const finalBuffer = new Uint8Array(totalSize); 143 | finalBuffer.set(header, 0); 144 | 145 | let offset = 8; 146 | chunks.forEach((chunk) => { 147 | finalBuffer.set(chunk, offset); 148 | offset += chunk.length; 149 | }); 150 | 151 | const blob = new Blob([finalBuffer], { type: "application/octet-stream" }); 152 | const link = document.createElement("a"); 153 | link.download = `${name}.icns`; 154 | link.href = URL.createObjectURL(blob); 155 | link.style.display = "none"; 156 | 157 | document.body.appendChild(link); 158 | link.click(); 159 | 160 | setTimeout(() => { 161 | document.body.removeChild(link); 162 | URL.revokeObjectURL(link.href); 163 | }, 100); 164 | } catch (error) { 165 | console.error("ICNS creation failed:", error); 166 | alert("Error generating ICNS file - check console for details"); 167 | } 168 | }; 169 | 170 | const downloadIconSize = (size, name = "folder") => { 171 | const canvas = document.getElementById(`folder-${size}`); 172 | const link = document.createElement("a"); 173 | link.download = `${name}-${size}.png`; 174 | link.href = canvas.toDataURL("image/png"); 175 | link.click(); 176 | }; 177 | 178 | const downloadIconsZip = async (name = "folder") => { 179 | const zip = new JSZip(); 180 | const canvasIds = [512, 256, 128, 96, 72, 64, 48, 32, 24, 16]; 181 | 182 | await Promise.all( 183 | canvasIds.map(async (size) => { 184 | const canvas = document.getElementById(`folder-${size}`); 185 | if (!canvas) return; 186 | 187 | const blob = await new Promise((resolve) => 188 | canvas.toBlob(resolve, "image/png") 189 | ); 190 | 191 | zip.file(`${name}-${size}.png`, blob, { compression: "STORE" }); 192 | }) 193 | ); 194 | 195 | zip.generateAsync({ type: "blob" }).then((blob) => { 196 | const link = document.createElement("a"); 197 | link.download = "folder.zip"; 198 | link.href = URL.createObjectURL(blob); 199 | link.click(); 200 | URL.revokeObjectURL(link.href); 201 | }); 202 | }; 203 | 204 | export function FolderGenerate(fileType, iconSize, name) { 205 | if (fileType === "ico") downloadIco(name); 206 | if (fileType === "icns") downloadIcns(name); 207 | if (fileType === "png") { 208 | if (iconSize === "all") downloadIconsZip(name); 209 | else downloadIconSize(iconSize, name); 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /src/functions/set-primary.jsx: -------------------------------------------------------------------------------- 1 | import "@/styles/globals.css"; 2 | 3 | function hexToRgb(hex) { 4 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 5 | return result 6 | ? { 7 | r: parseInt(result[1], 16), 8 | g: parseInt(result[2], 16), 9 | b: parseInt(result[3], 16), 10 | } 11 | : null; 12 | } 13 | 14 | function rgbToHex(r, g, b) { 15 | return "#" + ((r << 16) | (g << 8) | b).toString(16); 16 | } 17 | 18 | function mixColors(color1, color2) { 19 | const rgb1 = hexToRgb(color1); 20 | const rgb2 = hexToRgb(color2); 21 | 22 | const r = Math.floor((rgb1.r + rgb2.r) / 2); 23 | const g = Math.floor((rgb1.g + rgb2.g) / 2); 24 | const b = Math.floor((rgb1.b + rgb2.b) / 2); 25 | 26 | if (r === 0 && g === 0 && b === 0) return "#555555"; 27 | 28 | const brightness = (r * 299 + g * 587 + b * 114) / 1000; 29 | let clampedBrightness = 30 | brightness < 85 ? 85 : brightness > 221 ? 221 : brightness; 31 | 32 | const ratio = clampedBrightness / (brightness || 1); 33 | 34 | let finalR = Math.round(r * ratio); 35 | let finalG = Math.round(g * ratio); 36 | let finalB = Math.round(b * ratio); 37 | 38 | finalR = Math.min(255, Math.max(0, finalR)); 39 | finalG = Math.min(255, Math.max(0, finalG)); 40 | finalB = Math.min(255, Math.max(0, finalB)); 41 | 42 | const actualBrightness = (finalR * 299 + finalG * 587 + finalB * 114) / 1000; 43 | if (actualBrightness < clampedBrightness && clampedBrightness === 85) { 44 | const needed = (85 - actualBrightness) * 1000; 45 | const totalWeight = 299 + 587 + 114; 46 | finalR = Math.min( 47 | 255, 48 | finalR + Math.ceil(((299 / totalWeight) * needed) / 299) 49 | ); 50 | finalG = Math.min( 51 | 255, 52 | finalG + Math.ceil(((587 / totalWeight) * needed) / 587) 53 | ); 54 | finalB = Math.min( 55 | 255, 56 | finalB + Math.ceil(((114 / totalWeight) * needed) / 114) 57 | ); 58 | } else if ( 59 | actualBrightness > clampedBrightness && 60 | clampedBrightness === 221 61 | ) { 62 | const excess = (actualBrightness - 221) * 1000; 63 | const totalWeight = 299 + 587 + 114; 64 | finalR = Math.max( 65 | 0, 66 | finalR - Math.ceil(((299 / totalWeight) * excess) / 299) 67 | ); 68 | finalG = Math.max( 69 | 0, 70 | finalG - Math.ceil(((587 / totalWeight) * excess) / 587) 71 | ); 72 | finalB = Math.max( 73 | 0, 74 | finalB - Math.ceil(((114 / totalWeight) * excess) / 114) 75 | ); 76 | } 77 | 78 | const finalMixedColor = rgbToHex(finalR, finalG, finalB); 79 | return finalMixedColor === "#000000" ? "#555555" : finalMixedColor; 80 | } 81 | 82 | export function setPrimary(colors = ["#6aff81", "#4788b8"]) { 83 | const mixedColor = mixColors(colors[0], colors[1]); 84 | const root = document.documentElement; 85 | root.style.setProperty("--primary", mixedColor); 86 | } 87 | -------------------------------------------------------------------------------- /src/functions/theme-set.jsx: -------------------------------------------------------------------------------- 1 | "use server"; 2 | 3 | import { cookies } from "next/headers"; 4 | 5 | export async function setTheme(theme) { 6 | const cookiesInstance = await cookies(); 7 | cookiesInstance.set("theme", theme, { maxAge: 60 * 60 * 24 * 365 }); 8 | } 9 | -------------------------------------------------------------------------------- /src/functions/theme-swap.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { setTheme } from "@/functions/theme-set"; 4 | 5 | export function swapTheme(theme) { 6 | const newTheme = theme === "dark" ? "light" : "dark"; 7 | setTheme(newTheme); 8 | } 9 | -------------------------------------------------------------------------------- /src/i18n/navigation.jsx: -------------------------------------------------------------------------------- 1 | import { createNavigation } from "next-intl/navigation"; 2 | import { routing } from "./routing"; 3 | 4 | export const { Link, redirect, usePathname, useRouter, getPathname } = 5 | createNavigation(routing); 6 | -------------------------------------------------------------------------------- /src/i18n/request.jsx: -------------------------------------------------------------------------------- 1 | import { getRequestConfig } from "next-intl/server"; 2 | import { hasLocale } from "next-intl"; 3 | import { routing } from "./routing"; 4 | 5 | export default getRequestConfig(async ({ requestLocale }) => { 6 | // Typically corresponds to the `[locale]` segment 7 | const requested = await requestLocale; 8 | const locale = hasLocale(routing.locales, requested) 9 | ? requested 10 | : routing.defaultLocale; 11 | 12 | return { 13 | locale, 14 | messages: (await import(`../locales/${locale}.json`)).default, 15 | }; 16 | }); 17 | -------------------------------------------------------------------------------- /src/i18n/routing.jsx: -------------------------------------------------------------------------------- 1 | import { defineRouting } from "next-intl/routing"; 2 | 3 | const getLocales = () => { 4 | const context = require.context("../locales", false, /\.json$/); 5 | return context 6 | .keys() 7 | .map((key) => key.replace("./", "").replace(".json", "")); 8 | }; 9 | 10 | export const locales = getLocales(); 11 | const defaultLocale = "en"; 12 | 13 | export const routing = defineRouting({ 14 | locales, 15 | defaultLocale, 16 | }); 17 | -------------------------------------------------------------------------------- /src/lib/supabase.jsx: -------------------------------------------------------------------------------- 1 | import { createClient } from "@supabase/supabase-js"; 2 | 3 | export const supabaseClient = createClient( 4 | process.env.NEXT_PUBLIC_SUPABASE_URL, 5 | process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY 6 | ); 7 | 8 | export const createSupabaseServerClient = () => 9 | createClient( 10 | process.env.NEXT_PUBLIC_SUPABASE_URL, 11 | process.env.SUPABASE_SERVICE_ROLE_KEY, 12 | { 13 | auth: { 14 | persistSession: false, 15 | autoRefreshToken: false, 16 | }, 17 | } 18 | ); 19 | -------------------------------------------------------------------------------- /src/locales/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Deutsch", 3 | "translator": "Anonymous translator", 4 | "panelTitles": { 5 | "style": "Ordnerstil", 6 | "color": "Ordnerfarbe", 7 | "icon": "Ordnersymbol", 8 | "smallConfig": "Konfiguration für kleine Ordner", 9 | "image": "Symbol-Bild", 10 | "offset": "Symbol-Versatz", 11 | "config": "Symbol-Konfiguration" 12 | }, 13 | "smallFolderConfig": { 14 | "squareAndIcon": "Symbol mit Box-Hintergrund anzeigen", 15 | "iconOnly": "Nur Symbol anzeigen", 16 | "folderOnly": "Nur Ordner anzeigen", 17 | "folderAndIcon": "Ordner mit Symbol anzeigen" 18 | }, 19 | "folderConfig": { 20 | "gradient": "Farbverlauf", 21 | "solid": "Einfarbig", 22 | "original": "Original", 23 | "gradientStart": "Erstfarbe Farbverlauf", 24 | "gradientEnd": "Zweitfarbe Farbverlauf", 25 | "solidColor": "Einfarbig" 26 | }, 27 | "iconTypes": { 28 | "lucide": "Lucide (gewöhnliche Symbole)", 29 | "simple": "SimpleIcons (Logos)", 30 | "custom": "Hochladen (PNG, SVG oder JPEG)", 31 | "none": "Keins" 32 | }, 33 | "iconConfig": { 34 | "shadow": "Symbol-Schatten", 35 | "mask": "Symbol der Ordnergröße anpassen", 36 | "color": "Symbol-Farbe", 37 | "current": "Aktuelles Symbol:", 38 | "browse": "Suchen", 39 | "x": "X", 40 | "y": "Y", 41 | "scale": "Skala", 42 | "stroke": "Symbol-Linienbreite", 43 | "opacity": "Symbol-Opazität" 44 | }, 45 | "credits": { 46 | "title": "Impressum", 47 | "created": "Erstellt von:", 48 | "icons": "Symbole von:", 49 | "translations": "Übersetzungen von:", 50 | "special": "Danksagungen:", 51 | "donators": "Spender:", 52 | "fonts": "Verwendete Schriftarten:", 53 | "contributors": "Mitwirkende:", 54 | "help": "Du möchtest beim Übersetzen helfen? %Steig mit ein!%" 55 | }, 56 | "download": { 57 | "counter": "ordner weltweit heruntergeladen!", 58 | "download": "Herunterladen", 59 | "allSizes": "Alle Größen (ZIP-Datei)", 60 | "ico": ".ICO (Windows & Linux)", 61 | "icns": ".ICNS (macOS)", 62 | "png": ".PNG", 63 | "1024": "1024x1024", 64 | "512": "512x512", 65 | "256": "256x256", 66 | "128": "128x128", 67 | "96": "96x96", 68 | "72": "72x72", 69 | "64": "64x64", 70 | "48": "48x48", 71 | "32": "32x32", 72 | "24": "24x24", 73 | "16": "16x16" 74 | }, 75 | "donation": { 76 | "front": "Präsentiert von Ko-fi-Spendern wie ", 77 | "back": ". Danke!" 78 | }, 79 | "firefox": { 80 | "title": "Firefox-Nutzer aufgepasst!", 81 | "content1": "Symbol-Skalierung in Firefox ist zurzeit fehlerhaft, und kleiner skalierte Symbole werden mit einer pixeligen Auflösung gerendert. Das ist ein Fehler seitens FIrefox, da die imageSmoothing-Eigenschaft in canvas aktuell nicht unterstützt wird.", 82 | "content2": "Bis der Fehler von Firefox behoben oder ein Umweg gefunden wird, empfehle ich Chromium-basierte Browser.", 83 | "content3": "Sorry für die Mühen :(" 84 | }, 85 | "modal": { 86 | "close": "Schließen" 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/locales/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "English", 3 | "translator": "EthanHazel", 4 | "panelTitles": { 5 | "style": "Folder Style", 6 | "color": "Folder Color", 7 | "icon": "Folder Icon", 8 | "smallConfig": "Small Folder Config", 9 | "image": "Icon Image", 10 | "offset": "Icon Offset", 11 | "config": "Icon Config" 12 | }, 13 | "smallFolderConfig": { 14 | "squareAndIcon": "Show icon with box background", 15 | "iconOnly": "Show icon only", 16 | "folderOnly": "Show folder only", 17 | "folderAndIcon": "Show folder with icon" 18 | }, 19 | "folderConfig": { 20 | "gradient": "Gradient", 21 | "solid": "Solid", 22 | "original": "Original", 23 | "gradientStart": "Gradient start color", 24 | "gradientEnd": "Gradient end color", 25 | "solidColor": "Solid color" 26 | }, 27 | "iconTypes": { 28 | "lucide": "Lucide (General Icons)", 29 | "simple": "SimpleIcons (Brand Logos)", 30 | "custom": "Upload (PNG, SVG, or JPEG)", 31 | "none": "None" 32 | }, 33 | "iconConfig": { 34 | "shadow": "Give icon shadow", 35 | "mask": "Mask icon to fit folder", 36 | "color": "Icon color", 37 | "current": "Current icon:", 38 | "browse": "Browse", 39 | "x": "X", 40 | "y": "Y", 41 | "scale": "Scale", 42 | "stroke": "Icon stroke width", 43 | "opacity": "Icon opacity" 44 | }, 45 | "credits": { 46 | "title": "Credits", 47 | "created": "Created by:", 48 | "icons": "Icons from:", 49 | "translations": "Translations by:", 50 | "special": "Special thanks:", 51 | "donators": "Donators:", 52 | "fonts": "Fonts used:", 53 | "contributors": "Contributors:", 54 | "help": "Want to help translate? %Help us out!%" 55 | }, 56 | "download": { 57 | "counter": "folders downloaded wordwide!", 58 | "download": "Download", 59 | "allSizes": "All Sizes (Packaged ZIP)", 60 | "ico": ".ICO (Windows & Linux)", 61 | "icns": ".ICNS (macOS)", 62 | "png": ".PNG", 63 | "1024": "1024x1024", 64 | "512": "512x512", 65 | "256": "256x256", 66 | "128": "128x128", 67 | "96": "96x96", 68 | "72": "72x72", 69 | "64": "64x64", 70 | "48": "48x48", 71 | "32": "32x32", 72 | "24": "24x24", 73 | "16": "16x16" 74 | }, 75 | "donation": { 76 | "front": "Presented by Ko-fi donators like ", 77 | "back": ". Thank you!" 78 | }, 79 | "firefox": { 80 | "title": "Attention Firefox user!", 81 | "content1": "Icon scaling in Firefox is currently bugged, and scaled down icons will be rendered with a more pixelated look to them. This is an issue with Firefox not currently supporting the imageSmoothing property on Canvas.", 82 | "content2": "Until Firefox implements this, or there's a work around found, I recommend using a Chromium based browser.", 83 | "content3": "Sorry for the inconvenience :(" 84 | }, 85 | "modal": { 86 | "close": "Close" 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/locales/es.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Español", 3 | "translator": "AsRenCL", 4 | "panelTitles": { 5 | "style": "Estilo de carpeta", 6 | "color": "Color de carpeta", 7 | "icon": "Ícono de carpeta", 8 | "smallConfig": "Posicionamiento de carpeta", 9 | "image": "Imagen de ícono", 10 | "offset": "Posición de ícono", 11 | "config": "Ajustes de ícono" 12 | }, 13 | "smallFolderConfig": { 14 | "squareAndIcon": "Mostrar ícono con fondo", 15 | "iconOnly": "Mostrar solo el ícono", 16 | "folderOnly": "Mostrar solo carpeta", 17 | "folderAndIcon": "Mostrar carpeta con ícono" 18 | }, 19 | "folderConfig": { 20 | "gradient": "Degradado", 21 | "solid": "Sólido", 22 | "original": "Original", 23 | "gradientStart": "Color inicial degradado", 24 | "gradientEnd": "Color final degradado", 25 | "solidColor": "Color sólido" 26 | }, 27 | "iconTypes": { 28 | "lucide": "Lucide (Íconos en general)", 29 | "simple": "SimpleIcons (Logotipos de marca)", 30 | "custom": "Subir (PNG, SVG o JPEG)", 31 | "none": "Ninguno" 32 | }, 33 | "iconConfig": { 34 | "shadow": "Agregar sombreado", 35 | "mask": "Ajustar ícono a carpeta", 36 | "color": "Color del ícono", 37 | "current": "Ícono seleccionado:", 38 | "browse": "Navegar", 39 | "x": "X", 40 | "y": "Y", 41 | "scale": "Escala", 42 | "stroke": "Ancho de línea del ícono", 43 | "opacity": "Opacidad del ícono" 44 | }, 45 | "credits": { 46 | "title": "Créditos", 47 | "created": "Hecho por:", 48 | "icons": "Íconos de:", 49 | "translations": "Traducciones por:", 50 | "special": "Agradecimientos especiales:", 51 | "donators": "Donadores:", 52 | "fonts": "Tipografías utilizadas:", 53 | "contributors": "Contribuidores:", 54 | "help": "¿Quieres ayudar a traducir? %¡Échanos una mano!%" 55 | }, 56 | "download": { 57 | "counter": "carpetas descargadas en todo el mundo!", 58 | "download": "Descargar", 59 | "allSizes": "Todos los tamaños (ZIP compreso)", 60 | "ico": ".ICO (Windows y Linux)", 61 | "icns": ".ICNS (macOS)", 62 | "png": ".PNG", 63 | "1024": "1024x1024", 64 | "512": "512x512", 65 | "256": "256x256", 66 | "128": "128x128", 67 | "96": "96x96", 68 | "72": "72x72", 69 | "64": "64x64", 70 | "48": "48x48", 71 | "32": "32x32", 72 | "24": "24x24", 73 | "16": "16x16" 74 | }, 75 | "donation": { 76 | "front": "Presentado a usted por donadores de Ko-fi como ", 77 | "back": ". ¡Muchas gracias!" 78 | }, 79 | "firefox": { 80 | "title": "¡Atención usuario de Firefox!", 81 | "content1": "La escala de íconos en Firefox tiene varios errores y los íconos reducidos serán renderizados con un aspecto más pixeleado. Este es un problema debido a que Firefox no tiene soporte con la propiedad de imageSmoothing en canvas.", 82 | "content2": "Hasta que Firefox implemente esto, o haya una alternativa, recomiendo utilizar un navegador basado en Chromium.", 83 | "content3": "Lamento las inconveniencias :(" 84 | }, 85 | "modal": { 86 | "close": "Cerrar" 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/locales/pl.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "Polski", 3 | "translator": "FadeMind", 4 | "panelTitles": { 5 | "style": "Styl folderu", 6 | "color": "Kolor folderu", 7 | "icon": "Ikona folderu", 8 | "smallConfig": "Konfiguracja małego folderu", 9 | "image": "Obraz ikony", 10 | "offset": "Przesunięcie ikony", 11 | "config": "Konfiguracja ikony" 12 | }, 13 | "smallFolderConfig": { 14 | "squareAndIcon": "Pokaż kwadratową ikonę", 15 | "iconOnly": "Pokaż tylko ikonę", 16 | "folderOnly": "Pokaż tylko folder", 17 | "folderAndIcon": "Pokaż folder z ikoną" 18 | }, 19 | "folderConfig": { 20 | "gradient": "Gradient", 21 | "solid": "Jednolity", 22 | "original": "Oryginalny", 23 | "gradientStart": "Początkowy kolor gradientu", 24 | "gradientEnd": "Końcowy kolor gradientu", 25 | "solidColor": "Jednolity kolor" 26 | }, 27 | "iconTypes": { 28 | "lucide": "Lucide (Ogólne ikony)", 29 | "simple": "SimpleIcons (Logotypy marek)", 30 | "custom": "Prześlij (PNG, SVG lub JPEG)", 31 | "none": "Brak" 32 | }, 33 | "iconConfig": { 34 | "shadow": "Dodaj cień do ikony", 35 | "mask": "Dopasuj ikonę do folderu", 36 | "color": "Kolor ikony", 37 | "current": "Aktualna ikona:", 38 | "browse": "Przeglądaj", 39 | "x": "X", 40 | "y": "Y", 41 | "scale": "Skala", 42 | "stroke": "Grubość obrysu ikony", 43 | "opacity": "Przezroczystość ikony" 44 | }, 45 | "credits": { 46 | "title": "Podziękowania", 47 | "created": "Stworzone przez:", 48 | "icons": "Ikony od:", 49 | "translations": "Tłumaczenie:", 50 | "special": "Szczególne podziękowania:", 51 | "donators": "Wspierający:", 52 | "fonts": "Użyte czcionki:", 53 | "contributors": "Współtwórcy:", 54 | "help": "Chcesz pomóc w tłumaczeniu? %Pomóż nam!%" 55 | }, 56 | "download": { 57 | "counter": "pobranych folderów na całym świecie!", 58 | "download": "Pobierz", 59 | "allSizes": "Wszystkie rozmiary (ZIP)", 60 | "ico": ".ICO (Windows i Linux)", 61 | "icns": ".ICNS (macOS)", 62 | "png": ".PNG", 63 | "1024": "1024x1024", 64 | "512": "512x512", 65 | "256": "256x256", 66 | "128": "128x128", 67 | "96": "96x96", 68 | "72": "72x72", 69 | "64": "64x64", 70 | "48": "48x48", 71 | "32": "32x32", 72 | "24": "24x24", 73 | "16": "16x16" 74 | }, 75 | "donation": { 76 | "front": "Prezentowane dzięki darczyńcom Ko-fi, takim jak ", 77 | "back": ". Dziękujemy!" 78 | }, 79 | "firefox": { 80 | "title": "Uwaga użytkowniku Firefoxa!", 81 | "content1": "Skalowanie ikon w Firefoxie jest obecnie błędne, a pomniejszone ikony wyglądają bardziej pikselowo. Jest to problem z brakiem obsługi właściwości imageSmoothing na Canvas przez Firefox.", 82 | "content2": "Dopóki Firefox tego nie naprawi lub nie znajdzie się obejście, zalecam korzystanie z przeglądarki opartej na Chromium.", 83 | "content3": "Przepraszamy za niedogodności :(" 84 | }, 85 | "modal": { 86 | "close": "Zamknij" 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/middleware.jsx: -------------------------------------------------------------------------------- 1 | import createMiddleware from "next-intl/middleware"; 2 | import { routing } from "./i18n/routing"; 3 | 4 | export default createMiddleware({ 5 | ...routing, 6 | localeDetection: true, 7 | }); 8 | 9 | export const config = { 10 | matcher: "/((?!api|trpc|_next|_vercel|.*\\..*).*)", 11 | }; 12 | -------------------------------------------------------------------------------- /src/stores/folder-config.jsx: -------------------------------------------------------------------------------- 1 | import { create } from "zustand"; 2 | 3 | export const folderConfigStore = create((set) => ({ 4 | // "linear-gradient", "solid", "original" 5 | colorType: "linear-gradient", 6 | setColorType: (colorType) => set({ colorType }), 7 | gradientStartColor: "#6acbff", 8 | setGradientStartColor: (color) => set({ gradientStartColor: color }), 9 | gradientEndColor: "#1026ef", 10 | setGradientEndColor: (color) => set({ gradientEndColor: color }), 11 | solidColor: "#eb898b", 12 | setSolidColor: (color) => set({ solidColor: color }), 13 | 14 | // "sqaureAndIcon", "folderAndIcon", "folderOnly" 15 | folderSmallType: "sqaureAndIcon", 16 | setFolderSmallType: (folderSmallType) => set({ folderSmallType }), 17 | 18 | // "win10", "win11" 19 | folderType: "win11", 20 | setFolderType: (folderType) => set({ folderType }), 21 | 22 | // "lucide", "simple", "custom", "none" 23 | iconType: "lucide", 24 | setIconType: (type) => set({ iconType: type }), 25 | 26 | lucideSlug: "Image", 27 | setLucideSlug: (slug) => set({ lucideSlug: slug }), 28 | lucideStrokeWidth: 1.5, 29 | setLucideStrokeWidth: (width) => set({ lucideStrokeWidth: width }), 30 | 31 | simpleSlug: "simpleicons", 32 | setSimpleSlug: (slug) => set({ simpleSlug: slug }), 33 | 34 | customData: null, 35 | setCustomData: (data) => set({ customIconData: data }), 36 | customFileName: null, 37 | setCustomFileName: (name) => set({ customFileName: name }), 38 | 39 | iconOffset: [0, 0], 40 | setIconOffset: (offset) => set({ iconOffset: offset }), 41 | iconScale: 0.5, 42 | setIconScale: (scale) => set({ iconScale: scale }), 43 | iconColor: "#ffffff", 44 | setIconColor: (color) => set({ iconColor: color }), 45 | iconOpacity: 1, 46 | setIconOpacity: (opacity) => set({ iconOpacity: opacity }), 47 | iconShadow: true, 48 | setIconShadow: (shadow) => set({ iconShadow: shadow }), 49 | iconMasked: true, 50 | setIconMasked: (contained) => set({ iconMasked: contained }), 51 | })); 52 | 53 | export function getIconAnchor(folderType, folderSize) { 54 | if (folderType === "win11") { 55 | const offsets = { 56 | 512: [0, 26], 57 | 256: [0, 13], 58 | 128: [0, 6.5], 59 | 96: [0, 4], 60 | 72: [0, 3], 61 | 64: [0, 3], 62 | 48: [0, 1.5], 63 | 32: [0, 1], 64 | 24: [0, 1], 65 | 16: [0, 1], 66 | }; 67 | return offsets[folderSize] || [0, 0]; 68 | } else if (folderType === "win10") { 69 | const offsets = { 70 | 512: [96, 72], 71 | 256: [48, 36], 72 | 128: [24, 18], 73 | 96: [18, 12], 74 | 72: [14, 12], 75 | 64: [12, 9], 76 | 48: [9, 6], 77 | 32: [6, 6], 78 | 24: [5, 4], 79 | 16: [0, 0], 80 | }; 81 | return offsets[folderSize] || [0, 0]; 82 | } else if (folderType == "bigsur") { 83 | const offsets = { 84 | 1024: [0, 64], 85 | 512: [0, 32], 86 | 256: [0, 16], 87 | 128: [0, 8], 88 | 64: [0, 4], 89 | 32: [0, 2], 90 | 16: [0, 1], 91 | }; 92 | return offsets[folderSize] || [0, 0]; 93 | } else if (folderType == "mint-l") { 94 | const offsets = { 95 | 512: [0, 32], 96 | 256: [0, 16], 97 | 128: [0, 8], 98 | 96: [0, 6], 99 | 64: [0, 4], 100 | 48: [0, 3], 101 | 32: [0, 2], 102 | 24: [0, 2], 103 | 16: [0, 1], 104 | }; 105 | return offsets[folderSize] || [0, 0]; 106 | } else { 107 | return [0, 0]; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/styles/credits.css: -------------------------------------------------------------------------------- 1 | .credit { 2 | display: flex; 3 | flex-direction: row; 4 | align-items: flex-start; 5 | justify-content: space-between; 6 | margin: 0.5rem 0; 7 | gap: 1rem; 8 | width: 100%; 9 | } 10 | 11 | .credit-header { 12 | margin: 0; 13 | width: 50%; 14 | text-align: right; 15 | color: var(--tertiary); 16 | } 17 | 18 | .credit-content { 19 | display: flex; 20 | flex-direction: column; 21 | gap: 0.5rem; 22 | width: 100%; 23 | } 24 | 25 | .credit-translation { 26 | display: flex; 27 | flex-direction: row; 28 | gap: 0.5rem; 29 | width: 100%; 30 | } 31 | 32 | .credit-translation-name { 33 | font-weight: 600; 34 | color: var(--tertiary); 35 | } 36 | -------------------------------------------------------------------------------- /src/styles/folder.css: -------------------------------------------------------------------------------- 1 | .folder-icon-container { 2 | display: flex; 3 | justify-content: center; 4 | align-items: center; 5 | border: 1px solid var(--accent); 6 | border-radius: 0.5rem; 7 | padding: 1rem; 8 | flex-direction: column; 9 | background-color: var(--bg-accent); 10 | } 11 | 12 | .folder-size { 13 | font-size: 0.8rem; 14 | margin-top: 0.5rem; 15 | text-align: center; 16 | color: var(--tertiary); 17 | } 18 | -------------------------------------------------------------------------------- /src/styles/footer.css: -------------------------------------------------------------------------------- 1 | #footer { 2 | display: flex; 3 | position: fixed; 4 | flex-direction: row; 5 | bottom: 0; 6 | left: 0; 7 | width: calc(100% - 2rem); 8 | padding: 1rem; 9 | justify-content: space-between; 10 | align-items: center; 11 | height: 2.5rem; 12 | border-top: 1px solid var(--accent); 13 | box-shadow: rgba(0, 0, 0, 0.04) 0px 3px 5px; 14 | background-color: var(--bg); 15 | } 16 | 17 | #download-container { 18 | display: flex; 19 | flex-direction: row; 20 | gap: 1rem; 21 | align-items: center; 22 | } 23 | 24 | #donators { 25 | font-size: 0.8rem; 26 | color: var(--tertiary); 27 | margin-left: 1.25rem; 28 | display: flex; 29 | flex-direction: row; 30 | align-items: center; 31 | } 32 | 33 | #donators svg { 34 | margin-right: 1.5rem; 35 | color: var(--text); 36 | } 37 | 38 | #donator { 39 | margin-left: 0.25rem; 40 | color: var(--text); 41 | } 42 | -------------------------------------------------------------------------------- /src/styles/globals.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --lm-bg: #fff; 3 | --lm-bg-accent: #f9fafc; 4 | --lm-text: #1f2937; 5 | --lm-accent: #e5e7eb; 6 | --lm-secondary: #ccc; 7 | --lm-tertiary: #888; 8 | --lm-quaternary: #666; 9 | 10 | --dm-bg: #000000; 11 | --dm-bg-accent: #060606; 12 | --dm-text: #d2d2d2; 13 | --dm-accent: #111111; 14 | --dm-secondary: #3a3a3a; 15 | --dm-tertiary: #6d6d6d; 16 | --dm-quaternary: #9d9d9d; 17 | 18 | --bg: var(--lm-bg); 19 | --bg-accent: var(--lm-bg-accent); 20 | --text: var(--lm-text); 21 | --accent: var(--lm-accent); 22 | --secondary: var(--lm-secondary); 23 | --tertiary: var(--lm-tertiary); 24 | --quarternary: var(--lm-quaternary); 25 | 26 | --primary: #3d78f7; 27 | 28 | --header-font: "Syne", sans-serif; 29 | --body-font: "Inter", "Noto Sans", sans-serif; 30 | } 31 | 32 | body.dark { 33 | --bg: var(--dm-bg); 34 | --bg-accent: var(--dm-bg-accent); 35 | --text: var(--dm-text); 36 | --accent: var(--dm-accent); 37 | --secondary: var(--dm-secondary); 38 | --tertiary: var(--dm-tertiary); 39 | --quarternary: var(--dm-quaternary); 40 | } 41 | 42 | * { 43 | transition: background-color 0.1s, color 0.1s, border 0.1s; 44 | } 45 | 46 | @font-face { 47 | font-family: "Syne"; 48 | font-weight: 100 900; 49 | font-stretch: normal; 50 | font-style: normal; 51 | src: url("/fonts/syne.woff2") format("woff2-variations"); 52 | } 53 | 54 | @font-face { 55 | font-family: "Inter"; 56 | font-weight: 100 900; 57 | font-stretch: normal; 58 | font-style: normal; 59 | src: url("/fonts/inter.woff2") format("woff2-variations"); 60 | } 61 | 62 | @font-face { 63 | font-family: "Noto Sans"; 64 | font-weight: 100 900; 65 | font-stretch: normal; 66 | font-style: normal; 67 | src: url("/fonts/noto.woff2") format("woff2-variations"); 68 | } 69 | 70 | html { 71 | scroll-behavior: smooth; 72 | scrollbar-color: var(--tertiary) rgba(0, 0, 0, 0); 73 | scrollbar-width: thin; 74 | } 75 | 76 | body { 77 | font-family: var(--body-font); 78 | margin: 0; 79 | padding: 0; 80 | background: var(--bg); 81 | color: var(--text); 82 | } 83 | 84 | #left-container { 85 | display: flex; 86 | flex-direction: column; 87 | width: 600px; 88 | height: calc(100vh - 4rem - 4.5rem - 4.5rem - 1px); 89 | padding: 2rem; 90 | gap: 2rem; 91 | overflow-y: auto; 92 | background-color: var(--bg-accent); 93 | border-right: 1px solid var(--accent); 94 | box-shadow: rgba(0, 0, 0, 0.06) 0px 2px 4px 0px inset; 95 | position: fixed; 96 | top: 4.5rem; 97 | } 98 | 99 | #right-container { 100 | background-color: var(--bg); 101 | display: flex; 102 | flex-direction: row; 103 | width: calc(100% - 600px - 4rem); 104 | height: 100vh; 105 | justify-content: center; 106 | align-items: center; 107 | position: fixed; 108 | top: 0; 109 | right: 0; 110 | gap: 1rem; 111 | } 112 | 113 | .radio-list { 114 | display: flex; 115 | flex-direction: column; 116 | gap: 0.5rem; 117 | } 118 | 119 | .hidden { 120 | display: none; 121 | } 122 | 123 | #small-folders { 124 | display: flex; 125 | flex-direction: column; 126 | gap: 1rem; 127 | align-items: flex-start; 128 | justify-content: flex-start; 129 | } 130 | 131 | button, 132 | input[type="file"]::file-selector-button, 133 | input[type="button"], 134 | input[type="submit"] { 135 | cursor: pointer; 136 | user-select: none; 137 | border: none; 138 | border-radius: 0.5rem; 139 | background-color: var(--primary); 140 | color: var(--bg); 141 | padding: 0.5rem 1rem; 142 | font-family: var(--body-font); 143 | transition: background-color 0.1s, color 0.1s, border 0.1s; 144 | } 145 | 146 | input[type="text"], 147 | input[type="number"] { 148 | border: 1px solid var(--secondary); 149 | border-radius: 0.5rem; 150 | background-color: var(--accent); 151 | color: var(--text); 152 | padding: 0.5rem 1rem; 153 | font-family: var(--body-font); 154 | transition: background-color 0.1s, color 0.1s, border 0.1s; 155 | } 156 | 157 | input[type="text"]:hover, 158 | input[type="number"]:hover { 159 | border: 1px solid var(--primary); 160 | } 161 | 162 | input[type="text"]:focus, 163 | input[type="number"]:focus { 164 | border: 1px solid var(--primary); 165 | outline: 2px solid var(--primary); 166 | } 167 | 168 | select { 169 | border: 1px solid var(--secondary); 170 | border-radius: 0.5rem; 171 | background-color: var(--accent); 172 | color: var(--text); 173 | padding: 0.5rem 1rem; 174 | font-family: var(--body-font); 175 | transition: background-color 0.1s, color 0.1s, border 0.1s; 176 | cursor: pointer; 177 | user-select: none; 178 | } 179 | 180 | a { 181 | color: var(--primary); 182 | text-decoration: none; 183 | } 184 | 185 | a:hover { 186 | text-decoration: underline; 187 | } 188 | 189 | a:visited { 190 | color: var(--primary); 191 | } 192 | 193 | a:visited:hover { 194 | text-decoration: underline; 195 | } 196 | 197 | a:active { 198 | color: var(--quarternary); 199 | } 200 | 201 | #style-input { 202 | display: flex; 203 | flex-direction: row; 204 | align-items: center; 205 | } 206 | 207 | #lod-config { 208 | display: flex; 209 | flex-direction: column; 210 | gap: 0.5rem; 211 | } 212 | 213 | .download-counter { 214 | font-size: 0.8rem; 215 | color: var(--tertiary); 216 | } 217 | -------------------------------------------------------------------------------- /src/styles/header.css: -------------------------------------------------------------------------------- 1 | #header { 2 | display: flex; 3 | flex-direction: row; 4 | align-items: center; 5 | justify-content: space-between; 6 | gap: 1rem; 7 | width: calc(100% - 3rem); 8 | background-color: var(--bg); 9 | padding: 1rem 1rem 1rem 2rem; 10 | box-shadow: rgba(0, 0, 0, 0.04) 0px 3px 5px; 11 | border-bottom: 1px solid var(--accent); 12 | position: fixed; 13 | top: 0; 14 | left: 0; 15 | z-index: 1; 16 | height: 2.5rem; 17 | background-color: var(--bg-accent); 18 | } 19 | 20 | .header-logo { 21 | display: flex; 22 | width: 1.5rem; 23 | align-items: center; 24 | justify-content: center; 25 | margin-left: 0.5rem; 26 | } 27 | 28 | .header-logo svg { 29 | width: 100%; 30 | height: 100%; 31 | overflow: visible; 32 | } 33 | 34 | .header-title { 35 | font-family: var(--header-font); 36 | font-size: 1rem; 37 | letter-spacing: 0.15rem; 38 | color: var(--quaternary); 39 | margin-left: 0.25rem; 40 | } 41 | 42 | .header-version { 43 | font-family: var(--header-font); 44 | font-size: 0.75rem; 45 | color: var(--secondary); 46 | margin-left: 0.25rem; 47 | } 48 | 49 | .header-container { 50 | display: flex; 51 | flex-direction: row; 52 | align-items: center; 53 | gap: 1rem; 54 | } 55 | 56 | .firefox-warning { 57 | display: flex; 58 | flex-direction: row; 59 | padding: 0.5rem 1rem; 60 | gap: 1rem; 61 | border-radius: 0.5rem; 62 | background-color: var(--bg-accent); 63 | border: 1px solid var(--secondary); 64 | font-size: 0.75rem; 65 | align-items: center; 66 | } 67 | 68 | .firefox-warning-icon { 69 | fill: var(--secondary); 70 | width: 1.25rem; 71 | height: 1.25rem; 72 | } 73 | -------------------------------------------------------------------------------- /src/styles/inputs/checkbox.css: -------------------------------------------------------------------------------- 1 | .checkbox { 2 | display: flex; 3 | flex-direction: row; 4 | align-items: center; 5 | cursor: pointer; 6 | padding: 0.5rem; 7 | border-radius: 0.5rem; 8 | user-select: none; 9 | gap: 0.5rem; 10 | } 11 | 12 | .checkbox:hover { 13 | background-color: var(--accent); 14 | } 15 | 16 | .checkbox-label { 17 | cursor: pointer; 18 | } 19 | 20 | .checkbox-input { 21 | display: none; 22 | } 23 | 24 | .checkbox-fake-input { 25 | display: inline-flex; 26 | width: 1rem; 27 | height: 1rem; 28 | border-radius: 0.25rem; 29 | border: 1px solid var(--secondary); 30 | background-color: rgba(255, 255, 255, 0); 31 | cursor: pointer; 32 | position: relative; 33 | margin-right: 0.5rem; 34 | transition: background-color 0.05s ease-in-out, border-color 0.05s ease-in-out; 35 | justify-content: center; 36 | align-items: center; 37 | } 38 | 39 | .checkbox-fake-input-inner { 40 | display: inline-block; 41 | width: 0.5rem; 42 | height: 0.5rem; 43 | transition: 0.1s ease-in-out; 44 | color: rgba(255, 255, 255, 0); 45 | } 46 | 47 | .checkbox-input:checked + .checkbox-fake-input .checkbox-fake-input-inner { 48 | color: var(--bg); 49 | width: 1rem; 50 | height: 1rem; 51 | } 52 | 53 | .checkbox-input:checked + .checkbox-fake-input { 54 | background-color: var(--primary); 55 | border-color: var(--primary); 56 | } 57 | -------------------------------------------------------------------------------- /src/styles/inputs/color.css: -------------------------------------------------------------------------------- 1 | .color { 2 | display: flex; 3 | flex-direction: row; 4 | align-items: center; 5 | justify-content: space-between; 6 | cursor: pointer; 7 | padding: 0.5rem; 8 | border-radius: 0.5rem; 9 | } 10 | 11 | .color-left { 12 | display: flex; 13 | flex-direction: row; 14 | align-items: center; 15 | gap: 1rem; 16 | } 17 | 18 | .color:hover { 19 | background-color: var(--accent); 20 | } 21 | 22 | .color-fake-input { 23 | display: inline-block; 24 | width: 1rem; 25 | height: 1rem; 26 | margin-left: -1.5px; 27 | border-radius: 0.5rem; 28 | outline: 1px solid var(--secondary); 29 | border: 2px solid var(--bg-accent); 30 | background-color: rgba(255, 255, 255, 0); 31 | cursor: pointer; 32 | } 33 | 34 | .color-input { 35 | opacity: 0; 36 | position: absolute; 37 | pointer-events: none; 38 | } 39 | 40 | .color-value { 41 | font-size: 0.8rem; 42 | color: var(--tertiary); 43 | } 44 | -------------------------------------------------------------------------------- /src/styles/inputs/dropdown.css: -------------------------------------------------------------------------------- 1 | .dropdown-content { 2 | display: none; 3 | padding: 1rem 0 0 2rem; 4 | flex-direction: column; 5 | gap: 0.5rem; 6 | } 7 | 8 | .dropdown-content.open { 9 | display: flex; 10 | } 11 | 12 | .dropdown-header { 13 | cursor: pointer; 14 | user-select: none; 15 | display: flex; 16 | flex-direction: row; 17 | align-items: center; 18 | gap: 1.75rem; 19 | width: calc(100% - 1.75rem); 20 | margin-top: 1rem; 21 | padding: 0.75rem; 22 | border-radius: 0.5rem; 23 | } 24 | 25 | .dropdown-header:hover { 26 | background-color: var(--accent); 27 | } 28 | 29 | .dropdown-divider { 30 | border: none; 31 | border-top: 1px solid var(--secondary); 32 | width: 100%; 33 | } 34 | 35 | .dropdown-icon, 36 | .dropdown-symbol { 37 | display: flex; 38 | align-items: center; 39 | justify-content: center; 40 | width: 20px; 41 | height: 20px; 42 | } 43 | 44 | .dropdown-symbol svg { 45 | color: var(--tertiary); 46 | } 47 | 48 | .dropdown-icon svg { 49 | transition: transform 0.1s ease-in-out; 50 | } 51 | 52 | .dropdown-icon svg.open { 53 | transform: rotate(90deg); 54 | } 55 | 56 | .dropdown-name { 57 | white-space: nowrap; 58 | } 59 | 60 | .dropdown-break { 61 | width: 100%; 62 | height: 0.5rem; 63 | } 64 | -------------------------------------------------------------------------------- /src/styles/inputs/header-button.css: -------------------------------------------------------------------------------- 1 | #header-buttons { 2 | display: flex; 3 | flex-direction: row; 4 | align-items: center; 5 | justify-content: flex-end; 6 | gap: 1.5rem; 7 | margin-right: 0.5rem; 8 | } 9 | 10 | .header-button { 11 | display: flex; 12 | align-items: center; 13 | justify-content: center; 14 | fill: var(--tertiary); 15 | color: var(--tertiary) !important; 16 | } 17 | 18 | #sun { 19 | display: none; 20 | } 21 | 22 | .dark #moon { 23 | display: none; 24 | } 25 | 26 | .dark #sun { 27 | display: block; 28 | } 29 | 30 | .header-button:hover { 31 | cursor: pointer; 32 | color: var(--secondary) !important; 33 | fill: var(--secondary); 34 | } 35 | 36 | .header-button:active { 37 | color: var(--accent) !important; 38 | fill: var(--accent); 39 | } 40 | 41 | .header-button-svg { 42 | width: 1.25rem; 43 | height: 1.25rem; 44 | } 45 | 46 | .header-button-divider { 47 | display: block; 48 | width: 2px; 49 | height: 0.5rem; 50 | background-color: var(--accent); 51 | margin: 0 1rem; 52 | } 53 | 54 | .header-button-label { 55 | position: absolute; 56 | transform: translateY(125%); 57 | font-size: 0.75rem; 58 | display: flex; 59 | flex-direction: row; 60 | align-items: center; 61 | justify-content: center; 62 | gap: 0.25rem; 63 | color: var(--tertiary); 64 | background-color: var(--bg-accent); 65 | border-radius: 0.5rem; 66 | padding: 0.5rem; 67 | border: 1px solid var(--accent); 68 | box-shadow: rgba(0, 0, 0, 0.04) 0px 3px 5px; 69 | transition: opacity 0.1s ease-in-out, background-color 0.1s, color 0.1s, 70 | border 0.1s; 71 | opacity: 0; 72 | pointer-events: none; 73 | z-index: 2; 74 | } 75 | 76 | .header-button:hover .header-button-label { 77 | opacity: 1; 78 | pointer-events: all; 79 | } 80 | -------------------------------------------------------------------------------- /src/styles/inputs/img-radio.css: -------------------------------------------------------------------------------- 1 | .img-radio-input { 2 | display: none; 3 | } 4 | 5 | .img-radio-input:checked + .img-radio-img { 6 | background-color: var(--secondary) !important; 7 | } 8 | 9 | .img-radio { 10 | display: flex; 11 | flex: 1; 12 | flex-direction: row; 13 | align-items: center; 14 | justify-content: center; 15 | cursor: pointer; 16 | padding: 1rem; 17 | border-radius: 0.5rem; 18 | user-select: none; 19 | gap: 0.5rem; 20 | width: fit-content; 21 | height: fit-content; 22 | } 23 | 24 | .img-radio:hover > .img-radio-img { 25 | background-color: var(--accent); 26 | } 27 | 28 | .img-radio-img { 29 | display: flex; 30 | padding: 0.5rem; 31 | border-radius: 0.5rem; 32 | } 33 | -------------------------------------------------------------------------------- /src/styles/inputs/radio.css: -------------------------------------------------------------------------------- 1 | .radio { 2 | display: flex; 3 | flex-direction: row; 4 | align-items: center; 5 | cursor: pointer; 6 | padding: 0.5rem; 7 | border-radius: 0.5rem; 8 | user-select: none; 9 | gap: 0.5rem; 10 | } 11 | 12 | .radio:hover { 13 | background-color: var(--accent); 14 | } 15 | 16 | .radio-label { 17 | cursor: pointer; 18 | } 19 | 20 | .radio-input { 21 | display: none; 22 | } 23 | 24 | .radio-fake-input { 25 | display: inline-block; 26 | width: 1rem; 27 | height: 1rem; 28 | border-radius: 50%; 29 | border: 1px solid var(--secondary); 30 | background-color: rgba(255, 255, 255, 0); 31 | cursor: pointer; 32 | position: relative; 33 | margin-right: 0.5rem; 34 | transition: background-color 0.05s ease-in-out, border-color 0.05s ease-in-out; 35 | } 36 | 37 | .radio-fake-input-inner { 38 | display: inline-block; 39 | width: 1rem; 40 | height: 1rem; 41 | border-radius: 50%; 42 | background-color: rgba(255, 255, 255, 0); 43 | position: absolute; 44 | top: 50%; 45 | left: 50%; 46 | transform: translate(-50%, -50%); 47 | transition: background-color 0.1s ease-in-out, width 0.1s ease-in-out, 48 | height 0.1s ease-in-out; 49 | } 50 | 51 | .radio-input:checked + .radio-fake-input .radio-fake-input-inner { 52 | background-color: var(--bg); 53 | width: 0.5rem; 54 | height: 0.5rem; 55 | } 56 | 57 | .radio-input:checked + .radio-fake-input { 58 | background-color: var(--primary); 59 | border-color: var(--primary); 60 | } 61 | -------------------------------------------------------------------------------- /src/styles/inputs/range.css: -------------------------------------------------------------------------------- 1 | .range { 2 | display: flex; 3 | flex-direction: row; 4 | align-items: center; 5 | gap: 0.5rem; 6 | width: calc(100% - 1rem - 2px); 7 | border: 1px solid var(--secondary); 8 | border-radius: 0.5rem; 9 | padding: 0 0.5rem; 10 | } 11 | 12 | .range-input-container { 13 | width: 100%; 14 | display: inline-flex; 15 | flex-direction: row; 16 | align-items: center; 17 | padding: 0px; 18 | margin: 0px; 19 | position: relative; 20 | } 21 | 22 | .range-input { 23 | width: 100%; 24 | appearance: none; 25 | background-color: var(--bg-accent); 26 | height: calc(2rem + 4px); 27 | margin: 0; 28 | border: 1px solid var(--secondary); 29 | border-style: none solid none solid; 30 | } 31 | 32 | .range-input::-moz-range-thumb { 33 | appearance: none; 34 | width: 1rem; 35 | height: 100%; 36 | border-radius: 0; 37 | background-color: var(--primary); 38 | border: none; 39 | cursor: pointer; 40 | } 41 | 42 | .range-input::-webkit-slider-thumb { 43 | appearance: none; 44 | width: 1rem; 45 | height: calc(2rem + 4px); 46 | border-radius: 0; 47 | border: none; 48 | cursor: pointer; 49 | background-color: var(--primary); 50 | } 51 | 52 | .range-background { 53 | height: calc(2rem + 4px); 54 | background-color: var(--primary); 55 | position: absolute; 56 | pointer-events: none; 57 | opacity: 0.5; 58 | } 59 | 60 | .range-label { 61 | white-space: nowrap; 62 | margin: 0.5rem; 63 | } 64 | 65 | .range-value { 66 | color: var(--tertiary); 67 | border-left: 1px solid var(--accent); 68 | padding: 0 1rem; 69 | text-align: center; 70 | width: 4rem; 71 | } 72 | 73 | .range-reset { 74 | background: none; 75 | color: var(--tertiary); 76 | } 77 | 78 | .range-reset svg { 79 | width: 1rem; 80 | height: 1rem; 81 | } 82 | -------------------------------------------------------------------------------- /src/styles/inputs/slug-input.css: -------------------------------------------------------------------------------- 1 | #slug-input { 2 | margin-bottom: 1rem; 3 | } 4 | 5 | #slug-input-container { 6 | display: flex; 7 | flex-direction: row; 8 | align-items: center; 9 | justify-content: space-between; 10 | width: 100%; 11 | gap: 1rem; 12 | } 13 | 14 | .slug { 15 | width: 100%; 16 | text-transform: lowercase; 17 | } 18 | 19 | .slug-input-right { 20 | display: flex; 21 | flex-direction: column; 22 | gap: 1rem; 23 | width: 100%; 24 | } 25 | 26 | .slug-button { 27 | display: flex; 28 | width: 48px; 29 | height: 48px; 30 | justify-content: center; 31 | align-items: center; 32 | border-radius: 0.5rem; 33 | } 34 | 35 | #slug-input-label { 36 | display: flex; 37 | flex-direction: row; 38 | justify-content: space-between; 39 | } 40 | 41 | #slug-input-right-container { 42 | display: flex; 43 | flex-direction: row; 44 | gap: 1rem; 45 | } 46 | 47 | #folder-icon-preview { 48 | width: 48px; 49 | height: 48px; 50 | border-radius: 0.5rem; 51 | border: 1px solid var(--secondary); 52 | background-color: var(--lm-accent); 53 | padding: 1rem; 54 | } 55 | 56 | @keyframes invalid { 57 | 0% { 58 | transform: translateX(0); 59 | opacity: 1; 60 | } 61 | 25% { 62 | transform: translateX(-0.5rem); 63 | } 64 | 50% { 65 | transform: translateX(0.5rem); 66 | opacity: 0; 67 | } 68 | 75% { 69 | transform: translateX(-0.5rem); 70 | } 71 | 100% { 72 | transform: translateX(0); 73 | opacity: 1; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/styles/modal.css: -------------------------------------------------------------------------------- 1 | .modal-container { 2 | display: flex; 3 | position: fixed; 4 | left: 0px; 5 | top: 0px; 6 | width: 100%; 7 | height: 100%; 8 | background-color: rgba(0, 0, 0, 0.5); 9 | z-index: 1; 10 | justify-content: center; 11 | align-items: center; 12 | backdrop-filter: blur(5px); 13 | z-index: 10; 14 | } 15 | 16 | .modal { 17 | display: flex; 18 | flex-direction: column; 19 | gap: 1rem; 20 | border-radius: 0.5rem; 21 | background-color: var(--bg-accent); 22 | box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 6px -1px, 23 | rgba(0, 0, 0, 0.06) 0px 2px 4px -1px; 24 | width: 720px; 25 | border: 1px solid var(--secondary); 26 | } 27 | 28 | .modal-header { 29 | display: flex; 30 | flex-direction: row; 31 | justify-content: space-between; 32 | align-items: center; 33 | gap: 1rem; 34 | border-bottom: 1px solid var(--accent); 35 | padding: 1rem; 36 | } 37 | 38 | .modal-title { 39 | font-weight: 600; 40 | margin: 0; 41 | } 42 | 43 | .modal-content { 44 | display: flex; 45 | flex-direction: column; 46 | gap: 1rem; 47 | padding: 1rem; 48 | } 49 | 50 | .modal-footer { 51 | display: flex; 52 | flex-direction: row; 53 | justify-content: flex-end; 54 | gap: 1rem; 55 | border-top: 1px solid var(--accent); 56 | padding: 1rem; 57 | } 58 | -------------------------------------------------------------------------------- /src/styles/view.css: -------------------------------------------------------------------------------- 1 | #mobile { 2 | display: none; 3 | } 4 | 5 | #mobile h1 { 6 | margin: 0; 7 | padding: 0; 8 | font-size: 2.5rem; 9 | font-family: var(--header-font); 10 | } 11 | 12 | #mobile h3 { 13 | margin: 0; 14 | padding: 0; 15 | font-size: 1.2rem; 16 | font-family: var(--body-font); 17 | } 18 | 19 | #mobile p { 20 | margin: 0; 21 | padding: 0; 22 | font-size: 0.8rem; 23 | font-family: var(--body-font); 24 | } 25 | 26 | .dark #mobile img { 27 | filter: invert(); 28 | } 29 | 30 | #small-folder-256 { 31 | display: none; 32 | } 33 | 34 | @media screen and (max-width: 1400px), screen and (max-height: 720px) { 35 | #small-folder-64, 36 | #small-folder-48, 37 | #big-folder-512 { 38 | display: none; 39 | } 40 | 41 | #small-folder-256 { 42 | display: flex; 43 | } 44 | 45 | #left-container { 46 | width: calc(50% - 4rem - 1px) !important; 47 | } 48 | 49 | #right-container { 50 | width: 50% !important; 51 | } 52 | } 53 | 54 | @media screen and (max-width: 980px), screen and (max-height: 500px) { 55 | #app { 56 | display: none; 57 | } 58 | 59 | #mobile { 60 | display: flex; 61 | flex-direction: column; 62 | align-items: center; 63 | justify-content: center; 64 | height: calc(100vh - 2rem); 65 | gap: 2rem; 66 | text-align: center; 67 | padding: 1rem; 68 | } 69 | } 70 | --------------------------------------------------------------------------------