├── .github └── workflows │ └── build-and-deploy.yml ├── .gitignore ├── .node-version ├── .vscode └── settings.json ├── README.md ├── index.html ├── package.json ├── pnpm-lock.yaml ├── public ├── favicon.ico └── ogImage.png ├── src ├── App.tsx ├── Editor.tsx ├── Footer.tsx ├── Header.tsx ├── Menlo-Regular.woff ├── app.css ├── editor.css ├── footer.css ├── header.css ├── main.tsx ├── react-app-env.d.ts └── vite-env.d.ts ├── tsconfig.app.json ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts /.github/workflows/build-and-deploy.yml: -------------------------------------------------------------------------------- 1 | name: Build and Deploy 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | build-and-deploy: 8 | runs-on: ubuntu-latest 9 | permissions: 10 | contents: write 11 | 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v4 15 | 16 | - name: Setup Node.js 17 | uses: actions/setup-node@v4 18 | with: 19 | node-version: '23.5.0' 20 | 21 | - name: Setup pnpm 22 | uses: pnpm/action-setup@v2 23 | with: 24 | version: 10.4.1 25 | 26 | - name: Install dependencies 27 | run: pnpm install 28 | 29 | - name: Build 30 | run: pnpm run build 31 | 32 | - name: Deploy to GitHub Pages 33 | run: | 34 | git remote set-url origin https://git:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git 35 | git config user.name "github-actions[bot]" 36 | git config user.email "41898282+github-actions[bot]@users.noreply.github.com" 37 | pnpm run release 38 | env: 39 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | !.vscode/settings.json 19 | .idea 20 | .DS_Store 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? 26 | 27 | # TypeScript incremental compilation files 28 | *.tsbuildinfo -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | v23.5.0 -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.codeActionsOnSave": { 3 | "source.addMissingImports.ts": "explicit", 4 | "source.fixAll.ts": "explicit", 5 | "source.fixAll.typescript": "explicit", 6 | "source.organizeImports": "explicit", 7 | "source.organizeLinkDefinitions": "explicit", 8 | "source.sortImports": "explicit" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # project-tree-generator 2 | - 📦 Project Tree Generator 3 | - [📚 개발 후기글](https://velog.io/@_uchanlee/%EB%84%A4-%EB%A7%8C%EB%93%A4%EC%96%B4-%EB%93%9C%EB%A0%B8%EC%8A%B5%EB%8B%88%EB%8B%A4) 4 | 5 | 6 | ## [Play To Click 🎯](https://woochanleee.github.io/project-tree-generator) 7 | 8 | ## Screen Shots 9 | 10 | ### Feature 1 > Input your project tree and Copy tree 11 | 12 | ![My Movie 1](https://user-images.githubusercontent.com/48552260/114111695-99e1b100-9915-11eb-8396-8b6e9344a9b9.gif) 13 | 14 | ### Feature 2 > Generate tree by github repository() and branch(main) Copy tree 15 | 16 | ![My Movie 2](https://user-images.githubusercontent.com/48552260/114111751-ba117000-9915-11eb-8d36-80bf912de43d.gif) 17 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | Project Tree Generator 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "project-tree-generator", 3 | "homepage": "https://woochanleee.github.io/project-tree-generator", 4 | "type": "module", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "tsc -b && vite build", 8 | "preview": "vite preview", 9 | "release": "gh-pages -d dist" 10 | }, 11 | "dependencies": { 12 | "react": "^19.0.0", 13 | "react-dom": "^19.0.0" 14 | }, 15 | "devDependencies": { 16 | "@types/file-saver": "^2.0.7", 17 | "@types/react": "^19.0.2", 18 | "@types/react-dom": "^19.0.2", 19 | "@vitejs/plugin-react": "^4.3.4", 20 | "clipboard": "^2.0.8", 21 | "file-saver": "^2.0.5", 22 | "gh-pages": "^6.3.0", 23 | "globals": "^15.14.0", 24 | "jszip": "^3.6.0", 25 | "typescript": "^5.6.2", 26 | "vite": "^6.0.5" 27 | }, 28 | "packageManager": "pnpm@10.4.1" 29 | } 30 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | dependencies: 11 | react: 12 | specifier: ^19.0.0 13 | version: 19.0.0 14 | react-dom: 15 | specifier: ^19.0.0 16 | version: 19.0.0(react@19.0.0) 17 | devDependencies: 18 | '@types/file-saver': 19 | specifier: ^2.0.7 20 | version: 2.0.7 21 | '@types/react': 22 | specifier: ^19.0.2 23 | version: 19.0.2 24 | '@types/react-dom': 25 | specifier: ^19.0.2 26 | version: 19.0.2(@types/react@19.0.2) 27 | '@vitejs/plugin-react': 28 | specifier: ^4.3.4 29 | version: 4.3.4(vite@6.0.7) 30 | clipboard: 31 | specifier: ^2.0.8 32 | version: 2.0.11 33 | file-saver: 34 | specifier: ^2.0.5 35 | version: 2.0.5 36 | gh-pages: 37 | specifier: ^6.3.0 38 | version: 6.3.0 39 | globals: 40 | specifier: ^15.14.0 41 | version: 15.14.0 42 | jszip: 43 | specifier: ^3.6.0 44 | version: 3.10.1 45 | typescript: 46 | specifier: ^5.6.2 47 | version: 5.6.3 48 | vite: 49 | specifier: ^6.0.5 50 | version: 6.0.7 51 | 52 | packages: 53 | 54 | '@ampproject/remapping@2.3.0': 55 | resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} 56 | engines: {node: '>=6.0.0'} 57 | 58 | '@babel/code-frame@7.26.2': 59 | resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} 60 | engines: {node: '>=6.9.0'} 61 | 62 | '@babel/compat-data@7.26.3': 63 | resolution: {integrity: sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g==} 64 | engines: {node: '>=6.9.0'} 65 | 66 | '@babel/core@7.26.0': 67 | resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==} 68 | engines: {node: '>=6.9.0'} 69 | 70 | '@babel/generator@7.26.3': 71 | resolution: {integrity: sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==} 72 | engines: {node: '>=6.9.0'} 73 | 74 | '@babel/helper-compilation-targets@7.25.9': 75 | resolution: {integrity: sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==} 76 | engines: {node: '>=6.9.0'} 77 | 78 | '@babel/helper-module-imports@7.25.9': 79 | resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} 80 | engines: {node: '>=6.9.0'} 81 | 82 | '@babel/helper-module-transforms@7.26.0': 83 | resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} 84 | engines: {node: '>=6.9.0'} 85 | peerDependencies: 86 | '@babel/core': ^7.0.0 87 | 88 | '@babel/helper-plugin-utils@7.25.9': 89 | resolution: {integrity: sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==} 90 | engines: {node: '>=6.9.0'} 91 | 92 | '@babel/helper-string-parser@7.25.9': 93 | resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} 94 | engines: {node: '>=6.9.0'} 95 | 96 | '@babel/helper-validator-identifier@7.25.9': 97 | resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} 98 | engines: {node: '>=6.9.0'} 99 | 100 | '@babel/helper-validator-option@7.25.9': 101 | resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} 102 | engines: {node: '>=6.9.0'} 103 | 104 | '@babel/helpers@7.26.0': 105 | resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==} 106 | engines: {node: '>=6.9.0'} 107 | 108 | '@babel/parser@7.26.3': 109 | resolution: {integrity: sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==} 110 | engines: {node: '>=6.0.0'} 111 | hasBin: true 112 | 113 | '@babel/plugin-transform-react-jsx-self@7.25.9': 114 | resolution: {integrity: sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==} 115 | engines: {node: '>=6.9.0'} 116 | peerDependencies: 117 | '@babel/core': ^7.0.0-0 118 | 119 | '@babel/plugin-transform-react-jsx-source@7.25.9': 120 | resolution: {integrity: sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==} 121 | engines: {node: '>=6.9.0'} 122 | peerDependencies: 123 | '@babel/core': ^7.0.0-0 124 | 125 | '@babel/template@7.25.9': 126 | resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==} 127 | engines: {node: '>=6.9.0'} 128 | 129 | '@babel/traverse@7.26.4': 130 | resolution: {integrity: sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==} 131 | engines: {node: '>=6.9.0'} 132 | 133 | '@babel/types@7.26.3': 134 | resolution: {integrity: sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==} 135 | engines: {node: '>=6.9.0'} 136 | 137 | '@esbuild/aix-ppc64@0.24.2': 138 | resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==} 139 | engines: {node: '>=18'} 140 | cpu: [ppc64] 141 | os: [aix] 142 | 143 | '@esbuild/android-arm64@0.24.2': 144 | resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==} 145 | engines: {node: '>=18'} 146 | cpu: [arm64] 147 | os: [android] 148 | 149 | '@esbuild/android-arm@0.24.2': 150 | resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==} 151 | engines: {node: '>=18'} 152 | cpu: [arm] 153 | os: [android] 154 | 155 | '@esbuild/android-x64@0.24.2': 156 | resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==} 157 | engines: {node: '>=18'} 158 | cpu: [x64] 159 | os: [android] 160 | 161 | '@esbuild/darwin-arm64@0.24.2': 162 | resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==} 163 | engines: {node: '>=18'} 164 | cpu: [arm64] 165 | os: [darwin] 166 | 167 | '@esbuild/darwin-x64@0.24.2': 168 | resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==} 169 | engines: {node: '>=18'} 170 | cpu: [x64] 171 | os: [darwin] 172 | 173 | '@esbuild/freebsd-arm64@0.24.2': 174 | resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==} 175 | engines: {node: '>=18'} 176 | cpu: [arm64] 177 | os: [freebsd] 178 | 179 | '@esbuild/freebsd-x64@0.24.2': 180 | resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==} 181 | engines: {node: '>=18'} 182 | cpu: [x64] 183 | os: [freebsd] 184 | 185 | '@esbuild/linux-arm64@0.24.2': 186 | resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==} 187 | engines: {node: '>=18'} 188 | cpu: [arm64] 189 | os: [linux] 190 | 191 | '@esbuild/linux-arm@0.24.2': 192 | resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==} 193 | engines: {node: '>=18'} 194 | cpu: [arm] 195 | os: [linux] 196 | 197 | '@esbuild/linux-ia32@0.24.2': 198 | resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==} 199 | engines: {node: '>=18'} 200 | cpu: [ia32] 201 | os: [linux] 202 | 203 | '@esbuild/linux-loong64@0.24.2': 204 | resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==} 205 | engines: {node: '>=18'} 206 | cpu: [loong64] 207 | os: [linux] 208 | 209 | '@esbuild/linux-mips64el@0.24.2': 210 | resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==} 211 | engines: {node: '>=18'} 212 | cpu: [mips64el] 213 | os: [linux] 214 | 215 | '@esbuild/linux-ppc64@0.24.2': 216 | resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==} 217 | engines: {node: '>=18'} 218 | cpu: [ppc64] 219 | os: [linux] 220 | 221 | '@esbuild/linux-riscv64@0.24.2': 222 | resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==} 223 | engines: {node: '>=18'} 224 | cpu: [riscv64] 225 | os: [linux] 226 | 227 | '@esbuild/linux-s390x@0.24.2': 228 | resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==} 229 | engines: {node: '>=18'} 230 | cpu: [s390x] 231 | os: [linux] 232 | 233 | '@esbuild/linux-x64@0.24.2': 234 | resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==} 235 | engines: {node: '>=18'} 236 | cpu: [x64] 237 | os: [linux] 238 | 239 | '@esbuild/netbsd-arm64@0.24.2': 240 | resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==} 241 | engines: {node: '>=18'} 242 | cpu: [arm64] 243 | os: [netbsd] 244 | 245 | '@esbuild/netbsd-x64@0.24.2': 246 | resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==} 247 | engines: {node: '>=18'} 248 | cpu: [x64] 249 | os: [netbsd] 250 | 251 | '@esbuild/openbsd-arm64@0.24.2': 252 | resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==} 253 | engines: {node: '>=18'} 254 | cpu: [arm64] 255 | os: [openbsd] 256 | 257 | '@esbuild/openbsd-x64@0.24.2': 258 | resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==} 259 | engines: {node: '>=18'} 260 | cpu: [x64] 261 | os: [openbsd] 262 | 263 | '@esbuild/sunos-x64@0.24.2': 264 | resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==} 265 | engines: {node: '>=18'} 266 | cpu: [x64] 267 | os: [sunos] 268 | 269 | '@esbuild/win32-arm64@0.24.2': 270 | resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==} 271 | engines: {node: '>=18'} 272 | cpu: [arm64] 273 | os: [win32] 274 | 275 | '@esbuild/win32-ia32@0.24.2': 276 | resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==} 277 | engines: {node: '>=18'} 278 | cpu: [ia32] 279 | os: [win32] 280 | 281 | '@esbuild/win32-x64@0.24.2': 282 | resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==} 283 | engines: {node: '>=18'} 284 | cpu: [x64] 285 | os: [win32] 286 | 287 | '@jridgewell/gen-mapping@0.3.8': 288 | resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} 289 | engines: {node: '>=6.0.0'} 290 | 291 | '@jridgewell/resolve-uri@3.1.2': 292 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 293 | engines: {node: '>=6.0.0'} 294 | 295 | '@jridgewell/set-array@1.2.1': 296 | resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} 297 | engines: {node: '>=6.0.0'} 298 | 299 | '@jridgewell/sourcemap-codec@1.5.0': 300 | resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} 301 | 302 | '@jridgewell/trace-mapping@0.3.25': 303 | resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} 304 | 305 | '@nodelib/fs.scandir@2.1.5': 306 | resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} 307 | engines: {node: '>= 8'} 308 | 309 | '@nodelib/fs.stat@2.0.5': 310 | resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} 311 | engines: {node: '>= 8'} 312 | 313 | '@nodelib/fs.walk@1.2.8': 314 | resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} 315 | engines: {node: '>= 8'} 316 | 317 | '@rollup/rollup-android-arm-eabi@4.29.1': 318 | resolution: {integrity: sha512-ssKhA8RNltTZLpG6/QNkCSge+7mBQGUqJRisZ2MDQcEGaK93QESEgWK2iOpIDZ7k9zPVkG5AS3ksvD5ZWxmItw==} 319 | cpu: [arm] 320 | os: [android] 321 | 322 | '@rollup/rollup-android-arm64@4.29.1': 323 | resolution: {integrity: sha512-CaRfrV0cd+NIIcVVN/jx+hVLN+VRqnuzLRmfmlzpOzB87ajixsN/+9L5xNmkaUUvEbI5BmIKS+XTwXsHEb65Ew==} 324 | cpu: [arm64] 325 | os: [android] 326 | 327 | '@rollup/rollup-darwin-arm64@4.29.1': 328 | resolution: {integrity: sha512-2ORr7T31Y0Mnk6qNuwtyNmy14MunTAMx06VAPI6/Ju52W10zk1i7i5U3vlDRWjhOI5quBcrvhkCHyF76bI7kEw==} 329 | cpu: [arm64] 330 | os: [darwin] 331 | 332 | '@rollup/rollup-darwin-x64@4.29.1': 333 | resolution: {integrity: sha512-j/Ej1oanzPjmN0tirRd5K2/nncAhS9W6ICzgxV+9Y5ZsP0hiGhHJXZ2JQ53iSSjj8m6cRY6oB1GMzNn2EUt6Ng==} 334 | cpu: [x64] 335 | os: [darwin] 336 | 337 | '@rollup/rollup-freebsd-arm64@4.29.1': 338 | resolution: {integrity: sha512-91C//G6Dm/cv724tpt7nTyP+JdN12iqeXGFM1SqnljCmi5yTXriH7B1r8AD9dAZByHpKAumqP1Qy2vVNIdLZqw==} 339 | cpu: [arm64] 340 | os: [freebsd] 341 | 342 | '@rollup/rollup-freebsd-x64@4.29.1': 343 | resolution: {integrity: sha512-hEioiEQ9Dec2nIRoeHUP6hr1PSkXzQaCUyqBDQ9I9ik4gCXQZjJMIVzoNLBRGet+hIUb3CISMh9KXuCcWVW/8w==} 344 | cpu: [x64] 345 | os: [freebsd] 346 | 347 | '@rollup/rollup-linux-arm-gnueabihf@4.29.1': 348 | resolution: {integrity: sha512-Py5vFd5HWYN9zxBv3WMrLAXY3yYJ6Q/aVERoeUFwiDGiMOWsMs7FokXihSOaT/PMWUty/Pj60XDQndK3eAfE6A==} 349 | cpu: [arm] 350 | os: [linux] 351 | 352 | '@rollup/rollup-linux-arm-musleabihf@4.29.1': 353 | resolution: {integrity: sha512-RiWpGgbayf7LUcuSNIbahr0ys2YnEERD4gYdISA06wa0i8RALrnzflh9Wxii7zQJEB2/Eh74dX4y/sHKLWp5uQ==} 354 | cpu: [arm] 355 | os: [linux] 356 | 357 | '@rollup/rollup-linux-arm64-gnu@4.29.1': 358 | resolution: {integrity: sha512-Z80O+taYxTQITWMjm/YqNoe9d10OX6kDh8X5/rFCMuPqsKsSyDilvfg+vd3iXIqtfmp+cnfL1UrYirkaF8SBZA==} 359 | cpu: [arm64] 360 | os: [linux] 361 | 362 | '@rollup/rollup-linux-arm64-musl@4.29.1': 363 | resolution: {integrity: sha512-fOHRtF9gahwJk3QVp01a/GqS4hBEZCV1oKglVVq13kcK3NeVlS4BwIFzOHDbmKzt3i0OuHG4zfRP0YoG5OF/rA==} 364 | cpu: [arm64] 365 | os: [linux] 366 | 367 | '@rollup/rollup-linux-loongarch64-gnu@4.29.1': 368 | resolution: {integrity: sha512-5a7q3tnlbcg0OodyxcAdrrCxFi0DgXJSoOuidFUzHZ2GixZXQs6Tc3CHmlvqKAmOs5eRde+JJxeIf9DonkmYkw==} 369 | cpu: [loong64] 370 | os: [linux] 371 | 372 | '@rollup/rollup-linux-powerpc64le-gnu@4.29.1': 373 | resolution: {integrity: sha512-9b4Mg5Yfz6mRnlSPIdROcfw1BU22FQxmfjlp/CShWwO3LilKQuMISMTtAu/bxmmrE6A902W2cZJuzx8+gJ8e9w==} 374 | cpu: [ppc64] 375 | os: [linux] 376 | 377 | '@rollup/rollup-linux-riscv64-gnu@4.29.1': 378 | resolution: {integrity: sha512-G5pn0NChlbRM8OJWpJFMX4/i8OEU538uiSv0P6roZcbpe/WfhEO+AT8SHVKfp8qhDQzaz7Q+1/ixMy7hBRidnQ==} 379 | cpu: [riscv64] 380 | os: [linux] 381 | 382 | '@rollup/rollup-linux-s390x-gnu@4.29.1': 383 | resolution: {integrity: sha512-WM9lIkNdkhVwiArmLxFXpWndFGuOka4oJOZh8EP3Vb8q5lzdSCBuhjavJsw68Q9AKDGeOOIHYzYm4ZFvmWez5g==} 384 | cpu: [s390x] 385 | os: [linux] 386 | 387 | '@rollup/rollup-linux-x64-gnu@4.29.1': 388 | resolution: {integrity: sha512-87xYCwb0cPGZFoGiErT1eDcssByaLX4fc0z2nRM6eMtV9njAfEE6OW3UniAoDhX4Iq5xQVpE6qO9aJbCFumKYQ==} 389 | cpu: [x64] 390 | os: [linux] 391 | 392 | '@rollup/rollup-linux-x64-musl@4.29.1': 393 | resolution: {integrity: sha512-xufkSNppNOdVRCEC4WKvlR1FBDyqCSCpQeMMgv9ZyXqqtKBfkw1yfGMTUTs9Qsl6WQbJnsGboWCp7pJGkeMhKA==} 394 | cpu: [x64] 395 | os: [linux] 396 | 397 | '@rollup/rollup-win32-arm64-msvc@4.29.1': 398 | resolution: {integrity: sha512-F2OiJ42m77lSkizZQLuC+jiZ2cgueWQL5YC9tjo3AgaEw+KJmVxHGSyQfDUoYR9cci0lAywv2Clmckzulcq6ig==} 399 | cpu: [arm64] 400 | os: [win32] 401 | 402 | '@rollup/rollup-win32-ia32-msvc@4.29.1': 403 | resolution: {integrity: sha512-rYRe5S0FcjlOBZQHgbTKNrqxCBUmgDJem/VQTCcTnA2KCabYSWQDrytOzX7avb79cAAweNmMUb/Zw18RNd4mng==} 404 | cpu: [ia32] 405 | os: [win32] 406 | 407 | '@rollup/rollup-win32-x64-msvc@4.29.1': 408 | resolution: {integrity: sha512-+10CMg9vt1MoHj6x1pxyjPSMjHTIlqs8/tBztXvPAx24SKs9jwVnKqHJumlH/IzhaPUaj3T6T6wfZr8okdXaIg==} 409 | cpu: [x64] 410 | os: [win32] 411 | 412 | '@types/babel__core@7.20.5': 413 | resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} 414 | 415 | '@types/babel__generator@7.6.8': 416 | resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} 417 | 418 | '@types/babel__template@7.4.4': 419 | resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} 420 | 421 | '@types/babel__traverse@7.20.6': 422 | resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} 423 | 424 | '@types/estree@1.0.6': 425 | resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} 426 | 427 | '@types/file-saver@2.0.7': 428 | resolution: {integrity: sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==} 429 | 430 | '@types/react-dom@19.0.2': 431 | resolution: {integrity: sha512-c1s+7TKFaDRRxr1TxccIX2u7sfCnc3RxkVyBIUA2lCpyqCF+QoAwQ/CBg7bsMdVwP120HEH143VQezKtef5nCg==} 432 | peerDependencies: 433 | '@types/react': ^19.0.0 434 | 435 | '@types/react@19.0.2': 436 | resolution: {integrity: sha512-USU8ZI/xyKJwFTpjSVIrSeHBVAGagkHQKPNbxeWwql/vDmnTIBgx+TJnhFnj1NXgz8XfprU0egV2dROLGpsBEg==} 437 | 438 | '@vitejs/plugin-react@4.3.4': 439 | resolution: {integrity: sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug==} 440 | engines: {node: ^14.18.0 || >=16.0.0} 441 | peerDependencies: 442 | vite: ^4.2.0 || ^5.0.0 || ^6.0.0 443 | 444 | array-union@2.1.0: 445 | resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} 446 | engines: {node: '>=8'} 447 | 448 | async@3.2.6: 449 | resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} 450 | 451 | braces@3.0.3: 452 | resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} 453 | engines: {node: '>=8'} 454 | 455 | browserslist@4.24.3: 456 | resolution: {integrity: sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA==} 457 | engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} 458 | hasBin: true 459 | 460 | caniuse-lite@1.0.30001690: 461 | resolution: {integrity: sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==} 462 | 463 | clipboard@2.0.11: 464 | resolution: {integrity: sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==} 465 | 466 | commander@13.1.0: 467 | resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} 468 | engines: {node: '>=18'} 469 | 470 | commondir@1.0.1: 471 | resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} 472 | 473 | convert-source-map@2.0.0: 474 | resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} 475 | 476 | core-util-is@1.0.3: 477 | resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} 478 | 479 | csstype@3.1.3: 480 | resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} 481 | 482 | debug@4.4.0: 483 | resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} 484 | engines: {node: '>=6.0'} 485 | peerDependencies: 486 | supports-color: '*' 487 | peerDependenciesMeta: 488 | supports-color: 489 | optional: true 490 | 491 | delegate@3.2.0: 492 | resolution: {integrity: sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==} 493 | 494 | dir-glob@3.0.1: 495 | resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} 496 | engines: {node: '>=8'} 497 | 498 | electron-to-chromium@1.5.76: 499 | resolution: {integrity: sha512-CjVQyG7n7Sr+eBXE86HIulnL5N8xZY1sgmOPGuq/F0Rr0FJq63lg0kEtOIDfZBk44FnDLf6FUJ+dsJcuiUDdDQ==} 500 | 501 | email-addresses@5.0.0: 502 | resolution: {integrity: sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==} 503 | 504 | esbuild@0.24.2: 505 | resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==} 506 | engines: {node: '>=18'} 507 | hasBin: true 508 | 509 | escalade@3.2.0: 510 | resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} 511 | engines: {node: '>=6'} 512 | 513 | escape-string-regexp@1.0.5: 514 | resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} 515 | engines: {node: '>=0.8.0'} 516 | 517 | fast-glob@3.3.3: 518 | resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} 519 | engines: {node: '>=8.6.0'} 520 | 521 | fastq@1.19.0: 522 | resolution: {integrity: sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==} 523 | 524 | file-saver@2.0.5: 525 | resolution: {integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==} 526 | 527 | filename-reserved-regex@2.0.0: 528 | resolution: {integrity: sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==} 529 | engines: {node: '>=4'} 530 | 531 | filenamify@4.3.0: 532 | resolution: {integrity: sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==} 533 | engines: {node: '>=8'} 534 | 535 | fill-range@7.1.1: 536 | resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} 537 | engines: {node: '>=8'} 538 | 539 | find-cache-dir@3.3.2: 540 | resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} 541 | engines: {node: '>=8'} 542 | 543 | find-up@4.1.0: 544 | resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} 545 | engines: {node: '>=8'} 546 | 547 | fs-extra@11.3.0: 548 | resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==} 549 | engines: {node: '>=14.14'} 550 | 551 | fsevents@2.3.3: 552 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 553 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 554 | os: [darwin] 555 | 556 | gensync@1.0.0-beta.2: 557 | resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} 558 | engines: {node: '>=6.9.0'} 559 | 560 | gh-pages@6.3.0: 561 | resolution: {integrity: sha512-Ot5lU6jK0Eb+sszG8pciXdjMXdBJ5wODvgjR+imihTqsUWF2K6dJ9HST55lgqcs8wWcw6o6wAsUzfcYRhJPXbA==} 562 | engines: {node: '>=10'} 563 | hasBin: true 564 | 565 | glob-parent@5.1.2: 566 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 567 | engines: {node: '>= 6'} 568 | 569 | globals@11.12.0: 570 | resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} 571 | engines: {node: '>=4'} 572 | 573 | globals@15.14.0: 574 | resolution: {integrity: sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==} 575 | engines: {node: '>=18'} 576 | 577 | globby@11.1.0: 578 | resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} 579 | engines: {node: '>=10'} 580 | 581 | good-listener@1.2.2: 582 | resolution: {integrity: sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==} 583 | 584 | graceful-fs@4.2.11: 585 | resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} 586 | 587 | ignore@5.3.2: 588 | resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} 589 | engines: {node: '>= 4'} 590 | 591 | immediate@3.0.6: 592 | resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} 593 | 594 | inherits@2.0.4: 595 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 596 | 597 | is-extglob@2.1.1: 598 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 599 | engines: {node: '>=0.10.0'} 600 | 601 | is-glob@4.0.3: 602 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 603 | engines: {node: '>=0.10.0'} 604 | 605 | is-number@7.0.0: 606 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 607 | engines: {node: '>=0.12.0'} 608 | 609 | isarray@1.0.0: 610 | resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} 611 | 612 | js-tokens@4.0.0: 613 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} 614 | 615 | jsesc@3.1.0: 616 | resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} 617 | engines: {node: '>=6'} 618 | hasBin: true 619 | 620 | json5@2.2.3: 621 | resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} 622 | engines: {node: '>=6'} 623 | hasBin: true 624 | 625 | jsonfile@6.1.0: 626 | resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} 627 | 628 | jszip@3.10.1: 629 | resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} 630 | 631 | lie@3.3.0: 632 | resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} 633 | 634 | locate-path@5.0.0: 635 | resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} 636 | engines: {node: '>=8'} 637 | 638 | lru-cache@5.1.1: 639 | resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} 640 | 641 | make-dir@3.1.0: 642 | resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} 643 | engines: {node: '>=8'} 644 | 645 | merge2@1.4.1: 646 | resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} 647 | engines: {node: '>= 8'} 648 | 649 | micromatch@4.0.8: 650 | resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} 651 | engines: {node: '>=8.6'} 652 | 653 | ms@2.1.3: 654 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 655 | 656 | nanoid@3.3.8: 657 | resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} 658 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 659 | hasBin: true 660 | 661 | node-releases@2.0.19: 662 | resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} 663 | 664 | p-limit@2.3.0: 665 | resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} 666 | engines: {node: '>=6'} 667 | 668 | p-locate@4.1.0: 669 | resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} 670 | engines: {node: '>=8'} 671 | 672 | p-try@2.2.0: 673 | resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} 674 | engines: {node: '>=6'} 675 | 676 | pako@1.0.11: 677 | resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} 678 | 679 | path-exists@4.0.0: 680 | resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} 681 | engines: {node: '>=8'} 682 | 683 | path-type@4.0.0: 684 | resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} 685 | engines: {node: '>=8'} 686 | 687 | picocolors@1.1.1: 688 | resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 689 | 690 | picomatch@2.3.1: 691 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 692 | engines: {node: '>=8.6'} 693 | 694 | pkg-dir@4.2.0: 695 | resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} 696 | engines: {node: '>=8'} 697 | 698 | postcss@8.4.49: 699 | resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} 700 | engines: {node: ^10 || ^12 || >=14} 701 | 702 | process-nextick-args@2.0.1: 703 | resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} 704 | 705 | queue-microtask@1.2.3: 706 | resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} 707 | 708 | react-dom@19.0.0: 709 | resolution: {integrity: sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==} 710 | peerDependencies: 711 | react: ^19.0.0 712 | 713 | react-refresh@0.14.2: 714 | resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} 715 | engines: {node: '>=0.10.0'} 716 | 717 | react@19.0.0: 718 | resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} 719 | engines: {node: '>=0.10.0'} 720 | 721 | readable-stream@2.3.8: 722 | resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} 723 | 724 | reusify@1.0.4: 725 | resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} 726 | engines: {iojs: '>=1.0.0', node: '>=0.10.0'} 727 | 728 | rollup@4.29.1: 729 | resolution: {integrity: sha512-RaJ45M/kmJUzSWDs1Nnd5DdV4eerC98idtUOVr6FfKcgxqvjwHmxc5upLF9qZU9EpsVzzhleFahrT3shLuJzIw==} 730 | engines: {node: '>=18.0.0', npm: '>=8.0.0'} 731 | hasBin: true 732 | 733 | run-parallel@1.2.0: 734 | resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} 735 | 736 | safe-buffer@5.1.2: 737 | resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} 738 | 739 | scheduler@0.25.0: 740 | resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} 741 | 742 | select@1.1.2: 743 | resolution: {integrity: sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==} 744 | 745 | semver@6.3.1: 746 | resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} 747 | hasBin: true 748 | 749 | setimmediate@1.0.5: 750 | resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} 751 | 752 | slash@3.0.0: 753 | resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} 754 | engines: {node: '>=8'} 755 | 756 | source-map-js@1.2.1: 757 | resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 758 | engines: {node: '>=0.10.0'} 759 | 760 | string_decoder@1.1.1: 761 | resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} 762 | 763 | strip-outer@1.0.1: 764 | resolution: {integrity: sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==} 765 | engines: {node: '>=0.10.0'} 766 | 767 | tiny-emitter@2.1.0: 768 | resolution: {integrity: sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==} 769 | 770 | to-regex-range@5.0.1: 771 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 772 | engines: {node: '>=8.0'} 773 | 774 | trim-repeated@1.0.0: 775 | resolution: {integrity: sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==} 776 | engines: {node: '>=0.10.0'} 777 | 778 | typescript@5.6.3: 779 | resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} 780 | engines: {node: '>=14.17'} 781 | hasBin: true 782 | 783 | universalify@2.0.1: 784 | resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} 785 | engines: {node: '>= 10.0.0'} 786 | 787 | update-browserslist-db@1.1.1: 788 | resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} 789 | hasBin: true 790 | peerDependencies: 791 | browserslist: '>= 4.21.0' 792 | 793 | util-deprecate@1.0.2: 794 | resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} 795 | 796 | vite@6.0.7: 797 | resolution: {integrity: sha512-RDt8r/7qx9940f8FcOIAH9PTViRrghKaK2K1jY3RaAURrEUbm9Du1mJ72G+jlhtG3WwodnfzY8ORQZbBavZEAQ==} 798 | engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} 799 | hasBin: true 800 | peerDependencies: 801 | '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 802 | jiti: '>=1.21.0' 803 | less: '*' 804 | lightningcss: ^1.21.0 805 | sass: '*' 806 | sass-embedded: '*' 807 | stylus: '*' 808 | sugarss: '*' 809 | terser: ^5.16.0 810 | tsx: ^4.8.1 811 | yaml: ^2.4.2 812 | peerDependenciesMeta: 813 | '@types/node': 814 | optional: true 815 | jiti: 816 | optional: true 817 | less: 818 | optional: true 819 | lightningcss: 820 | optional: true 821 | sass: 822 | optional: true 823 | sass-embedded: 824 | optional: true 825 | stylus: 826 | optional: true 827 | sugarss: 828 | optional: true 829 | terser: 830 | optional: true 831 | tsx: 832 | optional: true 833 | yaml: 834 | optional: true 835 | 836 | yallist@3.1.1: 837 | resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} 838 | 839 | snapshots: 840 | 841 | '@ampproject/remapping@2.3.0': 842 | dependencies: 843 | '@jridgewell/gen-mapping': 0.3.8 844 | '@jridgewell/trace-mapping': 0.3.25 845 | 846 | '@babel/code-frame@7.26.2': 847 | dependencies: 848 | '@babel/helper-validator-identifier': 7.25.9 849 | js-tokens: 4.0.0 850 | picocolors: 1.1.1 851 | 852 | '@babel/compat-data@7.26.3': {} 853 | 854 | '@babel/core@7.26.0': 855 | dependencies: 856 | '@ampproject/remapping': 2.3.0 857 | '@babel/code-frame': 7.26.2 858 | '@babel/generator': 7.26.3 859 | '@babel/helper-compilation-targets': 7.25.9 860 | '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) 861 | '@babel/helpers': 7.26.0 862 | '@babel/parser': 7.26.3 863 | '@babel/template': 7.25.9 864 | '@babel/traverse': 7.26.4 865 | '@babel/types': 7.26.3 866 | convert-source-map: 2.0.0 867 | debug: 4.4.0 868 | gensync: 1.0.0-beta.2 869 | json5: 2.2.3 870 | semver: 6.3.1 871 | transitivePeerDependencies: 872 | - supports-color 873 | 874 | '@babel/generator@7.26.3': 875 | dependencies: 876 | '@babel/parser': 7.26.3 877 | '@babel/types': 7.26.3 878 | '@jridgewell/gen-mapping': 0.3.8 879 | '@jridgewell/trace-mapping': 0.3.25 880 | jsesc: 3.1.0 881 | 882 | '@babel/helper-compilation-targets@7.25.9': 883 | dependencies: 884 | '@babel/compat-data': 7.26.3 885 | '@babel/helper-validator-option': 7.25.9 886 | browserslist: 4.24.3 887 | lru-cache: 5.1.1 888 | semver: 6.3.1 889 | 890 | '@babel/helper-module-imports@7.25.9': 891 | dependencies: 892 | '@babel/traverse': 7.26.4 893 | '@babel/types': 7.26.3 894 | transitivePeerDependencies: 895 | - supports-color 896 | 897 | '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.0)': 898 | dependencies: 899 | '@babel/core': 7.26.0 900 | '@babel/helper-module-imports': 7.25.9 901 | '@babel/helper-validator-identifier': 7.25.9 902 | '@babel/traverse': 7.26.4 903 | transitivePeerDependencies: 904 | - supports-color 905 | 906 | '@babel/helper-plugin-utils@7.25.9': {} 907 | 908 | '@babel/helper-string-parser@7.25.9': {} 909 | 910 | '@babel/helper-validator-identifier@7.25.9': {} 911 | 912 | '@babel/helper-validator-option@7.25.9': {} 913 | 914 | '@babel/helpers@7.26.0': 915 | dependencies: 916 | '@babel/template': 7.25.9 917 | '@babel/types': 7.26.3 918 | 919 | '@babel/parser@7.26.3': 920 | dependencies: 921 | '@babel/types': 7.26.3 922 | 923 | '@babel/plugin-transform-react-jsx-self@7.25.9(@babel/core@7.26.0)': 924 | dependencies: 925 | '@babel/core': 7.26.0 926 | '@babel/helper-plugin-utils': 7.25.9 927 | 928 | '@babel/plugin-transform-react-jsx-source@7.25.9(@babel/core@7.26.0)': 929 | dependencies: 930 | '@babel/core': 7.26.0 931 | '@babel/helper-plugin-utils': 7.25.9 932 | 933 | '@babel/template@7.25.9': 934 | dependencies: 935 | '@babel/code-frame': 7.26.2 936 | '@babel/parser': 7.26.3 937 | '@babel/types': 7.26.3 938 | 939 | '@babel/traverse@7.26.4': 940 | dependencies: 941 | '@babel/code-frame': 7.26.2 942 | '@babel/generator': 7.26.3 943 | '@babel/parser': 7.26.3 944 | '@babel/template': 7.25.9 945 | '@babel/types': 7.26.3 946 | debug: 4.4.0 947 | globals: 11.12.0 948 | transitivePeerDependencies: 949 | - supports-color 950 | 951 | '@babel/types@7.26.3': 952 | dependencies: 953 | '@babel/helper-string-parser': 7.25.9 954 | '@babel/helper-validator-identifier': 7.25.9 955 | 956 | '@esbuild/aix-ppc64@0.24.2': 957 | optional: true 958 | 959 | '@esbuild/android-arm64@0.24.2': 960 | optional: true 961 | 962 | '@esbuild/android-arm@0.24.2': 963 | optional: true 964 | 965 | '@esbuild/android-x64@0.24.2': 966 | optional: true 967 | 968 | '@esbuild/darwin-arm64@0.24.2': 969 | optional: true 970 | 971 | '@esbuild/darwin-x64@0.24.2': 972 | optional: true 973 | 974 | '@esbuild/freebsd-arm64@0.24.2': 975 | optional: true 976 | 977 | '@esbuild/freebsd-x64@0.24.2': 978 | optional: true 979 | 980 | '@esbuild/linux-arm64@0.24.2': 981 | optional: true 982 | 983 | '@esbuild/linux-arm@0.24.2': 984 | optional: true 985 | 986 | '@esbuild/linux-ia32@0.24.2': 987 | optional: true 988 | 989 | '@esbuild/linux-loong64@0.24.2': 990 | optional: true 991 | 992 | '@esbuild/linux-mips64el@0.24.2': 993 | optional: true 994 | 995 | '@esbuild/linux-ppc64@0.24.2': 996 | optional: true 997 | 998 | '@esbuild/linux-riscv64@0.24.2': 999 | optional: true 1000 | 1001 | '@esbuild/linux-s390x@0.24.2': 1002 | optional: true 1003 | 1004 | '@esbuild/linux-x64@0.24.2': 1005 | optional: true 1006 | 1007 | '@esbuild/netbsd-arm64@0.24.2': 1008 | optional: true 1009 | 1010 | '@esbuild/netbsd-x64@0.24.2': 1011 | optional: true 1012 | 1013 | '@esbuild/openbsd-arm64@0.24.2': 1014 | optional: true 1015 | 1016 | '@esbuild/openbsd-x64@0.24.2': 1017 | optional: true 1018 | 1019 | '@esbuild/sunos-x64@0.24.2': 1020 | optional: true 1021 | 1022 | '@esbuild/win32-arm64@0.24.2': 1023 | optional: true 1024 | 1025 | '@esbuild/win32-ia32@0.24.2': 1026 | optional: true 1027 | 1028 | '@esbuild/win32-x64@0.24.2': 1029 | optional: true 1030 | 1031 | '@jridgewell/gen-mapping@0.3.8': 1032 | dependencies: 1033 | '@jridgewell/set-array': 1.2.1 1034 | '@jridgewell/sourcemap-codec': 1.5.0 1035 | '@jridgewell/trace-mapping': 0.3.25 1036 | 1037 | '@jridgewell/resolve-uri@3.1.2': {} 1038 | 1039 | '@jridgewell/set-array@1.2.1': {} 1040 | 1041 | '@jridgewell/sourcemap-codec@1.5.0': {} 1042 | 1043 | '@jridgewell/trace-mapping@0.3.25': 1044 | dependencies: 1045 | '@jridgewell/resolve-uri': 3.1.2 1046 | '@jridgewell/sourcemap-codec': 1.5.0 1047 | 1048 | '@nodelib/fs.scandir@2.1.5': 1049 | dependencies: 1050 | '@nodelib/fs.stat': 2.0.5 1051 | run-parallel: 1.2.0 1052 | 1053 | '@nodelib/fs.stat@2.0.5': {} 1054 | 1055 | '@nodelib/fs.walk@1.2.8': 1056 | dependencies: 1057 | '@nodelib/fs.scandir': 2.1.5 1058 | fastq: 1.19.0 1059 | 1060 | '@rollup/rollup-android-arm-eabi@4.29.1': 1061 | optional: true 1062 | 1063 | '@rollup/rollup-android-arm64@4.29.1': 1064 | optional: true 1065 | 1066 | '@rollup/rollup-darwin-arm64@4.29.1': 1067 | optional: true 1068 | 1069 | '@rollup/rollup-darwin-x64@4.29.1': 1070 | optional: true 1071 | 1072 | '@rollup/rollup-freebsd-arm64@4.29.1': 1073 | optional: true 1074 | 1075 | '@rollup/rollup-freebsd-x64@4.29.1': 1076 | optional: true 1077 | 1078 | '@rollup/rollup-linux-arm-gnueabihf@4.29.1': 1079 | optional: true 1080 | 1081 | '@rollup/rollup-linux-arm-musleabihf@4.29.1': 1082 | optional: true 1083 | 1084 | '@rollup/rollup-linux-arm64-gnu@4.29.1': 1085 | optional: true 1086 | 1087 | '@rollup/rollup-linux-arm64-musl@4.29.1': 1088 | optional: true 1089 | 1090 | '@rollup/rollup-linux-loongarch64-gnu@4.29.1': 1091 | optional: true 1092 | 1093 | '@rollup/rollup-linux-powerpc64le-gnu@4.29.1': 1094 | optional: true 1095 | 1096 | '@rollup/rollup-linux-riscv64-gnu@4.29.1': 1097 | optional: true 1098 | 1099 | '@rollup/rollup-linux-s390x-gnu@4.29.1': 1100 | optional: true 1101 | 1102 | '@rollup/rollup-linux-x64-gnu@4.29.1': 1103 | optional: true 1104 | 1105 | '@rollup/rollup-linux-x64-musl@4.29.1': 1106 | optional: true 1107 | 1108 | '@rollup/rollup-win32-arm64-msvc@4.29.1': 1109 | optional: true 1110 | 1111 | '@rollup/rollup-win32-ia32-msvc@4.29.1': 1112 | optional: true 1113 | 1114 | '@rollup/rollup-win32-x64-msvc@4.29.1': 1115 | optional: true 1116 | 1117 | '@types/babel__core@7.20.5': 1118 | dependencies: 1119 | '@babel/parser': 7.26.3 1120 | '@babel/types': 7.26.3 1121 | '@types/babel__generator': 7.6.8 1122 | '@types/babel__template': 7.4.4 1123 | '@types/babel__traverse': 7.20.6 1124 | 1125 | '@types/babel__generator@7.6.8': 1126 | dependencies: 1127 | '@babel/types': 7.26.3 1128 | 1129 | '@types/babel__template@7.4.4': 1130 | dependencies: 1131 | '@babel/parser': 7.26.3 1132 | '@babel/types': 7.26.3 1133 | 1134 | '@types/babel__traverse@7.20.6': 1135 | dependencies: 1136 | '@babel/types': 7.26.3 1137 | 1138 | '@types/estree@1.0.6': {} 1139 | 1140 | '@types/file-saver@2.0.7': {} 1141 | 1142 | '@types/react-dom@19.0.2(@types/react@19.0.2)': 1143 | dependencies: 1144 | '@types/react': 19.0.2 1145 | 1146 | '@types/react@19.0.2': 1147 | dependencies: 1148 | csstype: 3.1.3 1149 | 1150 | '@vitejs/plugin-react@4.3.4(vite@6.0.7)': 1151 | dependencies: 1152 | '@babel/core': 7.26.0 1153 | '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0) 1154 | '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0) 1155 | '@types/babel__core': 7.20.5 1156 | react-refresh: 0.14.2 1157 | vite: 6.0.7 1158 | transitivePeerDependencies: 1159 | - supports-color 1160 | 1161 | array-union@2.1.0: {} 1162 | 1163 | async@3.2.6: {} 1164 | 1165 | braces@3.0.3: 1166 | dependencies: 1167 | fill-range: 7.1.1 1168 | 1169 | browserslist@4.24.3: 1170 | dependencies: 1171 | caniuse-lite: 1.0.30001690 1172 | electron-to-chromium: 1.5.76 1173 | node-releases: 2.0.19 1174 | update-browserslist-db: 1.1.1(browserslist@4.24.3) 1175 | 1176 | caniuse-lite@1.0.30001690: {} 1177 | 1178 | clipboard@2.0.11: 1179 | dependencies: 1180 | good-listener: 1.2.2 1181 | select: 1.1.2 1182 | tiny-emitter: 2.1.0 1183 | 1184 | commander@13.1.0: {} 1185 | 1186 | commondir@1.0.1: {} 1187 | 1188 | convert-source-map@2.0.0: {} 1189 | 1190 | core-util-is@1.0.3: {} 1191 | 1192 | csstype@3.1.3: {} 1193 | 1194 | debug@4.4.0: 1195 | dependencies: 1196 | ms: 2.1.3 1197 | 1198 | delegate@3.2.0: {} 1199 | 1200 | dir-glob@3.0.1: 1201 | dependencies: 1202 | path-type: 4.0.0 1203 | 1204 | electron-to-chromium@1.5.76: {} 1205 | 1206 | email-addresses@5.0.0: {} 1207 | 1208 | esbuild@0.24.2: 1209 | optionalDependencies: 1210 | '@esbuild/aix-ppc64': 0.24.2 1211 | '@esbuild/android-arm': 0.24.2 1212 | '@esbuild/android-arm64': 0.24.2 1213 | '@esbuild/android-x64': 0.24.2 1214 | '@esbuild/darwin-arm64': 0.24.2 1215 | '@esbuild/darwin-x64': 0.24.2 1216 | '@esbuild/freebsd-arm64': 0.24.2 1217 | '@esbuild/freebsd-x64': 0.24.2 1218 | '@esbuild/linux-arm': 0.24.2 1219 | '@esbuild/linux-arm64': 0.24.2 1220 | '@esbuild/linux-ia32': 0.24.2 1221 | '@esbuild/linux-loong64': 0.24.2 1222 | '@esbuild/linux-mips64el': 0.24.2 1223 | '@esbuild/linux-ppc64': 0.24.2 1224 | '@esbuild/linux-riscv64': 0.24.2 1225 | '@esbuild/linux-s390x': 0.24.2 1226 | '@esbuild/linux-x64': 0.24.2 1227 | '@esbuild/netbsd-arm64': 0.24.2 1228 | '@esbuild/netbsd-x64': 0.24.2 1229 | '@esbuild/openbsd-arm64': 0.24.2 1230 | '@esbuild/openbsd-x64': 0.24.2 1231 | '@esbuild/sunos-x64': 0.24.2 1232 | '@esbuild/win32-arm64': 0.24.2 1233 | '@esbuild/win32-ia32': 0.24.2 1234 | '@esbuild/win32-x64': 0.24.2 1235 | 1236 | escalade@3.2.0: {} 1237 | 1238 | escape-string-regexp@1.0.5: {} 1239 | 1240 | fast-glob@3.3.3: 1241 | dependencies: 1242 | '@nodelib/fs.stat': 2.0.5 1243 | '@nodelib/fs.walk': 1.2.8 1244 | glob-parent: 5.1.2 1245 | merge2: 1.4.1 1246 | micromatch: 4.0.8 1247 | 1248 | fastq@1.19.0: 1249 | dependencies: 1250 | reusify: 1.0.4 1251 | 1252 | file-saver@2.0.5: {} 1253 | 1254 | filename-reserved-regex@2.0.0: {} 1255 | 1256 | filenamify@4.3.0: 1257 | dependencies: 1258 | filename-reserved-regex: 2.0.0 1259 | strip-outer: 1.0.1 1260 | trim-repeated: 1.0.0 1261 | 1262 | fill-range@7.1.1: 1263 | dependencies: 1264 | to-regex-range: 5.0.1 1265 | 1266 | find-cache-dir@3.3.2: 1267 | dependencies: 1268 | commondir: 1.0.1 1269 | make-dir: 3.1.0 1270 | pkg-dir: 4.2.0 1271 | 1272 | find-up@4.1.0: 1273 | dependencies: 1274 | locate-path: 5.0.0 1275 | path-exists: 4.0.0 1276 | 1277 | fs-extra@11.3.0: 1278 | dependencies: 1279 | graceful-fs: 4.2.11 1280 | jsonfile: 6.1.0 1281 | universalify: 2.0.1 1282 | 1283 | fsevents@2.3.3: 1284 | optional: true 1285 | 1286 | gensync@1.0.0-beta.2: {} 1287 | 1288 | gh-pages@6.3.0: 1289 | dependencies: 1290 | async: 3.2.6 1291 | commander: 13.1.0 1292 | email-addresses: 5.0.0 1293 | filenamify: 4.3.0 1294 | find-cache-dir: 3.3.2 1295 | fs-extra: 11.3.0 1296 | globby: 11.1.0 1297 | 1298 | glob-parent@5.1.2: 1299 | dependencies: 1300 | is-glob: 4.0.3 1301 | 1302 | globals@11.12.0: {} 1303 | 1304 | globals@15.14.0: {} 1305 | 1306 | globby@11.1.0: 1307 | dependencies: 1308 | array-union: 2.1.0 1309 | dir-glob: 3.0.1 1310 | fast-glob: 3.3.3 1311 | ignore: 5.3.2 1312 | merge2: 1.4.1 1313 | slash: 3.0.0 1314 | 1315 | good-listener@1.2.2: 1316 | dependencies: 1317 | delegate: 3.2.0 1318 | 1319 | graceful-fs@4.2.11: {} 1320 | 1321 | ignore@5.3.2: {} 1322 | 1323 | immediate@3.0.6: {} 1324 | 1325 | inherits@2.0.4: {} 1326 | 1327 | is-extglob@2.1.1: {} 1328 | 1329 | is-glob@4.0.3: 1330 | dependencies: 1331 | is-extglob: 2.1.1 1332 | 1333 | is-number@7.0.0: {} 1334 | 1335 | isarray@1.0.0: {} 1336 | 1337 | js-tokens@4.0.0: {} 1338 | 1339 | jsesc@3.1.0: {} 1340 | 1341 | json5@2.2.3: {} 1342 | 1343 | jsonfile@6.1.0: 1344 | dependencies: 1345 | universalify: 2.0.1 1346 | optionalDependencies: 1347 | graceful-fs: 4.2.11 1348 | 1349 | jszip@3.10.1: 1350 | dependencies: 1351 | lie: 3.3.0 1352 | pako: 1.0.11 1353 | readable-stream: 2.3.8 1354 | setimmediate: 1.0.5 1355 | 1356 | lie@3.3.0: 1357 | dependencies: 1358 | immediate: 3.0.6 1359 | 1360 | locate-path@5.0.0: 1361 | dependencies: 1362 | p-locate: 4.1.0 1363 | 1364 | lru-cache@5.1.1: 1365 | dependencies: 1366 | yallist: 3.1.1 1367 | 1368 | make-dir@3.1.0: 1369 | dependencies: 1370 | semver: 6.3.1 1371 | 1372 | merge2@1.4.1: {} 1373 | 1374 | micromatch@4.0.8: 1375 | dependencies: 1376 | braces: 3.0.3 1377 | picomatch: 2.3.1 1378 | 1379 | ms@2.1.3: {} 1380 | 1381 | nanoid@3.3.8: {} 1382 | 1383 | node-releases@2.0.19: {} 1384 | 1385 | p-limit@2.3.0: 1386 | dependencies: 1387 | p-try: 2.2.0 1388 | 1389 | p-locate@4.1.0: 1390 | dependencies: 1391 | p-limit: 2.3.0 1392 | 1393 | p-try@2.2.0: {} 1394 | 1395 | pako@1.0.11: {} 1396 | 1397 | path-exists@4.0.0: {} 1398 | 1399 | path-type@4.0.0: {} 1400 | 1401 | picocolors@1.1.1: {} 1402 | 1403 | picomatch@2.3.1: {} 1404 | 1405 | pkg-dir@4.2.0: 1406 | dependencies: 1407 | find-up: 4.1.0 1408 | 1409 | postcss@8.4.49: 1410 | dependencies: 1411 | nanoid: 3.3.8 1412 | picocolors: 1.1.1 1413 | source-map-js: 1.2.1 1414 | 1415 | process-nextick-args@2.0.1: {} 1416 | 1417 | queue-microtask@1.2.3: {} 1418 | 1419 | react-dom@19.0.0(react@19.0.0): 1420 | dependencies: 1421 | react: 19.0.0 1422 | scheduler: 0.25.0 1423 | 1424 | react-refresh@0.14.2: {} 1425 | 1426 | react@19.0.0: {} 1427 | 1428 | readable-stream@2.3.8: 1429 | dependencies: 1430 | core-util-is: 1.0.3 1431 | inherits: 2.0.4 1432 | isarray: 1.0.0 1433 | process-nextick-args: 2.0.1 1434 | safe-buffer: 5.1.2 1435 | string_decoder: 1.1.1 1436 | util-deprecate: 1.0.2 1437 | 1438 | reusify@1.0.4: {} 1439 | 1440 | rollup@4.29.1: 1441 | dependencies: 1442 | '@types/estree': 1.0.6 1443 | optionalDependencies: 1444 | '@rollup/rollup-android-arm-eabi': 4.29.1 1445 | '@rollup/rollup-android-arm64': 4.29.1 1446 | '@rollup/rollup-darwin-arm64': 4.29.1 1447 | '@rollup/rollup-darwin-x64': 4.29.1 1448 | '@rollup/rollup-freebsd-arm64': 4.29.1 1449 | '@rollup/rollup-freebsd-x64': 4.29.1 1450 | '@rollup/rollup-linux-arm-gnueabihf': 4.29.1 1451 | '@rollup/rollup-linux-arm-musleabihf': 4.29.1 1452 | '@rollup/rollup-linux-arm64-gnu': 4.29.1 1453 | '@rollup/rollup-linux-arm64-musl': 4.29.1 1454 | '@rollup/rollup-linux-loongarch64-gnu': 4.29.1 1455 | '@rollup/rollup-linux-powerpc64le-gnu': 4.29.1 1456 | '@rollup/rollup-linux-riscv64-gnu': 4.29.1 1457 | '@rollup/rollup-linux-s390x-gnu': 4.29.1 1458 | '@rollup/rollup-linux-x64-gnu': 4.29.1 1459 | '@rollup/rollup-linux-x64-musl': 4.29.1 1460 | '@rollup/rollup-win32-arm64-msvc': 4.29.1 1461 | '@rollup/rollup-win32-ia32-msvc': 4.29.1 1462 | '@rollup/rollup-win32-x64-msvc': 4.29.1 1463 | fsevents: 2.3.3 1464 | 1465 | run-parallel@1.2.0: 1466 | dependencies: 1467 | queue-microtask: 1.2.3 1468 | 1469 | safe-buffer@5.1.2: {} 1470 | 1471 | scheduler@0.25.0: {} 1472 | 1473 | select@1.1.2: {} 1474 | 1475 | semver@6.3.1: {} 1476 | 1477 | setimmediate@1.0.5: {} 1478 | 1479 | slash@3.0.0: {} 1480 | 1481 | source-map-js@1.2.1: {} 1482 | 1483 | string_decoder@1.1.1: 1484 | dependencies: 1485 | safe-buffer: 5.1.2 1486 | 1487 | strip-outer@1.0.1: 1488 | dependencies: 1489 | escape-string-regexp: 1.0.5 1490 | 1491 | tiny-emitter@2.1.0: {} 1492 | 1493 | to-regex-range@5.0.1: 1494 | dependencies: 1495 | is-number: 7.0.0 1496 | 1497 | trim-repeated@1.0.0: 1498 | dependencies: 1499 | escape-string-regexp: 1.0.5 1500 | 1501 | typescript@5.6.3: {} 1502 | 1503 | universalify@2.0.1: {} 1504 | 1505 | update-browserslist-db@1.1.1(browserslist@4.24.3): 1506 | dependencies: 1507 | browserslist: 4.24.3 1508 | escalade: 3.2.0 1509 | picocolors: 1.1.1 1510 | 1511 | util-deprecate@1.0.2: {} 1512 | 1513 | vite@6.0.7: 1514 | dependencies: 1515 | esbuild: 0.24.2 1516 | postcss: 8.4.49 1517 | rollup: 4.29.1 1518 | optionalDependencies: 1519 | fsevents: 2.3.3 1520 | 1521 | yallist@3.1.1: {} 1522 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/woochanleee/project-tree-generator/a4f462e26abfac168b2eeae4644b48abdd3d6a84/public/favicon.ico -------------------------------------------------------------------------------- /public/ogImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/woochanleee/project-tree-generator/a4f462e26abfac168b2eeae4644b48abdd3d6a84/public/ogImage.png -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import './app.css'; 2 | 3 | import { Editor } from './Editor.tsx'; 4 | import { Footer } from './Footer.tsx'; 5 | import { Header } from './Header.tsx'; 6 | 7 | export function App() { 8 | return ( 9 |
10 |
11 | 12 |
13 |
14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /src/Editor.tsx: -------------------------------------------------------------------------------- 1 | import { Dispatch, SetStateAction, useCallback, useEffect, useMemo, useRef, useState } from 'react'; 2 | 3 | import './editor.css'; 4 | 5 | import ClipBoard from 'clipboard'; 6 | import JSZip from 'jszip'; 7 | import { saveAs } from 'file-saver'; 8 | 9 | new ClipBoard('.copy-button'); 10 | 11 | type TreeContent = { 12 | id: number; 13 | text: string; 14 | depth: number; 15 | depthIndicator: string; 16 | }; 17 | 18 | type TreeProps = { 19 | treeContent: TreeContent; 20 | treeContents: TreeContent[]; 21 | setTreeContents: Dispatch>; 22 | focusId: number; 23 | setFocusId: Dispatch>; 24 | focusIdChanged: boolean; 25 | setFocusIdChanged: Dispatch>; 26 | }; 27 | 28 | function Tree({ treeContent, treeContents, setTreeContents, focusId, setFocusId, focusIdChanged, setFocusIdChanged }: TreeProps) { 29 | const { id, depth, text } = treeContent; 30 | 31 | const isLast = useCallback( 32 | (id: number, depth: number) => { 33 | for (const value of treeContents.slice(id)) { 34 | if (value.depth < depth) { 35 | return true; 36 | } 37 | if (value.depth === depth) { 38 | return false; 39 | } 40 | } 41 | return true; 42 | }, 43 | [treeContents] 44 | ); 45 | 46 | const parentsLastStatus = useMemo(() => { 47 | const results = []; 48 | let findDepth = depth - 1; 49 | for (let i = id - 2; i >= 0; i--) { 50 | if (treeContents[i].depth === findDepth) { 51 | findDepth--; 52 | results.push(isLast(treeContents[i].id, treeContents[i].depth)); 53 | } 54 | } 55 | 56 | return results.reverse(); 57 | }, [treeContents]); 58 | 59 | const contentRef = useRef(null); 60 | 61 | useEffect(() => { 62 | if (focusId === id) { 63 | contentRef.current?.focus(); 64 | setFocusIdChanged(false); 65 | } 66 | }, [focusIdChanged]); 67 | 68 | const depthIndicator = useMemo(() => { 69 | return ( 70 | parentsLastStatus.map((isLast) => (isLast ? '\u00A0\u00A0\u00A0' : '│\u00A0\u00A0')).join('') + 71 | (isLast(id, depth) ? '└─' : '├─') + 72 | '\u00A0' 73 | ); 74 | }, [parentsLastStatus]); 75 | 76 | useEffect(() => { 77 | const newTreeContents = [...treeContents]; 78 | newTreeContents[id - 1].depthIndicator = depthIndicator; 79 | setTreeContents(newTreeContents); 80 | }, [depthIndicator]); 81 | 82 | return ( 83 | <> 84 |
85 | {depthIndicator} 86 | { 92 | const newTreeContents = [...treeContents]; 93 | newTreeContents[id - 1].text = e.target.value; 94 | setTreeContents(newTreeContents); 95 | }} 96 | onKeyDown={(e) => { 97 | if (e.key === 'Tab') { 98 | if (id !== 1) { 99 | e.preventDefault(); 100 | } 101 | 102 | if (depth !== 1 && e.shiftKey) { 103 | const newTreeContents = treeContents.map((content, index) => ({ 104 | ...content, 105 | depth: index + 1 === id ? content.depth - 1 : content.depth, 106 | })); 107 | 108 | for (let i = id; i < newTreeContents.length; i++) { 109 | if (depth >= newTreeContents[i].depth) { 110 | break; 111 | } 112 | 113 | newTreeContents[i].depth = newTreeContents[i].depth - 1; 114 | } 115 | 116 | setTreeContents(newTreeContents); 117 | } 118 | } 119 | 120 | if (e.key === 'Backspace') { 121 | if (id !== 1 && (treeContents[id]?.depth ?? depth) <= depth && treeContents[id - 1].text === '') { 122 | const newTreeContents = [...treeContents]; 123 | newTreeContents.splice(id - 1, 1); 124 | 125 | for (let i = id - 1; i < newTreeContents.length; i++) { 126 | newTreeContents[i] = { 127 | ...newTreeContents[i], 128 | id: i + 1, 129 | }; 130 | } 131 | 132 | setTreeContents(newTreeContents); 133 | setFocusId(id - 1); 134 | setFocusIdChanged(true); 135 | } 136 | } 137 | 138 | if (e.key === 'ArrowUp') { 139 | if (id !== 1 && e.keyCode === 38) { 140 | setFocusId(id - 1); 141 | setFocusIdChanged(true); 142 | } 143 | } 144 | if (e.key === 'ArrowDown' && e.keyCode === 40) { 145 | if (treeContents.length !== id) { 146 | setFocusId(id + 1); 147 | setFocusIdChanged(true); 148 | } 149 | } 150 | if (e.key === 'Enter' && e.keyCode === 13) { 151 | e.preventDefault(); 152 | const newTreeContents = [...treeContents]; 153 | newTreeContents.splice(id, 0, { id: id + 1, text: '', depth, depthIndicator: '' }); 154 | 155 | for (let i = id; i < newTreeContents.length; i++) { 156 | newTreeContents[i] = { 157 | ...newTreeContents[i], 158 | id: i + 1, 159 | }; 160 | } 161 | 162 | setTreeContents(newTreeContents); 163 | setFocusId(id + 1); 164 | setFocusIdChanged(true); 165 | } 166 | 167 | if (!e.shiftKey && e.key === 'Tab') { 168 | e.preventDefault(); 169 | 170 | if (id !== 1 && treeContents[id - 2].depth + 1 !== depth) { 171 | setTreeContents( 172 | treeContents.map((content, index) => ({ 173 | ...content, 174 | depth: index + 1 === id ? content.depth + 1 : content.depth, 175 | })) 176 | ); 177 | } 178 | } 179 | }} 180 | /> 181 |
182 | 183 | ); 184 | } 185 | 186 | export function Editor() { 187 | const [rootText, setRootText] = useState(''); 188 | 189 | const [treeContents, setTreeContents] = useState([{ id: 1, depth: 1, text: '', depthIndicator: '' }]); 190 | const [focusId, setFocusId] = useState(1); 191 | const [focusIdChanged, setFocusIdChanged] = useState(false); 192 | 193 | const [copyClicked, setCopyClicked] = useState(false); 194 | 195 | const [githubRepositoryUrl, setGithubRepositoryUrl] = useState(''); 196 | 197 | function onSubmit(e: React.MouseEvent | React.FormEvent) { 198 | e.preventDefault(); 199 | 200 | fetch(`https://api.github.com/repos/${githubRepositoryUrl.split('https://github.com/').reverse()[0]}/git/trees/${branch}?recursive=1`, { 201 | method: 'GET', 202 | headers: { 203 | 'Content-Type': 'application/json', 204 | }, 205 | }) 206 | .then((res) => res.json()) 207 | .then((response) => { 208 | setTreeContents( 209 | response.tree.map((content: any, index: number) => { 210 | const depth = content.path.split('/'); 211 | const textIndex = depth.length; 212 | return { 213 | id: index + 1, 214 | depth: textIndex, 215 | text: depth[textIndex - 1], 216 | depthIndicator: '', 217 | }; 218 | }) 219 | ); 220 | setRootText(githubRepositoryUrl.split('/')[1]); 221 | console.log('Success:', JSON.stringify(response)); 222 | }) 223 | .catch((error) => { 224 | console.error('Error:', error); 225 | alert('깃허브로 부터 정보를 불러오는데 실패하였습니다.'); 226 | }); 227 | } 228 | 229 | const [branch, setBranch] = useState('main'); 230 | 231 | const onClickDownloadTree = useCallback(() => { 232 | const zip = new JSZip(); 233 | const folders = [zip.folder(rootText)]; 234 | 235 | treeContents.forEach((content, index) => { 236 | if (index !== 0) return; 237 | if (content.depth < treeContents[index - 1]?.depth) { 238 | folders.pop(); 239 | 240 | if (treeContents[index - 1].text.indexOf('.') === -1) { 241 | folders.pop(); 242 | } 243 | } else if (content.depth === treeContents[index - 1]?.depth) { 244 | if (treeContents[index - 1].text.indexOf('.') === -1) { 245 | folders.pop(); 246 | } 247 | } 248 | 249 | if (content.text.indexOf('.') >= 0) { 250 | folders[folders.length - 1]?.file(content.text, ''); 251 | } else { 252 | folders.push(folders[folders.length - 1]?.folder(content.text) ?? null); 253 | } 254 | }); 255 | 256 | zip.generateAsync({ type: 'blob' }).then(function (content) { 257 | saveAs(content, 'project-tree.zip'); 258 | }); 259 | }, [treeContents]); 260 | 261 | return ( 262 |
263 |
264 |

Project Tree

265 |
266 | setGithubRepositoryUrl(e.target.value)} 271 | /> 272 | setBranch(e.target.value)} placeholder='branch name' /> 273 | 274 |
275 |
276 | 283 | 300 |
301 | 📦 302 | setRootText(e.target.value)} /> 303 |
304 | {treeContents.map((treeContent) => ( 305 | 315 | ))} 316 |
317 |
318 |

Manual

319 |

↵: New Folder

320 |

⌫: Delete Folder

321 |

⇥: Depth +1

322 |

⇧ + ⇥: Depth -1

323 |

△: Up

324 |

▽: Down

325 |

326 | copy button 330 | : Copy Project Tree Code For Markdown 331 |

332 |
333 |
334 |
335 | ); 336 | } 337 | -------------------------------------------------------------------------------- /src/Footer.tsx: -------------------------------------------------------------------------------- 1 | import './footer.css'; 2 | 3 | export function Footer() { 4 | return ( 5 | 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /src/Header.tsx: -------------------------------------------------------------------------------- 1 | import './header.css'; 2 | 3 | export function Header() { 4 | return ( 5 |
6 | 22 |
23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /src/Menlo-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/woochanleee/project-tree-generator/a4f462e26abfac168b2eeae4644b48abdd3d6a84/src/Menlo-Regular.woff -------------------------------------------------------------------------------- /src/app.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | width: 100vw; 4 | height: 100vh; 5 | padding: 0; 6 | margin: 0; 7 | font-family: 'Menlo Regular', sans-serif; 8 | } 9 | 10 | main { 11 | min-width: 680px; 12 | margin: 0 auto; 13 | overflow: scroll; 14 | } 15 | 16 | @font-face { 17 | font-family: 'Menlo Regular'; 18 | font-style: normal; 19 | font-weight: normal; 20 | src: local('Menlo Regular'), url('Menlo-Regular.woff') format('woff'); 21 | } 22 | -------------------------------------------------------------------------------- /src/editor.css: -------------------------------------------------------------------------------- 1 | section { 2 | display: flex; 3 | justify-content: center; 4 | 5 | > div { 6 | > .github-repository-wrapper { 7 | display: flex; 8 | > input:first-child { 9 | flex-basis: 0; 10 | flex-grow: 1; 11 | } 12 | > input:nth-child(2) { 13 | width: 100px; 14 | } 15 | } 16 | 17 | > .editor { 18 | overflow: scroll; 19 | position: relative; 20 | width: 600px; 21 | height: 600px; 22 | padding: 16px; 23 | background-color: #f6f8fa; 24 | border-radius: 6px; 25 | 26 | > button { 27 | position: absolute; 28 | top: 8px; 29 | z-index: 1; 30 | width: 32px; 31 | height: 32px; 32 | border: 1px solid #d1d5da; 33 | border-radius: 4px; 34 | background: #fafbfc; 35 | cursor: pointer; 36 | outline: none; 37 | 38 | &:first-of-type { 39 | left: calc(100% - 80px); 40 | padding-top: 4px; 41 | } 42 | 43 | &:last-of-type { 44 | left: calc(100% - 40px); 45 | } 46 | 47 | &.success > i { 48 | background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xMy43OCA0LjIyYS43NS43NSAwIDAxMCAxLjA2bC03LjI1IDcuMjVhLjc1Ljc1IDAgMDEtMS4wNiAwTDIuMjIgOS4yOGEuNzUuNzUgMCAwMTEuMDYtMS4wNkw2IDEwLjk0bDYuNzItNi43MmEuNzUuNzUgMCAwMTEuMDYgMHoiLz48L3N2Zz4=); 49 | } 50 | 51 | > i { 52 | width: 100%; 53 | height: 100%; 54 | display: block; 55 | background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik01Ljc1IDFhLjc1Ljc1IDAgMDAtLjc1Ljc1djNjMCAuNDE0LjMzNi43NS43NS43NWg0LjVhLjc1Ljc1IDAgMDAuNzUtLjc1di0zYS43NS43NSAwIDAwLS43NS0uNzVoLTQuNXptLjc1IDNWMi41aDNWNGgtM3ptLTIuODc0LS40NjdhLjc1Ljc1IDAgMDAtLjc1Mi0xLjI5OEExLjc1IDEuNzUgMCAwMDIgMy43NXY5LjVjMCAuOTY2Ljc4NCAxLjc1IDEuNzUgMS43NWg4LjVBMS43NSAxLjc1IDAgMDAxNCAxMy4yNXYtOS41YTEuNzUgMS43NSAwIDAwLS44NzQtMS41MTUuNzUuNzUgMCAxMC0uNzUyIDEuMjk4LjI1LjI1IDAgMDEuMTI2LjIxN3Y5LjVhLjI1LjI1IDAgMDEtLjI1LjI1aC04LjVhLjI1LjI1IDAgMDEtLjI1LS4yNXYtOS41YS4yNS4yNSAwIDAxLjEyNi0uMjE3eiIvPjwvc3ZnPg==); 56 | background-position: center; 57 | background-repeat: no-repeat; 58 | } 59 | } 60 | 61 | > div { 62 | display: flex; 63 | align-items: center; 64 | 65 | > span { 66 | cursor: default; 67 | } 68 | 69 | > input { 70 | background: transparent; 71 | border: none; 72 | outline: none; 73 | width: 100%; 74 | } 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/footer.css: -------------------------------------------------------------------------------- 1 | footer { 2 | padding: 24px 0; 3 | text-align: center; 4 | } 5 | -------------------------------------------------------------------------------- /src/header.css: -------------------------------------------------------------------------------- 1 | header { 2 | > div { 3 | padding: 32px 0; 4 | box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1); 5 | display: flex; 6 | justify-content: center; 7 | align-items: flex-end; 8 | 9 | h1 { 10 | margin: 0; 11 | } 12 | 13 | a + a { 14 | margin-left: 16px; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import { App } from './App.tsx'; 5 | 6 | const rootElement = document.getElementById('root'); 7 | 8 | if (rootElement === null) { 9 | throw new Error('Root element not found'); 10 | } 11 | 12 | createRoot(rootElement).render( 13 | 14 | 15 | 16 | ); 17 | -------------------------------------------------------------------------------- /src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "isolatedModules": true, 13 | "moduleDetection": "force", 14 | "noEmit": true, 15 | "jsx": "react-jsx", 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true 22 | }, 23 | "include": ["src"] 24 | } 25 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.app.json" }, 5 | { "path": "./tsconfig.node.json" } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "lib": ["ES2023"], 5 | "module": "ESNext", 6 | "skipLibCheck": true, 7 | 8 | /* Bundler mode */ 9 | "moduleResolution": "bundler", 10 | "allowImportingTsExtensions": true, 11 | "isolatedModules": true, 12 | "moduleDetection": "force", 13 | "noEmit": true, 14 | 15 | /* Linting */ 16 | "strict": true, 17 | "noUnusedLocals": true, 18 | "noUnusedParameters": true, 19 | "noFallthroughCasesInSwitch": true 20 | }, 21 | "include": ["vite.config.ts"] 22 | } 23 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import react from '@vitejs/plugin-react'; 2 | import { defineConfig } from 'vite'; 3 | 4 | // https://vite.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | base: './', 8 | }); 9 | --------------------------------------------------------------------------------