🚧 Album

This commit is contained in:
MarceauKa 2019-11-05 14:09:08 +01:00
parent e5ee9bece5
commit efa4952dd4
15 changed files with 165 additions and 43 deletions

1
.gitignore vendored
View File

@ -4,6 +4,7 @@
/storage/*.json
/storage/*.key
/storage/*.index
/storage/medialibrary
/vendor
.env
.phpunit.result.cache

View File

@ -40,7 +40,7 @@ class AlbumController extends Controller
$post->save();
$this->processImages($data->get('images'), $album);
$this->processUploadedImages($data->get('uploaded'), $album);
return response()->json([
'post' => new PostResource($post),
@ -67,7 +67,8 @@ class AlbumController extends Controller
$album->save();
$album->post->save();
$this->processImages($data->get('images'), $album);
$this->processExistingImages($data->get('images'), $album);
$this->processUploadedImages($data->get('uploaded'), $album);
return response()->json([
'post' => new PostResource($album->post),
@ -75,12 +76,6 @@ class AlbumController extends Controller
]);
}
public function upload(StoreAlbumUploadRequest $request)
{
$file = $request->file('filepond');
return Storage::put('tmp', $file);
}
public function delete(Request $request, int $id)
{
/** @var Album $album */
@ -95,11 +90,19 @@ class AlbumController extends Controller
]);
}
public function processImages(array $images, Album $model): void
public function upload(StoreAlbumUploadRequest $request)
{
$images = collect($images)->reject(function ($item) {
return substr($item, 0, 4) !== 'tmp/';
});
$file = $request->file('filepond');
return Storage::put('tmp', $file);
}
public function processUploadedImages(array $images, Album $model): void
{
$images = collect($images)
->reject(function ($item) {
return substr($item, 0, 4) !== 'tmp/';
});
$images->each(function ($item) use ($model) {
$model->addMedia(Storage::path($item))
@ -108,4 +111,27 @@ class AlbumController extends Controller
Storage::delete($item);
});
}
public function processExistingImages(array $images, Album $model): void
{
$images = collect($images);
$medias = $model->getMedia('images');
foreach ($medias as $media) {
$image = $images->firstWhere('name', $media->name);
if (! $image) {
$media->delete();
}
}
foreach ($images as $image) {
$media = $medias->firstWhere('name', $image['name']);
if ($media) {
$media->order_column = $image['order'];
$media->save();
}
}
}
}

View File

@ -29,12 +29,21 @@ class StoreAlbumRequest extends FormRequest
'is_pinned' => [
'nullable',
],
'uploaded' => [
'nullable',
'array',
],
'uploaded.*' => [
'temp_image',
],
'images' => [
'nullable',
'array',
],
'images.*' => [
'temp_image',
'images.*.order' => [
'numeric',
'min:0',
'max:9999'
],
'tags' => [
'nullable',

View File

@ -7,14 +7,13 @@ use Illuminate\Support\Facades\Auth;
class AlbumResource extends JsonResource
{
/** @todo MediaResource */
public function toArray($request)
{
return [
'title' => $this->title,
'content' => $this->content,
'permalink' => $this->permalink,
'images' => [],
'images' => $this->getAlbumImages(),
'is_private' => $this->post->is_private,
'is_pinned' => $this->post->is_pinned,
'date_formated' => $this->created_at->diffForHumans(),
@ -29,4 +28,21 @@ class AlbumResource extends JsonResource
]),
];
}
protected function getAlbumImages(): array
{
return $this
->getMedia('images')
->transform(function ($item) {
return [
'name' => $item->name,
'size' => $item->human_readable_size,
'mime' => $item->mime_type,
'order' => $item->order_column,
'url_full' => $item->getFullUrl(),
'url_thumb' => $item->hasGeneratedConversion('thumb') ? $item->getFullUrl('thumb') : null,
];
})
->toArray();
}
}

View File

@ -11,6 +11,10 @@
- No more URL hash for Archive downloading
## Fixed
- PasswordGenerator border radius
# 1.2.25
## Added

View File

@ -18,8 +18,9 @@ return [
'albums' => [
'driver' => 'local',
'root' => storage_path('app/albums'),
'visibility' => 'private',
'root' => storage_path('app/public/albums'),
'url' => env('APP_URL').'/storage/albums',
'visibility' => 'public',
],
'public' => [

View File

@ -2,7 +2,7 @@
return [
'disk_name' => env('MEDIA_DISK', 'public'),
'max_file_size' => 1024 * 1024 * 10,
'max_file_size' => 1024 * 1024 * 30,
'queue_name' => '',
'media_model' => Spatie\MediaLibrary\Models\Media::class,
's3' => [

2
public/css/app.css vendored
View File

@ -20,4 +20,4 @@ fieldset[disabled] .multiselect{pointer-events:none}.multiselect__spinner{positi
/*!
* Font Awesome Free 5.11.2 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
*/@font-face{font-family:Font Awesome\ 5 Free;font-style:normal;font-weight:900;font-display:auto;src:url(/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.eot?8e4a6dcc692b3887f9f542cd6894d6d4);src:url(/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.eot?8e4a6dcc692b3887f9f542cd6894d6d4) format("embedded-opentype"),url(/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.woff2?44d537ab79f921fde5a28b2c1636f397) format("woff2"),url(/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.woff?333bae208dc363746961b234ff6c2500) format("woff"),url(/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.ttf?0bff33a5fd7ec390235476b4859747a0) format("truetype"),url(/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.svg?c2801fb415f03c7b170934769d7b5397) format("svg")}.fa,.fas{font-family:Font Awesome\ 5 Free;font-weight:900}.multiselect__tags{border-color:#ced4da;border-radius:1rem}.multiselect__tags .multiselect__tag{margin-bottom:0}.chest-lines .flip-list-move{transition:transform .5s}.chest-lines .no-move{transition:transform 0s}.chest-lines .ghost{opacity:.5;background:#c8ebfb}body.dark{background-image:linear-gradient(0deg,#505285 0,#b5aee4)}body.dark .pagination .page-link{border:none;box-shadow:0 10px 20px rgba(0,0,0,.1)}body,html{min-height:100%;height:100%}body{background-image:linear-gradient(0deg,#dad4ec 0,#f3e7e9);background-repeat:no-repeat;background-size:cover;background-attachment:fixed}nav.navbar{background-color:hsla(0,0%,100%,.9)}.list-group,nav.navbar{box-shadow:0 10px 20px rgba(0,0,0,.1)}.list-group{background-color:transparent;border-radius:1rem;border-color:transparent}.list-group .list-group-item{border:none}.dropdown-menu{box-shadow:0 10px 20px rgba(0,0,0,.1);z-index:1600}#app{display:flex;flex-direction:column;justify-content:space-between;min-height:100%}#app>nav.navbar{padding:1.5rem 1rem}#app>nav.navbar .navbar-brand{display:flex;flex-flow:row nowrap}#app>nav.navbar .navbar-brand img{max-height:30px;width:auto;margin-right:10px}#app>nav.navbar .navbar-brand .fa-stack{height:1em;width:1em;line-height:1em}#app>nav.navbar .navbar-brand .fa-stack .fa-stack-2x{font-size:1em}#app>nav.navbar .navbar-brand .fa-stack .fa-stack-1x{font-size:.5em}#app>nav.navbar #search{width:100%;padding-left:1rem;padding-right:1rem}#app>nav.navbar #search .results{display:none;z-index:500;position:absolute;top:40px;width:calc(100% - 2rem);box-shadow:0 10px 20px rgba(0,0,0,.1)}#app>nav.navbar #search .results.active,#app>nav.navbar #search body.dark .dropdown .dropdown-menu .results.dropdown-item:focus,#app>nav.navbar #search body.dark .dropdown .dropdown-menu .results.dropdown-item:hover,body.dark .dropdown .dropdown-menu #app>nav.navbar #search .results.dropdown-item:focus,body.dark .dropdown .dropdown-menu #app>nav.navbar #search .results.dropdown-item:hover{display:block}#app>nav.navbar #search .results .list-group-item{display:flex;flex-wrap:wrap;justify-content:space-between}#app>nav.navbar #search .results .list-group-item div:first-child>span{text-transform:uppercase}@media (max-width:767.98px){#app>nav.navbar #search{margin-top:10px;padding-left:0;padding-right:0}#app>nav.navbar #search .results{width:100%}}@media (max-width:767.98px){#app>nav.navbar ul.navbar-nav li.dropdown>a{text-align:right}}#app>main{flex-grow:2}#app>footer{width:100%;background-color:hsla(0,0%,100%,.9);padding:1.5rem 1rem}#app>footer,.card{box-shadow:0 10px 20px rgba(0,0,0,.1)}.card .card-header{border-bottom:none}.card .card-footer{border-top:none}.card-columns.column-1{-moz-column-count:1;column-count:1}.card-columns.column-2{-moz-column-count:2;column-count:2}.card-columns.column-3{-moz-column-count:3;column-count:3}.card-columns.column-4{-moz-column-count:4;column-count:4}@media (max-width:767.98px){.card-columns.column-2,.card-columns.column-3,.card-columns.column-4{-moz-column-count:1;column-count:1}}@media (min-width:768px) and (max-width:991.98px){.card-columns.column-3,.card-columns.column-4{-moz-column-count:2;column-count:2}}@media (min-width:992px) and (max-width:1199.98px){.card-columns.column-4{-moz-column-count:3;column-count:3}}.card-columns.compact .card-content,.card-columns.compact .card-preview{display:none}.card-preview .responsive-preview{overflow:hidden;position:relative;padding-bottom:56.25%;padding-top:30px;height:0}.card-preview .responsive-preview iframe{position:absolute;top:0;left:0;width:100%;height:100%}.card--album h5.card-title span,.card--chest h5.card-title span,.card--link h5.card-title span,.card--story h5.card-title span{text-transform:uppercase}
*/@font-face{font-family:Font Awesome\ 5 Free;font-style:normal;font-weight:900;font-display:auto;src:url(/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.eot?8e4a6dcc692b3887f9f542cd6894d6d4);src:url(/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.eot?8e4a6dcc692b3887f9f542cd6894d6d4) format("embedded-opentype"),url(/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.woff2?44d537ab79f921fde5a28b2c1636f397) format("woff2"),url(/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.woff?333bae208dc363746961b234ff6c2500) format("woff"),url(/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.ttf?0bff33a5fd7ec390235476b4859747a0) format("truetype"),url(/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.svg?c2801fb415f03c7b170934769d7b5397) format("svg")}.fa,.fas{font-family:Font Awesome\ 5 Free;font-weight:900}.multiselect__tags{border-color:#ced4da;border-radius:1rem}.multiselect__tags .multiselect__tag{margin-bottom:0}.flip-list-move{transition:transform .5s}.no-move{transition:transform 0s}.ghost{opacity:.5;background:#c8ebfb}body.dark{background-image:linear-gradient(0deg,#505285 0,#b5aee4)}body.dark .pagination .page-link{border:none;box-shadow:0 10px 20px rgba(0,0,0,.1)}body,html{min-height:100%;height:100%}body{background-image:linear-gradient(0deg,#dad4ec 0,#f3e7e9);background-repeat:no-repeat;background-size:cover;background-attachment:fixed}nav.navbar{background-color:hsla(0,0%,100%,.9)}.list-group,nav.navbar{box-shadow:0 10px 20px rgba(0,0,0,.1)}.list-group{background-color:transparent;border-radius:1rem;border-color:transparent}.list-group .list-group-item{border:none}.dropdown-menu{box-shadow:0 10px 20px rgba(0,0,0,.1);z-index:1600}#app{display:flex;flex-direction:column;justify-content:space-between;min-height:100%}#app>nav.navbar{padding:1.5rem 1rem}#app>nav.navbar .navbar-brand{display:flex;flex-flow:row nowrap}#app>nav.navbar .navbar-brand img{max-height:30px;width:auto;margin-right:10px}#app>nav.navbar .navbar-brand .fa-stack{height:1em;width:1em;line-height:1em}#app>nav.navbar .navbar-brand .fa-stack .fa-stack-2x{font-size:1em}#app>nav.navbar .navbar-brand .fa-stack .fa-stack-1x{font-size:.5em}#app>nav.navbar #search{width:100%;padding-left:1rem;padding-right:1rem}#app>nav.navbar #search .results{display:none;z-index:500;position:absolute;top:40px;width:calc(100% - 2rem);box-shadow:0 10px 20px rgba(0,0,0,.1)}#app>nav.navbar #search .results.active,#app>nav.navbar #search body.dark .dropdown .dropdown-menu .results.dropdown-item:focus,#app>nav.navbar #search body.dark .dropdown .dropdown-menu .results.dropdown-item:hover,body.dark .dropdown .dropdown-menu #app>nav.navbar #search .results.dropdown-item:focus,body.dark .dropdown .dropdown-menu #app>nav.navbar #search .results.dropdown-item:hover{display:block}#app>nav.navbar #search .results .list-group-item{display:flex;flex-wrap:wrap;justify-content:space-between}#app>nav.navbar #search .results .list-group-item div:first-child>span{text-transform:uppercase}@media (max-width:767.98px){#app>nav.navbar #search{margin-top:10px;padding-left:0;padding-right:0}#app>nav.navbar #search .results{width:100%}}@media (max-width:767.98px){#app>nav.navbar ul.navbar-nav li.dropdown>a{text-align:right}}#app>main{flex-grow:2}#app>footer{width:100%;background-color:hsla(0,0%,100%,.9);padding:1.5rem 1rem}#app>footer,.card{box-shadow:0 10px 20px rgba(0,0,0,.1)}.card .card-header{border-bottom:none}.card .card-footer{border-top:none}.card-columns.column-1{-moz-column-count:1;column-count:1}.card-columns.column-2{-moz-column-count:2;column-count:2}.card-columns.column-3{-moz-column-count:3;column-count:3}.card-columns.column-4{-moz-column-count:4;column-count:4}@media (max-width:767.98px){.card-columns.column-2,.card-columns.column-3,.card-columns.column-4{-moz-column-count:1;column-count:1}}@media (min-width:768px) and (max-width:991.98px){.card-columns.column-3,.card-columns.column-4{-moz-column-count:2;column-count:2}}@media (min-width:992px) and (max-width:1199.98px){.card-columns.column-4{-moz-column-count:3;column-count:3}}.card-columns.compact .card-content,.card-columns.compact .card-preview{display:none}.card-preview .responsive-preview{overflow:hidden;position:relative;padding-bottom:56.25%;padding-top:30px;height:0}.card-preview .responsive-preview iframe{position:absolute;top:0;left:0;width:100%;height:100%}.card--album h5.card-title span,.card--chest h5.card-title span,.card--link h5.card-title span,.card--story h5.card-title span{text-transform:uppercase}

2
public/js/app.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{
"/js/app.js": "/js/app.js?id=2ca905405fbbc0cf3020",
"/css/app.css": "/css/app.css?id=855d6b1636f80eceaaa9",
"/js/app.js": "/js/app.js?id=3a11495c0d3469afe37e",
"/css/app.css": "/css/app.css?id=96bbbe1b452be7b4a33a",
"/js/manifest.js": "/js/manifest.js?id=3c768977c2574a34506e",
"/js/vendor.js": "/js/vendor.js?id=24c264fe7e2a39bcb572"
}

View File

@ -27,11 +27,38 @@
@init="initUpload"
@processfile="handleFileProcess"
ref="pond"
v-if="album"
/>
<div class="alert alert-info" v-else>
{{ __('Create your album to add images') }}
<div v-if="form.images">
<draggable v-model="form.images"
group="images"
v-bind="dragOptions"
@start="startDragging"
@end="endDragging"
handle=".handle-order"
>
<transition-group
type="transition"
tag="div"
:name="!drag ? 'flip-list' : null"
>
<figure v-for="image in form.images" class="figure mr-2" :key="`item-${image.name}`">
<img :src="image.url_thumb || image.url_full"
class="figure-img img-fluid rounded"
style="height: 100px;"
/>
<figcaption class="figure-caption d-flex justify-content-center">
<button type="button" class="btn btn-sm btn-outline-secondary handle-order mr-1"><i class="fas fa-arrows-alt"></i></button>
<confirm tag="button"
class="btn btn-sm btn-outline-secondary"
@confirmed="deleteImage(image)"
text="<i class='fas fa-trash-alt'></i>"
text-confirm="<i class='fas fa-check'></i>"
></confirm>
</figcaption>
</figure>
</transition-group>
</draggable>
</div>
</div>
@ -82,6 +109,7 @@ let defaultAlbum = function () {
title: null,
content: null,
images: [],
uploaded: [],
is_private: false,
is_pinned: false,
tags: []
@ -114,12 +142,21 @@ export default {
return {
form: defaultAlbum(),
loading: false,
drag: false,
dragOptions: {
animation: 200,
group: "images",
disabled: false,
ghostClass: "ghost",
forceFallback: true
},
}
},
mounted() {
if (this.album) {
this.form = this.album;
this.form.uploaded = [];
}
},
@ -132,6 +169,7 @@ export default {
url: this.album ? this.album.url_update : '/api/album',
data: this.form
}).then(response => {
this.loading = false;
window.location = `/album/${response.data.post.postable_id}/edit`
}).catch(error => {
this.loading = false;
@ -157,7 +195,33 @@ export default {
handleFileProcess(error, file) {
if (error === null) {
this.form.images.push(file.serverId);
this.form.uploaded.push(file.serverId);
}
},
deleteImage(item) {
let index = this.form.images.indexOf(item);
if (index !== -1) {
this.form.images.splice(index, 1);
this.updateImagesOrder();
}
},
startDragging() {
this.drag = true;
},
endDragging(item) {
this.drag = false;
this.updateImagesOrder();
},
updateImagesOrder() {
let total = this.form.images.length - 1;
for (let i = 0; i <= total; i++) {
this.form.images[i].order = i + 1;
}
}
},

View File

@ -4,8 +4,8 @@
<draggable v-model="lines"
group="lines"
v-bind="dragOptions"
@start="drag=true"
@end="drag=false"
@start="drag = true"
@end="drag = false"
handle=".handle-order"
>
<transition-group

View File

@ -1,6 +1,10 @@
<template>
<div class="btn-group" role="group">
<button type="button" class="btn btn-outline-secondary border-right-0 dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<button type="button" class="btn btn-outline-secondary border-right-0 dropdown-toggle"
style="border-radius: 0"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false">
<i class="fas fa-dice pr-1"></i>
</button>

View File

@ -7,15 +7,13 @@
}
}
.chest-lines {
.flip-list-move {
transition: transform 0.5s;
}
.no-move {
transition: transform 0s;
}
.ghost {
opacity: 0.5;
background: #c8ebfb;
}
.flip-list-move {
transition: transform 0.5s;
}
.no-move {
transition: transform 0s;
}
.ghost {
opacity: 0.5;
background: #c8ebfb;
}

View File

@ -1,6 +1,5 @@
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::post('search', 'SearchController@search')->name('search');
@ -27,7 +26,7 @@ Route::put('chest/{id}', 'ChestController@update')->name('chest.update');
Route::delete('chest/{id}', 'ChestController@delete')->name('chest.delete');
Route::post('album', 'AlbumController@store')->name('album.store');
Route::post('album/upload', 'AlbumController@upload')->name('album.upload');
Route::post('album/upload', 'AlbumController@uploadImage')->name('album.image.upload');
Route::put('album/{id}', 'AlbumController@update')->name('album.update');
Route::delete('album/{id}', 'AlbumController@delete')->name('album.delete');