diff --git a/.gitignore b/.gitignore index 279cf27..da4d77b 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,4 @@ cert.pem /draft.yaml /.blueprint /.editorconfig +/storage/media-library/* diff --git a/README.md b/README.md index 9064a78..5c52485 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ docker-compose up -d php - [x] Label Manager - [x] Category Manager - [x] Recipe Manager -- [ ] Image uploads +- [x] Image uploads - [ ] Paginate Recipe Manager - [ ] User Management ### Other @@ -102,3 +102,4 @@ docker-compose up -d php - [ ] "I made it" counter - [ ] Reviews/ratings - [x] Roles for access to the recipe manager as a contributor +- [ ] Associate images to labels/categories (?) diff --git a/app/Http/Controllers/Admin/ImageController.php b/app/Http/Controllers/Admin/ImageController.php new file mode 100644 index 0000000..3c58f35 --- /dev/null +++ b/app/Http/Controllers/Admin/ImageController.php @@ -0,0 +1,26 @@ +model->media()->update(['collection_name' => 'default']); + $media->update(['collection_name' => 'hero']); + + return redirect()->back()->withBanner('Image set to hero'); + } + + public function destroy(Media $media) + { + $media->delete(); + + return redirect()->back() + ->withBanner('Image deleted', BannerTypeEnum::danger); + } +} diff --git a/app/Http/Controllers/Admin/RecipeController.php b/app/Http/Controllers/Admin/RecipeController.php index dccf98c..f3c9ab6 100644 --- a/app/Http/Controllers/Admin/RecipeController.php +++ b/app/Http/Controllers/Admin/RecipeController.php @@ -10,6 +10,7 @@ use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Validation\Rule; +use Illuminate\Validation\Rules\File; use Inertia\Inertia; class RecipeController extends Controller @@ -57,7 +58,7 @@ public function store(Request $request): RedirectResponse public function edit(Recipe $recipe) { return Inertia::render('Admin/Recipe/RecipeEdit')->with([ - 'recipe' => fn () => $recipe->makeVisible('id')->loadMissing('labels', 'categories'), + 'recipe' => fn () => $recipe->makeVisible('id')->loadMissing('labels', 'categories', 'media'), 'labels' => fn () => Label::withTrashed() ->orderBy('order_column') ->get() @@ -66,6 +67,7 @@ public function edit(Recipe $recipe) ->orderBy('order_column') ->get() ->makeVisible('id'), + 'images' => fn () => $recipe->loadMissing('media')->media, ]); } @@ -128,4 +130,22 @@ public function restore(Recipe $recipe) return redirect()->route('admin.recipes.index') ->withBanner("Restored {$name}"); } + + public function imageStore(Recipe $recipe, Request $request) + { + $request->validate([ + 'images' => ['array'], + 'images.*' => ['required', File::image()->max(10 * 1024)], + ]); + + foreach ($request->images as $key => $image) { + $recipe->addMediaFromRequest("images.{$key}") + ->setName("{$recipe->name} Image") + ->setFileName(sprintf('%s-%s.%s', $recipe->slug, \Str::random(6), $image->extension())) + ->preservingOriginal() + ->toMediaCollection(); + } + + return response()->noContent(); + } } diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index 9a8623f..e2e2ff1 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -12,7 +12,7 @@ class HomeController extends Controller public function __invoke(Request $request): Response { return Inertia::render('Dashboard')->with([ - 'most_recent_recipes' => Inertia::lazy(fn () => Recipe::with('images', 'labels', 'categories') + 'most_recent_recipes' => Inertia::lazy(fn () => Recipe::with('media', 'labels', 'categories') ->orderBy('id', 'desc') ->limit(3) ->get()), diff --git a/app/Http/Controllers/RecipeController.php b/app/Http/Controllers/RecipeController.php index b0e6316..4da7c3e 100644 --- a/app/Http/Controllers/RecipeController.php +++ b/app/Http/Controllers/RecipeController.php @@ -11,7 +11,7 @@ class RecipeController extends Controller { public function __invoke(Recipe $recipe, Request $request): Response { - $recipe->loadMissing('images', 'labels', 'categories'); + $recipe->loadMissing('labels', 'categories', 'media'); return Inertia::render('Recipe/RecipeShow')->with([ 'recipe' => fn () => $recipe, diff --git a/app/Models/Image.php b/app/Models/Image.php deleted file mode 100644 index 789a767..0000000 --- a/app/Models/Image.php +++ /dev/null @@ -1,37 +0,0 @@ - 'integer', - ]; - - public function recipes(): BelongsToMany - { - return $this->belongsToMany(Recipe::class); - } -} diff --git a/app/Models/Recipe.php b/app/Models/Recipe.php index 1d6505b..c5d86c9 100644 --- a/app/Models/Recipe.php +++ b/app/Models/Recipe.php @@ -2,18 +2,23 @@ namespace App\Models; +use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\SoftDeletes; use Laravel\Scout\Searchable; +use Spatie\Image\Enums\Fit; +use Spatie\MediaLibrary\HasMedia; +use Spatie\MediaLibrary\InteractsWithMedia; +use Spatie\MediaLibrary\MediaCollections\Models\Media; use Spatie\Sluggable\HasSlug; use Spatie\Sluggable\SlugOptions; -class Recipe extends Model +class Recipe extends Model implements HasMedia { - use HasFactory, HasSlug, Searchable, SoftDeletes; + use HasFactory, HasSlug, InteractsWithMedia, Searchable, SoftDeletes; /** * The attributes that are mass assignable. @@ -45,6 +50,8 @@ class Recipe extends Model protected $hidden = ['id']; + protected $appends = ['hero', 'hero_preview']; + public function getRouteKeyName(): string { return 'slug'; @@ -57,6 +64,35 @@ public function getSlugOptions(): SlugOptions ->saveSlugsTo('slug'); } + protected function hero(): Attribute + { + return Attribute::make( + get: fn () => $this->getFirstMedia('hero')?->getUrl() ?? '', + ); + } + + protected function heroPreview(): Attribute + { + return Attribute::make( + get: fn () => $this->getFirstMedia('hero')?->preview_url ?? '', + ); + } + + public function registerMediaConversions(?Media $media = null): void + { + $this + ->addMediaConversion('preview') + ->fit(Fit::Contain, 600, 400) + ->nonQueued(); + } + + public function registerMediaCollections(): void + { + $this + ->addMediaCollection('hero') + ->singleFile(); + } + public function toSearchableArray(): array { return [ @@ -75,11 +111,6 @@ public function user(): BelongsTo return $this->belongsTo(User::class); } - public function images(): BelongsTo - { - return $this->belongsTo(Image::class); - } - public function labels(): BelongsToMany { return $this->belongsToMany(Label::class)->orderBy((new Label)->determineOrderColumnName()); diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 2a61bee..a934a74 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -4,6 +4,7 @@ use App\Enums\BannerTypeEnum; use Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider; +use Illuminate\Database\Eloquent\Model; use Illuminate\Http\RedirectResponse; use Illuminate\Support\ServiceProvider; @@ -14,6 +15,9 @@ class AppServiceProvider extends ServiceProvider */ public function register(): void { + Model::preventLazyLoading(! app()->isProduction()); + Model::preventAccessingMissingAttributes(! app()->isProduction()); + // @codeCoverageIgnoreStart if ($this->app->isLocal()) { $this->app->register(IdeHelperServiceProvider::class); diff --git a/bootstrap/app.php b/bootstrap/app.php index 461aafd..133a7a3 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -15,9 +15,9 @@ $middleware->web(append: [ \App\Http\Middleware\HandleInertiaRequests::class, \Illuminate\Http\Middleware\AddLinkHeadersForPreloadedAssets::class, + ])->validateCsrfTokens(except: [ + 'admin/recipes/*/image', ]); - - // }) ->withExceptions(function (Exceptions $exceptions) { // diff --git a/composer.json b/composer.json index a7d6786..d31f159 100644 --- a/composer.json +++ b/composer.json @@ -13,6 +13,7 @@ "laravel/scout": "^10.8", "laravel/tinker": "^2.9", "spatie/eloquent-sortable": "^4.2", + "spatie/laravel-medialibrary": "^11.0.0", "spatie/laravel-sluggable": "^3.6", "tightenco/ziggy": "^2.0" }, diff --git a/composer.lock b/composer.lock index 25d9dd4..a4ea37d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "9ada6f4b5c68bbe5cf842db314e0e98b", + "content-hash": "591320302071b7be3715432b7c78475e", "packages": [ { "name": "bacon/bacon-qr-code", @@ -2276,6 +2276,87 @@ ], "time": "2024-01-28T23:22:08+00:00" }, + { + "name": "maennchen/zipstream-php", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/maennchen/ZipStream-PHP.git", + "reference": "b8174494eda667f7d13876b4a7bfef0f62a7c0d1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/b8174494eda667f7d13876b4a7bfef0f62a7c0d1", + "reference": "b8174494eda667f7d13876b4a7bfef0f62a7c0d1", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "ext-zlib": "*", + "php-64bit": "^8.1" + }, + "require-dev": { + "ext-zip": "*", + "friendsofphp/php-cs-fixer": "^3.16", + "guzzlehttp/guzzle": "^7.5", + "mikey179/vfsstream": "^1.6", + "php-coveralls/php-coveralls": "^2.5", + "phpunit/phpunit": "^10.0", + "vimeo/psalm": "^5.0" + }, + "suggest": { + "guzzlehttp/psr7": "^2.4", + "psr/http-message": "^2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "ZipStream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paul Duncan", + "email": "pabs@pablotron.org" + }, + { + "name": "Jonatan Männchen", + "email": "jonatan@maennchen.ch" + }, + { + "name": "Jesse Donat", + "email": "donatj@gmail.com" + }, + { + "name": "András Kolesár", + "email": "kolesar@kolesar.hu" + } + ], + "description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.", + "keywords": [ + "stream", + "zip" + ], + "support": { + "issues": "https://github.com/maennchen/ZipStream-PHP/issues", + "source": "https://github.com/maennchen/ZipStream-PHP/tree/3.1.0" + }, + "funding": [ + { + "url": "https://github.com/maennchen", + "type": "github" + }, + { + "url": "https://opencollective.com/zipstream", + "type": "open_collective" + } + ], + "time": "2023-06-21T14:59:35+00:00" + }, { "name": "mobiledetect/mobiledetectlib", "version": "4.8.06", @@ -3825,6 +3906,241 @@ ], "time": "2024-02-26T11:54:22+00:00" }, + { + "name": "spatie/image", + "version": "3.4.0", + "source": { + "type": "git", + "url": "https://github.com/spatie/image.git", + "reference": "d4ca0851e2cb40535331e0057d2bb1fda57d57b7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/image/zipball/d4ca0851e2cb40535331e0057d2bb1fda57d57b7", + "reference": "d4ca0851e2cb40535331e0057d2bb1fda57d57b7", + "shasum": "" + }, + "require": { + "ext-exif": "*", + "ext-json": "*", + "ext-mbstring": "*", + "php": "^8.2", + "spatie/image-optimizer": "^1.7.2", + "spatie/temporary-directory": "^2.2", + "symfony/process": "^6.4|^7.0" + }, + "require-dev": { + "ext-gd": "*", + "ext-imagick": "*", + "pestphp/pest": "^2.28", + "phpstan/phpstan": "^1.10.50", + "spatie/pest-plugin-snapshots": "^2.1", + "spatie/pixelmatch-php": "^1.0", + "spatie/ray": "^1.40.1", + "symfony/var-dumper": "^6.4|7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\Image\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Manipulate images with an expressive API", + "homepage": "https://github.com/spatie/image", + "keywords": [ + "image", + "spatie" + ], + "support": { + "source": "https://github.com/spatie/image/tree/3.4.0" + }, + "funding": [ + { + "url": "https://spatie.be/open-source/support-us", + "type": "custom" + }, + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2024-03-05T17:21:09+00:00" + }, + { + "name": "spatie/image-optimizer", + "version": "1.7.2", + "source": { + "type": "git", + "url": "https://github.com/spatie/image-optimizer.git", + "reference": "62f7463483d1bd975f6f06025d89d42a29608fe1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/image-optimizer/zipball/62f7463483d1bd975f6f06025d89d42a29608fe1", + "reference": "62f7463483d1bd975f6f06025d89d42a29608fe1", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "php": "^7.3|^8.0", + "psr/log": "^1.0 | ^2.0 | ^3.0", + "symfony/process": "^4.2|^5.0|^6.0|^7.0" + }, + "require-dev": { + "pestphp/pest": "^1.21", + "phpunit/phpunit": "^8.5.21|^9.4.4", + "symfony/var-dumper": "^4.2|^5.0|^6.0|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\ImageOptimizer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Easily optimize images using PHP", + "homepage": "https://github.com/spatie/image-optimizer", + "keywords": [ + "image-optimizer", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/image-optimizer/issues", + "source": "https://github.com/spatie/image-optimizer/tree/1.7.2" + }, + "time": "2023-11-03T10:08:02+00:00" + }, + { + "name": "spatie/laravel-medialibrary", + "version": "11.4.6", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-medialibrary.git", + "reference": "a6002b04b4a2e3227b3d5996ad78f8d73302db24" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-medialibrary/zipball/a6002b04b4a2e3227b3d5996ad78f8d73302db24", + "reference": "a6002b04b4a2e3227b3d5996ad78f8d73302db24", + "shasum": "" + }, + "require": { + "ext-exif": "*", + "ext-fileinfo": "*", + "ext-json": "*", + "illuminate/bus": "^10.0|^11.0", + "illuminate/conditionable": "^10.0|^11.0", + "illuminate/console": "^10.0|^11.0", + "illuminate/database": "^10.0|^11.0", + "illuminate/pipeline": "^10.0|^11.0", + "illuminate/support": "^10.0|^11.0", + "maennchen/zipstream-php": "^3.1", + "php": "^8.2", + "spatie/image": "^3.3.2", + "spatie/laravel-package-tools": "^1.16.1", + "spatie/temporary-directory": "^2.2", + "symfony/console": "^6.4.1|^7.0" + }, + "conflict": { + "php-ffmpeg/php-ffmpeg": "<0.6.1" + }, + "require-dev": { + "aws/aws-sdk-php": "^3.293.10", + "ext-imagick": "*", + "ext-pdo_sqlite": "*", + "ext-zip": "*", + "guzzlehttp/guzzle": "^7.8.1", + "larastan/larastan": "^2.7", + "league/flysystem-aws-s3-v3": "^3.22", + "mockery/mockery": "^1.6.7", + "orchestra/testbench": "^7.0|^8.17|^9.0", + "pestphp/pest": "^2.28", + "phpstan/extension-installer": "^1.3.1", + "spatie/laravel-ray": "^1.33", + "spatie/pdf-to-image": "^2.2", + "spatie/pest-plugin-snapshots": "^2.1" + }, + "suggest": { + "league/flysystem-aws-s3-v3": "Required to use AWS S3 file storage", + "php-ffmpeg/php-ffmpeg": "Required for generating video thumbnails", + "spatie/pdf-to-image": "Required for generating thumbnails of PDFs and SVGs" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Spatie\\MediaLibrary\\MediaLibraryServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Spatie\\MediaLibrary\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Associate files with Eloquent models", + "homepage": "https://github.com/spatie/laravel-medialibrary", + "keywords": [ + "cms", + "conversion", + "downloads", + "images", + "laravel", + "laravel-medialibrary", + "media", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/laravel-medialibrary/issues", + "source": "https://github.com/spatie/laravel-medialibrary/tree/11.4.6" + }, + "funding": [ + { + "url": "https://spatie.be/open-source/support-us", + "type": "custom" + }, + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2024-03-19T14:17:05+00:00" + }, { "name": "spatie/laravel-package-tools", "version": "1.16.3", @@ -3944,6 +4260,67 @@ ], "time": "2024-02-26T08:33:29+00:00" }, + { + "name": "spatie/temporary-directory", + "version": "2.2.1", + "source": { + "type": "git", + "url": "https://github.com/spatie/temporary-directory.git", + "reference": "76949fa18f8e1a7f663fd2eaa1d00e0bcea0752a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/temporary-directory/zipball/76949fa18f8e1a7f663fd2eaa1d00e0bcea0752a", + "reference": "76949fa18f8e1a7f663fd2eaa1d00e0bcea0752a", + "shasum": "" + }, + "require": { + "php": "^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\TemporaryDirectory\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alex Vanderbist", + "email": "alex@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Easily create, use and destroy temporary directories", + "homepage": "https://github.com/spatie/temporary-directory", + "keywords": [ + "php", + "spatie", + "temporary-directory" + ], + "support": { + "issues": "https://github.com/spatie/temporary-directory/issues", + "source": "https://github.com/spatie/temporary-directory/tree/2.2.1" + }, + "funding": [ + { + "url": "https://spatie.be/open-source/support-us", + "type": "custom" + }, + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2023-12-25T11:46:58+00:00" + }, { "name": "symfony/clock", "version": "v7.0.5", diff --git a/database/factories/ImageFactory.php b/database/factories/ImageFactory.php deleted file mode 100644 index 281961d..0000000 --- a/database/factories/ImageFactory.php +++ /dev/null @@ -1,28 +0,0 @@ - $this->faker->name(), - 'description' => $this->faker->text(), - 'path' => $this->faker->word(), - ]; - } -} diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index ea955ad..9d0638c 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -36,6 +36,7 @@ public function definition(): array 'remember_token' => Str::random(10), 'profile_photo_path' => null, 'current_team_id' => null, + 'role' => null, ]; } diff --git a/database/migrations/2024_03_14_231137_create_images_table.php b/database/migrations/2024_03_14_231137_create_images_table.php deleted file mode 100644 index 8185a37..0000000 --- a/database/migrations/2024_03_14_231137_create_images_table.php +++ /dev/null @@ -1,30 +0,0 @@ -id(); - $table->string('name'); - $table->string('description')->nullable(); - $table->string('path'); - $table->timestamps(); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::dropIfExists('images'); - } -}; diff --git a/database/migrations/2024_03_21_185358_create_media_table.php b/database/migrations/2024_03_21_185358_create_media_table.php new file mode 100644 index 0000000..3230389 --- /dev/null +++ b/database/migrations/2024_03_21_185358_create_media_table.php @@ -0,0 +1,32 @@ +id(); + + $table->morphs('model'); + $table->uuid('uuid')->nullable()->unique(); + $table->string('collection_name'); + $table->string('name'); + $table->string('file_name'); + $table->string('mime_type')->nullable(); + $table->string('disk'); + $table->string('conversions_disk')->nullable(); + $table->unsignedBigInteger('size'); + $table->json('manipulations'); + $table->json('custom_properties'); + $table->json('generated_conversions'); + $table->json('responsive_images'); + $table->unsignedInteger('order_column')->nullable()->index(); + + $table->nullableTimestamps(); + }); + } +}; diff --git a/provision/docker_php b/provision/docker_php index 4cc8562..19e76ba 100644 --- a/provision/docker_php +++ b/provision/docker_php @@ -10,9 +10,12 @@ RUN pecl install xdebug && docker-php-ext-enable xdebug RUN docker-php-ext-configure pgsql -with-pgsql=/usr/local/pgsql RUN docker-php-ext-configure calendar -RUN docker-php-ext-install -j $(nproc) pdo pdo_pgsql zip pcntl posix bcmath opcache soap intl calendar +RUN docker-php-ext-install -j $(nproc) pdo pdo_pgsql zip pcntl posix bcmath opcache soap intl calendar exif +RUN docker-php-ext-configure gd --with-freetype=/usr/include/ --with-jpeg=/usr/include/ \ + && docker-php-ext-install gd -RUN docker-php-ext-enable sodium redis imagick +RUN docker-php-ext-enable sodium redis imagick exif gd +RUN apt-get install -y jpegoptim optipng pngquant gifsicle libavif-bin libjpeg62-turbo-dev RUN echo "memory_limit=1G" >> /usr/local/etc/php/conf.d/docker-php-memory.ini diff --git a/resources/js/Components/RecipeCard.vue b/resources/js/Components/RecipeCard.vue index 80d69b5..a0a71eb 100644 --- a/resources/js/Components/RecipeCard.vue +++ b/resources/js/Components/RecipeCard.vue @@ -28,7 +28,7 @@ defineProps({
stew diff --git a/resources/js/Pages/Admin/Recipe/RecipeEdit.vue b/resources/js/Pages/Admin/Recipe/RecipeEdit.vue index 70ac4f8..3f07bfc 100644 --- a/resources/js/Pages/Admin/Recipe/RecipeEdit.vue +++ b/resources/js/Pages/Admin/Recipe/RecipeEdit.vue @@ -4,6 +4,7 @@ import Breadcrumb from 'primevue/breadcrumb'; import Button from "primevue/button"; import Card from "primevue/card"; import Fieldset from "primevue/fieldset"; +import FileUpload from "primevue/fileupload"; import InputText from "primevue/inputtext"; import InputNumber from "primevue/inputnumber"; import Listbox from "primevue/listbox"; @@ -11,6 +12,7 @@ import Textarea from 'primevue/textarea' import {router, useForm, Link} from "@inertiajs/vue3"; import {onMounted, ref, watch} from "vue"; import Markdown from "@/Components/Markdown.vue"; +import {makeHero, destroyHero} from "@/imageManagerComposable.js"; const props = defineProps({ recipe: { @@ -33,26 +35,19 @@ const props = defineProps({ default() { return []; }, + }, + images: { + type: [Array, Object], + required: false, + default() { + return []; + }, } }); const labelOptions = ref([]); const categoryOptions = ref([]); -onMounted(() => { - for (const [key, value] of Object.entries(props.recipe)) { - form[key] = value; - } - for (const [key, value] of Object.entries(props.recipe.categories || [])) { - form.categoriesSelected.push(value.slug); - } - for (const [key, value] of Object.entries(props.recipe.labels || [])) { - form.labelsSelected.push(value.slug); - } - labelOptions.value = props.labels; - categoryOptions.value = props.categories; -}); - const form = useForm({ id: null, name: null, @@ -66,6 +61,14 @@ const form = useForm({ categoriesSelected: [], }); +const onAdvancedUpload = () => { + router.reload(({ only: ['images'], preserveScroll: true, })); +}; + +const onUploadError = ($event) => { + console.log($event); +}; + const save = () => { if (form.id) { form.put(route("admin.recipes.update", {recipe: form.slug})); @@ -82,6 +85,32 @@ const breadcrumbs = ref([ { label: 'Recipes', url: route("admin.recipes.index") }, { label: props.recipe.slug ? `Edit Recipe` : "New Recipe" } ]); + +const setHero = (id) => { + makeHero(id, () => { + onAdvancedUpload(); + }) +} + +const deleteHero = (id) => { + destroyHero(id, () => { + onAdvancedUpload(); + }) +} + +onMounted(() => { + for (const [key, value] of Object.entries(props.recipe)) { + form[key] = value; + } + for (const [key, value] of Object.entries(props.recipe.categories || [])) { + form.categoriesSelected.push(value.slug); + } + for (const [key, value] of Object.entries(props.recipe.labels || [])) { + form.labelsSelected.push(value.slug); + } + labelOptions.value = props.labels; + categoryOptions.value = props.categories; +});