├── .gitignore ├── index.html ├── package-lock.json ├── package.json ├── public ├── demo.mp4 └── vite.svg ├── src ├── main.ts ├── style.scss └── vite-env.d.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Vite + TS 10 | 11 | 12 | 13 |
14 |
15 | 17 | 19 | 20 | 21 | 22 | 25 | 26 | 28 | 31 | 32 |
33 | 39 | 45 |
46 |
47 |
48 |
49 |
50 |

51 | Your screen is too small to view this page :/
52 | Expand your screen or open the site on a computer : ) 53 |

54 |
55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "unique-transition-between-grid-and-list-views", 3 | "version": "0.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "unique-transition-between-grid-and-list-views", 9 | "version": "0.0.0", 10 | "dependencies": { 11 | "gsap": "^3.12.2" 12 | }, 13 | "devDependencies": { 14 | "sass": "^1.63.6", 15 | "typescript": "^5.0.2", 16 | "vite": "^4.4.0" 17 | } 18 | }, 19 | "node_modules/@esbuild/android-arm": { 20 | "version": "0.18.13", 21 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.13.tgz", 22 | "integrity": "sha512-KwqFhxRFMKZINHzCqf8eKxE0XqWlAVPRxwy6rc7CbVFxzUWB2sA/s3hbMZeemPdhN3fKBkqOaFhTbS8xJXYIWQ==", 23 | "cpu": [ 24 | "arm" 25 | ], 26 | "dev": true, 27 | "optional": true, 28 | "os": [ 29 | "android" 30 | ], 31 | "engines": { 32 | "node": ">=12" 33 | } 34 | }, 35 | "node_modules/@esbuild/android-arm64": { 36 | "version": "0.18.13", 37 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.13.tgz", 38 | "integrity": "sha512-j7NhycJUoUAG5kAzGf4fPWfd17N6SM3o1X6MlXVqfHvs2buFraCJzos9vbeWjLxOyBKHyPOnuCuipbhvbYtTAg==", 39 | "cpu": [ 40 | "arm64" 41 | ], 42 | "dev": true, 43 | "optional": true, 44 | "os": [ 45 | "android" 46 | ], 47 | "engines": { 48 | "node": ">=12" 49 | } 50 | }, 51 | "node_modules/@esbuild/android-x64": { 52 | "version": "0.18.13", 53 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.13.tgz", 54 | "integrity": "sha512-M2eZkRxR6WnWfVELHmv6MUoHbOqnzoTVSIxgtsyhm/NsgmL+uTmag/VVzdXvmahak1I6sOb1K/2movco5ikDJg==", 55 | "cpu": [ 56 | "x64" 57 | ], 58 | "dev": true, 59 | "optional": true, 60 | "os": [ 61 | "android" 62 | ], 63 | "engines": { 64 | "node": ">=12" 65 | } 66 | }, 67 | "node_modules/@esbuild/darwin-x64": { 68 | "version": "0.18.13", 69 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.13.tgz", 70 | "integrity": "sha512-RIrxoKH5Eo+yE5BtaAIMZaiKutPhZjw+j0OCh8WdvKEKJQteacq0myZvBDLU+hOzQOZWJeDnuQ2xgSScKf1Ovw==", 71 | "cpu": [ 72 | "x64" 73 | ], 74 | "dev": true, 75 | "optional": true, 76 | "os": [ 77 | "darwin" 78 | ], 79 | "engines": { 80 | "node": ">=12" 81 | } 82 | }, 83 | "node_modules/@esbuild/freebsd-arm64": { 84 | "version": "0.18.13", 85 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.13.tgz", 86 | "integrity": "sha512-AfRPhHWmj9jGyLgW/2FkYERKmYR+IjYxf2rtSLmhOrPGFh0KCETFzSjx/JX/HJnvIqHt/DRQD/KAaVsUKoI3Xg==", 87 | "cpu": [ 88 | "arm64" 89 | ], 90 | "dev": true, 91 | "optional": true, 92 | "os": [ 93 | "freebsd" 94 | ], 95 | "engines": { 96 | "node": ">=12" 97 | } 98 | }, 99 | "node_modules/@esbuild/freebsd-x64": { 100 | "version": "0.18.13", 101 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.13.tgz", 102 | "integrity": "sha512-pGzWWZJBInhIgdEwzn8VHUBang8UvFKsvjDkeJ2oyY5gZtAM6BaxK0QLCuZY+qoj/nx/lIaItH425rm/hloETA==", 103 | "cpu": [ 104 | "x64" 105 | ], 106 | "dev": true, 107 | "optional": true, 108 | "os": [ 109 | "freebsd" 110 | ], 111 | "engines": { 112 | "node": ">=12" 113 | } 114 | }, 115 | "node_modules/@esbuild/linux-arm": { 116 | "version": "0.18.13", 117 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.13.tgz", 118 | "integrity": "sha512-4iMxLRMCxGyk7lEvkkvrxw4aJeC93YIIrfbBlUJ062kilUUnAiMb81eEkVvCVoh3ON283ans7+OQkuy1uHW+Hw==", 119 | "cpu": [ 120 | "arm" 121 | ], 122 | "dev": true, 123 | "optional": true, 124 | "os": [ 125 | "linux" 126 | ], 127 | "engines": { 128 | "node": ">=12" 129 | } 130 | }, 131 | "node_modules/@esbuild/linux-arm64": { 132 | "version": "0.18.13", 133 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.13.tgz", 134 | "integrity": "sha512-hCzZbVJEHV7QM77fHPv2qgBcWxgglGFGCxk6KfQx6PsVIdi1u09X7IvgE9QKqm38OpkzaAkPnnPqwRsltvLkIQ==", 135 | "cpu": [ 136 | "arm64" 137 | ], 138 | "dev": true, 139 | "optional": true, 140 | "os": [ 141 | "linux" 142 | ], 143 | "engines": { 144 | "node": ">=12" 145 | } 146 | }, 147 | "node_modules/@esbuild/linux-ia32": { 148 | "version": "0.18.13", 149 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.13.tgz", 150 | "integrity": "sha512-I3OKGbynl3AAIO6onXNrup/ttToE6Rv2XYfFgLK/wnr2J+1g+7k4asLrE+n7VMhaqX+BUnyWkCu27rl+62Adug==", 151 | "cpu": [ 152 | "ia32" 153 | ], 154 | "dev": true, 155 | "optional": true, 156 | "os": [ 157 | "linux" 158 | ], 159 | "engines": { 160 | "node": ">=12" 161 | } 162 | }, 163 | "node_modules/@esbuild/linux-loong64": { 164 | "version": "0.18.13", 165 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.13.tgz", 166 | "integrity": "sha512-8pcKDApAsKc6WW51ZEVidSGwGbebYw2qKnO1VyD8xd6JN0RN6EUXfhXmDk9Vc4/U3Y4AoFTexQewQDJGsBXBpg==", 167 | "cpu": [ 168 | "loong64" 169 | ], 170 | "dev": true, 171 | "optional": true, 172 | "os": [ 173 | "linux" 174 | ], 175 | "engines": { 176 | "node": ">=12" 177 | } 178 | }, 179 | "node_modules/@esbuild/linux-mips64el": { 180 | "version": "0.18.13", 181 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.13.tgz", 182 | "integrity": "sha512-6GU+J1PLiVqWx8yoCK4Z0GnfKyCGIH5L2KQipxOtbNPBs+qNDcMJr9euxnyJ6FkRPyMwaSkjejzPSISD9hb+gg==", 183 | "cpu": [ 184 | "mips64el" 185 | ], 186 | "dev": true, 187 | "optional": true, 188 | "os": [ 189 | "linux" 190 | ], 191 | "engines": { 192 | "node": ">=12" 193 | } 194 | }, 195 | "node_modules/@esbuild/linux-ppc64": { 196 | "version": "0.18.13", 197 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.13.tgz", 198 | "integrity": "sha512-pfn/OGZ8tyR8YCV7MlLl5hAit2cmS+j/ZZg9DdH0uxdCoJpV7+5DbuXrR+es4ayRVKIcfS9TTMCs60vqQDmh+w==", 199 | "cpu": [ 200 | "ppc64" 201 | ], 202 | "dev": true, 203 | "optional": true, 204 | "os": [ 205 | "linux" 206 | ], 207 | "engines": { 208 | "node": ">=12" 209 | } 210 | }, 211 | "node_modules/@esbuild/linux-riscv64": { 212 | "version": "0.18.13", 213 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.13.tgz", 214 | "integrity": "sha512-aIbhU3LPg0lOSCfVeGHbmGYIqOtW6+yzO+Nfv57YblEK01oj0mFMtvDJlOaeAZ6z0FZ9D13oahi5aIl9JFphGg==", 215 | "cpu": [ 216 | "riscv64" 217 | ], 218 | "dev": true, 219 | "optional": true, 220 | "os": [ 221 | "linux" 222 | ], 223 | "engines": { 224 | "node": ">=12" 225 | } 226 | }, 227 | "node_modules/@esbuild/linux-s390x": { 228 | "version": "0.18.13", 229 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.13.tgz", 230 | "integrity": "sha512-Pct1QwF2sp+5LVi4Iu5Y+6JsGaV2Z2vm4O9Dd7XZ5tKYxEHjFtb140fiMcl5HM1iuv6xXO8O1Vrb1iJxHlv8UA==", 231 | "cpu": [ 232 | "s390x" 233 | ], 234 | "dev": true, 235 | "optional": true, 236 | "os": [ 237 | "linux" 238 | ], 239 | "engines": { 240 | "node": ">=12" 241 | } 242 | }, 243 | "node_modules/@esbuild/linux-x64": { 244 | "version": "0.18.13", 245 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.13.tgz", 246 | "integrity": "sha512-zTrIP0KzYP7O0+3ZnmzvUKgGtUvf4+piY8PIO3V8/GfmVd3ZyHJGz7Ht0np3P1wz+I8qJ4rjwJKqqEAbIEPngA==", 247 | "cpu": [ 248 | "x64" 249 | ], 250 | "dev": true, 251 | "optional": true, 252 | "os": [ 253 | "linux" 254 | ], 255 | "engines": { 256 | "node": ">=12" 257 | } 258 | }, 259 | "node_modules/@esbuild/netbsd-x64": { 260 | "version": "0.18.13", 261 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.13.tgz", 262 | "integrity": "sha512-I6zs10TZeaHDYoGxENuksxE1sxqZpCp+agYeW039yqFwh3MgVvdmXL5NMveImOC6AtpLvE4xG5ujVic4NWFIDQ==", 263 | "cpu": [ 264 | "x64" 265 | ], 266 | "dev": true, 267 | "optional": true, 268 | "os": [ 269 | "netbsd" 270 | ], 271 | "engines": { 272 | "node": ">=12" 273 | } 274 | }, 275 | "node_modules/@esbuild/sunos-x64": { 276 | "version": "0.18.13", 277 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.13.tgz", 278 | "integrity": "sha512-X/xzuw4Hzpo/yq3YsfBbIsipNgmsm8mE/QeWbdGdTTeZ77fjxI2K0KP3AlhZ6gU3zKTw1bKoZTuKLnqcJ537qw==", 279 | "cpu": [ 280 | "x64" 281 | ], 282 | "dev": true, 283 | "optional": true, 284 | "os": [ 285 | "sunos" 286 | ], 287 | "engines": { 288 | "node": ">=12" 289 | } 290 | }, 291 | "node_modules/@esbuild/win32-arm64": { 292 | "version": "0.18.13", 293 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.13.tgz", 294 | "integrity": "sha512-4CGYdRQT/ILd+yLLE5i4VApMPfGE0RPc/wFQhlluDQCK09+b4JDbxzzjpgQqTPrdnP7r5KUtGVGZYclYiPuHrw==", 295 | "cpu": [ 296 | "arm64" 297 | ], 298 | "dev": true, 299 | "optional": true, 300 | "os": [ 301 | "win32" 302 | ], 303 | "engines": { 304 | "node": ">=12" 305 | } 306 | }, 307 | "node_modules/@esbuild/win32-ia32": { 308 | "version": "0.18.13", 309 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.13.tgz", 310 | "integrity": "sha512-D+wKZaRhQI+MUGMH+DbEr4owC2D7XnF+uyGiZk38QbgzLcofFqIOwFs7ELmIeU45CQgfHNy9Q+LKW3cE8g37Kg==", 311 | "cpu": [ 312 | "ia32" 313 | ], 314 | "dev": true, 315 | "optional": true, 316 | "os": [ 317 | "win32" 318 | ], 319 | "engines": { 320 | "node": ">=12" 321 | } 322 | }, 323 | "node_modules/@esbuild/win32-x64": { 324 | "version": "0.18.13", 325 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.13.tgz", 326 | "integrity": "sha512-iVl6lehAfJS+VmpF3exKpNQ8b0eucf5VWfzR8S7xFve64NBNz2jPUgx1X93/kfnkfgP737O+i1k54SVQS7uVZA==", 327 | "cpu": [ 328 | "x64" 329 | ], 330 | "dev": true, 331 | "optional": true, 332 | "os": [ 333 | "win32" 334 | ], 335 | "engines": { 336 | "node": ">=12" 337 | } 338 | }, 339 | "node_modules/anymatch": { 340 | "version": "3.1.3", 341 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 342 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 343 | "dev": true, 344 | "dependencies": { 345 | "normalize-path": "^3.0.0", 346 | "picomatch": "^2.0.4" 347 | }, 348 | "engines": { 349 | "node": ">= 8" 350 | } 351 | }, 352 | "node_modules/binary-extensions": { 353 | "version": "2.2.0", 354 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 355 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 356 | "dev": true, 357 | "engines": { 358 | "node": ">=8" 359 | } 360 | }, 361 | "node_modules/braces": { 362 | "version": "3.0.2", 363 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 364 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 365 | "dev": true, 366 | "dependencies": { 367 | "fill-range": "^7.0.1" 368 | }, 369 | "engines": { 370 | "node": ">=8" 371 | } 372 | }, 373 | "node_modules/chokidar": { 374 | "version": "3.5.3", 375 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 376 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 377 | "dev": true, 378 | "funding": [ 379 | { 380 | "type": "individual", 381 | "url": "https://paulmillr.com/funding/" 382 | } 383 | ], 384 | "dependencies": { 385 | "anymatch": "~3.1.2", 386 | "braces": "~3.0.2", 387 | "glob-parent": "~5.1.2", 388 | "is-binary-path": "~2.1.0", 389 | "is-glob": "~4.0.1", 390 | "normalize-path": "~3.0.0", 391 | "readdirp": "~3.6.0" 392 | }, 393 | "engines": { 394 | "node": ">= 8.10.0" 395 | }, 396 | "optionalDependencies": { 397 | "fsevents": "~2.3.2" 398 | } 399 | }, 400 | "node_modules/esbuild": { 401 | "version": "0.18.13", 402 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.13.tgz", 403 | "integrity": "sha512-vhg/WR/Oiu4oUIkVhmfcc23G6/zWuEQKFS+yiosSHe4aN6+DQRXIfeloYGibIfVhkr4wyfuVsGNLr+sQU1rWWw==", 404 | "dev": true, 405 | "hasInstallScript": true, 406 | "bin": { 407 | "esbuild": "bin/esbuild" 408 | }, 409 | "engines": { 410 | "node": ">=12" 411 | }, 412 | "optionalDependencies": { 413 | "@esbuild/android-arm": "0.18.13", 414 | "@esbuild/android-arm64": "0.18.13", 415 | "@esbuild/android-x64": "0.18.13", 416 | "@esbuild/darwin-arm64": "0.18.13", 417 | "@esbuild/darwin-x64": "0.18.13", 418 | "@esbuild/freebsd-arm64": "0.18.13", 419 | "@esbuild/freebsd-x64": "0.18.13", 420 | "@esbuild/linux-arm": "0.18.13", 421 | "@esbuild/linux-arm64": "0.18.13", 422 | "@esbuild/linux-ia32": "0.18.13", 423 | "@esbuild/linux-loong64": "0.18.13", 424 | "@esbuild/linux-mips64el": "0.18.13", 425 | "@esbuild/linux-ppc64": "0.18.13", 426 | "@esbuild/linux-riscv64": "0.18.13", 427 | "@esbuild/linux-s390x": "0.18.13", 428 | "@esbuild/linux-x64": "0.18.13", 429 | "@esbuild/netbsd-x64": "0.18.13", 430 | "@esbuild/openbsd-x64": "0.18.13", 431 | "@esbuild/sunos-x64": "0.18.13", 432 | "@esbuild/win32-arm64": "0.18.13", 433 | "@esbuild/win32-ia32": "0.18.13", 434 | "@esbuild/win32-x64": "0.18.13" 435 | } 436 | }, 437 | "node_modules/fill-range": { 438 | "version": "7.0.1", 439 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 440 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 441 | "dev": true, 442 | "dependencies": { 443 | "to-regex-range": "^5.0.1" 444 | }, 445 | "engines": { 446 | "node": ">=8" 447 | } 448 | }, 449 | "node_modules/fsevents": { 450 | "version": "2.3.2", 451 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 452 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 453 | "dev": true, 454 | "hasInstallScript": true, 455 | "optional": true, 456 | "os": [ 457 | "darwin" 458 | ], 459 | "engines": { 460 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 461 | } 462 | }, 463 | "node_modules/glob-parent": { 464 | "version": "5.1.2", 465 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 466 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 467 | "dev": true, 468 | "dependencies": { 469 | "is-glob": "^4.0.1" 470 | }, 471 | "engines": { 472 | "node": ">= 6" 473 | } 474 | }, 475 | "node_modules/gsap": { 476 | "version": "3.12.2", 477 | "resolved": "https://registry.npmjs.org/gsap/-/gsap-3.12.2.tgz", 478 | "integrity": "sha512-EkYnpG8qHgYBFAwsgsGEqvT1WUidX0tt/ijepx7z8EUJHElykg91RvW1XbkT59T0gZzzszOpjQv7SE41XuIXyQ==" 479 | }, 480 | "node_modules/immutable": { 481 | "version": "4.3.1", 482 | "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.1.tgz", 483 | "integrity": "sha512-lj9cnmB/kVS0QHsJnYKD1uo3o39nrbKxszjnqS9Fr6NB7bZzW45U6WSGBPKXDL/CvDKqDNPA4r3DoDQ8GTxo2A==", 484 | "dev": true 485 | }, 486 | "node_modules/is-binary-path": { 487 | "version": "2.1.0", 488 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 489 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 490 | "dev": true, 491 | "dependencies": { 492 | "binary-extensions": "^2.0.0" 493 | }, 494 | "engines": { 495 | "node": ">=8" 496 | } 497 | }, 498 | "node_modules/is-extglob": { 499 | "version": "2.1.1", 500 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 501 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 502 | "dev": true, 503 | "engines": { 504 | "node": ">=0.10.0" 505 | } 506 | }, 507 | "node_modules/is-glob": { 508 | "version": "4.0.3", 509 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 510 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 511 | "dev": true, 512 | "dependencies": { 513 | "is-extglob": "^2.1.1" 514 | }, 515 | "engines": { 516 | "node": ">=0.10.0" 517 | } 518 | }, 519 | "node_modules/is-number": { 520 | "version": "7.0.0", 521 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 522 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 523 | "dev": true, 524 | "engines": { 525 | "node": ">=0.12.0" 526 | } 527 | }, 528 | "node_modules/nanoid": { 529 | "version": "3.3.6", 530 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", 531 | "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", 532 | "dev": true, 533 | "funding": [ 534 | { 535 | "type": "github", 536 | "url": "https://github.com/sponsors/ai" 537 | } 538 | ], 539 | "bin": { 540 | "nanoid": "bin/nanoid.cjs" 541 | }, 542 | "engines": { 543 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 544 | } 545 | }, 546 | "node_modules/normalize-path": { 547 | "version": "3.0.0", 548 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 549 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 550 | "dev": true, 551 | "engines": { 552 | "node": ">=0.10.0" 553 | } 554 | }, 555 | "node_modules/picocolors": { 556 | "version": "1.0.0", 557 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 558 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", 559 | "dev": true 560 | }, 561 | "node_modules/picomatch": { 562 | "version": "2.3.1", 563 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 564 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 565 | "dev": true, 566 | "engines": { 567 | "node": ">=8.6" 568 | }, 569 | "funding": { 570 | "url": "https://github.com/sponsors/jonschlinkert" 571 | } 572 | }, 573 | "node_modules/postcss": { 574 | "version": "8.4.26", 575 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.26.tgz", 576 | "integrity": "sha512-jrXHFF8iTloAenySjM/ob3gSj7pCu0Ji49hnjqzsgSRa50hkWCKD0HQ+gMNJkW38jBI68MpAAg7ZWwHwX8NMMw==", 577 | "dev": true, 578 | "funding": [ 579 | { 580 | "type": "opencollective", 581 | "url": "https://opencollective.com/postcss/" 582 | }, 583 | { 584 | "type": "tidelift", 585 | "url": "https://tidelift.com/funding/github/npm/postcss" 586 | }, 587 | { 588 | "type": "github", 589 | "url": "https://github.com/sponsors/ai" 590 | } 591 | ], 592 | "dependencies": { 593 | "nanoid": "^3.3.6", 594 | "picocolors": "^1.0.0", 595 | "source-map-js": "^1.0.2" 596 | }, 597 | "engines": { 598 | "node": "^10 || ^12 || >=14" 599 | } 600 | }, 601 | "node_modules/readdirp": { 602 | "version": "3.6.0", 603 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 604 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 605 | "dev": true, 606 | "dependencies": { 607 | "picomatch": "^2.2.1" 608 | }, 609 | "engines": { 610 | "node": ">=8.10.0" 611 | } 612 | }, 613 | "node_modules/rollup": { 614 | "version": "3.26.2", 615 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.26.2.tgz", 616 | "integrity": "sha512-6umBIGVz93er97pMgQO08LuH3m6PUb3jlDUUGFsNJB6VgTCUaDFpupf5JfU30529m/UKOgmiX+uY6Sx8cOYpLA==", 617 | "dev": true, 618 | "bin": { 619 | "rollup": "dist/bin/rollup" 620 | }, 621 | "engines": { 622 | "node": ">=14.18.0", 623 | "npm": ">=8.0.0" 624 | }, 625 | "optionalDependencies": { 626 | "fsevents": "~2.3.2" 627 | } 628 | }, 629 | "node_modules/sass": { 630 | "version": "1.63.6", 631 | "resolved": "https://registry.npmjs.org/sass/-/sass-1.63.6.tgz", 632 | "integrity": "sha512-MJuxGMHzaOW7ipp+1KdELtqKbfAWbH7OLIdoSMnVe3EXPMTmxTmlaZDCTsgIpPCs3w99lLo9/zDKkOrJuT5byw==", 633 | "dev": true, 634 | "dependencies": { 635 | "chokidar": ">=3.0.0 <4.0.0", 636 | "immutable": "^4.0.0", 637 | "source-map-js": ">=0.6.2 <2.0.0" 638 | }, 639 | "bin": { 640 | "sass": "sass.js" 641 | }, 642 | "engines": { 643 | "node": ">=14.0.0" 644 | } 645 | }, 646 | "node_modules/source-map-js": { 647 | "version": "1.0.2", 648 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 649 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", 650 | "dev": true, 651 | "engines": { 652 | "node": ">=0.10.0" 653 | } 654 | }, 655 | "node_modules/to-regex-range": { 656 | "version": "5.0.1", 657 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 658 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 659 | "dev": true, 660 | "dependencies": { 661 | "is-number": "^7.0.0" 662 | }, 663 | "engines": { 664 | "node": ">=8.0" 665 | } 666 | }, 667 | "node_modules/typescript": { 668 | "version": "5.1.6", 669 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", 670 | "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", 671 | "dev": true, 672 | "bin": { 673 | "tsc": "bin/tsc", 674 | "tsserver": "bin/tsserver" 675 | }, 676 | "engines": { 677 | "node": ">=14.17" 678 | } 679 | }, 680 | "node_modules/vite": { 681 | "version": "4.4.4", 682 | "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.4.tgz", 683 | "integrity": "sha512-4mvsTxjkveWrKDJI70QmelfVqTm+ihFAb6+xf4sjEU2TmUCTlVX87tmg/QooPEMQb/lM9qGHT99ebqPziEd3wg==", 684 | "dev": true, 685 | "dependencies": { 686 | "esbuild": "^0.18.10", 687 | "postcss": "^8.4.25", 688 | "rollup": "^3.25.2" 689 | }, 690 | "bin": { 691 | "vite": "bin/vite.js" 692 | }, 693 | "engines": { 694 | "node": "^14.18.0 || >=16.0.0" 695 | }, 696 | "funding": { 697 | "url": "https://github.com/vitejs/vite?sponsor=1" 698 | }, 699 | "optionalDependencies": { 700 | "fsevents": "~2.3.2" 701 | }, 702 | "peerDependencies": { 703 | "@types/node": ">= 14", 704 | "less": "*", 705 | "lightningcss": "^1.21.0", 706 | "sass": "*", 707 | "stylus": "*", 708 | "sugarss": "*", 709 | "terser": "^5.4.0" 710 | }, 711 | "peerDependenciesMeta": { 712 | "@types/node": { 713 | "optional": true 714 | }, 715 | "less": { 716 | "optional": true 717 | }, 718 | "lightningcss": { 719 | "optional": true 720 | }, 721 | "sass": { 722 | "optional": true 723 | }, 724 | "stylus": { 725 | "optional": true 726 | }, 727 | "sugarss": { 728 | "optional": true 729 | }, 730 | "terser": { 731 | "optional": true 732 | } 733 | } 734 | } 735 | } 736 | } 737 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "unique-transition-between-grid-and-list-views", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "devDependencies": { 12 | "sass": "^1.63.6", 13 | "typescript": "^5.0.2", 14 | "vite": "^4.4.0" 15 | }, 16 | "dependencies": { 17 | "gsap": "^3.12.2" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /public/demo.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ln-dev7/unique-transition-between-grid-and-list-views/37753a33e33dcc238e9cdd6191e753ace848c88d/public/demo.mp4 -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import gsap from "gsap"; 2 | 3 | interface Data { 4 | id: number; 5 | name: string; 6 | description: string; 7 | } 8 | 9 | const data: Data[] = [ 10 | { 11 | id: 1, 12 | name: "Cycling 2019", 13 | description: "MARCH 16, 2019", 14 | }, 15 | { 16 | id: 2, 17 | name: "Secret Dataset", 18 | description: "APRIL 15, 2018", 19 | }, 20 | { 21 | id: 3, 22 | name: "Public Dataset", 23 | description: "JANUARY 15, 2020", 24 | }, 25 | { 26 | id: 4, 27 | name: "Android Sheet", 28 | description: "MARCH 15, 2021", 29 | }, 30 | { 31 | id: 5, 32 | name: "iOS Sheet", 33 | description: "APRIL 15, 2021", 34 | }, 35 | { 36 | id: 6, 37 | name: "FrontEnd Sheet", 38 | description: "NOVEMBER 20, 2020", 39 | }, 40 | { 41 | id: 7, 42 | name: "Private Dataset", 43 | description: "APRIL 15, 2015", 44 | }, 45 | { 46 | id: 8, 47 | name: "Google Sheet", 48 | description: "MARCH 15, 2016", 49 | }, 50 | { 51 | id: 9, 52 | name: "iOS Sheet", 53 | description: "APRIL 15, 2021", 54 | }, 55 | ]; 56 | 57 | const main = document.querySelector("main")! as HTMLDivElement; 58 | 59 | data.forEach((item) => { 60 | main.innerHTML += ` 61 |
62 |
63 |
64 |

${item.name}

65 | ${item.description} 66 |
67 |
68 | 69 | 70 |
71 |
72 |
73 | `; 74 | }); 75 | 76 | const cards = document.querySelectorAll(".card"); 77 | 78 | cards.forEach((card, index) => { 79 | const row = Math.floor(index / 3) + 1; 80 | const col = (index % 3) + 1; 81 | 82 | const element = card as HTMLDivElement; 83 | 84 | element.style.left = (col - 1) * 250 + "px"; 85 | element.style.top = (row - 1) * 220 + "px"; 86 | }); 87 | 88 | const groupBtn = document.querySelector(".group")! as HTMLButtonElement; 89 | const listBtn = document.querySelector(".list")! as HTMLButtonElement; 90 | 91 | const primaryDuration = 0.3; 92 | 93 | listBtn.addEventListener("click", () => { 94 | if (!listBtn.classList.contains("active")) { 95 | listBtn.classList.add("active"); 96 | groupBtn.classList.remove("active"); 97 | groupBtn.disabled = true; 98 | 99 | gsap.to(".card:nth-child(2), .card:nth-child(5), .card:nth-child(8)", { 100 | y: 73, 101 | duration: `${primaryDuration}`, 102 | }); 103 | 104 | gsap.to(".card:nth-child(3), .card:nth-child(6), .card:nth-child(9)", { 105 | y: 146, 106 | duration: `${primaryDuration}`, 107 | }); 108 | 109 | gsap.to(".card .content .right", { 110 | y: 20, 111 | opacity: 0, 112 | display: "none", 113 | duration: `${primaryDuration}`, 114 | }); 115 | 116 | gsap.to(".card .content .left span", { 117 | opacity: 0, 118 | duration: `${primaryDuration}`, 119 | onComplete: () => { 120 | document.querySelectorAll(".card .content .left").forEach((item) => { 121 | const element = item as HTMLDivElement; 122 | element.style.height = "fit-content"; 123 | }); 124 | }, 125 | }); 126 | 127 | gsap.to(".card", { 128 | height: "68px", 129 | delay: `${primaryDuration}`, 130 | duration: `${primaryDuration}`, 131 | }); 132 | 133 | gsap.to(".card", { 134 | width: "100%", 135 | left: 0, 136 | delay: `${primaryDuration * 2.3}`, 137 | duration: `${primaryDuration * 1.5}`, 138 | onComplete: () => { 139 | document.querySelectorAll(".card .content .left").forEach((item) => { 140 | const element = item as HTMLDivElement; 141 | element.style.width = "200px"; 142 | }); 143 | document.querySelectorAll(".card .content .right").forEach((item) => { 144 | const element = item as HTMLDivElement; 145 | element.style.width = "100%"; 146 | element.style.padding = "0"; 147 | }); 148 | gsap.to(".card .content .left span", { 149 | opacity: 1, 150 | duration: `${primaryDuration}`, 151 | }); 152 | gsap.to(".card .content .right", { 153 | y: 0, 154 | opacity: 1, 155 | duration: `${primaryDuration}`, 156 | display: "flex", 157 | onComplete: () => { 158 | groupBtn.disabled = false; 159 | }, 160 | }); 161 | }, 162 | }); 163 | } 164 | }); 165 | 166 | groupBtn.addEventListener("click", () => { 167 | if (!groupBtn.classList.contains("active")) { 168 | groupBtn.classList.add("active"); 169 | listBtn.classList.remove("active"); 170 | listBtn.disabled = true; 171 | 172 | gsap.to(".card .content .right", { 173 | y: 20, 174 | opacity: 0, 175 | display: "none", 176 | duration: `${primaryDuration}`, 177 | }); 178 | 179 | gsap.to(".card .content .left span", { 180 | opacity: 0, 181 | duration: `${primaryDuration}`, 182 | onComplete: () => { 183 | document.querySelectorAll(".card .content .right").forEach((item) => { 184 | const element = item as HTMLDivElement; 185 | element.style.width = "fit-content"; 186 | element.style.padding = "1.5rem 0 0 0"; 187 | }); 188 | document.querySelectorAll(".card .content .left").forEach((item) => { 189 | const element = item as HTMLDivElement; 190 | element.style.width = "fit-content"; 191 | }); 192 | }, 193 | }); 194 | 195 | gsap.to(".card", { 196 | width: "240px", 197 | left: (index) => (index % 3) * 250 + "px", 198 | delay: `${primaryDuration}`, 199 | duration: `${primaryDuration * 1.5}`, 200 | }); 201 | 202 | gsap.to(".card", { 203 | height: "210px", 204 | delay: `${primaryDuration * 2.3}`, 205 | duration: `${primaryDuration}`, 206 | onComplete: () => { 207 | gsap.to(".card .content .left span", { 208 | opacity: 1, 209 | duration: `${primaryDuration}`, 210 | }); 211 | gsap.to(".card .content .right", { 212 | y: 0, 213 | opacity: 1, 214 | display: "flex", 215 | duration: `${primaryDuration}`, 216 | }); 217 | }, 218 | }); 219 | 220 | gsap.to(".card:nth-child(2), .card:nth-child(5), .card:nth-child(8)", { 221 | y: 0, 222 | duration: `${primaryDuration}`, 223 | delay: `${primaryDuration * 3.3}`, 224 | }); 225 | 226 | gsap.to(".card:nth-child(3), .card:nth-child(6), .card:nth-child(9)", { 227 | y: 0, 228 | duration: `${primaryDuration}`, 229 | delay: `${primaryDuration * 3.3}`, 230 | onComplete: () => { 231 | listBtn.disabled = false; 232 | }, 233 | }); 234 | } 235 | }); 236 | -------------------------------------------------------------------------------- /src/style.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | } 6 | 7 | *, 8 | *::before, 9 | *::after { 10 | box-sizing: border-box; 11 | padding: 0; 12 | margin: 0; 13 | } 14 | 15 | body { 16 | width: 100%; 17 | display: flex; 18 | justify-content: center; 19 | align-items: flex-start; 20 | min-height: 100vh; 21 | background: #f8fafc; 22 | padding-bottom: 6rem; 23 | } 24 | 25 | #app-mobile { 26 | display: none; 27 | justify-content: center; 28 | align-items: center; 29 | min-height: 100vh; 30 | h3 { 31 | text-align: center; 32 | font-weight: 400; 33 | } 34 | @media screen and (max-width: 780px) { 35 | display: flex; 36 | } 37 | } 38 | 39 | #app-desktop { 40 | width: 100%; 41 | max-width: 740px; 42 | position: relative; 43 | @media screen and (max-width: 780px) { 44 | display: none; 45 | } 46 | } 47 | 48 | .header { 49 | width: 100%; 50 | padding: 1rem 0; 51 | display: flex; 52 | justify-content: flex-end; 53 | align-items: center; 54 | gap: 1rem; 55 | z-index: 5; 56 | button, 57 | a { 58 | display: flex; 59 | justify-content: center; 60 | align-items: center; 61 | width: 40px; 62 | height: 40px; 63 | border-radius: 50%; 64 | border: 1px solid #64748b; 65 | padding: 0.5rem; 66 | cursor: pointer; 67 | color: #64748b; 68 | transition: 0.3s; 69 | outline: none; 70 | background: #fff; 71 | &:hover, 72 | &.active { 73 | background: #e2e8f0; 74 | } 75 | svg { 76 | } 77 | } 78 | hr{ 79 | width: 1px; 80 | height: 20px; 81 | background: #64748b; 82 | } 83 | a { 84 | &:hover { 85 | background: #cffafe; 86 | } 87 | } 88 | } 89 | 90 | #main { 91 | position: relative; 92 | width: 100%; 93 | padding: 0 0.5rem 0 0.5rem; 94 | .card { 95 | position: absolute; 96 | width: 240px; 97 | height: 210px; 98 | .content { 99 | width: 100%; 100 | height: 100%; 101 | background: #e2e8f0; 102 | border-radius: 10px; 103 | border: 1px solid #cbd5e1; 104 | padding: 0.75rem; 105 | display: flex; 106 | justify-content: space-between; 107 | gap: 1.5rem; 108 | .left { 109 | display: flex; 110 | flex-direction: column; 111 | align-items: flex-start; 112 | h3 { 113 | color: #0f172a; 114 | font-size: 16px; 115 | } 116 | span { 117 | color: #334155; 118 | font-size: 12px; 119 | } 120 | } 121 | .right { 122 | display: flex; 123 | flex-direction: column; 124 | align-items: flex-start; 125 | gap: 0.25rem; 126 | padding: 1.5rem 0 0 0; 127 | button { 128 | outline: none; 129 | border: none; 130 | padding: 0.125rem 0.5rem; 131 | border-radius: 4px; 132 | font-weight: 400; 133 | background: #f1f5f9; 134 | font-size: 12px; 135 | } 136 | } 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | 16 | /* Linting */ 17 | "strict": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noFallthroughCasesInSwitch": true 21 | }, 22 | "include": ["src"] 23 | } 24 | --------------------------------------------------------------------------------