├── .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 |
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 |
109 |
110 |
111 |
{t("icons")}
112 |
128 |
129 |
130 |
{t("fonts")}
131 |
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 |
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 |
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 |
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 |
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 |
--------------------------------------------------------------------------------