diff --git a/laravel_app/app/Http/Controllers/DownloadController.php b/laravel_app/app/Http/Controllers/DownloadController.php
index ed72448..774bc5e 100644
--- a/laravel_app/app/Http/Controllers/DownloadController.php
+++ b/laravel_app/app/Http/Controllers/DownloadController.php
@@ -7,7 +7,7 @@
class DownloadController extends Controller
{
public function show() {
- return view('download.show');
+ return view('download.show', ['project' => $project]);
}
//
}
diff --git a/laravel_app/app/Http/Controllers/ProjectController.php b/laravel_app/app/Http/Controllers/ProjectController.php
index ad96032..04c77f7 100644
--- a/laravel_app/app/Http/Controllers/ProjectController.php
+++ b/laravel_app/app/Http/Controllers/ProjectController.php
@@ -16,5 +16,5 @@ public function show(Project $project)
{
return view('projects.show', compact('project'));
}
- //
+
}
diff --git a/laravel_app/app/Http/Controllers/ProjectReportController.php b/laravel_app/app/Http/Controllers/ProjectReportController.php
new file mode 100644
index 0000000..a0a98ca
--- /dev/null
+++ b/laravel_app/app/Http/Controllers/ProjectReportController.php
@@ -0,0 +1,14 @@
+projectReport = $projectReport;
+ //
+ }
+
+ /**
+ * Execute the job.
+ */
+ public function handle(): void
+ {
+ logger('in handle');
+ $this->projectReport->weeksAgo();
+
+ $projectFolder = base_path('../');
+
+ $command = [
+ sprintf('%sbuild_report.sh', $projectFolder),
+ sprintf('--filename=%s', $this->projectReport->getFullPathName()),
+ sprintf('--weeks_ago=%s', $this->projectReport->weeksAgo()),
+ sprintf('--report_date=%s', $this->projectReport->getReportDate()),
+ ];
+
+ // Convert commands array to a single string
+
+ $process = new Process($command);
+ $process->setTimeout(120);
+ $currentPath = '/usr/gnu/bin:/usr/local/bin:/bin:/usr/bin/Users/mfolkerts/anaconda3/bin:/Library/Apple/usr/bin';
+
+ $process->setEnv(['PATH' => $currentPath.':/usr/local/Cellar/pandoc/3.1.8/bin/pandoc']);
+// $process->setTimeout(36000); // stel een geschikte timeout in
+ $process->start();
+ try {
+ $myOutput = [];
+ $process->wait(function ($type, $buffer) use (&$myOutput) {
+// $this->stream(to: 'processOutput', content: $buffer);
+ $myOutput[] = $buffer;
+ logger($buffer);
+ });
+ $this->processOutput = collect($myOutput)->join('\n');
+ $this->projectReport->setStatusSuccess();
+ } catch (ProcessFailedException $exception) {
+ echo $exception->getMessage();
+ $this->projectReport->setStatusFailed();
+ }
+
+ //
+ }
+}
diff --git a/laravel_app/app/Livewire/Download/DownloadGrid.php b/laravel_app/app/Livewire/Download/DownloadGrid.php
index e48695d..c625446 100644
--- a/laravel_app/app/Livewire/Download/DownloadGrid.php
+++ b/laravel_app/app/Livewire/Download/DownloadGrid.php
@@ -2,27 +2,21 @@
namespace App\Livewire\Download;
-use Illuminate\Support\Carbon;
-use Illuminate\Support\Facades\Storage;
+use App\Models\Project;
use Livewire\Component;
class DownloadGrid extends Component
{
- public $directories;
+ private $files = [];
- public function mount()
+ public function mount(Project $project)
{
- $this->directories = collect(Storage::directories('chemba/single_images'))
- ->map(function ($directory) {
- $parts = explode('/', $directory);
- return Carbon::parse(end($parts));
- })->sortByDesc(function ($date, $key) {
- return $date;
- })->values();
+ $this->files = $project->getMosaicList();
+// dd($this->directories);
}
public function render()
{
- return view('livewire.download.download-grid')->with(['directories', $this->directories]);
+ return view('livewire.download.download-grid')->with(['files' => $this->files]);
}
}
diff --git a/laravel_app/app/Livewire/Project/ReportRow.php b/laravel_app/app/Livewire/Project/ReportRow.php
new file mode 100644
index 0000000..a4ae934
--- /dev/null
+++ b/laravel_app/app/Livewire/Project/ReportRow.php
@@ -0,0 +1,24 @@
+report->project->download_path . '/' . $this->report->path;
+
+ if (!Storage::exists($filePath)) {
+ abort(404);
+ }
+
+ return Storage::download($filePath);
+ }
+
+}
diff --git a/laravel_app/app/Livewire/Projects/ReportManager.php b/laravel_app/app/Livewire/Projects/ReportManager.php
index 94c35a6..2bc96bf 100644
--- a/laravel_app/app/Livewire/Projects/ReportManager.php
+++ b/laravel_app/app/Livewire/Projects/ReportManager.php
@@ -2,12 +2,79 @@
namespace App\Livewire\Projects;
+use App\Jobs\ProjectReportGeneratorJob;
+use App\Models\Project;
+use App\Rules\AllMosaicsPresentRule;
use Livewire\Component;
class ReportManager extends Component
{
+ public $formData = [];
+ public $project_id;
+
+ public $showReportModal = false;
+
+ public $listeners = ['refresh' => '$refresh'];
+
+ public function openCreateReportModal()
+ {
+ $this->resetFormData();
+ $this->showReportModal = true;
+ }
+
+ public function mount(Project $project)
+ {
+ $this->project_id = $project->id;
+ }
+
public function render()
{
- return view('livewire.projects.report-manager');
+ $project = Project::find($this->project_id);
+ return view('livewire.projects.report-manager')->with(compact('project'));
+ }
+
+ private function resetFormData()
+ {
+ $this->formData['week'] = now()->weekOfYear;
+ $this->formData['year'] = now()->year;
+ }
+
+ public function saveProjectReport()
+ {
+ sleep(1);
+ $this->validate([
+ 'formData.week' => ['required', 'integer', 'min:1', 'max:53' ],
+ 'formData.year' => 'required|integer|min:2020|max:'.now()->addYear()->year,
+ 'formData' => [new AllMosaicsPresentRule($this->project_id)],
+ ]);
+
+ $newReport = Project::find($this->project_id)
+ ->reports()->create([
+ 'name' => 'Report for week '.$this->formData['week'].' of '.$this->formData['year'],
+ 'week' => $this->formData['week'],
+ 'year' => $this->formData['year'],
+ 'path' => 'reports/week_'.$this->formData['week'].'_'.$this->formData['year'].'.docx',
+ ]);
+
+ ProjectReportGeneratorJob::dispatch($newReport);
+ $this->dispatch('refresh');
+
+ $this->showReportModal = false;
+
+ }
+
+ public function getDateRangeProperty()
+ {
+ if (empty($this->formData['week']) || strlen($this->formData['year']) !== 4) {
+ return 'Invalid week or year';
+ }
+ $begin = now()
+ ->setISODate($this->formData['year'], $this->formData['week'])
+ ->startOfWeek();
+ $end = now()
+ ->setISODate($this->formData['year'], $this->formData['week'])
+ ->endOfWeek();
+ return $begin->format('Y-m-d').' - '.$end->format('Y-m-d');
+
}
}
diff --git a/laravel_app/app/Models/Project.php b/laravel_app/app/Models/Project.php
index 7346bf5..e7e9b3d 100644
--- a/laravel_app/app/Models/Project.php
+++ b/laravel_app/app/Models/Project.php
@@ -4,18 +4,21 @@
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Carbon;
+use Illuminate\Support\Facades\Storage;
+use Illuminate\Support\Str;
class Project extends Model
{
use HasFactory;
protected $fillable = [
-
'name',
'mail_template',
'mail_subject',
'mail_frequency',
'mail_day',
+ 'download_path',
];
public static function saveWithFormData(mixed $formData)
@@ -65,6 +68,24 @@ private function upsertMailRecipients($formData)
);
}
+ private function getMosaicPath()
+ {
+ return sprintf('%s/%s', $this->download_path, 'weekly_mosaic');
+ }
+
+ public function getMosaicList(): \Illuminate\Support\Collection
+ {
+ return collect(Storage::files($this->getMosaicPath()))
+ ->filter(fn($file) => Str::endsWith($file, '.tif'))
+ ->sortByDesc(function ($file) {
+ $parts = explode('_', str_replace('.tif', '', $file));
+ $week = $parts[1];
+ $year = $parts[2];
+ return $year.sprintf('%02d', $week);
+ })
+ ->values();
+ }
+
protected static function boot()
{
parent::boot(); // TODO: Change the autogenerated stub
@@ -80,11 +101,16 @@ protected static function boot()
});
}
+ public function reports()
+ {
+ return $this->hasMany(ProjectReport::class);
+ }
+
public function getAttachmentPathAttribute()
{
return storage_path(sprintf('%s/attachments', $this->download_path));
- return '/storage/' . $this->download_path . '/attachments';
+ return '/storage/'.$this->download_path.'/attachments';
}
public function boundingBoxes()
@@ -106,4 +132,46 @@ public function downloads()
{
return $this->hasMany(ProjectDownload::class);
}
+
+ public function allMosaicsPresent(Carbon $endDate)
+ {
+ // end date is in the future
+ if ($endDate->isFuture()) {
+ throw new \Exception('End date is in the future');
+ }
+
+ $mosaicsNotPresentInFilesystem = $this->getMosiacFilenameListByEndDate($endDate)
+ ->filter(function ($filename) {
+ return !$this->getMosaicList()->contains(function ($mosaicFilename) use ($filename) {
+ return Str::endsWith( $mosaicFilename, substr($filename, -16));
+ });
+ });
+ if ($mosaicsNotPresentInFilesystem->count() === 0) {
+ return true;
+ }
+ $message = sprintf(
+ 'Missing mosaics: %s',
+ $mosaicsNotPresentInFilesystem->implode(', ')
+ );
+ throw new \Exception($message);
+ }
+
+ public function getMosiacFilenameListByEndDate(Carbon $endDate): \Illuminate\Support\Collection
+ {
+ $result = collect([]);
+ for ($i = 0; $i < 4; $i++) {
+ $week = $endDate->weekOfYear;
+ $year = $endDate->year;
+ if ($week === 53) {
+ $year--;
+ }
+
+ $result->add(sprintf('week_%02d_%04d.tif', $week, $year));
+
+ $endDate = $endDate->subWeek();
+ }
+ return $result;
+ }
+
+
}
diff --git a/laravel_app/app/Models/ProjectReport.php b/laravel_app/app/Models/ProjectReport.php
new file mode 100644
index 0000000..93a3917
--- /dev/null
+++ b/laravel_app/app/Models/ProjectReport.php
@@ -0,0 +1,68 @@
+status = 'success';
+ $this->save();
+ }
+
+ public function setStatusFailed()
+ {
+ $this->status = 'failed';
+ $this->save();
+ }
+
+ public function project()
+ {
+ return $this->belongsTo(Project::class);
+ }
+
+ public function weeksAgo()
+ {
+ return now()->diffInWeeks(now()->setISODate($this->year, $this->week));
+ }
+
+ public function getFileName()
+ {
+ return 'week_'.$this->week.'_'.$this->year;
+ }
+
+ public function getFullPathName()
+ {
+ return storage_path('app/'.$this->project->download_path.'/'.$this->path);
+ }
+
+ public function getReportDate()
+ {
+ return self::getReportDateForYearAndWeek(
+ $this->project,
+ $this->year,
+ $this->week
+ )->toDateString();
+ }
+
+ public static function getReportDateForYearAndWeek(Project $project, $year, $week)
+ {
+ $date = Carbon::now()->setISODate($year, $week);
+
+ $dayOfWeek = Carbon::parse($project->mail_day)->subDay(2)->dayOfWeek;
+ if ($dayOfWeek == 6) {
+ $reportDay = $date->startOfWeek()->subDay();
+ } else {
+ $reportDay = $date->startOfWeek()->addDays($dayOfWeek);
+ }
+
+ return $reportDay;
+
+ }
+}
diff --git a/laravel_app/app/Models/Report.php b/laravel_app/app/Models/Report.php
deleted file mode 100644
index ce3631e..0000000
--- a/laravel_app/app/Models/Report.php
+++ /dev/null
@@ -1,11 +0,0 @@
-projectId = $projectId;
+ }
+
+ public function passes($attribute, $value)
+ {
+ try {
+ $project = Project::find($this->projectId);
+
+ if (!$project) {
+ $this->errorMessage = 'Project not found.';
+ return false;
+ }
+
+ return $project->allMosaicsPresent(
+ ProjectReport::getReportDateForYearAndWeek($project, $value['year'], $value['week'])
+ );
+ } catch (\Exception $e) {
+ $this->errorMessage = $e->getMessage();
+ return false;
+ }
+ }
+
+ public function message()
+ {
+ return $this->errorMessage;
+ }
+}
diff --git a/laravel_app/config/app.php b/laravel_app/config/app.php
index 597cf42..548588d 100644
--- a/laravel_app/config/app.php
+++ b/laravel_app/config/app.php
@@ -188,4 +188,9 @@
// 'Example' => App\Facades\Example::class,
])->toArray(),
+ /*
+ *
+ */
+ 'password' => env('LAPTOP_PASSWORD', 'secret'),
+
];
diff --git a/laravel_app/database/migrations/2023_10_24_123510_create_reports_table.php b/laravel_app/database/migrations/2023_10_24_123510_create_project_reports_table.php
similarity index 67%
rename from laravel_app/database/migrations/2023_10_24_123510_create_reports_table.php
rename to laravel_app/database/migrations/2023_10_24_123510_create_project_reports_table.php
index fb8b205..8085fe8 100644
--- a/laravel_app/database/migrations/2023_10_24_123510_create_reports_table.php
+++ b/laravel_app/database/migrations/2023_10_24_123510_create_project_reports_table.php
@@ -11,10 +11,14 @@
*/
public function up(): void
{
- Schema::create('reports', function (Blueprint $table) {
+ Schema::create('project_reports', function (Blueprint $table) {
$table->id();
$table->string('path');
$table->string('name');
+ $table->integer('week');
+ $table->integer('year');
+ $table->string('status')->default('pending');
+ $table->unsignedBigInteger('project_id');
$table->timestamps();
});
}
diff --git a/laravel_app/database/migrations/2023_12_19_131149_create_jobs_table.php b/laravel_app/database/migrations/2023_12_19_131149_create_jobs_table.php
new file mode 100644
index 0000000..6098d9b
--- /dev/null
+++ b/laravel_app/database/migrations/2023_12_19_131149_create_jobs_table.php
@@ -0,0 +1,32 @@
+bigIncrements('id');
+ $table->string('queue')->index();
+ $table->longText('payload');
+ $table->unsignedTinyInteger('attempts');
+ $table->unsignedInteger('reserved_at')->nullable();
+ $table->unsignedInteger('available_at');
+ $table->unsignedInteger('created_at');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::dropIfExists('jobs');
+ }
+};
diff --git a/laravel_app/database/migrations/2023_12_19_132243_create_failed_jobs_table.php b/laravel_app/database/migrations/2023_12_19_132243_create_failed_jobs_table.php
new file mode 100644
index 0000000..249da81
--- /dev/null
+++ b/laravel_app/database/migrations/2023_12_19_132243_create_failed_jobs_table.php
@@ -0,0 +1,32 @@
+id();
+ $table->string('uuid')->unique();
+ $table->text('connection');
+ $table->text('queue');
+ $table->longText('payload');
+ $table->longText('exception');
+ $table->timestamp('failed_at')->useCurrent();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::dropIfExists('failed_jobs');
+ }
+};
diff --git a/laravel_app/package-lock.json b/laravel_app/package-lock.json
index 86f5059..b9a5dbb 100644
--- a/laravel_app/package-lock.json
+++ b/laravel_app/package-lock.json
@@ -1,15 +1,22 @@
{
- "name": "Laravel_app",
+ "name": "laravel_app",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
+ "@alpinejs/collapse": "^3.13.3",
+ "@alpinejs/focus": "^3.13.3",
+ "@alpinejs/intersect": "^3.13.3",
+ "@alpinejs/ui": "^3.13.3-beta.4",
+ "@ryangjchandler/alpine-clipboard": "^2.3.0",
+ "@tailwindcss/aspect-ratio": "^0.4.2",
+ "alpinejs": "^3.13.3",
"tailwindcss": "^3.3.3"
},
"devDependencies": {
- "@tailwindcss/forms": "^0.5.2",
- "@tailwindcss/typography": "^0.5.0",
+ "@tailwindcss/forms": "^0.5.7",
+ "@tailwindcss/typography": "^0.5.10",
"autoprefixer": "^10.4.7",
"axios": "^1.1.2",
"laravel-vite-plugin": "^0.8.0",
@@ -22,7 +29,6 @@
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
"integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
- "dev": true,
"engines": {
"node": ">=10"
},
@@ -30,6 +36,30 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/@alpinejs/collapse": {
+ "version": "3.13.3",
+ "resolved": "https://registry.npmjs.org/@alpinejs/collapse/-/collapse-3.13.3.tgz",
+ "integrity": "sha512-iGO6IzqBwVNxAaoS4XCCJIIg9U/mH7v4vk6wlzxXKFWMXt2yynw93TkdELyjwxQqeNTEGimZRR+2wNf9yhJn0A=="
+ },
+ "node_modules/@alpinejs/focus": {
+ "version": "3.13.3",
+ "resolved": "https://registry.npmjs.org/@alpinejs/focus/-/focus-3.13.3.tgz",
+ "integrity": "sha512-fTRX/9wOfysyZ1PJ4gHeUnmiNTIgqBDIqKxeP5iMvj1UHD3TFLDXllvoIKH3ezqcsyQZqxd/q1MFM7dlIhkmeg==",
+ "dependencies": {
+ "focus-trap": "^6.9.4",
+ "tabbable": "^5.3.3"
+ }
+ },
+ "node_modules/@alpinejs/intersect": {
+ "version": "3.13.3",
+ "resolved": "https://registry.npmjs.org/@alpinejs/intersect/-/intersect-3.13.3.tgz",
+ "integrity": "sha512-4iwomnp4VXP1OmFfyol0sEgWdMFmX1WBlc8/gxRt6tO8PeeJjnZMdGjJeY6gNeRWS4g6I9aTUycdsyl6OQNv7w=="
+ },
+ "node_modules/@alpinejs/ui": {
+ "version": "3.13.3-beta.4",
+ "resolved": "https://registry.npmjs.org/@alpinejs/ui/-/ui-3.13.3-beta.4.tgz",
+ "integrity": "sha512-Dc6j40tELUqSAIg93Dgi+Carkw8MB+YXm0sILD41vkxw0ByHf5pICCBvhxkcVRg2I/2/6YM/W7i1ZUORNEqrgw=="
+ },
"node_modules/@esbuild/android-arm": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz",
@@ -386,7 +416,6 @@
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
"integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
- "dev": true,
"dependencies": {
"@jridgewell/set-array": "^1.0.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
@@ -400,7 +429,6 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
"integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
- "dev": true,
"engines": {
"node": ">=6.0.0"
}
@@ -409,7 +437,6 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
- "dev": true,
"engines": {
"node": ">=6.0.0"
}
@@ -417,14 +444,12 @@
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
- "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
- "dev": true
+ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.19",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz",
"integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==",
- "dev": true,
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
@@ -434,7 +459,6 @@
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
- "dev": true,
"dependencies": {
"@nodelib/fs.stat": "2.0.5",
"run-parallel": "^1.1.9"
@@ -447,7 +471,6 @@
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
- "dev": true,
"engines": {
"node": ">= 8"
}
@@ -456,7 +479,6 @@
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
- "dev": true,
"dependencies": {
"@nodelib/fs.scandir": "2.1.5",
"fastq": "^1.6.0"
@@ -465,10 +487,23 @@
"node": ">= 8"
}
},
+ "node_modules/@ryangjchandler/alpine-clipboard": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/@ryangjchandler/alpine-clipboard/-/alpine-clipboard-2.3.0.tgz",
+ "integrity": "sha512-r1YL/LL851vSemjgcca+M6Yz9SNtA9ATul8nJ0n0sAS1W3V1GUWvH0Od2XdQF1r36YJF+/4sUc0eHF/Zexw7dA=="
+ },
+ "node_modules/@tailwindcss/aspect-ratio": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/aspect-ratio/-/aspect-ratio-0.4.2.tgz",
+ "integrity": "sha512-8QPrypskfBa7QIMuKHg2TA7BqES6vhBrDLOv8Unb6FcFyd3TjKbc6lcmb9UPQHxfl24sXoJ41ux/H7qQQvfaSQ==",
+ "peerDependencies": {
+ "tailwindcss": ">=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1"
+ }
+ },
"node_modules/@tailwindcss/forms": {
- "version": "0.5.6",
- "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.6.tgz",
- "integrity": "sha512-Fw+2BJ0tmAwK/w01tEFL5TiaJBX1NLT1/YbWgvm7ws3Qcn11kiXxzNTEQDMs5V3mQemhB56l3u0i9dwdzSQldA==",
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.7.tgz",
+ "integrity": "sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw==",
"dev": true,
"dependencies": {
"mini-svg-data-uri": "^1.2.3"
@@ -505,17 +540,36 @@
"node": ">=4"
}
},
+ "node_modules/@vue/reactivity": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.1.5.tgz",
+ "integrity": "sha512-1tdfLmNjWG6t/CsPldh+foumYFo3cpyCHgBYQ34ylaMsJ+SNHQ1kApMIa8jN+i593zQuaw3AdWH0nJTARzCFhg==",
+ "dependencies": {
+ "@vue/shared": "3.1.5"
+ }
+ },
+ "node_modules/@vue/shared": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.1.5.tgz",
+ "integrity": "sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA=="
+ },
+ "node_modules/alpinejs": {
+ "version": "3.13.3",
+ "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.13.3.tgz",
+ "integrity": "sha512-WZ6WQjkAOl+WdW/jukzNHq9zHFDNKmkk/x6WF7WdyNDD6woinrfXCVsZXm0galjbco+pEpYmJLtwlZwcOfIVdg==",
+ "dependencies": {
+ "@vue/reactivity": "~3.1.1"
+ }
+ },
"node_modules/any-promise": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
- "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
- "dev": true
+ "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="
},
"node_modules/anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
- "dev": true,
"dependencies": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
@@ -527,8 +581,7 @@
"node_modules/arg": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
- "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
- "dev": true
+ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
},
"node_modules/asynckit": {
"version": "0.4.0",
@@ -587,14 +640,12 @@
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
- "dev": true
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"node_modules/binary-extensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
- "dev": true,
"engines": {
"node": ">=8"
}
@@ -603,7 +654,6 @@
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "dev": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -613,7 +663,6 @@
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
- "dev": true,
"dependencies": {
"fill-range": "^7.0.1"
},
@@ -657,7 +706,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
- "dev": true,
"engines": {
"node": ">= 6"
}
@@ -686,7 +734,6 @@
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
- "dev": true,
"funding": [
{
"type": "individual",
@@ -713,7 +760,6 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dev": true,
"dependencies": {
"is-glob": "^4.0.1"
},
@@ -737,7 +783,6 @@
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
"integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
- "dev": true,
"engines": {
"node": ">= 6"
}
@@ -745,14 +790,12 @@
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
- "dev": true
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
},
"node_modules/cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
- "dev": true,
"bin": {
"cssesc": "bin/cssesc"
},
@@ -772,14 +815,12 @@
"node_modules/didyoumean": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
- "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
- "dev": true
+ "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="
},
"node_modules/dlv": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
- "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
- "dev": true
+ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
},
"node_modules/electron-to-chromium": {
"version": "1.4.549",
@@ -837,7 +878,6 @@
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
"integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
- "dev": true,
"dependencies": {
"@nodelib/fs.stat": "^2.0.2",
"@nodelib/fs.walk": "^1.2.3",
@@ -853,7 +893,6 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dev": true,
"dependencies": {
"is-glob": "^4.0.1"
},
@@ -865,7 +904,6 @@
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
"integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
- "dev": true,
"dependencies": {
"reusify": "^1.0.4"
}
@@ -874,7 +912,6 @@
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "dev": true,
"dependencies": {
"to-regex-range": "^5.0.1"
},
@@ -882,6 +919,14 @@
"node": ">=8"
}
},
+ "node_modules/focus-trap": {
+ "version": "6.9.4",
+ "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-6.9.4.tgz",
+ "integrity": "sha512-v2NTsZe2FF59Y+sDykKY+XjqZ0cPfhq/hikWVL88BqLivnNiEffAsac6rP6H45ff9wG9LL5ToiDqrLEP9GX9mw==",
+ "dependencies": {
+ "tabbable": "^5.3.3"
+ }
+ },
"node_modules/follow-redirects": {
"version": "1.15.3",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz",
@@ -932,14 +977,12 @@
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
- "dev": true
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
},
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "dev": true,
"hasInstallScript": true,
"optional": true,
"os": [
@@ -953,7 +996,6 @@
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
- "dev": true,
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
@@ -973,7 +1015,6 @@
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
- "dev": true,
"dependencies": {
"is-glob": "^4.0.3"
},
@@ -985,7 +1026,6 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz",
"integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==",
- "dev": true,
"engines": {
"node": ">= 0.4.0"
}
@@ -994,7 +1034,6 @@
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
- "dev": true,
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
@@ -1003,14 +1042,12 @@
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
- "dev": true
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"node_modules/is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
- "dev": true,
"dependencies": {
"binary-extensions": "^2.0.0"
},
@@ -1022,7 +1059,6 @@
"version": "2.13.0",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz",
"integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==",
- "dev": true,
"dependencies": {
"has": "^1.0.3"
},
@@ -1034,7 +1070,6 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -1043,7 +1078,6 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "dev": true,
"dependencies": {
"is-extglob": "^2.1.1"
},
@@ -1055,7 +1089,6 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true,
"engines": {
"node": ">=0.12.0"
}
@@ -1064,7 +1097,6 @@
"version": "1.20.0",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.20.0.tgz",
"integrity": "sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA==",
- "dev": true,
"bin": {
"jiti": "bin/jiti.js"
}
@@ -1089,7 +1121,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
"integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
- "dev": true,
"engines": {
"node": ">=10"
}
@@ -1097,8 +1128,7 @@
"node_modules/lines-and-columns": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
- "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
- "dev": true
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
},
"node_modules/lodash.castarray": {
"version": "4.4.0",
@@ -1122,7 +1152,6 @@
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
- "dev": true,
"engines": {
"node": ">= 8"
}
@@ -1131,7 +1160,6 @@
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
- "dev": true,
"dependencies": {
"braces": "^3.0.2",
"picomatch": "^2.3.1"
@@ -1174,7 +1202,6 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
@@ -1186,7 +1213,6 @@
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
"integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
- "dev": true,
"dependencies": {
"any-promise": "^1.0.0",
"object-assign": "^4.0.1",
@@ -1197,7 +1223,6 @@
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
- "dev": true,
"funding": [
{
"type": "github",
@@ -1221,7 +1246,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -1239,7 +1263,6 @@
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -1248,7 +1271,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
"integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
- "dev": true,
"engines": {
"node": ">= 6"
}
@@ -1257,7 +1279,6 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
- "dev": true,
"dependencies": {
"wrappy": "1"
}
@@ -1266,7 +1287,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -1274,20 +1294,17 @@
"node_modules/path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
- "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
- "dev": true
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
},
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
- "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
- "dev": true
+ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
},
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
- "dev": true,
"engines": {
"node": ">=8.6"
},
@@ -1299,7 +1316,6 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -1308,7 +1324,6 @@
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
"integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
- "dev": true,
"engines": {
"node": ">= 6"
}
@@ -1317,7 +1332,6 @@
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
- "dev": true,
"funding": [
{
"type": "opencollective",
@@ -1345,7 +1359,6 @@
"version": "15.1.0",
"resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
"integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
- "dev": true,
"dependencies": {
"postcss-value-parser": "^4.0.0",
"read-cache": "^1.0.0",
@@ -1362,7 +1375,6 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
"integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
- "dev": true,
"dependencies": {
"camelcase-css": "^2.0.1"
},
@@ -1381,7 +1393,6 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz",
"integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==",
- "dev": true,
"dependencies": {
"lilconfig": "^2.0.5",
"yaml": "^2.1.1"
@@ -1410,7 +1421,6 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz",
"integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==",
- "dev": true,
"dependencies": {
"postcss-selector-parser": "^6.0.11"
},
@@ -1429,7 +1439,6 @@
"version": "6.0.13",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz",
"integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==",
- "dev": true,
"dependencies": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
@@ -1441,8 +1450,7 @@
"node_modules/postcss-value-parser": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
- "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
- "dev": true
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
@@ -1454,7 +1462,6 @@
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
- "dev": true,
"funding": [
{
"type": "github",
@@ -1474,7 +1481,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
"integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
- "dev": true,
"dependencies": {
"pify": "^2.3.0"
}
@@ -1483,7 +1489,6 @@
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
- "dev": true,
"dependencies": {
"picomatch": "^2.2.1"
},
@@ -1495,7 +1500,6 @@
"version": "1.22.6",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz",
"integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==",
- "dev": true,
"dependencies": {
"is-core-module": "^2.13.0",
"path-parse": "^1.0.7",
@@ -1512,7 +1516,6 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
- "dev": true,
"engines": {
"iojs": ">=1.0.0",
"node": ">=0.10.0"
@@ -1538,7 +1541,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
- "dev": true,
"funding": [
{
"type": "github",
@@ -1561,7 +1563,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -1570,7 +1571,6 @@
"version": "3.34.0",
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz",
"integrity": "sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==",
- "dev": true,
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.2",
"commander": "^4.0.0",
@@ -1592,7 +1592,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
- "dev": true,
"engines": {
"node": ">= 0.4"
},
@@ -1600,11 +1599,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/tabbable": {
+ "version": "5.3.3",
+ "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.3.3.tgz",
+ "integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA=="
+ },
"node_modules/tailwindcss": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.3.tgz",
"integrity": "sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==",
- "dev": true,
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
"arg": "^5.0.2",
@@ -1641,7 +1644,6 @@
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
"integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
- "dev": true,
"dependencies": {
"any-promise": "^1.0.0"
}
@@ -1650,7 +1652,6 @@
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
"integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
- "dev": true,
"dependencies": {
"thenify": ">= 3.1.0 < 4"
},
@@ -1662,7 +1663,6 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
"dependencies": {
"is-number": "^7.0.0"
},
@@ -1673,8 +1673,7 @@
"node_modules/ts-interface-checker": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
- "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
- "dev": true
+ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="
},
"node_modules/update-browserslist-db": {
"version": "1.0.13",
@@ -1709,8 +1708,7 @@
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
- "dev": true
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"node_modules/vite": {
"version": "4.4.11",
@@ -1783,14 +1781,12 @@
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
- "dev": true
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
"node_modules/yaml": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.2.tgz",
"integrity": "sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==",
- "dev": true,
"engines": {
"node": ">= 14"
}
diff --git a/laravel_app/package.json b/laravel_app/package.json
index 69666fd..4c11eae 100644
--- a/laravel_app/package.json
+++ b/laravel_app/package.json
@@ -6,8 +6,8 @@
"build": "vite build"
},
"devDependencies": {
- "@tailwindcss/forms": "^0.5.2",
- "@tailwindcss/typography": "^0.5.0",
+ "@tailwindcss/forms": "^0.5.7",
+ "@tailwindcss/typography": "^0.5.10",
"autoprefixer": "^10.4.7",
"axios": "^1.1.2",
"laravel-vite-plugin": "^0.8.0",
@@ -16,6 +16,13 @@
"vite": "^4.0.0"
},
"dependencies": {
+ "@alpinejs/collapse": "^3.13.3",
+ "@alpinejs/focus": "^3.13.3",
+ "@alpinejs/intersect": "^3.13.3",
+ "@alpinejs/ui": "^3.13.3-beta.4",
+ "@ryangjchandler/alpine-clipboard": "^2.3.0",
+ "@tailwindcss/aspect-ratio": "^0.4.2",
+ "alpinejs": "^3.13.3",
"tailwindcss": "^3.3.3"
}
}
diff --git a/laravel_app/resources/css/app.css b/laravel_app/resources/css/app.css
index 0de2120..34ca985 100644
--- a/laravel_app/resources/css/app.css
+++ b/laravel_app/resources/css/app.css
@@ -1,7 +1,9 @@
+@import url('https://rsms.me/inter/inter.css');
@tailwind base;
@tailwind components;
@tailwind utilities;
+
[x-cloak] {
display: none;
}
diff --git a/laravel_app/resources/js/alpine.js b/laravel_app/resources/js/alpine.js
new file mode 100644
index 0000000..1574ca1
--- /dev/null
+++ b/laravel_app/resources/js/alpine.js
@@ -0,0 +1,22 @@
+import { Livewire, Alpine } from '../../vendor/livewire/livewire/dist/livewire.esm';
+// import Intersect from "@alpinejs/intersect";
+import focus from "@alpinejs/focus";
+// import Clipboard from "@ryangjchandler/alpine-clipboard";
+// import collapse from "@alpinejs/collapse";
+import ui from "@alpinejs/ui";
+Alpine.plugin(ui)
+Alpine.plugin(focus)
+// Alpine.plugin(Clipboard);
+// Alpine.plugin(Intersect);
+// Alpine.plugin(collapse);
+import htabs from './history-tabs';
+htabs(Alpine)
+
+window.Alpine = Alpine
+
+document.addEventListener("alpine:init", () => {
+ console.log("Alpine Initialized")
+});
+
+Livewire.start();
+
diff --git a/laravel_app/resources/js/app.js b/laravel_app/resources/js/app.js
index e59d6a0..861ee70 100644
--- a/laravel_app/resources/js/app.js
+++ b/laravel_app/resources/js/app.js
@@ -1 +1,2 @@
import './bootstrap';
+import('./alpine');
diff --git a/laravel_app/resources/js/history-tabs.js b/laravel_app/resources/js/history-tabs.js
new file mode 100644
index 0000000..2f53478
--- /dev/null
+++ b/laravel_app/resources/js/history-tabs.js
@@ -0,0 +1,167 @@
+
+export default function (Alpine) {
+ Alpine.directive('htabs', (el, directive) => {
+ if (! directive.value) handleRoot(el, Alpine)
+ else if (directive.value === 'list') handleList(el, Alpine)
+ else if (directive.value === 'tab') handleTab(el, Alpine)
+ else if (directive.value === 'panels') handlePanels(el, Alpine)
+ else if (directive.value === 'panel') handlePanel(el, Alpine)
+ }).before('bind')
+
+ Alpine.magic('htab', el => {
+ let $data = Alpine.$data(el)
+
+ return {
+ get isSelected() {
+ return $data.__selectedIndex === $data.__tabs.indexOf($data.__tabEl)
+ },
+ get isDisabled() {
+ return $data.__isDisabled
+ }
+ }
+ })
+
+ Alpine.magic('hpanel', el => {
+ let $data = Alpine.$data(el)
+
+ return {
+ get isSelected() {
+ return $data.__selectedIndex === $data.__panels.indexOf($data.__panelEl)
+ }
+ }
+ })
+}
+
+function handleRoot(el, Alpine) {
+ Alpine.bind(el, {
+ 'x-modelable': '__selectedIndex',
+ 'x-data'() {
+ return {
+ init() {
+ window.addEventListener('popstate', this.__handlePopState.bind(this));
+
+ queueMicrotask(() => {
+ let defaultIndex = this.__selectedIndex || Number(Alpine.bound(this.$el, 'default-index', 0))
+ let tabs = this.__activeTabs()
+ let clamp = (number, min, max) => Math.min(Math.max(number, min), max)
+
+ this.__selectedIndex = clamp(defaultIndex, 0, tabs.length -1)
+
+ Alpine.effect(() => {
+ this.__manualActivation = Alpine.bound(this.$el, 'manual', false)
+ })
+
+ this.__syncTabWithUrl();
+ })
+ },
+ __tabs: [],
+ __panels: [],
+ __selectedIndex: null,
+ __tabGroupEl: undefined,
+ __manualActivation: false,
+ __addTab(el) { this.__tabs.push(el) },
+ __addPanel(el) { this.__panels.push(el) },
+ __selectTab(el) {
+ if (this.__selectedIndex !== this.__tabs.indexOf(el)) {
+ this.__selectedIndex = this.__tabs.indexOf(el)
+ this.__updateUrl();
+ }
+ },
+ __updateUrl() {
+ const selectedTab = this.__tabs[this.__selectedIndex];
+ const tabName = selectedTab.getAttribute('data-tab-name');
+ const url = new URL(window.location);
+ url.searchParams.set('selected-tab', tabName);
+ window.history.pushState({ tabIndex: this.__selectedIndex }, '', url);
+ },
+
+ __handlePopState() {
+ this.__syncTabWithUrl();
+ },
+
+ __syncTabWithUrl() {
+ const urlParams = new URLSearchParams(window.location.search);
+ const tabName = urlParams.get('selected-tab');
+ const tabIndex = this.__tabs.findIndex(tab => tab.getAttribute('data-tab-name') === tabName);
+ this.__selectedIndex = 0;
+ if (tabIndex >= 0) {
+ this.__selectedIndex = tabIndex;
+ }
+ },
+ __activeTabs() {
+ return this.__tabs.filter(i => !i.__disabled)
+ },
+ }
+ }
+ })
+}
+
+function handleList(el, Alpine) {
+ Alpine.bind(el, {
+ 'x-init'() { this.$data.__tabGroupEl = this.$el }
+ })
+}
+
+function handleTab(el, Alpine) {
+ Alpine.bind(el, {
+ 'x-init'() { if (this.$el.tagName.toLowerCase() === 'button' && !this.$el.hasAttribute('type')) this.$el.type = 'button' },
+ 'x-data'() { return {
+ init() {
+ this.__tabEl = this.$el
+ this.$data.__addTab(this.$el)
+ this.__tabEl.__disabled = Alpine.bound(this.$el, 'disabled', false)
+ this.__isDisabled = this.__tabEl.__disabled
+ },
+ __tabEl: undefined,
+ __isDisabled: false,
+ }},
+ '@click'() {
+ if (this.$el.__disabled) return
+
+ this.$data.__selectTab(this.$el)
+
+ this.$el.focus()
+ },
+ '@keydown.enter.prevent.stop'() { this.__selectTab(this.$el) },
+ '@keydown.space.prevent.stop'() { this.__selectTab(this.$el) },
+ '@keydown.home.prevent.stop'() { this.$focus.within(this.$data.__activeTabs()).first() },
+ '@keydown.page-up.prevent.stop'() { this.$focus.within(this.$data.__activeTabs()).first() },
+ '@keydown.end.prevent.stop'() { this.$focus.within(this.$data.__activeTabs()).last() },
+ '@keydown.page-down.prevent.stop'() { this.$focus.within(this.$data.__activeTabs()).last() },
+ '@keydown.down.prevent.stop'() { this.$focus.within(this.$data.__activeTabs()).withWrapAround().next() },
+ '@keydown.right.prevent.stop'() { this.$focus.within(this.$data.__activeTabs()).withWrapAround().next() },
+ '@keydown.up.prevent.stop'() { this.$focus.within(this.$data.__activeTabs()).withWrapAround().prev() },
+ '@keydown.left.prevent.stop'() { this.$focus.within(this.$data.__activeTabs()).withWrapAround().prev() },
+ ':tabindex'() { return this.$tab.isSelected ? 0 : -1 },
+ '@focus'() {
+ if (this.$data.__manualActivation) {
+ this.$el.focus()
+ } else {
+ if (this.$el.__disabled) return
+ this.$data.__selectTab(this.$el)
+
+ this.$el.focus()
+ }
+ },
+ })
+}
+
+function handlePanels(el, Alpine) {
+ Alpine.bind(el, {
+ //
+ })
+}
+
+function handlePanel(el, Alpine) {
+ Alpine.bind(el, {
+ ':tabindex'() { return this.$panel.isSelected ? 0 : -1 },
+ 'x-data'() { return {
+ init() {
+ this.__panelEl = this.$el
+ this.$data.__addPanel(this.$el)
+ },
+ __panelEl: undefined,
+ }},
+ 'x-show'() { return this.$panel.isSelected },
+ })
+}
diff --git a/laravel_app/resources/views/components/badge.blade.php b/laravel_app/resources/views/components/badge.blade.php
new file mode 100644
index 0000000..3501a7f
--- /dev/null
+++ b/laravel_app/resources/views/components/badge.blade.php
@@ -0,0 +1,27 @@
+@props([
+ 'status' => 'success',
+])
+ ['bg' => 'bg-green-100', 'text' => 'text-green-700'],
+ 'error' => ['bg' => 'bg-red-100', 'text' => 'text-red-700'],
+ 'warning' => ['bg' => 'bg-yellow-100', 'text' => 'text-yellow-800'],
+ 'info' => ['bg' => 'bg-blue-100', 'text' => 'text-blue-700'],
+ 'pending' => ['bg' => 'bg-gray-100', 'text' => 'text-gray-600'],
+];
+
+// Default to 'success' if the provided status is not in the defined array
+if (!array_key_exists($status, $statusToColors)) {
+ $status = 'success';
+}
+
+// Get the color class for the given status
+$colorClasses = $statusToColors[$status];
+
+?>
+
+
+ {{ $status }}
+
diff --git a/laravel_app/resources/views/components/report-manager-properties-modal.blade.php b/laravel_app/resources/views/components/report-manager-properties-modal.blade.php
new file mode 100644
index 0000000..e58283d
--- /dev/null
+++ b/laravel_app/resources/views/components/report-manager-properties-modal.blade.php
@@ -0,0 +1,50 @@
+@props([
+ 'formData',
+ /** @var \App\Livewire\Projects\ProjectManager */
+ 'reportManager'
+])
+
+