Merge branch 'main' of git.digital-infinity.de:DigitalInfinity/NAI_Photobox
This commit is contained in:
commit
52d0d725f5
35
.devcontainer/devcontainer.json
Normal file
35
.devcontainer/devcontainer.json
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"name": "Fotobox",
|
||||||
|
"image": "mcr.microsoft.com/devcontainers/base:trixie",
|
||||||
|
|
||||||
|
"postCreateCommand": "sudo sh docker/init.sh",
|
||||||
|
"forwardPorts": [8000],
|
||||||
|
"portsAttributes": {
|
||||||
|
"8000": {
|
||||||
|
"label": "Laravel Dev Server",
|
||||||
|
"onAutoForward": "notify"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
|
"extensions": [
|
||||||
|
"bmewburn.vscode-intelephense-client",
|
||||||
|
"onecentlin.laravel-blade",
|
||||||
|
"amiralizadeh9480.laravel-extra-intellisense",
|
||||||
|
"dbaeumer.vscode-eslint",
|
||||||
|
"esbenp.prettier-vscode",
|
||||||
|
"laravel.vscode-laravel",
|
||||||
|
"bradlc.vscode-tailwindcss"
|
||||||
|
],
|
||||||
|
"settings": {
|
||||||
|
"php.validate.executablePath": "/usr/bin/php",
|
||||||
|
"intelephense.environment.phpVersion": "8.5",
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||||
|
"[php]": {
|
||||||
|
"editor.defaultFormatter": "bmewburn.vscode-intelephense-client"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
.dockerignore
Normal file
7
.dockerignore
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
vendor/
|
||||||
|
node_modules/
|
||||||
|
public/build/
|
||||||
|
.git/
|
||||||
|
.env
|
||||||
|
storage/framework/
|
||||||
|
storage/logs/
|
||||||
@ -63,3 +63,5 @@ AWS_BUCKET=
|
|||||||
AWS_USE_PATH_STYLE_ENDPOINT=false
|
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||||
|
|
||||||
VITE_APP_NAME="${APP_NAME}"
|
VITE_APP_NAME="${APP_NAME}"
|
||||||
|
|
||||||
|
PHOTO_RETENTION_HOURS=24
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -26,3 +26,6 @@ _ide_helper.php
|
|||||||
Homestead.json
|
Homestead.json
|
||||||
Homestead.yaml
|
Homestead.yaml
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
public/fonts/filament/filament/*/*.woff2
|
||||||
|
public/js/filament/**/*.js
|
||||||
|
public/*/filament/**/*.css
|
||||||
|
|||||||
13
Dockerfile
Normal file
13
Dockerfile
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
FROM debian:trixie-backports
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y git curl zip unzip
|
||||||
|
RUN rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Node.js 22
|
||||||
|
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
|
||||||
|
&& apt-get install -y nodejs \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
28
app/Console/Commands/CleanupPhotos.php
Normal file
28
app/Console/Commands/CleanupPhotos.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Models\PhotoJob;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
|
class CleanupPhotos extends Command
|
||||||
|
{
|
||||||
|
protected $signature = 'photos:cleanup';
|
||||||
|
protected $description = 'Delete photos and their jobs older than the configured retention period';
|
||||||
|
|
||||||
|
public function handle(): void
|
||||||
|
{
|
||||||
|
$hours = config('fotobox.photo_retention_hours');
|
||||||
|
$cutoff = now()->subHours($hours);
|
||||||
|
|
||||||
|
$jobs = PhotoJob::where('created_at', '<', $cutoff)->get();
|
||||||
|
|
||||||
|
foreach ($jobs as $job) {
|
||||||
|
Storage::disk('public')->delete($job->image_path);
|
||||||
|
$job->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->info("Deleted {$jobs->count()} photo(s) older than {$hours} hour(s).");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\Photoprofiles\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Resources\Photoprofiles\PhotoprofileResource;
|
||||||
|
use Filament\Resources\Pages\CreateRecord;
|
||||||
|
|
||||||
|
class CreatePhotoprofile extends CreateRecord
|
||||||
|
{
|
||||||
|
protected static string $resource = PhotoprofileResource::class;
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\Photoprofiles\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Resources\Photoprofiles\PhotoprofileResource;
|
||||||
|
use Filament\Actions\DeleteAction;
|
||||||
|
use Filament\Resources\Pages\EditRecord;
|
||||||
|
|
||||||
|
class EditPhotoprofile extends EditRecord
|
||||||
|
{
|
||||||
|
protected static string $resource = PhotoprofileResource::class;
|
||||||
|
|
||||||
|
protected function getHeaderActions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
DeleteAction::make(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\Photoprofiles\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Resources\Photoprofiles\PhotoprofileResource;
|
||||||
|
use Filament\Actions\CreateAction;
|
||||||
|
use Filament\Resources\Pages\ListRecords;
|
||||||
|
|
||||||
|
class ListPhotoprofiles extends ListRecords
|
||||||
|
{
|
||||||
|
protected static string $resource = PhotoprofileResource::class;
|
||||||
|
|
||||||
|
protected function getHeaderActions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
CreateAction::make(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\Photoprofiles;
|
||||||
|
|
||||||
|
use App\Filament\Resources\Photoprofiles\Pages\CreatePhotoprofile;
|
||||||
|
use App\Filament\Resources\Photoprofiles\Pages\EditPhotoprofile;
|
||||||
|
use App\Filament\Resources\Photoprofiles\Pages\ListPhotoprofiles;
|
||||||
|
use App\Filament\Resources\Photoprofiles\Schemas\PhotoprofileForm;
|
||||||
|
use App\Filament\Resources\Photoprofiles\Tables\PhotoprofilesTable;
|
||||||
|
use App\Models\Photoprofile;
|
||||||
|
use BackedEnum;
|
||||||
|
use Filament\Resources\Resource;
|
||||||
|
use Filament\Schemas\Schema;
|
||||||
|
use Filament\Support\Icons\Heroicon;
|
||||||
|
use Filament\Tables\Table;
|
||||||
|
|
||||||
|
class PhotoprofileResource extends Resource
|
||||||
|
{
|
||||||
|
protected static ?string $model = Photoprofile::class;
|
||||||
|
|
||||||
|
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack;
|
||||||
|
|
||||||
|
protected static ?string $recordTitleAttribute = 'name';
|
||||||
|
|
||||||
|
public static function form(Schema $schema): Schema
|
||||||
|
{
|
||||||
|
return PhotoprofileForm::configure($schema);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function table(Table $table): Table
|
||||||
|
{
|
||||||
|
return PhotoprofilesTable::configure($table);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getRelations(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
//
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getPages(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'index' => ListPhotoprofiles::route('/'),
|
||||||
|
'create' => CreatePhotoprofile::route('/create'),
|
||||||
|
'edit' => EditPhotoprofile::route('/{record}/edit'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\Photoprofiles\Schemas;
|
||||||
|
|
||||||
|
use Filament\Forms\Components\Checkbox;
|
||||||
|
use Filament\Forms\Components\Textarea;
|
||||||
|
use Filament\Forms\Components\TextInput;
|
||||||
|
use Filament\Schemas\Schema;
|
||||||
|
|
||||||
|
class PhotoprofileForm
|
||||||
|
{
|
||||||
|
public static function configure(Schema $schema): Schema
|
||||||
|
{
|
||||||
|
return $schema
|
||||||
|
->components([
|
||||||
|
TextInput::make('name')
|
||||||
|
->label('Name')
|
||||||
|
->required(),
|
||||||
|
Checkbox::make('active')
|
||||||
|
->label('Aktiv'),
|
||||||
|
Textarea::make('commands')
|
||||||
|
->label('Befehle')
|
||||||
|
->required(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\Photoprofiles\Tables;
|
||||||
|
|
||||||
|
use Filament\Actions\BulkActionGroup;
|
||||||
|
use Filament\Actions\DeleteBulkAction;
|
||||||
|
use Filament\Actions\EditAction;
|
||||||
|
use Filament\Tables\Columns\IconColumn;
|
||||||
|
use Filament\Tables\Columns\TextColumn;
|
||||||
|
use Filament\Tables\Table;
|
||||||
|
|
||||||
|
class PhotoprofilesTable
|
||||||
|
{
|
||||||
|
public static function configure(Table $table): Table
|
||||||
|
{
|
||||||
|
return $table
|
||||||
|
->columns([
|
||||||
|
TextColumn::make('created_at')
|
||||||
|
->dateTime()
|
||||||
|
->sortable()
|
||||||
|
->toggleable(isToggledHiddenByDefault: true),
|
||||||
|
TextColumn::make('updated_at')
|
||||||
|
->dateTime()
|
||||||
|
->sortable()
|
||||||
|
->toggleable(isToggledHiddenByDefault: true),
|
||||||
|
TextColumn::make('name')
|
||||||
|
->label('Name')
|
||||||
|
->searchable(),
|
||||||
|
IconColumn::make('active')
|
||||||
|
->label('Aktiv')
|
||||||
|
])
|
||||||
|
->filters([
|
||||||
|
//
|
||||||
|
])
|
||||||
|
->recordActions([
|
||||||
|
EditAction::make(),
|
||||||
|
])
|
||||||
|
->toolbarActions([
|
||||||
|
BulkActionGroup::make([
|
||||||
|
DeleteBulkAction::make(),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
11
app/Filament/Resources/Users/Pages/CreateUser.php
Normal file
11
app/Filament/Resources/Users/Pages/CreateUser.php
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\Users\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Resources\Users\UserResource;
|
||||||
|
use Filament\Resources\Pages\CreateRecord;
|
||||||
|
|
||||||
|
class CreateUser extends CreateRecord
|
||||||
|
{
|
||||||
|
protected static string $resource = UserResource::class;
|
||||||
|
}
|
||||||
19
app/Filament/Resources/Users/Pages/EditUser.php
Normal file
19
app/Filament/Resources/Users/Pages/EditUser.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\Users\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Resources\Users\UserResource;
|
||||||
|
use Filament\Actions\DeleteAction;
|
||||||
|
use Filament\Resources\Pages\EditRecord;
|
||||||
|
|
||||||
|
class EditUser extends EditRecord
|
||||||
|
{
|
||||||
|
protected static string $resource = UserResource::class;
|
||||||
|
|
||||||
|
protected function getHeaderActions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
DeleteAction::make(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
19
app/Filament/Resources/Users/Pages/ListUsers.php
Normal file
19
app/Filament/Resources/Users/Pages/ListUsers.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\Users\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Resources\Users\UserResource;
|
||||||
|
use Filament\Actions\CreateAction;
|
||||||
|
use Filament\Resources\Pages\ListRecords;
|
||||||
|
|
||||||
|
class ListUsers extends ListRecords
|
||||||
|
{
|
||||||
|
protected static string $resource = UserResource::class;
|
||||||
|
|
||||||
|
protected function getHeaderActions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
CreateAction::make(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
35
app/Filament/Resources/Users/Schemas/UserForm.php
Normal file
35
app/Filament/Resources/Users/Schemas/UserForm.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\Users\Schemas;
|
||||||
|
|
||||||
|
use Filament\Forms\Components\Checkbox;
|
||||||
|
use Filament\Forms\Components\TextInput;
|
||||||
|
use Filament\Schemas\Schema;
|
||||||
|
|
||||||
|
class UserForm
|
||||||
|
{
|
||||||
|
public static function configure(Schema $schema): Schema
|
||||||
|
{
|
||||||
|
return $schema
|
||||||
|
->components([
|
||||||
|
TextInput::make('name')
|
||||||
|
->label('Name')
|
||||||
|
->required(),
|
||||||
|
TextInput::make('email')
|
||||||
|
->label('E-Mail')
|
||||||
|
->email()
|
||||||
|
->required()
|
||||||
|
->unique(ignoreRecord: true),
|
||||||
|
TextInput::make('password')
|
||||||
|
->label('Passwort')
|
||||||
|
->password()
|
||||||
|
->revealable()
|
||||||
|
->required(fn (string $operation) => $operation === 'create')
|
||||||
|
->dehydrateStateUsing(fn ($state) => filled($state) ? bcrypt($state) : null)
|
||||||
|
->dehydrated(fn ($state) => filled($state))
|
||||||
|
->minLength(8),
|
||||||
|
Checkbox::make('is_admin')
|
||||||
|
->label('Administrator'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
44
app/Filament/Resources/Users/Tables/UsersTable.php
Normal file
44
app/Filament/Resources/Users/Tables/UsersTable.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\Users\Tables;
|
||||||
|
|
||||||
|
use Filament\Actions\BulkActionGroup;
|
||||||
|
use Filament\Actions\DeleteBulkAction;
|
||||||
|
use Filament\Actions\EditAction;
|
||||||
|
use Filament\Tables\Columns\IconColumn;
|
||||||
|
use Filament\Tables\Columns\TextColumn;
|
||||||
|
use Filament\Tables\Table;
|
||||||
|
|
||||||
|
class UsersTable
|
||||||
|
{
|
||||||
|
public static function configure(Table $table): Table
|
||||||
|
{
|
||||||
|
return $table
|
||||||
|
->columns([
|
||||||
|
TextColumn::make('name')
|
||||||
|
->label('Name')
|
||||||
|
->searchable()
|
||||||
|
->sortable(),
|
||||||
|
TextColumn::make('email')
|
||||||
|
->label('E-Mail')
|
||||||
|
->searchable()
|
||||||
|
->sortable(),
|
||||||
|
IconColumn::make('is_admin')
|
||||||
|
->label('Administrator'),
|
||||||
|
TextColumn::make('created_at')
|
||||||
|
->label('Erstellt')
|
||||||
|
->dateTime()
|
||||||
|
->sortable()
|
||||||
|
->toggleable(isToggledHiddenByDefault: true),
|
||||||
|
])
|
||||||
|
->filters([])
|
||||||
|
->recordActions([
|
||||||
|
EditAction::make(),
|
||||||
|
])
|
||||||
|
->toolbarActions([
|
||||||
|
BulkActionGroup::make([
|
||||||
|
DeleteBulkAction::make(),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
54
app/Filament/Resources/Users/UserResource.php
Normal file
54
app/Filament/Resources/Users/UserResource.php
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\Users;
|
||||||
|
|
||||||
|
use App\Filament\Resources\Users\Pages\CreateUser;
|
||||||
|
use App\Filament\Resources\Users\Pages\EditUser;
|
||||||
|
use App\Filament\Resources\Users\Pages\ListUsers;
|
||||||
|
use App\Filament\Resources\Users\Schemas\UserForm;
|
||||||
|
use App\Filament\Resources\Users\Tables\UsersTable;
|
||||||
|
use App\Models\User;
|
||||||
|
use BackedEnum;
|
||||||
|
use Filament\Resources\Resource;
|
||||||
|
use Filament\Schemas\Schema;
|
||||||
|
use Filament\Support\Icons\Heroicon;
|
||||||
|
use Filament\Tables\Table;
|
||||||
|
|
||||||
|
class UserResource extends Resource
|
||||||
|
{
|
||||||
|
protected static ?string $model = User::class;
|
||||||
|
|
||||||
|
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedUsers;
|
||||||
|
|
||||||
|
protected static ?string $recordTitleAttribute = 'name';
|
||||||
|
|
||||||
|
protected static ?string $navigationLabel = 'Benutzer';
|
||||||
|
|
||||||
|
protected static ?string $modelLabel = 'Benutzer';
|
||||||
|
|
||||||
|
protected static ?string $pluralModelLabel = 'Benutzer';
|
||||||
|
|
||||||
|
public static function form(Schema $schema): Schema
|
||||||
|
{
|
||||||
|
return UserForm::configure($schema);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function table(Table $table): Table
|
||||||
|
{
|
||||||
|
return UsersTable::configure($table);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getRelations(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getPages(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'index' => ListUsers::route('/'),
|
||||||
|
'create' => CreateUser::route('/create'),
|
||||||
|
'edit' => EditUser::route('/{record}/edit'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
37
app/Http/Controllers/LoginController.php
Normal file
37
app/Http/Controllers/LoginController.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class LoginController extends Controller
|
||||||
|
{
|
||||||
|
public function show()
|
||||||
|
{
|
||||||
|
return view('auth.login');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function login(Request $request)
|
||||||
|
{
|
||||||
|
$credentials = $request->validate([
|
||||||
|
'email' => ['required', 'email'],
|
||||||
|
'password' => ['required'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (Auth::attempt($credentials, $request->boolean('remember'))) {
|
||||||
|
$request->session()->regenerate();
|
||||||
|
return redirect()->intended('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
return back()->withErrors(['email' => 'Die eingegebenen Daten stimmen nicht überein.'])->onlyInput('email');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function logout(Request $request)
|
||||||
|
{
|
||||||
|
Auth::logout();
|
||||||
|
$request->session()->invalidate();
|
||||||
|
$request->session()->regenerateToken();
|
||||||
|
return redirect('/login');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,19 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Middleware;
|
|
||||||
|
|
||||||
use Closure;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
|
||||||
|
|
||||||
class RestrictToSubnet
|
|
||||||
{
|
|
||||||
public function handle(Request $request, Closure $next, string $subnet = '192'): Response
|
|
||||||
{
|
|
||||||
if (!str_starts_with($request->ip(), $subnet) && !str_starts_with($request->ip(), "127")) {
|
|
||||||
abort(403);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $next($request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -3,6 +3,7 @@
|
|||||||
namespace App\Jobs;
|
namespace App\Jobs;
|
||||||
|
|
||||||
use App\Models\PhotoJob;
|
use App\Models\PhotoJob;
|
||||||
|
use App\Models\Photoprofile;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Queue\Queueable;
|
use Illuminate\Foundation\Queue\Queueable;
|
||||||
use Illuminate\Support\Facades\Process;
|
use Illuminate\Support\Facades\Process;
|
||||||
@ -20,12 +21,15 @@ class ConvertToComic implements ShouldQueue
|
|||||||
{
|
{
|
||||||
$absolutePath = Storage::disk('public')->path($this->photoJob->image_path);
|
$absolutePath = Storage::disk('public')->path($this->photoJob->image_path);
|
||||||
|
|
||||||
$command = 'gmic ' . escapeshellarg($absolutePath) .
|
$photoprofile = $this->photoJob->photoprofile
|
||||||
' simplelocalcontrast_p 16,2,0,1,1,1,1,1,1,1,1,0' .
|
?? Photoprofile::where('active', 1)->first();
|
||||||
' -o ' . escapeshellarg($absolutePath) .
|
$photocommands = [];
|
||||||
' && gmic ' . escapeshellarg($absolutePath) .
|
foreach (explode(PHP_EOL, $photoprofile->commands) as $command) {
|
||||||
' cl_comic 4,1,0,0,1,15,15,1,10,20,6,2,0,0,0,0,0,0,50,50' .
|
if (count($photocommands) > 0) $photocommands[] = ' && gmic ' . escapeshellarg($absolutePath) . ' ' . $command . ' -o ' . escapeshellarg($absolutePath);
|
||||||
' -o ' . escapeshellarg($absolutePath);
|
else $photocommands[] = 'gmic ' . escapeshellarg($absolutePath) . ' ' . $command . ' -o ' . escapeshellarg($absolutePath);
|
||||||
|
}
|
||||||
|
$command = implode($photocommands);
|
||||||
|
|
||||||
$result = Process::timeout(0)->run($command);
|
$result = Process::timeout(0)->run($command);
|
||||||
|
|
||||||
$this->photoJob->update([
|
$this->photoJob->update([
|
||||||
|
|||||||
@ -4,6 +4,7 @@ namespace App\Livewire;
|
|||||||
|
|
||||||
use App\Jobs\ConvertToComic;
|
use App\Jobs\ConvertToComic;
|
||||||
use App\Models\PhotoJob;
|
use App\Models\PhotoJob;
|
||||||
|
use App\Models\Photoprofile;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
@ -11,6 +12,12 @@ use Livewire\Component;
|
|||||||
class CameraCapture extends Component
|
class CameraCapture extends Component
|
||||||
{
|
{
|
||||||
public string $status = '';
|
public string $status = '';
|
||||||
|
public ?int $photoprofileId = null;
|
||||||
|
|
||||||
|
public function mount(): void
|
||||||
|
{
|
||||||
|
$this->photoprofileId = Photoprofile::where('active', 1)->value('id');
|
||||||
|
}
|
||||||
|
|
||||||
public function delete(int $jobId): void
|
public function delete(int $jobId): void
|
||||||
{
|
{
|
||||||
@ -39,6 +46,7 @@ class CameraCapture extends Component
|
|||||||
$job = PhotoJob::create([
|
$job = PhotoJob::create([
|
||||||
'image_path' => $filename,
|
'image_path' => $filename,
|
||||||
'status' => 'processing',
|
'status' => 'processing',
|
||||||
|
'photoprofile_id' => $this->photoprofileId,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
ConvertToComic::dispatch($job);
|
ConvertToComic::dispatch($job);
|
||||||
@ -55,7 +63,8 @@ class CameraCapture extends Component
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
$hasProcessing = $recentPhotos->contains('status', 'processing');
|
$hasProcessing = $recentPhotos->contains('status', 'processing');
|
||||||
|
$photoprofiles = Photoprofile::where('active', 1)->pluck('name', 'id');
|
||||||
|
|
||||||
return view('livewire.camera-capture', compact('recentPhotos', 'hasProcessing'));
|
return view('livewire.camera-capture', compact('recentPhotos', 'hasProcessing', 'photoprofiles'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,8 +3,14 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use App\Models\Photoprofile;
|
||||||
|
|
||||||
class PhotoJob extends Model
|
class PhotoJob extends Model
|
||||||
{
|
{
|
||||||
protected $fillable = ['image_path', 'status'];
|
protected $fillable = ['image_path', 'status', 'photoprofile_id'];
|
||||||
|
|
||||||
|
public function photoprofile()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Photoprofile::class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
app/Models/Photoprofile.php
Normal file
12
app/Models/Photoprofile.php
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
#[Fillable('name', 'commands')]
|
||||||
|
class Photoprofile extends Model
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
@ -2,31 +2,33 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
|
||||||
use Database\Factories\UserFactory;
|
use Database\Factories\UserFactory;
|
||||||
|
use Filament\Models\Contracts\FilamentUser;
|
||||||
|
use Filament\Panel;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Hidden;
|
use Illuminate\Database\Eloquent\Attributes\Hidden;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
|
|
||||||
#[Fillable(['name', 'email', 'password'])]
|
#[Fillable(['name', 'email', 'password', 'is_admin'])]
|
||||||
#[Hidden(['password', 'remember_token'])]
|
#[Hidden(['password', 'remember_token'])]
|
||||||
class User extends Authenticatable
|
class User extends Authenticatable implements FilamentUser
|
||||||
{
|
{
|
||||||
/** @use HasFactory<UserFactory> */
|
/** @use HasFactory<UserFactory> */
|
||||||
use HasFactory, Notifiable;
|
use HasFactory, Notifiable;
|
||||||
|
|
||||||
/**
|
public function canAccessPanel(Panel $panel): bool
|
||||||
* Get the attributes that should be cast.
|
{
|
||||||
*
|
return $this->is_admin;
|
||||||
* @return array<string, string>
|
}
|
||||||
*/
|
|
||||||
protected function casts(): array
|
protected function casts(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'email_verified_at' => 'datetime',
|
'email_verified_at' => 'datetime',
|
||||||
'password' => 'hashed',
|
'password' => 'hashed',
|
||||||
|
'is_admin' => 'boolean',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
59
app/Providers/Filament/AdminPanelProvider.php
Normal file
59
app/Providers/Filament/AdminPanelProvider.php
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers\Filament;
|
||||||
|
|
||||||
|
use Filament\Http\Middleware\Authenticate;
|
||||||
|
use Filament\Http\Middleware\AuthenticateSession;
|
||||||
|
use Filament\Http\Middleware\DisableBladeIconComponents;
|
||||||
|
use Filament\Http\Middleware\DispatchServingFilamentEvent;
|
||||||
|
use Filament\Pages\Dashboard;
|
||||||
|
use Filament\Panel;
|
||||||
|
use Filament\PanelProvider;
|
||||||
|
use Filament\Support\Colors\Color;
|
||||||
|
use Filament\Widgets\AccountWidget;
|
||||||
|
use Filament\Widgets\FilamentInfoWidget;
|
||||||
|
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
|
||||||
|
use Illuminate\Cookie\Middleware\EncryptCookies;
|
||||||
|
use Illuminate\Foundation\Http\Middleware\PreventRequestForgery;
|
||||||
|
use Illuminate\Routing\Middleware\SubstituteBindings;
|
||||||
|
use Illuminate\Session\Middleware\StartSession;
|
||||||
|
use Illuminate\View\Middleware\ShareErrorsFromSession;
|
||||||
|
|
||||||
|
class AdminPanelProvider extends PanelProvider
|
||||||
|
{
|
||||||
|
public function panel(Panel $panel): Panel
|
||||||
|
{
|
||||||
|
return $panel
|
||||||
|
->default()
|
||||||
|
->id('admin')
|
||||||
|
->path('admin')
|
||||||
|
->login()
|
||||||
|
->colors([
|
||||||
|
'primary' => Color::Amber,
|
||||||
|
])
|
||||||
|
->discoverResources(in: app_path('Filament/Resources'), for: 'App\Filament\Resources')
|
||||||
|
->discoverPages(in: app_path('Filament/Pages'), for: 'App\Filament\Pages')
|
||||||
|
->pages([
|
||||||
|
Dashboard::class,
|
||||||
|
])
|
||||||
|
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\Filament\Widgets')
|
||||||
|
->widgets([
|
||||||
|
AccountWidget::class,
|
||||||
|
FilamentInfoWidget::class,
|
||||||
|
])
|
||||||
|
->middleware([
|
||||||
|
EncryptCookies::class,
|
||||||
|
AddQueuedCookiesToResponse::class,
|
||||||
|
StartSession::class,
|
||||||
|
AuthenticateSession::class,
|
||||||
|
ShareErrorsFromSession::class,
|
||||||
|
PreventRequestForgery::class,
|
||||||
|
SubstituteBindings::class,
|
||||||
|
DisableBladeIconComponents::class,
|
||||||
|
DispatchServingFilamentEvent::class,
|
||||||
|
])
|
||||||
|
->authMiddleware([
|
||||||
|
Authenticate::class,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,7 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use App\Providers\AppServiceProvider;
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
AppServiceProvider::class,
|
App\Providers\AppServiceProvider::class,
|
||||||
|
App\Providers\Filament\AdminPanelProvider::class,
|
||||||
];
|
];
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.3",
|
"php": "^8.3",
|
||||||
|
"filament/filament": "^5.0",
|
||||||
"laravel/framework": "^13.8",
|
"laravel/framework": "^13.8",
|
||||||
"laravel/tinker": "^3.0",
|
"laravel/tinker": "^3.0",
|
||||||
"livewire/livewire": "^4.3"
|
"livewire/livewire": "^4.3"
|
||||||
@ -52,7 +53,8 @@
|
|||||||
],
|
],
|
||||||
"post-autoload-dump": [
|
"post-autoload-dump": [
|
||||||
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
|
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
|
||||||
"@php artisan package:discover --ansi"
|
"@php artisan package:discover --ansi",
|
||||||
|
"@php artisan filament:upgrade"
|
||||||
],
|
],
|
||||||
"post-update-cmd": [
|
"post-update-cmd": [
|
||||||
"@php artisan vendor:publish --tag=laravel-assets --ansi --force"
|
"@php artisan vendor:publish --tag=laravel-assets --ansi --force"
|
||||||
|
|||||||
2366
composer.lock
generated
2366
composer.lock
generated
File diff suppressed because it is too large
Load Diff
137
config/filament.php
Normal file
137
config/filament.php
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Broadcasting
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| By uncommenting the Laravel Echo configuration, you may connect Filament
|
||||||
|
| to any Pusher-compatible websockets server.
|
||||||
|
|
|
||||||
|
| This will allow your users to receive real-time notifications.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'broadcasting' => [
|
||||||
|
|
||||||
|
// 'echo' => [
|
||||||
|
// 'broadcaster' => 'pusher',
|
||||||
|
// 'key' => env('VITE_PUSHER_APP_KEY'),
|
||||||
|
// 'cluster' => env('VITE_PUSHER_APP_CLUSTER'),
|
||||||
|
// 'wsHost' => env('VITE_PUSHER_HOST'),
|
||||||
|
// 'wsPort' => env('VITE_PUSHER_PORT'),
|
||||||
|
// 'wssPort' => env('VITE_PUSHER_PORT'),
|
||||||
|
// 'authEndpoint' => '/broadcasting/auth',
|
||||||
|
// 'disableStats' => true,
|
||||||
|
// 'encrypted' => true,
|
||||||
|
// 'forceTLS' => env('VITE_PUSHER_SCHEME', 'https') === 'https',
|
||||||
|
// ],
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Default Filesystem Disk
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This is the storage disk Filament will use to store files. You may use
|
||||||
|
| any of the disks defined in the `config/filesystems.php`.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'default_filesystem_disk' => env('FILESYSTEM_DISK', 'local'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Temporary File URL Expiry
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When Filament generates temporary URLs for previewing private files
|
||||||
|
| (file uploads, image columns, image entries, rich editor attachments,
|
||||||
|
| etc.), this value controls how many minutes those URLs remain valid.
|
||||||
|
|
|
||||||
|
| The generated URL's expiry is rounded up to the end of the hour it
|
||||||
|
| falls in, so the effective lifetime will be between this value and
|
||||||
|
| this value plus up to 60 minutes.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'temporary_file_url_expiry_minutes' => 30,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Assets Path
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This is the directory where Filament's assets will be published to. It
|
||||||
|
| is relative to the `public` directory of your Laravel application.
|
||||||
|
|
|
||||||
|
| After changing the path, you should run `php artisan filament:assets`.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'assets_path' => null,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Cache Path
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This is the directory that Filament will use to store cache files that
|
||||||
|
| are used to optimize the registration of components.
|
||||||
|
|
|
||||||
|
| After changing the path, you should run `php artisan filament:cache-components`.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'cache_path' => base_path('bootstrap/cache/filament'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Livewire Loading Delay
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This sets the delay before loading indicators appear.
|
||||||
|
|
|
||||||
|
| Setting this to 'none' makes indicators appear immediately, which can be
|
||||||
|
| desirable for high-latency connections. Setting it to 'default' applies
|
||||||
|
| Livewire's standard 200ms delay.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'livewire_loading_delay' => 'default',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| File Generation
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Artisan commands that generate files can be configured here by setting
|
||||||
|
| configuration flags that will impact their location or content.
|
||||||
|
|
|
||||||
|
| Often, this is useful to preserve file generation behavior from a
|
||||||
|
| previous version of Filament, to ensure consistency between older and
|
||||||
|
| newer generated files. These flags are often documented in the upgrade
|
||||||
|
| guide for the version of Filament you are upgrading to.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'file_generation' => [
|
||||||
|
'flags' => [],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| System Route Prefix
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This is the prefix used for the system routes that Filament registers,
|
||||||
|
| such as the routes for downloading exports and failed import rows.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'system_route_prefix' => 'filament',
|
||||||
|
|
||||||
|
];
|
||||||
17
config/fotobox.php
Normal file
17
config/fotobox.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Photo Retention
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Photos and their associated jobs older than this many hours will be
|
||||||
|
| automatically deleted by the photos:cleanup scheduled command.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'photo_retention_hours' => (int) env('PHOTO_RETENTION_HOURS', 24),
|
||||||
|
|
||||||
|
];
|
||||||
@ -30,6 +30,7 @@ class UserFactory extends Factory
|
|||||||
'email_verified_at' => now(),
|
'email_verified_at' => now(),
|
||||||
'password' => static::$password ??= Hash::make('password'),
|
'password' => static::$password ??= Hash::make('password'),
|
||||||
'remember_token' => Str::random(10),
|
'remember_token' => Str::random(10),
|
||||||
|
'is_admin' => false,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('photoprofiles', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->timestamps();
|
||||||
|
$table->boolean('active')->default(1);
|
||||||
|
$table->string("name");
|
||||||
|
$table->string("commands");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('photoprofiles');
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('photo_jobs', function (Blueprint $table) {
|
||||||
|
$table->foreignId('photoprofile_id')->nullable()->constrained('photoprofiles')->nullOnDelete();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('photo_jobs', function (Blueprint $table) {
|
||||||
|
$table->dropForeignIdFor(\App\Models\Photoprofile::class);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->boolean('is_admin')->default(false)->after('remember_token');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('is_admin');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
namespace Database\Seeders;
|
namespace Database\Seeders;
|
||||||
|
|
||||||
use App\Models\User;
|
|
||||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||||
use Illuminate\Database\Seeder;
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
@ -10,16 +9,11 @@ class DatabaseSeeder extends Seeder
|
|||||||
{
|
{
|
||||||
use WithoutModelEvents;
|
use WithoutModelEvents;
|
||||||
|
|
||||||
/**
|
|
||||||
* Seed the application's database.
|
|
||||||
*/
|
|
||||||
public function run(): void
|
public function run(): void
|
||||||
{
|
{
|
||||||
// User::factory(10)->create();
|
$this->call([
|
||||||
|
UserSeeder::class,
|
||||||
User::factory()->create([
|
PhotoprofileSeeder::class,
|
||||||
'name' => 'Test User',
|
|
||||||
'email' => 'test@example.com',
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
56
database/seeders/PhotoprofileSeeder.php
Normal file
56
database/seeders/PhotoprofileSeeder.php
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use App\Models\Photoprofile;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
|
class PhotoprofileSeeder extends Seeder
|
||||||
|
{
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
$profiles = [
|
||||||
|
[
|
||||||
|
'name' => 'Comic',
|
||||||
|
'active' => true,
|
||||||
|
'commands' => 'simplelocalcontrast_p 16,2,0,1,1,1,1,1,1,1,1,0
|
||||||
|
cl_comic 4,1,0,0,1,15,15,1,10,20,6,2,0,0,0,0,0,0,50,50',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Edges',
|
||||||
|
'active' => true,
|
||||||
|
'commands' => 'fx_canny 5,0.05,0.15,1',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Tron',
|
||||||
|
'active' => true,
|
||||||
|
'commands' => 'samj_chalkitup 5,2.5,1.5,50,1,5,5,0,0,7,0.8,1.9,7,0',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Warhol',
|
||||||
|
'active' => true,
|
||||||
|
'commands' => 'warhol 3,3,2,40',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'SW-Comic',
|
||||||
|
'active' => true,
|
||||||
|
'commands' => 'simplelocalcontrast_p 16,2,0,1,1,1,1,1,1,1,1,0
|
||||||
|
cl_lineart 0,0,2,1,15,15,1,0,6,2,2,0,0,0,50,50',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Neon',
|
||||||
|
'active' => true,
|
||||||
|
'commands' => 'fx_gradient2rgb 0.58,0,5.8,0,0',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Neon 2',
|
||||||
|
'active' => true,
|
||||||
|
'commands' => 'fx_gcd_canny 1,0.05,0.15',
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($profiles as $profile) {
|
||||||
|
Photoprofile::firstOrCreate(['name' => $profile['name']], $profile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
31
database/seeders/UserSeeder.php
Normal file
31
database/seeders/UserSeeder.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
|
||||||
|
class UserSeeder extends Seeder
|
||||||
|
{
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
User::firstOrCreate(
|
||||||
|
['email' => 'admin@fotobox.local'],
|
||||||
|
[
|
||||||
|
'name' => 'Admin',
|
||||||
|
'password' => Hash::make('admin'),
|
||||||
|
'is_admin' => true,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
User::firstOrCreate(
|
||||||
|
['email' => 'user@fotobox.local'],
|
||||||
|
[
|
||||||
|
'name' => 'User',
|
||||||
|
'password' => Hash::make('user'),
|
||||||
|
'is_admin' => false,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
39
docker-compose.yml
Normal file
39
docker-compose.yml
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
services:
|
||||||
|
init:
|
||||||
|
build: .
|
||||||
|
command: sh docker/init.sh
|
||||||
|
env_file: .env
|
||||||
|
volumes:
|
||||||
|
- .:/app
|
||||||
|
|
||||||
|
app:
|
||||||
|
build: .
|
||||||
|
command: php artisan serve --host=0.0.0.0 --port=8000
|
||||||
|
env_file: .env
|
||||||
|
ports:
|
||||||
|
- "8000:8000"
|
||||||
|
volumes:
|
||||||
|
- .:/app
|
||||||
|
depends_on:
|
||||||
|
init:
|
||||||
|
condition: service_completed_successfully
|
||||||
|
|
||||||
|
scheduler:
|
||||||
|
build: .
|
||||||
|
command: php artisan schedule:work
|
||||||
|
env_file: .env
|
||||||
|
volumes:
|
||||||
|
- .:/app
|
||||||
|
depends_on:
|
||||||
|
init:
|
||||||
|
condition: service_completed_successfully
|
||||||
|
|
||||||
|
worker:
|
||||||
|
build: .
|
||||||
|
command: php artisan queue:work --tries=3
|
||||||
|
env_file: .env
|
||||||
|
volumes:
|
||||||
|
- .:/app
|
||||||
|
depends_on:
|
||||||
|
init:
|
||||||
|
condition: service_completed_successfully
|
||||||
39
docker/init.sh
Executable file
39
docker/init.sh
Executable file
@ -0,0 +1,39 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ "$(whoami)" != "root" ]; then
|
||||||
|
SUDO=sudo
|
||||||
|
fi
|
||||||
|
|
||||||
|
${SUDO} apt-get update
|
||||||
|
${SUDO} apt-get -y install lsb-release ca-certificates curl
|
||||||
|
${SUDO} curl -sSLo /tmp/debsuryorg-archive-keyring.deb https://packages.sury.org/debsuryorg-archive-keyring.deb
|
||||||
|
${SUDO} dpkg -i /tmp/debsuryorg-archive-keyring.deb
|
||||||
|
${SUDO} sh -c 'echo "deb [signed-by=/usr/share/keyrings/debsuryorg-archive-keyring.gpg] https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list'
|
||||||
|
${SUDO} apt-get update
|
||||||
|
|
||||||
|
apt-get update
|
||||||
|
apt-get -y install php8.5 php8.5-cli php8.5-zip php8.5-sqlite3 php8.5-xml php8.5-pgsql php8.5-bcmath php8.5-intl php8.5-mbstring sqlite3 composer npm
|
||||||
|
curl -fsSL -o gmic.deb "https://gmic.eu/get_file.php?file=linux/gmic_3.7.6_debian13_trixie_amd64.deb"
|
||||||
|
apt-get -y install ./gmic.deb
|
||||||
|
rm gmic.deb
|
||||||
|
|
||||||
|
echo "==> Installing Composer dependencies..."
|
||||||
|
composer install --no-interaction --prefer-dist --optimize-autoloader
|
||||||
|
|
||||||
|
echo "==> Installing npm dependencies..."
|
||||||
|
npm install
|
||||||
|
|
||||||
|
echo "==> Building frontend assets..."
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# Create SQLite database file if it doesn't exist yet
|
||||||
|
[ -f database/database.sqlite ] || touch database/database.sqlite
|
||||||
|
|
||||||
|
echo "==> Running database migrations..."
|
||||||
|
php artisan migrate --force
|
||||||
|
|
||||||
|
echo "==> Linking storage..."
|
||||||
|
php artisan storage:link --force 2>/dev/null || true
|
||||||
|
|
||||||
|
echo "==> Init complete."
|
||||||
352
package-lock.json
generated
352
package-lock.json
generated
@ -16,21 +16,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@emnapi/core": {
|
"node_modules/@emnapi/core": {
|
||||||
"version": "1.10.0",
|
"version": "1.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz",
|
||||||
"integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
|
"integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emnapi/wasi-threads": "1.2.1",
|
"@emnapi/wasi-threads": "1.2.2",
|
||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@emnapi/runtime": {
|
"node_modules/@emnapi/runtime": {
|
||||||
"version": "1.10.0",
|
"version": "1.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz",
|
||||||
"integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
|
"integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
@ -39,9 +39,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@emnapi/wasi-threads": {
|
"node_modules/@emnapi/wasi-threads": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz",
|
||||||
"integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
|
"integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
@ -100,14 +100,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@napi-rs/wasm-runtime": {
|
"node_modules/@napi-rs/wasm-runtime": {
|
||||||
"version": "1.1.4",
|
"version": "1.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz",
|
||||||
"integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==",
|
"integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tybys/wasm-util": "^0.10.1"
|
"@tybys/wasm-util": "^0.10.3"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@ -119,9 +119,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@oxc-project/types": {
|
"node_modules/@oxc-project/types": {
|
||||||
"version": "0.132.0",
|
"version": "0.137.0",
|
||||||
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.132.0.tgz",
|
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.137.0.tgz",
|
||||||
"integrity": "sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==",
|
"integrity": "sha512-WT+Gb24i8hmvo85AIv2oEYouEXkRlKAlT9WaCa3TfLgNCN+GhrJOGZuIlMouAh38Qe4QOx26eUOVsq70qXrywA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
@ -129,9 +129,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-android-arm64": {
|
"node_modules/@rolldown/binding-android-arm64": {
|
||||||
"version": "1.0.2",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.3.tgz",
|
||||||
"integrity": "sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ==",
|
"integrity": "sha512-DT6Z3PhvioeHMvxo+xHc3KtqggrI7CCTXCmC2h/5zUlp5jVitv7XEy+9q5/7v8IolhlioawpMo8Kg0EEBy7J0g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -146,9 +146,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-darwin-arm64": {
|
"node_modules/@rolldown/binding-darwin-arm64": {
|
||||||
"version": "1.0.2",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.3.tgz",
|
||||||
"integrity": "sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==",
|
"integrity": "sha512-0NwgwsjM7LrsuVnXMK3koTpagBNOhloc/BNjKqZjv4V5zI5r13qx69uVhRx+o5Z0yy4Hzq+lpy7TAgUG/ocvrw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -163,9 +163,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-darwin-x64": {
|
"node_modules/@rolldown/binding-darwin-x64": {
|
||||||
"version": "1.0.2",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.3.tgz",
|
||||||
"integrity": "sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==",
|
"integrity": "sha512-YtiBp4disu6V560loT6PjMdiRaWmVvDNrUunAalbiFx2ggeJwxdAsgZMcoGP17uyAsTwAj5V1niksxlHnVQ1Sw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -180,9 +180,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-freebsd-x64": {
|
"node_modules/@rolldown/binding-freebsd-x64": {
|
||||||
"version": "1.0.2",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.3.tgz",
|
||||||
"integrity": "sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==",
|
"integrity": "sha512-yD3EkEdXk2LypPxnf/kSZHirarsI8gcPzc62SukhR9VJTyvV+F9Q/GxWNuCojc7sXyuVC4DxRGhdDK4X8VSsbw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -197,9 +197,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
|
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
|
||||||
"version": "1.0.2",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.3.tgz",
|
||||||
"integrity": "sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==",
|
"integrity": "sha512-c+8vieQbsD7HNAHKIA34w0GJ9FedFFuJGD+7E6vz7Q3uqAIugL5p45fhlsj4UaAsHpcmlqugBWMhA0/j7o0sIg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@ -214,9 +214,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-arm64-gnu": {
|
"node_modules/@rolldown/binding-linux-arm64-gnu": {
|
||||||
"version": "1.0.2",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.3.tgz",
|
||||||
"integrity": "sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==",
|
"integrity": "sha512-50jD0uUwLvur7Zz9LHz17kaAdTPjn5wN93hEgjvmYFRZwiR7ZJYovTd5ipyWJDAnXKvZ+wgc+/Ika6dwSF5OcA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -231,9 +231,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-arm64-musl": {
|
"node_modules/@rolldown/binding-linux-arm64-musl": {
|
||||||
"version": "1.0.2",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.3.tgz",
|
||||||
"integrity": "sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==",
|
"integrity": "sha512-BO9+oPL8K9poZJBfYPsXNtYjPE5uM3qeehT3aFcW4LITOl+iSqhp0abzjR2nWBUNjIZeKXjAEWBZ64WjNoHd6w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -248,9 +248,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
|
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
|
||||||
"version": "1.0.2",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.3.tgz",
|
||||||
"integrity": "sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==",
|
"integrity": "sha512-f3VpLB1vQ0Eo6ecr/6cekLnvYMFF4YBFoVGkfkvPLq1bAkbAwHYQPZKoAmG6OJyTcxxoC+AvezGx/S1obNC0Mw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
@ -265,9 +265,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-s390x-gnu": {
|
"node_modules/@rolldown/binding-linux-s390x-gnu": {
|
||||||
"version": "1.0.2",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.3.tgz",
|
||||||
"integrity": "sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==",
|
"integrity": "sha512-AmurZ26Pqx/RI9N1gzEOCklkKXl927yjfXWUUS0O7Puh8ARM/Ob8qfrD3qnWksScdw6cSrW5PSHE9DyLu7+PtA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
@ -282,9 +282,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-x64-gnu": {
|
"node_modules/@rolldown/binding-linux-x64-gnu": {
|
||||||
"version": "1.0.2",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.3.tgz",
|
||||||
"integrity": "sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==",
|
"integrity": "sha512-JJpqs8bRGITDOdbkNKnlojzBabbOHrqjSvDr0IVsZObE1lBcPjxItUEY9eWIDbxaJ3cGrXPWGfGkIxFijg/URg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -299,9 +299,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-x64-musl": {
|
"node_modules/@rolldown/binding-linux-x64-musl": {
|
||||||
"version": "1.0.2",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.3.tgz",
|
||||||
"integrity": "sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==",
|
"integrity": "sha512-rSJcdjPxzA/by/6/rYs+v+bXU7UjvnbUWz8MJb6kh6+knqB1dCrtHg0uu7C/4haqJvqdkYHQ5IGn+tCH9GLW/g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -316,9 +316,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-openharmony-arm64": {
|
"node_modules/@rolldown/binding-openharmony-arm64": {
|
||||||
"version": "1.0.2",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.3.tgz",
|
||||||
"integrity": "sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==",
|
"integrity": "sha512-hQ3/PYkDJICgevvyNcVrihVeqq7k1Pp3VZ9lY+dauAYUJKO+auqApvANhvR1An9BhmqYKvW2Mu1F9u4DXSMLxQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -333,9 +333,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-wasm32-wasi": {
|
"node_modules/@rolldown/binding-wasm32-wasi": {
|
||||||
"version": "1.0.2",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.3.tgz",
|
||||||
"integrity": "sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==",
|
"integrity": "sha512-Elcv/BtML9lXrV6JuKITc/grN2kYV9gjsQpW8Jfw4ioK0TOkjBjye0nnyqQNy9STNaI20lXNaQBRrD5gSgR0Yg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"wasm32"
|
"wasm32"
|
||||||
],
|
],
|
||||||
@ -343,18 +343,18 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emnapi/core": "1.10.0",
|
"@emnapi/core": "1.11.1",
|
||||||
"@emnapi/runtime": "1.10.0",
|
"@emnapi/runtime": "1.11.1",
|
||||||
"@napi-rs/wasm-runtime": "^1.1.4"
|
"@napi-rs/wasm-runtime": "^1.1.6"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^20.19.0 || >=22.12.0"
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-win32-arm64-msvc": {
|
"node_modules/@rolldown/binding-win32-arm64-msvc": {
|
||||||
"version": "1.0.2",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.3.tgz",
|
||||||
"integrity": "sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==",
|
"integrity": "sha512-2DrEfhluH9yhiaFApmsjsjwrSYbNcY1oFTzYSP1a535jDbV98zCFanA/96TBUd0iDFcxGmw9QRExwGCXz3U+/g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -369,9 +369,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-win32-x64-msvc": {
|
"node_modules/@rolldown/binding-win32-x64-msvc": {
|
||||||
"version": "1.0.2",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.3.tgz",
|
||||||
"integrity": "sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==",
|
"integrity": "sha512-OL4OMk7UPXOeVGGd3qo5zJyPIljf4AFgk5QAkPPS+OoLuOOozhuaQGC18MxVTnw/06q93gShAJzlwnSCY9YtqA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -393,49 +393,49 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/node": {
|
"node_modules/@tailwindcss/node": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.1.tgz",
|
||||||
"integrity": "sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==",
|
"integrity": "sha512-6NDaqRoAMSXD1mr/RXu0HBvNE9a2n5tHPsxu9XHLws8o4Twes5rBM2205SUUiJ9goAtadrN6xTGX0UDEwp/N4A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/remapping": "^2.3.5",
|
"@jridgewell/remapping": "^2.3.5",
|
||||||
"enhanced-resolve": "^5.21.0",
|
"enhanced-resolve": "5.21.6",
|
||||||
"jiti": "^2.6.1",
|
"jiti": "^2.7.0",
|
||||||
"lightningcss": "1.32.0",
|
"lightningcss": "1.32.0",
|
||||||
"magic-string": "^0.30.21",
|
"magic-string": "^0.30.21",
|
||||||
"source-map-js": "^1.2.1",
|
"source-map-js": "^1.2.1",
|
||||||
"tailwindcss": "4.3.0"
|
"tailwindcss": "4.3.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/oxide": {
|
"node_modules/@tailwindcss/oxide": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.1.tgz",
|
||||||
"integrity": "sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==",
|
"integrity": "sha512-yVPyo8RNkabVr3O2EhHEE0Rewu7YKzc1DhIqfL46LKveFrmu9XbDazNOJY7/GRuvw1h6u3utWnR29H/p5JPlgA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 20"
|
"node": ">= 20"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@tailwindcss/oxide-android-arm64": "4.3.0",
|
"@tailwindcss/oxide-android-arm64": "4.3.1",
|
||||||
"@tailwindcss/oxide-darwin-arm64": "4.3.0",
|
"@tailwindcss/oxide-darwin-arm64": "4.3.1",
|
||||||
"@tailwindcss/oxide-darwin-x64": "4.3.0",
|
"@tailwindcss/oxide-darwin-x64": "4.3.1",
|
||||||
"@tailwindcss/oxide-freebsd-x64": "4.3.0",
|
"@tailwindcss/oxide-freebsd-x64": "4.3.1",
|
||||||
"@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.0",
|
"@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.1",
|
||||||
"@tailwindcss/oxide-linux-arm64-gnu": "4.3.0",
|
"@tailwindcss/oxide-linux-arm64-gnu": "4.3.1",
|
||||||
"@tailwindcss/oxide-linux-arm64-musl": "4.3.0",
|
"@tailwindcss/oxide-linux-arm64-musl": "4.3.1",
|
||||||
"@tailwindcss/oxide-linux-x64-gnu": "4.3.0",
|
"@tailwindcss/oxide-linux-x64-gnu": "4.3.1",
|
||||||
"@tailwindcss/oxide-linux-x64-musl": "4.3.0",
|
"@tailwindcss/oxide-linux-x64-musl": "4.3.1",
|
||||||
"@tailwindcss/oxide-wasm32-wasi": "4.3.0",
|
"@tailwindcss/oxide-wasm32-wasi": "4.3.1",
|
||||||
"@tailwindcss/oxide-win32-arm64-msvc": "4.3.0",
|
"@tailwindcss/oxide-win32-arm64-msvc": "4.3.1",
|
||||||
"@tailwindcss/oxide-win32-x64-msvc": "4.3.0"
|
"@tailwindcss/oxide-win32-x64-msvc": "4.3.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/oxide-android-arm64": {
|
"node_modules/@tailwindcss/oxide-android-arm64": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.1.tgz",
|
||||||
"integrity": "sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==",
|
"integrity": "sha512-SVlyf61g374l5cHyg8x9kf5xmLcOaxvOTsbsqDnSsDJaKOEFZ7GCvi84VAVGpxojYOs1+3K6M0UjXfqPU8vmOQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -450,9 +450,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/oxide-darwin-arm64": {
|
"node_modules/@tailwindcss/oxide-darwin-arm64": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.1.tgz",
|
||||||
"integrity": "sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==",
|
"integrity": "sha512-hVnWLwv+e/l7c4WKyVtHVrIPvYdqWHjRB3MDIqARynzFtnQg85kmQEFCbV9Ja0VVx4xXTIiDWY60Y7iz/iNoDA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -467,9 +467,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/oxide-darwin-x64": {
|
"node_modules/@tailwindcss/oxide-darwin-x64": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.1.tgz",
|
||||||
"integrity": "sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==",
|
"integrity": "sha512-Cf7abu0WVgbhU7ANgPUnSAvm7nCvMweusHb8FnaHlLfv/Caq4GYaEZg7ZImzzmjx4lIAfuS8q+eLIS7A7IzxIg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -484,9 +484,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/oxide-freebsd-x64": {
|
"node_modules/@tailwindcss/oxide-freebsd-x64": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.1.tgz",
|
||||||
"integrity": "sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==",
|
"integrity": "sha512-ZZqzX2Y+GXtXXfqSfpJhDm60OoZfvLHLCgm+J7NVqgHHJjG/m9ugZI77RwTsVd4fnBJuCFP6Ae6kTJb71UdS8g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -501,9 +501,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
|
"node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.1.tgz",
|
||||||
"integrity": "sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==",
|
"integrity": "sha512-/Ah/xik0LaMYfv9DZ0S/t4pBlBNYOcqtRwusjgovHkvT8ixueWCLyJjsaF5kQIckjb4IT8Q6K6p/iPmZMixYgg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@ -518,9 +518,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
|
"node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.1.tgz",
|
||||||
"integrity": "sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==",
|
"integrity": "sha512-gqdFoVJlw444GvpnheZLHmvTzSxI/cOUUh2KSNejQjTcYkW062SVD+En0rUgD+QV91bz1XGIGtt1HJd48xUGbQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -535,9 +535,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/oxide-linux-arm64-musl": {
|
"node_modules/@tailwindcss/oxide-linux-arm64-musl": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.1.tgz",
|
||||||
"integrity": "sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==",
|
"integrity": "sha512-Bwv9KwOvE0VKa86xPFif9b9c3Y1NxOV1P0gLti/IYaWEsQYZXDlxfGEtA8mdDZ7SG3wyNXAWYT5SIn3giL57oA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -552,9 +552,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/oxide-linux-x64-gnu": {
|
"node_modules/@tailwindcss/oxide-linux-x64-gnu": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.1.tgz",
|
||||||
"integrity": "sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==",
|
"integrity": "sha512-Ymi8O8T15HYQdOUWUtTI6ldN0neHP85FC+Qz32xTcZ7iJXtem/x8ITev0o1e9e5rkqj4lONZfTRLvkmin1+tKg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -569,9 +569,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/oxide-linux-x64-musl": {
|
"node_modules/@tailwindcss/oxide-linux-x64-musl": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.1.tgz",
|
||||||
"integrity": "sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==",
|
"integrity": "sha512-M+P/91qJ6uILLw4k2G93GMDRAXj61SMvFQYt39AqvUqYgExXpLL5aepfns7sj4HiAQeolirQF9E0lzRvdf4zPQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -586,9 +586,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/oxide-wasm32-wasi": {
|
"node_modules/@tailwindcss/oxide-wasm32-wasi": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.1.tgz",
|
||||||
"integrity": "sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==",
|
"integrity": "sha512-zsM8uOeqvVGHsAXsJxsT28ttosFahLJKCLOTUBqRAtKnVgGSRitds9T432QiT8b77Yga7JIBkulIRRlJPtYhRA==",
|
||||||
"bundleDependencies": [
|
"bundleDependencies": [
|
||||||
"@napi-rs/wasm-runtime",
|
"@napi-rs/wasm-runtime",
|
||||||
"@emnapi/core",
|
"@emnapi/core",
|
||||||
@ -608,7 +608,7 @@
|
|||||||
"@emnapi/runtime": "^1.10.0",
|
"@emnapi/runtime": "^1.10.0",
|
||||||
"@emnapi/wasi-threads": "^1.2.1",
|
"@emnapi/wasi-threads": "^1.2.1",
|
||||||
"@napi-rs/wasm-runtime": "^1.1.4",
|
"@napi-rs/wasm-runtime": "^1.1.4",
|
||||||
"@tybys/wasm-util": "^0.10.1",
|
"@tybys/wasm-util": "^0.10.2",
|
||||||
"tslib": "^2.8.1"
|
"tslib": "^2.8.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -616,9 +616,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
|
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.1.tgz",
|
||||||
"integrity": "sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==",
|
"integrity": "sha512-aiNvSq9BsVk8V513lDKlrCFAgf8qBMPZTpgEhInL+NwQqs97mYmupVMrPrgBBSL8Pv/0zXu9MrMF9rMun1ZeNg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -633,9 +633,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/oxide-win32-x64-msvc": {
|
"node_modules/@tailwindcss/oxide-win32-x64-msvc": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.1.tgz",
|
||||||
"integrity": "sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==",
|
"integrity": "sha512-xDEyu1rg290472FEGaKHnzyDyh5QH+AlWvsU5hMoMtPpzmKlRI0jaYKCgSHDYtaQWZOYbMaduSyCwFwY4n1HmA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -650,24 +650,24 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tailwindcss/vite": {
|
"node_modules/@tailwindcss/vite": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.1.tgz",
|
||||||
"integrity": "sha512-t6J3OrB5Fc0ExuhohouH0fWUGMYL6PTLhW+E7zIk/pdbnJARZDCwjBznFnkh5ynRnIRSI4YjtTH0t6USjJISrw==",
|
"integrity": "sha512-hItDHuIIlEV61R+faXu66s1K36aTurO/Qw0e45Vskz57gXl9pWOT6eg3zmcEui6CZXddbN7zd41bwmvag4JGwQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tailwindcss/node": "4.3.0",
|
"@tailwindcss/node": "4.3.1",
|
||||||
"@tailwindcss/oxide": "4.3.0",
|
"@tailwindcss/oxide": "4.3.1",
|
||||||
"tailwindcss": "4.3.0"
|
"tailwindcss": "4.3.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"vite": "^5.2.0 || ^6 || ^7 || ^8"
|
"vite": "^5.2.0 || ^6 || ^7 || ^8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tybys/wasm-util": {
|
"node_modules/@tybys/wasm-util": {
|
||||||
"version": "0.10.2",
|
"version": "0.10.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz",
|
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz",
|
||||||
"integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==",
|
"integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
@ -772,15 +772,15 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/concurrently": {
|
"node_modules/concurrently": {
|
||||||
"version": "9.2.1",
|
"version": "9.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.3.tgz",
|
||||||
"integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==",
|
"integrity": "sha512-ihjs0E2SxvDgq/MK418hX6YycQgKhsqxpbZuZbHo0yKfqDWdymWMjWYIpCIzqDDLLKClHlXev8whW/8WXmJ0BA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chalk": "4.1.2",
|
"chalk": "4.1.2",
|
||||||
"rxjs": "7.8.2",
|
"rxjs": "7.8.2",
|
||||||
"shell-quote": "1.8.3",
|
"shell-quote": "1.8.4",
|
||||||
"supports-color": "8.1.1",
|
"supports-color": "8.1.1",
|
||||||
"tree-kill": "1.2.2",
|
"tree-kill": "1.2.2",
|
||||||
"yargs": "17.7.2"
|
"yargs": "17.7.2"
|
||||||
@ -828,9 +828,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/enhanced-resolve": {
|
"node_modules/enhanced-resolve": {
|
||||||
"version": "5.22.0",
|
"version": "5.21.6",
|
||||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.22.0.tgz",
|
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.6.tgz",
|
||||||
"integrity": "sha512-xYcDWrpELkFzz9SpZ3PlI6Eu6eD93Yf0WLDRxikGhWJ3MAir2SNZTIVCVZqZ/NUyx8AdMc2gT9C0gPiw18kG+A==",
|
"integrity": "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -1253,9 +1253,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
"version": "3.3.12",
|
"version": "3.3.15",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz",
|
||||||
"integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
|
"integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -1473,13 +1473,13 @@
|
|||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/rolldown": {
|
"node_modules/rolldown": {
|
||||||
"version": "1.0.2",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.3.tgz",
|
||||||
"integrity": "sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g==",
|
"integrity": "sha512-1F1eEtUBtFvcGm1HQ9TiUIUHPQG7mSAODrhIzjxoUEFuo8OcbrGLiVLkevNgj84TE4lnHvnumwFjhJO5Eu135g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@oxc-project/types": "=0.132.0",
|
"@oxc-project/types": "=0.137.0",
|
||||||
"@rolldown/pluginutils": "^1.0.0"
|
"@rolldown/pluginutils": "^1.0.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
@ -1489,21 +1489,21 @@
|
|||||||
"node": "^20.19.0 || >=22.12.0"
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@rolldown/binding-android-arm64": "1.0.2",
|
"@rolldown/binding-android-arm64": "1.1.3",
|
||||||
"@rolldown/binding-darwin-arm64": "1.0.2",
|
"@rolldown/binding-darwin-arm64": "1.1.3",
|
||||||
"@rolldown/binding-darwin-x64": "1.0.2",
|
"@rolldown/binding-darwin-x64": "1.1.3",
|
||||||
"@rolldown/binding-freebsd-x64": "1.0.2",
|
"@rolldown/binding-freebsd-x64": "1.1.3",
|
||||||
"@rolldown/binding-linux-arm-gnueabihf": "1.0.2",
|
"@rolldown/binding-linux-arm-gnueabihf": "1.1.3",
|
||||||
"@rolldown/binding-linux-arm64-gnu": "1.0.2",
|
"@rolldown/binding-linux-arm64-gnu": "1.1.3",
|
||||||
"@rolldown/binding-linux-arm64-musl": "1.0.2",
|
"@rolldown/binding-linux-arm64-musl": "1.1.3",
|
||||||
"@rolldown/binding-linux-ppc64-gnu": "1.0.2",
|
"@rolldown/binding-linux-ppc64-gnu": "1.1.3",
|
||||||
"@rolldown/binding-linux-s390x-gnu": "1.0.2",
|
"@rolldown/binding-linux-s390x-gnu": "1.1.3",
|
||||||
"@rolldown/binding-linux-x64-gnu": "1.0.2",
|
"@rolldown/binding-linux-x64-gnu": "1.1.3",
|
||||||
"@rolldown/binding-linux-x64-musl": "1.0.2",
|
"@rolldown/binding-linux-x64-musl": "1.1.3",
|
||||||
"@rolldown/binding-openharmony-arm64": "1.0.2",
|
"@rolldown/binding-openharmony-arm64": "1.1.3",
|
||||||
"@rolldown/binding-wasm32-wasi": "1.0.2",
|
"@rolldown/binding-wasm32-wasi": "1.1.3",
|
||||||
"@rolldown/binding-win32-arm64-msvc": "1.0.2",
|
"@rolldown/binding-win32-arm64-msvc": "1.1.3",
|
||||||
"@rolldown/binding-win32-x64-msvc": "1.0.2"
|
"@rolldown/binding-win32-x64-msvc": "1.1.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rxjs": {
|
"node_modules/rxjs": {
|
||||||
@ -1523,9 +1523,9 @@
|
|||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/shell-quote": {
|
"node_modules/shell-quote": {
|
||||||
"version": "1.8.3",
|
"version": "1.8.4",
|
||||||
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.4.tgz",
|
||||||
"integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==",
|
"integrity": "sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -1588,9 +1588,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tailwindcss": {
|
"node_modules/tailwindcss": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.1.tgz",
|
||||||
"integrity": "sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==",
|
"integrity": "sha512-hk+TB1m+K8CYNrP6rjQaq/Y+4Zylwpa87mLYBKCunwnnQ9p+fHb7kmSfGqyEJoxF/O6CDyABWVFEafNSYKll+Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
@ -1609,9 +1609,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tinyglobby": {
|
"node_modules/tinyglobby": {
|
||||||
"version": "0.2.16",
|
"version": "0.2.17",
|
||||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
|
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
|
||||||
"integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
|
"integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -1643,17 +1643,17 @@
|
|||||||
"license": "0BSD"
|
"license": "0BSD"
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "8.0.14",
|
"version": "8.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.14.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-8.1.0.tgz",
|
||||||
"integrity": "sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw==",
|
"integrity": "sha512-BuJcQK/56NQTWDGn4ABea3q4SSBdNPWwNZKTkkUpcMPnLoquSYH8llRtSUIgoL1KSCpHt5eghLShn50mH36y7Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lightningcss": "^1.32.0",
|
"lightningcss": "^1.32.0",
|
||||||
"picomatch": "^4.0.4",
|
"picomatch": "^4.0.4",
|
||||||
"postcss": "^8.5.15",
|
"postcss": "^8.5.15",
|
||||||
"rolldown": "1.0.2",
|
"rolldown": "~1.1.2",
|
||||||
"tinyglobby": "^0.2.16"
|
"tinyglobby": "^0.2.17"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"vite": "bin/vite.js"
|
"vite": "bin/vite.js"
|
||||||
@ -1669,7 +1669,7 @@
|
|||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/node": "^20.19.0 || >=22.12.0",
|
"@types/node": "^20.19.0 || >=22.12.0",
|
||||||
"@vitejs/devtools": "^0.1.18",
|
"@vitejs/devtools": "^0.3.0",
|
||||||
"esbuild": "^0.27.0 || ^0.28.0",
|
"esbuild": "^0.27.0 || ^0.28.0",
|
||||||
"jiti": ">=1.21.0",
|
"jiti": ">=1.21.0",
|
||||||
"less": "^4.0.0",
|
"less": "^4.0.0",
|
||||||
|
|||||||
45
resources/views/auth/login.blade.php
Normal file
45
resources/views/auth/login.blade.php
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Fotobox – Anmelden</title>
|
||||||
|
@if (file_exists(public_path('build/manifest.json')) || file_exists(public_path('hot')))
|
||||||
|
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||||
|
@endif
|
||||||
|
</head>
|
||||||
|
<body class="bg-gray-950 text-white min-h-screen flex flex-col items-center justify-center p-6">
|
||||||
|
|
||||||
|
<h1 class="text-3xl font-bold mb-8 tracking-wide">Fotobox</h1>
|
||||||
|
|
||||||
|
<form method="POST" action="{{ route('login') }}" class="w-full max-w-sm flex flex-col gap-4">
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<label for="email" class="text-sm text-gray-400">E-Mail</label>
|
||||||
|
<input id="email" type="email" name="email" value="{{ old('email') }}" required autofocus
|
||||||
|
class="rounded-xl bg-white/10 border border-white/20 px-4 py-3 text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-white/40">
|
||||||
|
@error('email')
|
||||||
|
<span class="text-sm text-red-400">{{ $message }}</span>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<label for="password" class="text-sm text-gray-400">Passwort</label>
|
||||||
|
<input id="password" type="password" name="password" required
|
||||||
|
class="rounded-xl bg-white/10 border border-white/20 px-4 py-3 text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-white/40">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label class="flex items-center gap-2 text-sm text-gray-400 cursor-pointer">
|
||||||
|
<input type="checkbox" name="remember" class="rounded">
|
||||||
|
Angemeldet bleiben
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<button type="submit"
|
||||||
|
class="mt-2 px-10 py-4 bg-white text-gray-950 font-semibold text-lg rounded-full shadow-lg hover:bg-gray-200 active:scale-95 transition-all duration-150">
|
||||||
|
Anmelden
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -9,11 +9,13 @@
|
|||||||
@endif
|
@endif
|
||||||
@livewireStyles
|
@livewireStyles
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-gray-950 text-white min-h-screen flex flex-col items-center justify-center p-6">
|
<body class="bg-gray-950 text-white h-screen flex flex-col items-center p-6 overflow-hidden">
|
||||||
|
|
||||||
<h1 class="text-3xl font-bold mb-8 tracking-wide">Fotobox</h1>
|
<h1 class="shrink-0 text-3xl font-bold mb-8 tracking-wide">Fotobox</h1>
|
||||||
|
|
||||||
|
<div class="flex-1 min-h-0 w-full flex flex-col items-center">
|
||||||
@livewire('camera-capture')
|
@livewire('camera-capture')
|
||||||
|
</div>
|
||||||
|
|
||||||
@livewireScripts
|
@livewireScripts
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
<div class="flex flex-col items-center w-full"
|
<div class="flex flex-col items-center w-full h-full"
|
||||||
x-data="{ lightbox: null }"
|
x-data="{ lightbox: null }"
|
||||||
x-on:keydown.escape.window="lightbox = null">
|
x-on:keydown.escape.window="lightbox = null">
|
||||||
|
|
||||||
<div class="relative w-full max-w-7xl">
|
<div class="flex-1 min-h-0 w-full flex justify-center">
|
||||||
|
<div class="relative h-full" style="aspect-ratio: 16/9; max-width: 100%;">
|
||||||
<video id="video" autoplay playsinline
|
<video id="video" autoplay playsinline
|
||||||
class="w-full rounded-2xl shadow-2xl bg-gray-900 aspect-video object-cover" style="transform: scaleX(-1);"></video>
|
class="w-full h-full rounded-2xl shadow-2xl bg-gray-900" style="transform: scaleX(-1);"></video>
|
||||||
|
|
||||||
<canvas id="canvas" class="hidden"></canvas>
|
<canvas id="canvas" class="hidden"></canvas>
|
||||||
|
|
||||||
@ -14,19 +15,29 @@
|
|||||||
<span id="countdown-num" class="text-white font-bold drop-shadow-lg" style="font-size: 8rem; line-height: 1;"></span>
|
<span id="countdown-num" class="text-white font-bold drop-shadow-lg" style="font-size: 8rem; line-height: 1;"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="shrink-0 mt-6 w-full max-w-xs">
|
||||||
|
<select wire:model="photoprofileId"
|
||||||
|
class="w-full rounded-full bg-black/50 text-white border border-white/20 px-5 py-3 text-sm focus:outline-none focus:ring-2 focus:ring-white/40 appearance-none text-center">
|
||||||
|
@foreach ($photoprofiles as $id => $name)
|
||||||
|
<option value="{{ $id }}">{{ $name }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button id="capture-btn"
|
<button id="capture-btn"
|
||||||
wire:loading.attr="disabled"
|
wire:loading.attr="disabled"
|
||||||
@disabled($hasProcessing)
|
@disabled($hasProcessing)
|
||||||
class="mt-8 px-10 py-4 bg-white text-gray-950 font-semibold text-lg rounded-full shadow-lg hover:bg-gray-200 active:scale-95 transition-all duration-150 disabled:opacity-50 disabled:cursor-not-allowed">
|
class="shrink-0 mt-8 px-10 py-4 bg-white text-gray-950 font-semibold text-lg rounded-full shadow-lg hover:bg-gray-200 active:scale-95 transition-all duration-150 disabled:opacity-50 disabled:cursor-not-allowed">
|
||||||
<span wire:loading.remove>{{ $hasProcessing ? 'Erstelle Bild...' : 'Foto aufnehmen' }}</span>
|
<span wire:loading.remove>{{ $hasProcessing ? 'Erstelle Bild...' : 'Foto aufnehmen' }}</span>
|
||||||
<span wire:loading>Saving…</span>
|
<span wire:loading>Saving…</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div class="mt-4 text-sm text-gray-400 h-6">{{ $status }}</div>
|
<div class="shrink-0 mt-4 text-sm text-gray-400 h-6">{{ $status }}</div>
|
||||||
|
|
||||||
@if ($recentPhotos->isNotEmpty())
|
@if ($recentPhotos->isNotEmpty())
|
||||||
<div class="mt-10 w-full max-w-2xl">
|
<div class="shrink-0 mt-10 w-full max-w-2xl">
|
||||||
<h2 class="text-sm font-medium text-gray-400 mb-3 tracking-wide uppercase">Recent Photos</h2>
|
<h2 class="text-sm font-medium text-gray-400 mb-3 tracking-wide uppercase">Recent Photos</h2>
|
||||||
<div class="grid grid-cols-5 gap-2" @if($hasProcessing) wire:poll.2000ms @endif>
|
<div class="grid grid-cols-5 gap-2" @if($hasProcessing) wire:poll.2000ms @endif>
|
||||||
@foreach ($recentPhotos as $photo)
|
@foreach ($recentPhotos as $photo)
|
||||||
@ -95,7 +106,10 @@
|
|||||||
|
|
||||||
async function startCamera() {
|
async function startCamera() {
|
||||||
try {
|
try {
|
||||||
const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: false });
|
const stream = await navigator.mediaDevices.getUserMedia({
|
||||||
|
video: { width: { ideal: 4096 }, height: { ideal: 2160 } },
|
||||||
|
audio: false,
|
||||||
|
});
|
||||||
video.srcObject = stream;
|
video.srcObject = stream;
|
||||||
} catch {
|
} catch {
|
||||||
$wire.set('status', 'Camera access denied or unavailable.');
|
$wire.set('status', 'Camera access denied or unavailable.');
|
||||||
@ -131,7 +145,7 @@
|
|||||||
|
|
||||||
canvas.width = video.videoWidth;
|
canvas.width = video.videoWidth;
|
||||||
canvas.height = video.videoHeight;
|
canvas.height = video.videoHeight;
|
||||||
canvas.getContext('2d').drawImage(video, 0, 0);
|
canvas.getContext('2d').drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
|
||||||
const imageData = canvas.toDataURL('image/jpeg', 0.9);
|
const imageData = canvas.toDataURL('image/jpeg', 0.9);
|
||||||
|
|
||||||
await $wire.capture(imageData);
|
await $wire.capture(imageData);
|
||||||
|
|||||||
@ -2,7 +2,10 @@
|
|||||||
|
|
||||||
use Illuminate\Foundation\Inspiring;
|
use Illuminate\Foundation\Inspiring;
|
||||||
use Illuminate\Support\Facades\Artisan;
|
use Illuminate\Support\Facades\Artisan;
|
||||||
|
use Illuminate\Support\Facades\Schedule;
|
||||||
|
|
||||||
Artisan::command('inspire', function () {
|
Artisan::command('inspire', function () {
|
||||||
$this->comment(Inspiring::quote());
|
$this->comment(Inspiring::quote());
|
||||||
})->purpose('Display an inspiring quote');
|
})->purpose('Display an inspiring quote');
|
||||||
|
|
||||||
|
Schedule::command('photos:cleanup')->hourly();
|
||||||
|
|||||||
@ -1,8 +1,16 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\Http\Controllers\LoginController;
|
||||||
use App\Http\Controllers\PhotoController;
|
use App\Http\Controllers\PhotoController;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
Route::get('/', [PhotoController::class, 'index'])
|
Route::middleware('guest')->group(function () {
|
||||||
->middleware(\App\Http\Middleware\RestrictToSubnet::class)
|
Route::get('/login', [LoginController::class, 'show'])->name('login');
|
||||||
->name('camera');
|
Route::post('/login', [LoginController::class, 'login']);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::post('/logout', [LoginController::class, 'logout'])->name('logout')->middleware('auth');
|
||||||
|
|
||||||
|
Route::middleware('auth')->group(function () {
|
||||||
|
Route::get('/', [PhotoController::class, 'index'])->name('camera');
|
||||||
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user