├── .gitattributes ├── .gitignore ├── README.md ├── assets ├── bundle │ ├── app.min.css │ ├── app.min.js │ └── filemanager.min.js ├── fonts │ ├── FontAwesome.otf │ ├── HindSiliguri-Regular.ttf │ ├── SolaimanLipi.ttf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ └── fontawesome-webfont.woff └── img │ ├── ajax-loader.gif │ ├── logo.png │ └── previews │ ├── doc.png │ ├── missing.png │ ├── pdf.png │ ├── txt.png │ ├── xls.png │ └── zip.png ├── composer.json ├── config └── filemanager.php ├── migrations └── 2020_05_02_100001_create_filemanager_table.php ├── previews ├── preview-desktop.png └── preview-mobile.png ├── routes └── web.php ├── src ├── Classes │ └── SimpleImage.php ├── Console │ └── FilemanagerInstall.php ├── Controllers │ └── FilemanagerController.php ├── Model │ └── Filemanager.php ├── ServiceProvider.php ├── helpers.php └── views │ ├── index.blade.php │ └── partials │ ├── action.blade.php │ ├── mobile.blade.php │ ├── popup.blade.php │ └── preview.blade.php └── translations ├── ar └── filemanager.php ├── bn └── filemanager.php ├── de └── filemanager.php ├── en └── filemanager.php ├── hi └── filemanager.php ├── id └── filemanager.php ├── ja └── filemanager.php └── ur └── filemanager.php /.gitattributes: -------------------------------------------------------------------------------- 1 | *.css linguist-detectable=false 2 | *.html linguist-detectable=false 3 | *.js linguist-detectable=false 4 | *.php linguist-detectable=true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | /__assets 3 | /.idea 4 | /node_modules 5 | /composer.lock 6 | /.phpunit.result.cache 7 | /gulpfile.js 8 | /package.json 9 | /package-lock.json -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Laravel Simple Filemanager

2 |

3 | 4 | 5 | 6 | 7 |

8 |

A simple filemanager for Laravel Framework

9 | 10 | ![Image description](previews/preview-desktop.png) 11 | 12 | ## Support 13 | Buy Me A Coffee 14 | 15 | ## Features 16 | - Multi-Language support (English, বাংলা, हिन्दी, العربية, German, Indonesian, 日本語). 17 | - Popular Editor Support: TinyMCE 4, TinyMCE 5, CKEditor, Summernote 18 | - Clean & fresh responsive UI 19 | - Easy to install 20 | - Configurable middleware 21 | - Configurable route 22 | - Drag and drop file upload 23 | - Single/Multiple file upload 24 | - Single file selection 25 | - Batch file selection 26 | - Convert image format 27 | - Batch file delete 28 | - File rename 29 | - Quick file search 30 | - File download 31 | - Event listener 32 | - and more 33 | 34 | ## Licence 35 | 36 | #### Commercial license 37 | If you want to use it to develop commercial sites, themes, projects, and applications, the Commercial license is the appropriate license. With this option, your source code is kept proprietary. To purchase a commercial license you need to buy a licence from the owner. [Contact for licence](https://laravelarticle.com/page/contact) 38 | - **$50** - 1 Developer 39 | - **$150** - Team (Upto 8 developers) 40 | - **$350** - Organization (Unlimited Developers) 41 | 42 | #### Open-source license 43 | Free for personal blog and non-commercial usages. If you are creating an open-source application then use it by following the [CC BY-NC 4.0](https://creativecommons.org/licenses/by-nc/4.0/) licence rules. 44 | 45 | 46 | ## Documentation 47 | Get full documentation of [Laravel Simple Filemanager](https://laravelarticle.com/laravel-simple-filemanager) 48 | 49 | 50 | ## Changelog 51 | v1.0.2 52 | - TinyMCE 5 support added 53 | 54 | -------------------------------------------------------------------------------- /assets/bundle/app.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Ladda 3 | * http://lab.hakim.se/ladda 4 | * MIT licensed 5 | * 6 | * Copyright (C) 2016 Hakim El Hattab, http://hakim.se 7 | */ 8 | .ladda-button { 9 | position: relative; 10 | } 11 | .ladda-button .ladda-spinner { 12 | position: absolute; 13 | z-index: 2; 14 | display: inline-block; 15 | width: 32px; 16 | height: 32px; 17 | top: 50%; 18 | margin-top: 0; 19 | opacity: 0; 20 | pointer-events: none; 21 | } 22 | .ladda-button .ladda-label { 23 | position: relative; 24 | z-index: 3; 25 | } 26 | .ladda-button .ladda-progress { 27 | position: absolute; 28 | width: 0; 29 | height: 100%; 30 | left: 0; 31 | top: 0; 32 | background: rgba(0, 0, 0, 0.2); 33 | visibility: hidden; 34 | opacity: 0; 35 | -webkit-transition: 0.1s linear all !important; 36 | -moz-transition: 0.1s linear all !important; 37 | -ms-transition: 0.1s linear all !important; 38 | -o-transition: 0.1s linear all !important; 39 | transition: 0.1s linear all !important; 40 | } 41 | .ladda-button[data-loading] .ladda-progress { 42 | opacity: 1; 43 | visibility: visible; 44 | } 45 | .ladda-button, 46 | .ladda-button .ladda-spinner, 47 | .ladda-button .ladda-label { 48 | -webkit-transition: 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all !important; 49 | -moz-transition: 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all !important; 50 | -ms-transition: 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all !important; 51 | -o-transition: 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all !important; 52 | transition: 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all !important; 53 | } 54 | .ladda-button[data-style=zoom-in], 55 | .ladda-button[data-style=zoom-in] .ladda-spinner, 56 | .ladda-button[data-style=zoom-in] .ladda-label, 57 | .ladda-button[data-style=zoom-out], 58 | .ladda-button[data-style=zoom-out] .ladda-spinner, 59 | .ladda-button[data-style=zoom-out] .ladda-label { 60 | -webkit-transition: 0.3s ease all !important; 61 | -moz-transition: 0.3s ease all !important; 62 | -ms-transition: 0.3s ease all !important; 63 | -o-transition: 0.3s ease all !important; 64 | transition: 0.3s ease all !important; 65 | } 66 | .ladda-button[data-style=expand-right] .ladda-spinner { 67 | right: -6px; 68 | } 69 | .ladda-button[data-style=expand-right][data-size="s"] .ladda-spinner, 70 | .ladda-button[data-style=expand-right][data-size="xs"] .ladda-spinner { 71 | right: -12px; 72 | } 73 | .ladda-button[data-style=expand-right][data-loading] { 74 | padding-right: 56px; 75 | } 76 | .ladda-button[data-style=expand-right][data-loading] .ladda-spinner { 77 | opacity: 1; 78 | } 79 | .ladda-button[data-style=expand-right][data-loading][data-size="s"], 80 | .ladda-button[data-style=expand-right][data-loading][data-size="xs"] { 81 | padding-right: 40px; 82 | } 83 | .ladda-button[data-style=expand-left] .ladda-spinner { 84 | left: 26px; 85 | } 86 | .ladda-button[data-style=expand-left][data-size="s"] .ladda-spinner, 87 | .ladda-button[data-style=expand-left][data-size="xs"] .ladda-spinner { 88 | left: 4px; 89 | } 90 | .ladda-button[data-style=expand-left][data-loading] { 91 | padding-left: 56px; 92 | } 93 | .ladda-button[data-style=expand-left][data-loading] .ladda-spinner { 94 | opacity: 1; 95 | } 96 | .ladda-button[data-style=expand-left][data-loading][data-size="s"], 97 | .ladda-button[data-style=expand-left][data-loading][data-size="xs"] { 98 | padding-left: 40px; 99 | } 100 | .ladda-button[data-style=expand-up] { 101 | overflow: hidden; 102 | } 103 | .ladda-button[data-style=expand-up] .ladda-spinner { 104 | top: -32px; 105 | left: 50%; 106 | margin-left: 0; 107 | } 108 | .ladda-button[data-style=expand-up][data-loading] { 109 | padding-top: 54px; 110 | } 111 | .ladda-button[data-style=expand-up][data-loading] .ladda-spinner { 112 | opacity: 1; 113 | top: 26px; 114 | margin-top: 0; 115 | } 116 | .ladda-button[data-style=expand-up][data-loading][data-size="s"], 117 | .ladda-button[data-style=expand-up][data-loading][data-size="xs"] { 118 | padding-top: 32px; 119 | } 120 | .ladda-button[data-style=expand-up][data-loading][data-size="s"] .ladda-spinner, 121 | .ladda-button[data-style=expand-up][data-loading][data-size="xs"] .ladda-spinner { 122 | top: 4px; 123 | } 124 | .ladda-button[data-style=expand-down] { 125 | overflow: hidden; 126 | } 127 | .ladda-button[data-style=expand-down] .ladda-spinner { 128 | top: 62px; 129 | left: 50%; 130 | margin-left: 0; 131 | } 132 | .ladda-button[data-style=expand-down][data-size="s"] .ladda-spinner, 133 | .ladda-button[data-style=expand-down][data-size="xs"] .ladda-spinner { 134 | top: 40px; 135 | } 136 | .ladda-button[data-style=expand-down][data-loading] { 137 | padding-bottom: 54px; 138 | } 139 | .ladda-button[data-style=expand-down][data-loading] .ladda-spinner { 140 | opacity: 1; 141 | } 142 | .ladda-button[data-style=expand-down][data-loading][data-size="s"], 143 | .ladda-button[data-style=expand-down][data-loading][data-size="xs"] { 144 | padding-bottom: 32px; 145 | } 146 | .ladda-button[data-style=slide-left] { 147 | overflow: hidden; 148 | } 149 | .ladda-button[data-style=slide-left] .ladda-label { 150 | position: relative; 151 | } 152 | .ladda-button[data-style=slide-left] .ladda-spinner { 153 | left: 100%; 154 | margin-left: 0; 155 | } 156 | .ladda-button[data-style=slide-left][data-loading] .ladda-label { 157 | opacity: 0; 158 | left: -100%; 159 | } 160 | .ladda-button[data-style=slide-left][data-loading] .ladda-spinner { 161 | opacity: 1; 162 | left: 50%; 163 | } 164 | .ladda-button[data-style=slide-right] { 165 | overflow: hidden; 166 | } 167 | .ladda-button[data-style=slide-right] .ladda-label { 168 | position: relative; 169 | } 170 | .ladda-button[data-style=slide-right] .ladda-spinner { 171 | right: 100%; 172 | margin-left: 0; 173 | left: 16px; 174 | } 175 | .ladda-button[data-style=slide-right][data-loading] .ladda-label { 176 | opacity: 0; 177 | left: 100%; 178 | } 179 | .ladda-button[data-style=slide-right][data-loading] .ladda-spinner { 180 | opacity: 1; 181 | left: 50%; 182 | } 183 | .ladda-button[data-style=slide-up] { 184 | overflow: hidden; 185 | } 186 | .ladda-button[data-style=slide-up] .ladda-label { 187 | position: relative; 188 | } 189 | .ladda-button[data-style=slide-up] .ladda-spinner { 190 | left: 50%; 191 | margin-left: 0; 192 | margin-top: 1em; 193 | } 194 | .ladda-button[data-style=slide-up][data-loading] .ladda-label { 195 | opacity: 0; 196 | top: -1em; 197 | } 198 | .ladda-button[data-style=slide-up][data-loading] .ladda-spinner { 199 | opacity: 1; 200 | margin-top: 0; 201 | } 202 | .ladda-button[data-style=slide-down] { 203 | overflow: hidden; 204 | } 205 | .ladda-button[data-style=slide-down] .ladda-label { 206 | position: relative; 207 | } 208 | .ladda-button[data-style=slide-down] .ladda-spinner { 209 | left: 50%; 210 | margin-left: 0; 211 | margin-top: -2em; 212 | } 213 | .ladda-button[data-style=slide-down][data-loading] .ladda-label { 214 | opacity: 0; 215 | top: 1em; 216 | } 217 | .ladda-button[data-style=slide-down][data-loading] .ladda-spinner { 218 | opacity: 1; 219 | margin-top: 0; 220 | } 221 | .ladda-button[data-style=zoom-out] { 222 | overflow: hidden; 223 | } 224 | .ladda-button[data-style=zoom-out] .ladda-spinner { 225 | left: 50%; 226 | margin-left: 32px; 227 | -webkit-transform: scale(2.5); 228 | -moz-transform: scale(2.5); 229 | -ms-transform: scale(2.5); 230 | -o-transform: scale(2.5); 231 | transform: scale(2.5); 232 | } 233 | .ladda-button[data-style=zoom-out] .ladda-label { 234 | position: relative; 235 | display: inline-block; 236 | } 237 | .ladda-button[data-style=zoom-out][data-loading] .ladda-label { 238 | opacity: 0; 239 | -webkit-transform: scale(0.5); 240 | -moz-transform: scale(0.5); 241 | -ms-transform: scale(0.5); 242 | -o-transform: scale(0.5); 243 | transform: scale(0.5); 244 | } 245 | .ladda-button[data-style=zoom-out][data-loading] .ladda-spinner { 246 | opacity: 1; 247 | margin-left: 0; 248 | -webkit-transform: none; 249 | -moz-transform: none; 250 | -ms-transform: none; 251 | -o-transform: none; 252 | transform: none; 253 | } 254 | .ladda-button[data-style=zoom-in] { 255 | overflow: hidden; 256 | } 257 | .ladda-button[data-style=zoom-in] .ladda-spinner { 258 | left: 50%; 259 | margin-left: -16px; 260 | -webkit-transform: scale(0.2); 261 | -moz-transform: scale(0.2); 262 | -ms-transform: scale(0.2); 263 | -o-transform: scale(0.2); 264 | transform: scale(0.2); 265 | } 266 | .ladda-button[data-style=zoom-in] .ladda-label { 267 | position: relative; 268 | display: inline-block; 269 | } 270 | .ladda-button[data-style=zoom-in][data-loading] .ladda-label { 271 | opacity: 0; 272 | -webkit-transform: scale(2.2); 273 | -moz-transform: scale(2.2); 274 | -ms-transform: scale(2.2); 275 | -o-transform: scale(2.2); 276 | transform: scale(2.2); 277 | } 278 | .ladda-button[data-style=zoom-in][data-loading] .ladda-spinner { 279 | opacity: 1; 280 | margin-left: 0; 281 | -webkit-transform: none; 282 | -moz-transform: none; 283 | -ms-transform: none; 284 | -o-transform: none; 285 | transform: none; 286 | } 287 | .ladda-button[data-style=contract] { 288 | overflow: hidden; 289 | width: 100px; 290 | } 291 | .ladda-button[data-style=contract] .ladda-spinner { 292 | left: 50%; 293 | margin-left: 0; 294 | } 295 | .ladda-button[data-style=contract][data-loading] { 296 | border-radius: 50%; 297 | width: 52px; 298 | } 299 | .ladda-button[data-style=contract][data-loading] .ladda-label { 300 | opacity: 0; 301 | } 302 | .ladda-button[data-style=contract][data-loading] .ladda-spinner { 303 | opacity: 1; 304 | } 305 | .ladda-button[data-style=contract-overlay] { 306 | overflow: hidden; 307 | width: 100px; 308 | box-shadow: 0px 0px 0px 2000px transparent; 309 | } 310 | .ladda-button[data-style=contract-overlay] .ladda-spinner { 311 | left: 50%; 312 | margin-left: 0; 313 | } 314 | .ladda-button[data-style=contract-overlay][data-loading] { 315 | border-radius: 50%; 316 | width: 52px; 317 | box-shadow: 0px 0px 0px 2000px rgba(0, 0, 0, 0.8); 318 | } 319 | .ladda-button[data-style=contract-overlay][data-loading] .ladda-label { 320 | opacity: 0; 321 | } 322 | .ladda-button[data-style=contract-overlay][data-loading] .ladda-spinner { 323 | opacity: 1; 324 | } 325 | 326 | @-webkit-keyframes passing-through { 327 | 0% { 328 | opacity: 0; 329 | -webkit-transform: translateY(40px); 330 | -moz-transform: translateY(40px); 331 | -ms-transform: translateY(40px); 332 | -o-transform: translateY(40px); 333 | transform: translateY(40px); 334 | } 335 | 30%, 336 | 70% { 337 | opacity: 1; 338 | -webkit-transform: translateY(0px); 339 | -moz-transform: translateY(0px); 340 | -ms-transform: translateY(0px); 341 | -o-transform: translateY(0px); 342 | transform: translateY(0px); 343 | } 344 | 100% { 345 | opacity: 0; 346 | -webkit-transform: translateY(-40px); 347 | -moz-transform: translateY(-40px); 348 | -ms-transform: translateY(-40px); 349 | -o-transform: translateY(-40px); 350 | transform: translateY(-40px); 351 | } 352 | } 353 | @-moz-keyframes passing-through { 354 | 0% { 355 | opacity: 0; 356 | -webkit-transform: translateY(40px); 357 | -moz-transform: translateY(40px); 358 | -ms-transform: translateY(40px); 359 | -o-transform: translateY(40px); 360 | transform: translateY(40px); 361 | } 362 | 30%, 363 | 70% { 364 | opacity: 1; 365 | -webkit-transform: translateY(0px); 366 | -moz-transform: translateY(0px); 367 | -ms-transform: translateY(0px); 368 | -o-transform: translateY(0px); 369 | transform: translateY(0px); 370 | } 371 | 100% { 372 | opacity: 0; 373 | -webkit-transform: translateY(-40px); 374 | -moz-transform: translateY(-40px); 375 | -ms-transform: translateY(-40px); 376 | -o-transform: translateY(-40px); 377 | transform: translateY(-40px); 378 | } 379 | } 380 | @keyframes passing-through { 381 | 0% { 382 | opacity: 0; 383 | -webkit-transform: translateY(40px); 384 | -moz-transform: translateY(40px); 385 | -ms-transform: translateY(40px); 386 | -o-transform: translateY(40px); 387 | transform: translateY(40px); 388 | } 389 | 30%, 390 | 70% { 391 | opacity: 1; 392 | -webkit-transform: translateY(0px); 393 | -moz-transform: translateY(0px); 394 | -ms-transform: translateY(0px); 395 | -o-transform: translateY(0px); 396 | transform: translateY(0px); 397 | } 398 | 100% { 399 | opacity: 0; 400 | -webkit-transform: translateY(-40px); 401 | -moz-transform: translateY(-40px); 402 | -ms-transform: translateY(-40px); 403 | -o-transform: translateY(-40px); 404 | transform: translateY(-40px); 405 | } 406 | } 407 | @-webkit-keyframes slide-in { 408 | 0% { 409 | opacity: 0; 410 | -webkit-transform: translateY(40px); 411 | -moz-transform: translateY(40px); 412 | -ms-transform: translateY(40px); 413 | -o-transform: translateY(40px); 414 | transform: translateY(40px); 415 | } 416 | 30% { 417 | opacity: 1; 418 | -webkit-transform: translateY(0px); 419 | -moz-transform: translateY(0px); 420 | -ms-transform: translateY(0px); 421 | -o-transform: translateY(0px); 422 | transform: translateY(0px); 423 | } 424 | } 425 | @-moz-keyframes slide-in { 426 | 0% { 427 | opacity: 0; 428 | -webkit-transform: translateY(40px); 429 | -moz-transform: translateY(40px); 430 | -ms-transform: translateY(40px); 431 | -o-transform: translateY(40px); 432 | transform: translateY(40px); 433 | } 434 | 30% { 435 | opacity: 1; 436 | -webkit-transform: translateY(0px); 437 | -moz-transform: translateY(0px); 438 | -ms-transform: translateY(0px); 439 | -o-transform: translateY(0px); 440 | transform: translateY(0px); 441 | } 442 | } 443 | @keyframes slide-in { 444 | 0% { 445 | opacity: 0; 446 | -webkit-transform: translateY(40px); 447 | -moz-transform: translateY(40px); 448 | -ms-transform: translateY(40px); 449 | -o-transform: translateY(40px); 450 | transform: translateY(40px); 451 | } 452 | 30% { 453 | opacity: 1; 454 | -webkit-transform: translateY(0px); 455 | -moz-transform: translateY(0px); 456 | -ms-transform: translateY(0px); 457 | -o-transform: translateY(0px); 458 | transform: translateY(0px); 459 | } 460 | } 461 | @-webkit-keyframes pulse { 462 | 0% { 463 | -webkit-transform: scale(1); 464 | -moz-transform: scale(1); 465 | -ms-transform: scale(1); 466 | -o-transform: scale(1); 467 | transform: scale(1); 468 | } 469 | 10% { 470 | -webkit-transform: scale(1.1); 471 | -moz-transform: scale(1.1); 472 | -ms-transform: scale(1.1); 473 | -o-transform: scale(1.1); 474 | transform: scale(1.1); 475 | } 476 | 20% { 477 | -webkit-transform: scale(1); 478 | -moz-transform: scale(1); 479 | -ms-transform: scale(1); 480 | -o-transform: scale(1); 481 | transform: scale(1); 482 | } 483 | } 484 | @-moz-keyframes pulse { 485 | 0% { 486 | -webkit-transform: scale(1); 487 | -moz-transform: scale(1); 488 | -ms-transform: scale(1); 489 | -o-transform: scale(1); 490 | transform: scale(1); 491 | } 492 | 10% { 493 | -webkit-transform: scale(1.1); 494 | -moz-transform: scale(1.1); 495 | -ms-transform: scale(1.1); 496 | -o-transform: scale(1.1); 497 | transform: scale(1.1); 498 | } 499 | 20% { 500 | -webkit-transform: scale(1); 501 | -moz-transform: scale(1); 502 | -ms-transform: scale(1); 503 | -o-transform: scale(1); 504 | transform: scale(1); 505 | } 506 | } 507 | @keyframes pulse { 508 | 0% { 509 | -webkit-transform: scale(1); 510 | -moz-transform: scale(1); 511 | -ms-transform: scale(1); 512 | -o-transform: scale(1); 513 | transform: scale(1); 514 | } 515 | 10% { 516 | -webkit-transform: scale(1.1); 517 | -moz-transform: scale(1.1); 518 | -ms-transform: scale(1.1); 519 | -o-transform: scale(1.1); 520 | transform: scale(1.1); 521 | } 522 | 20% { 523 | -webkit-transform: scale(1); 524 | -moz-transform: scale(1); 525 | -ms-transform: scale(1); 526 | -o-transform: scale(1); 527 | transform: scale(1); 528 | } 529 | } 530 | .dropzone, 531 | .dropzone * { 532 | box-sizing: border-box; 533 | } 534 | .dropzone { 535 | min-height: 150px; 536 | border: 2px solid rgba(0, 0, 0, 0.3); 537 | background: white; 538 | padding: 20px 20px; 539 | } 540 | .dropzone.dz-clickable { 541 | cursor: pointer; 542 | } 543 | .dropzone.dz-clickable * { 544 | cursor: default; 545 | } 546 | .dropzone.dz-clickable .dz-message, 547 | .dropzone.dz-clickable .dz-message * { 548 | cursor: pointer; 549 | } 550 | .dropzone.dz-started .dz-message { 551 | display: none; 552 | } 553 | .dropzone.dz-drag-hover { 554 | border-style: solid; 555 | } 556 | .dropzone.dz-drag-hover .dz-message { 557 | opacity: 0.5; 558 | } 559 | .dropzone .dz-message { 560 | text-align: center; 561 | margin: 2em 0; 562 | } 563 | .dropzone .dz-preview { 564 | position: relative; 565 | display: inline-block; 566 | vertical-align: top; 567 | margin: 16px; 568 | min-height: 100px; 569 | } 570 | .dropzone .dz-preview:hover { 571 | z-index: 1000; 572 | } 573 | .dropzone .dz-preview:hover .dz-details { 574 | opacity: 1; 575 | } 576 | .dropzone .dz-preview.dz-file-preview .dz-image { 577 | border-radius: 20px; 578 | background: #999; 579 | background: linear-gradient(to bottom, #eee, #ddd); 580 | } 581 | .dropzone .dz-preview.dz-file-preview .dz-details { 582 | opacity: 1; 583 | } 584 | .dropzone .dz-preview.dz-image-preview { 585 | background: white; 586 | } 587 | .dropzone .dz-preview.dz-image-preview .dz-details { 588 | -webkit-transition: opacity 0.2s linear; 589 | -moz-transition: opacity 0.2s linear; 590 | -ms-transition: opacity 0.2s linear; 591 | -o-transition: opacity 0.2s linear; 592 | transition: opacity 0.2s linear; 593 | } 594 | .dropzone .dz-preview .dz-remove { 595 | font-size: 14px; 596 | text-align: center; 597 | display: block; 598 | cursor: pointer; 599 | border: none; 600 | } 601 | .dropzone .dz-preview .dz-remove:hover { 602 | text-decoration: underline; 603 | } 604 | .dropzone .dz-preview:hover .dz-details { 605 | opacity: 1; 606 | } 607 | .dropzone .dz-preview .dz-details { 608 | z-index: 20; 609 | position: absolute; 610 | top: 0; 611 | left: 0; 612 | opacity: 0; 613 | font-size: 13px; 614 | min-width: 100%; 615 | max-width: 100%; 616 | padding: 2em 1em; 617 | text-align: center; 618 | color: rgba(0, 0, 0, 0.9); 619 | line-height: 150%; 620 | } 621 | .dropzone .dz-preview .dz-details .dz-size { 622 | margin-bottom: 1em; 623 | font-size: 16px; 624 | } 625 | .dropzone .dz-preview .dz-details .dz-filename { 626 | white-space: nowrap; 627 | } 628 | .dropzone .dz-preview .dz-details .dz-filename:hover span { 629 | border: 1px solid rgba(200, 200, 200, 0.8); 630 | background-color: rgba(255, 255, 255, 0.8); 631 | } 632 | .dropzone .dz-preview .dz-details .dz-filename:not(:hover) { 633 | overflow: hidden; 634 | text-overflow: ellipsis; 635 | } 636 | .dropzone .dz-preview .dz-details .dz-filename:not(:hover) span { 637 | border: 1px solid transparent; 638 | } 639 | .dropzone .dz-preview .dz-details .dz-filename span, 640 | .dropzone .dz-preview .dz-details .dz-size span { 641 | background-color: rgba(255, 255, 255, 0.4); 642 | padding: 0 0.4em; 643 | border-radius: 3px; 644 | } 645 | .dropzone .dz-preview:hover .dz-image img { 646 | -webkit-transform: scale(1.05, 1.05); 647 | -moz-transform: scale(1.05, 1.05); 648 | -ms-transform: scale(1.05, 1.05); 649 | -o-transform: scale(1.05, 1.05); 650 | transform: scale(1.05, 1.05); 651 | -webkit-filter: blur(8px); 652 | filter: blur(8px); 653 | } 654 | .dropzone .dz-preview .dz-image { 655 | border-radius: 20px; 656 | overflow: hidden; 657 | width: 120px; 658 | height: 120px; 659 | position: relative; 660 | display: block; 661 | z-index: 10; 662 | } 663 | .dropzone .dz-preview .dz-image img { 664 | display: block; 665 | } 666 | .dropzone .dz-preview.dz-success .dz-success-mark { 667 | -webkit-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); 668 | -moz-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); 669 | -ms-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); 670 | -o-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); 671 | animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); 672 | } 673 | .dropzone .dz-preview.dz-error .dz-error-mark { 674 | opacity: 1; 675 | -webkit-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); 676 | -moz-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); 677 | -ms-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); 678 | -o-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); 679 | animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); 680 | } 681 | .dropzone .dz-preview .dz-success-mark, 682 | .dropzone .dz-preview .dz-error-mark { 683 | pointer-events: none; 684 | opacity: 0; 685 | z-index: 500; 686 | position: absolute; 687 | display: block; 688 | top: 50%; 689 | left: 50%; 690 | margin-left: -27px; 691 | margin-top: -27px; 692 | } 693 | .dropzone .dz-preview .dz-success-mark svg, 694 | .dropzone .dz-preview .dz-error-mark svg { 695 | display: block; 696 | width: 54px; 697 | height: 54px; 698 | } 699 | .dropzone .dz-preview.dz-processing .dz-progress { 700 | opacity: 1; 701 | -webkit-transition: all 0.2s linear; 702 | -moz-transition: all 0.2s linear; 703 | -ms-transition: all 0.2s linear; 704 | -o-transition: all 0.2s linear; 705 | transition: all 0.2s linear; 706 | } 707 | .dropzone .dz-preview.dz-complete .dz-progress { 708 | opacity: 0; 709 | -webkit-transition: opacity 0.4s ease-in; 710 | -moz-transition: opacity 0.4s ease-in; 711 | -ms-transition: opacity 0.4s ease-in; 712 | -o-transition: opacity 0.4s ease-in; 713 | transition: opacity 0.4s ease-in; 714 | } 715 | .dropzone .dz-preview:not(.dz-processing) .dz-progress { 716 | -webkit-animation: pulse 6s ease infinite; 717 | -moz-animation: pulse 6s ease infinite; 718 | -ms-animation: pulse 6s ease infinite; 719 | -o-animation: pulse 6s ease infinite; 720 | animation: pulse 6s ease infinite; 721 | } 722 | .dropzone .dz-preview .dz-progress { 723 | opacity: 1; 724 | z-index: 1000; 725 | pointer-events: none; 726 | position: absolute; 727 | height: 16px; 728 | left: 50%; 729 | top: 50%; 730 | margin-top: -8px; 731 | width: 80px; 732 | margin-left: -40px; 733 | background: rgba(255, 255, 255, 0.9); 734 | -webkit-transform: scale(1); 735 | border-radius: 8px; 736 | overflow: hidden; 737 | } 738 | .dropzone .dz-preview .dz-progress .dz-upload { 739 | background: #333; 740 | background: linear-gradient(to bottom, #666, #444); 741 | position: absolute; 742 | top: 0; 743 | left: 0; 744 | bottom: 0; 745 | width: 0; 746 | -webkit-transition: width 300ms ease-in-out; 747 | -moz-transition: width 300ms ease-in-out; 748 | -ms-transition: width 300ms ease-in-out; 749 | -o-transition: width 300ms ease-in-out; 750 | transition: width 300ms ease-in-out; 751 | } 752 | .dropzone .dz-preview.dz-error .dz-error-message { 753 | display: block; 754 | } 755 | .dropzone .dz-preview.dz-error:hover .dz-error-message { 756 | opacity: 1; 757 | pointer-events: auto; 758 | } 759 | .dropzone .dz-preview .dz-error-message { 760 | pointer-events: none; 761 | z-index: 1000; 762 | position: absolute; 763 | display: block; 764 | display: none; 765 | opacity: 0; 766 | -webkit-transition: opacity 0.3s ease; 767 | -moz-transition: opacity 0.3s ease; 768 | -ms-transition: opacity 0.3s ease; 769 | -o-transition: opacity 0.3s ease; 770 | transition: opacity 0.3s ease; 771 | border-radius: 8px; 772 | font-size: 13px; 773 | top: 130px; 774 | left: -10px; 775 | width: 140px; 776 | background: #be2626; 777 | background: linear-gradient(to bottom, #be2626, #a92222); 778 | padding: 0.5em 1.2em; 779 | color: white; 780 | } 781 | .dropzone .dz-preview .dz-error-message:after { 782 | content: ''; 783 | position: absolute; 784 | top: -6px; 785 | left: 64px; 786 | width: 0; 787 | height: 0; 788 | border-left: 6px solid transparent; 789 | border-right: 6px solid transparent; 790 | border-bottom: 6px solid #be2626; 791 | } 792 | 793 | /*! 794 | * Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome 795 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 796 | */ 797 | @font-face { 798 | font-family: 'FontAwesome'; 799 | src: url('../fonts/fontawesome-webfont.eot?v=4.2.0'); 800 | src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.2.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff?v=4.2.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.2.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular') format('svg'); 801 | font-weight: normal; 802 | font-style: normal; 803 | } 804 | .fa { 805 | display: inline-block; 806 | font: normal normal normal 14px/1 FontAwesome; 807 | font-size: inherit; 808 | text-rendering: auto; 809 | -webkit-font-smoothing: antialiased; 810 | -moz-osx-font-smoothing: grayscale; 811 | } 812 | .fa-lg { 813 | font-size: 1.33333333em; 814 | line-height: 0.75em; 815 | vertical-align: -15%; 816 | } 817 | .fa-2x { 818 | font-size: 2em; 819 | } 820 | .fa-3x { 821 | font-size: 3em; 822 | } 823 | .fa-4x { 824 | font-size: 4em; 825 | } 826 | .fa-5x { 827 | font-size: 5em; 828 | } 829 | .fa-fw { 830 | width: 1.28571429em; 831 | text-align: center; 832 | } 833 | .fa-ul { 834 | padding-left: 0; 835 | margin-left: 2.14285714em; 836 | list-style-type: none; 837 | } 838 | .fa-ul > li { 839 | position: relative; 840 | } 841 | .fa-li { 842 | position: absolute; 843 | left: -2.14285714em; 844 | width: 2.14285714em; 845 | top: 0.14285714em; 846 | text-align: center; 847 | } 848 | .fa-li.fa-lg { 849 | left: -1.85714286em; 850 | } 851 | .fa-border { 852 | padding: 0.2em 0.25em 0.15em; 853 | border: solid 0.08em #eee; 854 | border-radius: 0.1em; 855 | } 856 | .pull-right { 857 | float: right; 858 | } 859 | .pull-left { 860 | float: left; 861 | } 862 | .fa.pull-left { 863 | margin-right: 0.3em; 864 | } 865 | .fa.pull-right { 866 | margin-left: 0.3em; 867 | } 868 | .fa-spin { 869 | -webkit-animation: fa-spin 2s infinite linear; 870 | animation: fa-spin 2s infinite linear; 871 | } 872 | @-webkit-keyframes fa-spin { 873 | 0% { 874 | -webkit-transform: rotate(0deg); 875 | transform: rotate(0deg); 876 | } 877 | 100% { 878 | -webkit-transform: rotate(359deg); 879 | transform: rotate(359deg); 880 | } 881 | } 882 | @keyframes fa-spin { 883 | 0% { 884 | -webkit-transform: rotate(0deg); 885 | transform: rotate(0deg); 886 | } 887 | 100% { 888 | -webkit-transform: rotate(359deg); 889 | transform: rotate(359deg); 890 | } 891 | } 892 | .fa-rotate-90 { 893 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1); 894 | -webkit-transform: rotate(90deg); 895 | -ms-transform: rotate(90deg); 896 | transform: rotate(90deg); 897 | } 898 | .fa-rotate-180 { 899 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); 900 | -webkit-transform: rotate(180deg); 901 | -ms-transform: rotate(180deg); 902 | transform: rotate(180deg); 903 | } 904 | .fa-rotate-270 { 905 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); 906 | -webkit-transform: rotate(270deg); 907 | -ms-transform: rotate(270deg); 908 | transform: rotate(270deg); 909 | } 910 | .fa-flip-horizontal { 911 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1); 912 | -webkit-transform: scale(-1, 1); 913 | -ms-transform: scale(-1, 1); 914 | transform: scale(-1, 1); 915 | } 916 | .fa-flip-vertical { 917 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1); 918 | -webkit-transform: scale(1, -1); 919 | -ms-transform: scale(1, -1); 920 | transform: scale(1, -1); 921 | } 922 | :root .fa-rotate-90, 923 | :root .fa-rotate-180, 924 | :root .fa-rotate-270, 925 | :root .fa-flip-horizontal, 926 | :root .fa-flip-vertical { 927 | filter: none; 928 | } 929 | .fa-stack { 930 | position: relative; 931 | display: inline-block; 932 | width: 2em; 933 | height: 2em; 934 | line-height: 2em; 935 | vertical-align: middle; 936 | } 937 | .fa-stack-1x, 938 | .fa-stack-2x { 939 | position: absolute; 940 | left: 0; 941 | width: 100%; 942 | text-align: center; 943 | } 944 | .fa-stack-1x { 945 | line-height: inherit; 946 | } 947 | .fa-stack-2x { 948 | font-size: 2em; 949 | } 950 | .fa-inverse { 951 | color: #fff; 952 | } 953 | .fa-glass:before { 954 | content: "\f000"; 955 | } 956 | .fa-music:before { 957 | content: "\f001"; 958 | } 959 | .fa-search:before { 960 | content: "\f002"; 961 | } 962 | .fa-envelope-o:before { 963 | content: "\f003"; 964 | } 965 | .fa-heart:before { 966 | content: "\f004"; 967 | } 968 | .fa-star:before { 969 | content: "\f005"; 970 | } 971 | .fa-star-o:before { 972 | content: "\f006"; 973 | } 974 | .fa-user:before { 975 | content: "\f007"; 976 | } 977 | .fa-film:before { 978 | content: "\f008"; 979 | } 980 | .fa-th-large:before { 981 | content: "\f009"; 982 | } 983 | .fa-th:before { 984 | content: "\f00a"; 985 | } 986 | .fa-th-list:before { 987 | content: "\f00b"; 988 | } 989 | .fa-check:before { 990 | content: "\f00c"; 991 | } 992 | .fa-remove:before, 993 | .fa-close:before, 994 | .fa-times:before { 995 | content: "\f00d"; 996 | } 997 | .fa-search-plus:before { 998 | content: "\f00e"; 999 | } 1000 | .fa-search-minus:before { 1001 | content: "\f010"; 1002 | } 1003 | .fa-power-off:before { 1004 | content: "\f011"; 1005 | } 1006 | .fa-signal:before { 1007 | content: "\f012"; 1008 | } 1009 | .fa-gear:before, 1010 | .fa-cog:before { 1011 | content: "\f013"; 1012 | } 1013 | .fa-trash-o:before { 1014 | content: "\f014"; 1015 | } 1016 | .fa-home:before { 1017 | content: "\f015"; 1018 | } 1019 | .fa-file-o:before { 1020 | content: "\f016"; 1021 | } 1022 | .fa-clock-o:before { 1023 | content: "\f017"; 1024 | } 1025 | .fa-road:before { 1026 | content: "\f018"; 1027 | } 1028 | .fa-download:before { 1029 | content: "\f019"; 1030 | } 1031 | .fa-arrow-circle-o-down:before { 1032 | content: "\f01a"; 1033 | } 1034 | .fa-arrow-circle-o-up:before { 1035 | content: "\f01b"; 1036 | } 1037 | .fa-inbox:before { 1038 | content: "\f01c"; 1039 | } 1040 | .fa-play-circle-o:before { 1041 | content: "\f01d"; 1042 | } 1043 | .fa-rotate-right:before, 1044 | .fa-repeat:before { 1045 | content: "\f01e"; 1046 | } 1047 | .fa-refresh:before { 1048 | content: "\f021"; 1049 | } 1050 | .fa-list-alt:before { 1051 | content: "\f022"; 1052 | } 1053 | .fa-lock:before { 1054 | content: "\f023"; 1055 | } 1056 | .fa-flag:before { 1057 | content: "\f024"; 1058 | } 1059 | .fa-headphones:before { 1060 | content: "\f025"; 1061 | } 1062 | .fa-volume-off:before { 1063 | content: "\f026"; 1064 | } 1065 | .fa-volume-down:before { 1066 | content: "\f027"; 1067 | } 1068 | .fa-volume-up:before { 1069 | content: "\f028"; 1070 | } 1071 | .fa-qrcode:before { 1072 | content: "\f029"; 1073 | } 1074 | .fa-barcode:before { 1075 | content: "\f02a"; 1076 | } 1077 | .fa-tag:before { 1078 | content: "\f02b"; 1079 | } 1080 | .fa-tags:before { 1081 | content: "\f02c"; 1082 | } 1083 | .fa-book:before { 1084 | content: "\f02d"; 1085 | } 1086 | .fa-bookmark:before { 1087 | content: "\f02e"; 1088 | } 1089 | .fa-print:before { 1090 | content: "\f02f"; 1091 | } 1092 | .fa-camera:before { 1093 | content: "\f030"; 1094 | } 1095 | .fa-font:before { 1096 | content: "\f031"; 1097 | } 1098 | .fa-bold:before { 1099 | content: "\f032"; 1100 | } 1101 | .fa-italic:before { 1102 | content: "\f033"; 1103 | } 1104 | .fa-text-height:before { 1105 | content: "\f034"; 1106 | } 1107 | .fa-text-width:before { 1108 | content: "\f035"; 1109 | } 1110 | .fa-align-left:before { 1111 | content: "\f036"; 1112 | } 1113 | .fa-align-center:before { 1114 | content: "\f037"; 1115 | } 1116 | .fa-align-right:before { 1117 | content: "\f038"; 1118 | } 1119 | .fa-align-justify:before { 1120 | content: "\f039"; 1121 | } 1122 | .fa-list:before { 1123 | content: "\f03a"; 1124 | } 1125 | .fa-dedent:before, 1126 | .fa-outdent:before { 1127 | content: "\f03b"; 1128 | } 1129 | .fa-indent:before { 1130 | content: "\f03c"; 1131 | } 1132 | .fa-video-camera:before { 1133 | content: "\f03d"; 1134 | } 1135 | .fa-photo:before, 1136 | .fa-image:before, 1137 | .fa-picture-o:before { 1138 | content: "\f03e"; 1139 | } 1140 | .fa-pencil:before { 1141 | content: "\f040"; 1142 | } 1143 | .fa-map-marker:before { 1144 | content: "\f041"; 1145 | } 1146 | .fa-adjust:before { 1147 | content: "\f042"; 1148 | } 1149 | .fa-tint:before { 1150 | content: "\f043"; 1151 | } 1152 | .fa-edit:before, 1153 | .fa-pencil-square-o:before { 1154 | content: "\f044"; 1155 | } 1156 | .fa-share-square-o:before { 1157 | content: "\f045"; 1158 | } 1159 | .fa-check-square-o:before { 1160 | content: "\f046"; 1161 | } 1162 | .fa-arrows:before { 1163 | content: "\f047"; 1164 | } 1165 | .fa-step-backward:before { 1166 | content: "\f048"; 1167 | } 1168 | .fa-fast-backward:before { 1169 | content: "\f049"; 1170 | } 1171 | .fa-backward:before { 1172 | content: "\f04a"; 1173 | } 1174 | .fa-play:before { 1175 | content: "\f04b"; 1176 | } 1177 | .fa-pause:before { 1178 | content: "\f04c"; 1179 | } 1180 | .fa-stop:before { 1181 | content: "\f04d"; 1182 | } 1183 | .fa-forward:before { 1184 | content: "\f04e"; 1185 | } 1186 | .fa-fast-forward:before { 1187 | content: "\f050"; 1188 | } 1189 | .fa-step-forward:before { 1190 | content: "\f051"; 1191 | } 1192 | .fa-eject:before { 1193 | content: "\f052"; 1194 | } 1195 | .fa-chevron-left:before { 1196 | content: "\f053"; 1197 | } 1198 | .fa-chevron-right:before { 1199 | content: "\f054"; 1200 | } 1201 | .fa-plus-circle:before { 1202 | content: "\f055"; 1203 | } 1204 | .fa-minus-circle:before { 1205 | content: "\f056"; 1206 | } 1207 | .fa-times-circle:before { 1208 | content: "\f057"; 1209 | } 1210 | .fa-check-circle:before { 1211 | content: "\f058"; 1212 | } 1213 | .fa-question-circle:before { 1214 | content: "\f059"; 1215 | } 1216 | .fa-info-circle:before { 1217 | content: "\f05a"; 1218 | } 1219 | .fa-crosshairs:before { 1220 | content: "\f05b"; 1221 | } 1222 | .fa-times-circle-o:before { 1223 | content: "\f05c"; 1224 | } 1225 | .fa-check-circle-o:before { 1226 | content: "\f05d"; 1227 | } 1228 | .fa-ban:before { 1229 | content: "\f05e"; 1230 | } 1231 | .fa-arrow-left:before { 1232 | content: "\f060"; 1233 | } 1234 | .fa-arrow-right:before { 1235 | content: "\f061"; 1236 | } 1237 | .fa-arrow-up:before { 1238 | content: "\f062"; 1239 | } 1240 | .fa-arrow-down:before { 1241 | content: "\f063"; 1242 | } 1243 | .fa-mail-forward:before, 1244 | .fa-share:before { 1245 | content: "\f064"; 1246 | } 1247 | .fa-expand:before { 1248 | content: "\f065"; 1249 | } 1250 | .fa-compress:before { 1251 | content: "\f066"; 1252 | } 1253 | .fa-plus:before { 1254 | content: "\f067"; 1255 | } 1256 | .fa-minus:before { 1257 | content: "\f068"; 1258 | } 1259 | .fa-asterisk:before { 1260 | content: "\f069"; 1261 | } 1262 | .fa-exclamation-circle:before { 1263 | content: "\f06a"; 1264 | } 1265 | .fa-gift:before { 1266 | content: "\f06b"; 1267 | } 1268 | .fa-leaf:before { 1269 | content: "\f06c"; 1270 | } 1271 | .fa-fire:before { 1272 | content: "\f06d"; 1273 | } 1274 | .fa-eye:before { 1275 | content: "\f06e"; 1276 | } 1277 | .fa-eye-slash:before { 1278 | content: "\f070"; 1279 | } 1280 | .fa-warning:before, 1281 | .fa-exclamation-triangle:before { 1282 | content: "\f071"; 1283 | } 1284 | .fa-plane:before { 1285 | content: "\f072"; 1286 | } 1287 | .fa-calendar:before { 1288 | content: "\f073"; 1289 | } 1290 | .fa-random:before { 1291 | content: "\f074"; 1292 | } 1293 | .fa-comment:before { 1294 | content: "\f075"; 1295 | } 1296 | .fa-magnet:before { 1297 | content: "\f076"; 1298 | } 1299 | .fa-chevron-up:before { 1300 | content: "\f077"; 1301 | } 1302 | .fa-chevron-down:before { 1303 | content: "\f078"; 1304 | } 1305 | .fa-retweet:before { 1306 | content: "\f079"; 1307 | } 1308 | .fa-shopping-cart:before { 1309 | content: "\f07a"; 1310 | } 1311 | .fa-folder:before { 1312 | content: "\f07b"; 1313 | } 1314 | .fa-folder-open:before { 1315 | content: "\f07c"; 1316 | } 1317 | .fa-arrows-v:before { 1318 | content: "\f07d"; 1319 | } 1320 | .fa-arrows-h:before { 1321 | content: "\f07e"; 1322 | } 1323 | .fa-bar-chart-o:before, 1324 | .fa-bar-chart:before { 1325 | content: "\f080"; 1326 | } 1327 | .fa-twitter-square:before { 1328 | content: "\f081"; 1329 | } 1330 | .fa-facebook-square:before { 1331 | content: "\f082"; 1332 | } 1333 | .fa-camera-retro:before { 1334 | content: "\f083"; 1335 | } 1336 | .fa-key:before { 1337 | content: "\f084"; 1338 | } 1339 | .fa-gears:before, 1340 | .fa-cogs:before { 1341 | content: "\f085"; 1342 | } 1343 | .fa-comments:before { 1344 | content: "\f086"; 1345 | } 1346 | .fa-thumbs-o-up:before { 1347 | content: "\f087"; 1348 | } 1349 | .fa-thumbs-o-down:before { 1350 | content: "\f088"; 1351 | } 1352 | .fa-star-half:before { 1353 | content: "\f089"; 1354 | } 1355 | .fa-heart-o:before { 1356 | content: "\f08a"; 1357 | } 1358 | .fa-sign-out:before { 1359 | content: "\f08b"; 1360 | } 1361 | .fa-linkedin-square:before { 1362 | content: "\f08c"; 1363 | } 1364 | .fa-thumb-tack:before { 1365 | content: "\f08d"; 1366 | } 1367 | .fa-external-link:before { 1368 | content: "\f08e"; 1369 | } 1370 | .fa-sign-in:before { 1371 | content: "\f090"; 1372 | } 1373 | .fa-trophy:before { 1374 | content: "\f091"; 1375 | } 1376 | .fa-github-square:before { 1377 | content: "\f092"; 1378 | } 1379 | .fa-upload:before { 1380 | content: "\f093"; 1381 | } 1382 | .fa-lemon-o:before { 1383 | content: "\f094"; 1384 | } 1385 | .fa-phone:before { 1386 | content: "\f095"; 1387 | } 1388 | .fa-square-o:before { 1389 | content: "\f096"; 1390 | } 1391 | .fa-bookmark-o:before { 1392 | content: "\f097"; 1393 | } 1394 | .fa-phone-square:before { 1395 | content: "\f098"; 1396 | } 1397 | .fa-twitter:before { 1398 | content: "\f099"; 1399 | } 1400 | .fa-facebook:before { 1401 | content: "\f09a"; 1402 | } 1403 | .fa-github:before { 1404 | content: "\f09b"; 1405 | } 1406 | .fa-unlock:before { 1407 | content: "\f09c"; 1408 | } 1409 | .fa-credit-card:before { 1410 | content: "\f09d"; 1411 | } 1412 | .fa-rss:before { 1413 | content: "\f09e"; 1414 | } 1415 | .fa-hdd-o:before { 1416 | content: "\f0a0"; 1417 | } 1418 | .fa-bullhorn:before { 1419 | content: "\f0a1"; 1420 | } 1421 | .fa-bell:before { 1422 | content: "\f0f3"; 1423 | } 1424 | .fa-certificate:before { 1425 | content: "\f0a3"; 1426 | } 1427 | .fa-hand-o-right:before { 1428 | content: "\f0a4"; 1429 | } 1430 | .fa-hand-o-left:before { 1431 | content: "\f0a5"; 1432 | } 1433 | .fa-hand-o-up:before { 1434 | content: "\f0a6"; 1435 | } 1436 | .fa-hand-o-down:before { 1437 | content: "\f0a7"; 1438 | } 1439 | .fa-arrow-circle-left:before { 1440 | content: "\f0a8"; 1441 | } 1442 | .fa-arrow-circle-right:before { 1443 | content: "\f0a9"; 1444 | } 1445 | .fa-arrow-circle-up:before { 1446 | content: "\f0aa"; 1447 | } 1448 | .fa-arrow-circle-down:before { 1449 | content: "\f0ab"; 1450 | } 1451 | .fa-globe:before { 1452 | content: "\f0ac"; 1453 | } 1454 | .fa-wrench:before { 1455 | content: "\f0ad"; 1456 | } 1457 | .fa-tasks:before { 1458 | content: "\f0ae"; 1459 | } 1460 | .fa-filter:before { 1461 | content: "\f0b0"; 1462 | } 1463 | .fa-briefcase:before { 1464 | content: "\f0b1"; 1465 | } 1466 | .fa-arrows-alt:before { 1467 | content: "\f0b2"; 1468 | } 1469 | .fa-group:before, 1470 | .fa-users:before { 1471 | content: "\f0c0"; 1472 | } 1473 | .fa-chain:before, 1474 | .fa-link:before { 1475 | content: "\f0c1"; 1476 | } 1477 | .fa-cloud:before { 1478 | content: "\f0c2"; 1479 | } 1480 | .fa-flask:before { 1481 | content: "\f0c3"; 1482 | } 1483 | .fa-cut:before, 1484 | .fa-scissors:before { 1485 | content: "\f0c4"; 1486 | } 1487 | .fa-copy:before, 1488 | .fa-files-o:before { 1489 | content: "\f0c5"; 1490 | } 1491 | .fa-paperclip:before { 1492 | content: "\f0c6"; 1493 | } 1494 | .fa-save:before, 1495 | .fa-floppy-o:before { 1496 | content: "\f0c7"; 1497 | } 1498 | .fa-square:before { 1499 | content: "\f0c8"; 1500 | } 1501 | .fa-navicon:before, 1502 | .fa-reorder:before, 1503 | .fa-bars:before { 1504 | content: "\f0c9"; 1505 | } 1506 | .fa-list-ul:before { 1507 | content: "\f0ca"; 1508 | } 1509 | .fa-list-ol:before { 1510 | content: "\f0cb"; 1511 | } 1512 | .fa-strikethrough:before { 1513 | content: "\f0cc"; 1514 | } 1515 | .fa-underline:before { 1516 | content: "\f0cd"; 1517 | } 1518 | .fa-table:before { 1519 | content: "\f0ce"; 1520 | } 1521 | .fa-magic:before { 1522 | content: "\f0d0"; 1523 | } 1524 | .fa-truck:before { 1525 | content: "\f0d1"; 1526 | } 1527 | .fa-pinterest:before { 1528 | content: "\f0d2"; 1529 | } 1530 | .fa-pinterest-square:before { 1531 | content: "\f0d3"; 1532 | } 1533 | .fa-google-plus-square:before { 1534 | content: "\f0d4"; 1535 | } 1536 | .fa-google-plus:before { 1537 | content: "\f0d5"; 1538 | } 1539 | .fa-money:before { 1540 | content: "\f0d6"; 1541 | } 1542 | .fa-caret-down:before { 1543 | content: "\f0d7"; 1544 | } 1545 | .fa-caret-up:before { 1546 | content: "\f0d8"; 1547 | } 1548 | .fa-caret-left:before { 1549 | content: "\f0d9"; 1550 | } 1551 | .fa-caret-right:before { 1552 | content: "\f0da"; 1553 | } 1554 | .fa-columns:before { 1555 | content: "\f0db"; 1556 | } 1557 | .fa-unsorted:before, 1558 | .fa-sort:before { 1559 | content: "\f0dc"; 1560 | } 1561 | .fa-sort-down:before, 1562 | .fa-sort-desc:before { 1563 | content: "\f0dd"; 1564 | } 1565 | .fa-sort-up:before, 1566 | .fa-sort-asc:before { 1567 | content: "\f0de"; 1568 | } 1569 | .fa-envelope:before { 1570 | content: "\f0e0"; 1571 | } 1572 | .fa-linkedin:before { 1573 | content: "\f0e1"; 1574 | } 1575 | .fa-rotate-left:before, 1576 | .fa-undo:before { 1577 | content: "\f0e2"; 1578 | } 1579 | .fa-legal:before, 1580 | .fa-gavel:before { 1581 | content: "\f0e3"; 1582 | } 1583 | .fa-dashboard:before, 1584 | .fa-tachometer:before { 1585 | content: "\f0e4"; 1586 | } 1587 | .fa-comment-o:before { 1588 | content: "\f0e5"; 1589 | } 1590 | .fa-comments-o:before { 1591 | content: "\f0e6"; 1592 | } 1593 | .fa-flash:before, 1594 | .fa-bolt:before { 1595 | content: "\f0e7"; 1596 | } 1597 | .fa-sitemap:before { 1598 | content: "\f0e8"; 1599 | } 1600 | .fa-umbrella:before { 1601 | content: "\f0e9"; 1602 | } 1603 | .fa-paste:before, 1604 | .fa-clipboard:before { 1605 | content: "\f0ea"; 1606 | } 1607 | .fa-lightbulb-o:before { 1608 | content: "\f0eb"; 1609 | } 1610 | .fa-exchange:before { 1611 | content: "\f0ec"; 1612 | } 1613 | .fa-cloud-download:before { 1614 | content: "\f0ed"; 1615 | } 1616 | .fa-cloud-upload:before { 1617 | content: "\f0ee"; 1618 | } 1619 | .fa-user-md:before { 1620 | content: "\f0f0"; 1621 | } 1622 | .fa-stethoscope:before { 1623 | content: "\f0f1"; 1624 | } 1625 | .fa-suitcase:before { 1626 | content: "\f0f2"; 1627 | } 1628 | .fa-bell-o:before { 1629 | content: "\f0a2"; 1630 | } 1631 | .fa-coffee:before { 1632 | content: "\f0f4"; 1633 | } 1634 | .fa-cutlery:before { 1635 | content: "\f0f5"; 1636 | } 1637 | .fa-file-text-o:before { 1638 | content: "\f0f6"; 1639 | } 1640 | .fa-building-o:before { 1641 | content: "\f0f7"; 1642 | } 1643 | .fa-hospital-o:before { 1644 | content: "\f0f8"; 1645 | } 1646 | .fa-ambulance:before { 1647 | content: "\f0f9"; 1648 | } 1649 | .fa-medkit:before { 1650 | content: "\f0fa"; 1651 | } 1652 | .fa-fighter-jet:before { 1653 | content: "\f0fb"; 1654 | } 1655 | .fa-beer:before { 1656 | content: "\f0fc"; 1657 | } 1658 | .fa-h-square:before { 1659 | content: "\f0fd"; 1660 | } 1661 | .fa-plus-square:before { 1662 | content: "\f0fe"; 1663 | } 1664 | .fa-angle-double-left:before { 1665 | content: "\f100"; 1666 | } 1667 | .fa-angle-double-right:before { 1668 | content: "\f101"; 1669 | } 1670 | .fa-angle-double-up:before { 1671 | content: "\f102"; 1672 | } 1673 | .fa-angle-double-down:before { 1674 | content: "\f103"; 1675 | } 1676 | .fa-angle-left:before { 1677 | content: "\f104"; 1678 | } 1679 | .fa-angle-right:before { 1680 | content: "\f105"; 1681 | } 1682 | .fa-angle-up:before { 1683 | content: "\f106"; 1684 | } 1685 | .fa-angle-down:before { 1686 | content: "\f107"; 1687 | } 1688 | .fa-desktop:before { 1689 | content: "\f108"; 1690 | } 1691 | .fa-laptop:before { 1692 | content: "\f109"; 1693 | } 1694 | .fa-tablet:before { 1695 | content: "\f10a"; 1696 | } 1697 | .fa-mobile-phone:before, 1698 | .fa-mobile:before { 1699 | content: "\f10b"; 1700 | } 1701 | .fa-circle-o:before { 1702 | content: "\f10c"; 1703 | } 1704 | .fa-quote-left:before { 1705 | content: "\f10d"; 1706 | } 1707 | .fa-quote-right:before { 1708 | content: "\f10e"; 1709 | } 1710 | .fa-spinner:before { 1711 | content: "\f110"; 1712 | } 1713 | .fa-circle:before { 1714 | content: "\f111"; 1715 | } 1716 | .fa-mail-reply:before, 1717 | .fa-reply:before { 1718 | content: "\f112"; 1719 | } 1720 | .fa-github-alt:before { 1721 | content: "\f113"; 1722 | } 1723 | .fa-folder-o:before { 1724 | content: "\f114"; 1725 | } 1726 | .fa-folder-open-o:before { 1727 | content: "\f115"; 1728 | } 1729 | .fa-smile-o:before { 1730 | content: "\f118"; 1731 | } 1732 | .fa-frown-o:before { 1733 | content: "\f119"; 1734 | } 1735 | .fa-meh-o:before { 1736 | content: "\f11a"; 1737 | } 1738 | .fa-gamepad:before { 1739 | content: "\f11b"; 1740 | } 1741 | .fa-keyboard-o:before { 1742 | content: "\f11c"; 1743 | } 1744 | .fa-flag-o:before { 1745 | content: "\f11d"; 1746 | } 1747 | .fa-flag-checkered:before { 1748 | content: "\f11e"; 1749 | } 1750 | .fa-terminal:before { 1751 | content: "\f120"; 1752 | } 1753 | .fa-code:before { 1754 | content: "\f121"; 1755 | } 1756 | .fa-mail-reply-all:before, 1757 | .fa-reply-all:before { 1758 | content: "\f122"; 1759 | } 1760 | .fa-star-half-empty:before, 1761 | .fa-star-half-full:before, 1762 | .fa-star-half-o:before { 1763 | content: "\f123"; 1764 | } 1765 | .fa-location-arrow:before { 1766 | content: "\f124"; 1767 | } 1768 | .fa-crop:before { 1769 | content: "\f125"; 1770 | } 1771 | .fa-code-fork:before { 1772 | content: "\f126"; 1773 | } 1774 | .fa-unlink:before, 1775 | .fa-chain-broken:before { 1776 | content: "\f127"; 1777 | } 1778 | .fa-question:before { 1779 | content: "\f128"; 1780 | } 1781 | .fa-info:before { 1782 | content: "\f129"; 1783 | } 1784 | .fa-exclamation:before { 1785 | content: "\f12a"; 1786 | } 1787 | .fa-superscript:before { 1788 | content: "\f12b"; 1789 | } 1790 | .fa-subscript:before { 1791 | content: "\f12c"; 1792 | } 1793 | .fa-eraser:before { 1794 | content: "\f12d"; 1795 | } 1796 | .fa-puzzle-piece:before { 1797 | content: "\f12e"; 1798 | } 1799 | .fa-microphone:before { 1800 | content: "\f130"; 1801 | } 1802 | .fa-microphone-slash:before { 1803 | content: "\f131"; 1804 | } 1805 | .fa-shield:before { 1806 | content: "\f132"; 1807 | } 1808 | .fa-calendar-o:before { 1809 | content: "\f133"; 1810 | } 1811 | .fa-fire-extinguisher:before { 1812 | content: "\f134"; 1813 | } 1814 | .fa-rocket:before { 1815 | content: "\f135"; 1816 | } 1817 | .fa-maxcdn:before { 1818 | content: "\f136"; 1819 | } 1820 | .fa-chevron-circle-left:before { 1821 | content: "\f137"; 1822 | } 1823 | .fa-chevron-circle-right:before { 1824 | content: "\f138"; 1825 | } 1826 | .fa-chevron-circle-up:before { 1827 | content: "\f139"; 1828 | } 1829 | .fa-chevron-circle-down:before { 1830 | content: "\f13a"; 1831 | } 1832 | .fa-html5:before { 1833 | content: "\f13b"; 1834 | } 1835 | .fa-css3:before { 1836 | content: "\f13c"; 1837 | } 1838 | .fa-anchor:before { 1839 | content: "\f13d"; 1840 | } 1841 | .fa-unlock-alt:before { 1842 | content: "\f13e"; 1843 | } 1844 | .fa-bullseye:before { 1845 | content: "\f140"; 1846 | } 1847 | .fa-ellipsis-h:before { 1848 | content: "\f141"; 1849 | } 1850 | .fa-ellipsis-v:before { 1851 | content: "\f142"; 1852 | } 1853 | .fa-rss-square:before { 1854 | content: "\f143"; 1855 | } 1856 | .fa-play-circle:before { 1857 | content: "\f144"; 1858 | } 1859 | .fa-ticket:before { 1860 | content: "\f145"; 1861 | } 1862 | .fa-minus-square:before { 1863 | content: "\f146"; 1864 | } 1865 | .fa-minus-square-o:before { 1866 | content: "\f147"; 1867 | } 1868 | .fa-level-up:before { 1869 | content: "\f148"; 1870 | } 1871 | .fa-level-down:before { 1872 | content: "\f149"; 1873 | } 1874 | .fa-check-square:before { 1875 | content: "\f14a"; 1876 | } 1877 | .fa-pencil-square:before { 1878 | content: "\f14b"; 1879 | } 1880 | .fa-external-link-square:before { 1881 | content: "\f14c"; 1882 | } 1883 | .fa-share-square:before { 1884 | content: "\f14d"; 1885 | } 1886 | .fa-compass:before { 1887 | content: "\f14e"; 1888 | } 1889 | .fa-toggle-down:before, 1890 | .fa-caret-square-o-down:before { 1891 | content: "\f150"; 1892 | } 1893 | .fa-toggle-up:before, 1894 | .fa-caret-square-o-up:before { 1895 | content: "\f151"; 1896 | } 1897 | .fa-toggle-right:before, 1898 | .fa-caret-square-o-right:before { 1899 | content: "\f152"; 1900 | } 1901 | .fa-euro:before, 1902 | .fa-eur:before { 1903 | content: "\f153"; 1904 | } 1905 | .fa-gbp:before { 1906 | content: "\f154"; 1907 | } 1908 | .fa-dollar:before, 1909 | .fa-usd:before { 1910 | content: "\f155"; 1911 | } 1912 | .fa-rupee:before, 1913 | .fa-inr:before { 1914 | content: "\f156"; 1915 | } 1916 | .fa-cny:before, 1917 | .fa-rmb:before, 1918 | .fa-yen:before, 1919 | .fa-jpy:before { 1920 | content: "\f157"; 1921 | } 1922 | .fa-ruble:before, 1923 | .fa-rouble:before, 1924 | .fa-rub:before { 1925 | content: "\f158"; 1926 | } 1927 | .fa-won:before, 1928 | .fa-krw:before { 1929 | content: "\f159"; 1930 | } 1931 | .fa-bitcoin:before, 1932 | .fa-btc:before { 1933 | content: "\f15a"; 1934 | } 1935 | .fa-file:before { 1936 | content: "\f15b"; 1937 | } 1938 | .fa-file-text:before { 1939 | content: "\f15c"; 1940 | } 1941 | .fa-sort-alpha-asc:before { 1942 | content: "\f15d"; 1943 | } 1944 | .fa-sort-alpha-desc:before { 1945 | content: "\f15e"; 1946 | } 1947 | .fa-sort-amount-asc:before { 1948 | content: "\f160"; 1949 | } 1950 | .fa-sort-amount-desc:before { 1951 | content: "\f161"; 1952 | } 1953 | .fa-sort-numeric-asc:before { 1954 | content: "\f162"; 1955 | } 1956 | .fa-sort-numeric-desc:before { 1957 | content: "\f163"; 1958 | } 1959 | .fa-thumbs-up:before { 1960 | content: "\f164"; 1961 | } 1962 | .fa-thumbs-down:before { 1963 | content: "\f165"; 1964 | } 1965 | .fa-youtube-square:before { 1966 | content: "\f166"; 1967 | } 1968 | .fa-youtube:before { 1969 | content: "\f167"; 1970 | } 1971 | .fa-xing:before { 1972 | content: "\f168"; 1973 | } 1974 | .fa-xing-square:before { 1975 | content: "\f169"; 1976 | } 1977 | .fa-youtube-play:before { 1978 | content: "\f16a"; 1979 | } 1980 | .fa-dropbox:before { 1981 | content: "\f16b"; 1982 | } 1983 | .fa-stack-overflow:before { 1984 | content: "\f16c"; 1985 | } 1986 | .fa-instagram:before { 1987 | content: "\f16d"; 1988 | } 1989 | .fa-flickr:before { 1990 | content: "\f16e"; 1991 | } 1992 | .fa-adn:before { 1993 | content: "\f170"; 1994 | } 1995 | .fa-bitbucket:before { 1996 | content: "\f171"; 1997 | } 1998 | .fa-bitbucket-square:before { 1999 | content: "\f172"; 2000 | } 2001 | .fa-tumblr:before { 2002 | content: "\f173"; 2003 | } 2004 | .fa-tumblr-square:before { 2005 | content: "\f174"; 2006 | } 2007 | .fa-long-arrow-down:before { 2008 | content: "\f175"; 2009 | } 2010 | .fa-long-arrow-up:before { 2011 | content: "\f176"; 2012 | } 2013 | .fa-long-arrow-left:before { 2014 | content: "\f177"; 2015 | } 2016 | .fa-long-arrow-right:before { 2017 | content: "\f178"; 2018 | } 2019 | .fa-apple:before { 2020 | content: "\f179"; 2021 | } 2022 | .fa-windows:before { 2023 | content: "\f17a"; 2024 | } 2025 | .fa-android:before { 2026 | content: "\f17b"; 2027 | } 2028 | .fa-linux:before { 2029 | content: "\f17c"; 2030 | } 2031 | .fa-dribbble:before { 2032 | content: "\f17d"; 2033 | } 2034 | .fa-skype:before { 2035 | content: "\f17e"; 2036 | } 2037 | .fa-foursquare:before { 2038 | content: "\f180"; 2039 | } 2040 | .fa-trello:before { 2041 | content: "\f181"; 2042 | } 2043 | .fa-female:before { 2044 | content: "\f182"; 2045 | } 2046 | .fa-male:before { 2047 | content: "\f183"; 2048 | } 2049 | .fa-gittip:before { 2050 | content: "\f184"; 2051 | } 2052 | .fa-sun-o:before { 2053 | content: "\f185"; 2054 | } 2055 | .fa-moon-o:before { 2056 | content: "\f186"; 2057 | } 2058 | .fa-archive:before { 2059 | content: "\f187"; 2060 | } 2061 | .fa-bug:before { 2062 | content: "\f188"; 2063 | } 2064 | .fa-vk:before { 2065 | content: "\f189"; 2066 | } 2067 | .fa-weibo:before { 2068 | content: "\f18a"; 2069 | } 2070 | .fa-renren:before { 2071 | content: "\f18b"; 2072 | } 2073 | .fa-pagelines:before { 2074 | content: "\f18c"; 2075 | } 2076 | .fa-stack-exchange:before { 2077 | content: "\f18d"; 2078 | } 2079 | .fa-arrow-circle-o-right:before { 2080 | content: "\f18e"; 2081 | } 2082 | .fa-arrow-circle-o-left:before { 2083 | content: "\f190"; 2084 | } 2085 | .fa-toggle-left:before, 2086 | .fa-caret-square-o-left:before { 2087 | content: "\f191"; 2088 | } 2089 | .fa-dot-circle-o:before { 2090 | content: "\f192"; 2091 | } 2092 | .fa-wheelchair:before { 2093 | content: "\f193"; 2094 | } 2095 | .fa-vimeo-square:before { 2096 | content: "\f194"; 2097 | } 2098 | .fa-turkish-lira:before, 2099 | .fa-try:before { 2100 | content: "\f195"; 2101 | } 2102 | .fa-plus-square-o:before { 2103 | content: "\f196"; 2104 | } 2105 | .fa-space-shuttle:before { 2106 | content: "\f197"; 2107 | } 2108 | .fa-slack:before { 2109 | content: "\f198"; 2110 | } 2111 | .fa-envelope-square:before { 2112 | content: "\f199"; 2113 | } 2114 | .fa-wordpress:before { 2115 | content: "\f19a"; 2116 | } 2117 | .fa-openid:before { 2118 | content: "\f19b"; 2119 | } 2120 | .fa-institution:before, 2121 | .fa-bank:before, 2122 | .fa-university:before { 2123 | content: "\f19c"; 2124 | } 2125 | .fa-mortar-board:before, 2126 | .fa-graduation-cap:before { 2127 | content: "\f19d"; 2128 | } 2129 | .fa-yahoo:before { 2130 | content: "\f19e"; 2131 | } 2132 | .fa-google:before { 2133 | content: "\f1a0"; 2134 | } 2135 | .fa-reddit:before { 2136 | content: "\f1a1"; 2137 | } 2138 | .fa-reddit-square:before { 2139 | content: "\f1a2"; 2140 | } 2141 | .fa-stumbleupon-circle:before { 2142 | content: "\f1a3"; 2143 | } 2144 | .fa-stumbleupon:before { 2145 | content: "\f1a4"; 2146 | } 2147 | .fa-delicious:before { 2148 | content: "\f1a5"; 2149 | } 2150 | .fa-digg:before { 2151 | content: "\f1a6"; 2152 | } 2153 | .fa-pied-piper:before { 2154 | content: "\f1a7"; 2155 | } 2156 | .fa-pied-piper-alt:before { 2157 | content: "\f1a8"; 2158 | } 2159 | .fa-drupal:before { 2160 | content: "\f1a9"; 2161 | } 2162 | .fa-joomla:before { 2163 | content: "\f1aa"; 2164 | } 2165 | .fa-language:before { 2166 | content: "\f1ab"; 2167 | } 2168 | .fa-fax:before { 2169 | content: "\f1ac"; 2170 | } 2171 | .fa-building:before { 2172 | content: "\f1ad"; 2173 | } 2174 | .fa-child:before { 2175 | content: "\f1ae"; 2176 | } 2177 | .fa-paw:before { 2178 | content: "\f1b0"; 2179 | } 2180 | .fa-spoon:before { 2181 | content: "\f1b1"; 2182 | } 2183 | .fa-cube:before { 2184 | content: "\f1b2"; 2185 | } 2186 | .fa-cubes:before { 2187 | content: "\f1b3"; 2188 | } 2189 | .fa-behance:before { 2190 | content: "\f1b4"; 2191 | } 2192 | .fa-behance-square:before { 2193 | content: "\f1b5"; 2194 | } 2195 | .fa-steam:before { 2196 | content: "\f1b6"; 2197 | } 2198 | .fa-steam-square:before { 2199 | content: "\f1b7"; 2200 | } 2201 | .fa-recycle:before { 2202 | content: "\f1b8"; 2203 | } 2204 | .fa-automobile:before, 2205 | .fa-car:before { 2206 | content: "\f1b9"; 2207 | } 2208 | .fa-cab:before, 2209 | .fa-taxi:before { 2210 | content: "\f1ba"; 2211 | } 2212 | .fa-tree:before { 2213 | content: "\f1bb"; 2214 | } 2215 | .fa-spotify:before { 2216 | content: "\f1bc"; 2217 | } 2218 | .fa-deviantart:before { 2219 | content: "\f1bd"; 2220 | } 2221 | .fa-soundcloud:before { 2222 | content: "\f1be"; 2223 | } 2224 | .fa-database:before { 2225 | content: "\f1c0"; 2226 | } 2227 | .fa-file-pdf-o:before { 2228 | content: "\f1c1"; 2229 | } 2230 | .fa-file-word-o:before { 2231 | content: "\f1c2"; 2232 | } 2233 | .fa-file-excel-o:before { 2234 | content: "\f1c3"; 2235 | } 2236 | .fa-file-powerpoint-o:before { 2237 | content: "\f1c4"; 2238 | } 2239 | .fa-file-photo-o:before, 2240 | .fa-file-picture-o:before, 2241 | .fa-file-image-o:before { 2242 | content: "\f1c5"; 2243 | } 2244 | .fa-file-zip-o:before, 2245 | .fa-file-archive-o:before { 2246 | content: "\f1c6"; 2247 | } 2248 | .fa-file-sound-o:before, 2249 | .fa-file-audio-o:before { 2250 | content: "\f1c7"; 2251 | } 2252 | .fa-file-movie-o:before, 2253 | .fa-file-video-o:before { 2254 | content: "\f1c8"; 2255 | } 2256 | .fa-file-code-o:before { 2257 | content: "\f1c9"; 2258 | } 2259 | .fa-vine:before { 2260 | content: "\f1ca"; 2261 | } 2262 | .fa-codepen:before { 2263 | content: "\f1cb"; 2264 | } 2265 | .fa-jsfiddle:before { 2266 | content: "\f1cc"; 2267 | } 2268 | .fa-life-bouy:before, 2269 | .fa-life-buoy:before, 2270 | .fa-life-saver:before, 2271 | .fa-support:before, 2272 | .fa-life-ring:before { 2273 | content: "\f1cd"; 2274 | } 2275 | .fa-circle-o-notch:before { 2276 | content: "\f1ce"; 2277 | } 2278 | .fa-ra:before, 2279 | .fa-rebel:before { 2280 | content: "\f1d0"; 2281 | } 2282 | .fa-ge:before, 2283 | .fa-empire:before { 2284 | content: "\f1d1"; 2285 | } 2286 | .fa-git-square:before { 2287 | content: "\f1d2"; 2288 | } 2289 | .fa-git:before { 2290 | content: "\f1d3"; 2291 | } 2292 | .fa-hacker-news:before { 2293 | content: "\f1d4"; 2294 | } 2295 | .fa-tencent-weibo:before { 2296 | content: "\f1d5"; 2297 | } 2298 | .fa-qq:before { 2299 | content: "\f1d6"; 2300 | } 2301 | .fa-wechat:before, 2302 | .fa-weixin:before { 2303 | content: "\f1d7"; 2304 | } 2305 | .fa-send:before, 2306 | .fa-paper-plane:before { 2307 | content: "\f1d8"; 2308 | } 2309 | .fa-send-o:before, 2310 | .fa-paper-plane-o:before { 2311 | content: "\f1d9"; 2312 | } 2313 | .fa-history:before { 2314 | content: "\f1da"; 2315 | } 2316 | .fa-circle-thin:before { 2317 | content: "\f1db"; 2318 | } 2319 | .fa-header:before { 2320 | content: "\f1dc"; 2321 | } 2322 | .fa-paragraph:before { 2323 | content: "\f1dd"; 2324 | } 2325 | .fa-sliders:before { 2326 | content: "\f1de"; 2327 | } 2328 | .fa-share-alt:before { 2329 | content: "\f1e0"; 2330 | } 2331 | .fa-share-alt-square:before { 2332 | content: "\f1e1"; 2333 | } 2334 | .fa-bomb:before { 2335 | content: "\f1e2"; 2336 | } 2337 | .fa-soccer-ball-o:before, 2338 | .fa-futbol-o:before { 2339 | content: "\f1e3"; 2340 | } 2341 | .fa-tty:before { 2342 | content: "\f1e4"; 2343 | } 2344 | .fa-binoculars:before { 2345 | content: "\f1e5"; 2346 | } 2347 | .fa-plug:before { 2348 | content: "\f1e6"; 2349 | } 2350 | .fa-slideshare:before { 2351 | content: "\f1e7"; 2352 | } 2353 | .fa-twitch:before { 2354 | content: "\f1e8"; 2355 | } 2356 | .fa-yelp:before { 2357 | content: "\f1e9"; 2358 | } 2359 | .fa-newspaper-o:before { 2360 | content: "\f1ea"; 2361 | } 2362 | .fa-wifi:before { 2363 | content: "\f1eb"; 2364 | } 2365 | .fa-calculator:before { 2366 | content: "\f1ec"; 2367 | } 2368 | .fa-paypal:before { 2369 | content: "\f1ed"; 2370 | } 2371 | .fa-google-wallet:before { 2372 | content: "\f1ee"; 2373 | } 2374 | .fa-cc-visa:before { 2375 | content: "\f1f0"; 2376 | } 2377 | .fa-cc-mastercard:before { 2378 | content: "\f1f1"; 2379 | } 2380 | .fa-cc-discover:before { 2381 | content: "\f1f2"; 2382 | } 2383 | .fa-cc-amex:before { 2384 | content: "\f1f3"; 2385 | } 2386 | .fa-cc-paypal:before { 2387 | content: "\f1f4"; 2388 | } 2389 | .fa-cc-stripe:before { 2390 | content: "\f1f5"; 2391 | } 2392 | .fa-bell-slash:before { 2393 | content: "\f1f6"; 2394 | } 2395 | .fa-bell-slash-o:before { 2396 | content: "\f1f7"; 2397 | } 2398 | .fa-trash:before { 2399 | content: "\f1f8"; 2400 | } 2401 | .fa-copyright:before { 2402 | content: "\f1f9"; 2403 | } 2404 | .fa-at:before { 2405 | content: "\f1fa"; 2406 | } 2407 | .fa-eyedropper:before { 2408 | content: "\f1fb"; 2409 | } 2410 | .fa-paint-brush:before { 2411 | content: "\f1fc"; 2412 | } 2413 | .fa-birthday-cake:before { 2414 | content: "\f1fd"; 2415 | } 2416 | .fa-area-chart:before { 2417 | content: "\f1fe"; 2418 | } 2419 | .fa-pie-chart:before { 2420 | content: "\f200"; 2421 | } 2422 | .fa-line-chart:before { 2423 | content: "\f201"; 2424 | } 2425 | .fa-lastfm:before { 2426 | content: "\f202"; 2427 | } 2428 | .fa-lastfm-square:before { 2429 | content: "\f203"; 2430 | } 2431 | .fa-toggle-off:before { 2432 | content: "\f204"; 2433 | } 2434 | .fa-toggle-on:before { 2435 | content: "\f205"; 2436 | } 2437 | .fa-bicycle:before { 2438 | content: "\f206"; 2439 | } 2440 | .fa-bus:before { 2441 | content: "\f207"; 2442 | } 2443 | .fa-ioxhost:before { 2444 | content: "\f208"; 2445 | } 2446 | .fa-angellist:before { 2447 | content: "\f209"; 2448 | } 2449 | .fa-cc:before { 2450 | content: "\f20a"; 2451 | } 2452 | .fa-shekel:before, 2453 | .fa-sheqel:before, 2454 | .fa-ils:before { 2455 | content: "\f20b"; 2456 | } 2457 | .fa-meanpath:before { 2458 | content: "\f20c"; 2459 | } 2460 | 2461 | .makeAbsoluteFullDiv { 2462 | position: absolute; 2463 | height: 100%; 2464 | width: 100%; 2465 | top: 0; 2466 | left: 0; 2467 | } 2468 | @font-face { 2469 | font-family: 'SolaimanLipi'; 2470 | src: url('../fonts/solaimanlipi.ttf') format('truetype'); 2471 | font-weight: normal; 2472 | font-style: normal; 2473 | } 2474 | @font-face { 2475 | font-family: 'Hind Siliguri'; 2476 | src: url('../fonts/HindSiliguri-Regular.ttf') format('opentype'); 2477 | font-weight: normal; 2478 | font-style: normal; 2479 | } 2480 | * { 2481 | margin: 0; 2482 | padding: 0; 2483 | box-sizing: border-box; 2484 | font-family: sans-serif; 2485 | } 2486 | .bn div, 2487 | .bn span, 2488 | .bn p, 2489 | .bn input::placeholder, 2490 | .bn button, 2491 | .bn a { 2492 | font-family: 'SolaimanLipi', sans-serif; 2493 | } 2494 | .bn h2 { 2495 | font-family: "Hind Siliguri", sans-serif; 2496 | margin-top: -8px; 2497 | } 2498 | .btn_mobile_upload, 2499 | .btn_mobile_upload_close, 2500 | .btn_mobile_preview, 2501 | .dz-size { 2502 | display: none; 2503 | } 2504 | .dz_preview_container { 2505 | margin-top: 10px; 2506 | } 2507 | .dz_custom_preview_box { 2508 | display: none; 2509 | } 2510 | .dz_custom_preview { 2511 | display: flex; 2512 | overflow: hidden; 2513 | border-bottom: 1px solid #ddd; 2514 | align-items: center; 2515 | color: #333; 2516 | margin-bottom: 3px; 2517 | background: white; 2518 | padding: 5px 10px; 2519 | font-size: 13px; 2520 | } 2521 | .dz_custom_preview .image { 2522 | min-width: 50px; 2523 | max-width: 50px; 2524 | max-height: 50px; 2525 | overflow: hidden; 2526 | margin-right: 10px; 2527 | } 2528 | .dz_custom_preview .image img { 2529 | width: 100%; 2530 | height: 100%; 2531 | } 2532 | .dz_custom_preview .info { 2533 | margin-right: 5px; 2534 | white-space: nowrap; 2535 | text-overflow: ellipsis; 2536 | overflow: hidden; 2537 | flex-grow: 1; 2538 | } 2539 | .dz_custom_preview .info .dz-filename { 2540 | max-height: 35px; 2541 | } 2542 | .dz_custom_preview .info .dz-progress { 2543 | background: #ddd; 2544 | height: 3px; 2545 | margin-top: 5px; 2546 | } 2547 | .dz_custom_preview .info .dz-progress span.dz-upload { 2548 | background: orange; 2549 | height: 3px; 2550 | display: block; 2551 | width: 0; 2552 | } 2553 | .btn { 2554 | border: none; 2555 | padding: 2px 8px; 2556 | border-radius: 4px; 2557 | margin: 0 2px; 2558 | height: 30px; 2559 | cursor: pointer; 2560 | line-height: 30px; 2561 | } 2562 | .success { 2563 | background: #2ecc71; 2564 | color: #fff; 2565 | } 2566 | .primary { 2567 | background: #3F51B5; 2568 | color: white; 2569 | } 2570 | .danger { 2571 | background: #e74c3c; 2572 | color: #fff; 2573 | } 2574 | .warning { 2575 | background: orange; 2576 | color: #fff; 2577 | } 2578 | .active { 2579 | background: linen; 2580 | } 2581 | button { 2582 | border: none; 2583 | padding: 5px 8px; 2584 | border-radius: 4px; 2585 | margin: 0 2px; 2586 | height: 30px; 2587 | cursor: pointer; 2588 | } 2589 | button:focus { 2590 | outline: none; 2591 | border: 1px solid #333; 2592 | } 2593 | header { 2594 | min-height: 65px; 2595 | max-height: 65px; 2596 | background: #1BA8F3; 2597 | color: #fff; 2598 | padding: 0 20px; 2599 | display: flex; 2600 | justify-content: space-between; 2601 | align-items: center; 2602 | } 2603 | header .app_title { 2604 | display: flex; 2605 | height: 40px; 2606 | align-items: center; 2607 | } 2608 | header .app_title span { 2609 | margin-left: 5px; 2610 | } 2611 | header .right { 2612 | display: flex; 2613 | align-items: center; 2614 | } 2615 | header .right .btn_bulk_actions { 2616 | border: none; 2617 | padding: 5px 8px; 2618 | border-radius: 4px; 2619 | margin: 0 2px; 2620 | height: 30px; 2621 | cursor: pointer; 2622 | } 2623 | header .right input { 2624 | border: none; 2625 | padding: 5px 10px; 2626 | border-radius: 2px; 2627 | min-height: 30px; 2628 | } 2629 | header .right a.btn-doc { 2630 | border: none; 2631 | padding: 0 8px; 2632 | border-radius: 2px; 2633 | max-height: 30px; 2634 | cursor: pointer; 2635 | text-decoration: none; 2636 | color: #333; 2637 | background: #fff; 2638 | display: block; 2639 | line-height: 30px; 2640 | margin-left: 5px; 2641 | } 2642 | header .right .search_box { 2643 | position: relative; 2644 | } 2645 | header .right .search_box input:focus { 2646 | outline: none; 2647 | } 2648 | header .right .searching { 2649 | position: absolute; 2650 | right: 0; 2651 | top: 0; 2652 | background: #f0f0f0; 2653 | color: white; 2654 | width: 35px; 2655 | height: 30px; 2656 | display: flex; 2657 | justify-content: center; 2658 | align-items: center; 2659 | border-left: 1px solid #ddd; 2660 | border-top-right-radius: 2px; 2661 | border-bottom-right-radius: 2px; 2662 | z-index: 2; 2663 | } 2664 | header .right .clear_search { 2665 | position: absolute; 2666 | z-index: 1; 2667 | cursor: pointer; 2668 | right: 0; 2669 | top: 0; 2670 | background: #333; 2671 | color: white; 2672 | width: 35px; 2673 | height: 30px; 2674 | display: flex; 2675 | justify-content: center; 2676 | align-items: center; 2677 | border-left: 1px solid #ddd; 2678 | border-top-right-radius: 2px; 2679 | border-bottom-right-radius: 2px; 2680 | } 2681 | .wrapper { 2682 | display: flex; 2683 | } 2684 | .wrapper .sidebar { 2685 | padding: 20px; 2686 | width: 20%; 2687 | background: #FAFAFA; 2688 | min-height: calc(100vh - 65px); 2689 | max-height: calc(100vh - 65px); 2690 | padding-top: 0; 2691 | border-right: 1px solid #ddd; 2692 | overflow-y: auto; 2693 | } 2694 | .wrapper .sidebar::-webkit-scrollbar { 2695 | width: 2px; 2696 | } 2697 | .wrapper .sidebar .upload_section .upload_title { 2698 | padding: 10px; 2699 | background: #f5f5f5; 2700 | font-weight: 700; 2701 | color: #555; 2702 | } 2703 | .wrapper .sidebar .upload_section .upload_area { 2704 | border: 2px dotted #e4e4e4; 2705 | background: white; 2706 | min-height: 60px; 2707 | max-height: 80px; 2708 | text-align: center; 2709 | color: #c5c2c2; 2710 | } 2711 | .wrapper .sidebar .upload_section .upload_area .dz-default { 2712 | max-height: 70px; 2713 | margin: 0; 2714 | line-height: 20px; 2715 | } 2716 | .wrapper .sidebar .preview_section .preview_header { 2717 | display: flex; 2718 | justify-content: space-between; 2719 | background: #f5f5f5; 2720 | padding: 10px; 2721 | font-weight: 700; 2722 | color: #555; 2723 | } 2724 | .wrapper .sidebar .preview_section .image_wrapper { 2725 | margin-top: 20px; 2726 | width: 100%; 2727 | overflow: hidden; 2728 | } 2729 | .wrapper .sidebar .preview_section .image_wrapper img { 2730 | width: 100%; 2731 | } 2732 | .wrapper .sidebar .preview_section .info { 2733 | margin-top: 10px; 2734 | } 2735 | .wrapper .sidebar .preview_section .info h2 { 2736 | font-size: 18px; 2737 | } 2738 | .wrapper .sidebar .preview_section .info p { 2739 | font-size: 13px; 2740 | } 2741 | .wrapper .content { 2742 | width: 80%; 2743 | position: relative; 2744 | } 2745 | .wrapper .content .load_more { 2746 | min-height: 25px; 2747 | background: #ddd; 2748 | text-align: center; 2749 | padding: 5px; 2750 | } 2751 | .wrapper .content .content_footer { 2752 | min-height: 40px; 2753 | position: absolute; 2754 | background: #FAFAFA; 2755 | width: 100%; 2756 | bottom: 0; 2757 | left: 0; 2758 | right: 0; 2759 | border-top: 1px solid #ddd; 2760 | display: flex; 2761 | align-items: center; 2762 | justify-content: space-between; 2763 | } 2764 | .wrapper .content .content_footer .left { 2765 | margin-left: 20px; 2766 | font-size: 14px; 2767 | color: #444; 2768 | } 2769 | .wrapper .content .content_footer .right { 2770 | margin-right: 20px; 2771 | } 2772 | .wrapper .content .content_footer .right button { 2773 | min-width: 100px; 2774 | background: #4CAF50; 2775 | color: #fff; 2776 | } 2777 | .wrapper .gallery { 2778 | display: flex; 2779 | flex-direction: column; 2780 | max-height: calc(100vh - 105px); 2781 | overflow-y: auto; 2782 | } 2783 | .wrapper .gallery::-webkit-scrollbar { 2784 | width: 2px; 2785 | } 2786 | .wrapper .gallery .gl_header { 2787 | background: #F5F5F5; 2788 | font-weight: 700; 2789 | position: sticky; 2790 | top: 0; 2791 | z-index: 1; 2792 | } 2793 | .wrapper .gallery .gl_item { 2794 | display: flex; 2795 | margin: 5px 0; 2796 | min-height: 40px; 2797 | line-height: 40px; 2798 | padding: 0 20px; 2799 | font-size: 15px; 2800 | color: #555; 2801 | } 2802 | .wrapper .gallery .gl_item:first-child { 2803 | margin-top: 0; 2804 | } 2805 | .wrapper .gallery .gl_item:hover { 2806 | background: #fafafa; 2807 | } 2808 | .wrapper .gallery .gl_item .name { 2809 | width: 40%; 2810 | display: flex; 2811 | align-items: center; 2812 | } 2813 | .wrapper .gallery .gl_item .name input[type="checkbox"] { 2814 | margin-right: 8px; 2815 | /* Double-sized Checkboxes */ 2816 | -ms-transform: scale(1.5); 2817 | /* IE */ 2818 | -moz-transform: scale(1.5); 2819 | /* FF */ 2820 | -webkit-transform: scale(1.5); 2821 | /* Safari and Chrome */ 2822 | -o-transform: scale(1.5); 2823 | /* Opera */ 2824 | padding: 4px; 2825 | } 2826 | .wrapper .gallery .gl_item .name .thum { 2827 | width: 40px; 2828 | height: 40px; 2829 | border-radius: 50%; 2830 | } 2831 | .wrapper .gallery .gl_item .name .thum img { 2832 | width: 100%; 2833 | display: inline-block; 2834 | vertical-align: middle; 2835 | } 2836 | .wrapper .gallery .gl_item .name .thum p { 2837 | margin-left: 3px; 2838 | margin-top: 4px; 2839 | } 2840 | .wrapper .gallery .gl_item .name p { 2841 | width: 100%; 2842 | margin-left: 10px; 2843 | white-space: nowrap; 2844 | overflow: hidden; 2845 | text-overflow: ellipsis; 2846 | } 2847 | .wrapper .gallery .gl_item .size { 2848 | width: 10%; 2849 | } 2850 | .wrapper .gallery .gl_item .type { 2851 | width: 10%; 2852 | } 2853 | .wrapper .gallery .gl_item .modified { 2854 | width: 20%; 2855 | } 2856 | .wrapper .gallery .gl_item .action { 2857 | width: 20%; 2858 | display: flex; 2859 | flex-direction: row; 2860 | align-items: center; 2861 | justify-content: flex-end; 2862 | } 2863 | .wrapper .gallery .gl_item .action button { 2864 | border: none; 2865 | padding: 5px 8px; 2866 | border-radius: 4px; 2867 | margin: 0 2px; 2868 | height: 30px; 2869 | cursor: pointer; 2870 | } 2871 | .wrapper .gallery .gl_item .action button:last-child { 2872 | margin-right: 0; 2873 | } 2874 | .wrapper .gallery .gl_item .action .select { 2875 | background: #2ecc71; 2876 | color: #fff; 2877 | } 2878 | .wrapper .gallery .gl_item .action .delete { 2879 | background: #e74c3c; 2880 | color: #fff; 2881 | } 2882 | .wrapper .gallery .gl_item { 2883 | display: flex; 2884 | } 2885 | button:disabled { 2886 | opacity: 0.6; 2887 | cursor: not-allowed !important; 2888 | } 2889 | .popup { 2890 | width: 50%; 2891 | background: #fff; 2892 | position: absolute; 2893 | margin: 0 auto; 2894 | left: 0; 2895 | right: 0; 2896 | top: 20%; 2897 | z-index: 200; 2898 | box-shadow: 1px 0px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23); 2899 | } 2900 | .popup .header { 2901 | display: flex; 2902 | background: whitesmoke; 2903 | justify-content: space-between; 2904 | height: 35px; 2905 | align-items: center; 2906 | border-bottom: 1px solid #ddd; 2907 | } 2908 | .popup .header .title { 2909 | margin-left: 15px; 2910 | font-weight: 700; 2911 | } 2912 | .popup .header .close { 2913 | width: 30px; 2914 | background: #333; 2915 | color: #fff; 2916 | text-align: center; 2917 | line-height: 35px; 2918 | border-bottom: 1px solid #333; 2919 | cursor: pointer; 2920 | } 2921 | .popup .popup_content { 2922 | min-height: 100px; 2923 | width: 100%; 2924 | padding: 15px; 2925 | } 2926 | .popup .popup_content .form-group { 2927 | margin-bottom: 10px; 2928 | } 2929 | .popup .popup_content label { 2930 | display: block; 2931 | color: #777; 2932 | } 2933 | .popup .popup_content input { 2934 | border: 0; 2935 | padding: 5px; 2936 | border: 1px solid #ddd; 2937 | width: 100%; 2938 | margin-top: 5px; 2939 | } 2940 | .popup .popup_content input:focus { 2941 | outline: none; 2942 | border-bottom: 1px solid #666; 2943 | } 2944 | .popup .footer { 2945 | padding: 0 15px; 2946 | display: flex; 2947 | background: whitesmoke; 2948 | justify-content: space-between; 2949 | height: 40px; 2950 | align-items: center; 2951 | border-top: 1px solid #ddd; 2952 | } 2953 | @media only screen and (max-width: 780px) { 2954 | .btn_mobile_upload, 2955 | .btn_mobile_preview { 2956 | display: block; 2957 | } 2958 | .btn_desktop_preview, 2959 | .upload_section { 2960 | display: none; 2961 | } 2962 | .btn_mobile_upload_close { 2963 | display: block; 2964 | float: right; 2965 | margin-top: 4px; 2966 | margin-right: 3px; 2967 | } 2968 | body { 2969 | height: 100vh; 2970 | overflow: hidden; 2971 | } 2972 | header { 2973 | flex-direction: column; 2974 | max-height: 100px !important; 2975 | padding: 10px 15px; 2976 | align-items: flex-start; 2977 | } 2978 | header .right { 2979 | margin-top: 10px; 2980 | } 2981 | header .right .btn_bulk_actions, 2982 | header .right .btn-doc { 2983 | font-size: 12px; 2984 | } 2985 | .wrapper { 2986 | flex-direction: column; 2987 | } 2988 | .wrapper .sidebar, 2989 | .wrapper .content { 2990 | width: 100%; 2991 | } 2992 | .wrapper .sidebar { 2993 | height: auto; 2994 | min-height: 1px !important; 2995 | padding-left: 15px; 2996 | } 2997 | .wrapper .sidebar .btn_mobile_upload { 2998 | margin-top: 10px; 2999 | } 3000 | .wrapper .sidebar .preview_section { 3001 | display: none; 3002 | } 3003 | .wrapper .content { 3004 | position: inherit; 3005 | max-height: calc(100vh - 150px); 3006 | } 3007 | .wrapper .content .gallery { 3008 | max-height: calc(100vh - 150px); 3009 | } 3010 | .wrapper .content .gallery .gl_item .size, 3011 | .wrapper .content .gallery .gl_item .type, 3012 | .wrapper .content .gallery .gl_item .modified { 3013 | display: none; 3014 | } 3015 | .wrapper .content .gallery .gl_item .name, 3016 | .wrapper .content .gallery .gl_item .action { 3017 | width: 50%; 3018 | } 3019 | .mobile_upload { 3020 | position: absolute; 3021 | overflow: auto; 3022 | top: 0; 3023 | left: 0; 3024 | right: 0; 3025 | bottom: 0; 3026 | min-height: 100vh; 3027 | z-index: 101; 3028 | background: #fff; 3029 | padding: 20px; 3030 | } 3031 | .mobile_upload .btn_mobile_upload_close { 3032 | position: absolute; 3033 | right: 18px; 3034 | top: 15px; 3035 | } 3036 | .mobile_upload .upload_area { 3037 | margin-top: 20px; 3038 | overflow: auto; 3039 | min-height: 50px; 3040 | } 3041 | .mobile_upload .upload_area .dz-default { 3042 | margin: 0; 3043 | } 3044 | .mobile_upload .mobile_preview_container { 3045 | background: #f4f4f4; 3046 | margin-top: 20px; 3047 | padding: 10px; 3048 | } 3049 | .mobile_preview { 3050 | position: fixed; 3051 | top: 0; 3052 | left: 0; 3053 | right: 0; 3054 | background: #fff; 3055 | padding: 15px; 3056 | z-index: 100; 3057 | height: 100vh; 3058 | } 3059 | .mobile_preview .preview_section { 3060 | overflow-y: auto; 3061 | height: 95vh; 3062 | } 3063 | .mobile_preview .preview_section .preview_header { 3064 | display: flex; 3065 | justify-content: space-between; 3066 | background: #f5f5f5; 3067 | padding: 10px; 3068 | font-weight: 700; 3069 | color: #555; 3070 | } 3071 | .mobile_preview .preview_section .image_wrapper { 3072 | margin-top: 20px; 3073 | width: 100%; 3074 | } 3075 | .mobile_preview .preview_section .image_wrapper img { 3076 | width: 100%; 3077 | } 3078 | .mobile_preview .preview_section .info { 3079 | margin-top: 10px; 3080 | } 3081 | .mobile_preview .preview_section .info h2 { 3082 | font-size: 18px; 3083 | } 3084 | .mobile_preview .preview_section .info p { 3085 | font-size: 13px; 3086 | } 3087 | } 3088 | /*# sourceMappingURL=style.css.map */ 3089 | -------------------------------------------------------------------------------- /assets/bundle/filemanager.min.js: -------------------------------------------------------------------------------- 1 | var filemanager={baseUrl:"",ckBrowseUrl:""};function tinyMceCallback(){var e=parseInt(tinyMCE.majorVersion),n=window,i=document,t=i.documentElement,a=i.getElementsByTagName("body")[0],r=n.innerWidth||t.clientWidth||a.clientWidth,l=n.innerHeight||t.clientHeight||a.clientHeight,o=filemanager.baseUrl+"?editor=tinyMCE&file_type=image";if(4===e)tinyMCE.activeEditor.windowManager.open({file:o,title:"Filemanager",width:.8*r,height:.8*l,resizable:"yes",close_previous:"no"});else{if(5!==e)throw"TinyMCE version:"+e+" is not supported";tinyMCE.activeEditor.windowManager.openUrl({title:"Filemanager",url:o,width:.8*r,height:.8*l})}}setTimeout(function(){filemanager.ckBrowseUrl=filemanager.baseUrl+"?editor=ckEditor"}),filemanager.openWindow=function(e){var n,i,t;e&&(t="toolbar=no,location=no,directories=no,status=no,menubar=no,resizable=yes,dependent=yes",t+=",width="+(n=.7*screen.width),t+=",height="+(i=.7*screen.height),t+=",left="+(screen.width-n)/2,t+=",top="+(screen.height-i)/2,window.open(e,"Filemanager",t))},filemanager.btnSummernote=function(n){return $.summernote.ui.button({contents:' Filemanager',tooltip:"Pick a file",click:function(){console.log(n);var e=null;n.$note[0].className&&(e="."+n.$note[0].className),n.$note[0].id&&(e="#"+n.$note[0].id),filemanager.openWindow(filemanager.baseUrl+"?editor=summernote¬e="+e)}}).render()},filemanager.tinyMceCallback=tinyMceCallback,filemanager.selectFile=function(e){var n;e&&(n=filemanager.baseUrl+"?&input_id="+e,filemanager.openWindow(n))},filemanager.bulkSelectFile=function(e){var n;e&&(n=filemanager.baseUrl+"?bulk=true&callback="+e,filemanager.openWindow(n))}; -------------------------------------------------------------------------------- /assets/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haruncpi/laravel-simple-filemanager/2dda264ad5fe870cbfc3c62cfe6ef223a8bf1425/assets/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /assets/fonts/HindSiliguri-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haruncpi/laravel-simple-filemanager/2dda264ad5fe870cbfc3c62cfe6ef223a8bf1425/assets/fonts/HindSiliguri-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/SolaimanLipi.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haruncpi/laravel-simple-filemanager/2dda264ad5fe870cbfc3c62cfe6ef223a8bf1425/assets/fonts/SolaimanLipi.ttf -------------------------------------------------------------------------------- /assets/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haruncpi/laravel-simple-filemanager/2dda264ad5fe870cbfc3c62cfe6ef223a8bf1425/assets/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /assets/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haruncpi/laravel-simple-filemanager/2dda264ad5fe870cbfc3c62cfe6ef223a8bf1425/assets/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /assets/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haruncpi/laravel-simple-filemanager/2dda264ad5fe870cbfc3c62cfe6ef223a8bf1425/assets/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /assets/img/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haruncpi/laravel-simple-filemanager/2dda264ad5fe870cbfc3c62cfe6ef223a8bf1425/assets/img/ajax-loader.gif -------------------------------------------------------------------------------- /assets/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haruncpi/laravel-simple-filemanager/2dda264ad5fe870cbfc3c62cfe6ef223a8bf1425/assets/img/logo.png -------------------------------------------------------------------------------- /assets/img/previews/doc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haruncpi/laravel-simple-filemanager/2dda264ad5fe870cbfc3c62cfe6ef223a8bf1425/assets/img/previews/doc.png -------------------------------------------------------------------------------- /assets/img/previews/missing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haruncpi/laravel-simple-filemanager/2dda264ad5fe870cbfc3c62cfe6ef223a8bf1425/assets/img/previews/missing.png -------------------------------------------------------------------------------- /assets/img/previews/pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haruncpi/laravel-simple-filemanager/2dda264ad5fe870cbfc3c62cfe6ef223a8bf1425/assets/img/previews/pdf.png -------------------------------------------------------------------------------- /assets/img/previews/txt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haruncpi/laravel-simple-filemanager/2dda264ad5fe870cbfc3c62cfe6ef223a8bf1425/assets/img/previews/txt.png -------------------------------------------------------------------------------- /assets/img/previews/xls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haruncpi/laravel-simple-filemanager/2dda264ad5fe870cbfc3c62cfe6ef223a8bf1425/assets/img/previews/xls.png -------------------------------------------------------------------------------- /assets/img/previews/zip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haruncpi/laravel-simple-filemanager/2dda264ad5fe870cbfc3c62cfe6ef223a8bf1425/assets/img/previews/zip.png -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "haruncpi/laravel-simple-filemanager", 3 | "description": "A simple filemanager for Laravel", 4 | "license": "cc-by-nc-4.0", 5 | "keywords": [ 6 | "laravel", 7 | "simple", 8 | "filemanager", 9 | "file manager", 10 | "media manager" 11 | ], 12 | "type": "library", 13 | "authors": [ 14 | { 15 | "name": "MD.HARUN-UR-RASHID", 16 | "email": "harun.cox@gmail.com" 17 | } 18 | ], 19 | "minimum-stability": "dev", 20 | "prefer-stable": true, 21 | "require": { 22 | "php": ">=5.6" 23 | }, 24 | "autoload": { 25 | "files": [ 26 | "src/helpers.php" 27 | ], 28 | "psr-4": { 29 | "Haruncpi\\LaravelSimpleFilemanager\\": "src" 30 | } 31 | }, 32 | "scripts": { 33 | "phpunit": "phpunit" 34 | }, 35 | "extra": { 36 | "laravel": { 37 | "providers": [ 38 | "Haruncpi\\LaravelSimpleFilemanager\\ServiceProvider" 39 | ] 40 | } 41 | }, 42 | "config": { 43 | "preferred-install": "dist", 44 | "sort-packages": true, 45 | "optimize-autoloader": true 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /config/filemanager.php: -------------------------------------------------------------------------------- 1 | 'admin/filemanager', 4 | 'middleware' => ['web', 'auth'], 5 | 'allow_format' => 'jpeg,jpg,png,gif,webp', 6 | 'max_size' => 500, 7 | 'max_image_width' => 1024, 8 | 'image_quality' => 80, 9 | ]; -------------------------------------------------------------------------------- /migrations/2020_05_02_100001_create_filemanager_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->string('name'); 19 | $table->string('ext',4); 20 | $table->float('file_size'); 21 | $table->bigInteger('user_id')->unsigned(); 22 | $table->string('absolute_url'); 23 | $table->json('extra')->nullable(); 24 | $table->timestamps(); 25 | }); 26 | } 27 | 28 | /** 29 | * Reverse the migrations. 30 | * 31 | * @return void 32 | */ 33 | public function down() 34 | { 35 | Schema::dropIfExists('filemanager'); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /previews/preview-desktop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haruncpi/laravel-simple-filemanager/2dda264ad5fe870cbfc3c62cfe6ef223a8bf1425/previews/preview-desktop.png -------------------------------------------------------------------------------- /previews/preview-mobile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haruncpi/laravel-simple-filemanager/2dda264ad5fe870cbfc3c62cfe6ef223a8bf1425/previews/preview-mobile.png -------------------------------------------------------------------------------- /routes/web.php: -------------------------------------------------------------------------------- 1 | '\Haruncpi\LaravelSimpleFilemanager\Controllers', 5 | 'middleware' => config('filemanager.middleware') 6 | ], function () { 7 | Route::get(config('filemanager.base_route'), 'FilemanagerController@getIndex') 8 | ->name('filemanager.base_route'); 9 | 10 | Route::post(config('filemanager.base_route'), 'FilemanagerController@postAction') 11 | ->name('filemanager.action_route'); 12 | }); -------------------------------------------------------------------------------- /src/Classes/SimpleImage.php: -------------------------------------------------------------------------------- 1 | fromDataUri($image); 32 | } elseif($image) { 33 | $this->fromFile($image); 34 | } 35 | } 36 | 37 | // 38 | // Destroys the image resource 39 | // 40 | public function __destruct() { 41 | if($this->image !== null && get_resource_type($this->image) === 'gd') { 42 | imagedestroy($this->image); 43 | } 44 | } 45 | 46 | public function fromDataUri($uri) { 47 | 48 | preg_match('/^data:(.*?);/', $uri, $matches); 49 | if(!count($matches)) { 50 | throw new \Exception('Invalid data URI.', self::ERR_INVALID_DATA_URI); 51 | } 52 | 53 | // Determine mime type 54 | $this->mimeType = $matches[1]; 55 | if(!preg_match('/^image\/(gif|jpeg|png)$/', $this->mimeType)) { 56 | throw new \Exception( 57 | 'Unsupported format: ' . $this->mimeType, 58 | self::ERR_UNSUPPORTED_FORMAT 59 | ); 60 | } 61 | 62 | // Get image data 63 | $uri = base64_decode(preg_replace('/^data:(.*?);base64,/', '', $uri)); 64 | $this->image = imagecreatefromstring($uri); 65 | if(!$this->image) { 66 | throw new \Exception("Invalid image data.", self::ERR_INVALID_IMAGE); 67 | } 68 | 69 | return $this; 70 | } 71 | 72 | 73 | // Returns a SimpleImage object. 74 | // 75 | public function fromFile($file) { 76 | $handle = @fopen($file, 'r'); 77 | if($handle === false) { 78 | throw new \Exception("File not found: $file", self::ERR_FILE_NOT_FOUND); 79 | } 80 | fclose($handle); 81 | 82 | // Get image info 83 | $info = getimagesize($file); 84 | if($info === false) { 85 | throw new \Exception("Invalid image file: $file", self::ERR_INVALID_IMAGE); 86 | } 87 | $this->mimeType = $info['mime']; 88 | 89 | // Create image object from file 90 | switch($this->mimeType) { 91 | case 'image/gif': 92 | // Load the gif 93 | $gif = imagecreatefromgif($file); 94 | if($gif) { 95 | // Copy the gif over to a true color image to preserve its transparency. This is a 96 | // workaround to prevent imagepalettetruecolor() from borking transparency. 97 | $width = imagesx($gif); 98 | $height = imagesy($gif); 99 | $this->image = imagecreatetruecolor($width, $height); 100 | $transparentColor = imagecolorallocatealpha($this->image, 0, 0, 0, 127); 101 | imagecolortransparent($this->image, $transparentColor); 102 | imagefill($this->image, 0, 0, $transparentColor); 103 | imagecopy($this->image, $gif, 0, 0, 0, 0, $width, $height); 104 | imagedestroy($gif); 105 | } 106 | break; 107 | case 'image/jpeg': 108 | $this->image = imagecreatefromjpeg($file); 109 | break; 110 | case 'image/png': 111 | $this->image = imagecreatefrompng($file); 112 | break; 113 | case 'image/webp': 114 | $this->image = imagecreatefromwebp($file); 115 | break; 116 | case 'image/bmp': 117 | case 'image/x-ms-bmp': 118 | case 'image/x-windows-bmp': 119 | $this->image = imagecreatefrombmp($file); 120 | break; 121 | } 122 | if(!$this->image) { 123 | throw new \Exception("Unsupported format: " . $this->mimeType, self::ERR_UNSUPPORTED_FORMAT); 124 | } 125 | 126 | // Convert pallete images to true color images 127 | imagepalettetotruecolor($this->image); 128 | 129 | // Load exif data from JPEG images 130 | if($this->mimeType === 'image/jpeg' && function_exists('exif_read_data')) { 131 | $this->exif = @exif_read_data($file); 132 | } 133 | 134 | return $this; 135 | } 136 | 137 | 138 | // $width* (int) - The width of the image. 139 | // $height* (int) - The height of the image. 140 | // $color (string|array) - Optional fill color for the new image (default 'transparent'). 141 | // 142 | // Returns a SimpleImage object. 143 | // 144 | public function fromNew($width, $height, $color = 'transparent') { 145 | $this->image = imagecreatetruecolor($width, $height); 146 | 147 | // Use PNG for dynamically created images because it's lossless and supports transparency 148 | $this->mimeType = 'image/png'; 149 | 150 | // Fill the image with color 151 | $this->fill($color); 152 | 153 | return $this; 154 | } 155 | 156 | 157 | // $string* (string) - The raw image data as a string. Example: 158 | // $string = file_get_contents('image.jpg'); 159 | // Returns a SimpleImage object. 160 | public function fromString($string) { 161 | return $this->fromFile('data://;base64,' . base64_encode($string)); 162 | } 163 | 164 | // Generates an image. 165 | // 166 | // $mimeType (string) - The image format to output as a mime type (defaults to the original mime 167 | // type). 168 | // $quality (int) - Image quality as a percentage (default 100). 169 | // 170 | // Returns an array containing the image data and mime type. 171 | // 172 | protected function generate($mimeType = null, $quality = 100) { 173 | // Format defaults to the original mime type 174 | $mimeType = $mimeType ?: $this->mimeType; 175 | 176 | // Ensure quality is a valid integer 177 | if($quality === null) $quality = 100; 178 | $quality = self::keepWithin((int) $quality, 0, 100); 179 | 180 | // Capture output 181 | ob_start(); 182 | 183 | // Generate the image 184 | switch($mimeType) { 185 | case 'image/gif': 186 | imagesavealpha($this->image, true); 187 | imagegif($this->image, null); 188 | break; 189 | case 'image/jpeg': 190 | imageinterlace($this->image, true); 191 | imagejpeg($this->image, null, $quality); 192 | break; 193 | case 'image/png': 194 | imagesavealpha($this->image, true); 195 | imagepng($this->image, null, round(9 * $quality / 100)); 196 | break; 197 | case 'image/webp': 198 | // Not all versions of PHP will have webp support enabled 199 | if(!function_exists('imagewebp')) { 200 | throw new \Exception( 201 | 'WEBP support is not enabled in your version of PHP.', 202 | self::ERR_WEBP_NOT_ENABLED 203 | ); 204 | } 205 | imagesavealpha($this->image, true); 206 | imagewebp($this->image, null, $quality); 207 | break; 208 | case 'image/bmp': 209 | case 'image/x-ms-bmp': 210 | case 'image/x-windows-bmp': 211 | imageinterlace($this->image, true); 212 | imagebmp($this->image, null, $quality); 213 | break; 214 | default: 215 | throw new \Exception('Unsupported format: ' . $mimeType, self::ERR_UNSUPPORTED_FORMAT); 216 | } 217 | 218 | // Stop capturing 219 | $data = ob_get_contents(); 220 | ob_end_clean(); 221 | 222 | return [ 223 | 'data' => $data, 224 | 'mimeType' => $mimeType 225 | ]; 226 | } 227 | 228 | 229 | // $mimeType (string) - The image format to output as a mime type (defaults to the original mime 230 | // type). 231 | // $quality (int) - Image quality as a percentage (default 100). 232 | // 233 | // Returns a string containing a data URI. 234 | // 235 | public function toDataUri($mimeType = null, $quality = 100) { 236 | $image = $this->generate($mimeType, $quality); 237 | 238 | return 'data:' . $image['mimeType'] . ';base64,' . base64_encode($image['data']); 239 | } 240 | 241 | // 242 | // Forces the image to be downloaded to the clients machine. Must be called before any output is 243 | // sent to the screen. 244 | // 245 | // $filename* (string) - The filename (without path) to send to the client (e.g. 'image.jpeg'). 246 | // $mimeType (string) - The image format to output as a mime type (defaults to the original mime 247 | // type). 248 | // $quality (int) - Image quality as a percentage (default 100). 249 | // 250 | public function toDownload($filename, $mimeType = null, $quality = 100) { 251 | $image = $this->generate($mimeType, $quality); 252 | 253 | // Set download headers 254 | header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); 255 | header('Content-Description: File Transfer'); 256 | header('Content-Length: ' . strlen($image['data'])); 257 | header('Content-Transfer-Encoding: Binary'); 258 | header('Content-Type: application/octet-stream'); 259 | header("Content-Disposition: attachment; filename=\"$filename\""); 260 | 261 | echo $image['data']; 262 | 263 | return $this; 264 | } 265 | 266 | // 267 | // Writes the image to a file. 268 | // 269 | // $mimeType (string) - The image format to output as a mime type (defaults to the original mime 270 | // type). 271 | // $quality (int) - Image quality as a percentage (default 100). 272 | // 273 | // Returns a SimpleImage object. 274 | // 275 | public function toFile($file, $mimeType = null, $quality = 100) { 276 | $image = $this->generate($mimeType, $quality); 277 | 278 | // Save the image to file 279 | if(!file_put_contents($file, $image['data'])) { 280 | throw new \Exception("Failed to write image to file: $file", self::ERR_WRITE); 281 | } 282 | 283 | return $this; 284 | } 285 | 286 | // 287 | // Outputs the image to the screen. Must be called before any output is sent to the screen. 288 | // 289 | // $mimeType (string) - The image format to output as a mime type (defaults to the original mime 290 | // type). 291 | // $quality (int) - Image quality as a percentage (default 100). 292 | // 293 | // Returns a SimpleImage object. 294 | // 295 | public function toScreen($mimeType = null, $quality = 100) { 296 | $image = $this->generate($mimeType, $quality); 297 | 298 | // Output the image to stdout 299 | header('Content-Type: ' . $image['mimeType']); 300 | echo $image['data']; 301 | 302 | return $this; 303 | } 304 | 305 | // 306 | // Generates an image string. 307 | // 308 | // $mimeType (string) - The image format to output as a mime type (defaults to the original mime 309 | // type). 310 | // $quality (int) - Image quality as a percentage (default 100). 311 | // 312 | // Returns a SimpleImage object. 313 | // 314 | public function toString($mimeType = null, $quality = 100) { 315 | return $this->generate($mimeType, $quality)['data']; 316 | } 317 | 318 | ////////////////////////////////////////////////////////////////////////////////////////////////// 319 | // Utilities 320 | ////////////////////////////////////////////////////////////////////////////////////////////////// 321 | 322 | // 323 | // Ensures a numeric value is always within the min and max range. 324 | // 325 | // $value* (int|float) - A numeric value to test. 326 | // $min* (int|float) - The minimum allowed value. 327 | // $max* (int|float) - The maximum allowed value. 328 | // 329 | // Returns an int|float value. 330 | // 331 | protected static function keepWithin($value, $min, $max) { 332 | if($value < $min) return $min; 333 | if($value > $max) return $max; 334 | return $value; 335 | } 336 | 337 | // 338 | // Gets the image's current aspect ratio. 339 | // 340 | // Returns the aspect ratio as a float. 341 | // 342 | public function getAspectRatio() { 343 | return $this->getWidth() / $this->getHeight(); 344 | } 345 | 346 | // 347 | // Gets the image's exif data. 348 | // 349 | // Returns an array of exif data or null if no data is available. 350 | // 351 | public function getExif() { 352 | return isset($this->exif) ? $this->exif : null; 353 | } 354 | 355 | // 356 | // Gets the image's current height. 357 | // 358 | // Returns the height as an integer. 359 | // 360 | public function getHeight() { 361 | return (int) imagesy($this->image); 362 | } 363 | 364 | // 365 | // Gets the mime type of the loaded image. 366 | // 367 | // Returns a mime type string. 368 | // 369 | public function getMimeType() { 370 | return $this->mimeType; 371 | } 372 | 373 | // 374 | // Gets the image's current orientation. 375 | // 376 | // Returns a string: 'landscape', 'portrait', or 'square' 377 | // 378 | public function getOrientation() { 379 | $width = $this->getWidth(); 380 | $height = $this->getHeight(); 381 | 382 | if($width > $height) return 'landscape'; 383 | if($width < $height) return 'portrait'; 384 | return 'square'; 385 | } 386 | 387 | // 388 | // Gets the resolution of the image 389 | // 390 | // Returns the resolution as an array of integers: [96, 96] 391 | // 392 | public function getResolution() { 393 | return imageresolution($this->image); 394 | } 395 | 396 | // 397 | // Gets the image's current width. 398 | // 399 | // Returns the width as an integer. 400 | // 401 | public function getWidth() { 402 | return (int) imagesx($this->image); 403 | } 404 | 405 | ////////////////////////////////////////////////////////////////////////////////////////////////// 406 | // Manipulation 407 | ////////////////////////////////////////////////////////////////////////////////////////////////// 408 | 409 | // 410 | // Same as PHP's imagecopymerge, but works with transparent images. Used internally for overlay. 411 | // 412 | protected static function imageCopyMergeAlpha($dstIm, $srcIm, $dstX, $dstY, $srcX, $srcY, $srcW, $srcH, $pct) { 413 | // Are we merging with transparency? 414 | if($pct < 100) { 415 | // Disable alpha blending and "colorize" the image using a transparent color 416 | imagealphablending($srcIm, false); 417 | imagefilter($srcIm, IMG_FILTER_COLORIZE, 0, 0, 0, 127 * ((100 - $pct) / 100)); 418 | } 419 | 420 | imagecopy($dstIm, $srcIm, $dstX, $dstY, $srcX, $srcY, $srcW, $srcH); 421 | 422 | return true; 423 | } 424 | 425 | // 426 | // Rotates an image so the orientation will be correct based on its exif data. It is safe to call 427 | // this method on images that don't have exif data (no changes will be made). 428 | // 429 | // Returns a SimpleImage object. 430 | // 431 | public function autoOrient() { 432 | $exif = $this->getExif(); 433 | 434 | if(!$exif || !isset($exif['Orientation'])){ 435 | return $this; 436 | } 437 | 438 | switch($exif['Orientation']) { 439 | case 1: // Do nothing! 440 | break; 441 | case 2: // Flip horizontally 442 | $this->flip('x'); 443 | break; 444 | case 3: // Rotate 180 degrees 445 | $this->rotate(180); 446 | break; 447 | case 4: // Flip vertically 448 | $this->flip('y'); 449 | break; 450 | case 5: // Rotate 90 degrees clockwise and flip vertically 451 | $this->flip('y')->rotate(90); 452 | break; 453 | case 6: // Rotate 90 clockwise 454 | $this->rotate(90); 455 | break; 456 | case 7: // Rotate 90 clockwise and flip horizontally 457 | $this->flip('x')->rotate(90); 458 | break; 459 | case 8: // Rotate 90 counterclockwise 460 | $this->rotate(-90); 461 | break; 462 | } 463 | 464 | return $this; 465 | } 466 | 467 | // 468 | // Proportionally resize the image to fit inside a specific width and height. 469 | // 470 | // $maxWidth* (int) - The maximum width the image can be. 471 | // $maxHeight* (int) - The maximum height the image can be. 472 | // 473 | // Returns a SimpleImage object. 474 | // 475 | public function bestFit($maxWidth, $maxHeight) { 476 | // If the image already fits, there's nothing to do 477 | if($this->getWidth() <= $maxWidth && $this->getHeight() <= $maxHeight) { 478 | return $this; 479 | } 480 | 481 | // Calculate max width or height based on orientation 482 | if($this->getOrientation() === 'portrait') { 483 | $height = $maxHeight; 484 | $width = $maxHeight * $this->getAspectRatio(); 485 | } else { 486 | $width = $maxWidth; 487 | $height = $maxWidth / $this->getAspectRatio(); 488 | } 489 | 490 | // Reduce to max width 491 | if($width > $maxWidth) { 492 | $width = $maxWidth; 493 | $height = $width / $this->getAspectRatio(); 494 | } 495 | 496 | // Reduce to max height 497 | if($height > $maxHeight) { 498 | $height = $maxHeight; 499 | $width = $height * $this->getAspectRatio(); 500 | } 501 | 502 | return $this->resize($width, $height); 503 | } 504 | 505 | // 506 | // Crop the image. 507 | // 508 | // $x1 - Top left x coordinate. 509 | // $y1 - Top left y coordinate. 510 | // $x2 - Bottom right x coordinate. 511 | // $y2 - Bottom right x coordinate. 512 | // 513 | // Returns a SimpleImage object. 514 | // 515 | public function crop($x1, $y1, $x2, $y2) { 516 | // Keep crop within image dimensions 517 | $x1 = self::keepWithin($x1, 0, $this->getWidth()); 518 | $x2 = self::keepWithin($x2, 0, $this->getWidth()); 519 | $y1 = self::keepWithin($y1, 0, $this->getHeight()); 520 | $y2 = self::keepWithin($y2, 0, $this->getHeight()); 521 | 522 | // Crop it 523 | $this->image = imagecrop($this->image, [ 524 | 'x' => min($x1, $x2), 525 | 'y' => min($y1, $y2), 526 | 'width' => abs($x2 - $x1), 527 | 'height' => abs($y2 - $y1) 528 | ]); 529 | 530 | return $this; 531 | } 532 | 533 | // 534 | // Applies a duotone filter to the image. 535 | // 536 | // $lightColor* (string|array) - The lightest color in the duotone. 537 | // $darkColor* (string|array) - The darkest color in the duotone. 538 | // 539 | // Returns a SimpleImage object. 540 | // 541 | function duotone($lightColor, $darkColor) { 542 | $lightColor = self::normalizeColor($lightColor); 543 | $darkColor = self::normalizeColor($darkColor); 544 | 545 | // Calculate averages between light and dark colors 546 | $redAvg = $lightColor['red'] - $darkColor['red']; 547 | $greenAvg = $lightColor['green'] - $darkColor['green']; 548 | $blueAvg = $lightColor['blue'] - $darkColor['blue']; 549 | 550 | // Create a matrix of all possible duotone colors based on gray values 551 | $pixels = []; 552 | for($i = 0; $i <= 255; $i++) { 553 | $grayAvg = $i / 255; 554 | $pixels['red'][$i] = $darkColor['red'] + $grayAvg * $redAvg; 555 | $pixels['green'][$i] = $darkColor['green'] + $grayAvg * $greenAvg; 556 | $pixels['blue'][$i] = $darkColor['blue'] + $grayAvg * $blueAvg; 557 | } 558 | 559 | // Apply the filter pixel by pixel 560 | for($x = 0; $x < $this->getWidth(); $x++) { 561 | for($y = 0; $y < $this->getHeight(); $y++) { 562 | $rgb = $this->getColorAt($x, $y); 563 | $gray = min(255, round(0.299 * $rgb['red'] + 0.114 * $rgb['blue'] + 0.587 * $rgb['green'])); 564 | $this->dot($x, $y, [ 565 | 'red' => $pixels['red'][$gray], 566 | 'green' => $pixels['green'][$gray], 567 | 'blue' => $pixels['blue'][$gray] 568 | ]); 569 | } 570 | } 571 | 572 | return $this; 573 | } 574 | 575 | // 576 | // Proportionally resize the image to a specific height. 577 | // 578 | // **DEPRECATED:** This method was deprecated in version 3.2.2 and will be removed in version 4.0. 579 | // Please use `resize(null, $height)` instead. 580 | // 581 | // $height* (int) - The height to resize the image to. 582 | // 583 | // Returns a SimpleImage object. 584 | // 585 | public function fitToHeight($height) { 586 | return $this->resize(null, $height); 587 | } 588 | 589 | // 590 | // Proportionally resize the image to a specific width. 591 | // 592 | // **DEPRECATED:** This method was deprecated in version 3.2.2 and will be removed in version 4.0. 593 | // Please use `resize($width, null)` instead. 594 | // 595 | // $width* (int) - The width to resize the image to. 596 | // 597 | // Returns a SimpleImage object. 598 | // 599 | public function fitToWidth($width) { 600 | return $this->resize($width, null); 601 | } 602 | 603 | // 604 | // Flip the image horizontally or vertically. 605 | // 606 | // $direction* (string) - The direction to flip: x|y|both 607 | // 608 | // Returns a SimpleImage object. 609 | // 610 | public function flip($direction) { 611 | switch($direction) { 612 | case 'x': 613 | imageflip($this->image, IMG_FLIP_HORIZONTAL); 614 | break; 615 | case 'y': 616 | imageflip($this->image, IMG_FLIP_VERTICAL); 617 | break; 618 | case 'both': 619 | imageflip($this->image, IMG_FLIP_BOTH); 620 | break; 621 | } 622 | 623 | return $this; 624 | } 625 | 626 | // 627 | // Reduces the image to a maximum number of colors. 628 | // 629 | // $max* (int) - The maximum number of colors to use. 630 | // $dither (bool) - Whether or not to use a dithering effect (default true). 631 | // 632 | // Returns a SimpleImage object. 633 | // 634 | public function maxColors($max, $dither = true) { 635 | imagetruecolortopalette($this->image, $dither, max(1, $max)); 636 | 637 | return $this; 638 | } 639 | 640 | // 641 | // Place an image on top of the current image. 642 | // 643 | // $overlay* (string|SimpleImage) - The image to overlay. This can be a filename, a data URI, or 644 | // a SimpleImage object. 645 | // $anchor (string) - The anchor point: 'center', 'top', 'bottom', 'left', 'right', 'top left', 646 | // 'top right', 'bottom left', 'bottom right' (default 'center') 647 | // $opacity (float) - The opacity level of the overlay 0-1 (default 1). 648 | // $xOffset (int) - Horizontal offset in pixels (default 0). 649 | // $yOffset (int) - Vertical offset in pixels (default 0). 650 | // 651 | // Returns a SimpleImage object. 652 | // 653 | public function overlay($overlay, $anchor = 'center', $opacity = 1, $xOffset = 0, $yOffset = 0) { 654 | // Load overlay image 655 | if(!($overlay instanceof SimpleImage)) { 656 | $overlay = new SimpleImage($overlay); 657 | } 658 | 659 | // Convert opacity 660 | $opacity = self::keepWithin($opacity, 0, 1) * 100; 661 | 662 | // Determine placement 663 | switch($anchor) { 664 | case 'top left': 665 | $x = $xOffset; 666 | $y = $yOffset; 667 | break; 668 | case 'top right': 669 | $x = $this->getWidth() - $overlay->getWidth() + $xOffset; 670 | $y = $yOffset; 671 | break; 672 | case 'top': 673 | $x = ($this->getWidth() / 2) - ($overlay->getWidth() / 2) + $xOffset; 674 | $y = $yOffset; 675 | break; 676 | case 'bottom left': 677 | $x = $xOffset; 678 | $y = $this->getHeight() - $overlay->getHeight() + $yOffset; 679 | break; 680 | case 'bottom right': 681 | $x = $this->getWidth() - $overlay->getWidth() + $xOffset; 682 | $y = $this->getHeight() - $overlay->getHeight() + $yOffset; 683 | break; 684 | case 'bottom': 685 | $x = ($this->getWidth() / 2) - ($overlay->getWidth() / 2) + $xOffset; 686 | $y = $this->getHeight() - $overlay->getHeight() + $yOffset; 687 | break; 688 | case 'left': 689 | $x = $xOffset; 690 | $y = ($this->getHeight() / 2) - ($overlay->getHeight() / 2) + $yOffset; 691 | break; 692 | case 'right': 693 | $x = $this->getWidth() - $overlay->getWidth() + $xOffset; 694 | $y = ($this->getHeight() / 2) - ($overlay->getHeight() / 2) + $yOffset; 695 | break; 696 | default: 697 | $x = ($this->getWidth() / 2) - ($overlay->getWidth() / 2) + $xOffset; 698 | $y = ($this->getHeight() / 2) - ($overlay->getHeight() / 2) + $yOffset; 699 | break; 700 | } 701 | 702 | // Perform the overlay 703 | self::imageCopyMergeAlpha( 704 | $this->image, 705 | $overlay->image, 706 | $x, $y, 707 | 0, 0, 708 | $overlay->getWidth(), 709 | $overlay->getHeight(), 710 | $opacity 711 | ); 712 | 713 | return $this; 714 | } 715 | 716 | // 717 | // Resize an image to the specified dimensions. If only one dimension is specified, the image will 718 | // be resized proportionally. 719 | // 720 | // $width* (int) - The new image width. 721 | // $height* (int) - The new image height. 722 | // 723 | // Returns a SimpleImage object. 724 | // 725 | public function resize($width = null, $height = null) { 726 | // No dimentions specified 727 | if(!$width && !$height) { 728 | return $this; 729 | } 730 | 731 | // Resize to width 732 | if($width && !$height) { 733 | $height = $width / $this->getAspectRatio(); 734 | } 735 | 736 | // Resize to height 737 | if(!$width && $height) { 738 | $width = $height * $this->getAspectRatio(); 739 | } 740 | 741 | // If the dimensions are the same, there's no need to resize 742 | if($this->getWidth() === $width && $this->getHeight() === $height) { 743 | return $this; 744 | } 745 | 746 | // We can't use imagescale because it doesn't seem to preserve transparency properly. The 747 | // workaround is to create a new truecolor image, allocate a transparent color, and copy the 748 | // image over to it using imagecopyresampled. 749 | $newImage = imagecreatetruecolor($width, $height); 750 | $transparentColor = imagecolorallocatealpha($newImage, 0, 0, 0, 127); 751 | imagecolortransparent($newImage, $transparentColor); 752 | imagefill($newImage, 0, 0, $transparentColor); 753 | imagecopyresampled( 754 | $newImage, 755 | $this->image, 756 | 0, 0, 0, 0, 757 | $width, 758 | $height, 759 | $this->getWidth(), 760 | $this->getHeight() 761 | ); 762 | 763 | // Swap out the new image 764 | $this->image = $newImage; 765 | 766 | return $this; 767 | } 768 | 769 | // 770 | // Sets an image's resolution, as per https://www.php.net/manual/en/function.imageresolution.php 771 | // 772 | // $res_x* (int) - The horizontal resolution in DPI 773 | // $res_y (int) - The vertical resolution in DPI 774 | // 775 | // Returns a SimpleImage object. 776 | // 777 | public function resolution($res_x, $res_y = null) { 778 | if(is_null($res_y)) { 779 | imageresolution($this->image, $res_x); 780 | } else { 781 | imageresolution($this->image, $res_x, $res_y); 782 | } 783 | 784 | return $this; 785 | } 786 | 787 | // 788 | // Rotates the image. 789 | // 790 | // $angle* (int) - The angle of rotation (-360 - 360). 791 | // $backgroundColor (string|array) - The background color to use for the uncovered zone area 792 | // after rotation (default 'transparent'). 793 | // 794 | // Returns a SimpleImage object. 795 | // 796 | public function rotate($angle, $backgroundColor = 'transparent') { 797 | // Rotate the image on a canvas with the desired background color 798 | $backgroundColor = $this->allocateColor($backgroundColor); 799 | 800 | $this->image = imagerotate( 801 | $this->image, 802 | -(self::keepWithin($angle, -360, 360)), 803 | $backgroundColor 804 | ); 805 | imagecolortransparent($this->image, imagecolorallocatealpha($this->image, 0, 0, 0, 127)); 806 | 807 | return $this; 808 | } 809 | 810 | // 811 | // Adds text to the image. 812 | // 813 | // $text* (string) - The desired text. 814 | // $options (array) - An array of options. 815 | // - fontFile* (string) - The TrueType (or compatible) font file to use. 816 | // - size (int) - The size of the font in pixels (default 12). 817 | // - color (string|array) - The text color (default black). 818 | // - anchor (string) - The anchor point: 'center', 'top', 'bottom', 'left', 'right', 819 | // 'top left', 'top right', 'bottom left', 'bottom right' (default 'center'). 820 | // - xOffset (int) - The horizontal offset in pixels (default 0). 821 | // - yOffset (int) - The vertical offset in pixels (default 0). 822 | // - shadow (array) - Text shadow params. 823 | // - x* (int) - Horizontal offset in pixels. 824 | // - y* (int) - Vertical offset in pixels. 825 | // - color* (string|array) - The text shadow color. 826 | // $boundary (array) - If passed, this variable will contain an array with coordinates that 827 | // surround the text: [x1, y1, x2, y2, width, height]. This can be used for calculating the 828 | // text's position after it gets added to the image. 829 | // 830 | // Returns a SimpleImage object. 831 | // 832 | public function text($text, $options, &$boundary = null) { 833 | // Check for freetype support 834 | if(!function_exists('imagettftext')) { 835 | throw new \Exception( 836 | 'Freetype support is not enabled in your version of PHP.', 837 | self::ERR_FREETYPE_NOT_ENABLED 838 | ); 839 | } 840 | 841 | // Default options 842 | $options = array_merge([ 843 | 'fontFile' => null, 844 | 'size' => 12, 845 | 'color' => 'black', 846 | 'anchor' => 'center', 847 | 'xOffset' => 0, 848 | 'yOffset' => 0, 849 | 'shadow' => null 850 | ], $options); 851 | 852 | // Extract and normalize options 853 | $fontFile = $options['fontFile']; 854 | $size = ($options['size'] / 96) * 72; // Convert px to pt (72pt per inch, 96px per inch) 855 | $color = $this->allocateColor($options['color']); 856 | $anchor = $options['anchor']; 857 | $xOffset = $options['xOffset']; 858 | $yOffset = $options['yOffset']; 859 | $angle = 0; 860 | 861 | // Calculate the bounding box dimensions 862 | // 863 | // Since imagettfbox() returns a bounding box from the text's baseline, we can end up with 864 | // different heights for different strings of the same font size. For example, 'type' will often 865 | // be taller than 'text' because the former has a descending letter. 866 | // 867 | // To compensate for this, we create two bounding boxes: one to measure the cap height and 868 | // another to measure the descender height. Based on that, we can adjust the text vertically 869 | // to appear inside the box with a reasonable amount of consistency. 870 | // 871 | // See: https://github.com/claviska/SimpleImage/issues/165 872 | // 873 | $box = imagettfbbox($size, $angle, $fontFile, $text); 874 | if(!$box) { 875 | throw new \Exception("Unable to load font file: $fontFile", self::ERR_FONT_FILE); 876 | } 877 | $boxWidth = abs($box[6] - $box[2]); 878 | $boxHeight = $options['size']; 879 | 880 | // Determine cap height 881 | $box = imagettfbbox($size, $angle, $fontFile, 'X'); 882 | $capHeight = abs($box[7] - $box[1]); 883 | 884 | // Determine descender height 885 | $box = imagettfbbox($size, $angle, $fontFile, 'X Qgjpqy'); 886 | $fullHeight = abs($box[7] - $box[1]); 887 | $descenderHeight = $fullHeight - $capHeight; 888 | 889 | // Determine position 890 | switch($anchor) { 891 | case 'top left': 892 | $x = $xOffset; 893 | $y = $yOffset + $boxHeight; 894 | break; 895 | case 'top right': 896 | $x = $this->getWidth() - $boxWidth + $xOffset; 897 | $y = $yOffset + $boxHeight; 898 | break; 899 | case 'top': 900 | $x = ($this->getWidth() / 2) - ($boxWidth / 2) + $xOffset; 901 | $y = $yOffset + $boxHeight; 902 | break; 903 | case 'bottom left': 904 | $x = $xOffset; 905 | $y = $this->getHeight() - $boxHeight + $yOffset + $boxHeight; 906 | break; 907 | case 'bottom right': 908 | $x = $this->getWidth() - $boxWidth + $xOffset; 909 | $y = $this->getHeight() - $boxHeight + $yOffset + $boxHeight; 910 | break; 911 | case 'bottom': 912 | $x = ($this->getWidth() / 2) - ($boxWidth / 2) + $xOffset; 913 | $y = $this->getHeight() - $boxHeight + $yOffset + $boxHeight; 914 | break; 915 | case 'left': 916 | $x = $xOffset; 917 | $y = ($this->getHeight() / 2) - (($boxHeight / 2) - $boxHeight) + $yOffset; 918 | break; 919 | case 'right'; 920 | $x = $this->getWidth() - $boxWidth + $xOffset; 921 | $y = ($this->getHeight() / 2) - (($boxHeight / 2) - $boxHeight) + $yOffset; 922 | break; 923 | default: // center 924 | $x = ($this->getWidth() / 2) - ($boxWidth / 2) + $xOffset; 925 | $y = ($this->getHeight() / 2) - (($boxHeight / 2) - $boxHeight) + $yOffset; 926 | break; 927 | } 928 | 929 | $x = (int) round($x); 930 | $y = (int) round($y); 931 | 932 | // Pass the boundary back by reference 933 | $boundary = [ 934 | 'x1' => $x, 935 | 'y1' => $y - $boxHeight, // $y is the baseline, not the top! 936 | 'x2' => $x + $boxWidth, 937 | 'y2' => $y, 938 | 'width' => $boxWidth, 939 | 'height' => $boxHeight 940 | ]; 941 | 942 | // Text shadow 943 | if(is_array($options['shadow'])) { 944 | imagettftext( 945 | $this->image, 946 | $size, 947 | $angle, 948 | $x + $options['shadow']['x'], 949 | $y + $options['shadow']['y'] - $descenderHeight, 950 | $this->allocateColor($options['shadow']['color']), 951 | $fontFile, 952 | $text 953 | ); 954 | } 955 | 956 | // Draw the text 957 | imagettftext($this->image, $size, $angle, $x, $y - $descenderHeight, $color, $fontFile, $text); 958 | 959 | return $this; 960 | } 961 | 962 | // 963 | // Creates a thumbnail image. This function attempts to get the image as close to the provided 964 | // dimensions as possible, then crops the remaining overflow to force the desired size. Useful 965 | // for generating thumbnail images. 966 | // 967 | // $width* (int) - The thumbnail width. 968 | // $height* (int) - The thumbnail height. 969 | // $anchor (string) - The anchor point: 'center', 'top', 'bottom', 'left', 'right', 'top left', 970 | // 'top right', 'bottom left', 'bottom right' (default 'center'). 971 | // 972 | // Returns a SimpleImage object. 973 | // 974 | public function thumbnail($width, $height, $anchor = 'center') { 975 | // Determine aspect ratios 976 | $currentRatio = $this->getHeight() / $this->getWidth(); 977 | $targetRatio = $height / $width; 978 | 979 | // Fit to height/width 980 | if($targetRatio > $currentRatio) { 981 | $this->resize(null, $height); 982 | } else { 983 | $this->resize($width, null); 984 | } 985 | 986 | switch($anchor) { 987 | case 'top': 988 | $x1 = floor(($this->getWidth() / 2) - ($width / 2)); 989 | $x2 = $width + $x1; 990 | $y1 = 0; 991 | $y2 = $height; 992 | break; 993 | case 'bottom': 994 | $x1 = floor(($this->getWidth() / 2) - ($width / 2)); 995 | $x2 = $width + $x1; 996 | $y1 = $this->getHeight() - $height; 997 | $y2 = $this->getHeight(); 998 | break; 999 | case 'left': 1000 | $x1 = 0; 1001 | $x2 = $width; 1002 | $y1 = floor(($this->getHeight() / 2) - ($height / 2)); 1003 | $y2 = $height + $y1; 1004 | break; 1005 | case 'right': 1006 | $x1 = $this->getWidth() - $width; 1007 | $x2 = $this->getWidth(); 1008 | $y1 = floor(($this->getHeight() / 2) - ($height / 2)); 1009 | $y2 = $height + $y1; 1010 | break; 1011 | case 'top left': 1012 | $x1 = 0; 1013 | $x2 = $width; 1014 | $y1 = 0; 1015 | $y2 = $height; 1016 | break; 1017 | case 'top right': 1018 | $x1 = $this->getWidth() - $width; 1019 | $x2 = $this->getWidth(); 1020 | $y1 = 0; 1021 | $y2 = $height; 1022 | break; 1023 | case 'bottom left': 1024 | $x1 = 0; 1025 | $x2 = $width; 1026 | $y1 = $this->getHeight() - $height; 1027 | $y2 = $this->getHeight(); 1028 | break; 1029 | case 'bottom right': 1030 | $x1 = $this->getWidth() - $width; 1031 | $x2 = $this->getWidth(); 1032 | $y1 = $this->getHeight() - $height; 1033 | $y2 = $this->getHeight(); 1034 | break; 1035 | default: 1036 | $x1 = floor(($this->getWidth() / 2) - ($width / 2)); 1037 | $x2 = $width + $x1; 1038 | $y1 = floor(($this->getHeight() / 2) - ($height / 2)); 1039 | $y2 = $height + $y1; 1040 | break; 1041 | } 1042 | 1043 | // Return the cropped thumbnail image 1044 | return $this->crop($x1, $y1, $x2, $y2); 1045 | } 1046 | 1047 | ////////////////////////////////////////////////////////////////////////////////////////////////// 1048 | // Drawing 1049 | ////////////////////////////////////////////////////////////////////////////////////////////////// 1050 | 1051 | // 1052 | // Draws an arc. 1053 | // 1054 | // $x* (int) - The x coordinate of the arc's center. 1055 | // $y* (int) - The y coordinate of the arc's center. 1056 | // $width* (int) - The width of the arc. 1057 | // $height* (int) - The height of the arc. 1058 | // $start* (int) - The start of the arc in degrees. 1059 | // $end* (int) - The end of the arc in degrees. 1060 | // $color* (string|array) - The arc color. 1061 | // $thickness (int|string) - Line thickness in pixels or 'filled' (default 1). 1062 | // 1063 | // Returns a SimpleImage object. 1064 | // 1065 | public function arc($x, $y, $width, $height, $start, $end, $color, $thickness = 1) { 1066 | // Allocate the color 1067 | $color = $this->allocateColor($color); 1068 | 1069 | // Draw an arc 1070 | if($thickness === 'filled') { 1071 | imagesetthickness($this->image, 1); 1072 | imagefilledarc($this->image, $x, $y, $width, $height, $start, $end, $color, IMG_ARC_PIE); 1073 | } else { 1074 | imagesetthickness($this->image, $thickness); 1075 | imagearc($this->image, $x, $y, $width, $height, $start, $end, $color); 1076 | } 1077 | 1078 | return $this; 1079 | } 1080 | 1081 | // 1082 | // Draws a border around the image. 1083 | // 1084 | // $color* (string|array) - The border color. 1085 | // $thickness (int) - The thickness of the border (default 1). 1086 | // 1087 | // Returns a SimpleImage object. 1088 | // 1089 | public function border($color, $thickness = 1) { 1090 | $x1 = 0; 1091 | $y1 = 0; 1092 | $x2 = $this->getWidth() - 1; 1093 | $y2 = $this->getHeight() - 1; 1094 | 1095 | // Draw a border rectangle until it reaches the correct width 1096 | for($i = 0; $i < $thickness; $i++) { 1097 | $this->rectangle($x1++, $y1++, $x2--, $y2--, $color); 1098 | } 1099 | 1100 | return $this; 1101 | } 1102 | 1103 | // 1104 | // Draws a single pixel dot. 1105 | // 1106 | // $x* (int) - The x coordinate of the dot. 1107 | // $y* (int) - The y coordinate of the dot. 1108 | // $color* (string|array) - The dot color. 1109 | // 1110 | // Returns a SimpleImage object. 1111 | // 1112 | public function dot($x, $y, $color) { 1113 | $color = $this->allocateColor($color); 1114 | imagesetpixel($this->image, $x, $y, $color); 1115 | 1116 | return $this; 1117 | } 1118 | 1119 | // 1120 | // Draws an ellipse. 1121 | // 1122 | // $x* (int) - The x coordinate of the center. 1123 | // $y* (int) - The y coordinate of the center. 1124 | // $width* (int) - The ellipse width. 1125 | // $height* (int) - The ellipse height. 1126 | // $color* (string|array) - The ellipse color. 1127 | // $thickness (int|string) - Line thickness in pixels or 'filled' (default 1). 1128 | // 1129 | // Returns a SimpleImage object. 1130 | // 1131 | public function ellipse($x, $y, $width, $height, $color, $thickness = 1) { 1132 | // Allocate the color 1133 | $color = $this->allocateColor($color); 1134 | 1135 | // Draw an ellipse 1136 | if($thickness === 'filled') { 1137 | imagesetthickness($this->image, 1); 1138 | imagefilledellipse($this->image, $x, $y, $width, $height, $color); 1139 | } else { 1140 | // imagesetthickness doesn't appear to work with imageellipse, so we work around it. 1141 | imagesetthickness($this->image, 1); 1142 | $i = 0; 1143 | while($i++ < $thickness * 2 - 1) { 1144 | imageellipse($this->image, $x, $y, --$width, $height--, $color); 1145 | } 1146 | } 1147 | 1148 | return $this; 1149 | } 1150 | 1151 | // 1152 | // Fills the image with a solid color. 1153 | // 1154 | // $color (string|array) - The fill color. 1155 | // 1156 | // Returns a SimpleImage object. 1157 | // 1158 | public function fill($color) { 1159 | // Draw a filled rectangle over the entire image 1160 | $this->rectangle(0, 0, $this->getWidth(), $this->getHeight(), 'white', 'filled'); 1161 | 1162 | // Now flood it with the appropriate color 1163 | $color = $this->allocateColor($color); 1164 | imagefill($this->image, 0, 0, $color); 1165 | 1166 | return $this; 1167 | } 1168 | 1169 | // 1170 | // Draws a line. 1171 | // 1172 | // $x1* (int) - The x coordinate for the first point. 1173 | // $y1* (int) - The y coordinate for the first point. 1174 | // $x2* (int) - The x coordinate for the second point. 1175 | // $y2* (int) - The y coordinate for the second point. 1176 | // $color (string|array) - The line color. 1177 | // $thickness (int) - The line thickness (default 1). 1178 | // 1179 | // Returns a SimpleImage object. 1180 | // 1181 | public function line($x1, $y1, $x2, $y2, $color, $thickness = 1) { 1182 | // Allocate the color 1183 | $color = $this->allocateColor($color); 1184 | 1185 | // Draw a line 1186 | imagesetthickness($this->image, $thickness); 1187 | imageline($this->image, $x1, $y1, $x2, $y2, $color); 1188 | 1189 | return $this; 1190 | } 1191 | 1192 | // 1193 | // Draws a polygon. 1194 | // 1195 | // $vertices* (array) - The polygon's vertices in an array of x/y arrays. Example: 1196 | // [ 1197 | // ['x' => x1, 'y' => y1], 1198 | // ['x' => x2, 'y' => y2], 1199 | // ['x' => xN, 'y' => yN] 1200 | // ] 1201 | // $color* (string|array) - The polygon color. 1202 | // $thickness (int|string) - Line thickness in pixels or 'filled' (default 1). 1203 | // 1204 | // Returns a SimpleImage object. 1205 | // 1206 | public function polygon($vertices, $color, $thickness = 1) { 1207 | // Allocate the color 1208 | $color = $this->allocateColor($color); 1209 | 1210 | // Convert [['x' => x1, 'y' => x1], ['x' => x1, 'y' => y2], ...] to [x1, y1, x2, y2, ...] 1211 | $points = []; 1212 | foreach($vertices as $vals) { 1213 | $points[] = $vals['x']; 1214 | $points[] = $vals['y']; 1215 | } 1216 | 1217 | // Draw a polygon 1218 | if($thickness === 'filled') { 1219 | imagesetthickness($this->image, 1); 1220 | imagefilledpolygon($this->image, $points, count($vertices), $color); 1221 | } else { 1222 | imagesetthickness($this->image, $thickness); 1223 | imagepolygon($this->image, $points, count($vertices), $color); 1224 | } 1225 | 1226 | return $this; 1227 | } 1228 | 1229 | // 1230 | // Draws a rectangle. 1231 | // 1232 | // $x1* (int) - The upper left x coordinate. 1233 | // $y1* (int) - The upper left y coordinate. 1234 | // $x2* (int) - The bottom right x coordinate. 1235 | // $y2* (int) - The bottom right y coordinate. 1236 | // $color* (string|array) - The rectangle color. 1237 | // $thickness (int|string) - Line thickness in pixels or 'filled' (default 1). 1238 | // 1239 | // Returns a SimpleImage object. 1240 | // 1241 | public function rectangle($x1, $y1, $x2, $y2, $color, $thickness = 1) { 1242 | // Allocate the color 1243 | $color = $this->allocateColor($color); 1244 | 1245 | // Draw a rectangle 1246 | if($thickness === 'filled') { 1247 | imagesetthickness($this->image, 1); 1248 | imagefilledrectangle($this->image, $x1, $y1, $x2, $y2, $color); 1249 | } else { 1250 | imagesetthickness($this->image, $thickness); 1251 | imagerectangle($this->image, $x1, $y1, $x2, $y2, $color); 1252 | } 1253 | 1254 | return $this; 1255 | } 1256 | 1257 | // 1258 | // Draws a rounded rectangle. 1259 | // 1260 | // $x1* (int) - The upper left x coordinate. 1261 | // $y1* (int) - The upper left y coordinate. 1262 | // $x2* (int) - The bottom right x coordinate. 1263 | // $y2* (int) - The bottom right y coordinate. 1264 | // $radius* (int) - The border radius in pixels. 1265 | // $color* (string|array) - The rectangle color. 1266 | // $thickness (int|string) - Line thickness in pixels or 'filled' (default 1). 1267 | // 1268 | // Returns a SimpleImage object. 1269 | // 1270 | public function roundedRectangle($x1, $y1, $x2, $y2, $radius, $color, $thickness = 1) { 1271 | if($thickness === 'filled') { 1272 | // Draw the filled rectangle without edges 1273 | $this->rectangle($x1 + $radius + 1, $y1, $x2 - $radius - 1, $y2, $color, 'filled'); 1274 | $this->rectangle($x1, $y1 + $radius + 1, $x1 + $radius, $y2 - $radius - 1, $color, 'filled'); 1275 | $this->rectangle($x2 - $radius, $y1 + $radius + 1, $x2, $y2 - $radius - 1, $color, 'filled'); 1276 | // Fill in the edges with arcs 1277 | $this->arc($x1 + $radius, $y1 + $radius, $radius * 2, $radius * 2, 180, 270, $color, 'filled'); 1278 | $this->arc($x2 - $radius, $y1 + $radius, $radius * 2, $radius * 2, 270, 360, $color, 'filled'); 1279 | $this->arc($x1 + $radius, $y2 - $radius, $radius * 2, $radius * 2, 90, 180, $color, 'filled'); 1280 | $this->arc($x2 - $radius, $y2 - $radius, $radius * 2, $radius * 2, 360, 90, $color, 'filled'); 1281 | } else { 1282 | // Draw the rectangle outline without edges 1283 | $this->line($x1 + $radius, $y1, $x2 - $radius, $y1, $color, $thickness); 1284 | $this->line($x1 + $radius, $y2, $x2 - $radius, $y2, $color, $thickness); 1285 | $this->line($x1, $y1 + $radius, $x1, $y2 - $radius, $color, $thickness); 1286 | $this->line($x2, $y1 + $radius, $x2, $y2 - $radius, $color, $thickness); 1287 | // Fill in the edges with arcs 1288 | $this->arc($x1 + $radius, $y1 + $radius, $radius * 2, $radius * 2, 180, 270, $color, $thickness); 1289 | $this->arc($x2 - $radius, $y1 + $radius, $radius * 2, $radius * 2, 270, 360, $color, $thickness); 1290 | $this->arc($x1 + $radius, $y2 - $radius, $radius * 2, $radius * 2, 90, 180, $color, $thickness); 1291 | $this->arc($x2 - $radius, $y2 - $radius, $radius * 2, $radius * 2, 360, 90, $color, $thickness); 1292 | } 1293 | 1294 | return $this; 1295 | } 1296 | 1297 | ////////////////////////////////////////////////////////////////////////////////////////////////// 1298 | // Filters 1299 | ////////////////////////////////////////////////////////////////////////////////////////////////// 1300 | 1301 | // 1302 | // Applies the blur filter. 1303 | // 1304 | // $type (string) - The blur algorithm to use: 'selective', 'gaussian' (default 'gaussian'). 1305 | // $passes (int) - The number of time to apply the filter, enhancing the effect (default 1). 1306 | // 1307 | // Returns a SimpleImage object. 1308 | // 1309 | public function blur($type = 'selective', $passes = 1) { 1310 | $filter = $type === 'gaussian' ? IMG_FILTER_GAUSSIAN_BLUR : IMG_FILTER_SELECTIVE_BLUR; 1311 | 1312 | for($i = 0; $i < $passes; $i++) { 1313 | imagefilter($this->image, $filter); 1314 | } 1315 | 1316 | return $this; 1317 | } 1318 | 1319 | // 1320 | // Applies the brightness filter to brighten the image. 1321 | // 1322 | // $percentage* (int) - Percentage to brighten the image (0 - 100). 1323 | // 1324 | // Returns a SimpleImage object. 1325 | // 1326 | public function brighten($percentage) { 1327 | $percentage = self::keepWithin(255 * $percentage / 100, 0, 255); 1328 | 1329 | imagefilter($this->image, IMG_FILTER_BRIGHTNESS, $percentage); 1330 | 1331 | return $this; 1332 | } 1333 | 1334 | // 1335 | // Applies the colorize filter. 1336 | // 1337 | // $color* (string|array) - The filter color. 1338 | // 1339 | // Returns a SimpleImage object. 1340 | // 1341 | public function colorize($color) { 1342 | $color = self::normalizeColor($color); 1343 | 1344 | imagefilter( 1345 | $this->image, 1346 | IMG_FILTER_COLORIZE, 1347 | $color['red'], 1348 | $color['green'], 1349 | $color['blue'], 1350 | 127 - ($color['alpha'] * 127) 1351 | ); 1352 | 1353 | return $this; 1354 | } 1355 | 1356 | // 1357 | // Applies the contrast filter. 1358 | // 1359 | // $percentage* (int) - Percentage to adjust (-100 - 100). 1360 | // 1361 | // Returns a SimpleImage object. 1362 | // 1363 | public function contrast($percentage) { 1364 | imagefilter($this->image, IMG_FILTER_CONTRAST, self::keepWithin($percentage, -100, 100)); 1365 | 1366 | return $this; 1367 | } 1368 | 1369 | // 1370 | // Applies the brightness filter to darken the image. 1371 | // 1372 | // $percentage* (int) - Percentage to darken the image (0 - 100). 1373 | // 1374 | // Returns a SimpleImage object. 1375 | // 1376 | public function darken($percentage) { 1377 | $percentage = self::keepWithin(255 * $percentage / 100, 0, 255); 1378 | 1379 | imagefilter($this->image, IMG_FILTER_BRIGHTNESS, -$percentage); 1380 | 1381 | return $this; 1382 | } 1383 | 1384 | // 1385 | // Applies the desaturate (grayscale) filter. 1386 | // 1387 | // Returns a SimpleImage object. 1388 | // 1389 | public function desaturate() { 1390 | imagefilter($this->image, IMG_FILTER_GRAYSCALE); 1391 | 1392 | return $this; 1393 | } 1394 | 1395 | // 1396 | // Applies the edge detect filter. 1397 | // 1398 | // Returns a SimpleImage object. 1399 | // 1400 | public function edgeDetect() { 1401 | imagefilter($this->image, IMG_FILTER_EDGEDETECT); 1402 | 1403 | return $this; 1404 | } 1405 | 1406 | // 1407 | // Applies the emboss filter. 1408 | // 1409 | // Returns a SimpleImage object. 1410 | // 1411 | public function emboss() { 1412 | imagefilter($this->image, IMG_FILTER_EMBOSS); 1413 | 1414 | return $this; 1415 | } 1416 | 1417 | // 1418 | // Inverts the image's colors. 1419 | // 1420 | // Returns a SimpleImage object. 1421 | // 1422 | public function invert() { 1423 | imagefilter($this->image, IMG_FILTER_NEGATE); 1424 | 1425 | return $this; 1426 | } 1427 | 1428 | // 1429 | // Changes the image's opacity level. 1430 | // 1431 | // $opacity* (float) - The desired opacity level (0 - 1). 1432 | // 1433 | // Returns a SimpleImage object. 1434 | // 1435 | public function opacity($opacity) { 1436 | // Create a transparent image 1437 | $newImage = new SimpleImage(); 1438 | $newImage->fromNew($this->getWidth(), $this->getHeight()); 1439 | 1440 | // Copy the current image (with opacity) onto the transparent image 1441 | self::imageCopyMergeAlpha( 1442 | $newImage->image, 1443 | $this->image, 1444 | 0, 0, 1445 | 0, 0, 1446 | $this->getWidth(), 1447 | $this->getHeight(), 1448 | self::keepWithin($opacity, 0, 1) * 100 1449 | ); 1450 | 1451 | return $this; 1452 | } 1453 | 1454 | // 1455 | // Applies the pixelate filter. 1456 | // 1457 | // $size (int) - The size of the blocks in pixels (default 10). 1458 | // 1459 | // Returns a SimpleImage object. 1460 | // 1461 | public function pixelate($size = 10) { 1462 | imagefilter($this->image, IMG_FILTER_PIXELATE, $size, true); 1463 | 1464 | return $this; 1465 | } 1466 | 1467 | // 1468 | // Simulates a sepia effect by desaturating the image and applying a sepia tone. 1469 | // 1470 | // Returns a SimpleImage object. 1471 | // 1472 | public function sepia() { 1473 | imagefilter($this->image, IMG_FILTER_GRAYSCALE); 1474 | imagefilter($this->image, IMG_FILTER_COLORIZE, 70, 35, 0); 1475 | 1476 | return $this; 1477 | } 1478 | 1479 | // 1480 | // Sharpens the image. 1481 | // 1482 | // $amount (int) - Sharpening amount (default 50) 1483 | // 1484 | // Returns a SimpleImage object. 1485 | // 1486 | public function sharpen($amount = 50) { 1487 | // Normalize amount 1488 | $amount = max(1, min(100, $amount)) / 100; 1489 | 1490 | $sharpen = [ 1491 | [-1, -1, -1], 1492 | [-1, 8 / $amount, -1], 1493 | [-1, -1, -1], 1494 | ]; 1495 | $divisor = array_sum(array_map('array_sum', $sharpen)); 1496 | 1497 | imageconvolution($this->image, $sharpen, $divisor, 0); 1498 | 1499 | return $this; 1500 | } 1501 | 1502 | // 1503 | // Applies the mean remove filter to produce a sketch effect. 1504 | // 1505 | // Returns a SimpleImage object. 1506 | // 1507 | public function sketch() { 1508 | imagefilter($this->image, IMG_FILTER_MEAN_REMOVAL); 1509 | 1510 | return $this; 1511 | } 1512 | 1513 | ////////////////////////////////////////////////////////////////////////////////////////////////// 1514 | // Color utilities 1515 | ////////////////////////////////////////////////////////////////////////////////////////////////// 1516 | 1517 | // 1518 | // Converts a "friendly color" into a color identifier for use with GD's image functions. 1519 | // 1520 | // $image (resource) - The target image. 1521 | // $color (string|array) - The color to allocate. 1522 | // 1523 | // Returns a color identifier. 1524 | // 1525 | protected function allocateColor($color) { 1526 | $color = self::normalizeColor($color); 1527 | 1528 | // Was this color already allocated? 1529 | $index = imagecolorexactalpha( 1530 | $this->image, 1531 | $color['red'], 1532 | $color['green'], 1533 | $color['blue'], 1534 | 127 - ($color['alpha'] * 127) 1535 | ); 1536 | if($index > -1) { 1537 | // Yes, return this color index 1538 | return $index; 1539 | } 1540 | 1541 | // Allocate a new color index 1542 | return imagecolorallocatealpha( 1543 | $this->image, 1544 | $color['red'], 1545 | $color['green'], 1546 | $color['blue'], 1547 | 127 - ($color['alpha'] * 127) 1548 | ); 1549 | } 1550 | 1551 | // 1552 | // Adjusts a color by increasing/decreasing red/green/blue/alpha values independently. 1553 | // 1554 | // $color* (string|array) - The color to adjust. 1555 | // $red* (int) - Red adjustment (-255 - 255). 1556 | // $green* (int) - Green adjustment (-255 - 255). 1557 | // $blue* (int) - Blue adjustment (-255 - 255). 1558 | // $alpha* (float) - Alpha adjustment (-1 - 1). 1559 | // 1560 | // Returns an RGBA color array. 1561 | // 1562 | public static function adjustColor($color, $red, $green, $blue, $alpha) { 1563 | // Normalize to RGBA 1564 | $color = self::normalizeColor($color); 1565 | 1566 | // Adjust each channel 1567 | return self::normalizeColor([ 1568 | 'red' => $color['red'] + $red, 1569 | 'green' => $color['green'] + $green, 1570 | 'blue' => $color['blue'] + $blue, 1571 | 'alpha' => $color['alpha'] + $alpha 1572 | ]); 1573 | } 1574 | 1575 | // 1576 | // Darkens a color. 1577 | // 1578 | // $color* (string|array) - The color to darken. 1579 | // $amount* (int) - Amount to darken (0 - 255). 1580 | // 1581 | // Returns an RGBA color array. 1582 | // 1583 | public static function darkenColor($color, $amount) { 1584 | return self::adjustColor($color, -$amount, -$amount, -$amount, 0); 1585 | } 1586 | 1587 | // 1588 | // Extracts colors from an image like a human would do.™ This method requires the third-party 1589 | // library \League\ColorExtractor. If you're using Composer, it will be installed for you 1590 | // automatically. 1591 | // 1592 | // $count (int) - The max number of colors to extract (default 5). 1593 | // $backgroundColor (string|array) - By default any pixel with alpha value greater than zero will 1594 | // be discarded. This is because transparent colors are not perceived as is. For example, fully 1595 | // transparent black would be seen white on a white background. So if you want to take 1596 | // transparency into account, you have to specify a default background color. 1597 | // 1598 | // Returns an array of RGBA colors arrays. 1599 | // 1600 | public function extractColors($count = 5, $backgroundColor = null) { 1601 | // Check for required library 1602 | if(!class_exists('\League\ColorExtractor\ColorExtractor')) { 1603 | throw new \Exception( 1604 | 'Required library \League\ColorExtractor is missing.', 1605 | self::ERR_LIB_NOT_LOADED 1606 | ); 1607 | } 1608 | 1609 | // Convert background color to an integer value 1610 | if($backgroundColor) { 1611 | $backgroundColor = self::normalizeColor($backgroundColor); 1612 | $backgroundColor = \League\ColorExtractor\Color::fromRgbToInt([ 1613 | 'r' => $backgroundColor['red'], 1614 | 'g' => $backgroundColor['green'], 1615 | 'b' => $backgroundColor['blue'] 1616 | ]); 1617 | } 1618 | 1619 | // Extract colors from the image 1620 | $palette = \League\ColorExtractor\Palette::fromGD($this->image, $backgroundColor); 1621 | $extractor = new \League\ColorExtractor\ColorExtractor($palette); 1622 | $colors = $extractor->extract($count); 1623 | 1624 | // Convert colors to an RGBA color array 1625 | foreach($colors as $key => $value) { 1626 | $colors[$key] = self::normalizeColor(\League\ColorExtractor\Color::fromIntToHex($value)); 1627 | } 1628 | 1629 | return $colors; 1630 | } 1631 | 1632 | // 1633 | // Gets the RGBA value of a single pixel. 1634 | // 1635 | // $x* (int) - The horizontal position of the pixel. 1636 | // $y* (int) - The vertical position of the pixel. 1637 | // 1638 | // Returns an RGBA color array or false if the x/y position is off the canvas. 1639 | // 1640 | public function getColorAt($x, $y) { 1641 | // Coordinates must be on the canvas 1642 | if($x < 0 || $x > $this->getWidth() || $y < 0 || $y > $this->getHeight()) { 1643 | return false; 1644 | } 1645 | 1646 | // Get the color of this pixel and convert it to RGBA 1647 | $color = imagecolorat($this->image, $x, $y); 1648 | $rgba = imagecolorsforindex($this->image, $color); 1649 | $rgba['alpha'] = 127 - ($color >> 24) & 0xFF; 1650 | 1651 | return $rgba; 1652 | } 1653 | 1654 | // 1655 | // Lightens a color. 1656 | // 1657 | // $color* (string|array) - The color to lighten. 1658 | // $amount* (int) - Amount to darken (0 - 255). 1659 | // 1660 | // Returns an RGBA color array. 1661 | // 1662 | public static function lightenColor($color, $amount) { 1663 | return self::adjustColor($color, $amount, $amount, $amount, 0); 1664 | } 1665 | 1666 | // 1667 | // Normalizes a hex or array color value to a well-formatted RGBA array. 1668 | // 1669 | // $color* (string|array) - A CSS color name, hex string, or an array [red, green, blue, alpha]. 1670 | // You can pipe alpha transparency through hex strings and color names. For example: 1671 | // 1672 | // #fff|0.50 <-- 50% white 1673 | // red|0.25 <-- 25% red 1674 | // 1675 | // Returns an array: [red, green, blue, alpha] 1676 | // 1677 | public static function normalizeColor($color) { 1678 | // 140 CSS color names and hex values 1679 | $cssColors = [ 1680 | 'aliceblue' => '#f0f8ff', 'antiquewhite' => '#faebd7', 'aqua' => '#00ffff', 1681 | 'aquamarine' => '#7fffd4', 'azure' => '#f0ffff', 'beige' => '#f5f5dc', 'bisque' => '#ffe4c4', 1682 | 'black' => '#000000', 'blanchedalmond' => '#ffebcd', 'blue' => '#0000ff', 1683 | 'blueviolet' => '#8a2be2', 'brown' => '#a52a2a', 'burlywood' => '#deb887', 1684 | 'cadetblue' => '#5f9ea0', 'chartreuse' => '#7fff00', 'chocolate' => '#d2691e', 1685 | 'coral' => '#ff7f50', 'cornflowerblue' => '#6495ed', 'cornsilk' => '#fff8dc', 1686 | 'crimson' => '#dc143c', 'cyan' => '#00ffff', 'darkblue' => '#00008b', 'darkcyan' => '#008b8b', 1687 | 'darkgoldenrod' => '#b8860b', 'darkgray' => '#a9a9a9', 'darkgrey' => '#a9a9a9', 1688 | 'darkgreen' => '#006400', 'darkkhaki' => '#bdb76b', 'darkmagenta' => '#8b008b', 1689 | 'darkolivegreen' => '#556b2f', 'darkorange' => '#ff8c00', 'darkorchid' => '#9932cc', 1690 | 'darkred' => '#8b0000', 'darksalmon' => '#e9967a', 'darkseagreen' => '#8fbc8f', 1691 | 'darkslateblue' => '#483d8b', 'darkslategray' => '#2f4f4f', 'darkslategrey' => '#2f4f4f', 1692 | 'darkturquoise' => '#00ced1', 'darkviolet' => '#9400d3', 'deeppink' => '#ff1493', 1693 | 'deepskyblue' => '#00bfff', 'dimgray' => '#696969', 'dimgrey' => '#696969', 1694 | 'dodgerblue' => '#1e90ff', 'firebrick' => '#b22222', 'floralwhite' => '#fffaf0', 1695 | 'forestgreen' => '#228b22', 'fuchsia' => '#ff00ff', 'gainsboro' => '#dcdcdc', 1696 | 'ghostwhite' => '#f8f8ff', 'gold' => '#ffd700', 'goldenrod' => '#daa520', 'gray' => '#808080', 1697 | 'grey' => '#808080', 'green' => '#008000', 'greenyellow' => '#adff2f', 1698 | 'honeydew' => '#f0fff0', 'hotpink' => '#ff69b4', 'indianred ' => '#cd5c5c', 1699 | 'indigo ' => '#4b0082', 'ivory' => '#fffff0', 'khaki' => '#f0e68c', 'lavender' => '#e6e6fa', 1700 | 'lavenderblush' => '#fff0f5', 'lawngreen' => '#7cfc00', 'lemonchiffon' => '#fffacd', 1701 | 'lightblue' => '#add8e6', 'lightcoral' => '#f08080', 'lightcyan' => '#e0ffff', 1702 | 'lightgoldenrodyellow' => '#fafad2', 'lightgray' => '#d3d3d3', 'lightgrey' => '#d3d3d3', 1703 | 'lightgreen' => '#90ee90', 'lightpink' => '#ffb6c1', 'lightsalmon' => '#ffa07a', 1704 | 'lightseagreen' => '#20b2aa', 'lightskyblue' => '#87cefa', 'lightslategray' => '#778899', 1705 | 'lightslategrey' => '#778899', 'lightsteelblue' => '#b0c4de', 'lightyellow' => '#ffffe0', 1706 | 'lime' => '#00ff00', 'limegreen' => '#32cd32', 'linen' => '#faf0e6', 'magenta' => '#ff00ff', 1707 | 'maroon' => '#800000', 'mediumaquamarine' => '#66cdaa', 'mediumblue' => '#0000cd', 1708 | 'mediumorchid' => '#ba55d3', 'mediumpurple' => '#9370db', 'mediumseagreen' => '#3cb371', 1709 | 'mediumslateblue' => '#7b68ee', 'mediumspringgreen' => '#00fa9a', 1710 | 'mediumturquoise' => '#48d1cc', 'mediumvioletred' => '#c71585', 'midnightblue' => '#191970', 1711 | 'mintcream' => '#f5fffa', 'mistyrose' => '#ffe4e1', 'moccasin' => '#ffe4b5', 1712 | 'navajowhite' => '#ffdead', 'navy' => '#000080', 'oldlace' => '#fdf5e6', 'olive' => '#808000', 1713 | 'olivedrab' => '#6b8e23', 'orange' => '#ffa500', 'orangered' => '#ff4500', 1714 | 'orchid' => '#da70d6', 'palegoldenrod' => '#eee8aa', 'palegreen' => '#98fb98', 1715 | 'paleturquoise' => '#afeeee', 'palevioletred' => '#db7093', 'papayawhip' => '#ffefd5', 1716 | 'peachpuff' => '#ffdab9', 'peru' => '#cd853f', 'pink' => '#ffc0cb', 'plum' => '#dda0dd', 1717 | 'powderblue' => '#b0e0e6', 'purple' => '#800080', 'rebeccapurple' => '#663399', 1718 | 'red' => '#ff0000', 'rosybrown' => '#bc8f8f', 'royalblue' => '#4169e1', 1719 | 'saddlebrown' => '#8b4513', 'salmon' => '#fa8072', 'sandybrown' => '#f4a460', 1720 | 'seagreen' => '#2e8b57', 'seashell' => '#fff5ee', 'sienna' => '#a0522d', 1721 | 'silver' => '#c0c0c0', 'skyblue' => '#87ceeb', 'slateblue' => '#6a5acd', 1722 | 'slategray' => '#708090', 'slategrey' => '#708090', 'snow' => '#fffafa', 1723 | 'springgreen' => '#00ff7f', 'steelblue' => '#4682b4', 'tan' => '#d2b48c', 'teal' => '#008080', 1724 | 'thistle' => '#d8bfd8', 'tomato' => '#ff6347', 'turquoise' => '#40e0d0', 1725 | 'violet' => '#ee82ee', 'wheat' => '#f5deb3', 'white' => '#ffffff', 'whitesmoke' => '#f5f5f5', 1726 | 'yellow' => '#ffff00', 'yellowgreen' => '#9acd32' 1727 | ]; 1728 | 1729 | // Parse alpha from '#fff|.5' and 'white|.5' 1730 | if(is_string($color) && strstr($color, '|')) { 1731 | $color = explode('|', $color); 1732 | $alpha = (float) $color[1]; 1733 | $color = trim($color[0]); 1734 | } else { 1735 | $alpha = 1; 1736 | } 1737 | 1738 | // Translate CSS color names to hex values 1739 | if(is_string($color) && array_key_exists(strtolower($color), $cssColors)) { 1740 | $color = $cssColors[strtolower($color)]; 1741 | } 1742 | 1743 | // Translate transparent keyword to a transparent color 1744 | if($color === 'transparent') { 1745 | $color = ['red' => 0, 'green' => 0, 'blue' => 0, 'alpha' => 0]; 1746 | } 1747 | 1748 | // Convert hex values to RGBA 1749 | if(is_string($color)) { 1750 | // Remove # 1751 | $hex = preg_replace('/^#/', '', $color); 1752 | 1753 | // Support short and standard hex codes 1754 | if(strlen($hex) === 3) { 1755 | list($red, $green, $blue) = [ 1756 | $hex[0] . $hex[0], 1757 | $hex[1] . $hex[1], 1758 | $hex[2] . $hex[2] 1759 | ]; 1760 | } elseif(strlen($hex) === 6) { 1761 | list($red, $green, $blue) = [ 1762 | $hex[0] . $hex[1], 1763 | $hex[2] . $hex[3], 1764 | $hex[4] . $hex[5] 1765 | ]; 1766 | } else { 1767 | throw new \Exception("Invalid color value: $color", self::ERR_INVALID_COLOR); 1768 | } 1769 | 1770 | // Turn color into an array 1771 | $color = [ 1772 | 'red' => hexdec($red), 1773 | 'green' => hexdec($green), 1774 | 'blue' => hexdec($blue), 1775 | 'alpha' => $alpha 1776 | ]; 1777 | } 1778 | 1779 | // Enforce color value ranges 1780 | if(is_array($color)) { 1781 | // RGB default to 0 1782 | $color['red'] = isset($color['red']) ? $color['red'] : 0; 1783 | $color['green'] = isset($color['green']) ? $color['green'] : 0; 1784 | $color['blue'] = isset($color['blue']) ? $color['blue'] : 0; 1785 | 1786 | // Alpha defaults to 1 1787 | $color['alpha'] = isset($color['alpha']) ? $color['alpha'] : 1; 1788 | 1789 | return [ 1790 | 'red' => (int) self::keepWithin((int) $color['red'], 0, 255), 1791 | 'green' => (int) self::keepWithin((int) $color['green'], 0, 255), 1792 | 'blue' => (int) self::keepWithin((int) $color['blue'], 0, 255), 1793 | 'alpha' => self::keepWithin($color['alpha'], 0, 1) 1794 | ]; 1795 | } 1796 | 1797 | throw new \Exception("Invalid color value: $color", self::ERR_INVALID_COLOR); 1798 | } 1799 | 1800 | } -------------------------------------------------------------------------------- /src/Console/FilemanagerInstall.php: -------------------------------------------------------------------------------- 1 | confirm("filemanager.php already exist. Do you want to overwrite?"); 45 | if ($confirm) { 46 | $this->publishConfig(); 47 | $this->info("config overwrite finished"); 48 | } else { 49 | $this->info("skipped config publish"); 50 | } 51 | } else { 52 | $this->publishConfig(); 53 | $this->info("config published"); 54 | } 55 | 56 | //assets 57 | if (File::exists(public_path('filemanager'))) { 58 | $confirm = $this->confirm("filemanager directory already exist. Do you want to overwrite?"); 59 | if ($confirm) { 60 | $this->publishAssets(); 61 | $this->info("assets overwrite finished"); 62 | } else { 63 | $this->info("skipped assets publish"); 64 | } 65 | } else { 66 | $this->publishAssets(); 67 | $this->info("assets published"); 68 | } 69 | 70 | //migration 71 | if (File::exists(database_path("migrations/$migrationFile"))) { 72 | $confirm = $this->confirm("migration file already exist. Do you want to overwrite?"); 73 | if ($confirm) { 74 | $this->publishMigration(); 75 | $this->info("migration overwrite finished"); 76 | } else { 77 | $this->info("skipped migration publish"); 78 | } 79 | } else { 80 | $this->publishMigration(); 81 | $this->info("migration published"); 82 | } 83 | 84 | $this->call('migrate'); 85 | } 86 | 87 | private function publishConfig() 88 | { 89 | $this->call('vendor:publish', [ 90 | '--provider' => "Haruncpi\LaravelSimpleFilemanager\ServiceProvider", 91 | '--tag' => 'config', 92 | '--force' => true 93 | ]); 94 | } 95 | 96 | private function publishMigration() 97 | { 98 | $this->call('vendor:publish', [ 99 | '--provider' => "Haruncpi\LaravelSimpleFilemanager\ServiceProvider", 100 | '--tag' => 'migrations', 101 | '--force' => true 102 | ]); 103 | } 104 | 105 | private function publishAssets() 106 | { 107 | $this->call('vendor:publish', [ 108 | '--provider' => "Haruncpi\LaravelSimpleFilemanager\ServiceProvider", 109 | '--tag' => 'assets', 110 | '--force' => true 111 | ]); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/Controllers/FilemanagerController.php: -------------------------------------------------------------------------------- 1 | fields = ['id', 'name', 'ext', 'file_size', 'absolute_url', 'extra', 'created_at', 'updated_at']; 26 | $this->orderTypes = ['asc', 'desc']; 27 | $this->basePath = public_path('filemanager/uploads'); 28 | $this->baseUrl = url('filemanager/uploads'); 29 | $this->config = config('filemanager'); 30 | $this->imageFormat = ['jpg', 'jpeg', 'png', 'gif', 'webp']; 31 | } 32 | 33 | public function getIndex(Request $request) 34 | { 35 | if ($request->has('action')) { 36 | $action = $request->get('action'); 37 | 38 | switch ($action) { 39 | case 'files': 40 | return $this->getFiles($request); 41 | break; 42 | default: 43 | break; 44 | } 45 | } 46 | 47 | $thumbUrl = $this->baseUrl . '/thumbs'; 48 | $acceptedFiles = implode(',', preg_filter('/^/', '.', array_map('trim', explode(',', config('filemanager.allow_format', 'jpg,png'))))); 49 | 50 | return view('filemanager::index', [ 51 | 'thumbUrl' => $thumbUrl, 52 | 'acceptedFiles' => $acceptedFiles 53 | ]); 54 | } 55 | 56 | public function postAction(Request $request) 57 | { 58 | if ($request->has('action')) { 59 | $action = $request->get('action'); 60 | switch ($action) { 61 | case 'upload': 62 | return $this->postUpload($request); 63 | break; 64 | case 'updateName': 65 | return $this->postUpdateName($request); 66 | break; 67 | case 'convert': 68 | return $this->postConvertImage($request); 69 | break; 70 | case 'delete': 71 | return $this->postDelete($request); 72 | break; 73 | } 74 | } 75 | } 76 | 77 | public function getFiles(Request $r) 78 | { 79 | $data = new Filemanager(); 80 | $data = $data->orderBy('id', 'desc'); 81 | $data = $data->where('user_id', Auth()->user()->id); 82 | 83 | if ($r->has('q')) { 84 | $q = $r->get('q'); 85 | if ($q !== 'undefined' && $q !== '' && !empty($q)) { 86 | $data = $data->where('name', 'like', '%' . $q . '%'); 87 | } 88 | } 89 | 90 | if ($r->has('file_type')) { 91 | $type = $r->get('file_type'); 92 | switch ($type) { 93 | case 'image'; 94 | $data = $data->whereIn('ext', $this->imageFormat); 95 | break; 96 | } 97 | } 98 | 99 | return $data->paginate(20); 100 | } 101 | 102 | private function getAbsoluteUrl($fileName) 103 | { 104 | return $this->baseUrl . '/' . $fileName; 105 | } 106 | 107 | private function postConvertImage(Request $request) 108 | { 109 | $id = $request->get('id'); 110 | $name = $request->get('name'); 111 | $ext = $request->get('ext'); 112 | $convertExt = $request->get('format'); 113 | $imageExtensions = ['png', 'jpg', 'gif', 'jpeg', 'webp']; 114 | 115 | if (!in_array($ext, $imageExtensions)) { 116 | return ['success' => false, 'msg' => 'Only image can convert']; 117 | } 118 | 119 | if (!in_array($convertExt, $imageExtensions)) { 120 | return ['success' => false, 'msg' => "Only image are convertable"]; 121 | } 122 | 123 | if ($ext == $convertExt) { 124 | return ['success' => false, 'msg' => "Image already in $convertExt format"]; 125 | } 126 | 127 | //end validation 128 | 129 | $fromFile = $this->basePath . '/' . $name; 130 | $newName = basename($name, "." . $ext) . ".$convertExt"; 131 | $newFile = $this->basePath . '/' . $newName; 132 | 133 | 134 | try { 135 | //recreate and delete old 136 | (new SimpleImage())->fromFile($fromFile) 137 | ->toFile($newFile, "image/$convertExt"); 138 | 139 | File::delete($fromFile); 140 | 141 | //delete thumb and recreate new thumb 142 | File::delete($this->basePath . '/thumbs/' . $name); 143 | $this->makeThumb($newFile); 144 | 145 | $fileSizeInByte = File::size($newFile); 146 | $data = Filemanager::find($id); 147 | 148 | $data->update([ 149 | 'name' => $newName, 150 | 'file_size' => $fileSizeInByte, 151 | 'ext' => $convertExt, 152 | 'absolute_url' => $this->getAbsoluteUrl($newName) 153 | ]); 154 | 155 | return ['success' => true, 'msg' => 'Convert success', 'data' => $data]; 156 | } catch (\Exception $e) { 157 | return ['success' => false, 'msg' => $e->getMessage()]; 158 | } 159 | } 160 | 161 | private function postUpdateName(Request $request) 162 | { 163 | $id = $request->get('id'); 164 | $name = $request->get('name'); 165 | $ext = $request->get('ext'); 166 | $finalName = $name . '.' . $ext; 167 | 168 | $oldData = Filemanager::findOrFail($id); 169 | if ($oldData->name == $finalName) { 170 | return ['success' => true, 'msg' => 'filename not changed']; 171 | }; 172 | 173 | $data = Filemanager::whereNotIn('id', [$id])->where('name', $finalName)->count(); 174 | if ($data) { 175 | return ['success' => false, 'msg' => 'Filename already exist']; 176 | } 177 | 178 | try { 179 | DB::beginTransaction(); 180 | 181 | $fromName = $this->basePath . '/' . $oldData->name; 182 | $toName = $this->basePath . '/' . $finalName; 183 | 184 | File::move($fromName, $toName); 185 | 186 | $imageExtensions = ['png', 'jpg', 'gif', 'jpeg', 'webp']; 187 | if (in_array($oldData->ext, $imageExtensions)) { 188 | $fromThumb = $this->basePath . '/thumbs/' . $oldData->name; 189 | $toThumb = $this->basePath . '/thumbs/' . $finalName; 190 | File::move($fromThumb, $toThumb); 191 | } 192 | 193 | 194 | $oldData->update([ 195 | 'name' => $finalName, 196 | 'absolute_url' => $this->getAbsoluteUrl($finalName) 197 | ]); 198 | DB::commit(); 199 | return [ 200 | 'success' => true, 'msg' => 'successfully updated', 201 | 'data' => $oldData 202 | ]; 203 | } catch (\Exception $e) { 204 | DB::rollBack(); 205 | return ['success' => false, 'msg' => $e->getMessage()]; 206 | } 207 | 208 | 209 | } 210 | 211 | public function makeThumb($sourcePath) 212 | { 213 | $filename = basename($sourcePath); 214 | $pathToSave = $this->basePath . '/thumbs'; 215 | 216 | if (!file_exists($pathToSave)) { 217 | mkdir($pathToSave, 0777, true); 218 | } 219 | 220 | $savePathWithName = $pathToSave . '/' . $filename; 221 | 222 | (new SimpleImage())->fromFile($sourcePath) 223 | ->resize(40, 40) 224 | ->toFile($savePathWithName); 225 | 226 | 227 | } 228 | 229 | private function handleRollback(\Exception $e, $fileName) 230 | { 231 | Log::error($e->getMessage()); 232 | DB::rollBack(); 233 | $this->deleteFile($fileName); 234 | return ['success' => false, 'msg' => $e->getMessage()]; 235 | } 236 | 237 | public function postUpload(Request $request) 238 | { 239 | 240 | $allowTypes = str_replace(' ', '', config('filemanager.allow_format')); 241 | $validator = Validator::make($request->all(), [ 242 | 'photo.*' => ['required', 'mimes:' . $allowTypes, 'max:' . config('filemanager.max_size')], 243 | ], [], ['photo' => 'file']); 244 | 245 | if ($validator->fails()) { 246 | $msg = $validator->errors()->first(); 247 | return response() 248 | ->json([ 249 | 'success' => false, 250 | 'msg' => $msg 251 | ], 500); 252 | } 253 | 254 | if (!$request->hasFile('photo')) { 255 | return response()->json(['success' => false, 'msg' => 'No file selected'], 500); 256 | } 257 | 258 | $defaultWidth = config('filemanager.max_image_width', 1024); 259 | if (!is_numeric($defaultWidth)) throw new \Exception('max image width value must be integer value'); 260 | 261 | $imageQuality = config('filemanager.image_quality', 100); 262 | if (!is_numeric($imageQuality)) throw new \Exception('image quality value must be integer value'); 263 | 264 | 265 | $photo = $request->file('photo'); 266 | $fileName = $photo->getClientOriginalName(); 267 | $filePath = $this->basePath . '/' . $fileName; 268 | $pathInfo = pathinfo($fileName); 269 | $extension = $photo->getClientOriginalExtension(); 270 | $fileSizeInByte = $photo->getSize(); 271 | $dateTime = date('Y-m-d H:i:s'); 272 | $imageExtensions = ['png', 'jpg', 'gif', 'jpeg', 'webp']; 273 | $extra = []; 274 | DB::beginTransaction(); 275 | 276 | if (!file_exists($this->basePath)) { 277 | mkdir($this->basePath, 0777, true); 278 | } 279 | 280 | try { 281 | //duplicate check and rename if exist 282 | if (File::exists($filePath)) { 283 | $ext = isset($pathInfo['extension']) ? ('.' . $pathInfo['extension']) : ''; 284 | // Look for a number before the extension; add one if there isn't already 285 | if (preg_match('/(.*?)(\d+)$/', $pathInfo['filename'], $match)) { 286 | // Have a number; get it 287 | $base = $match[1]; 288 | $number = intVal($match[2]); 289 | } else { 290 | // No number; pretend we found a zero 291 | $base = $pathInfo['filename']; 292 | $number = 0; 293 | } 294 | 295 | // Choose a name with an incremented number until a file with that name 296 | // doesn't exist 297 | do { 298 | $fileName = $base . ++$number . $ext; 299 | } while (File::exists($this->basePath . '/' . $fileName)); 300 | } 301 | } catch (\Exception $e) { 302 | $this->handleRollback($e, $fileName); 303 | } 304 | 305 | if (in_array($extension, $imageExtensions)) { 306 | try { 307 | $savePathWithName = $this->basePath . '/' . $fileName; 308 | 309 | (new SimpleImage())->fromFile($photo) 310 | ->resize($defaultWidth) 311 | ->toFile($savePathWithName, null, $imageQuality); 312 | 313 | $fileSizeInByte = File::size($savePathWithName); 314 | 315 | list($width, $height) = getimagesize($savePathWithName); 316 | $extra['width'] = $width; 317 | $extra['height'] = $height; 318 | 319 | 320 | } catch (\Exception $e) { 321 | return $this->handleRollback($e, $fileName); 322 | } 323 | 324 | } else { 325 | $photo->move($this->basePath, $fileName); 326 | } 327 | 328 | 329 | try { 330 | $data = [ 331 | 'name' => $fileName, 332 | 'ext' => $extension, 333 | 'file_size' => $fileSizeInByte, 334 | 'user_id' => Auth()->user()->id, 335 | 'absolute_url' => $this->getAbsoluteUrl($fileName), 336 | 'created_at' => $dateTime, 337 | 'updated_at' => $dateTime, 338 | 'extra' => json_encode($extra) 339 | ]; 340 | $insertId = DB::table($this->tableName)->insertGetId($data); 341 | } catch (\Exception $e) { 342 | return $this->handleRollback($e, $fileName); 343 | } 344 | 345 | //make thumbnail image 346 | try { 347 | $finalFilePath = $this->basePath . '/' . $fileName; 348 | if (in_array($extension, $imageExtensions)) { 349 | $this->makeThumb($finalFilePath); 350 | } 351 | } catch (\Exception $e) { 352 | return $this->handleRollback($e, $fileName); 353 | } 354 | //make thumbnail image 355 | 356 | DB::commit(); 357 | $data = Filemanager::find($insertId); 358 | return [ 359 | 'success' => true, 360 | 'data' => $data, 361 | 'msg' => 'Upload successful' 362 | ]; 363 | 364 | } 365 | 366 | public function deleteFile($fileName) 367 | { 368 | try { 369 | //delete main file 370 | File::delete($this->basePath . '/' . $fileName); 371 | //delete thumb 372 | File::delete($this->basePath . '/thumbs/' . $fileName); 373 | 374 | return true; 375 | } catch (\Exception $e) { 376 | return false; 377 | } 378 | } 379 | 380 | public function postDelete(Request $request) 381 | { 382 | $id = $request->input('id'); 383 | $userId = Auth()->user()->id; 384 | 385 | $data = DB::table($this->tableName) 386 | ->where('id', $id) 387 | ->where('user_id', $userId) 388 | ->first(); 389 | 390 | $query = DB::table($this->tableName) 391 | ->where('id', $id) 392 | ->where('user_id', $userId); 393 | 394 | if ($query->count()) { 395 | if (File::exists($this->basePath . '/' . $data->name)) { 396 | try { 397 | $this->deleteFile($data->name); 398 | //delete records from db 399 | $query->delete(); 400 | } catch (\Exception $e) { 401 | } 402 | } else { 403 | $query->delete(); 404 | } 405 | return ['success' => true, 'msg' => 'Delete successfully']; 406 | } 407 | } 408 | 409 | } -------------------------------------------------------------------------------- /src/Model/Filemanager.php: -------------------------------------------------------------------------------- 1 | 'json']; 10 | protected $fillable = ['name', 'ext', 'file_size', 'absolute_url', 'extra']; 11 | 12 | public function getCreatedAtAttribute($value) 13 | { 14 | return Carbon::parse($value)->diffForHumans(); 15 | } 16 | 17 | public function getUpdatedAtAttribute($value) 18 | { 19 | return Carbon::parse($value)->diffForHumans(); 20 | } 21 | } -------------------------------------------------------------------------------- /src/ServiceProvider.php: -------------------------------------------------------------------------------- 1 | publishes([ 21 | self::CONFIG_PATH => config_path() 22 | ], 'config'); 23 | 24 | $this->publishes([ 25 | self::MIGRATION_PATH => database_path('migrations') 26 | ], 'migrations'); 27 | 28 | $this->publishes([ 29 | self::ASSET_PATH => public_path('filemanager') 30 | ], 'assets'); 31 | } 32 | 33 | public function boot() 34 | { 35 | 36 | $this->publish(); 37 | $this->loadRoutesFrom(self::ROUTE_PATH . '/web.php'); 38 | $this->loadViewsFrom(self::VIEW_PATH, 'filemanager'); 39 | $this->loadTranslationsFrom(self::TRANSLATION_PATH,'filemanager'); 40 | 41 | Blade::directive('FilemanagerScript', function ($expression) { 42 | $output= ""; 43 | $output .= ""; 44 | return $output; 45 | }); 46 | } 47 | 48 | public function register() 49 | { 50 | $this->mergeConfigFrom( 51 | self::CONFIG_PATH . '/filemanager.php', 52 | 'filemanager' 53 | ); 54 | 55 | $this->commands([FilemanagerInstall::class]); 56 | } 57 | } -------------------------------------------------------------------------------- /src/helpers.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{trans('filemanager::filemanager.title')}} 9 | 10 | 20 | 21 | 24 | 25 | 26 | 27 |
28 |

{{trans('filemanager::filemanager.title')}}

30 | 31 |
32 | 36 | 37 | 47 | {{trans('filemanager::filemanager.doc')}} 49 |
50 |
51 | 52 |
53 |
54 |
55 | 56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | 64 | 65 |
66 | 106 |
107 | 154 | 168 |
169 | 170 | 171 | @include('filemanager::partials.mobile') 172 | 173 | 174 | 175 | @include('filemanager::partials.popup') 176 | 177 |
178 | 179 | 180 | 181 | 683 | 684 | 685 | -------------------------------------------------------------------------------- /src/views/partials/action.blade.php: -------------------------------------------------------------------------------- 1 | 7 | 8 | 14 | 15 | 18 | 19 | 24 | 25 | 29 | 30 | 32 | -------------------------------------------------------------------------------- /src/views/partials/mobile.blade.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
{{trans('filemanager::filemanager.preview')}}
5 |
6 | 7 |
8 |
9 | 10 |
11 | @{{ preview.name }} 12 |
13 |
14 | @include('filemanager::partials.preview') 15 |
16 |
17 |
18 | 19 |
20 |
21 | 22 |
23 | 24 |

{{trans('filemanager::filemanager.upload')}}

25 | 26 | 27 |
29 |
30 |
31 |
-------------------------------------------------------------------------------- /src/views/partials/popup.blade.php: -------------------------------------------------------------------------------- 1 | 20 | 21 | -------------------------------------------------------------------------------- /src/views/partials/preview.blade.php: -------------------------------------------------------------------------------- 1 |

@{{ preview.name }}

2 | 3 |

4 | {{trans('filemanager::filemanager.size')}}: @{{ formatBytes(preview.file_size) }}
5 | {{trans('filemanager::filemanager.type')}}: @{{ preview.ext }}
6 | {{trans('filemanager::filemanager.dimension')}}: @{{ preview.extra.width+'x'+preview.extra.height}}
7 | {{trans('filemanager::filemanager.created')}}: @{{ preview.created_at }}
8 | {{trans('filemanager::filemanager.modified')}}: @{{ preview.updated_at }}
9 |

-------------------------------------------------------------------------------- /translations/ar/filemanager.php: -------------------------------------------------------------------------------- 1 | 'مدير الملفات', 4 | 'upload' => 'رفع', 5 | 'upload-message' => 'أفلت الملفات هنا للتحميل', 6 | 'success-upload' => 'تم الرفع بنجاح!', 7 | 'search' => 'بحث', 8 | 'doc' => 'الوثيقة', 9 | 'bulk-delete' => 'حذف مجمّع', 10 | 'preview' => 'معاينة', 11 | 'name' => 'اسم', 12 | 'size' => 'بحجم', 13 | 'type' => 'نوع', 14 | 'modified' => 'تم التعديل', 15 | 'created' => 'خلقت', 16 | 'dimension' => 'البعد', 17 | 'action' => 'عمل', 18 | 'bulk-select' => 'تحديد مجمع', 19 | 'showing-files' => 'Showing :current of :total files', 20 | 'edit' => 'تعديل', 21 | 'update' => 'تحديث', 22 | 'convert' => 'تحويل', 23 | 'format' => 'شكل', 24 | 'choose_format' => 'اختر تنسيق', 25 | ]; 26 | -------------------------------------------------------------------------------- /translations/bn/filemanager.php: -------------------------------------------------------------------------------- 1 | 'ফাইলম্যানেজার', 4 | 'upload' => 'আপলোড', 5 | 'upload-message' => 'আপলোড করতে ফাইল এখানে ড্রপ করুন', 6 | 'success-upload' => 'সফলভাবে আপলোড হয়েছে!', 7 | 'search' => 'ফাইল খুজুন', 8 | 'doc' => 'ডকুমেন্টেশন', 9 | 'bulk-delete' => 'একসাথে মুছুন', 10 | 'preview' => 'প্রিভিউ', 11 | 'name' => 'নাম', 12 | 'size' => 'সাইজ', 13 | 'type' => 'টাইপ', 14 | 'modified' => 'মডিফাইড', 15 | 'created' => 'তৈরী হয়েছে', 16 | 'dimension' => 'মাপ', 17 | 'action' => 'অপশন', 18 | 'bulk-select' => 'একসাথে সিলেক্ট', 19 | 'showing-files' => ':total টির মধ্যে :current টি ফাইল দেখানো হচ্ছে', 20 | 'edit' => 'ইডিট', 21 | 'update' => 'আপডেট', 22 | 'convert' => 'কনভার্ট', 23 | 'format' => 'ফরম্যাট', 24 | 'choose_format' => 'ফরম্যাট নির্বাচন', 25 | ]; 26 | -------------------------------------------------------------------------------- /translations/de/filemanager.php: -------------------------------------------------------------------------------- 1 | 'Filemanager', 4 | 'upload' => 'Upload', 5 | 'upload-message' => 'Dateien hier zum Hochladen ablegen', 6 | 'success-upload' => 'Erfolgreich hochgeladen!', 7 | 'search' => 'Search', 8 | 'doc' => 'Doc', 9 | 'bulk-delete' => 'Bulk Del', 10 | 'preview' => 'Vorschau', 11 | 'name' => 'Name', 12 | 'size' => 'Größe', 13 | 'type' => 'Typ', 14 | 'modified' => 'Modifiziert', 15 | 'created' => 'erstellt', 16 | 'dimension' => 'Dimension', 17 | 'action' => 'Aktion', 18 | 'bulk-select' => 'Bulk Select', 19 | 'showing-files' => 'Zeige :current von :total der Dateien', 20 | 'edit' => 'Edit', 21 | 'update' => 'Update', 22 | 'convert' => 'Convert', 23 | 'format' => 'Format', 24 | 'choose_format' => 'Choose Format', 25 | ]; 26 | -------------------------------------------------------------------------------- /translations/en/filemanager.php: -------------------------------------------------------------------------------- 1 | 'Filemanager', 4 | 'upload' => 'Upload', 5 | 'upload-message' => 'Drop files here to upload', 6 | 'success-upload' => 'Successfully uploaded!', 7 | 'search' => 'Search', 8 | 'doc' => 'Doc', 9 | 'bulk-delete' => 'Bulk Del', 10 | 'preview' => 'Preview', 11 | 'name' => 'Name', 12 | 'size' => 'Size', 13 | 'type' => 'Type', 14 | 'modified' => 'Modified', 15 | 'created' => 'Created', 16 | 'dimension' => 'Dimension', 17 | 'action' => 'Action', 18 | 'bulk-select' => 'Bulk Select', 19 | 'showing-files' => 'Showing :current of :total files', 20 | 'edit' => 'Edit', 21 | 'update' => 'Update', 22 | 'convert' => 'Convert', 23 | 'format' => 'Format', 24 | 'choose_format' => 'Choose Format', 25 | ]; 26 | -------------------------------------------------------------------------------- /translations/hi/filemanager.php: -------------------------------------------------------------------------------- 1 | 'फ़ाइल प्रबंधक', 4 | 'upload' => 'डालना', 5 | 'upload-message' => 'अपलोड करने के लिए फ़ाइलें यहाँ डालें', 6 | 'success-upload' => 'सफलतापूर्वक अपलोड किया गया!', 7 | 'search' => 'खोज', 8 | 'doc' => 'डॉक्टर', 9 | 'bulk-delete' => 'थोक डेल', 10 | 'preview' => 'पूर्वावलोकन', 11 | 'name' => 'नाम', 12 | 'size' => 'आकार', 13 | 'type' => 'प्रकार', 14 | 'modified' => 'संशोधित', 15 | 'created' => 'बनाया था', 16 | 'dimension' => 'आयाम', 17 | 'action' => 'कार्य', 18 | 'bulk-select' => 'थोक का चयन करें', 19 | 'showing-files' => 'दिखाना :current की :total फाइलें', 20 | 'edit' => 'संपादित करें', 21 | 'update' => 'अपडेट करें', 22 | 'convert' => 'धर्मांतरित', 23 | 'format' => 'स्वरूप', 24 | 'choose_format' => 'प्रारूप चुनें', 25 | ]; 26 | -------------------------------------------------------------------------------- /translations/id/filemanager.php: -------------------------------------------------------------------------------- 1 | 'Manajer Berkas', 4 | 'upload' => 'Unggah', 5 | 'upload-message' => 'Letakkan file di sini untuk mengunggah', 6 | 'success-upload' => 'Berhasil mengunggah!', 7 | 'search' => 'Cari', 8 | 'doc' => 'Dokumentasi', 9 | 'bulk-delete' => 'Hapus Masal', 10 | 'preview' => 'Pratinjau', 11 | 'name' => 'Nama', 12 | 'size' => 'Ukuran', 13 | 'type' => 'Tipe', 14 | 'modified' => 'Diubah', 15 | 'created' => 'Dibuat', 16 | 'dimension' => 'Dimensi', 17 | 'action' => 'Tindakan', 18 | 'bulk-select' => 'Pilih Masal', 19 | 'showing-files' => 'Menampilkan :current dari :total berkas', 20 | 'edit' => 'Ubah', 21 | 'update' => 'Perbaharui', 22 | 'convert' => 'Konversi', 23 | 'format' => 'Format', 24 | 'choose_format' => 'Pilih Format', 25 | ]; 26 | -------------------------------------------------------------------------------- /translations/ja/filemanager.php: -------------------------------------------------------------------------------- 1 | 'ファイルマネージャー', 4 | 'upload' => 'アップロードする', 5 | 'upload-message' => 'ここにファイルをドロップしてアップロード', 6 | 'success-upload' => '正常にアップロードされました!', 7 | 'search' => '探す', 8 | 'doc' => 'ドク', 9 | 'bulk-delete' => '一括削除', 10 | 'preview' => 'プレビュー', 11 | 'name' => '名前', 12 | 'size' => 'サイズ', 13 | 'type' => 'タイプ', 14 | 'modified' => '修正', 15 | 'created' => '作成した', 16 | 'dimension' => '寸法', 17 | 'action' => 'アクション', 18 | 'bulk-select' => '一括選択', 19 | 'showing-files' => 'Showing :current of :total files', 20 | 'edit' => '編集する', 21 | 'update' => '更新', 22 | 'convert' => '変換', 23 | 'format' => 'フォーマット', 24 | 'choose_format' => 'フォーマットを選択', 25 | ]; 26 | -------------------------------------------------------------------------------- /translations/ur/filemanager.php: -------------------------------------------------------------------------------- 1 | 'فائل مینجر', 4 | 'upload' => 'اپ لوڈ کریں', 5 | 'upload-message' => 'فائلیں یہاں اپ لوڈ کرنے کے لئے گرا دیں', 6 | 'success-upload' => 'کامیابی کے ساتھ اپ لوڈ ہو گیا!', 7 | 'search' => 'تلاش کریں', 8 | 'doc' => 'ڈاکٹر', 9 | 'bulk-delete' => 'بلک ڈیلیٹ', 10 | 'preview' => 'پیش نظارہ', 11 | 'name' => 'نام', 12 | 'size' => 'سائز', 13 | 'type' => 'ٹائپ کریں', 14 | 'modified' => 'ترمیم شدہ', 15 | 'created' => 'بنائی گئی', 16 | 'dimension' => 'طول و عرض', 17 | 'action' => 'عمل', 18 | 'bulk-select' => 'بلک منتخب کریں', 19 | 'showing-files' => 'Showing :current of :total files', 20 | 'edit' => 'ترمیم', 21 | 'update' => 'اپ ڈیٹ', 22 | 'convert' => 'تبدیل کریں', 23 | 'format' => 'فارمیٹ', 24 | 'choose_format' => 'شکل منتخب کریں', 25 | ]; 26 | --------------------------------------------------------------------------------