WIP
This commit is contained in:
12
.env.example
12
.env.example
@@ -62,3 +62,15 @@ AWS_BUCKET=
|
|||||||
AWS_USE_PATH_STYLE_ENDPOINT=false
|
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||||
|
|
||||||
VITE_APP_NAME="${APP_NAME}"
|
VITE_APP_NAME="${APP_NAME}"
|
||||||
|
|
||||||
|
REVERB_APP_ID=937919
|
||||||
|
REVERB_APP_KEY=5ljogsvykrp9zocjl63r
|
||||||
|
REVERB_APP_SECRET=urnthocgauio2cfzdlu7
|
||||||
|
REVERB_HOST="localhost"
|
||||||
|
REVERB_PORT=8080
|
||||||
|
REVERB_SCHEME=http
|
||||||
|
|
||||||
|
VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
|
||||||
|
VITE_REVERB_HOST="${REVERB_HOST}"
|
||||||
|
VITE_REVERB_PORT="${REVERB_PORT}"
|
||||||
|
VITE_REVERB_SCHEME="${REVERB_SCHEME}"
|
||||||
@@ -9,6 +9,12 @@
|
|||||||
|
|
||||||
## About Laravel
|
## About Laravel
|
||||||
|
|
||||||
|
Requires the php gd extensions
|
||||||
|
|
||||||
|
Todo:
|
||||||
|
|
||||||
|
Cleanup deleted Photos Job
|
||||||
|
|
||||||
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:
|
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:
|
||||||
|
|
||||||
- [Simple, fast routing engine](https://laravel.com/docs/routing).
|
- [Simple, fast routing engine](https://laravel.com/docs/routing).
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class ImageController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function show(Image $image) : BinaryFileResponse
|
public function show(Image $image) : BinaryFileResponse
|
||||||
{
|
{
|
||||||
return response()->file(Storage::disk('images')->path($image->album->id . '/original/' . $image->id));
|
return response()->file(Storage::disk('images')->path($image->album->id . '/thumbnail/' . $image->id . '.avif'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2,6 +2,15 @@
|
|||||||
|
|
||||||
namespace App\Livewire\Drawer\Album;
|
namespace App\Livewire\Drawer\Album;
|
||||||
|
|
||||||
|
use App\Models\BatchMutation;
|
||||||
|
use App\Services\MediaImporter;
|
||||||
|
use App\Models\Album;
|
||||||
|
use Illuminate\Contracts\View\Factory;
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\Support\Facades\Bus;
|
||||||
|
use Livewire\Attributes\Locked;
|
||||||
|
use Livewire\Attributes\On;
|
||||||
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Livewire\Features\SupportFileUploads\WithFileUploads;
|
use Livewire\Features\SupportFileUploads\WithFileUploads;
|
||||||
|
|
||||||
@@ -9,9 +18,37 @@ class AddImage extends Component
|
|||||||
{
|
{
|
||||||
use WithFileUploads;
|
use WithFileUploads;
|
||||||
|
|
||||||
|
#[Locked]
|
||||||
|
public Album $album;
|
||||||
|
|
||||||
|
#[Locked]
|
||||||
|
public bool $processing = false;
|
||||||
|
|
||||||
|
#[Validate(['media.*' => 'image|max:8192'])] // max:8MB
|
||||||
public $media = [];
|
public $media = [];
|
||||||
|
|
||||||
public function render()
|
public function save(MediaImporter $importer) : void {
|
||||||
|
$this->validate();
|
||||||
|
|
||||||
|
$jobs = array_map(fn($file) => $importer->import($file, $this->album), $this->media);
|
||||||
|
$batch = Bus::batch($jobs)
|
||||||
|
->name('Media import in ' . $this->album->name)
|
||||||
|
->allowFailures()
|
||||||
|
->dispatch();
|
||||||
|
|
||||||
|
BatchMutation::create([
|
||||||
|
'album_id' => $this->album->id,
|
||||||
|
'batch_id' => $batch->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->redirect(route('album.show', $this->album), navigate: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function mount(Album $album) : void {
|
||||||
|
$this->album = $album;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render() : View|Factory
|
||||||
{
|
{
|
||||||
return view('livewire.drawer.album.add-image');
|
return view('livewire.drawer.album.add-image');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ class Album extends Model
|
|||||||
return $this->hasMany(Image::class);
|
return $this->hasMany(Image::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function mutations() : HasMany {
|
||||||
|
return $this->hasMany(BatchMutation::class);
|
||||||
|
}
|
||||||
|
|
||||||
public function media() : Collection {
|
public function media() : Collection {
|
||||||
return $this->images;
|
return $this->images;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,22 @@ class Image extends Model implements HasThumbnail
|
|||||||
{
|
{
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The model's default values for attributes.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $attributes = [
|
||||||
|
'isCover' => false,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes that are mass assignable.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = ['album_id'];
|
||||||
|
|
||||||
public function album(): BelongsTo
|
public function album(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Album::class);
|
return $this->belongsTo(Album::class);
|
||||||
|
|||||||
@@ -11,7 +11,10 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
*/
|
*/
|
||||||
public function register(): void
|
public function register(): void
|
||||||
{
|
{
|
||||||
//
|
if ($this->app->environment('local')) {
|
||||||
|
$this->app->register(\Laravel\Telescope\TelescopeServiceProvider::class);
|
||||||
|
$this->app->register(TelescopeServiceProvider::class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ return Application::configure(basePath: dirname(__DIR__))
|
|||||||
->withRouting(
|
->withRouting(
|
||||||
web: __DIR__.'/../routes/web.php',
|
web: __DIR__.'/../routes/web.php',
|
||||||
commands: __DIR__.'/../routes/console.php',
|
commands: __DIR__.'/../routes/console.php',
|
||||||
|
channels: __DIR__.'/../routes/channels.php',
|
||||||
health: '/up',
|
health: '/up',
|
||||||
)
|
)
|
||||||
->withMiddleware(function (Middleware $middleware) {
|
->withMiddleware(function (Middleware $middleware) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
App\Providers\AppServiceProvider::class,
|
App\Providers\AppServiceProvider::class,
|
||||||
|
App\Providers\HorizonServiceProvider::class,
|
||||||
App\Providers\LivewireAssetProvider::class,
|
App\Providers\LivewireAssetProvider::class,
|
||||||
App\Providers\TelescopeServiceProvider::class,
|
App\Providers\MediaImporterServiceProvider::class,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -6,7 +6,10 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.2",
|
"php": "^8.2",
|
||||||
|
"intervention/image-laravel": "^1.2",
|
||||||
"laravel/framework": "^11.0",
|
"laravel/framework": "^11.0",
|
||||||
|
"laravel/horizon": "^5.24",
|
||||||
|
"laravel/reverb": "@beta",
|
||||||
"laravel/telescope": "^5.0",
|
"laravel/telescope": "^5.0",
|
||||||
"laravel/tinker": "^2.9",
|
"laravel/tinker": "^2.9",
|
||||||
"livewire/livewire": "^3.4"
|
"livewire/livewire": "^3.4"
|
||||||
@@ -51,7 +54,9 @@
|
|||||||
},
|
},
|
||||||
"extra": {
|
"extra": {
|
||||||
"laravel": {
|
"laravel": {
|
||||||
"dont-discover": []
|
"dont-discover": [
|
||||||
|
"laravel/telescope"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
|
|||||||
1867
composer.lock
generated
1867
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -39,7 +39,7 @@ return [
|
|||||||
'images' => [
|
'images' => [
|
||||||
'driver' => 'local',
|
'driver' => 'local',
|
||||||
'root' => storage_path('app/images'),
|
'root' => storage_path('app/images'),
|
||||||
'throw' => false,
|
'throw' => true,
|
||||||
],
|
],
|
||||||
|
|
||||||
'public' => [
|
'public' => [
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ use App\Models\Image;
|
|||||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Str;
|
use Intervention\Image\Laravel\Facades\Image as InterventionImage;
|
||||||
|
use \App\Importers\Image\Jobs\GenerateThumbnail;
|
||||||
|
use \App\Importers\Image\Jobs\GenerateFullscreen;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Image>
|
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Image>
|
||||||
@@ -28,7 +30,11 @@ class ImageFactory extends Factory
|
|||||||
$height = rand(2000, 4000);
|
$height = rand(2000, 4000);
|
||||||
$width = rand(2000, 4000);
|
$width = rand(2000, 4000);
|
||||||
$image_content = Http::get("https://picsum.photos/{$width}/{$height}")->body();
|
$image_content = Http::get("https://picsum.photos/{$width}/{$height}")->body();
|
||||||
Storage::disk('images')->put($image->album->id . '/original/' . $image->id, $image_content);
|
$encoded = InterventionImage::read($image_content)->toAvif(config('gallery.image.quality'));
|
||||||
|
Storage::disk('images')->put($image->album->id . '/original/' . $image->id . '.avif', $encoded);
|
||||||
|
|
||||||
|
GenerateThumbnail::dispatch($image);
|
||||||
|
GenerateFullscreen::dispatch($image);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,6 @@ return new class extends Migration
|
|||||||
*/
|
*/
|
||||||
public function down(): void
|
public function down(): void
|
||||||
{
|
{
|
||||||
Schema::dropIfExists('categories_tags');
|
Schema::dropIfExists('category_tag');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
26
package-lock.json
generated
26
package-lock.json
generated
@@ -16,8 +16,10 @@
|
|||||||
"@tailwindcss/forms": "^0.5.7",
|
"@tailwindcss/forms": "^0.5.7",
|
||||||
"autoprefixer": "^10.4.19",
|
"autoprefixer": "^10.4.19",
|
||||||
"axios": "^1.6.4",
|
"axios": "^1.6.4",
|
||||||
|
"laravel-echo": "^1.16.1",
|
||||||
"laravel-vite-plugin": "^1.0",
|
"laravel-vite-plugin": "^1.0",
|
||||||
"postcss": "^8.4.38",
|
"postcss": "^8.4.38",
|
||||||
|
"pusher-js": "^8.4.0-rc2",
|
||||||
"tailwindcss": "^3.4.3",
|
"tailwindcss": "^3.4.3",
|
||||||
"vite": "^5.0"
|
"vite": "^5.0"
|
||||||
}
|
}
|
||||||
@@ -1450,6 +1452,15 @@
|
|||||||
"jiti": "bin/jiti.js"
|
"jiti": "bin/jiti.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/laravel-echo": {
|
||||||
|
"version": "1.16.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/laravel-echo/-/laravel-echo-1.16.1.tgz",
|
||||||
|
"integrity": "sha512-++Ylb6M3ariC9Rk5WE5gZjj6wcEV5kvLF8b+geJ5/rRIfdoOA+eG6b9qJPrarMD9rY28Apx+l3eelIrCc2skVg==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/laravel-vite-plugin": {
|
"node_modules/laravel-vite-plugin": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-1.0.2.tgz",
|
||||||
@@ -1862,6 +1873,15 @@
|
|||||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/pusher-js": {
|
||||||
|
"version": "8.4.0-rc2",
|
||||||
|
"resolved": "https://registry.npmjs.org/pusher-js/-/pusher-js-8.4.0-rc2.tgz",
|
||||||
|
"integrity": "sha512-d87GjOEEl9QgO5BWmViSqW0LOzPvybvX6WA9zLUstNdB57jVJuR27zHkRnrav2a3+zAMlHbP2Og8wug+rG8T+g==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"tweetnacl": "^1.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/queue-microtask": {
|
"node_modules/queue-microtask": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||||
@@ -2236,6 +2256,12 @@
|
|||||||
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
|
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/tweetnacl": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/update-browserslist-db": {
|
"node_modules/update-browserslist-db": {
|
||||||
"version": "1.0.13",
|
"version": "1.0.13",
|
||||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
|
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
"filepond-plugin-file-validate-size": "^2.2.8",
|
"filepond-plugin-file-validate-size": "^2.2.8",
|
||||||
"filepond-plugin-file-validate-type": "^1.2.9",
|
"filepond-plugin-file-validate-type": "^1.2.9",
|
||||||
"filepond-plugin-image-exif-orientation": "^1.0.11",
|
"filepond-plugin-image-exif-orientation": "^1.0.11",
|
||||||
"filepond-plugin-image-preview": "^4.6.12",
|
"filepond-plugin-image-preview": "^4.6.12"
|
||||||
"filepond-plugin-image-transform": "^3.8.7"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,4 +29,5 @@
|
|||||||
|
|
||||||
.filepond--drop-label {
|
.filepond--drop-label {
|
||||||
@apply text-gray-900 dark:text-white;
|
@apply text-gray-900 dark:text-white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,13 +4,11 @@ import FilePondPluginImageExifOrientation from 'filepond-plugin-image-exif-orien
|
|||||||
import FilePondPluginImagePreview from 'filepond-plugin-image-preview';
|
import FilePondPluginImagePreview from 'filepond-plugin-image-preview';
|
||||||
import FilePondPluginFileValidateSize from 'filepond-plugin-file-validate-size';
|
import FilePondPluginFileValidateSize from 'filepond-plugin-file-validate-size';
|
||||||
import FilePondPluginFileValidateType from 'filepond-plugin-file-validate-type';
|
import FilePondPluginFileValidateType from 'filepond-plugin-file-validate-type';
|
||||||
import FilePondPluginImageTransform from 'filepond-plugin-image-transform';
|
|
||||||
|
|
||||||
FilePond.registerPlugin(FilePondPluginImageExifOrientation);
|
FilePond.registerPlugin(FilePondPluginImageExifOrientation);
|
||||||
FilePond.registerPlugin(FilePondPluginImagePreview);
|
FilePond.registerPlugin(FilePondPluginImagePreview);
|
||||||
FilePond.registerPlugin(FilePondPluginFileValidateSize);
|
FilePond.registerPlugin(FilePondPluginFileValidateSize);
|
||||||
FilePond.registerPlugin(FilePondPluginFileValidateType);
|
FilePond.registerPlugin(FilePondPluginFileValidateType);
|
||||||
FilePond.registerPlugin(FilePondPluginImageTransform);
|
|
||||||
|
|
||||||
window.FilePond = FilePond;
|
window.FilePond = FilePond;
|
||||||
|
|
||||||
@@ -18,8 +16,7 @@ document.addEventListener('alpine:init', () => {
|
|||||||
Alpine.store('uploader', {
|
Alpine.store('uploader', {
|
||||||
states: {},
|
states: {},
|
||||||
setState(state, value) {
|
setState(state, value) {
|
||||||
console.log(state, value);
|
|
||||||
this.states[state] = value;
|
this.states[state] = value;
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
@@ -25,24 +25,28 @@
|
|||||||
<h1 class="mb-4 mx-8 text-4xl font-extrabold leading-none tracking-tight text-gray-900 md:text-5xl lg:text-6xl dark:text-white">
|
<h1 class="mb-4 mx-8 text-4xl font-extrabold leading-none tracking-tight text-gray-900 md:text-5xl lg:text-6xl dark:text-white">
|
||||||
{{ $album->name }}
|
{{ $album->name }}
|
||||||
</h1>
|
</h1>
|
||||||
<div class="m-8 flex flex-wrap flex-row gap-4">
|
@if($album->mutations->count() > 0)
|
||||||
@foreach ($album->images as $image)
|
<livewire:drawer.album.progress-monitor :mutation="$album->mutations->first()"/>
|
||||||
<figure class="relative group rounded-lg cursor-pointer h-80 flex-grow overflow-hidden">
|
@else
|
||||||
<img class="max-h-full min-w-full align-bottom object-cover"
|
<div class="m-8 flex flex-wrap flex-row gap-4">
|
||||||
src="{{ $image->getThumbnail() }}" alt="{{ $album->name }} Bild">
|
@foreach ($album->images as $image)
|
||||||
<div class="opacity-0 group-hover:opacity-40 absolute inset-0 w-full h-full bg-black flex items-center justify-center transition-opacity">
|
<figure class="relative group rounded-lg cursor-pointer h-80 flex-grow overflow-hidden">
|
||||||
<svg class="w-1/2 h-1/2 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
<img class="max-h-full min-w-full align-bottom object-cover"
|
||||||
<path stroke="currentColor" stroke-width="2" d="M21 12c0 1.2-4.03 6-9 6s-9-4.8-9-6c0-1.2 4.03-6 9-6s9 4.8 9 6Z"/>
|
src="{{ $image->getThumbnail() }}" alt="{{ $album->name }} Bild">
|
||||||
<path stroke="currentColor" stroke-width="2" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/>
|
<div class="opacity-0 group-hover:opacity-40 absolute inset-0 w-full h-full bg-black flex items-center justify-center transition-opacity">
|
||||||
</svg>
|
<svg class="w-1/2 h-1/2 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||||
</div>
|
<path stroke="currentColor" stroke-width="2" d="M21 12c0 1.2-4.03 6-9 6s-9-4.8-9-6c0-1.2 4.03-6 9-6s9 4.8 9 6Z"/>
|
||||||
</figure>
|
<path stroke="currentColor" stroke-width="2" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/>
|
||||||
@endforeach
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<x-drawer name="image-add" >
|
</figure>
|
||||||
<x-slot:title>Neue Bilder zu {{ $album->name }} hinzufügen</x-slot:title>
|
@endforeach
|
||||||
<x-slot:content>
|
</div>
|
||||||
<livewire:drawer.album.addImage></livewire:drawer.album.addImage>
|
<x-drawer name="image-add" >
|
||||||
</x-slot:content>
|
<x-slot:title>Neue Bilder zu {{ $album->name }} hinzufügen</x-slot:title>
|
||||||
</x-drawer>
|
<x-slot:content>
|
||||||
|
<livewire:drawer.album.addImage :album="$album"></livewire:drawer.album.addImage>
|
||||||
|
</x-slot:content>
|
||||||
|
</x-drawer>
|
||||||
|
@endif
|
||||||
</x-layout>
|
</x-layout>
|
||||||
@@ -3,8 +3,8 @@
|
|||||||
x-data="{ show: false }"
|
x-data="{ show: false }"
|
||||||
class="overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 justify-center items-center w-full md:inset-0 h-screen max-h-full flex backdrop-blur-md bg-white/30 dark:bg-gray-800/30"
|
class="overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 justify-center items-center w-full md:inset-0 h-screen max-h-full flex backdrop-blur-md bg-white/30 dark:bg-gray-800/30"
|
||||||
:class="{ 'translate-y-full': !show }"
|
:class="{ 'translate-y-full': !show }"
|
||||||
@click="$dispatch('drawer-close-{{ $name }}')"
|
@click.self="$dispatch('drawer-close-{{ $name }}')"
|
||||||
x-on:touchstart="$dispatch('drawer-close-{{ $name }}')"
|
x-on:touchstart.self="$dispatch('drawer-close-{{ $name }}')"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
id="drawer-{{ $name }}"
|
id="drawer-{{ $name }}"
|
||||||
@@ -16,16 +16,21 @@
|
|||||||
:class="{ 'translate-y-full': !show, 'xl:-bottom-full': !show }"
|
:class="{ 'translate-y-full': !show, 'xl:-bottom-full': !show }"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="p-4 cursor-pointer max-xl:hover:bg-gray-50 max-xl:dark:hover:bg-gray-700 xl:border-b dark:border-gray-600 xl:flex xl:items-center xl:justify-between xl:p-4"
|
class="p-4 cursor-pointer max-xl:hover:bg-gray-50 max-xl:dark:hover:bg-gray-700 xl:border-b dark:border-gray-600 xl:flex xl:items-center xl:justify-between xl:p-4">
|
||||||
@click="$dispatch('drawer-close-{{ $name }}')"
|
<span
|
||||||
x-on:touchstart="$dispatch('drawer-close-{{ $name }}')"
|
class="xl:hidden absolute w-8 h-1 -translate-x-1/2 bg-gray-300 rounded-lg top-3 left-1/2 dark:bg-gray-600"
|
||||||
>
|
@click="$dispatch('drawer-close-{{ $name }}')"
|
||||||
<span class="xl:hidden absolute w-8 h-1 -translate-x-1/2 bg-gray-300 rounded-lg top-3 left-1/2 dark:bg-gray-600">
|
x-on:touchstart="$dispatch('drawer-close-{{ $name }}')"
|
||||||
|
>
|
||||||
</span>
|
</span>
|
||||||
<h5 class="inline-flex items-center text-base text-gray-500 dark:text-gray-400 font-medium">
|
<h5 class="inline-flex items-center text-base text-gray-500 dark:text-gray-400 font-medium">
|
||||||
{{ $title }}
|
{{ $title }}
|
||||||
</h5>
|
</h5>
|
||||||
<button class="end-2.5 text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:hover:bg-gray-600 dark:hover:text-white">
|
<button
|
||||||
|
class="end-2.5 text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:hover:bg-gray-600 dark:hover:text-white"
|
||||||
|
@click="$dispatch('drawer-close-{{ $name }}')"
|
||||||
|
x-on:touchstart="$dispatch('drawer-close-{{ $name }}')"
|
||||||
|
>
|
||||||
<svg class="max-xl:hidden w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
|
<svg class="max-xl:hidden w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
|
||||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
@@ -68,6 +68,28 @@
|
|||||||
load();
|
load();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
imageResizeTargetWidth: 600,
|
||||||
|
imageCropAspectRatio: 1,
|
||||||
|
imageTransformVariants: {
|
||||||
|
thumb_medium_: (transforms) => {
|
||||||
|
transforms.resize = {
|
||||||
|
size: {
|
||||||
|
width: 384,
|
||||||
|
height: 384,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return transforms;
|
||||||
|
},
|
||||||
|
thumb_small_: (transforms) => {
|
||||||
|
transforms.resize = {
|
||||||
|
size: {
|
||||||
|
width: 128,
|
||||||
|
height: 128,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return transforms;
|
||||||
|
},
|
||||||
|
},
|
||||||
allowImagePreview: {{ $preview ? 'true' : 'false' }},
|
allowImagePreview: {{ $preview ? 'true' : 'false' }},
|
||||||
styleItemPanelAspectRatio: '0.5625',
|
styleItemPanelAspectRatio: '0.5625',
|
||||||
allowFileTypeValidation: {{ $validate ? 'true' : 'false' }},
|
allowFileTypeValidation: {{ $validate ? 'true' : 'false' }},
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
<form class="flex h-1/3 bg-cover relative">
|
@persist('search')
|
||||||
<div class="relative m-auto w-1/2">
|
<form class="flex h-[300px] relative overflow-hidden mb-8">
|
||||||
<label for="default-search" class="mb-2 text-sm font-medium text-gray-900 sr-only dark:text-white">Suchen</label>
|
<img class="absolute object-cover" src="/placeholder.jpg" />
|
||||||
<div class="relative">
|
<div class="relative m-auto w-1/2">
|
||||||
<div class="absolute inset-y-0 start-0 flex items-center ps-3 pointer-events-none">
|
<label for="default-search" class="mb-2 text-sm font-medium text-gray-900 sr-only dark:text-white">Suchen</label>
|
||||||
<svg class="w-4 h-4 text-gray-500 dark:text-gray-400" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 20">
|
<div class="relative">
|
||||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z"/>
|
<div class="absolute inset-y-0 start-0 flex items-center ps-3 pointer-events-none">
|
||||||
</svg>
|
<svg class="w-4 h-4 text-gray-500 dark:text-gray-400" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 20">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<input type="search" id="default-search" class="block w-full p-4 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="Nach Alben suchen" required />
|
||||||
|
<button type="submit" class="text-white absolute end-2.5 bottom-2.5 bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-4 py-2 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">Suchen</button>
|
||||||
</div>
|
</div>
|
||||||
<input type="search" id="default-search" class="block w-full p-4 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="Nach Alben suchen" required />
|
|
||||||
<button type="submit" class="text-white absolute end-2.5 bottom-2.5 bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-4 py-2 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">Suchen</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
</form>
|
@endpersist
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
<html
|
<html
|
||||||
lang="{{ str_replace('_', '-', app()->getLocale()) }}"
|
lang="{{ str_replace('_', '-', app()->getLocale()) }}"
|
||||||
x-data="{ darkMode: $persist(false) }"
|
x-data="{ darkMode: $persist(false) }"
|
||||||
:class="{'dark': darkMode }"
|
:class="{'dark': darkMode}"
|
||||||
x-init="
|
x-init="
|
||||||
if (!('darkMode' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
if (!('darkMode' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||||
localStorage.setItem('darkMode', JSON.stringify(true));
|
localStorage.setItem('darkMode', JSON.stringify(true));
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
@vite('resources/js/app.js')
|
@vite('resources/js/app.js')
|
||||||
<title>{{ $title ?? config('app.name') }}</title>
|
<title>{{ $title ?? config('app.name') }}</title>
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-white dark:bg-gray-800">
|
<body class="bg-white dark:bg-gray-800 min-h-screen flex flex-col">
|
||||||
@persist('theme-switcher')
|
@persist('theme-switcher')
|
||||||
<x-theme-switcher />
|
<x-theme-switcher />
|
||||||
@endpersist
|
@endpersist
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
<form wire:submit="save" class="p-4">
|
<form
|
||||||
|
wire:submit="save"
|
||||||
|
class="p-4"
|
||||||
|
x-data="{loading: false, message: ''}"
|
||||||
|
x-on:import-progress-report="message = $event.detail.message"
|
||||||
|
>
|
||||||
<x-form.upload wire:model="media" name="media" label="Medien" multiple />
|
<x-form.upload wire:model="media" name="media" label="Medien" multiple />
|
||||||
|
|
||||||
<button x-transition x-show="$store.uploader.states && $store.uploader.states.media == 3" disabled type="button" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center me-2 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800 inline-flex items-center">
|
<button x-transition x-show="$store.uploader.states && $store.uploader.states.media == 3" disabled type="button" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center me-2 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800 inline-flex items-center">
|
||||||
@@ -17,5 +22,5 @@
|
|||||||
<span class="font-medium">Dateien mit Fehlern vorhanden!</span> Du kannst nicht speichern, bis die Fehler behoben sind.
|
<span class="font-medium">Dateien mit Fehlern vorhanden!</span> Du kannst nicht speichern, bis die Fehler behoben sind.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button x-transition.delay.500ms x-show="$store.uploader.states && $store.uploader.states.media == 4" type="submit" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800">Speichern</button>
|
<button x-transition.delay.500ms x-show="$store.uploader.states && $store.uploader.states.media == 4" type="submit" @click="loading = true" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800">Speichern</button>
|
||||||
</div>
|
</form>
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Illuminate\Foundation\Inspiring;
|
|
||||||
use Illuminate\Support\Facades\Artisan;
|
use Illuminate\Support\Facades\Artisan;
|
||||||
|
use Illuminate\Support\Facades\Schedule;
|
||||||
|
|
||||||
Artisan::command('inspire', function () {
|
Schedule::command('queue:prune-batches')->daily();
|
||||||
$this->comment(Inspiring::quote());
|
Schedule::command('horizon:snapshot')->everyFiveMinutes();
|
||||||
})->purpose('Display an inspiring quote')->hourly();
|
|
||||||
Reference in New Issue
Block a user