phases one of time logged now with log display

This commit is contained in:
Mark Gregory
2026-06-22 12:53:56 +01:00
parent c1a9d0de27
commit 052bae718e
231 changed files with 15113 additions and 12891 deletions
@@ -1,8 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 42" {{ $attributes }}>
<path
fill="currentColor"
fill-rule="evenodd"
clip-rule="evenodd"
d="M17.2 5.633 8.6.855 0 5.633v26.51l16.2 9 16.2-9v-8.442l7.6-4.223V9.856l-8.6-4.777-8.6 4.777V18.3l-5.6 3.111V5.633ZM38 18.301l-5.6 3.11v-6.157l5.6-3.11V18.3Zm-1.06-7.856-5.54 3.078-5.54-3.079 5.54-3.078 5.54 3.079ZM24.8 18.3v-6.157l5.6 3.111v6.158L24.8 18.3Zm-1 1.732 5.54 3.078-13.14 7.302-5.54-3.078 13.14-7.3v-.002Zm-16.2 7.89 7.6 4.222V38.3L2 30.966V7.92l5.6 3.111v16.892ZM8.6 9.3 3.06 6.222 8.6 3.143l5.54 3.08L8.6 9.3Zm21.8 15.51-13.2 7.334V38.3l13.2-7.334v-6.156ZM9.6 11.034l5.6-3.11v14.6l-5.6 3.11v-14.6Z"
/>
<path fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"
d="M17.2 5.633 8.6.855 0 5.633v26.51l16.2 9 16.2-9v-8.442l7.6-4.223V9.856l-8.6-4.777-8.6 4.777V18.3l-5.6 3.111V5.633ZM38 18.301l-5.6 3.11v-6.157l5.6-3.11V18.3Zm-1.06-7.856-5.54 3.078-5.54-3.079 5.54-3.078 5.54 3.079ZM24.8 18.3v-6.157l5.6 3.111v6.158L24.8 18.3Zm-1 1.732 5.54 3.078-13.14 7.302-5.54-3.078 13.14-7.3v-.002Zm-16.2 7.89 7.6 4.222V38.3L2 30.966V7.92l5.6 3.111v16.892ZM8.6 9.3 3.06 6.222 8.6 3.143l5.54 3.08L8.6 9.3Zm21.8 15.51-13.2 7.334V38.3l13.2-7.334v-6.156ZM9.6 11.034l5.6-3.11v14.6l-5.6 3.11v-14.6Z" />
</svg>

Before

Width:  |  Height:  |  Size: 714 B

After

Width:  |  Height:  |  Size: 683 B

@@ -2,15 +2,17 @@
'sidebar' => false,
])
@if($sidebar)
@if ($sidebar)
<flux:sidebar.brand name="Warehouse Management System" {{ $attributes }}>
<x-slot name="logo" class="flex aspect-square size-8 items-center justify-center rounded-md bg-accent-content text-accent-foreground">
<x-slot name="logo"
class="flex aspect-square size-8 items-center justify-center rounded-md bg-accent-content text-accent-foreground">
<x-app-logo-icon class="size-5 fill-current text-white dark:text-black" />
</x-slot>
</flux:sidebar.brand>
@else
<flux:brand name="Warehouse Management System" {{ $attributes }}>
<x-slot name="logo" class="flex aspect-square size-8 items-center justify-center rounded-md bg-accent-content text-accent-foreground">
<x-slot name="logo"
class="flex aspect-square size-8 items-center justify-center rounded-md bg-accent-content text-accent-foreground">
<x-app-logo-icon class="size-5 fill-current text-white dark:text-black" />
</x-slot>
</flux:brand>
@@ -1,7 +1,4 @@
@props([
'title',
'description',
])
@props(['title', 'description'])
<div class="flex w-full flex-col text-center">
<flux:heading size="xl">{{ $title }}</flux:heading>
@@ -1,6 +1,4 @@
@props([
'status',
])
@props(['status'])
@if ($status)
<div {{ $attributes->merge(['class' => 'font-medium text-sm text-green-600']) }}>
@@ -1,11 +1,4 @@
@props([
'title',
'description' => '',
'type' => 'line',
'config' => [],
'height' => 300,
'icon' => 'fa-chart-line',
])
@props(['title', 'description' => '', 'type' => 'line', 'config' => [], 'height' => 300, 'icon' => 'fa-chart-line'])
<div class="card wms-chart-card mb-4 h-100">
<div class="card-header wms-chart-card__header">
@@ -14,7 +7,7 @@
<h3 class="wms-chart-card__title">
<i class="fas {{ $icon }} me-2"></i>{{ $title }}
</h3>
@if($description !== '')
@if ($description !== '')
<p class="wms-chart-card__description">{{ $description }}</p>
@endif
</div>
@@ -22,13 +15,8 @@
<div class="card-body">
<div class="wms-chart-card__canvas" style="height: {{ (int) $height }}px;">
<canvas
data-wms-chart
data-chart-type="{{ $type }}"
data-chart-config='@json($config)'
aria-label="{{ $title }} chart"
role="img"
></canvas>
<canvas data-wms-chart data-chart-type="{{ $type }}" data-chart-config='@json($config)'
aria-label="{{ $title }} chart" role="img"></canvas>
</div>
</div>
</div>
@@ -1,9 +1,4 @@
@props([
'label',
'value' => 0,
'hint' => '',
'icon' => 'fa-chart-simple',
])
@props(['label', 'value' => 0, 'hint' => '', 'icon' => 'fa-chart-simple'])
<div class="col-xl-3 col-md-6">
<div class="card wms-metric-card mb-4">
@@ -11,7 +6,7 @@
<div>
<div class="wms-metric-card__label">{{ $label }}</div>
<div class="wms-metric-card__value">{{ is_numeric($value) ? number_format((int) $value) : $value }}</div>
@if($hint !== '')
@if ($hint !== '')
<div class="wms-metric-card__hint">{{ $hint }}</div>
@endif
</div>
@@ -1,17 +1,10 @@
<flux:dropdown position="bottom" align="start">
<flux:sidebar.profile
:name="auth()->user()->name"
:initials="auth()->user()->initials()"
icon:trailing="chevrons-up-down"
data-test="sidebar-menu-button"
/>
<flux:sidebar.profile :name="auth()->user()->name" :initials="auth()->user()->initials()"
icon:trailing="chevrons-up-down" data-test="sidebar-menu-button" />
<flux:menu>
<div class="flex items-center gap-2 px-1 py-1.5 text-start text-sm">
<flux:avatar
:name="auth()->user()->name"
:initials="auth()->user()->initials()"
/>
<flux:avatar :name="auth()->user()->name" :initials="auth()->user()->initials()" />
<div class="grid flex-1 text-start text-sm leading-tight">
<flux:heading class="truncate">{{ auth()->user()->name }}</flux:heading>
<flux:text class="truncate">{{ auth()->user()->email }}</flux:text>
@@ -24,13 +17,8 @@
</flux:menu.item>
<form method="POST" action="{{ route('logout') }}" class="w-full">
@csrf
<flux:menu.item
as="button"
type="submit"
icon="arrow-right-start-on-rectangle"
class="w-full cursor-pointer"
data-test="logout-button"
>
<flux:menu.item as="button" type="submit" icon="arrow-right-start-on-rectangle"
class="w-full cursor-pointer" data-test="logout-button">
{{ __('Log out') }}
</flux:menu.item>
</form>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,59 +1,53 @@
@assets
@vite('resources/js/passkeys.js')
@vite('resources/js/passkeys.js')
@endassets
<div
x-data="{
supported: false,
showForm: false,
name: '',
loading: false,
error: null,
updateSupport() {
this.supported = Boolean(window.Passkeys?.isSupported());
},
init() {
this.updateSupport();
<div x-data="{
supported: false,
showForm: false,
name: '',
loading: false,
error: null,
updateSupport() {
this.supported = Boolean(window.Passkeys?.isSupported());
},
init() {
this.updateSupport();
window.addEventListener('passkeys:ready', () => this.updateSupport(), { once: true });
},
async register() {
if (!this.name.trim()) return;
window.addEventListener('passkeys:ready', () => this.updateSupport(), { once: true });
},
async register() {
if (!this.name.trim()) return;
this.loading = true;
this.error = null;
this.loading = true;
this.error = null;
try {
await window.Passkeys.register({ name: this.name });
this.name = '';
this.showForm = false;
await $wire.loadPasskeys();
} catch (e) {
if (e.constructor?.name !== 'UserCancelledError') {
this.error = e.message;
}
} finally {
this.loading = false;
}
},
cancel() {
this.showForm = false;
try {
await window.Passkeys.register({ name: this.name });
this.name = '';
this.error = null;
},
}"
>
this.showForm = false;
await $wire.loadPasskeys();
} catch (e) {
if (e.constructor?.name !== 'UserCancelledError') {
this.error = e.message;
}
} finally {
this.loading = false;
}
},
cancel() {
this.showForm = false;
this.name = '';
this.error = null;
},
}">
<template x-if="!supported">
<flux:text>{{ __('Passkeys are not supported in this browser.') }}</flux:text>
</template>
<template x-if="supported && !showForm">
<div>
<flux:button
variant="primary"
icon="plus"
x-on:click="showForm = true"
>
<flux:button variant="primary" icon="plus" x-on:click="showForm = true">
{{ __('Add passkey') }}
</flux:button>
</div>
@@ -61,31 +55,19 @@
<template x-if="supported && showForm">
<div class="space-y-4 rounded-lg border border-zinc-200 dark:border-zinc-700 bg-zinc-50 dark:bg-zinc-800/50 p-4">
<flux:input
label="{{ __('Passkey name') }}"
x-model="name"
placeholder="{{ __('e.g., MacBook Pro, iPhone') }}"
x-on:keydown.enter.prevent="register()"
x-ref="passkeyNameInput"
x-init="$nextTick(() => $refs.passkeyNameInput?.focus())"
/>
<flux:input label="{{ __('Passkey name') }}" x-model="name"
placeholder="{{ __('e.g., MacBook Pro, iPhone') }}" x-on:keydown.enter.prevent="register()"
x-ref="passkeyNameInput" x-init="$nextTick(() => $refs.passkeyNameInput?.focus())" />
<flux:text class="!mt-1">{{ __('Give this passkey a name to help you identify it later.') }}</flux:text>
<p x-show="error" x-text="error" x-cloak class="text-sm text-red-600 dark:text-red-400"></p>
<div class="flex gap-2">
<flux:button
variant="primary"
x-on:click="register()"
x-bind:disabled="loading || !name.trim()"
>
<flux:button variant="primary" x-on:click="register()" x-bind:disabled="loading || !name.trim()">
<span x-show="!loading">{{ __('Register passkey') }}</span>
<span x-show="loading" x-cloak>{{ __('Registering...') }}</span>
</flux:button>
<flux:button
variant="ghost"
x-on:click="cancel()"
>
<flux:button variant="ghost" x-on:click="cancel()">
{{ __('Cancel') }}
</flux:button>
</div>
@@ -7,58 +7,50 @@
])
@assets
@vite('resources/js/passkeys.js')
@vite('resources/js/passkeys.js')
@endassets
<div
x-data="{
supported: false,
loading: false,
error: null,
updateSupport() {
this.supported = Boolean(window.Passkeys?.isSupported());
},
init() {
this.updateSupport();
<div x-data="{
supported: false,
loading: false,
error: null,
updateSupport() {
this.supported = Boolean(window.Passkeys?.isSupported());
},
init() {
this.updateSupport();
window.addEventListener('passkeys:ready', () => this.updateSupport(), { once: true });
},
async verify() {
this.loading = true;
this.error = null;
try {
const response = await window.Passkeys.verify({
routes: {
options: '{{ route($optionsRoute) }}',
submit: '{{ route($submitRoute) }}',
},
});
Livewire.navigate(response.redirect || '/dashboard');
} catch (e) {
if (e.constructor?.name !== 'UserCancelledError') {
this.error = e.message;
}
} finally {
this.loading = false;
window.addEventListener('passkeys:ready', () => this.updateSupport(), { once: true });
},
async verify() {
this.loading = true;
this.error = null;
try {
const response = await window.Passkeys.verify({
routes: {
options: '{{ route($optionsRoute) }}',
submit: '{{ route($submitRoute) }}',
},
});
Livewire.navigate(response.redirect || '/dashboard');
} catch (e) {
if (e.constructor?.name !== 'UserCancelledError') {
this.error = e.message;
}
},
}"
>
} finally {
this.loading = false;
}
},
}">
<template x-if="supported">
<div>
<div class="grid gap-2">
<flux:button
variant="outline"
icon="finger-print"
class="w-full"
x-on:click="verify()"
x-bind:disabled="loading"
>
<flux:button variant="outline" icon="finger-print" class="w-full" x-on:click="verify()"
x-bind:disabled="loading">
<span x-show="!loading">{{ $label }}</span>
<span x-show="loading" x-cloak>{{ $loadingLabel }}</span>
</flux:button>
<p x-show="error" x-text="error" x-cloak
class="text-sm text-center text-red-600 dark:text-red-400"></p>
<p x-show="error" x-text="error" x-cloak class="text-sm text-center text-red-600 dark:text-red-400"></p>
</div>
<div class="relative my-6">
@@ -10,17 +10,17 @@
<div class="wms-page-hero-copy">
<p class="wms-page-hero-kicker">{{ $eyebrow }}</p>
<h1 class="wms-page-hero-title">{{ $title }}</h1>
@if($description)
@if ($description)
<p class="wms-page-hero-description">{{ $description }}</p>
@endif
</div>
<div class="wms-page-hero-actions">
@foreach($stats as $stat)
@foreach ($stats as $stat)
<article class="wms-page-hero-stat">
<span>{{ $stat['label'] ?? '' }}</span>
<strong>
@if(! empty($stat['icon']))
@if (!empty($stat['icon']))
<i class="{{ $stat['icon'] }}" aria-hidden="true"></i>
@endif
{{ $stat['value'] ?? '' }}
@@ -28,13 +28,13 @@
</article>
@endforeach
@if($icon && count($stats) === 0)
@if ($icon && count($stats) === 0)
<article class="wms-page-hero-stat wms-page-hero-icon-card" aria-hidden="true">
<strong><i class="{{ $icon }}"></i></strong>
</article>
@endif
@if($slot->isNotEmpty())
@if ($slot->isNotEmpty())
{{ $slot }}
@endif
</div>
+12 -10
View File
@@ -1,28 +1,30 @@
<x-layouts::app :title="__('Dashboard')">
<x-wms.page-hero
eyebrow="Operations"
title="Warehouse Command Centre"
<x-wms.page-hero eyebrow="Operations" title="Warehouse Command Centre"
description="Open inventory, shipping, replenishment, analytics and administration workspaces from one clean operational dashboard."
icon="fa-solid fa-gauge-high"
/>
icon="fa-solid fa-gauge-high" />
<div class="grid gap-6 lg:grid-cols-3">
<section class="rounded-2xl border border-zinc-200 bg-white p-6 shadow-sm dark:border-zinc-800 dark:bg-zinc-900">
<p class="text-sm font-semibold uppercase tracking-[0.2em] text-cyan-600 dark:text-cyan-300">Operations</p>
<h2 class="mt-3 text-2xl font-bold text-zinc-900 dark:text-white">Warehouse command centre</h2>
<p class="mt-2 text-sm leading-6 text-zinc-600 dark:text-zinc-300">Use the navigation to open inventory, shipping, replenishment, analytics and administration workspaces.</p>
<p class="mt-2 text-sm leading-6 text-zinc-600 dark:text-zinc-300">Use the navigation to open inventory,
shipping, replenishment, analytics and administration workspaces.</p>
</section>
<section class="rounded-2xl border border-zinc-200 bg-white p-6 shadow-sm dark:border-zinc-800 dark:bg-zinc-900">
<p class="text-sm font-semibold uppercase tracking-[0.2em] text-emerald-600 dark:text-emerald-300">Health</p>
<p class="text-sm font-semibold uppercase tracking-[0.2em] text-emerald-600 dark:text-emerald-300">Health
</p>
<h2 class="mt-3 text-2xl font-bold text-zinc-900 dark:text-white">System OK</h2>
<p class="mt-2 text-sm leading-6 text-zinc-600 dark:text-zinc-300">Core platform services are ready for module integration, testing and tenant configuration.</p>
<p class="mt-2 text-sm leading-6 text-zinc-600 dark:text-zinc-300">Core platform services are ready for
module integration, testing and tenant configuration.</p>
</section>
<section class="rounded-2xl border border-zinc-200 bg-white p-6 shadow-sm dark:border-zinc-800 dark:bg-zinc-900">
<section
class="rounded-2xl border border-zinc-200 bg-white p-6 shadow-sm dark:border-zinc-800 dark:bg-zinc-900">
<p class="text-sm font-semibold uppercase tracking-[0.2em] text-sky-600 dark:text-sky-300">Modules</p>
<h2 class="mt-3 text-2xl font-bold text-zinc-900 dark:text-white">Enabled workspaces</h2>
<p class="mt-2 text-sm leading-6 text-zinc-600 dark:text-zinc-300">Placeholder modules are wired into the sidebar and ready for production controllers.</p>
<p class="mt-2 text-sm leading-6 text-zinc-600 dark:text-zinc-300">Placeholder modules are wired into the
sidebar and ready for production controllers.</p>
</section>
</div>
</x-layouts::app>
+47 -42
View File
@@ -1,54 +1,59 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>@yield('title')</title>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Styles -->
<style>
html, body {
background-color: #fff;
color: #636b6f;
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
font-weight: 100;
height: 100vh;
margin: 0;
}
<title>@yield('title')</title>
.full-height {
height: 100vh;
}
<!-- Styles -->
<style>
html,
body {
background-color: #fff;
color: #636b6f;
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
font-weight: 100;
height: 100vh;
margin: 0;
}
.flex-center {
align-items: center;
display: flex;
justify-content: center;
}
.full-height {
height: 100vh;
}
.position-ref {
position: relative;
}
.flex-center {
align-items: center;
display: flex;
justify-content: center;
}
.content {
text-align: center;
}
.position-ref {
position: relative;
}
.title {
font-size: 36px;
padding: 20px;
}
</style>
</head>
<body>
<div data-dusk="page-ready" style="position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);" aria-hidden="true"></div>
<div class="flex-center position-ref full-height">
<div class="content">
<div class="title">
@yield('message')
</div>
.content {
text-align: center;
}
.title {
font-size: 36px;
padding: 20px;
}
</style>
</head>
<body>
<div data-dusk="page-ready" style="position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);"
aria-hidden="true"></div>
<div class="flex-center position-ref full-height">
<div class="content">
<div class="title">
@yield('message')
</div>
</div>
</body>
</div>
</body>
</html>
File diff suppressed because one or more lines are too long
@@ -25,23 +25,14 @@
};
@endphp
<svg
{{ $attributes->class($classes) }}
data-flux-icon
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="{{ $strokeWidth }}"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
data-slot="icon"
>
<svg {{ $attributes->class($classes) }} data-flux-icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="{{ $strokeWidth }}" stroke-linecap="round" stroke-linejoin="round"
aria-hidden="true" data-slot="icon">
<path d="M12 7v14" />
<path d="M16 12h2" />
<path d="M16 8h2" />
<path d="M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z" />
<path
d="M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z" />
<path d="M6 12h2" />
<path d="M6 8h2" />
</svg>
@@ -25,19 +25,9 @@
};
@endphp
<svg
{{ $attributes->class($classes) }}
data-flux-icon
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="{{ $strokeWidth }}"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
data-slot="icon"
>
<svg {{ $attributes->class($classes) }} data-flux-icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="{{ $strokeWidth }}" stroke-linecap="round" stroke-linejoin="round"
aria-hidden="true" data-slot="icon">
<path d="m7 15 5 5 5-5" />
<path d="m7 9 5-5 5 5" />
</svg>
@@ -25,19 +25,9 @@
};
@endphp
<svg
{{ $attributes->class($classes) }}
data-flux-icon
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="{{ $strokeWidth }}"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
data-slot="icon"
>
<svg {{ $attributes->class($classes) }} data-flux-icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="{{ $strokeWidth }}" stroke-linecap="round" stroke-linejoin="round"
aria-hidden="true" data-slot="icon">
<path d="M9 20H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H20a2 2 0 0 1 2 2v5" />
<circle cx="13" cy="12" r="2" />
<path d="M18 19c-2.8 0-5-2.2-5-5v8" />
@@ -25,19 +25,9 @@
};
@endphp
<svg
{{ $attributes->class($classes) }}
data-flux-icon
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="{{ $strokeWidth }}"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
data-slot="icon"
>
<svg {{ $attributes->class($classes) }} data-flux-icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="{{ $strokeWidth }}" stroke-linecap="round" stroke-linejoin="round"
aria-hidden="true" data-slot="icon">
<rect width="7" height="7" x="3" y="3" rx="1" />
<rect width="7" height="7" x="14" y="3" rx="1" />
<rect width="7" height="7" x="14" y="14" rx="1" />
+4 -9
View File
@@ -6,15 +6,10 @@
<?php if ($expandable && $heading): ?>
<ui-disclosure
{{ $attributes->class('group/disclosure') }}
@if ($expanded === true) open @endif
data-flux-navlist-group
>
<button
type="button"
class="group/disclosure-button mb-[2px] flex h-10 w-full items-center rounded-lg text-zinc-500 hover:bg-zinc-800/5 hover:text-zinc-800 lg:h-8 dark:text-white/80 dark:hover:bg-white/[7%] dark:hover:text-white"
>
<ui-disclosure {{ $attributes->class('group/disclosure') }} @if ($expanded === true) open @endif
data-flux-navlist-group>
<button type="button"
class="group/disclosure-button mb-[2px] flex h-10 w-full items-center rounded-lg text-zinc-500 hover:bg-zinc-800/5 hover:text-zinc-800 lg:h-8 dark:text-white/80 dark:hover:bg-white/[7%] dark:hover:text-white">
<div class="ps-3 pe-4">
<flux:icon.chevron-down class="hidden size-3! group-data-open/disclosure-button:block" />
<flux:icon.chevron-right class="block size-3! group-data-open/disclosure-button:hidden" />
+1 -4
View File
@@ -3,10 +3,7 @@
@endphp
@if (request()->routeIs('helpdesk.*') && file_exists($helpdeskManifestPath))
@vite([
'Resources/assets/js/app.js',
'Resources/assets/css/app.css',
], 'build/helpdesk')
@vite(['Resources/assets/js/app.js', 'Resources/assets/css/app.css'], 'build/helpdesk')
@endif
<x-layouts::app.sidebar :title="$title ?? null">
+73 -73
View File
@@ -1,85 +1,85 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" class="dark">
@include('partials.head')
@include('partials.head')
<body class="min-h-screen bg-white dark:bg-zinc-800">
<div data-dusk="page-ready" style="position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);" aria-hidden="true"></div>
<flux:header container class="border-b border-zinc-200 bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-900">
<flux:sidebar.toggle class="lg:hidden mr-2" icon="bars-2" inset="left" />
<body class="min-h-screen bg-white dark:bg-zinc-800">
<div data-dusk="page-ready" style="position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);"
aria-hidden="true"></div>
<flux:header container class="border-b border-zinc-200 bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-900">
<flux:sidebar.toggle class="lg:hidden mr-2" icon="bars-2" inset="left" />
<x-app-logo href="{{ route('dashboard') }}" wire:navigate />
<x-app-logo href="{{ route('dashboard') }}" wire:navigate />
<flux:navbar class="-mb-px max-lg:hidden">
<flux:navbar.item icon="layout-grid" :href="route('dashboard')" :current="request()->routeIs('dashboard')" wire:navigate>
<flux:navbar class="-mb-px max-lg:hidden">
<flux:navbar.item icon="layout-grid" :href="route('dashboard')" :current="request()->routeIs('dashboard')"
wire:navigate>
{{ __('Dashboard') }}
</flux:navbar.item>
</flux:navbar>
<flux:spacer />
<flux:navbar class="me-1.5 space-x-0.5 rtl:space-x-reverse py-0!">
<flux:tooltip :content="__('Search')" position="bottom">
<flux:navbar.item class="!h-10 [&>div>svg]:size-5" icon="magnifying-glass" href="#"
:label="__('Search')" />
</flux:tooltip>
<flux:tooltip :content="__('Repository')" position="bottom">
<flux:navbar.item class="h-10 max-lg:hidden [&>div>svg]:size-5" icon="folder-git-2"
href="https://github.com/laravel/livewire-starter-kit" target="_blank" :label="__('Repository')" />
</flux:tooltip>
<flux:tooltip :content="__('Documentation')" position="bottom">
<flux:navbar.item class="h-10 max-lg:hidden [&>div>svg]:size-5" icon="book-open-text"
href="https://laravel.com/docs/starter-kits#livewire" target="_blank"
:label="__('Documentation')" />
</flux:tooltip>
</flux:navbar>
<x-desktop-user-menu />
</flux:header>
<!-- Mobile Menu -->
<flux:sidebar collapsible="mobile" sticky
class="lg:hidden border-e border-zinc-200 bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-900">
<flux:sidebar.header>
<x-app-logo :sidebar="true" href="{{ route('dashboard') }}" wire:navigate />
<flux:sidebar.collapse
class="in-data-flux-sidebar-on-desktop:not-in-data-flux-sidebar-collapsed-desktop:-mr-2" />
</flux:sidebar.header>
<flux:sidebar.nav>
<flux:sidebar.group :heading="__('Platform')">
<flux:sidebar.item icon="layout-grid" :href="route('dashboard')"
:current="request()->routeIs('dashboard')" wire:navigate>
{{ __('Dashboard') }}
</flux:navbar.item>
</flux:navbar>
<flux:spacer />
<flux:navbar class="me-1.5 space-x-0.5 rtl:space-x-reverse py-0!">
<flux:tooltip :content="__('Search')" position="bottom">
<flux:navbar.item class="!h-10 [&>div>svg]:size-5" icon="magnifying-glass" href="#" :label="__('Search')" />
</flux:tooltip>
<flux:tooltip :content="__('Repository')" position="bottom">
<flux:navbar.item
class="h-10 max-lg:hidden [&>div>svg]:size-5"
icon="folder-git-2"
href="https://github.com/laravel/livewire-starter-kit"
target="_blank"
:label="__('Repository')"
/>
</flux:tooltip>
<flux:tooltip :content="__('Documentation')" position="bottom">
<flux:navbar.item
class="h-10 max-lg:hidden [&>div>svg]:size-5"
icon="book-open-text"
href="https://laravel.com/docs/starter-kits#livewire"
target="_blank"
:label="__('Documentation')"
/>
</flux:tooltip>
</flux:navbar>
<x-desktop-user-menu />
</flux:header>
<!-- Mobile Menu -->
<flux:sidebar collapsible="mobile" sticky class="lg:hidden border-e border-zinc-200 bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-900">
<flux:sidebar.header>
<x-app-logo :sidebar="true" href="{{ route('dashboard') }}" wire:navigate />
<flux:sidebar.collapse class="in-data-flux-sidebar-on-desktop:not-in-data-flux-sidebar-collapsed-desktop:-mr-2" />
</flux:sidebar.header>
<flux:sidebar.nav>
<flux:sidebar.group :heading="__('Platform')">
<flux:sidebar.item icon="layout-grid" :href="route('dashboard')" :current="request()->routeIs('dashboard')" wire:navigate>
{{ __('Dashboard') }}
</flux:sidebar.item>
</flux:sidebar.group>
</flux:sidebar.nav>
<flux:spacer />
<flux:sidebar.nav>
<flux:sidebar.item icon="folder-git-2" href="https://github.com/laravel/livewire-starter-kit" target="_blank">
{{ __('Repository') }}
</flux:sidebar.item>
<flux:sidebar.item icon="book-open-text" href="https://laravel.com/docs/starter-kits#livewire" target="_blank">
{{ __('Documentation') }}
</flux:sidebar.item>
</flux:sidebar.nav>
</flux:sidebar>
</flux:sidebar.group>
</flux:sidebar.nav>
{{ $slot }}
<flux:spacer />
@persist('toast')
<flux:toast.group>
<flux:toast />
</flux:toast.group>
@endpersist
<flux:sidebar.nav>
<flux:sidebar.item icon="folder-git-2" href="https://github.com/laravel/livewire-starter-kit"
target="_blank">
{{ __('Repository') }}
</flux:sidebar.item>
<flux:sidebar.item icon="book-open-text" href="https://laravel.com/docs/starter-kits#livewire"
target="_blank">
{{ __('Documentation') }}
</flux:sidebar.item>
</flux:sidebar.nav>
</flux:sidebar>
{{ $slot }}
@persist('toast')
<flux:toast.group>
<flux:toast />
</flux:toast.group>
@endpersist
@fluxScripts
</body>
@fluxScripts
</body>
</html>
File diff suppressed because it is too large Load Diff
+29 -24
View File
@@ -1,34 +1,39 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" class="dark">
<head>
@include('partials.head')
</head>
<body class="min-h-screen bg-neutral-100 antialiased dark:bg-linear-to-b dark:from-neutral-950 dark:to-neutral-900">
<div data-dusk="page-ready" style="position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);" aria-hidden="true"></div>
<div class="bg-muted flex min-h-svh flex-col items-center justify-center gap-6 p-6 md:p-10">
<div class="flex w-full max-w-md flex-col gap-6">
<a href="{{ route('home') }}" class="flex flex-col items-center gap-2 font-medium" wire:navigate>
<span class="flex h-9 w-9 items-center justify-center rounded-md">
<x-app-logo-icon class="size-9 fill-current text-black dark:text-white" />
</span>
<span class="sr-only">{{ config('app.name', 'Laravel') }}</span>
</a>
<head>
@include('partials.head')
</head>
<div class="flex flex-col gap-6">
<div class="rounded-xl border bg-white dark:bg-stone-950 dark:border-stone-800 text-stone-800 shadow-xs">
<div class="px-10 py-8">{{ $slot }}</div>
</div>
<body class="min-h-screen bg-neutral-100 antialiased dark:bg-linear-to-b dark:from-neutral-950 dark:to-neutral-900">
<div data-dusk="page-ready" style="position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);"
aria-hidden="true"></div>
<div class="bg-muted flex min-h-svh flex-col items-center justify-center gap-6 p-6 md:p-10">
<div class="flex w-full max-w-md flex-col gap-6">
<a href="{{ route('home') }}" class="flex flex-col items-center gap-2 font-medium" wire:navigate>
<span class="flex h-9 w-9 items-center justify-center rounded-md">
<x-app-logo-icon class="size-9 fill-current text-black dark:text-white" />
</span>
<span class="sr-only">{{ config('app.name', 'Laravel') }}</span>
</a>
<div class="flex flex-col gap-6">
<div
class="rounded-xl border bg-white dark:bg-stone-950 dark:border-stone-800 text-stone-800 shadow-xs">
<div class="px-10 py-8">{{ $slot }}</div>
</div>
</div>
</div>
</div>
@persist('toast')
<flux:toast.group>
<flux:toast />
</flux:toast.group>
@endpersist
@persist('toast')
<flux:toast.group>
<flux:toast />
</flux:toast.group>
@endpersist
@fluxScripts
</body>
@fluxScripts
</body>
</html>
+27 -23
View File
@@ -1,30 +1,34 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" class="dark">
<head>
@include('partials.head')
</head>
<body class="min-h-screen bg-white antialiased dark:bg-linear-to-b dark:from-neutral-950 dark:to-neutral-900">
<div data-dusk="page-ready" style="position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);" aria-hidden="true"></div>
<div class="bg-background flex min-h-svh flex-col items-center justify-center gap-6 p-6 md:p-10">
<div class="flex w-full max-w-sm flex-col gap-2">
<a href="{{ route('home') }}" class="flex flex-col items-center gap-2 font-medium" wire:navigate>
<span class="flex h-9 w-9 mb-1 items-center justify-center rounded-md">
<x-app-logo-icon class="size-9 fill-current text-black dark:text-white" />
</span>
<span class="sr-only">{{ config('app.name', 'Laravel') }}</span>
</a>
<div class="flex flex-col gap-6">
{{ $slot }}
</div>
<head>
@include('partials.head')
</head>
<body class="min-h-screen bg-white antialiased dark:bg-linear-to-b dark:from-neutral-950 dark:to-neutral-900">
<div data-dusk="page-ready" style="position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);"
aria-hidden="true"></div>
<div class="bg-background flex min-h-svh flex-col items-center justify-center gap-6 p-6 md:p-10">
<div class="flex w-full max-w-sm flex-col gap-2">
<a href="{{ route('home') }}" class="flex flex-col items-center gap-2 font-medium" wire:navigate>
<span class="flex h-9 w-9 mb-1 items-center justify-center rounded-md">
<x-app-logo-icon class="size-9 fill-current text-black dark:text-white" />
</span>
<span class="sr-only">{{ config('app.name', 'Laravel') }}</span>
</a>
<div class="flex flex-col gap-6">
{{ $slot }}
</div>
</div>
</div>
@persist('toast')
<flux:toast.group>
<flux:toast />
</flux:toast.group>
@endpersist
@persist('toast')
<flux:toast.group>
<flux:toast />
</flux:toast.group>
@endpersist
@fluxScripts
</body>
@fluxScripts
</body>
</html>
+50 -41
View File
@@ -1,51 +1,60 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" class="dark">
<head>
@include('partials.head')
</head>
<body class="min-h-screen bg-white antialiased dark:bg-linear-to-b dark:from-neutral-950 dark:to-neutral-900">
<div data-dusk="page-ready" style="position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);" aria-hidden="true"></div>
<div class="relative grid h-dvh flex-col items-center justify-center px-8 sm:px-0 lg:max-w-none lg:grid-cols-2 lg:px-0">
<div class="bg-muted relative hidden h-full flex-col p-10 text-white lg:flex dark:border-e dark:border-neutral-800">
<div class="absolute inset-0 bg-neutral-900"></div>
<a href="{{ route('home') }}" class="relative z-20 flex items-center text-lg font-medium" wire:navigate>
<span class="flex h-10 w-10 items-center justify-center rounded-md">
<x-app-logo-icon class="me-2 h-7 fill-current text-white" />
</span>
{{ config('app.name', 'Laravel') }}
</a>
@php
[$message, $author] = str(Illuminate\Foundation\Inspiring::quotes()->random())->explode('-');
@endphp
<head>
@include('partials.head')
</head>
<div class="relative z-20 mt-auto">
<blockquote class="space-y-2">
<flux:heading size="lg">&ldquo;{{ trim($message) }}&rdquo;</flux:heading>
<footer><flux:heading>{{ trim($author) }}</flux:heading></footer>
</blockquote>
</div>
</div>
<div class="w-full lg:p-8">
<div class="mx-auto flex w-full flex-col justify-center space-y-6 sm:w-[350px]">
<a href="{{ route('home') }}" class="z-20 flex flex-col items-center gap-2 font-medium lg:hidden" wire:navigate>
<span class="flex h-9 w-9 items-center justify-center rounded-md">
<x-app-logo-icon class="size-9 fill-current text-black dark:text-white" />
</span>
<body class="min-h-screen bg-white antialiased dark:bg-linear-to-b dark:from-neutral-950 dark:to-neutral-900">
<div data-dusk="page-ready" style="position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);"
aria-hidden="true"></div>
<div
class="relative grid h-dvh flex-col items-center justify-center px-8 sm:px-0 lg:max-w-none lg:grid-cols-2 lg:px-0">
<div
class="bg-muted relative hidden h-full flex-col p-10 text-white lg:flex dark:border-e dark:border-neutral-800">
<div class="absolute inset-0 bg-neutral-900"></div>
<a href="{{ route('home') }}" class="relative z-20 flex items-center text-lg font-medium" wire:navigate>
<span class="flex h-10 w-10 items-center justify-center rounded-md">
<x-app-logo-icon class="me-2 h-7 fill-current text-white" />
</span>
{{ config('app.name', 'Laravel') }}
</a>
<span class="sr-only">{{ config('app.name', 'Laravel') }}</span>
</a>
{{ $slot }}
</div>
@php
[$message, $author] = str(Illuminate\Foundation\Inspiring::quotes()->random())->explode('-');
@endphp
<div class="relative z-20 mt-auto">
<blockquote class="space-y-2">
<flux:heading size="lg">&ldquo;{{ trim($message) }}&rdquo;</flux:heading>
<footer>
<flux:heading>{{ trim($author) }}</flux:heading>
</footer>
</blockquote>
</div>
</div>
<div class="w-full lg:p-8">
<div class="mx-auto flex w-full flex-col justify-center space-y-6 sm:w-[350px]">
<a href="{{ route('home') }}" class="z-20 flex flex-col items-center gap-2 font-medium lg:hidden"
wire:navigate>
<span class="flex h-9 w-9 items-center justify-center rounded-md">
<x-app-logo-icon class="size-9 fill-current text-black dark:text-white" />
</span>
@persist('toast')
<flux:toast.group>
<flux:toast />
</flux:toast.group>
@endpersist
<span class="sr-only">{{ config('app.name', 'Laravel') }}</span>
</a>
{{ $slot }}
</div>
</div>
</div>
@persist('toast')
<flux:toast.group>
<flux:toast />
</flux:toast.group>
@endpersist
@fluxScripts
</body>
@fluxScripts
</body>
</html>
@@ -1,33 +1,28 @@
{{-- Shared Application Top Bar --}}
@php
$user = auth()->user();
$dashboardRoute = Route::has('platform.dashboard') && method_exists($user, 'isMpbaPlatformAdmin') && $user?->isMpbaPlatformAdmin()
? 'platform.dashboard'
: (Route::has('dashboard') ? 'dashboard' : null);
$dashboardRoute =
Route::has('platform.dashboard') && method_exists($user, 'isMpbaPlatformAdmin') && $user?->isMpbaPlatformAdmin()
? 'platform.dashboard'
: (Route::has('dashboard')
? 'dashboard'
: null);
@endphp
<header class="sticky top-0 z-40 border-b border-white/10 bg-[#111118]/95 backdrop-blur" role="banner">
<div class="flex h-16 w-full items-center justify-between gap-3 px-3 sm:px-4 lg:px-6">
<div class="flex min-w-0 items-center gap-3 lg:hidden">
<button
type="button"
<button type="button"
class="inline-flex h-11 w-11 shrink-0 items-center justify-center rounded-xl border border-white/10 bg-white/5 text-white transition hover:bg-white/10 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-offset-2 focus:ring-offset-[#111118] lg:hidden"
data-wms-mobile-open
aria-label="{{ __('Open navigation menu') }}"
aria-controls="wms-main-sidebar"
aria-expanded="false"
data-test="mobile-menu-button"
>
data-wms-mobile-open aria-label="{{ __('Open navigation menu') }}" aria-controls="wms-main-sidebar"
aria-expanded="false" data-test="mobile-menu-button">
<i class="fa-solid fa-bars" aria-hidden="true"></i>
</button>
<a
href="{{ $dashboardRoute ? route($dashboardRoute) : '#' }}"
wire:navigate
class="flex min-w-0 items-center gap-3"
aria-label="{{ __('Warehouse Management System') }}"
>
<span class="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-cyan-600 text-sm font-bold text-white shadow-lg shadow-cyan-950/40">
<a href="{{ $dashboardRoute ? route($dashboardRoute) : '#' }}" wire:navigate
class="flex min-w-0 items-center gap-3" aria-label="{{ __('Warehouse Management System') }}">
<span
class="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-cyan-600 text-sm font-bold text-white shadow-lg shadow-cyan-950/40">
W
</span>
@@ -42,67 +37,64 @@
</a>
</div>
<div
id="userControls"
class="relative ml-auto flex shrink-0 items-center gap-3"
x-data="{ open: false }"
x-on:keydown.escape.window="open = false"
>
<button
type="button"
<div id="userControls" class="relative ml-auto flex shrink-0 items-center gap-3" x-data="{ open: false }"
x-on:keydown.escape.window="open = false">
<button type="button"
class="flex items-center gap-3 rounded-2xl border border-white/10 bg-white/5 px-2 py-2 text-left transition hover:bg-white/10 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-offset-2 focus:ring-offset-[#111118] sm:px-3"
x-on:click="open = ! open"
x-bind:aria-expanded="open.toString()"
aria-haspopup="menu"
data-test="top-user-menu-button"
>
x-on:click="open = ! open" x-bind:aria-expanded="open.toString()" aria-haspopup="menu"
data-test="top-user-menu-button">
<span class="hidden text-right md:block">
<span class="block max-w-48 truncate text-sm font-semibold text-white">{{ $user?->name ?? __('User') }}</span>
<span
class="block max-w-48 truncate text-sm font-semibold text-white">{{ $user?->name ?? __('User') }}</span>
<span class="block max-w-48 truncate text-xs text-white/50">{{ $user?->email ?? '' }}</span>
</span>
<span class="flex h-10 w-10 items-center justify-center rounded-full bg-blue-700 text-xs font-bold text-white shadow-lg shadow-blue-950/40">
<span
class="flex h-10 w-10 items-center justify-center rounded-full bg-blue-700 text-xs font-bold text-white shadow-lg shadow-blue-950/40">
{{ $user?->initials() ?? 'U' }}
</span>
<i class="fa-solid fa-chevron-down hidden text-white/50 sm:block" aria-hidden="true"></i>
</button>
<div
x-cloak
x-show="open"
x-transition.origin.top.right
x-on:click.outside="open = false"
<div x-cloak x-show="open" x-transition.origin.top.right x-on:click.outside="open = false"
class="absolute right-0 top-full mt-2 w-[calc(100vw-1.5rem)] max-w-72 overflow-hidden rounded-2xl border border-white/10 bg-[#181820] shadow-2xl shadow-black/40 sm:w-72"
role="menu"
>
role="menu">
<div class="border-b border-white/10 px-4 py-3">
<div class="truncate text-sm font-semibold text-white">{{ $user?->name ?? __('User') }}</div>
<div class="truncate text-xs text-white/50">{{ $user?->email ?? '' }}</div>
</div>
<div class="p-2">
@if($dashboardRoute)
<a href="{{ route($dashboardRoute) }}" wire:navigate class="block rounded-xl px-3 py-2 text-sm text-white/80 hover:bg-white/10 hover:text-white" role="menuitem">
@if ($dashboardRoute)
<a href="{{ route($dashboardRoute) }}" wire:navigate
class="block rounded-xl px-3 py-2 text-sm text-white/80 hover:bg-white/10 hover:text-white"
role="menuitem">
{{ __('Dashboard') }}
</a>
@endif
@if(Route::has('profile.edit'))
<a href="{{ route('profile.edit') }}" wire:navigate class="block rounded-xl px-3 py-2 text-sm text-white/80 hover:bg-white/10 hover:text-white" role="menuitem">
@if (Route::has('profile.edit'))
<a href="{{ route('profile.edit') }}" wire:navigate
class="block rounded-xl px-3 py-2 text-sm text-white/80 hover:bg-white/10 hover:text-white"
role="menuitem">
{{ __('Profile') }}
</a>
@endif
@if(Route::has('settings.index'))
<a href="{{ route('settings.index') }}" wire:navigate class="block rounded-xl px-3 py-2 text-sm text-white/80 hover:bg-white/10 hover:text-white" role="menuitem">
@if (Route::has('settings.index'))
<a href="{{ route('settings.index') }}" wire:navigate
class="block rounded-xl px-3 py-2 text-sm text-white/80 hover:bg-white/10 hover:text-white"
role="menuitem">
{{ __('Settings') }}
</a>
@endif
<form method="POST" action="{{ route('logout') }}" class="mt-2 border-t border-white/10 pt-2">
@csrf
<button type="submit" class="w-full rounded-xl px-3 py-2 text-left text-sm text-red-300 hover:bg-red-500/10 hover:text-red-200" role="menuitem" data-test="logout-button">
<button type="submit"
class="w-full rounded-xl px-3 py-2 text-left text-sm text-red-300 hover:bg-red-500/10 hover:text-red-200"
role="menuitem" data-test="logout-button">
{{ __('Sign out') }}
</button>
</form>
@@ -1,42 +1,38 @@
<x-layouts::auth :title="__('Confirm password')">
<section class="mx-auto w-full max-w-md overflow-hidden rounded-2xl border border-zinc-200 bg-white shadow-xl shadow-zinc-900/10 dark:border-zinc-800 dark:bg-zinc-950">
<section
class="mx-auto w-full max-w-md overflow-hidden rounded-2xl border border-zinc-200 bg-white shadow-xl shadow-zinc-900/10 dark:border-zinc-800 dark:bg-zinc-950">
<div class="h-1.5 bg-gradient-to-r from-emerald-500 via-sky-500 to-blue-600"></div>
<div class="space-y-7 p-6 sm:p-8">
<div class="space-y-5 text-center">
<div class="mx-auto flex h-14 w-14 items-center justify-center rounded-2xl bg-zinc-950 text-sm font-black text-white dark:bg-white dark:text-zinc-950">WMS</div>
<div
class="mx-auto flex h-14 w-14 items-center justify-center rounded-2xl bg-zinc-950 text-sm font-black text-white dark:bg-white dark:text-zinc-950">
WMS</div>
<div class="space-y-2">
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-sky-700 dark:text-sky-300">{{ __('Protected area') }}</p>
<h1 class="text-2xl font-bold tracking-tight text-zinc-950 dark:text-white">{{ __('Confirm password') }}</h1>
<p class="text-sm leading-6 text-zinc-600 dark:text-zinc-400">{{ __('Confirm your identity before continuing to this secure WMS workflow.') }}</p>
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-sky-700 dark:text-sky-300">
{{ __('Protected area') }}</p>
<h1 class="text-2xl font-bold tracking-tight text-zinc-950 dark:text-white">
{{ __('Confirm password') }}</h1>
<p class="text-sm leading-6 text-zinc-600 dark:text-zinc-400">
{{ __('Confirm your identity before continuing to this secure WMS workflow.') }}</p>
</div>
</div>
<div class="rounded-2xl border border-zinc-200 bg-zinc-50 p-5 dark:border-zinc-800 dark:bg-zinc-900/60">
<x-auth-session-status class="mb-5 rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-center text-sm text-emerald-800 dark:border-emerald-900/60 dark:bg-emerald-950/40 dark:text-emerald-200" :status="session('status')" />
<x-auth-session-status
class="mb-5 rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-center text-sm text-emerald-800 dark:border-emerald-900/60 dark:bg-emerald-950/40 dark:text-emerald-200"
:status="session('status')" />
<div class="mb-5">
<x-passkey-verify
options-route="passkey.confirm-options"
submit-route="passkey.confirm"
:label="__('Confirm with passkey')"
:loading-label="__('Confirming...')"
:separator="__('Or confirm with password')"
/>
<x-passkey-verify options-route="passkey.confirm-options" submit-route="passkey.confirm"
:label="__('Confirm with passkey')" :loading-label="__('Confirming...')" :separator="__('Or confirm with password')" />
</div>
<form method="POST" action="{{ route('password.confirm.store') }}" class="flex flex-col gap-5">
@csrf
<flux:input
name="password"
:label="__('Password')"
type="password"
required
autocomplete="current-password"
:placeholder="__('Password')"
viewable
/>
<flux:input name="password" :label="__('Password')" type="password" required
autocomplete="current-password" :placeholder="__('Password')" viewable />
<flux:button variant="primary" type="submit" class="w-full" data-test="confirm-password-button">
{{ __('Confirm') }}
@@ -1,35 +1,38 @@
<x-layouts::auth :title="__('Forgot password')">
<section class="mx-auto w-full max-w-md overflow-hidden rounded-2xl border border-zinc-200 bg-white shadow-xl shadow-zinc-900/10 dark:border-zinc-800 dark:bg-zinc-950">
<section
class="mx-auto w-full max-w-md overflow-hidden rounded-2xl border border-zinc-200 bg-white shadow-xl shadow-zinc-900/10 dark:border-zinc-800 dark:bg-zinc-950">
<div class="h-1.5 bg-gradient-to-r from-emerald-500 via-sky-500 to-blue-600"></div>
<div class="space-y-7 p-6 sm:p-8">
<div class="space-y-5 text-center">
<div class="mx-auto flex h-14 w-14 items-center justify-center rounded-2xl bg-zinc-950 text-sm font-black text-white dark:bg-white dark:text-zinc-950">WMS</div>
<div
class="mx-auto flex h-14 w-14 items-center justify-center rounded-2xl bg-zinc-950 text-sm font-black text-white dark:bg-white dark:text-zinc-950">
WMS</div>
<div class="space-y-2">
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-sky-700 dark:text-sky-300">{{ __('Account recovery') }}</p>
<h1 class="text-2xl font-bold tracking-tight text-zinc-950 dark:text-white">{{ __('Warehouse Management System') }}</h1>
<p class="text-sm leading-6 text-zinc-600 dark:text-zinc-400">{{ __('Request a secure reset link for your WMS account.') }}</p>
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-sky-700 dark:text-sky-300">
{{ __('Account recovery') }}</p>
<h1 class="text-2xl font-bold tracking-tight text-zinc-950 dark:text-white">
{{ __('Warehouse Management System') }}</h1>
<p class="text-sm leading-6 text-zinc-600 dark:text-zinc-400">
{{ __('Request a secure reset link for your WMS account.') }}</p>
</div>
</div>
<div class="rounded-2xl border border-zinc-200 bg-zinc-50 p-5 dark:border-zinc-800 dark:bg-zinc-900/60">
<x-auth-header :title="__('Forgot password')" :description="__('Enter your email address and we will send you a password reset link.')" />
<x-auth-session-status class="mt-5 rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-center text-sm text-emerald-800 dark:border-emerald-900/60 dark:bg-emerald-950/40 dark:text-emerald-200" :status="session('status')" />
<x-auth-session-status
class="mt-5 rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-center text-sm text-emerald-800 dark:border-emerald-900/60 dark:bg-emerald-950/40 dark:text-emerald-200"
:status="session('status')" />
<form method="POST" action="{{ route('password.email') }}" class="mt-6 flex flex-col gap-5">
@csrf
<flux:input
name="email"
:label="__('Email address')"
type="email"
required
autofocus
placeholder="email@example.com"
/>
<flux:input name="email" :label="__('Email address')" type="email" required autofocus
placeholder="email@example.com" />
<flux:button variant="primary" type="submit" class="w-full" data-test="email-password-reset-link-button">
<flux:button variant="primary" type="submit" class="w-full"
data-test="email-password-reset-link-button">
{{ __('Email password reset link') }}
</flux:button>
</form>
+46 -19
View File
@@ -1,28 +1,38 @@
<x-layouts::auth :title="__('Log in')">
<section class="mx-auto w-full max-w-md overflow-hidden rounded-2xl border border-zinc-200 bg-white shadow-xl shadow-zinc-900/10 dark:border-zinc-800 dark:bg-zinc-950">
<section
class="mx-auto w-full max-w-md overflow-hidden rounded-2xl border border-zinc-200 bg-white shadow-xl shadow-zinc-900/10 dark:border-zinc-800 dark:bg-zinc-950">
<div class="h-1.5 bg-gradient-to-r from-emerald-500 via-sky-500 to-blue-600"></div>
<div class="space-y-7 p-6 sm:p-8">
<div class="space-y-5 text-center">
<div class="mx-auto flex h-14 w-14 items-center justify-center rounded-2xl bg-zinc-950 text-sm font-black tracking-tight text-white shadow-lg shadow-zinc-900/20 dark:bg-white dark:text-zinc-950">
<div
class="mx-auto flex h-14 w-14 items-center justify-center rounded-2xl bg-zinc-950 text-sm font-black tracking-tight text-white shadow-lg shadow-zinc-900/20 dark:bg-white dark:text-zinc-950">
WMS
</div>
<div class="space-y-2">
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-sky-700 dark:text-sky-300">MPBA Limited</p>
<h1 class="text-2xl font-bold tracking-tight text-zinc-950 dark:text-white">{{ __('Warehouse Management System') }}</h1>
<p class="text-sm leading-6 text-zinc-600 dark:text-zinc-400">{{ __('Secure access for tenant workspaces, warehouse operations, support, licences, and dashboards.') }}</p>
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-sky-700 dark:text-sky-300">MPBA
Limited</p>
<h1 class="text-2xl font-bold tracking-tight text-zinc-950 dark:text-white">
{{ __('Warehouse Management System') }}</h1>
<p class="text-sm leading-6 text-zinc-600 dark:text-zinc-400">
{{ __('Secure access for tenant workspaces, warehouse operations, support, licences, and dashboards.') }}
</p>
</div>
</div>
<div class="rounded-2xl border border-zinc-200 bg-zinc-50 p-5 dark:border-zinc-800 dark:bg-zinc-900/60">
<div class="mb-6 space-y-1 text-center">
<p class="text-xs font-semibold uppercase tracking-[0.22em] text-sky-700 dark:text-sky-300">{{ __('Secure sign in') }}</p>
<p class="text-xs font-semibold uppercase tracking-[0.22em] text-sky-700 dark:text-sky-300">
{{ __('Secure sign in') }}</p>
<h2 class="text-xl font-bold text-zinc-950 dark:text-white">{{ __('Log in to your account') }}</h2>
<p class="text-sm text-zinc-600 dark:text-zinc-400">{{ __('Enter your email and password to continue.') }}</p>
<p class="text-sm text-zinc-600 dark:text-zinc-400">
{{ __('Enter your email and password to continue.') }}</p>
</div>
<x-auth-session-status class="mb-5 rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-center text-sm text-emerald-800 dark:border-emerald-900/60 dark:bg-emerald-950/40 dark:text-emerald-200" :status="session('status')" />
<x-auth-session-status
class="mb-5 rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-center text-sm text-emerald-800 dark:border-emerald-900/60 dark:bg-emerald-950/40 dark:text-emerald-200"
:status="session('status')" />
<div class="mb-5">
<x-passkey-verify />
@@ -32,28 +42,44 @@
@csrf
<div class="grid gap-2">
<label for="email" class="text-sm font-semibold text-zinc-800 dark:text-zinc-200">{{ __('Email address') }}</label>
<input id="email" name="email" type="email" value="{{ old('email') }}" required autofocus autocomplete="email" placeholder="email@example.com" class="w-full rounded-xl border border-zinc-300 bg-white px-4 py-3 text-sm text-zinc-950 shadow-sm outline-none transition placeholder:text-zinc-400 focus:border-sky-500 focus:ring-4 focus:ring-sky-100 dark:border-zinc-700 dark:bg-zinc-950 dark:text-white dark:placeholder:text-zinc-500 dark:focus:border-sky-400 dark:focus:ring-sky-950" />
@error('email')<p class="text-sm font-medium text-red-600 dark:text-red-400">{{ $message }}</p>@enderror
<label for="email"
class="text-sm font-semibold text-zinc-800 dark:text-zinc-200">{{ __('Email address') }}</label>
<input id="email" name="email" type="email" value="{{ old('email') }}" required
autofocus autocomplete="email" placeholder="email@example.com"
class="w-full rounded-xl border border-zinc-300 bg-white px-4 py-3 text-sm text-zinc-950 shadow-sm outline-none transition placeholder:text-zinc-400 focus:border-sky-500 focus:ring-4 focus:ring-sky-100 dark:border-zinc-700 dark:bg-zinc-950 dark:text-white dark:placeholder:text-zinc-500 dark:focus:border-sky-400 dark:focus:ring-sky-950" />
@error('email')
<p class="text-sm font-medium text-red-600 dark:text-red-400">{{ $message }}</p>
@enderror
</div>
<div class="grid gap-2">
<div class="flex items-center justify-between gap-3">
<label for="password" class="text-sm font-semibold text-zinc-800 dark:text-zinc-200">{{ __('Password') }}</label>
<label for="password"
class="text-sm font-semibold text-zinc-800 dark:text-zinc-200">{{ __('Password') }}</label>
@if (Route::has('password.request'))
<a class="text-sm font-semibold text-sky-700 underline underline-offset-4 hover:text-sky-900 dark:text-sky-300" href="{{ route('password.request') }}" wire:navigate>{{ __('Forgot password?') }}</a>
<a class="text-sm font-semibold text-sky-700 underline underline-offset-4 hover:text-sky-900 dark:text-sky-300"
href="{{ route('password.request') }}"
wire:navigate>{{ __('Forgot password?') }}</a>
@endif
</div>
<input id="password" name="password" type="password" required autocomplete="current-password" placeholder="{{ __('Password') }}" class="w-full rounded-xl border border-zinc-300 bg-white px-4 py-3 text-sm text-zinc-950 shadow-sm outline-none transition placeholder:text-zinc-400 focus:border-sky-500 focus:ring-4 focus:ring-sky-100 dark:border-zinc-700 dark:bg-zinc-950 dark:text-white dark:placeholder:text-zinc-500 dark:focus:border-sky-400 dark:focus:ring-sky-950" />
@error('password')<p class="text-sm font-medium text-red-600 dark:text-red-400">{{ $message }}</p>@enderror
<input id="password" name="password" type="password" required autocomplete="current-password"
placeholder="{{ __('Password') }}"
class="w-full rounded-xl border border-zinc-300 bg-white px-4 py-3 text-sm text-zinc-950 shadow-sm outline-none transition placeholder:text-zinc-400 focus:border-sky-500 focus:ring-4 focus:ring-sky-100 dark:border-zinc-700 dark:bg-zinc-950 dark:text-white dark:placeholder:text-zinc-500 dark:focus:border-sky-400 dark:focus:ring-sky-950" />
@error('password')
<p class="text-sm font-medium text-red-600 dark:text-red-400">{{ $message }}</p>
@enderror
</div>
<label class="flex items-center gap-3 rounded-xl border border-zinc-200 bg-white px-4 py-3 text-sm text-zinc-700 dark:border-zinc-800 dark:bg-zinc-950 dark:text-zinc-300">
<input name="remember" type="checkbox" value="1" @checked(old('remember')) class="rounded border-zinc-300 text-sky-600 focus:ring-sky-500 dark:border-zinc-700 dark:bg-zinc-950" />
<label
class="flex items-center gap-3 rounded-xl border border-zinc-200 bg-white px-4 py-3 text-sm text-zinc-700 dark:border-zinc-800 dark:bg-zinc-950 dark:text-zinc-300">
<input name="remember" type="checkbox" value="1" @checked(old('remember'))
class="rounded border-zinc-300 text-sky-600 focus:ring-sky-500 dark:border-zinc-700 dark:bg-zinc-950" />
<span>{{ __('Remember this device') }}</span>
</label>
<button type="submit" class="w-full rounded-xl bg-zinc-950 px-4 py-3 text-sm font-bold text-white shadow-sm transition hover:bg-zinc-800 focus:outline-none focus:ring-4 focus:ring-sky-200 dark:bg-white dark:text-zinc-950 dark:hover:bg-zinc-200 dark:focus:ring-sky-950" data-test="login-button">
<button type="submit"
class="w-full rounded-xl bg-zinc-950 px-4 py-3 text-sm font-bold text-white shadow-sm transition hover:bg-zinc-800 focus:outline-none focus:ring-4 focus:ring-sky-200 dark:bg-white dark:text-zinc-950 dark:hover:bg-zinc-200 dark:focus:ring-sky-950"
data-test="login-button">
{{ __('Log in') }}
</button>
</form>
@@ -61,7 +87,8 @@
<div class="text-center text-sm text-zinc-600 dark:text-zinc-400">
<span>{{ __('Need access?') }}</span>
<a href="{{ route('register') }}" wire:navigate class="font-semibold text-sky-700 underline underline-offset-4 hover:text-sky-900 dark:text-sky-300">{{ __('Create an account') }}</a>
<a href="{{ route('register') }}" wire:navigate
class="font-semibold text-sky-700 underline underline-offset-4 hover:text-sky-900 dark:text-sky-300">{{ __('Create an account') }}</a>
</div>
</div>
</section>
@@ -1,50 +1,77 @@
<x-layouts::auth :title="__('Register')">
<section class="mx-auto w-full max-w-md overflow-hidden rounded-2xl border border-zinc-200 bg-white shadow-xl shadow-zinc-900/10 dark:border-zinc-800 dark:bg-zinc-950">
<section
class="mx-auto w-full max-w-md overflow-hidden rounded-2xl border border-zinc-200 bg-white shadow-xl shadow-zinc-900/10 dark:border-zinc-800 dark:bg-zinc-950">
<div class="h-1.5 bg-gradient-to-r from-emerald-500 via-sky-500 to-blue-600"></div>
<div class="space-y-7 p-6 sm:p-8">
<div class="space-y-5 text-center">
<div class="mx-auto flex h-14 w-14 items-center justify-center rounded-2xl bg-zinc-950 text-sm font-black tracking-tight text-white shadow-lg shadow-zinc-900/20 dark:bg-white dark:text-zinc-950">
<div
class="mx-auto flex h-14 w-14 items-center justify-center rounded-2xl bg-zinc-950 text-sm font-black tracking-tight text-white shadow-lg shadow-zinc-900/20 dark:bg-white dark:text-zinc-950">
WMS
</div>
<div class="space-y-2">
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-sky-700 dark:text-sky-300">{{ __('MPBA Limited') }}</p>
<h1 class="text-2xl font-bold tracking-tight text-zinc-950 dark:text-white">{{ __('Create your WMS account') }}</h1>
<p class="text-sm leading-6 text-zinc-600 dark:text-zinc-400">{{ __('Register for secure access to your company workspace and warehouse operations.') }}</p>
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-sky-700 dark:text-sky-300">
{{ __('MPBA Limited') }}</p>
<h1 class="text-2xl font-bold tracking-tight text-zinc-950 dark:text-white">
{{ __('Create your WMS account') }}</h1>
<p class="text-sm leading-6 text-zinc-600 dark:text-zinc-400">
{{ __('Register for secure access to your company workspace and warehouse operations.') }}</p>
</div>
</div>
<div class="rounded-2xl border border-zinc-200 bg-zinc-50 p-5 dark:border-zinc-800 dark:bg-zinc-900/60">
<x-auth-session-status class="mb-5 rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-center text-sm text-emerald-800 dark:border-emerald-900/60 dark:bg-emerald-950/40 dark:text-emerald-200" :status="session('status')" />
<x-auth-session-status
class="mb-5 rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-center text-sm text-emerald-800 dark:border-emerald-900/60 dark:bg-emerald-950/40 dark:text-emerald-200"
:status="session('status')" />
<form method="POST" action="{{ route('register.store') }}" class="flex flex-col gap-5">
@csrf
<div class="grid gap-2">
<label for="name" class="text-sm font-semibold text-zinc-800 dark:text-zinc-200">{{ __('Name') }}</label>
<input id="name" name="name" type="text" value="{{ old('name') }}" required autofocus autocomplete="name" placeholder="{{ __('Full name') }}" class="w-full rounded-xl border border-zinc-300 bg-white px-4 py-3 text-sm text-zinc-950 shadow-sm outline-none transition placeholder:text-zinc-400 focus:border-sky-500 focus:ring-4 focus:ring-sky-100 dark:border-zinc-700 dark:bg-zinc-950 dark:text-white dark:placeholder:text-zinc-500 dark:focus:border-sky-400 dark:focus:ring-sky-950" />
@error('name')<p class="text-sm font-medium text-red-600 dark:text-red-400">{{ $message }}</p>@enderror
<label for="name"
class="text-sm font-semibold text-zinc-800 dark:text-zinc-200">{{ __('Name') }}</label>
<input id="name" name="name" type="text" value="{{ old('name') }}" required
autofocus autocomplete="name" placeholder="{{ __('Full name') }}"
class="w-full rounded-xl border border-zinc-300 bg-white px-4 py-3 text-sm text-zinc-950 shadow-sm outline-none transition placeholder:text-zinc-400 focus:border-sky-500 focus:ring-4 focus:ring-sky-100 dark:border-zinc-700 dark:bg-zinc-950 dark:text-white dark:placeholder:text-zinc-500 dark:focus:border-sky-400 dark:focus:ring-sky-950" />
@error('name')
<p class="text-sm font-medium text-red-600 dark:text-red-400">{{ $message }}</p>
@enderror
</div>
<div class="grid gap-2">
<label for="email" class="text-sm font-semibold text-zinc-800 dark:text-zinc-200">{{ __('Email address') }}</label>
<input id="email" name="email" type="email" value="{{ old('email') }}" required autocomplete="email" placeholder="email@example.com" class="w-full rounded-xl border border-zinc-300 bg-white px-4 py-3 text-sm text-zinc-950 shadow-sm outline-none transition placeholder:text-zinc-400 focus:border-sky-500 focus:ring-4 focus:ring-sky-100 dark:border-zinc-700 dark:bg-zinc-950 dark:text-white dark:placeholder:text-zinc-500 dark:focus:border-sky-400 dark:focus:ring-sky-950" />
@error('email')<p class="text-sm font-medium text-red-600 dark:text-red-400">{{ $message }}</p>@enderror
<label for="email"
class="text-sm font-semibold text-zinc-800 dark:text-zinc-200">{{ __('Email address') }}</label>
<input id="email" name="email" type="email" value="{{ old('email') }}" required
autocomplete="email" placeholder="email@example.com"
class="w-full rounded-xl border border-zinc-300 bg-white px-4 py-3 text-sm text-zinc-950 shadow-sm outline-none transition placeholder:text-zinc-400 focus:border-sky-500 focus:ring-4 focus:ring-sky-100 dark:border-zinc-700 dark:bg-zinc-950 dark:text-white dark:placeholder:text-zinc-500 dark:focus:border-sky-400 dark:focus:ring-sky-950" />
@error('email')
<p class="text-sm font-medium text-red-600 dark:text-red-400">{{ $message }}</p>
@enderror
</div>
<div class="grid gap-2">
<label for="password" class="text-sm font-semibold text-zinc-800 dark:text-zinc-200">{{ __('Password') }}</label>
<input id="password" name="password" type="password" required autocomplete="new-password" placeholder="{{ __('Password') }}" class="w-full rounded-xl border border-zinc-300 bg-white px-4 py-3 text-sm text-zinc-950 shadow-sm outline-none transition placeholder:text-zinc-400 focus:border-sky-500 focus:ring-4 focus:ring-sky-100 dark:border-zinc-700 dark:bg-zinc-950 dark:text-white dark:placeholder:text-zinc-500 dark:focus:border-sky-400 dark:focus:ring-sky-950" />
@error('password')<p class="text-sm font-medium text-red-600 dark:text-red-400">{{ $message }}</p>@enderror
<label for="password"
class="text-sm font-semibold text-zinc-800 dark:text-zinc-200">{{ __('Password') }}</label>
<input id="password" name="password" type="password" required autocomplete="new-password"
placeholder="{{ __('Password') }}"
class="w-full rounded-xl border border-zinc-300 bg-white px-4 py-3 text-sm text-zinc-950 shadow-sm outline-none transition placeholder:text-zinc-400 focus:border-sky-500 focus:ring-4 focus:ring-sky-100 dark:border-zinc-700 dark:bg-zinc-950 dark:text-white dark:placeholder:text-zinc-500 dark:focus:border-sky-400 dark:focus:ring-sky-950" />
@error('password')
<p class="text-sm font-medium text-red-600 dark:text-red-400">{{ $message }}</p>
@enderror
</div>
<div class="grid gap-2">
<label for="password_confirmation" class="text-sm font-semibold text-zinc-800 dark:text-zinc-200">{{ __('Confirm password') }}</label>
<input id="password_confirmation" name="password_confirmation" type="password" required autocomplete="new-password" placeholder="{{ __('Confirm password') }}" class="w-full rounded-xl border border-zinc-300 bg-white px-4 py-3 text-sm text-zinc-950 shadow-sm outline-none transition placeholder:text-zinc-400 focus:border-sky-500 focus:ring-4 focus:ring-sky-100 dark:border-zinc-700 dark:bg-zinc-950 dark:text-white dark:placeholder:text-zinc-500 dark:focus:border-sky-400 dark:focus:ring-sky-950" />
<label for="password_confirmation"
class="text-sm font-semibold text-zinc-800 dark:text-zinc-200">{{ __('Confirm password') }}</label>
<input id="password_confirmation" name="password_confirmation" type="password" required
autocomplete="new-password" placeholder="{{ __('Confirm password') }}"
class="w-full rounded-xl border border-zinc-300 bg-white px-4 py-3 text-sm text-zinc-950 shadow-sm outline-none transition placeholder:text-zinc-400 focus:border-sky-500 focus:ring-4 focus:ring-sky-100 dark:border-zinc-700 dark:bg-zinc-950 dark:text-white dark:placeholder:text-zinc-500 dark:focus:border-sky-400 dark:focus:ring-sky-950" />
</div>
<button type="submit" class="w-full rounded-xl bg-zinc-950 px-4 py-3 text-sm font-bold text-white shadow-sm transition hover:bg-zinc-800 focus:outline-none focus:ring-4 focus:ring-sky-200 dark:bg-white dark:text-zinc-950 dark:hover:bg-zinc-200 dark:focus:ring-sky-950" data-test="register-user-button">
<button type="submit"
class="w-full rounded-xl bg-zinc-950 px-4 py-3 text-sm font-bold text-white shadow-sm transition hover:bg-zinc-800 focus:outline-none focus:ring-4 focus:ring-sky-200 dark:bg-white dark:text-zinc-950 dark:hover:bg-zinc-200 dark:focus:ring-sky-950"
data-test="register-user-button">
{{ __('Create account') }}
</button>
</form>
@@ -52,7 +79,8 @@
<div class="text-center text-sm text-zinc-600 dark:text-zinc-400">
<span>{{ __('Already have access?') }}</span>
<a href="{{ route('login') }}" wire:navigate class="font-semibold text-sky-700 underline underline-offset-4 hover:text-sky-900 dark:text-sky-300">{{ __('Log in') }}</a>
<a href="{{ route('login') }}" wire:navigate
class="font-semibold text-sky-700 underline underline-offset-4 hover:text-sky-900 dark:text-sky-300">{{ __('Log in') }}</a>
</div>
</div>
</section>
@@ -1,54 +1,44 @@
<x-layouts::auth :title="__('Reset password')">
<section class="mx-auto w-full max-w-md overflow-hidden rounded-2xl border border-zinc-200 bg-white shadow-xl shadow-zinc-900/10 dark:border-zinc-800 dark:bg-zinc-950">
<section
class="mx-auto w-full max-w-md overflow-hidden rounded-2xl border border-zinc-200 bg-white shadow-xl shadow-zinc-900/10 dark:border-zinc-800 dark:bg-zinc-950">
<div class="h-1.5 bg-gradient-to-r from-emerald-500 via-sky-500 to-blue-600"></div>
<div class="space-y-7 p-6 sm:p-8">
<div class="space-y-5 text-center">
<div class="mx-auto flex h-14 w-14 items-center justify-center rounded-2xl bg-zinc-950 text-sm font-black text-white dark:bg-white dark:text-zinc-950">WMS</div>
<div
class="mx-auto flex h-14 w-14 items-center justify-center rounded-2xl bg-zinc-950 text-sm font-black text-white dark:bg-white dark:text-zinc-950">
WMS</div>
<div class="space-y-2">
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-sky-700 dark:text-sky-300">{{ __('Password reset') }}</p>
<h1 class="text-2xl font-bold tracking-tight text-zinc-950 dark:text-white">{{ __('Secure account recovery') }}</h1>
<p class="text-sm leading-6 text-zinc-600 dark:text-zinc-400">{{ __('Create a new password for your WMS account.') }}</p>
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-sky-700 dark:text-sky-300">
{{ __('Password reset') }}</p>
<h1 class="text-2xl font-bold tracking-tight text-zinc-950 dark:text-white">
{{ __('Secure account recovery') }}</h1>
<p class="text-sm leading-6 text-zinc-600 dark:text-zinc-400">
{{ __('Create a new password for your WMS account.') }}</p>
</div>
</div>
<div class="rounded-2xl border border-zinc-200 bg-zinc-50 p-5 dark:border-zinc-800 dark:bg-zinc-900/60">
<x-auth-session-status class="mb-5 rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-center text-sm text-emerald-800 dark:border-emerald-900/60 dark:bg-emerald-950/40 dark:text-emerald-200" :status="session('status')" />
<x-auth-session-status
class="mb-5 rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-center text-sm text-emerald-800 dark:border-emerald-900/60 dark:bg-emerald-950/40 dark:text-emerald-200"
:status="session('status')" />
<form method="POST" action="{{ route('password.update') }}" class="flex flex-col gap-5">
@csrf
<input type="hidden" name="token" value="{{ request()->route('token') }}">
<flux:input
name="email"
value="{{ request('email') }}"
:label="__('Email')"
type="email"
required
autocomplete="email"
/>
<flux:input name="email" value="{{ request('email') }}" :label="__('Email')" type="email"
required autocomplete="email" />
<flux:input
name="password"
:label="__('Password')"
type="password"
required
autocomplete="new-password"
:placeholder="__('Password')"
<flux:input name="password" :label="__('Password')" type="password" required
autocomplete="new-password" :placeholder="__('Password')"
passwordrules="{{ \Illuminate\Validation\Rules\Password::defaults()->toPasswordRulesString() }}"
viewable
/>
viewable />
<flux:input
name="password_confirmation"
:label="__('Confirm password')"
type="password"
required
autocomplete="new-password"
:placeholder="__('Confirm password')"
<flux:input name="password_confirmation" :label="__('Confirm password')" type="password" required
autocomplete="new-password" :placeholder="__('Confirm password')"
passwordrules="{{ \Illuminate\Validation\Rules\Password::defaults()->toPasswordRulesString() }}"
viewable
/>
viewable />
<flux:button type="submit" variant="primary" class="w-full" data-test="reset-password-button">
{{ __('Reset password') }}
@@ -1,59 +1,57 @@
<x-layouts::auth :title="__('Two-factor authentication')">
<section class="mx-auto w-full max-w-md overflow-hidden rounded-2xl border border-zinc-200 bg-white shadow-xl shadow-zinc-900/10 dark:border-zinc-800 dark:bg-zinc-950">
<section
class="mx-auto w-full max-w-md overflow-hidden rounded-2xl border border-zinc-200 bg-white shadow-xl shadow-zinc-900/10 dark:border-zinc-800 dark:bg-zinc-950">
<div class="h-1.5 bg-gradient-to-r from-emerald-500 via-sky-500 to-blue-600"></div>
<div class="space-y-7 p-6 sm:p-8">
<div class="space-y-5 text-center">
<div class="mx-auto flex h-14 w-14 items-center justify-center rounded-2xl bg-zinc-950 text-sm font-black text-white dark:bg-white dark:text-zinc-950">WMS</div>
<div
class="mx-auto flex h-14 w-14 items-center justify-center rounded-2xl bg-zinc-950 text-sm font-black text-white dark:bg-white dark:text-zinc-950">
WMS</div>
<div class="space-y-2">
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-sky-700 dark:text-sky-300">{{ __('Multi-factor security') }}</p>
<h1 class="text-2xl font-bold tracking-tight text-zinc-950 dark:text-white">{{ __('Verify your sign in') }}</h1>
<p class="text-sm leading-6 text-zinc-600 dark:text-zinc-400">{{ __('Complete the security challenge to continue into WMS.') }}</p>
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-sky-700 dark:text-sky-300">
{{ __('Multi-factor security') }}</p>
<h1 class="text-2xl font-bold tracking-tight text-zinc-950 dark:text-white">
{{ __('Verify your sign in') }}</h1>
<p class="text-sm leading-6 text-zinc-600 dark:text-zinc-400">
{{ __('Complete the security challenge to continue into WMS.') }}</p>
</div>
</div>
<div class="rounded-2xl border border-zinc-200 bg-zinc-50 p-5 dark:border-zinc-800 dark:bg-zinc-900/60">
<div
class="relative w-full h-auto"
x-cloak
x-data="{
showRecoveryInput: @js($errors->has('recovery_code')),
code: '',
recovery_code: '',
focusOtp() {
this.$nextTick(() => this.$refs.otp?.querySelector('input')?.focus());
},
init() {
if (! this.showRecoveryInput) {
<div class="relative w-full h-auto" x-cloak x-data="{
showRecoveryInput: @js($errors->has('recovery_code')),
code: '',
recovery_code: '',
focusOtp() {
this.$nextTick(() => this.$refs.otp?.querySelector('input')?.focus());
},
init() {
if (!this.showRecoveryInput) {
this.focusOtp();
}
},
toggleInput() {
this.showRecoveryInput = !this.showRecoveryInput;
this.code = '';
this.recovery_code = '';
$nextTick(() => {
this.showRecoveryInput ?
this.$refs.recovery_code?.focus() :
this.focusOtp();
}
},
toggleInput() {
this.showRecoveryInput = !this.showRecoveryInput;
this.code = '';
this.recovery_code = '';
$nextTick(() => {
this.showRecoveryInput
? this.$refs.recovery_code?.focus()
: this.focusOtp();
});
},
}"
>
});
},
}">
<div x-show="!showRecoveryInput">
<x-auth-header
:title="__('Authentication code')"
:description="__('Enter the authentication code provided by your authenticator application.')"
/>
<x-auth-header :title="__('Authentication code')" :description="__('Enter the authentication code provided by your authenticator application.')" />
</div>
<div x-show="showRecoveryInput">
<x-auth-header
:title="__('Recovery code')"
:description="__('Please confirm access to your account by entering one of your emergency recovery codes.')"
/>
<x-auth-header :title="__('Recovery code')" :description="__(
'Please confirm access to your account by entering one of your emergency recovery codes.',
)" />
</div>
<form method="POST" action="{{ route('two-factor.login.store') }}" class="mt-6">
@@ -62,27 +60,16 @@
<div class="space-y-5 text-center">
<div x-show="!showRecoveryInput">
<div class="my-5 flex items-center justify-center" x-ref="otp">
<flux:otp
x-model="code"
length="6"
name="code"
label="OTP Code"
label:sr-only
class="mx-auto"
/>
<flux:otp x-model="code" length="6" name="code" label="OTP Code"
label:sr-only class="mx-auto" />
</div>
</div>
<div x-show="showRecoveryInput">
<div class="my-5">
<flux:input
type="text"
name="recovery_code"
x-ref="recovery_code"
x-bind:required="showRecoveryInput"
autocomplete="one-time-code"
x-model="recovery_code"
/>
<flux:input type="text" name="recovery_code" x-ref="recovery_code"
x-bind:required="showRecoveryInput" autocomplete="one-time-code"
x-model="recovery_code" />
</div>
@error('recovery_code')
@@ -92,18 +79,16 @@
@enderror
</div>
<flux:button
variant="primary"
type="submit"
class="w-full"
>
<flux:button variant="primary" type="submit" class="w-full">
{{ __('Continue') }}
</flux:button>
</div>
<div class="mt-5 text-center text-sm leading-5 text-zinc-600 dark:text-zinc-400">
<span>{{ __('or you can') }}</span>
<button type="button" class="inline font-semibold text-sky-700 underline underline-offset-4 hover:text-sky-900 dark:text-sky-300" @click="toggleInput()">
<button type="button"
class="inline font-semibold text-sky-700 underline underline-offset-4 hover:text-sky-900 dark:text-sky-300"
@click="toggleInput()">
<span x-show="!showRecoveryInput">{{ __('login using a recovery code') }}</span>
<span x-show="showRecoveryInput">{{ __('login using an authentication code') }}</span>
</button>
@@ -1,14 +1,20 @@
<x-layouts::auth :title="__('Email verification')">
<section class="mx-auto w-full max-w-md overflow-hidden rounded-2xl border border-zinc-200 bg-white shadow-xl shadow-zinc-900/10 dark:border-zinc-800 dark:bg-zinc-950">
<section
class="mx-auto w-full max-w-md overflow-hidden rounded-2xl border border-zinc-200 bg-white shadow-xl shadow-zinc-900/10 dark:border-zinc-800 dark:bg-zinc-950">
<div class="h-1.5 bg-gradient-to-r from-emerald-500 via-sky-500 to-blue-600"></div>
<div class="space-y-7 p-6 sm:p-8">
<div class="space-y-5 text-center">
<div class="mx-auto flex h-14 w-14 items-center justify-center rounded-2xl bg-zinc-950 text-sm font-black text-white dark:bg-white dark:text-zinc-950">WMS</div>
<div
class="mx-auto flex h-14 w-14 items-center justify-center rounded-2xl bg-zinc-950 text-sm font-black text-white dark:bg-white dark:text-zinc-950">
WMS</div>
<div class="space-y-2">
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-sky-700 dark:text-sky-300">{{ __('Email verification') }}</p>
<h1 class="text-2xl font-bold tracking-tight text-zinc-950 dark:text-white">{{ __('Confirm your account') }}</h1>
<p class="text-sm leading-6 text-zinc-600 dark:text-zinc-400">{{ __('Verify your email address before accessing the WMS dashboard.') }}</p>
<p class="text-xs font-semibold uppercase tracking-[0.24em] text-sky-700 dark:text-sky-300">
{{ __('Email verification') }}</p>
<h1 class="text-2xl font-bold tracking-tight text-zinc-950 dark:text-white">
{{ __('Confirm your account') }}</h1>
<p class="text-sm leading-6 text-zinc-600 dark:text-zinc-400">
{{ __('Verify your email address before accessing the WMS dashboard.') }}</p>
</div>
</div>
@@ -18,7 +24,8 @@
</flux:text>
@if (session('status') == 'verification-link-sent')
<div class="mt-5 rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-center text-sm font-semibold text-emerald-800 dark:border-emerald-900/60 dark:bg-emerald-950/40 dark:text-emerald-200">
<div
class="mt-5 rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-center text-sm font-semibold text-emerald-800 dark:border-emerald-900/60 dark:bg-emerald-950/40 dark:text-emerald-200">
{{ __('A new verification link has been sent to the email address you provided during registration.') }}
</div>
@endif
@@ -33,7 +40,8 @@
<form method="POST" action="{{ route('logout') }}">
@csrf
<flux:button variant="ghost" type="submit" class="w-full cursor-pointer text-sm" data-test="logout-button">
<flux:button variant="ghost" type="submit" class="w-full cursor-pointer text-sm"
data-test="logout-button">
{{ __('Log out') }}
</flux:button>
</form>
@@ -3,7 +3,7 @@
<flux:heading class="sr-only">{{ __('Appearance settings') }}</flux:heading>
<x-settings.layout :heading="__('Appearance')" :subheading=" __('Update the appearance settings for your account')">
<x-settings.layout :heading="__('Appearance')" :subheading="__('Update the appearance settings for your account')">
<flux:radio.group x-data variant="segmented" x-model="$flux.appearance">
<flux:radio value="light" icon="sun">{{ __('Light') }}</flux:radio>
<flux:radio value="dark" icon="moon">{{ __('Dark') }}</flux:radio>
@@ -5,7 +5,8 @@
</div>
<flux:modal.trigger name="confirm-user-deletion">
<flux:button variant="danger" x-data="" x-on:click.prevent="$dispatch('open-modal', 'confirm-user-deletion')">
<flux:button variant="danger" x-data=""
x-on:click.prevent="$dispatch('open-modal', 'confirm-user-deletion')">
{{ __('Delete account') }}
</flux:button>
</flux:modal.trigger>
@@ -15,7 +15,8 @@
<flux:text class="mt-4">
{{ __('Your email address is unverified.') }}
<flux:link class="text-sm cursor-pointer" wire:click.prevent="resendVerificationNotification">
<flux:link class="text-sm cursor-pointer"
wire:click.prevent="resendVerificationNotification">
{{ __('Click here to re-send the verification email.') }}
</flux:link>
</flux:text>
@@ -5,35 +5,20 @@
<x-settings.layout :heading="__('Update password')" :subheading="__('Ensure your account is using a long, random password to stay secure')">
<form method="POST" wire:submit="updatePassword" class="mt-6 space-y-6">
<flux:input
wire:model="current_password"
:label="__('Current password')"
type="password"
required
autocomplete="current-password"
viewable
/>
<flux:input
wire:model="password"
:label="__('New password')"
type="password"
required
<flux:input wire:model="current_password" :label="__('Current password')" type="password" required
autocomplete="current-password" viewable />
<flux:input wire:model="password" :label="__('New password')" type="password" required
autocomplete="new-password"
passwordrules="{{ \Illuminate\Validation\Rules\Password::defaults()->toPasswordRulesString() }}"
viewable
/>
<flux:input
wire:model="password_confirmation"
:label="__('Confirm password')"
type="password"
required
viewable />
<flux:input wire:model="password_confirmation" :label="__('Confirm password')" type="password" required
autocomplete="new-password"
passwordrules="{{ \Illuminate\Validation\Rules\Password::defaults()->toPasswordRulesString() }}"
viewable
/>
viewable />
<div class="flex items-center gap-4">
<flux:button variant="primary" type="submit" data-test="update-password-button">{{ __('Save') }}</flux:button>
<flux:button variant="primary" type="submit" data-test="update-password-button">{{ __('Save') }}
</flux:button>
</div>
</form>
@@ -50,10 +35,7 @@
</flux:text>
<div class="flex justify-start">
<flux:button
variant="danger"
wire:click="disable"
>
<flux:button variant="danger" wire:click="disable">
{{ __('Disable 2FA') }}
</flux:button>
</div>
@@ -66,10 +48,7 @@
{{ __('When you enable two-factor authentication, you will be prompted for a secure pin during login. This pin can be retrieved from a TOTP-supported application on your phone.') }}
</flux:text>
<flux:button
variant="primary"
wire:click="enable"
>
<flux:button variant="primary" wire:click="enable">
{{ __('Enable 2FA') }}
</flux:button>
</div>
@@ -79,29 +58,29 @@
@endif
@if ($canManageTwoFactor)
<flux:modal
name="two-factor-setup-modal"
class="max-w-md md:min-w-md"
@close="closeModal"
wire:model="showModal"
>
<flux:modal name="two-factor-setup-modal" class="max-w-md md:min-w-md" @close="closeModal"
wire:model="showModal">
<div class="space-y-6">
<div class="flex flex-col items-center space-y-4">
<div class="p-0.5 w-auto rounded-full border border-stone-100 dark:border-stone-600 bg-white dark:bg-stone-800 shadow-sm">
<div class="p-2.5 rounded-full border border-stone-200 dark:border-stone-600 overflow-hidden bg-stone-100 dark:bg-stone-200 relative">
<div class="flex items-stretch absolute inset-0 w-full h-full divide-x [&>div]:flex-1 divide-stone-200 dark:divide-stone-300 justify-around opacity-50">
<div
class="p-0.5 w-auto rounded-full border border-stone-100 dark:border-stone-600 bg-white dark:bg-stone-800 shadow-sm">
<div
class="p-2.5 rounded-full border border-stone-200 dark:border-stone-600 overflow-hidden bg-stone-100 dark:bg-stone-200 relative">
<div
class="flex items-stretch absolute inset-0 w-full h-full divide-x [&>div]:flex-1 divide-stone-200 dark:divide-stone-300 justify-around opacity-50">
@for ($i = 1; $i <= 5; $i++)
<div></div>
@endfor
</div>
<div class="flex flex-col items-stretch absolute w-full h-full divide-y [&>div]:flex-1 inset-0 divide-stone-200 dark:divide-stone-300 justify-around opacity-50">
<div
class="flex flex-col items-stretch absolute w-full h-full divide-y [&>div]:flex-1 inset-0 divide-stone-200 dark:divide-stone-300 justify-around opacity-50">
@for ($i = 1; $i <= 5; $i++)
<div></div>
@endfor
</div>
<flux:icon.qr-code class="relative z-20 dark:text-accent-foreground"/>
<flux:icon.qr-code class="relative z-20 dark:text-accent-foreground" />
</div>
</div>
@@ -113,215 +92,175 @@
@if ($showVerificationStep)
<div class="space-y-6">
<div
class="flex flex-col items-center space-y-3 justify-center"
x-data
x-init="$nextTick(() => $el.querySelector('input')?.focus())"
>
<flux:otp
name="code"
wire:model="code"
length="6"
label="OTP Code"
label:sr-only
class="mx-auto"
/>
<div class="flex flex-col items-center space-y-3 justify-center" x-data
x-init="$nextTick(() => $el.querySelector('input')?.focus())">
<flux:otp name="code" wire:model="code" length="6" label="OTP Code" label:sr-only
class="mx-auto" />
</div>
<div class="flex items-center space-x-3">
<flux:button
variant="outline"
class="flex-1"
wire:click="resetVerification"
>
<flux:button variant="outline" class="flex-1" wire:click="resetVerification">
{{ __('Back') }}
</flux:button>
<flux:button
variant="primary"
class="flex-1"
wire:click="confirmTwoFactor"
x-bind:disabled="$wire.code.length < 6"
>
<flux:button variant="primary" class="flex-1" wire:click="confirmTwoFactor"
x-bind:disabled="$wire.code.length < 6">
{{ __('Confirm') }}
</flux:button>
</div>
</div>
@else
@error('setupData')
<flux:callout variant="danger" icon="x-circle" heading="{{ $message }}"/>
<flux:callout variant="danger" icon="x-circle" heading="{{ $message }}" />
@enderror
<div class="flex justify-center">
<div class="relative w-64 overflow-hidden border rounded-lg border-stone-200 dark:border-stone-700 aspect-square">
@empty($qrCodeSvg)
<div class="absolute inset-0 flex items-center justify-center bg-white dark:bg-stone-700 animate-pulse">
<flux:icon.loading/>
</div>
@else
<div x-data class="flex items-center justify-center h-full p-4">
<div
class="bg-white p-3 rounded"
:style="($flux.appearance === 'dark' || ($flux.appearance === 'system' && $flux.dark)) ? 'filter: invert(1) brightness(1.5)' : ''"
>
{!! $qrCodeSvg !!}
</div>
</div>
@endempty
</div>
</div>
<div>
<flux:button
:disabled="$errors->has('setupData')"
variant="primary"
class="w-full"
wire:click="showVerificationIfNecessary"
>
{{ $this->modalConfig['buttonText'] }}
</flux:button>
</div>
<div class="space-y-4">
<div class="relative flex items-center justify-center w-full">
<div class="absolute inset-0 w-full h-px top-1/2 bg-stone-200 dark:bg-stone-600"></div>
<span class="relative px-2 text-sm bg-white dark:bg-stone-800 text-stone-600 dark:text-stone-400">
{{ __('or, enter the code manually') }}
</span>
</div>
<div
class="flex items-center space-x-2"
x-data="{
copied: false,
async copy() {
try {
await navigator.clipboard.writeText('{{ $manualSetupKey }}');
this.copied = true;
setTimeout(() => this.copied = false, 1500);
} catch (e) {
console.warn('Could not copy to clipboard');
}
}
}"
>
<div class="flex items-stretch w-full border rounded-xl dark:border-stone-700">
@empty($manualSetupKey)
<div class="flex items-center justify-center w-full p-3 bg-stone-100 dark:bg-stone-700">
<flux:icon.loading variant="mini"/>
</div>
@else
<input
type="text"
readonly
value="{{ $manualSetupKey }}"
class="w-full p-3 bg-transparent outline-none text-stone-900 dark:text-stone-100"
/>
<button
@click="copy()"
class="px-3 transition-colors border-l cursor-pointer border-stone-200 dark:border-stone-600"
>
<flux:icon.document-duplicate x-show="!copied" variant="outline"></flux:icon>
<flux:icon.check
x-show="copied"
variant="solid"
class="text-green-500"
></flux:icon>
</button>
@endempty
class="relative w-64 overflow-hidden border rounded-lg border-stone-200 dark:border-stone-700 aspect-square">
@empty($qrCodeSvg)
<div
class="absolute inset-0 flex items-center justify-center bg-white dark:bg-stone-700 animate-pulse">
<flux:icon.loading />
</div>
</div>
@else
<div x-data class="flex items-center justify-center h-full p-4">
<div class="bg-white p-3 rounded"
:style="($flux.appearance === 'dark' || ($flux.appearance === 'system' && $flux
.dark)) ? 'filter: invert(1) brightness(1.5)' : ''">
{!! $qrCodeSvg !!}
</div>
</div>
@endempty
</div>
@endif
</div>
</flux:modal>
@endif
@if ($canManagePasskeys)
<section class="mt-12">
<flux:heading>{{ __('Passkeys') }}</flux:heading>
<flux:subheading>{{ __('Manage your passkeys for passwordless sign-in') }}</flux:subheading>
<div class="mt-6 flex flex-col w-full mx-auto space-y-6 text-sm" wire:cloak>
<div class="border rounded-lg border-zinc-200 dark:border-zinc-700 overflow-hidden">
@forelse ($passkeys as $passkey)
<div class="flex items-center justify-between p-4 {{ ! $loop->last ? 'border-b border-zinc-200 dark:border-zinc-700' : '' }}">
<div class="flex items-center gap-4">
<div class="flex size-10 shrink-0 items-center justify-center rounded-xl bg-zinc-100 dark:bg-zinc-800">
<flux:icon.key class="size-5 text-zinc-500 dark:text-zinc-400" />
</div>
<div class="space-y-1">
<div class="flex items-center gap-2.5">
<p class="font-medium tracking-tight">{{ $passkey['name'] }}</p>
@if ($passkey['authenticator'])
<flux:badge size="sm">{{ $passkey['authenticator'] }}</flux:badge>
@endif
</div>
<p class="text-zinc-500 dark:text-zinc-400 text-xs">
{{ __('Added :time', ['time' => $passkey['created_at_diff']]) }}
@if ($passkey['last_used_at_diff'])
<span class="opacity-50 mx-1">/</span>
{{ __('Last used :time', ['time' => $passkey['last_used_at_diff']]) }}
@endif
</p>
</div>
</div>
<flux:button
variant="ghost"
size="sm"
icon="trash"
icon:variant="outline"
wire:click="confirmDelete({{ $passkey['id'] }})"
class="text-red-500 hover:text-red-600 hover:bg-red-50 dark:hover:bg-red-950/50"
/>
</div>
@empty
<div class="p-8 text-center">
<div class="mx-auto mb-4 flex size-14 items-center justify-center rounded-2xl bg-zinc-100 dark:bg-zinc-800">
<flux:icon.key class="size-7 text-zinc-400 dark:text-zinc-500" />
</div>
<p class="font-medium">{{ __('No passkeys yet') }}</p>
<flux:text class="mt-1">{{ __('Add a passkey to sign in without a password') }}</flux:text>
</div>
@endforelse
</div>
<x-passkey-registration />
<div>
<flux:button :disabled="$errors->has('setupData')" variant="primary" class="w-full"
wire:click="showVerificationIfNecessary">
{{ $this->modalConfig['buttonText'] }}
</flux:button>
</div>
<div class="space-y-4">
<div class="relative flex items-center justify-center w-full">
<div class="absolute inset-0 w-full h-px top-1/2 bg-stone-200 dark:bg-stone-600"></div>
<span
class="relative px-2 text-sm bg-white dark:bg-stone-800 text-stone-600 dark:text-stone-400">
{{ __('or, enter the code manually') }}
</span>
</div>
<div class="flex items-center space-x-2" x-data="{
copied: false,
async copy() {
try {
await navigator.clipboard.writeText('{{ $manualSetupKey }}');
this.copied = true;
setTimeout(() => this.copied = false, 1500);
} catch (e) {
console.warn('Could not copy to clipboard');
}
}
}">
<div class="flex items-stretch w-full border rounded-xl dark:border-stone-700">
@empty($manualSetupKey)
<div
class="flex items-center justify-center w-full p-3 bg-stone-100 dark:bg-stone-700">
<flux:icon.loading variant="mini" />
</div>
@else
<input type="text" readonly value="{{ $manualSetupKey }}"
class="w-full p-3 bg-transparent outline-none text-stone-900 dark:text-stone-100" />
<button @click="copy()"
class="px-3 transition-colors border-l cursor-pointer border-stone-200 dark:border-stone-600">
<flux:icon.document-duplicate x-show="!copied" variant="outline"></flux:icon>
<flux:icon.check x-show="copied" variant="solid" class="text-green-500">
</flux:icon>
</button>
@endempty
</div>
</div>
</div>
</section>
@endif
</x-settings.layout>
<flux:modal
name="delete-passkey-modal"
class="max-w-md md:min-w-md"
@close="closeDeleteModal"
wire:model="showDeleteModal"
>
<div class="space-y-6">
<div class="space-y-2">
<flux:heading size="lg">{{ __('Remove passkey') }}</flux:heading>
<flux:text>
{{ __('Are you sure you want to remove the passkey ":name"? You will no longer be able to use it to sign in.', ['name' => $deletingPasskeyName]) }}
</flux:text>
</div>
<div class="flex gap-3 justify-end">
<flux:button
variant="outline"
wire:click="closeDeleteModal"
>
{{ __('Cancel') }}
</flux:button>
<flux:button
variant="danger"
wire:click="deletePasskey"
>
{{ __('Remove passkey') }}
</flux:button>
</div>
@endif
</div>
</flux:modal>
@endif
@if ($canManagePasskeys)
<section class="mt-12">
<flux:heading>{{ __('Passkeys') }}</flux:heading>
<flux:subheading>{{ __('Manage your passkeys for passwordless sign-in') }}</flux:subheading>
<div class="mt-6 flex flex-col w-full mx-auto space-y-6 text-sm" wire:cloak>
<div class="border rounded-lg border-zinc-200 dark:border-zinc-700 overflow-hidden">
@forelse ($passkeys as $passkey)
<div
class="flex items-center justify-between p-4 {{ !$loop->last ? 'border-b border-zinc-200 dark:border-zinc-700' : '' }}">
<div class="flex items-center gap-4">
<div
class="flex size-10 shrink-0 items-center justify-center rounded-xl bg-zinc-100 dark:bg-zinc-800">
<flux:icon.key class="size-5 text-zinc-500 dark:text-zinc-400" />
</div>
<div class="space-y-1">
<div class="flex items-center gap-2.5">
<p class="font-medium tracking-tight">{{ $passkey['name'] }}</p>
@if ($passkey['authenticator'])
<flux:badge size="sm">{{ $passkey['authenticator'] }}
</flux:badge>
@endif
</div>
<p class="text-zinc-500 dark:text-zinc-400 text-xs">
{{ __('Added :time', ['time' => $passkey['created_at_diff']]) }}
@if ($passkey['last_used_at_diff'])
<span class="opacity-50 mx-1">/</span>
{{ __('Last used :time', ['time' => $passkey['last_used_at_diff']]) }}
@endif
</p>
</div>
</div>
<flux:button variant="ghost" size="sm" icon="trash" icon:variant="outline"
wire:click="confirmDelete({{ $passkey['id'] }})"
class="text-red-500 hover:text-red-600 hover:bg-red-50 dark:hover:bg-red-950/50" />
</div>
@empty
<div class="p-8 text-center">
<div
class="mx-auto mb-4 flex size-14 items-center justify-center rounded-2xl bg-zinc-100 dark:bg-zinc-800">
<flux:icon.key class="size-7 text-zinc-400 dark:text-zinc-500" />
</div>
<p class="font-medium">{{ __('No passkeys yet') }}</p>
<flux:text class="mt-1">{{ __('Add a passkey to sign in without a password') }}
</flux:text>
</div>
@endforelse
</div>
<x-passkey-registration />
</div>
</section>
@endif
</x-settings.layout>
<flux:modal name="delete-passkey-modal" class="max-w-md md:min-w-md" @close="closeDeleteModal"
wire:model="showDeleteModal">
<div class="space-y-6">
<div class="space-y-2">
<flux:heading size="lg">{{ __('Remove passkey') }}</flux:heading>
<flux:text>
{{ __('Are you sure you want to remove the passkey ":name"? You will no longer be able to use it to sign in.', ['name' => $deletingPasskeyName]) }}
</flux:text>
</div>
<div class="flex gap-3 justify-end">
<flux:button variant="outline" wire:click="closeDeleteModal">
{{ __('Cancel') }}
</flux:button>
<flux:button variant="danger" wire:click="deletePasskey">
{{ __('Remove passkey') }}
</flux:button>
</div>
</div>
</flux:modal>
</section>
@@ -1,11 +1,8 @@
<div
class="py-6 space-y-6 border shadow-sm rounded-xl border-zinc-200 dark:border-white/10"
wire:cloak
x-data="{ showRecoveryCodes: false }"
>
<div class="py-6 space-y-6 border shadow-sm rounded-xl border-zinc-200 dark:border-white/10" wire:cloak
x-data="{ showRecoveryCodes: false }">
<div class="px-6 space-y-2">
<div class="flex items-center gap-2">
<flux:icon.lock-closed variant="outline" class="size-4"/>
<flux:icon.lock-closed variant="outline" class="size-4" />
<flux:heading size="lg" level="3">{{ __('2FA recovery codes') }}</flux:heading>
</div>
<flux:text variant="subtle">
@@ -15,66 +12,36 @@
<div class="px-6">
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<flux:button
x-show="!showRecoveryCodes"
icon="eye"
icon:variant="outline"
variant="primary"
@click="showRecoveryCodes = true;"
aria-expanded="false"
aria-controls="recovery-codes-section"
>
<flux:button x-show="!showRecoveryCodes" icon="eye" icon:variant="outline" variant="primary"
@click="showRecoveryCodes = true;" aria-expanded="false" aria-controls="recovery-codes-section">
{{ __('View recovery codes') }}
</flux:button>
<flux:button
x-show="showRecoveryCodes"
icon="eye-slash"
icon:variant="outline"
variant="primary"
@click="showRecoveryCodes = false"
aria-expanded="true"
aria-controls="recovery-codes-section"
>
<flux:button x-show="showRecoveryCodes" icon="eye-slash" icon:variant="outline" variant="primary"
@click="showRecoveryCodes = false" aria-expanded="true" aria-controls="recovery-codes-section">
{{ __('Hide recovery codes') }}
</flux:button>
@if (filled($recoveryCodes))
<flux:button
x-show="showRecoveryCodes"
icon="arrow-path"
variant="filled"
wire:click="regenerateRecoveryCodes"
>
<flux:button x-show="showRecoveryCodes" icon="arrow-path" variant="filled"
wire:click="regenerateRecoveryCodes">
{{ __('Regenerate codes') }}
</flux:button>
@endif
</div>
<div
x-show="showRecoveryCodes"
x-transition
id="recovery-codes-section"
class="relative overflow-hidden"
x-bind:aria-hidden="!showRecoveryCodes"
>
<div x-show="showRecoveryCodes" x-transition id="recovery-codes-section" class="relative overflow-hidden"
x-bind:aria-hidden="!showRecoveryCodes">
<div class="mt-3 space-y-3">
@error('recoveryCodes')
<flux:callout variant="danger" icon="x-circle" heading="{{$message}}"/>
<flux:callout variant="danger" icon="x-circle" heading="{{ $message }}" />
@enderror
@if (filled($recoveryCodes))
<div
class="grid gap-1 p-4 font-mono text-sm rounded-lg bg-zinc-100 dark:bg-white/5"
role="list"
aria-label="{{ __('Recovery codes') }}"
>
@foreach($recoveryCodes as $code)
<div
role="listitem"
class="select-text"
wire:loading.class="opacity-50 animate-pulse"
>
<div class="grid gap-1 p-4 font-mono text-sm rounded-lg bg-zinc-100 dark:bg-white/5" role="list"
aria-label="{{ __('Recovery codes') }}">
@foreach ($recoveryCodes as $code)
<div role="listitem" class="select-text" wire:loading.class="opacity-50 animate-pulse">
{{ $code }}
</div>
@endforeach
+31 -31
View File
@@ -1,41 +1,41 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>
{{ filled($title ?? null) ? $title.' - '.config('app.name', 'Laravel') : config('app.name', 'Laravel') }}
</title>
<title>
{{ filled($title ?? null) ? $title . ' - ' . config('app.name', 'Laravel') : config('app.name', 'Laravel') }}
</title>
<link rel="icon" href="{{ asset('favicons/favicon.ico') }}" sizes="any">
<link rel="icon" href="{{ asset('favicons/favicon.svg') }}" type="image/svg+xml">
<link rel="icon" href="{{ asset('favicons/favicon.ico') }}" sizes="any">
<link rel="icon" href="{{ asset('favicons/favicon.svg') }}" type="image/svg+xml">
<link rel="icon" type="image/png" sizes="16x16" href="{{ asset('favicons/favicon-16x16.png') }}">
<link rel="icon" type="image/png" sizes="32x32" href="{{ asset('favicons/favicon-32x32.png') }}">
<link rel="icon" type="image/png" sizes="48x48" href="{{ asset('favicons/favicon-48x48.png') }}">
<link rel="icon" type="image/png" sizes="64x64" href="{{ asset('favicons/favicon-64x64.png') }}">
<link rel="icon" type="image/png" sizes="96x96" href="{{ asset('favicons/favicon-96x96.png') }}">
<link rel="icon" type="image/png" sizes="128x128" href="{{ asset('favicons/favicon-128x128.png') }}">
<link rel="icon" type="image/png" sizes="192x192" href="{{ asset('favicons/favicon-192x192.png') }}">
<link rel="icon" type="image/png" sizes="256x256" href="{{ asset('favicons/favicon-256x256.png') }}">
<link rel="icon" type="image/png" sizes="384x384" href="{{ asset('favicons/favicon-384x384.png') }}">
<link rel="icon" type="image/png" sizes="512x512" href="{{ asset('favicons/favicon-512x512.png') }}">
<link rel="icon" type="image/png" sizes="16x16" href="{{ asset('favicons/favicon-16x16.png') }}">
<link rel="icon" type="image/png" sizes="32x32" href="{{ asset('favicons/favicon-32x32.png') }}">
<link rel="icon" type="image/png" sizes="48x48" href="{{ asset('favicons/favicon-48x48.png') }}">
<link rel="icon" type="image/png" sizes="64x64" href="{{ asset('favicons/favicon-64x64.png') }}">
<link rel="icon" type="image/png" sizes="96x96" href="{{ asset('favicons/favicon-96x96.png') }}">
<link rel="icon" type="image/png" sizes="128x128" href="{{ asset('favicons/favicon-128x128.png') }}">
<link rel="icon" type="image/png" sizes="192x192" href="{{ asset('favicons/favicon-192x192.png') }}">
<link rel="icon" type="image/png" sizes="256x256" href="{{ asset('favicons/favicon-256x256.png') }}">
<link rel="icon" type="image/png" sizes="384x384" href="{{ asset('favicons/favicon-384x384.png') }}">
<link rel="icon" type="image/png" sizes="512x512" href="{{ asset('favicons/favicon-512x512.png') }}">
<link rel="apple-touch-icon" sizes="180x180" href="{{ asset('favicons/apple-touch-icon.png') }}">
<link rel="manifest" href="{{ asset('favicons/site.webmanifest') }}">
<link rel="apple-touch-icon" sizes="180x180" href="{{ asset('favicons/apple-touch-icon.png') }}">
<link rel="manifest" href="{{ asset('favicons/site.webmanifest') }}">
<meta name="application-name" content="{{ config('app.name') }}">
<meta name="apple-mobile-web-app-title" content="{{ config('app.name') }}">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="format-detection" content="telephone=no">
<meta name="msapplication-config" content="{{ asset('favicons/browserconfig.xml') }}">
<meta name="msapplication-TileImage" content="{{ asset('favicons/mstile-150x150.png') }}">
<meta name="theme-color" content="#ffffff">
<meta name="application-name" content="{{ config('app.name') }}">
<meta name="apple-mobile-web-app-title" content="{{ config('app.name') }}">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="format-detection" content="telephone=no">
<meta name="msapplication-config" content="{{ asset('favicons/browserconfig.xml') }}">
<meta name="msapplication-TileImage" content="{{ asset('favicons/mstile-150x150.png') }}">
<meta name="theme-color" content="#ffffff">
@fonts
@fonts
@vite(['resources/css/app.css', 'resources/js/app.js'])
@fluxAppearance
@vite(['resources/css/app.css', 'resources/js/app.js'])
@fluxAppearance
</head>
@@ -5,11 +5,11 @@
$helpdeskSettingsRoute = Route::has('helpdesk.settings')
? 'helpdesk.settings'
: (Route::has('helpdesk.settings.index') ? 'helpdesk.settings.index' : null);
: (Route::has('helpdesk.settings.index')
? 'helpdesk.settings.index'
: null);
$helpdeskGitRoute = Route::has('helpdesk.git.index')
? 'helpdesk.git.index'
: null;
$helpdeskGitRoute = Route::has('helpdesk.git.index') ? 'helpdesk.git.index' : null;
$helpdeskWorkflowRoute = Route::has('helpdesk.workflow-templates.index')
? 'helpdesk.workflow-templates.index'
@@ -17,27 +17,29 @@
$documentationDashboardRoute = Route::has('documentation.index')
? 'documentation.index'
: (Route::has('documentation.documents.index') ? 'documentation.documents.index' : null);
: (Route::has('documentation.documents.index')
? 'documentation.documents.index'
: null);
$documentationCreateRoute = Route::has('documentation.documents.create')
? 'documentation.documents.create'
: null;
$documentationCreateRoute = Route::has('documentation.documents.create') ? 'documentation.documents.create' : null;
$documentationCategoriesRoute = Route::has('documentation.categories.index')
? 'documentation.categories.index'
: null;
@endphp
@if($helpdeskEnabled || $documentationEnabled)
@if(Route::has('helpdesk.index'))
<a href="{{ route('helpdesk.index') }}" wire:navigate class="wms-sidebar-link @if(request()->routeIs('helpdesk.*')) is-active @endif" title="{{ __('Support') }}">
@if ($helpdeskEnabled || $documentationEnabled)
@if (Route::has('helpdesk.index'))
<a href="{{ route('helpdesk.index') }}" wire:navigate
class="wms-sidebar-link @if (request()->routeIs('helpdesk.*')) is-active @endif" title="{{ __('Support') }}">
<i class="fa-solid fa-headset wms-sidebar-icon" aria-hidden="true"></i>
<span data-wms-sidebar-label>{{ __('Support') }}</span>
</a>
@endif
@if($documentationDashboardRoute)
<a href="{{ route($documentationDashboardRoute) }}" wire:navigate class="wms-sidebar-link @if(request()->routeIs('documentation.index') || request()->routeIs('documentation.documents.*')) is-active @endif" title="{{ __('Documentation') }}">
@if ($documentationDashboardRoute)
<a href="{{ route($documentationDashboardRoute) }}" wire:navigate
class="wms-sidebar-link @if (request()->routeIs('documentation.index') || request()->routeIs('documentation.documents.*')) is-active @endif" title="{{ __('Documentation') }}">
<i class="fa-solid fa-book-open wms-sidebar-icon" aria-hidden="true"></i>
<span data-wms-sidebar-label>{{ __('Documentation') }}</span>
</a>
@@ -1,6 +1,6 @@
<div class="d-flex align-items-center" x-data>
<form class="mr-2"
x-on:submit.prevent="
x-on:submit.prevent="
$refs.exportBtn.disabled = true;
var oTable = LaravelDataTables['{{ $tableId }}'];
var baseUrl = oTable.ajax.url() === '' ? window.location.toString() : oTable.ajax.url();
@@ -8,10 +8,10 @@
var url = new URL(baseUrl);
var searchParams = new URLSearchParams(url.search);
searchParams.set('action', 'exportQueue');
searchParams.set('exportType', '{{$fileType}}');
searchParams.set('sheetName', '{{$sheetName}}');
searchParams.set('buttonName', '{{$buttonName}}');
searchParams.set('emailTo', '{{urlencode($emailTo)}}');
searchParams.set('exportType', '{{ $fileType }}');
searchParams.set('sheetName', '{{ $sheetName }}');
searchParams.set('buttonName', '{{ $buttonName }}');
searchParams.set('emailTo', '{{ urlencode($emailTo) }}');
var tableParams = $.param(oTable.ajax.params());
if (tableParams) {
@@ -30,33 +30,30 @@
$wire.exporting = false;
$wire.exportFailed = true;
});
"
>
<button type="submit"
x-ref="exportBtn"
:disabled="$wire.exporting"
class="{{ $class }}"
>{{$buttonName}}
">
<button type="submit" x-ref="exportBtn" :disabled="$wire.exporting"
class="{{ $class }}">{{ $buttonName }}
</button>
</form>
@if($exporting && $emailTo)
@if ($exporting && $emailTo)
<div class="d-inline">Export will be emailed to {{ $emailTo }}.</div>
@endif
@if($exporting && !$exportFinished)
@if ($exporting && !$exportFinished)
<div class="d-inline" wire:poll="updateExportProgress">Exporting...please wait.</div>
@endif
@if($exportFinished && !$exportFailed && !$autoDownload)
<span>Done. Download file <a href="#" class="text-primary" wire:click.prevent="downloadExport">here</a></span>
@if ($exportFinished && !$exportFailed && !$autoDownload)
<span>Done. Download file <a href="#" class="text-primary"
wire:click.prevent="downloadExport">here</a></span>
@endif
@if($exportFinished && !$exportFailed && $autoDownload && $downloaded)
@if ($exportFinished && !$exportFailed && $autoDownload && $downloaded)
<span>Done. File has been downloaded.</span>
@endif
@if($exportFailed)
@if ($exportFailed)
<span>Export failed, please try again later.</span>
@endif
</div>
+13 -10
View File
@@ -1,15 +1,18 @@
document.addEventListener("DOMContentLoaded", function(){
window.{{ config('datatables-html.namespace', 'LaravelDataTables') }} = window.{{ config('datatables-html.namespace', 'LaravelDataTables') }} || {};
$.ajaxSetup({headers: {'X-CSRF-TOKEN': '{{csrf_token()}}'}});
@foreach($editors as $editor)
var {{$editor->instance}} = window.{{ config('datatables-html.namespace', 'LaravelDataTables') }}["%1$s-{{$editor->instance}}"] = new $.fn.dataTable.Editor({!! $editor->toJson() !!});
{!! $editor->scripts !!}
@foreach ((array) $editor->events as $event)
{{$editor->instance}}.on('{!! $event['event'] !!}', {!! $event['script'] !!});
@endforeach
window.{{ config('datatables-html.namespace', 'LaravelDataTables') }} =
window.{{ config('datatables-html.namespace', 'LaravelDataTables') }} || {};
$.ajaxSetup({headers: {'X-CSRF-TOKEN': '{{ csrf_token() }}'}});
@foreach ($editors as $editor)
var {{ $editor->instance }} =
window.{{ config('datatables-html.namespace', 'LaravelDataTables') }}["%1$s-{{ $editor->instance }}"] = new
$.fn.dataTable.Editor({!! $editor->toJson() !!});
{!! $editor->scripts !!}
@foreach ((array) $editor->events as $event)
{{ $editor->instance }}.on('{!! $event['event'] !!}', {!! $event['script'] !!});
@endforeach
window.{{ config('datatables-html.namespace', 'LaravelDataTables') }}["%1$s"] = $("#%1$s").DataTable(%2$s);
@endforeach
window.{{ config('datatables-html.namespace', 'LaravelDataTables') }}["%1$s"] = $("#%1$s").DataTable(%2$s);
});
@foreach ($scripts as $script)
@include($script)
@include($script)
@endforeach
+12 -8
View File
@@ -1,14 +1,18 @@
window.dtx = window.dtx || {};
window.dtx["%1$s"] = function(opts) {
window.{{ config('datatables-html.namespace', 'LaravelDataTables') }} = window.{{ config('datatables-html.namespace', 'LaravelDataTables') }} || {};
@if(isset($editors))
@foreach($editors as $editor)
var {{$editor->instance}} = window.{{ config('datatables-html.namespace', 'LaravelDataTables') }}["%1$s-{{$editor->instance}}"] = new $.fn.dataTable.Editor({!! $editor->toJson() !!});
{!! $editor->scripts !!}
window.{{ config('datatables-html.namespace', 'LaravelDataTables') }} =
window.{{ config('datatables-html.namespace', 'LaravelDataTables') }} || {};
@if (isset($editors))
@foreach ($editors as $editor)
var {{ $editor->instance }} =
window.{{ config('datatables-html.namespace', 'LaravelDataTables') }}["%1$s-{{ $editor->instance }}"] = new
$.fn.dataTable.Editor({!! $editor->toJson() !!});
{!! $editor->scripts !!}
@foreach ((array) $editor->events as $event)
{{$editor->instance}}.on('{!! $event['event'] !!}', {!! $event['script'] !!});
{{ $editor->instance }}.on('{!! $event['event'] !!}', {!! $event['script'] !!});
@endforeach
@endforeach
@endif
return window.{{ config('datatables-html.namespace', 'LaravelDataTables') }}["%1$s"] = $("#%1$s").DataTable($.extend(%2$s, opts));
@endif
return window.{{ config('datatables-html.namespace', 'LaravelDataTables') }}["%1$s"] =
$("#%1$s").DataTable($.extend(%2$s, opts));
}
@@ -1,14 +1,15 @@
$(function(){
@foreach($editors as $editor)
{{ config('datatables-html.namespace', 'LaravelDataTables') }}["%1$s-{{$editor->instance}}"].on('preSubmit', function(e, data, action) {
if (action !== 'remove') return;
@foreach ($editors as $editor)
{{ config('datatables-html.namespace', 'LaravelDataTables') }}["%1$s-{{ $editor->instance }}"].on('preSubmit',
function(e, data, action) {
if (action !== 'remove') return;
for (let row_id of Object.keys(data.data))
{
data.data[row_id] = {
DT_RowId: data.data[row_id].DT_RowId
};
}
});
@endforeach
for (let row_id of Object.keys(data.data))
{
data.data[row_id] = {
DT_RowId: data.data[row_id].DT_RowId
};
}
});
@endforeach
});
+5 -3
View File
@@ -1,6 +1,8 @@
window.{{ config('datatables-html.namespace', 'LaravelDataTables') }} = window.{{ config('datatables-html.namespace', 'LaravelDataTables') }} || {};
window.{{ config('datatables-html.namespace', 'LaravelDataTables') }} =
window.{{ config('datatables-html.namespace', 'LaravelDataTables') }} || {};
window.{{ config('datatables-html.namespace', 'LaravelDataTables') }}.options = %2$s
window.{{ config('datatables-html.namespace', 'LaravelDataTables') }}.editors = [];
@foreach($editors as $editor)
window.{{ config('datatables-html.namespace', 'LaravelDataTables') }}.editors["{{$editor->instance}}"] = {!! $editor->toJson() !!}
@foreach ($editors as $editor)
window.{{ config('datatables-html.namespace', 'LaravelDataTables') }}.editors["{{ $editor->instance }}"] =
{!! $editor->toJson() !!}
@endforeach
+38 -32
View File
@@ -1,38 +1,44 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Print Table</title>
<meta charset="UTF-8">
<meta name=description content="">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap CSS -->
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
<style>
body {margin: 20px}
</style>
</head>
<body>
<div data-dusk="page-ready" style="position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);" aria-hidden="true"></div>
<table class="table table-bordered table-condensed table-striped">
@foreach($data as $row)
@if ($loop->first)
<tr>
@foreach($row as $key => $value)
<th>{!! $key !!}</th>
@endforeach
</tr>
@endif
<head>
<title>Print Table</title>
<meta charset="UTF-8">
<meta name=description content="">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap CSS -->
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
<style>
body {
margin: 20px
}
</style>
</head>
<body>
<div data-dusk="page-ready" style="position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);"
aria-hidden="true"></div>
<table class="table table-bordered table-condensed table-striped">
@foreach ($data as $row)
@if ($loop->first)
<tr>
@foreach($row as $key => $value)
@if(is_string($value) || is_numeric($value))
<td>{!! $value !!}</td>
@else
<td></td>
@endif
@foreach ($row as $key => $value)
<th>{!! $key !!}</th>
@endforeach
</tr>
@endforeach
</table>
</body>
@endif
<tr>
@foreach ($row as $key => $value)
@if (is_string($value) || is_numeric($value))
<td>{!! $value !!}</td>
@else
<td></td>
@endif
@endforeach
</tr>
@endforeach
</table>
</body>
</html>
+20 -20
View File
@@ -1,23 +1,23 @@
$(function(){
$('#%1$s').on('xhr.dt', function (e, settings, json, xhr) {
if (json == null || !('disableOrdering' in json)) return;
$('#%1$s').on('xhr.dt', function (e, settings, json, xhr) {
if (json == null || !('disableOrdering' in json)) return;
let table = {{ config('datatables-html.namespace', 'LaravelDataTables') }}[$(this).attr('id')];
if (json.disableOrdering) {
table.settings()[0].aoColumns.forEach(function(column) {
column.bSortable = false;
$(column.nTh).removeClass('sorting_asc sorting_desc sorting').addClass('sorting_disabled');
});
} else {
let changed = false;
table.settings()[0].aoColumns.forEach(function(column) {
if (column.bSortable) return;
column.bSortable = true;
changed = true;
});
if (changed) {
table.draw();
}
}
});
let table = {{ config('datatables-html.namespace', 'LaravelDataTables') }}[$(this).attr('id')];
if (json.disableOrdering) {
table.settings()[0].aoColumns.forEach(function(column) {
column.bSortable = false;
$(column.nTh).removeClass('sorting_asc sorting_desc sorting').addClass('sorting_disabled');
});
} else {
let changed = false;
table.settings()[0].aoColumns.forEach(function(column) {
if (column.bSortable) return;
column.bSortable = true;
changed = true;
});
if (changed) {
table.draw();
}
}
});
});
+1 -1
View File
@@ -1,4 +1,4 @@
document.addEventListener("DOMContentLoaded",function(){window.{{ config('datatables-html.namespace', 'LaravelDataTables') }}=window.{{ config('datatables-html.namespace', 'LaravelDataTables') }}||{};window.{{ config('datatables-html.namespace', 'LaravelDataTables') }}["%1$s"]=$("#%1$s").DataTable(%2$s);});
@foreach ($scripts as $script)
@include($script)
@include($script)
@endforeach
@@ -21,34 +21,18 @@
$actionIsModalFooterSticky = $action->isModalFooterSticky();
$actionIsModalHeaderSticky = $action->isModalHeaderSticky();
$actionModalWidth = $action->getModalWidth();
$actionLivewireCallMountedActionName = $action->hasFormWrapper() ? $action->getLivewireCallMountedActionName() : null;
$actionLivewireCallMountedActionName = $action->hasFormWrapper()
? $action->getLivewireCallMountedActionName()
: null;
$actionModalWireKey = "{$this->getId()}.actions.{$action->getName()}.modal";
@endphp
<x-filament::modal
:alignment="$actionModalAlignment"
:autofocus="$actionIsModalAutofocused"
:close-button="$actionHasModalCloseButton"
:close-by-clicking-away="$actionIsModalClosedByClickingAway"
:close-by-escaping="$actionIsModalClosedByEscaping"
:description="$actionModalDescription"
:extra-modal-window-attribute-bag="$actionExtraModalWindowAttributeBag"
:extra-modal-overlay-attribute-bag="$actionExtraModalOverlayAttributeBag"
:footer-actions="$actionModalFooterActions"
:footer-actions-alignment="$actionModalFooterActionsAlignment"
:heading="$actionModalHeading"
:icon="$actionModalIcon"
:icon-color="$actionModalIconColor"
:id="$actionModalId"
:slide-over="$actionIsModalSlideOver"
:slide-over-position="$actionModalSlideOverPosition"
:sticky-footer="$actionIsModalFooterSticky"
:sticky-header="$actionIsModalHeaderSticky"
:width="$actionModalWidth"
:wire:key="$actionModalWireKey"
<x-filament::modal :alignment="$actionModalAlignment" :autofocus="$actionIsModalAutofocused" :close-button="$actionHasModalCloseButton" :close-by-clicking-away="$actionIsModalClosedByClickingAway" :close-by-escaping="$actionIsModalClosedByEscaping"
:description="$actionModalDescription" :extra-modal-window-attribute-bag="$actionExtraModalWindowAttributeBag" :extra-modal-overlay-attribute-bag="$actionExtraModalOverlayAttributeBag" :footer-actions="$actionModalFooterActions" :footer-actions-alignment="$actionModalFooterActionsAlignment" :heading="$actionModalHeading"
:icon="$actionModalIcon" :icon-color="$actionModalIconColor" :id="$actionModalId" :slide-over="$actionIsModalSlideOver" :slide-over-position="$actionModalSlideOverPosition" :sticky-footer="$actionIsModalFooterSticky"
:sticky-header="$actionIsModalHeaderSticky" :width="$actionModalWidth" :wire:key="$actionModalWireKey"
:wire:submit.prevent="$actionLivewireCallMountedActionName"
:x-on:modal-closed="'if ($event.detail.id === ' . \Illuminate\Support\Js::from($actionModalId) . ') $wire.unmountAction(false)'"
>
:x-on:modal-closed="'if ($event.detail.id === ' . \Illuminate\Support\Js::from($actionModalId) . ') $wire.unmountAction(false)'">
{{ FilamentView::renderHook(ActionsRenderHook::MODAL_CUSTOM_CONTENT_BEFORE, scopes: static::class, data: ['action' => $action]) }}
{{ $action->getModalContent() }}
@@ -37,9 +37,7 @@
->triggerView($triggerView)
->view($view);
$badge === true
? $group->badge()
: $group->badge($badge);
$badge === true ? $group->badge() : $group->badge($badge);
if ($button) {
$group
@@ -1,13 +1,9 @@
@if ($this instanceof \Filament\Actions\Contracts\HasActions && (! $this->hasActionsModalRendered))
<div
wire:partial="action-modals"
x-data="filamentActionModals({
livewireId: @js($this->getId()),
})"
style="height: 0"
>
@if ($this instanceof \Filament\Actions\Contracts\HasActions && !$this->hasActionsModalRendered)
<div wire:partial="action-modals" x-data="filamentActionModals({
livewireId: @js($this->getId()),
})" style="height: 0">
@foreach ($this->getMountedActions() as $action)
@if ((! $loop->last) || $this->mountedActionShouldOpenModal())
@if (!$loop->last || $this->mountedActionShouldOpenModal())
{{ $action->toModalHtmlable() }}
@endif
@endforeach
@@ -44,34 +44,17 @@
<x-dynamic-component :component="$fieldWrapperView" :field="$field">
<div
{{
$attributes
->merge($getExtraAttributes(), escape: false)
->class([
'fi-fo-builder',
'fi-collapsible' => $isCollapsible,
])
}}
>
{{ $attributes->merge($getExtraAttributes(), escape: false)->class(['fi-fo-builder', 'fi-collapsible' => $isCollapsible]) }}>
@if ($collapseAllActionIsVisible || $expandAllActionIsVisible)
<div
@class([
'fi-fo-builder-actions',
'fi-hidden' => count($items) < 2,
])
>
<div @class(['fi-fo-builder-actions', 'fi-hidden' => count($items) < 2])>
@if ($collapseAllActionIsVisible)
<span
x-on:click="$dispatch('builder-collapse', '{{ $statePath }}')"
>
<span x-on:click="$dispatch('builder-collapse', '{{ $statePath }}')">
{{ $collapseAllAction }}
</span>
@endif
@if ($expandAllActionIsVisible)
<span
x-on:click="$dispatch('builder-expand', '{{ $statePath }}')"
>
<span x-on:click="$dispatch('builder-expand', '{{ $statePath }}')">
{{ $expandAllAction }}
</span>
@endif
@@ -79,9 +62,7 @@
@endif
@if (count($items))
<ul
x-sortable
data-sortable-animation-duration="{{ $getReorderAnimationDuration() }}"
<ul x-sortable data-sortable-animation-duration="{{ $getReorderAnimationDuration() }}"
x-on:end.stop="
$wire.mountAction(
'reorder',
@@ -89,8 +70,7 @@
{ schemaComponent: '{{ $key }}' },
)
"
class="fi-fo-builder-items"
>
class="fi-fo-builder-items">
@php
$hasBlockLabels = $hasBlockLabels();
$hasBlockIcons = $hasBlockIcons();
@@ -102,7 +82,7 @@
@php
$visibleExtraItemActions = array_filter(
$extraItemActions,
fn (Action $action): bool => $action(['item' => $itemKey])->isVisible(),
fn(Action $action): bool => $action(['item' => $itemKey])->isVisible(),
);
$cloneAction = $cloneAction(['item' => $itemKey]);
$cloneActionIsVisible = $isCloneable && $cloneAction->isVisible();
@@ -115,39 +95,33 @@
$moveUpAction = $moveUpAction(['item' => $itemKey])->disabled($loop->first);
$moveUpActionIsVisible = $isReorderableWithButtons && $moveUpAction->isVisible();
$reorderActionIsVisible = $isReorderableWithDragAndDrop && $reorderAction->isVisible();
$hasItemHeader = $hasBlockHeaders && ($reorderActionIsVisible || $moveUpActionIsVisible || $moveDownActionIsVisible || $hasBlockIcons || $hasBlockLabels || $editActionIsVisible || $cloneActionIsVisible || $deleteActionIsVisible || $isCollapsible || $visibleExtraItemActions);
$hasItemHeader =
$hasBlockHeaders &&
($reorderActionIsVisible ||
$moveUpActionIsVisible ||
$moveDownActionIsVisible ||
$hasBlockIcons ||
$hasBlockLabels ||
$editActionIsVisible ||
$cloneActionIsVisible ||
$deleteActionIsVisible ||
$isCollapsible ||
$visibleExtraItemActions);
@endphp
<li
wire:ignore.self
wire:key="{{ $item->getLivewireKey() }}.item"
x-data="{
isCollapsed: @if ($persistCollapsed) $persist(@js($isCollapsed($item))).as(`builder-${@js($key)}-${@js($itemKey)}-isCollapsed`) @else @js($isCollapsed($item)) @endif,
}"
<li wire:ignore.self wire:key="{{ $item->getLivewireKey() }}.item" x-data="{
isCollapsed: @if ($persistCollapsed) $persist(@js($isCollapsed($item))).as(`builder-${@js($key)}-${@js($itemKey)}-isCollapsed`) @else @js($isCollapsed($item)) @endif,
}"
x-on:builder-expand.window="$event.detail === '{{ $statePath }}' && (isCollapsed = false)"
x-on:builder-collapse.window="$event.detail === '{{ $statePath }}' && (isCollapsed = true)"
x-on:expand="isCollapsed = false"
x-sortable-item="{{ $itemKey }}"
{{
$item->getParentComponent()->getExtraAttributeBag()
->class([
'fi-fo-builder-item',
'fi-fo-builder-item-has-header' => $hasItemHeader,
])
}}
x-bind:class="{ 'fi-collapsed': isCollapsed }"
>
x-on:expand="isCollapsed = false" x-sortable-item="{{ $itemKey }}"
{{ $item->getParentComponent()->getExtraAttributeBag()->class(['fi-fo-builder-item', 'fi-fo-builder-item-has-header' => $hasItemHeader]) }}
x-bind:class="{ 'fi-collapsed': isCollapsed }">
@if ($hasItemHeader)
<div
@if ($isCollapsible)
x-on:click.stop="isCollapsed = !isCollapsed"
@endif
class="fi-fo-builder-item-header"
>
<div @if ($isCollapsible) x-on:click.stop="isCollapsed = !isCollapsed" @endif
class="fi-fo-builder-item-header">
@if ($reorderActionIsVisible || $moveUpActionIsVisible || $moveDownActionIsVisible)
<ul
class="fi-fo-builder-item-header-start-actions"
>
<ul class="fi-fo-builder-item-header-start-actions">
@if ($reorderActionIsVisible)
<li x-on:click.stop>
{{ $reorderAction->extraAttributes(['x-sortable-handle' => true], merge: true) }}
@@ -171,28 +145,29 @@
@endphp
@if ($hasBlockIcons && filled($blockIcon))
{{ \Filament\Support\generate_icon_html($blockIcon, attributes: (new \Illuminate\View\ComponentAttributeBag)->class(['fi-fo-builder-item-header-icon'])) }}
{{ \Filament\Support\generate_icon_html($blockIcon, attributes: new \Illuminate\View\ComponentAttributeBag()->class(['fi-fo-builder-item-header-icon'])) }}
@endif
@if ($hasBlockLabels)
<{{ $blockLabelHeadingTag }}
@class([
'fi-fo-builder-item-header-label',
'fi-truncated' => $isBlockLabelTruncated,
])
>
<{{ $blockLabelHeadingTag }} @class([
'fi-fo-builder-item-header-label',
'fi-truncated' => $isBlockLabelTruncated,
])>
{{ $item->getParentComponent()->getLabel($item->getRawState(), $itemKey, $loop->index) }}
@if ($hasBlockNumbers)
{{ $loop->iteration }}
@endif
</{{ $blockLabelHeadingTag }}>
</{{ $blockLabelHeadingTag }}>
@endif
@if ($editActionIsVisible || $cloneActionIsVisible || $deleteActionIsVisible || $isCollapsible || $visibleExtraItemActions)
<ul
class="fi-fo-builder-item-header-end-actions"
>
@if (
$editActionIsVisible ||
$cloneActionIsVisible ||
$deleteActionIsVisible ||
$isCollapsible ||
$visibleExtraItemActions)
<ul class="fi-fo-builder-item-header-end-actions">
@foreach ($visibleExtraItemActions as $extraItemAction)
<li x-on:click.stop>
{{ $extraItemAction(['item' => $itemKey]) }}
@@ -218,19 +193,13 @@
@endif
@if ($isCollapsible)
<li
class="fi-fo-builder-item-header-collapsible-actions"
x-on:click.stop="isCollapsed = !isCollapsed"
>
<div
class="fi-fo-builder-item-header-collapse-action"
>
<li class="fi-fo-builder-item-header-collapsible-actions"
x-on:click.stop="isCollapsed = !isCollapsed">
<div class="fi-fo-builder-item-header-collapse-action">
{{ $getAction('collapse') }}
</div>
<div
class="fi-fo-builder-item-header-expand-action"
>
<div class="fi-fo-builder-item-header-expand-action">
{{ $getAction('expand') }}
</div>
</li>
@@ -240,29 +209,23 @@
</div>
@endif
<div
x-show="! isCollapsed"
@class([
'fi-fo-builder-item-content',
'fi-fo-builder-item-content-has-preview' => $hasBlockPreviews && $item->getParentComponent()->hasPreview(),
])
>
<div x-show="! isCollapsed" @class([
'fi-fo-builder-item-content',
'fi-fo-builder-item-content-has-preview' =>
$hasBlockPreviews && $item->getParentComponent()->hasPreview(),
])>
@if ($hasBlockPreviews && $item->getParentComponent()->hasPreview())
<div
@class([
'fi-fo-builder-item-preview',
'fi-interactive' => $hasInteractiveBlockPreviews,
])
>
<div @class([
'fi-fo-builder-item-preview',
'fi-interactive' => $hasInteractiveBlockPreviews,
])>
{{ $item->getParentComponent()->renderPreview($item->getRawState()) }}
</div>
@if ($editActionIsVisible && (! $hasInteractiveBlockPreviews))
<div
class="fi-fo-builder-item-preview-edit-overlay"
role="button"
x-on:click.stop="{{ '$wire.mountAction(\'edit\', { item: \'' . $itemKey . '\' }, { schemaComponent: \'' . $key . '\' })' }}"
></div>
@if ($editActionIsVisible && !$hasInteractiveBlockPreviews)
<div class="fi-fo-builder-item-preview-edit-overlay" role="button"
x-on:click.stop="{{ '$wire.mountAction(\'edit\', { item: \'' . $itemKey . '\' }, { schemaComponent: \'' . $key . '\' })' }}">
</div>
@endif
@else
{{ $item }}
@@ -270,19 +233,13 @@
</div>
</li>
@if (! $loop->last)
@if (!$loop->last)
@if ($isAddable && $addBetweenAction(['afterItem' => $itemKey])->isVisible())
<li class="fi-fo-builder-add-between-items-ctn">
<div class="fi-fo-builder-add-between-items">
<div class="fi-fo-builder-block-picker-ctn">
<x-filament-forms::builder.block-picker
:action="$addBetweenAction"
:after-item="$itemKey"
:columns="$blockPickerColumns"
:blocks="$blockPickerBlocks"
:key="$key"
:width="$blockPickerWidth"
>
<x-filament-forms::builder.block-picker :action="$addBetweenAction" :after-item="$itemKey"
:columns="$blockPickerColumns" :blocks="$blockPickerBlocks" :key="$key" :width="$blockPickerWidth">
<x-slot name="trigger">
{{ $addBetweenAction(['afterItem' => $itemKey]) }}
</x-slot>
@@ -292,17 +249,13 @@
</li>
@elseif (filled($labelBetweenItems))
<li class="fi-fo-builder-label-between-items-ctn">
<div
class="fi-fo-builder-label-between-items-divider-before"
></div>
<div class="fi-fo-builder-label-between-items-divider-before"></div>
<span class="fi-fo-builder-label-between-items">
{{ $labelBetweenItems }}
</span>
<div
class="fi-fo-builder-label-between-items-divider-after"
></div>
<div class="fi-fo-builder-label-between-items-divider-after"></div>
</li>
@endif
@endif
@@ -311,14 +264,8 @@
@endif
@if ($isAddable && $addAction->isVisible())
<x-filament-forms::builder.block-picker
:action="$addAction"
:action-alignment="$addActionAlignment"
:blocks="$blockPickerBlocks"
:columns="$blockPickerColumns"
:key="$key"
:width="$blockPickerWidth"
>
<x-filament-forms::builder.block-picker :action="$addAction" :action-alignment="$addActionAlignment" :blocks="$blockPickerBlocks"
:columns="$blockPickerColumns" :key="$key" :width="$blockPickerWidth">
<x-slot name="trigger">
{{ $addAction }}
</x-slot>
@@ -15,33 +15,22 @@
'width' => null,
])
<x-filament::dropdown
:placement="
match ($actionAlignment) {
Alignment::Start, Alignment::Left => 'bottom-start',
Alignment::End, Alignment::Right => 'bottom-end',
default => null,
}
"
shift
:width="$width"
:attributes="
\Filament\Support\prepare_inherited_attributes(
$attributes->class([
'fi-fo-builder-block-picker',
($actionAlignment instanceof Alignment) ? ('fi-align-' . $actionAlignment->value) : $actionAlignment,
]),
)
"
>
<x-filament::dropdown :placement="match ($actionAlignment) {
Alignment::Start, Alignment::Left => 'bottom-start',
Alignment::End, Alignment::Right => 'bottom-end',
default => null,
}" shift :width="$width" :attributes="\Filament\Support\prepare_inherited_attributes(
$attributes->class([
'fi-fo-builder-block-picker',
$actionAlignment instanceof Alignment ? 'fi-align-' . $actionAlignment->value : $actionAlignment,
]),
)">
<x-slot name="trigger">
{{ $trigger }}
</x-slot>
<x-filament::dropdown.list>
<div
{{ (new ComponentAttributeBag)->grid($columns, GridDirection::Column) }}
>
<div {{ new ComponentAttributeBag()->grid($columns, GridDirection::Column) }}>
@foreach ($blocks as $block)
@php
$blockIcon = $block->getIcon();
@@ -57,11 +46,7 @@
$wireClickAction = "mountAction('{$action->getName()}', {$wireClickActionArguments}, { schemaComponent: '{$key}' })";
@endphp
<x-filament::dropdown.list.item
:icon="$blockIcon"
x-on:click="close"
:wire:click="$wireClickAction"
>
<x-filament::dropdown.list.item :icon="$blockIcon" x-on:click="close" :wire:click="$wireClickAction">
{{ $block->getLabel() }}
</x-filament::dropdown.list.item>
@endforeach
@@ -15,50 +15,30 @@
@endphp
<x-dynamic-component :component="$fieldWrapperView" :field="$field">
<div
x-load
<div x-load
x-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('checkbox-list', 'filament/forms') }}"
x-data="checkboxListFormComponent({
livewireId: @js($this->getId()),
})"
{{ $getExtraAlpineAttributeBag()->class(['fi-fo-checkbox-list']) }}
>
@if (! $isDisabled)
livewireId: @js($this->getId()),
})" {{ $getExtraAlpineAttributeBag()->class(['fi-fo-checkbox-list']) }}>
@if (!$isDisabled)
@if ($isSearchable)
<x-filament::input.wrapper
inline-prefix
:prefix-icon="\Filament\Support\Icons\Heroicon::MagnifyingGlass"
:prefix-icon-alias="\Filament\Forms\View\FormsIconAlias::COMPONENTS_CHECKBOX_LIST_SEARCH_FIELD"
class="fi-fo-checkbox-list-search-input-wrp"
>
<input
placeholder="{{ $getSearchPrompt() }}"
type="search"
<x-filament::input.wrapper inline-prefix :prefix-icon="\Filament\Support\Icons\Heroicon::MagnifyingGlass" :prefix-icon-alias="\Filament\Forms\View\FormsIconAlias::COMPONENTS_CHECKBOX_LIST_SEARCH_FIELD"
class="fi-fo-checkbox-list-search-input-wrp">
<input placeholder="{{ $getSearchPrompt() }}" type="search"
x-model.debounce.{{ $getSearchDebounce() }}="search"
class="fi-input fi-input-has-inline-prefix"
/>
class="fi-input fi-input-has-inline-prefix" />
</x-filament::input.wrapper>
@endif
@if ($isBulkToggleable && count($options))
<div
x-cloak
class="fi-fo-checkbox-list-actions"
wire:key="{{ $livewireKey }}.actions"
>
<span
x-show="! areAllCheckboxesChecked"
x-on:click="toggleAllCheckboxes()"
wire:key="{{ $livewireKey }}.actions.select-all"
>
<div x-cloak class="fi-fo-checkbox-list-actions" wire:key="{{ $livewireKey }}.actions">
<span x-show="! areAllCheckboxesChecked" x-on:click="toggleAllCheckboxes()"
wire:key="{{ $livewireKey }}.actions.select-all">
{{ $getAction('selectAll') }}
</span>
<span
x-show="areAllCheckboxesChecked"
x-on:click="toggleAllCheckboxes()"
wire:key="{{ $livewireKey }}.actions.deselect-all"
>
<span x-show="areAllCheckboxesChecked" x-on:click="toggleAllCheckboxes()"
wire:key="{{ $livewireKey }}.actions.deselect-all">
{{ $getAction('deselectAll') }}
</span>
</div>
@@ -66,22 +46,15 @@
@endif
<div
{{
$getExtraAttributeBag()
->grid($getColumns(), $gridDirection)
->merge([
{{ $getExtraAttributeBag()->grid($getColumns(), $gridDirection)->merge(
[
'x-show' => $isSearchable ? 'visibleCheckboxListOptions.length' : null,
], escape: false)
->class([
'fi-fo-checkbox-list-options',
])
}}
>
],
escape: false,
)->class(['fi-fo-checkbox-list-options']) }}>
@forelse ($options as $value => $label)
<div
wire:key="{{ $livewireKey }}.options.{{ $value }}"
@if ($isSearchable)
x-show="
<div wire:key="{{ $livewireKey }}.options.{{ $value }}"
@if ($isSearchable) x-show="
$el
.querySelector('.fi-fo-checkbox-list-option-label')
?.innerText.toLowerCase()
@@ -90,29 +63,20 @@
.querySelector('.fi-fo-checkbox-list-option-description')
?.innerText.toLowerCase()
.includes(search.toLowerCase())
"
@endif
class="fi-fo-checkbox-list-option-ctn"
>
" @endif
class="fi-fo-checkbox-list-option-ctn">
<label class="fi-fo-checkbox-list-option">
<input
type="checkbox"
{{
$extraInputAttributeBag
->merge([
<input type="checkbox"
{{ $extraInputAttributeBag->merge(
[
'disabled' => $isDisabled || $isOptionDisabled($value, $label),
'value' => e($value),
'wire:loading.attr' => 'disabled',
$wireModelAttribute => $statePath,
'x-on:change' => $isBulkToggleable ? 'checkIfAllCheckboxesAreChecked()' : null,
], escape: false)
->class([
'fi-checkbox-input',
'fi-valid' => ! $errors->has($statePath),
'fi-invalid' => $errors->has($statePath),
])
}}
/>
],
escape: false,
)->class(['fi-checkbox-input', 'fi-valid' => !$errors->has($statePath), 'fi-invalid' => $errors->has($statePath)]) }} />
<div class="fi-fo-checkbox-list-option-text">
<span class="fi-fo-checkbox-list-option-label">
@@ -124,9 +88,7 @@
</span>
@if ($hasDescription($value))
<p
class="fi-fo-checkbox-list-option-description"
>
<p class="fi-fo-checkbox-list-option-description">
{{ $getDescription($value) }}
</p>
@endif
@@ -139,11 +101,8 @@
</div>
@if ($isSearchable)
<div
x-cloak
x-show="search && ! visibleCheckboxListOptions.length"
class="fi-fo-checkbox-list-no-search-results-message"
>
<div x-cloak x-show="search && ! visibleCheckboxListOptions.length"
class="fi-fo-checkbox-list-no-search-results-message">
{{ $getNoSearchResultsMessage() }}
</div>
@endif
@@ -2,28 +2,27 @@
$fieldWrapperView = $getFieldWrapperView();
$statePath = $getStatePath();
$attributes = $attributes
->merge([
'autofocus' => $isAutofocused(),
'disabled' => $isDisabled(),
'id' => $getId(),
'required' => $isRequired() && (! $isConcealed()),
'wire:loading.attr' => 'disabled',
$applyStateBindingModifiers('wire:model') => $statePath,
], escape: false)
->merge(
[
'autofocus' => $isAutofocused(),
'disabled' => $isDisabled(),
'id' => $getId(),
'required' => $isRequired() && !$isConcealed(),
'wire:loading.attr' => 'disabled',
$applyStateBindingModifiers('wire:model') => $statePath,
],
escape: false,
)
->merge($getExtraAttributes(), escape: false)
->merge($getExtraInputAttributes(), escape: false)
->class([
'fi-checkbox-input',
'fi-valid' => ! $errors->has($statePath),
'fi-valid' => !$errors->has($statePath),
'fi-invalid' => $errors->has($statePath),
]);
@endphp
<x-dynamic-component
:component="$fieldWrapperView"
:field="$field"
:inline-label-vertical-alignment="\Filament\Support\Enums\VerticalAlignment::Center"
>
<x-dynamic-component :component="$fieldWrapperView" :field="$field" :inline-label-vertical-alignment="\Filament\Support\Enums\VerticalAlignment::Center">
@if ($isInline())
<x-slot name="labelPrefix">
<input type="checkbox" {{ $attributes }} />
@@ -13,36 +13,21 @@
@endphp
<x-dynamic-component :component="$fieldWrapperView" :field="$field">
<x-filament::input.wrapper
:disabled="$isDisabled"
:valid="! $errors->has($statePath)"
:attributes="
\Filament\Support\prepare_inherited_attributes($extraAttributeBag)
->class(['fi-fo-code-editor'])
"
>
<div
x-load
<x-filament::input.wrapper :disabled="$isDisabled" :valid="!$errors->has($statePath)" :attributes="\Filament\Support\prepare_inherited_attributes($extraAttributeBag)->class(['fi-fo-code-editor'])">
<div x-load
x-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('code-editor', 'filament/forms') }}"
x-data="codeEditorFormComponent({
canWrap: @js($canWrap()),
isDisabled: @js($isDisabled),
isLive: @js($isLive),
isLiveDebounced: @js($isLiveDebounced),
isLiveOnBlur: @js($isLiveOnBlur),
liveDebounce: @js($liveDebounce),
language: @js($language?->value),
state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$statePath}')", isOptimisticallyLive: false) }},
})"
wire:ignore
wire:key="{{ $livewireKey }}.{{
substr(md5(serialize([
$isDisabled,
$language?->value,
])), 0, 64)
}}"
{{ $getExtraAlpineAttributeBag() }}
>
canWrap: @js($canWrap()),
isDisabled: @js($isDisabled),
isLive: @js($isLive),
isLiveDebounced: @js($isLiveDebounced),
isLiveOnBlur: @js($isLiveOnBlur),
liveDebounce: @js($liveDebounce),
language: @js($language?->value),
state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$statePath}')", isOptimisticallyLive: false) }},
})" wire:ignore
wire:key="{{ $livewireKey }}.{{ substr(md5(serialize([$isDisabled, $language?->value])), 0, 64) }}"
{{ $getExtraAlpineAttributeBag() }}>
<div x-ref="editor" x-cloak></div>
</div>
</x-filament::input.wrapper>
@@ -20,94 +20,63 @@
$placeholder = $getPlaceholder();
@endphp
<x-dynamic-component
:component="$fieldWrapperView"
:field="$field"
:inline-label-vertical-alignment="\Filament\Support\Enums\VerticalAlignment::Center"
>
<x-filament::input.wrapper
:disabled="$isDisabled"
:inline-prefix="$isPrefixInline"
:inline-suffix="$isSuffixInline"
:prefix="$prefixLabel"
:prefix-actions="$prefixActions"
:prefix-icon="$prefixIcon"
:prefix-icon-color="$prefixIconColor"
:suffix="$suffixLabel"
:suffix-actions="$suffixActions"
:suffix-icon="$suffixIcon"
:suffix-icon-color="$suffixIconColor"
:valid="! $errors->has($statePath)"
x-on:focus-input.stop="$el.querySelector('input')?.focus()"
:attributes="
\Filament\Support\prepare_inherited_attributes($extraAttributeBag)
->class('fi-fo-color-picker')
"
>
<div
x-load
<x-dynamic-component :component="$fieldWrapperView" :field="$field" :inline-label-vertical-alignment="\Filament\Support\Enums\VerticalAlignment::Center">
<x-filament::input.wrapper :disabled="$isDisabled" :inline-prefix="$isPrefixInline" :inline-suffix="$isSuffixInline" :prefix="$prefixLabel" :prefix-actions="$prefixActions"
:prefix-icon="$prefixIcon" :prefix-icon-color="$prefixIconColor" :suffix="$suffixLabel" :suffix-actions="$suffixActions" :suffix-icon="$suffixIcon" :suffix-icon-color="$suffixIconColor"
:valid="!$errors->has($statePath)" x-on:focus-input.stop="$el.querySelector('input')?.focus()" :attributes="\Filament\Support\prepare_inherited_attributes($extraAttributeBag)->class('fi-fo-color-picker')">
<div x-load
x-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('color-picker', 'filament/forms') }}"
x-data="colorPickerFormComponent({
isAutofocused: @js($isAutofocused()),
isDisabled: @js($isDisabled),
isLive: @js($isLive),
isLiveDebounced: @js($isLiveDebounced),
isLiveOnBlur: @js($isLiveOnBlur),
liveDebounce: @js($liveDebounce),
state: $wire.$entangle('{{ $statePath }}'),
})"
x-on:keydown.esc="isOpen() && $event.stopPropagation()"
isAutofocused: @js($isAutofocused()),
isDisabled: @js($isDisabled),
isLive: @js($isLive),
isLiveDebounced: @js($isLiveDebounced),
isLiveOnBlur: @js($isLiveOnBlur),
liveDebounce: @js($liveDebounce),
state: $wire.$entangle('{{ $statePath }}'),
})" x-on:keydown.esc="isOpen() && $event.stopPropagation()"
x-on:focusout="if (isOpen() && ! $el.contains($event.relatedTarget)) $refs.panel.close()"
{{ $getExtraAlpineAttributeBag()->class(['fi-input-wrp-content']) }}
>
<input
x-on:focus="$refs.panel.open($refs.input)"
x-on:keydown.enter.prevent.stop="togglePanelVisibility()"
{{ $getExtraAlpineAttributeBag()->class(['fi-input-wrp-content']) }}>
<input x-on:focus="$refs.panel.open($refs.input)" x-on:keydown.enter.prevent.stop="togglePanelVisibility()"
x-ref="input"
{{
$getExtraInputAttributeBag()
->merge([
{{ $getExtraInputAttributeBag()->merge(
[
'autocomplete' => 'off',
'disabled' => $isDisabled,
'id' => $getId(),
'placeholder' => filled($placeholder) ? e($placeholder) : null,
'required' => $isRequired() && (! $isConcealed()),
'required' => $isRequired() && !$isConcealed(),
'type' => 'text',
'x-model' . ($isLiveDebounced ? '.debounce.' . $liveDebounce : null) => 'state',
'x-on:blur' => $isLiveOnBlur ? 'isOpen() ? null : commitState()' : null,
], escape: false)
->class([
'fi-input',
'fi-input-has-inline-prefix' => $isPrefixInline && (count($prefixActions) || $prefixIcon || filled($prefixLabel)),
'fi-input-has-inline-suffix' => $isSuffixInline && (count($suffixActions) || $suffixIcon || filled($suffixLabel)),
])
}}
/>
],
escape: false,
)->class([
'fi-input',
'fi-input-has-inline-prefix' =>
$isPrefixInline && (count($prefixActions) || $prefixIcon || filled($prefixLabel)),
'fi-input-has-inline-suffix' =>
$isSuffixInline && (count($suffixActions) || $suffixIcon || filled($suffixLabel)),
]) }} />
<div
class="fi-fo-color-picker-preview my-auto me-3 size-5 shrink-0 rounded-full select-none"
<div class="fi-fo-color-picker-preview my-auto me-3 size-5 shrink-0 rounded-full select-none"
x-on:click="togglePanelVisibility()"
x-bind:class="{
'fi-empty': ! state,
'fi-empty': !state,
}"
x-bind:style="{ 'background-color': state }"
></div>
x-bind:style="{ 'background-color': state }"></div>
<div
wire:ignore.self
wire:key="{{ $getLivewireKey() }}.panel"
x-cloak
x-float.placement.bottom-start.offset.flip.shift="{ offset: 8 }"
x-ref="panel"
class="fi-fo-color-picker-panel"
>
<div wire:ignore.self wire:key="{{ $getLivewireKey() }}.panel" x-cloak
x-float.placement.bottom-start.offset.flip.shift="{ offset: 8 }" x-ref="panel"
class="fi-fo-color-picker-panel">
@php
$tag = match ($getFormat()) {
'hsl' => 'hsl-string',
'rgb' => 'rgb-string',
'rgba' => 'rgba-string',
default => 'hex',
} . '-color-picker';
$tag =
match ($getFormat()) {
'hsl' => 'hsl-string',
'rgb' => 'rgb-string',
'rgba' => 'rgba-string',
default => 'hex',
} . '-color-picker';
@endphp
<{{ $tag }} x-ref="picker" color="{{ $getState() }}" />
@@ -34,33 +34,17 @@
$livewireKey = $getLivewireKey();
@endphp
<x-dynamic-component
:component="$fieldWrapperView"
:field="$field"
:inline-label-vertical-alignment="\Filament\Support\Enums\VerticalAlignment::Center"
>
<x-filament::input.wrapper
:disabled="$isDisabled"
:inline-prefix="$isPrefixInline"
:inline-suffix="$isSuffixInline"
:prefix="$prefixLabel"
:prefix-actions="$prefixActions"
:prefix-icon="$prefixIcon"
:prefix-icon-color="$prefixIconColor"
:suffix="$suffixLabel"
:suffix-actions="$suffixActions"
:suffix-icon="$suffixIcon"
:suffix-icon-color="$suffixIconColor"
:valid="! $errors->has($statePath)"
x-on:focus-input.stop="$el.querySelector('input:not([type=hidden])')?.focus()"
:attributes="\Filament\Support\prepare_inherited_attributes($extraAttributeBag)->class(['fi-fo-date-time-picker'])"
>
<x-dynamic-component :component="$fieldWrapperView" :field="$field" :inline-label-vertical-alignment="\Filament\Support\Enums\VerticalAlignment::Center">
<x-filament::input.wrapper :disabled="$isDisabled" :inline-prefix="$isPrefixInline" :inline-suffix="$isSuffixInline" :prefix="$prefixLabel" :prefix-actions="$prefixActions"
:prefix-icon="$prefixIcon" :prefix-icon-color="$prefixIconColor" :suffix="$suffixLabel" :suffix-actions="$suffixActions" :suffix-icon="$suffixIcon" :suffix-icon-color="$suffixIconColor"
:valid="!$errors->has($statePath)" x-on:focus-input.stop="$el.querySelector('input:not([type=hidden])')?.focus()"
:attributes="\Filament\Support\prepare_inherited_attributes($extraAttributeBag)->class([
'fi-fo-date-time-picker',
])">
@if ($isNative())
<input
{{
$extraInputAttributeBag
->merge($extraAlpineAttributes, escape: false)
->merge([
{{ $extraInputAttributeBag->merge($extraAlpineAttributes, escape: false)->merge(
[
'autofocus' => $isAutofocused,
'disabled' => $isDisabled,
'id' => $id,
@@ -69,62 +53,45 @@
'min' => $hasTime ? $minDate : ($minDate ? \Carbon\Carbon::parse($minDate)->toDateString() : null),
'placeholder' => filled($placeholder) ? e($placeholder) : null,
'readonly' => $isReadOnly,
'required' => $isRequired && (! $isConcealed),
'required' => $isRequired && !$isConcealed,
'step' => $step,
'type' => $type,
$applyStateBindingModifiers('wire:model') => $statePath,
'x-data' => count($extraAlpineAttributes) ? '{}' : null,
], escape: false)
->class([
'fi-input',
'fi-input-has-inline-prefix' => $isPrefixInline && (count($prefixActions) || $prefixIcon || filled($prefixLabel)),
'fi-input-has-inline-suffix' => $isSuffixInline && (count($suffixActions) || $suffixIcon || filled($suffixLabel)),
])
}}
/>
],
escape: false,
)->class([
'fi-input',
'fi-input-has-inline-prefix' =>
$isPrefixInline && (count($prefixActions) || $prefixIcon || filled($prefixLabel)),
'fi-input-has-inline-suffix' =>
$isSuffixInline && (count($suffixActions) || $suffixIcon || filled($suffixLabel)),
]) }} />
@else
<div
x-load
<div x-load
x-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('date-time-picker', 'filament/forms') }}"
x-data="dateTimePickerFormComponent({
defaultFocusedDate: @js($defaultFocusedDate),
displayFormat:
'{{ convert_date_format($getDisplayFormat())->to('day.js') }}',
firstDayOfWeek: {{ $getFirstDayOfWeek() }},
isAutofocused: @js($isAutofocused),
locale: @js($getLocale()),
shouldCloseOnDateSelection: @js($shouldCloseOnDateSelection()),
state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$statePath}')") }},
})"
wire:ignore
wire:key="{{ $livewireKey }}.{{
substr(md5(serialize([
$disabledDates,
$isDisabled,
$isReadOnly,
$maxDate,
$minDate,
$hasDate,
$hasTime,
$hasSeconds,
])), 0, 64)
}}"
x-on:keydown.esc="isOpen() && $event.stopPropagation()"
{{ $getExtraAlpineAttributeBag() }}
>
defaultFocusedDate: @js($defaultFocusedDate),
displayFormat: '{{ convert_date_format($getDisplayFormat())->to('day.js') }}',
firstDayOfWeek: {{ $getFirstDayOfWeek() }},
isAutofocused: @js($isAutofocused),
locale: @js($getLocale()),
shouldCloseOnDateSelection: @js($shouldCloseOnDateSelection()),
state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$statePath}')") }},
})" wire:ignore
wire:key="{{ $livewireKey }}.{{ substr(
md5(serialize([$disabledDates, $isDisabled, $isReadOnly, $maxDate, $minDate, $hasDate, $hasTime, $hasSeconds])),
0,
64,
) }}"
x-on:keydown.esc="isOpen() && $event.stopPropagation()" {{ $getExtraAlpineAttributeBag() }}>
<input x-ref="maxDate" type="hidden" value="{{ $maxDate }}" />
<input x-ref="minDate" type="hidden" value="{{ $minDate }}" />
<input
x-ref="disabledDates"
type="hidden"
value="{{ json_encode($disabledDates) }}"
/>
<input x-ref="disabledDates" type="hidden" value="{{ json_encode($disabledDates) }}" />
<button
x-ref="button"
x-on:click="togglePanelVisibility()"
<button x-ref="button" x-on:click="togglePanelVisibility()"
x-on:keydown.enter.prevent.stop="
if (! $el.disabled) {
isOpen() ? selectDate() : togglePanelVisibility()
@@ -137,93 +104,42 @@
x-on:keydown.backspace.prevent.stop="if (! $el.disabled) clearState()"
x-on:keydown.clear.prevent.stop="if (! $el.disabled) clearState()"
x-on:keydown.delete.prevent.stop="if (! $el.disabled) clearState()"
aria-label="{{ $placeholder }}"
type="button"
tabindex="-1"
@disabled($isDisabled || $isReadOnly)
{{
$getExtraTriggerAttributeBag()->class([
'fi-fo-date-time-picker-trigger',
])
}}
>
<input
@disabled($isDisabled)
readonly
placeholder="{{ $placeholder }}"
wire:key="{{ $livewireKey }}.display-text"
x-model="displayText"
aria-label="{{ $placeholder }}" type="button" tabindex="-1" @disabled($isDisabled || $isReadOnly)
{{ $getExtraTriggerAttributeBag()->class(['fi-fo-date-time-picker-trigger']) }}>
<input @disabled($isDisabled) readonly placeholder="{{ $placeholder }}"
wire:key="{{ $livewireKey }}.display-text" x-model="displayText"
@if ($id = $getId()) id="{{ $id }}" @endif
@class([
'fi-fo-date-time-picker-display-text-input',
])
/>
@class(['fi-fo-date-time-picker-display-text-input']) />
</button>
<div
x-ref="panel"
x-cloak
x-float.placement.bottom-start.offset.flip.shift="{ offset: 8 }"
wire:ignore
wire:key="{{ $livewireKey }}.panel"
@class([
'fi-fo-date-time-picker-panel',
])
>
<div x-ref="panel" x-cloak x-float.placement.bottom-start.offset.flip.shift="{ offset: 8 }" wire:ignore
wire:key="{{ $livewireKey }}.panel" @class(['fi-fo-date-time-picker-panel'])>
@if ($hasDate)
<div class="fi-fo-date-time-picker-panel-header">
<select
x-model="focusedMonth"
class="fi-fo-date-time-picker-month-select"
>
<select x-model="focusedMonth" class="fi-fo-date-time-picker-month-select">
<template x-for="(month, index) in months">
<option
x-bind:value="index"
x-text="month"
></option>
<option x-bind:value="index" x-text="month"></option>
</template>
</select>
<input
type="number"
inputmode="numeric"
x-model.debounce="focusedYear"
class="fi-fo-date-time-picker-year-input"
/>
<input type="number" inputmode="numeric" x-model.debounce="focusedYear"
class="fi-fo-date-time-picker-year-input" />
</div>
<div class="fi-fo-date-time-picker-calendar-header">
<template
x-for="(day, index) in dayLabels"
x-bind:key="index"
>
<div
x-text="day"
class="fi-fo-date-time-picker-calendar-header-day"
></div>
<template x-for="(day, index) in dayLabels" x-bind:key="index">
<div x-text="day" class="fi-fo-date-time-picker-calendar-header-day"></div>
</template>
</div>
<div
role="grid"
class="fi-fo-date-time-picker-calendar"
>
<template
x-for="day in emptyDaysInFocusedMonth"
x-bind:key="day"
>
<div role="grid" class="fi-fo-date-time-picker-calendar">
<template x-for="day in emptyDaysInFocusedMonth" x-bind:key="day">
<div></div>
</template>
<template
x-for="day in daysInFocusedMonth"
x-bind:key="day"
>
<div
x-text="day"
x-on:click="dayIsDisabled(day) || selectDate(day)"
x-on:mouseenter="setFocusedDay(day)"
role="option"
<template x-for="day in daysInFocusedMonth" x-bind:key="day">
<div x-text="day" x-on:click="dayIsDisabled(day) || selectDate(day)"
x-on:mouseenter="setFocusedDay(day)" role="option"
x-bind:aria-selected="focusedDate.date() === day"
x-bind:class="{
'fi-fo-date-time-picker-calendar-day-today': dayIsToday(day),
@@ -231,59 +147,33 @@
'fi-selected': dayIsSelected(day),
'fi-disabled': dayIsDisabled(day),
}"
class="fi-fo-date-time-picker-calendar-day"
></div>
class="fi-fo-date-time-picker-calendar-day"></div>
</template>
</div>
@endif
@if ($hasTime)
<div class="fi-fo-date-time-picker-time-inputs">
<input
max="23"
min="0"
step="{{ $getHoursStep() }}"
type="number"
inputmode="numeric"
x-on:blur="checkTimeInputValidity"
x-on:invalid="timeInputInvalid"
x-model.debounce="hour"
/>
<input max="23" min="0" step="{{ $getHoursStep() }}" type="number"
inputmode="numeric" x-on:blur="checkTimeInputValidity" x-on:invalid="timeInputInvalid"
x-model.debounce="hour" />
<span
class="fi-fo-date-time-picker-time-input-separator"
>
<span class="fi-fo-date-time-picker-time-input-separator">
:
</span>
<input
max="59"
min="0"
step="{{ $getMinutesStep() }}"
type="number"
inputmode="numeric"
x-on:blur="checkTimeInputValidity"
x-on:invalid="timeInputInvalid"
x-model.debounce="minute"
/>
<input max="59" min="0" step="{{ $getMinutesStep() }}" type="number"
inputmode="numeric" x-on:blur="checkTimeInputValidity" x-on:invalid="timeInputInvalid"
x-model.debounce="minute" />
@if ($hasSeconds)
<span
class="fi-fo-date-time-picker-time-input-separator"
>
<span class="fi-fo-date-time-picker-time-input-separator">
:
</span>
<input
max="59"
min="0"
step="{{ $getSecondsStep() }}"
type="number"
inputmode="numeric"
x-on:blur="checkTimeInputValidity"
x-on:invalid="timeInputInvalid"
x-model.debounce="second"
/>
<input max="59" min="0" step="{{ $getSecondsStep() }}" type="number"
inputmode="numeric" x-on:blur="checkTimeInputValidity"
x-on:invalid="timeInputInvalid" x-model.debounce="second" />
@endif
</div>
@endif
@@ -28,7 +28,8 @@
if ($field) {
$hasInlineLabel ??= $field->hasInlineLabel();
$hasNestedRecursiveValidationRules ??= $field instanceof \Filament\Forms\Components\Contracts\HasNestedRecursiveValidationRules;
$hasNestedRecursiveValidationRules ??=
$field instanceof \Filament\Forms\Components\Contracts\HasNestedRecursiveValidationRules;
$id ??= $field->getId();
$isDisabled ??= $field->isDisabled();
$label ??= $field->getLabel();
@@ -50,83 +51,88 @@
$aboveErrorMessageSchema = $field?->getChildSchema($field::ABOVE_ERROR_MESSAGE_SCHEMA_KEY)?->toHtmlString();
$belowErrorMessageSchema = $field?->getChildSchema($field::BELOW_ERROR_MESSAGE_SCHEMA_KEY)?->toHtmlString();
$hasError = $hasErrors && (filled($errorMessage) || filled($errorMessages) || (filled($statePath) && ($errors->has($statePath) || ($hasNestedRecursiveValidationRules && $errors->has("{$statePath}.*")))));
$hasError =
$hasErrors &&
(filled($errorMessage) ||
filled($errorMessages) ||
(filled($statePath) &&
($errors->has($statePath) || ($hasNestedRecursiveValidationRules && $errors->has("{$statePath}.*")))));
if ($hasError && filled($statePath) && blank($errorMessage) && blank($errorMessages)) {
if ($shouldShowAllValidationMessages) {
$errorMessages = $errors->has($statePath) ? $errors->get($statePath) : ($hasNestedRecursiveValidationRules ? $errors->get("{$statePath}.*") : []);
$errorMessages = $errors->has($statePath)
? $errors->get($statePath)
: ($hasNestedRecursiveValidationRules
? $errors->get("{$statePath}.*")
: []);
if (count($errorMessages) === 1) {
$errorMessage = Arr::first($errorMessages);
$errorMessages = [];
}
} else {
$errorMessage = $errors->has($statePath) ? $errors->first($statePath) : ($hasNestedRecursiveValidationRules ? $errors->first("{$statePath}.*") : null);
$errorMessage = $errors->has($statePath)
? $errors->first($statePath)
: ($hasNestedRecursiveValidationRules
? $errors->first("{$statePath}.*")
: null);
}
}
@endphp
<div
data-field-wrapper
{{
$attributes
->merge($field?->getExtraFieldWrapperAttributes() ?? [], escape: false)
->class([
'fi-fo-field',
'fi-fo-field-has-inline-label' => $hasInlineLabel,
])
}}
>
<div data-field-wrapper
{{ $attributes->merge($field?->getExtraFieldWrapperAttributes() ?? [], escape: false)->class(['fi-fo-field', 'fi-fo-field-has-inline-label' => $hasInlineLabel]) }}>
@if (filled($label) && $labelSrOnly)
<{{ $labelTag }}
@if ($labelTag === 'label')
for="{{ $id }}"
@if ($labelTag === 'label') for="{{ $id }}"
@else
id="{{ $id }}-label"
@endif
class="fi-fo-field-label fi-sr-only"
>
id="{{ $id }}-label" @endif
class="fi-fo-field-label fi-sr-only">
{{ $label }}
</{{ $labelTag }}>
</{{ $labelTag }}>
@endif
@if ((filled($label) && (! $labelSrOnly)) || $hasInlineLabel || $aboveLabelSchema || $belowLabelSchema || $beforeLabelSchema || $afterLabelSchema || $labelPrefix || $labelSuffix)
<div
@class([
'fi-fo-field-label-col',
"fi-vertical-align-{$inlineLabelVerticalAlignment->value}" => $hasInlineLabel,
])
>
@if (
(filled($label) && !$labelSrOnly) ||
$hasInlineLabel ||
$aboveLabelSchema ||
$belowLabelSchema ||
$beforeLabelSchema ||
$afterLabelSchema ||
$labelPrefix ||
$labelSuffix)
<div @class([
'fi-fo-field-label-col',
"fi-vertical-align-{$inlineLabelVerticalAlignment->value}" => $hasInlineLabel,
])>
{{ $aboveLabelSchema }}
<div
@class([
'fi-fo-field-label-ctn',
($label instanceof \Illuminate\View\ComponentSlot) ? $label->attributes->get('class') : null,
])
>
<div @class([
'fi-fo-field-label-ctn',
$label instanceof \Illuminate\View\ComponentSlot
? $label->attributes->get('class')
: null,
])>
{{ $beforeLabelSchema }}
@if ((filled($label) && (! $labelSrOnly)) || $labelPrefix || $labelSuffix)
@if ((filled($label) && !$labelSrOnly) || $labelPrefix || $labelSuffix)
<{{ $labelTag }}
@if ($labelTag === 'label')
for="{{ $id }}"
@if ($labelTag === 'label') for="{{ $id }}"
@else
id="{{ $id }}-label"
@endif
class="fi-fo-field-label"
>
id="{{ $id }}-label" @endif
class="fi-fo-field-label">
{{ $labelPrefix }}
@if (filled($label) && (! $labelSrOnly))
@if (filled($label) && !$labelSrOnly)
<span class="fi-fo-field-label-content">
{{ $label }}@if ($required && (! $isDisabled))<sup class="fi-fo-field-label-required-mark">*</sup>
{{ $label }}@if ($required && !$isDisabled)
<sup class="fi-fo-field-label-required-mark">*</sup>
@endif
</span>
@endif
{{ $labelSuffix }}
</{{ $labelTag }}>
</{{ $labelTag }}>
@endif
{{ $afterLabelSchema }}
@@ -136,7 +142,15 @@
</div>
@endif
@if ((! \Filament\Support\is_slot_empty($slot)) || $hasError || $aboveContentSchema || $belowContentSchema || $beforeContentSchema || $afterContentSchema || $aboveErrorMessageSchema || $belowErrorMessageSchema)
@if (
!\Filament\Support\is_slot_empty($slot) ||
$hasError ||
$aboveContentSchema ||
$belowContentSchema ||
$beforeContentSchema ||
$afterContentSchema ||
$aboveErrorMessageSchema ||
$belowErrorMessageSchema)
<div class="fi-fo-field-content-col">
{{ $aboveContentSchema }}
@@ -160,10 +174,7 @@
{{ $aboveErrorMessageSchema }}
@if (filled($errorMessages))
<ul
data-validation-error
class="fi-fo-field-wrp-error-list"
>
<ul data-validation-error class="fi-fo-field-wrp-error-list">
@foreach ($errorMessages as $errorMessage)
<li class="fi-fo-field-wrp-error-message">
@if ($areHtmlErrorMessagesAllowed)
@@ -175,17 +186,11 @@
@endforeach
</ul>
@elseif ($areHtmlErrorMessagesAllowed)
<div
data-validation-error
class="fi-fo-field-wrp-error-message"
>
<div data-validation-error class="fi-fo-field-wrp-error-message">
{!! $errorMessage !!}
</div>
@else
<p
data-validation-error
class="fi-fo-field-wrp-error-message"
>
<p data-validation-error class="fi-fo-field-wrp-error-message">
{{ $errorMessage }}
</p>
@endif
@@ -18,238 +18,193 @@
$alignment = $getAlignment() ?? Alignment::Start;
if (! $alignment instanceof Alignment) {
$alignment = filled($alignment) ? (Alignment::tryFrom($alignment) ?? $alignment) : null;
if (!$alignment instanceof Alignment) {
$alignment = filled($alignment) ? Alignment::tryFrom($alignment) ?? $alignment : null;
}
@endphp
<x-dynamic-component
:component="$fieldWrapperView"
:field="$field"
label-tag="div"
>
<div
x-load
<x-dynamic-component :component="$fieldWrapperView" :field="$field" label-tag="div">
<div x-load
x-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('file-upload', 'filament/forms') }}"
x-data="fileUploadFormComponent({
acceptedFileTypes: @js($getAcceptedFileTypes()),
automaticallyCropImagesAspectRatio: @js($automaticallyCropImagesAspectRatio),
automaticallyOpenImageEditorForAspectRatio: @js($getAutomaticallyOpenImageEditorForAspectRatio()),
automaticallyResizeImagesMode: @js($getAutomaticallyResizeImagesMode()),
automaticallyResizeImagesHeight: @js($automaticallyResizeImagesHeight),
automaticallyResizeImagesWidth: @js($automaticallyResizeImagesWidth),
cancelUploadUsing: (fileKey) => {
$wire.cancelUpload(`{{ $statePath }}.${fileKey}`)
acceptedFileTypes: @js($getAcceptedFileTypes()),
automaticallyCropImagesAspectRatio: @js($automaticallyCropImagesAspectRatio),
automaticallyOpenImageEditorForAspectRatio: @js($getAutomaticallyOpenImageEditorForAspectRatio()),
automaticallyResizeImagesMode: @js($getAutomaticallyResizeImagesMode()),
automaticallyResizeImagesHeight: @js($automaticallyResizeImagesHeight),
automaticallyResizeImagesWidth: @js($automaticallyResizeImagesWidth),
cancelUploadUsing: (fileKey) => {
$wire.cancelUpload(`{{ $statePath }}.${fileKey}`)
},
canEditSvgs: @js($canEditSvgs()),
confirmSvgEditingMessage: @js(__('filament-forms::components.file_upload.editor.svg.messages.confirmation')),
deleteUploadedFileUsing: async (fileKey) => {
return await $wire.callSchemaComponentMethod(
@js($key),
'deleteUploadedFile', { fileKey },
)
},
disabledSvgEditingMessage: @js(__('filament-forms::components.file_upload.editor.svg.messages.disabled')),
getUploadedFilesUsing: async () => {
return await Livewire.fireAction(
$wire.__instance,
'callSchemaComponentMethod',
[@js($key), 'getUploadedFiles'], { async: true },
)
},
hasCircleCropper: @js($hasCircleCropper),
hasImageEditor: @js($hasImageEditor),
imageEditorEmptyFillColor: @js($getImageEditorEmptyFillColor()),
imageEditorMode: @js($getImageEditorMode()),
imageEditorViewportHeight: @js($getImageEditorViewportHeight()),
imageEditorViewportWidth: @js($getImageEditorViewportWidth()),
imagePreviewHeight: @js($getImagePreviewHeight()),
isAvatar: @js($isAvatar),
isDeletable: @js($isDeletable()),
isDisabled: @js($isDisabled),
isDownloadable: @js($isDownloadable()),
isImageEditorExplicitlyEnabled: @js($isImageEditorExplicitlyEnabled),
isMultiple: @js($isMultiple),
isOpenable: @js($isOpenable()),
isPasteable: @js($isPasteable()),
isPreviewable: @js($isPreviewable()),
isReorderable: @js($isReorderable()),
isSvgEditingConfirmed: @js($isSvgEditingConfirmed()),
itemPanelAspectRatio: @js($getItemPanelAspectRatio()),
loadingIndicatorPosition: @js($getLoadingIndicatorPosition()),
locale: @js(app()->getLocale()),
maxFiles: @js($maxFiles = $getMaxFiles()),
maxFilesValidationMessage: @js($maxFiles ? trans_choice('validation.max.array', $maxFiles, ['attribute' => $getValidationAttribute(), 'max' => $maxFiles]) : null),
maxParallelUploads: @js($getMaxParallelUploads()),
maxSize: @js(($size = $getMaxSize()) ? "{$size}KB" : null),
mimeTypeMap: @js($getMimeTypeMap()),
minSize: @js(($size = $getMinSize()) ? "{$size}KB" : null),
panelAspectRatio: @js($getPanelAspectRatio()),
panelLayout: @js($getPanelLayout()),
placeholder: @js($getPlaceholder()),
removeUploadedFileButtonPosition: @js($getRemoveUploadedFileButtonPosition()),
removeUploadedFileUsing: async (fileKey) => {
return await $wire.callSchemaComponentMethod(
@js($key),
'removeUploadedFile', { fileKey },
)
},
reorderUploadedFilesUsing: async (fileKeys) => {
return await $wire.callSchemaComponentMethod(
@js($key),
'reorderUploadedFiles', { fileKeys },
)
},
shouldAppendFiles: @js($shouldAppendFiles()),
shouldAutomaticallyUpscaleImagesWhenResizing: @js($shouldAutomaticallyUpscaleImagesWhenResizing()),
shouldOrientImageFromExif: @js($shouldOrientImagesFromExif()),
shouldTransformImage: @js($automaticallyCropImagesAspectRatio || $automaticallyResizeImagesHeight || $automaticallyResizeImagesWidth),
state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$statePath}')") }},
uploadButtonPosition: @js($getUploadButtonPosition()),
uploadingMessage: @js($getUploadingMessage()),
uploadProgressIndicatorPosition: @js($getUploadProgressIndicatorPosition()),
uploadUsing: (fileKey, file, success, error, progress) => {
$wire.upload(
`{{ $statePath }}.${fileKey}`,
file,
() => {
success(fileKey)
},
canEditSvgs: @js($canEditSvgs()),
confirmSvgEditingMessage: @js(__('filament-forms::components.file_upload.editor.svg.messages.confirmation')),
deleteUploadedFileUsing: async (fileKey) => {
return await $wire.callSchemaComponentMethod(
@js($key),
'deleteUploadedFile',
{ fileKey },
)
error,
(progressEvent) => {
progress(true, progressEvent.detail.progress, 100)
},
disabledSvgEditingMessage: @js(__('filament-forms::components.file_upload.editor.svg.messages.disabled')),
getUploadedFilesUsing: async () => {
return await Livewire.fireAction(
$wire.__instance,
'callSchemaComponentMethod',
[@js($key), 'getUploadedFiles'],
{ async: true },
)
},
hasCircleCropper: @js($hasCircleCropper),
hasImageEditor: @js($hasImageEditor),
imageEditorEmptyFillColor: @js($getImageEditorEmptyFillColor()),
imageEditorMode: @js($getImageEditorMode()),
imageEditorViewportHeight: @js($getImageEditorViewportHeight()),
imageEditorViewportWidth: @js($getImageEditorViewportWidth()),
imagePreviewHeight: @js($getImagePreviewHeight()),
isAvatar: @js($isAvatar),
isDeletable: @js($isDeletable()),
isDisabled: @js($isDisabled),
isDownloadable: @js($isDownloadable()),
isImageEditorExplicitlyEnabled: @js($isImageEditorExplicitlyEnabled),
isMultiple: @js($isMultiple),
isOpenable: @js($isOpenable()),
isPasteable: @js($isPasteable()),
isPreviewable: @js($isPreviewable()),
isReorderable: @js($isReorderable()),
isSvgEditingConfirmed: @js($isSvgEditingConfirmed()),
itemPanelAspectRatio: @js($getItemPanelAspectRatio()),
loadingIndicatorPosition: @js($getLoadingIndicatorPosition()),
locale: @js(app()->getLocale()),
maxFiles: @js($maxFiles = $getMaxFiles()),
maxFilesValidationMessage: @js($maxFiles ? trans_choice('validation.max.array', $maxFiles, ['attribute' => $getValidationAttribute(), 'max' => $maxFiles]) : null),
maxParallelUploads: @js($getMaxParallelUploads()),
maxSize: @js(($size = $getMaxSize()) ? "{$size}KB" : null),
mimeTypeMap: @js($getMimeTypeMap()),
minSize: @js(($size = $getMinSize()) ? "{$size}KB" : null),
panelAspectRatio: @js($getPanelAspectRatio()),
panelLayout: @js($getPanelLayout()),
placeholder: @js($getPlaceholder()),
removeUploadedFileButtonPosition: @js($getRemoveUploadedFileButtonPosition()),
removeUploadedFileUsing: async (fileKey) => {
return await $wire.callSchemaComponentMethod(
@js($key),
'removeUploadedFile',
{ fileKey },
)
},
reorderUploadedFilesUsing: async (fileKeys) => {
return await $wire.callSchemaComponentMethod(
@js($key),
'reorderUploadedFiles',
{ fileKeys },
)
},
shouldAppendFiles: @js($shouldAppendFiles()),
shouldAutomaticallyUpscaleImagesWhenResizing: @js($shouldAutomaticallyUpscaleImagesWhenResizing()),
shouldOrientImageFromExif: @js($shouldOrientImagesFromExif()),
shouldTransformImage: @js($automaticallyCropImagesAspectRatio || $automaticallyResizeImagesHeight || $automaticallyResizeImagesWidth),
state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$statePath}')") }},
uploadButtonPosition: @js($getUploadButtonPosition()),
uploadingMessage: @js($getUploadingMessage()),
uploadProgressIndicatorPosition: @js($getUploadProgressIndicatorPosition()),
uploadUsing: (fileKey, file, success, error, progress) => {
$wire.upload(
`{{ $statePath }}.${fileKey}`,
file,
() => {
success(fileKey)
},
error,
(progressEvent) => {
progress(true, progressEvent.detail.progress, 100)
},
)
},
})"
wire:ignore
wire:key="{{ $livewireKey }}.{{
substr(md5(serialize([
$isDisabled,
])), 0, 64)
}}"
{{
$attributes
->merge([
)
},
})" wire:ignore
wire:key="{{ $livewireKey }}.{{ substr(md5(serialize([$isDisabled])), 0, 64) }}"
{{ $attributes->merge(
[
'aria-labelledby' => "{$id}-label",
'id' => $id,
'role' => 'group',
], escape: false)
->merge($getExtraAttributes(), escape: false)
->merge($getExtraAlpineAttributes(), escape: false)
->class([
'fi-fo-file-upload',
'fi-fo-file-upload-avatar' => $isAvatar,
($alignment instanceof Alignment) ? "fi-align-{$alignment->value}" : $alignment,
])
}}
>
],
escape: false,
)->merge($getExtraAttributes(), escape: false)->merge($getExtraAlpineAttributes(), escape: false)->class([
'fi-fo-file-upload',
'fi-fo-file-upload-avatar' => $isAvatar,
$alignment instanceof Alignment ? "fi-align-{$alignment->value}" : $alignment,
]) }}>
<div class="fi-fo-file-upload-input-ctn">
<input
x-ref="input"
{{
$getExtraInputAttributeBag()
->merge([
'aria-labelledby' => "{$id}-label",
'disabled' => $isDisabled,
'multiple' => $isMultiple,
'type' => 'file',
], escape: false)
}}
/>
<input x-ref="input"
{{ $getExtraInputAttributeBag()->merge(
[
'aria-labelledby' => "{$id}-label",
'disabled' => $isDisabled,
'multiple' => $isMultiple,
'type' => 'file',
],
escape: false,
) }} />
</div>
<div
x-show="error"
x-text="error"
x-cloak
class="fi-fo-file-upload-error-message"
></div>
<div x-show="error" x-text="error" x-cloak class="fi-fo-file-upload-error-message"></div>
@if ($hasImageEditor && (! $isDisabled))
<div
x-show="isEditorOpen"
x-cloak
x-on:click.stop=""
x-trap.noscroll="isEditorOpen"
x-on:keydown.escape.prevent.stop="closeEditor"
@class([
@if ($hasImageEditor && !$isDisabled)
<div x-show="isEditorOpen" x-cloak x-on:click.stop="" x-trap.noscroll="isEditorOpen"
x-on:keydown.escape.prevent.stop="closeEditor" @class([
'fi-fo-file-upload-editor',
'fi-fo-file-upload-editor-circle-cropper' => $hasCircleCropper,
'fi-fo-file-upload-editor-crop-only' => ! $isImageEditorExplicitlyEnabled,
])
>
<div
aria-hidden="true"
class="fi-fo-file-upload-editor-overlay"
></div>
'fi-fo-file-upload-editor-crop-only' => !$isImageEditorExplicitlyEnabled,
])>
<div aria-hidden="true" class="fi-fo-file-upload-editor-overlay"></div>
<div class="fi-fo-file-upload-editor-window">
<div class="fi-fo-file-upload-editor-image-ctn">
<img
x-ref="editor"
class="fi-fo-file-upload-editor-image"
/>
<img x-ref="editor" class="fi-fo-file-upload-editor-image" />
</div>
<div class="fi-fo-file-upload-editor-control-panel">
@if ($isImageEditorExplicitlyEnabled)
<div
class="fi-fo-file-upload-editor-control-panel-main"
>
<div
class="fi-fo-file-upload-editor-control-panel-group"
>
<div class="fi-fo-file-upload-editor-control-panel-main">
<div class="fi-fo-file-upload-editor-control-panel-group">
@foreach ([
[
'label' => __('filament-forms::components.file_upload.editor.fields.x_position.label'),
'ref' => 'xPositionInput',
'unit' => __('filament-forms::components.file_upload.editor.fields.x_position.unit'),
'alpineSaveHandler' => 'editor.setData({...editor.getData(true), x: +$el.value})',
],
[
'label' => __('filament-forms::components.file_upload.editor.fields.y_position.label'),
'ref' => 'yPositionInput',
'unit' => __('filament-forms::components.file_upload.editor.fields.y_position.unit'),
'alpineSaveHandler' => 'editor.setData({...editor.getData(true), y: +$el.value})',
],
[
'label' => __('filament-forms::components.file_upload.editor.fields.width.label'),
'ref' => 'widthInput',
'unit' => __('filament-forms::components.file_upload.editor.fields.width.unit'),
'alpineSaveHandler' => 'editor.setData({...editor.getData(true), width: +$el.value})',
],
[
'label' => __('filament-forms::components.file_upload.editor.fields.height.label'),
'ref' => 'heightInput',
'unit' => __('filament-forms::components.file_upload.editor.fields.height.unit'),
'alpineSaveHandler' => 'editor.setData({...editor.getData(true), height: +$el.value})',
],
[
'label' => __('filament-forms::components.file_upload.editor.fields.rotation.label'),
'ref' => 'rotationInput',
'unit' => __('filament-forms::components.file_upload.editor.fields.rotation.unit'),
'alpineSaveHandler' => 'editor.rotateTo(+$el.value)',
],
] as $input)
[
'label' => __('filament-forms::components.file_upload.editor.fields.x_position.label'),
'ref' => 'xPositionInput',
'unit' => __('filament-forms::components.file_upload.editor.fields.x_position.unit'),
'alpineSaveHandler' => 'editor.setData({...editor.getData(true), x: +$el.value})',
],
[
'label' => __('filament-forms::components.file_upload.editor.fields.y_position.label'),
'ref' => 'yPositionInput',
'unit' => __('filament-forms::components.file_upload.editor.fields.y_position.unit'),
'alpineSaveHandler' => 'editor.setData({...editor.getData(true), y: +$el.value})',
],
[
'label' => __('filament-forms::components.file_upload.editor.fields.width.label'),
'ref' => 'widthInput',
'unit' => __('filament-forms::components.file_upload.editor.fields.width.unit'),
'alpineSaveHandler' => 'editor.setData({...editor.getData(true), width: +$el.value})',
],
[
'label' => __('filament-forms::components.file_upload.editor.fields.height.label'),
'ref' => 'heightInput',
'unit' => __('filament-forms::components.file_upload.editor.fields.height.unit'),
'alpineSaveHandler' => 'editor.setData({...editor.getData(true), height: +$el.value})',
],
[
'label' => __('filament-forms::components.file_upload.editor.fields.rotation.label'),
'ref' => 'rotationInput',
'unit' => __('filament-forms::components.file_upload.editor.fields.rotation.unit'),
'alpineSaveHandler' => 'editor.rotateTo(+$el.value)',
],
] as $input)
<label>
<x-filament::input.wrapper>
<x-slot name="prefix">
{{ $input['label'] }}
</x-slot>
<input
x-on:keyup.enter.prevent.stop="editor && {!! $input['alpineSaveHandler'] !!}"
<input x-on:keyup.enter.prevent.stop="editor && {!! $input['alpineSaveHandler'] !!}"
x-on:blur="editor && {!! $input['alpineSaveHandler'] !!}"
x-ref="{{ $input['ref'] }}"
x-on:keydown.enter.prevent
type="text"
class="fi-input"
/>
x-ref="{{ $input['ref'] }}" x-on:keydown.enter.prevent
type="text" class="fi-input" />
<x-slot name="suffix">
{{ $input['unit'] }}
@@ -259,19 +214,14 @@
@endforeach
</div>
<div
class="fi-fo-file-upload-editor-control-panel-group"
>
<div class="fi-fo-file-upload-editor-control-panel-group">
@foreach ($getImageEditorActions() as $groupedActions)
<div class="fi-btn-group">
@foreach ($groupedActions as $action)
<button
aria-label="{{ $action['label'] }}"
type="button"
<button aria-label="{{ $action['label'] }}" type="button"
x-on:click.prevent.stop="{{ $action['alpineClickHandler'] }}"
x-tooltip="{ content: @js($action['label']), theme: $store.theme }"
class="fi-btn"
>
class="fi-btn">
{{ $action['iconHtml'] }}
</button>
@endforeach
@@ -280,28 +230,22 @@
</div>
@if (count($aspectRatios = $getImageEditorAspectRatioOptionsForJs()))
<div
class="fi-fo-file-upload-editor-control-panel-group"
>
<div
class="fi-fo-file-upload-editor-control-panel-group-title"
>
<div class="fi-fo-file-upload-editor-control-panel-group">
<div class="fi-fo-file-upload-editor-control-panel-group-title">
{{ __('filament-forms::components.file_upload.editor.aspect_ratios.label') }}
</div>
@foreach (collect($aspectRatios)->chunk(5) as $ratiosChunk)
<div class="fi-btn-group">
@foreach ($ratiosChunk as $label => $ratio)
<button
type="button"
<button type="button"
x-on:click.prevent.stop="
currentRatio = @js($label) {!! ';' !!}
editor.setAspectRatio(@js($ratio))
"
x-tooltip="{ content: @js(__('filament-forms::components.file_upload.editor.actions.set_aspect_ratio.label', ['ratio' => $label])), theme: $store.theme }"
x-bind:class="{ 'fi-active': currentRatio === @js($label) }"
class="fi-btn"
>
class="fi-btn">
{{ $label }}
</button>
@endforeach
@@ -312,59 +256,30 @@
</div>
@endif
<div
class="fi-fo-file-upload-editor-control-panel-footer"
>
<div class="fi-fo-file-upload-editor-control-panel-footer">
@if ($isImageEditorExplicitlyEnabled)
<button
type="button"
x-on:click.prevent="pond.imageEditEditor.oncancel"
class="fi-btn"
>
<button type="button" x-on:click.prevent="pond.imageEditEditor.oncancel"
class="fi-btn">
{{ __('filament-forms::components.file_upload.editor.actions.cancel.label') }}
</button>
<button
type="button"
x-on:click.prevent.stop="editor.reset()"
{{
(new \Illuminate\View\ComponentAttributeBag)
->color(\Filament\Support\View\Components\ButtonComponent::class, 'danger')
->class(['fi-btn fi-fo-file-upload-editor-control-panel-reset-action'])
}}
>
<button type="button" x-on:click.prevent.stop="editor.reset()"
{{ new \Illuminate\View\ComponentAttributeBag()->color(\Filament\Support\View\Components\ButtonComponent::class, 'danger')->class(['fi-btn fi-fo-file-upload-editor-control-panel-reset-action']) }}>
{{ __('filament-forms::components.file_upload.editor.actions.reset.label') }}
</button>
<button
type="button"
x-on:click.prevent="saveEditor"
{{
(new \Illuminate\View\ComponentAttributeBag)
->color(\Filament\Support\View\Components\ButtonComponent::class, 'success')
->class(['fi-btn'])
}}
>
<button type="button" x-on:click.prevent="saveEditor"
{{ new \Illuminate\View\ComponentAttributeBag()->color(\Filament\Support\View\Components\ButtonComponent::class, 'success')->class(['fi-btn']) }}>
{{ __('filament-forms::components.file_upload.editor.actions.save.label') }}
</button>
@else
<button
type="button"
x-on:click.prevent="saveEditor"
{{
(new \Illuminate\View\ComponentAttributeBag)
->color(\Filament\Support\View\Components\ButtonComponent::class, 'success')
->class(['fi-btn'])
}}
>
<button type="button" x-on:click.prevent="saveEditor"
{{ new \Illuminate\View\ComponentAttributeBag()->color(\Filament\Support\View\Components\ButtonComponent::class, 'success')->class(['fi-btn']) }}>
{{ __('filament-forms::components.file_upload.editor.actions.save.label') }}
</button>
<button
type="button"
x-on:click.prevent="pond.imageEditEditor.oncancel"
class="fi-btn"
>
<button type="button" x-on:click.prevent="pond.imageEditEditor.oncancel"
class="fi-btn">
{{ __('filament-forms::components.file_upload.editor.actions.cancel.label') }}
</button>
@endif
@@ -1,12 +1,9 @@
<input
{{
$attributes
->merge([
{{ $attributes->merge(
[
'id' => $getId(),
'type' => 'hidden',
$applyStateBindingModifiers('wire:model') => $getStatePath(),
], escape: false)
->merge($getExtraAttributes(), escape: false)
->class(['fi-fo-hidden'])
}}
/>
],
escape: false,
)->merge($getExtraAttributes(), escape: false)->class(['fi-fo-hidden']) }} />
@@ -14,46 +14,20 @@
$livewireKey = $getLivewireKey();
@endphp
<x-dynamic-component
:component="$fieldWrapperView"
:field="$field"
class="fi-fo-key-value-wrp"
>
<x-filament::input.wrapper
:disabled="$isDisabled"
:valid="! $errors->has($statePath)"
:attributes="
\Filament\Support\prepare_inherited_attributes($extraAttributeBag)
->class(['fi-fo-key-value'])
"
>
<div
x-load
<x-dynamic-component :component="$fieldWrapperView" :field="$field" class="fi-fo-key-value-wrp">
<x-filament::input.wrapper :disabled="$isDisabled" :valid="!$errors->has($statePath)" :attributes="\Filament\Support\prepare_inherited_attributes($extraAttributeBag)->class(['fi-fo-key-value'])">
<div x-load
x-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('key-value', 'filament/forms') }}"
x-data="keyValueFormComponent({
state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$statePath}')") }},
})"
wire:ignore
wire:key="{{ $livewireKey }}.{{
substr(md5(serialize([
$isDisabled,
])), 0, 64)
}}"
{{
$attributes
->merge($getExtraAlpineAttributes(), escape: false)
->class(['fi-fo-key-value-table-ctn'])
}}
>
state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$statePath}')") }},
})" wire:ignore
wire:key="{{ $livewireKey }}.{{ substr(md5(serialize([$isDisabled])), 0, 64) }}"
{{ $attributes->merge($getExtraAlpineAttributes(), escape: false)->class(['fi-fo-key-value-table-ctn']) }}>
<table class="fi-fo-key-value-table">
<thead>
<tr>
@if ($isReorderable && (! $isDisabled))
<th
scope="col"
x-show="rows.length"
class="fi-has-action"
></th>
@if ($isReorderable && !$isDisabled)
<th scope="col" x-show="rows.length" class="fi-has-action"></th>
@endif
<th scope="col">
@@ -64,66 +38,39 @@
{{ $getValueLabel() }}
</th>
@if ($isDeletable && (! $isDisabled))
<th
scope="col"
x-show="rows.length"
class="fi-has-action"
></th>
@if ($isDeletable && !$isDisabled)
<th scope="col" x-show="rows.length" class="fi-has-action"></th>
@endif
</tr>
</thead>
<tbody
@if ($isReorderable)
x-on:end.stop="reorderRows($event)"
@if ($isReorderable) x-on:end.stop="reorderRows($event)"
x-sortable
data-sortable-animation-duration="{{ $getReorderAnimationDuration() }}"
@endif
>
<template
x-bind:key="index"
x-for="(row, index) in rows"
>
<tr
@if ($isReorderable)
x-bind:x-sortable-item="row.key"
@endif
>
@if ($isReorderable && (! $isDisabled))
data-sortable-animation-duration="{{ $getReorderAnimationDuration() }}" @endif>
<template x-bind:key="index" x-for="(row, index) in rows">
<tr @if ($isReorderable) x-bind:x-sortable-item="row.key" @endif>
@if ($isReorderable && !$isDisabled)
<td class="fi-has-action">
<div
x-sortable-handle
class="fi-fo-key-value-table-row-sortable-handle"
>
<div x-sortable-handle class="fi-fo-key-value-table-row-sortable-handle">
{{ $getAction('reorder') }}
</div>
</td>
@endif
<td>
<input
@disabled((! $canEditKeys) || $isDisabled)
placeholder="{{ $keyPlaceholder }}"
type="text"
x-model="row.key"
x-on:input.debounce.{{ $debounce ?? '500ms' }}="updateState"
class="fi-input"
/>
<input @disabled(!$canEditKeys || $isDisabled) placeholder="{{ $keyPlaceholder }}" type="text"
x-model="row.key" x-on:input.debounce.{{ $debounce ?? '500ms' }}="updateState"
class="fi-input" />
</td>
<td>
<input
@disabled((! $canEditValues) || $isDisabled)
placeholder="{{ $valuePlaceholder }}"
type="text"
x-model="row.value"
x-on:input.debounce.{{ $debounce ?? '500ms' }}="updateState"
class="fi-input"
/>
<input @disabled(!$canEditValues || $isDisabled) placeholder="{{ $valuePlaceholder }}"
type="text" x-model="row.value"
x-on:input.debounce.{{ $debounce ?? '500ms' }}="updateState" class="fi-input" />
</td>
@if ($isDeletable && (! $isDisabled))
@if ($isDeletable && !$isDisabled)
<td class="fi-has-action">
<div x-on:click="deleteRow(index)">
{{ $getAction('delete') }}
@@ -135,11 +82,8 @@
</tbody>
</table>
@if ($isAddable && (! $isDisabled))
<div
x-on:click="addRow"
class="fi-fo-key-value-add-action-ctn"
>
@if ($isAddable && !$isDisabled)
<div x-on:click="addRow" class="fi-fo-key-value-add-action-ctn">
{{ $getAction('add') }}
</div>
@endif
@@ -8,13 +8,12 @@
@if (filled($id) || filled($extraAttributes))
{!! '<div' !!}
{{-- Avoid formatting issues with unclosed elements --}}
{{
$attributes
->merge([
{{ $attributes->merge(
[
'id' => $id,
], escape: false)
->merge($extraAttributes, escape: false)
}}
],
escape: false,
)->merge($extraAttributes, escape: false) }}
>
@endif
@@ -15,63 +15,50 @@
{!! str($getState())->markdown($getCommonMarkOptions(), $getCommonMarkExtensions())->sanitizeHtml() !!}
</div>
@else
<x-filament::input.wrapper
:valid="! $errors->has($statePath)"
:attributes="
\Filament\Support\prepare_inherited_attributes($extraAttributeBag)
->class(['fi-fo-markdown-editor'])
"
>
<div
aria-labelledby="{{ $id }}-label"
id="{{ $id }}"
role="group"
x-load
<x-filament::input.wrapper :valid="!$errors->has($statePath)" :attributes="\Filament\Support\prepare_inherited_attributes($extraAttributeBag)->class(['fi-fo-markdown-editor'])">
<div aria-labelledby="{{ $id }}-label" id="{{ $id }}" role="group" x-load
x-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('markdown-editor', 'filament/forms') }}"
x-data="markdownEditorFormComponent({
canAttachFiles: @js($hasFileAttachments()),
isLiveDebounced: @js($isLiveDebounced()),
isLiveOnBlur: @js($isLiveOnBlur()),
label: @js($label),
liveDebounce: @js($getNormalizedLiveDebounce()),
maxHeight: @js($getMaxHeight()),
minHeight: @js($getMinHeight()),
placeholder: @js($getPlaceholder()),
state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$statePath}')", isOptimisticallyLive: false) }},
toolbarButtons: @js($getToolbarButtons()),
translations: @js(__('filament-forms::components.markdown_editor')),
uploadFileAttachmentUsing: async (file, onSuccess, onError) => {
const acceptedTypes = @js($fileAttachmentsAcceptedFileTypes)
if (acceptedTypes && ! acceptedTypes.includes(file.type)) {
return onError(@js($fileAttachmentsAcceptedFileTypes ? __('filament-forms::components.markdown_editor.file_attachments_accepted_file_types_message', ['values' => implode(', ', $fileAttachmentsAcceptedFileTypes)]) : null))
}
const maxSize = @js($fileAttachmentsMaxSize)
if (maxSize && file.size > +maxSize * 1024) {
return onError(@js($fileAttachmentsMaxSize ? trans_choice('filament-forms::components.markdown_editor.file_attachments_max_size_message', $fileAttachmentsMaxSize, ['max' => $fileAttachmentsMaxSize]) : null))
}
$wire.upload(`componentFileAttachments.{{ $statePath }}`, file, () => {
$wire
.callSchemaComponentMethod(
'{{ $key }}',
'saveUploadedFileAttachmentAndGetUrl',
)
.then((url) => {
if (! url) {
return onError()
}
onSuccess(url)
})
canAttachFiles: @js($hasFileAttachments()),
isLiveDebounced: @js($isLiveDebounced()),
isLiveOnBlur: @js($isLiveOnBlur()),
label: @js($label),
liveDebounce: @js($getNormalizedLiveDebounce()),
maxHeight: @js($getMaxHeight()),
minHeight: @js($getMinHeight()),
placeholder: @js($getPlaceholder()),
state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$statePath}')", isOptimisticallyLive: false) }},
toolbarButtons: @js($getToolbarButtons()),
translations: @js(__('filament-forms::components.markdown_editor')),
uploadFileAttachmentUsing: async (file, onSuccess, onError) => {
const acceptedTypes = @js($fileAttachmentsAcceptedFileTypes)
if (acceptedTypes && !acceptedTypes.includes(file.type)) {
return onError(@js($fileAttachmentsAcceptedFileTypes ? __('filament-forms::components.markdown_editor.file_attachments_accepted_file_types_message', ['values' => implode(', ', $fileAttachmentsAcceptedFileTypes)]) : null))
}
const maxSize = @js($fileAttachmentsMaxSize)
if (maxSize && file.size > +maxSize * 1024) {
return onError(@js($fileAttachmentsMaxSize ? trans_choice('filament-forms::components.markdown_editor.file_attachments_max_size_message', $fileAttachmentsMaxSize, ['max' => $fileAttachmentsMaxSize]) : null))
}
$wire.upload(`componentFileAttachments.{{ $statePath }}`, file, () => {
$wire
.callSchemaComponentMethod(
'{{ $key }}',
'saveUploadedFileAttachmentAndGetUrl',
)
.then((url) => {
if (!url) {
return onError()
}
onSuccess(url)
})
},
})"
wire:ignore
{{ $getExtraAlpineAttributeBag() }}
>
})
},
})" wire:ignore {{ $getExtraAlpineAttributeBag() }}>
<textarea x-ref="editor" x-cloak></textarea>
</div>
</x-filament::input.wrapper>
@@ -12,21 +12,19 @@
<x-dynamic-component :component="$fieldWrapperView" :field="$field">
<div
{{
$attributes
->merge([
{{ $attributes->merge(
[
'id' => $id,
], escape: false)
->merge($extraAttributes, escape: false)
->class([
'fi-fo-modal-table-select',
'fi-fo-modal-table-select-disabled' => $isDisabled,
'fi-fo-modal-table-select-multiple' => $isMultiple,
])
}}
>
@if (((! $isMultiple) && filled($optionLabel = $getOptionLabel())) ||
($isMultiple && filled($optionLabels = $getOptionLabels())))
],
escape: false,
)->merge($extraAttributes, escape: false)->class([
'fi-fo-modal-table-select',
'fi-fo-modal-table-select-disabled' => $isDisabled,
'fi-fo-modal-table-select-multiple' => $isMultiple,
]) }}>
@if (
(!$isMultiple && filled($optionLabel = $getOptionLabel())) ||
($isMultiple && filled($optionLabels = $getOptionLabels())))
@if ($isMultiple && $hasBadges)
<div class="fi-fo-modal-table-select-badges-ctn">
@foreach ($optionLabels as $optionLabel)
@@ -60,7 +58,7 @@
</div>
@endif
@if (! $isDisabled)
@if (!$isDisabled)
<div>
{{ $getAction('select') }}
</div>
@@ -1,10 +1,9 @@
@php
$fieldWrapperView = $getFieldWrapperView();
$placeholder = $getPlaceholder();
$extraAttributes = $getExtraAttributeBag()
->merge($getExtraAlpineAttributes(), escape: false);
$extraInputAttributes = $getExtraInputAttributeBag()
->merge([
$extraAttributes = $getExtraAttributeBag()->merge($getExtraAlpineAttributes(), escape: false);
$extraInputAttributes = $getExtraInputAttributeBag()->merge(
[
'autocomplete' => false,
'autofocus' => $isAutofocused(),
'disabled' => $isDisabled(),
@@ -12,18 +11,15 @@
'length' => $getLength(),
'placeholder' => filled($placeholder) ? e($placeholder) : null,
'readonly' => $isReadOnly(),
'required' => $isRequired() && (! $isConcealed()),
'required' => $isRequired() && !$isConcealed(),
$applyStateBindingModifiers('wire:model') => $getStatePath(),
], escape: false);
],
escape: false,
);
@endphp
<x-dynamic-component :component="$fieldWrapperView" :field="$field">
<x-filament::input.one-time-code
:attributes="\Filament\Support\prepare_inherited_attributes($extraAttributes)"
>
<x-slot
name="input"
:attributes="\Filament\Support\prepare_inherited_attributes($extraInputAttributes)"
></x-slot>
<x-filament::input.one-time-code :attributes="\Filament\Support\prepare_inherited_attributes($extraAttributes)">
<x-slot name="input" :attributes="\Filament\Support\prepare_inherited_attributes($extraInputAttributes)"></x-slot>
</x-filament::input.one-time-code>
</x-dynamic-component>
@@ -14,27 +14,16 @@
}
@endphp
<div
data-field-wrapper
{{
(new ComponentAttributeBag)
->merge($field?->getExtraFieldWrapperAttributes() ?? [], escape: false)
->class([
'fi-fo-field',
])
}}
>
<div data-field-wrapper
{{ new ComponentAttributeBag()->merge($field?->getExtraFieldWrapperAttributes() ?? [], escape: false)->class(['fi-fo-field']) }}>
@if (filled($label))
<{{ $labelTag }}
@if ($labelTag === 'label')
for="{{ $id }}"
@if ($labelTag === 'label') for="{{ $id }}"
@else
id="{{ $id }}-label"
@endif
class="fi-fo-field-label fi-sr-only"
>
id="{{ $id }}-label" @endif
class="fi-fo-field-label fi-sr-only">
{{ $label }}
</{{ $labelTag }}>
</{{ $labelTag }}>
@endif
{{ $slot }}
@@ -14,39 +14,29 @@
<x-dynamic-component :component="$fieldWrapperView" :field="$field">
<div
{{
$getExtraAttributeBag()
->when(! $isInline, fn (ComponentAttributeBag $attributes) => $attributes->grid($getColumns(), $gridDirection))
->class([
'fi-fo-radio',
'fi-inline' => $isInline,
])
}}
>
{{ $getExtraAttributeBag()->when(!$isInline, fn(ComponentAttributeBag $attributes) => $attributes->grid($getColumns(), $gridDirection))->class(['fi-fo-radio', 'fi-inline' => $isInline]) }}>
@foreach ($getOptions() as $value => $label)
@php
$inputAttributes = $extraInputAttributeBag
->merge([
$inputAttributes = $extraInputAttributeBag->merge(
[
'autofocus' => $loop->first && $isAutofocused(),
'disabled' => $isDisabled || $isOptionDisabled($value, $label),
'id' => e($id . '-' . $value),
'name' => $id,
'value' => e($value),
$wireModelAttribute => $statePath,
], escape: false);
],
escape: false,
);
@endphp
<label class="fi-fo-radio-label">
<input
type="radio"
{{
$inputAttributes->class([
'fi-radio-input',
'fi-valid' => ! $errors->has($statePath),
'fi-invalid' => $errors->has($statePath),
])
}}
/>
<input type="radio"
{{ $inputAttributes->class([
'fi-radio-input',
'fi-valid' => !$errors->has($statePath),
'fi-invalid' => $errors->has($statePath),
]) }} />
<div class="fi-fo-radio-label-text">
<p>
@@ -42,34 +42,17 @@
<x-dynamic-component :component="$fieldWrapperView" :field="$field">
<div
{{
$attributes
->merge($getExtraAttributes(), escape: false)
->class([
'fi-fo-repeater',
'fi-collapsible' => $isCollapsible,
])
}}
>
{{ $attributes->merge($getExtraAttributes(), escape: false)->class(['fi-fo-repeater', 'fi-collapsible' => $isCollapsible]) }}>
@if ($collapseAllActionIsVisible || $expandAllActionIsVisible)
<div
@class([
'fi-fo-repeater-actions',
'fi-hidden' => count($items) < 2,
])
>
<div @class(['fi-fo-repeater-actions', 'fi-hidden' => count($items) < 2])>
@if ($collapseAllActionIsVisible)
<span
x-on:click="$dispatch('repeater-collapse', '{{ $statePath }}')"
>
<span x-on:click="$dispatch('repeater-collapse', '{{ $statePath }}')">
{{ $collapseAllAction }}
</span>
@endif
@if ($expandAllActionIsVisible)
<span
x-on:click="$dispatch('repeater-expand', '{{ $statePath }}')"
>
<span x-on:click="$dispatch('repeater-expand', '{{ $statePath }}')">
{{ $expandAllAction }}
</span>
@endif
@@ -77,24 +60,23 @@
@endif
@if (count($items))
<ul
x-sortable
{{
(new ComponentAttributeBag)
->grid($getGridColumns())
->merge([
<ul x-sortable
{{ new ComponentAttributeBag()->grid($getGridColumns())->merge(
[
'data-sortable-animation-duration' => $getReorderAnimationDuration(),
'x-on:end.stop' => '$wire.mountAction(\'reorder\', { items: $event.target.sortable.toArray() }, { schemaComponent: \'' . $key . '\' })',
], escape: false)
->class(['fi-fo-repeater-items'])
}}
>
'x-on:end.stop' =>
'$wire.mountAction(\'reorder\', { items: $event.target.sortable.toArray() }, { schemaComponent: \'' .
$key .
'\' })',
],
escape: false,
)->class(['fi-fo-repeater-items']) }}>
@foreach ($items as $itemKey => $item)
@php
$itemLabel = $getItemLabel($itemKey, $loop->index);
$visibleExtraItemActions = array_filter(
$extraItemActions,
fn (Action $action): bool => $action(['item' => $itemKey])->isVisible(),
fn(Action $action): bool => $action(['item' => $itemKey])->isVisible(),
);
$cloneAction = $cloneAction(['item' => $itemKey]);
$cloneActionIsVisible = $isCloneable && $cloneAction->isVisible();
@@ -105,36 +87,33 @@
$moveUpAction = $moveUpAction(['item' => $itemKey])->disabled($loop->first);
$moveUpActionIsVisible = $isReorderableWithButtons && $moveUpAction->isVisible();
$reorderActionIsVisible = $isReorderableWithDragAndDrop && $reorderAction->isVisible();
$hasItemHeader = $hasItemHeaders && ($reorderActionIsVisible || $moveUpActionIsVisible || $moveDownActionIsVisible || filled($itemLabel) || $cloneActionIsVisible || $deleteActionIsVisible || $isCollapsible || $visibleExtraItemActions);
$hasItemHeader =
$hasItemHeaders &&
($reorderActionIsVisible ||
$moveUpActionIsVisible ||
$moveDownActionIsVisible ||
filled($itemLabel) ||
$cloneActionIsVisible ||
$deleteActionIsVisible ||
$isCollapsible ||
$visibleExtraItemActions);
@endphp
<li
wire:ignore.self
wire:key="{{ $item->getLivewireKey() }}.item"
x-data="{
isCollapsed: @if ($persistCollapsed) $persist(@js($isCollapsed($item))).as(`repeater-${@js($key)}-${@js($itemKey)}-isCollapsed`) @else @js($isCollapsed($item)) @endif,
}"
<li wire:ignore.self wire:key="{{ $item->getLivewireKey() }}.item" x-data="{
isCollapsed: @if ($persistCollapsed) $persist(@js($isCollapsed($item))).as(`repeater-${@js($key)}-${@js($itemKey)}-isCollapsed`) @else @js($isCollapsed($item)) @endif,
}"
x-on:repeater-expand.window="$event.detail === '{{ $statePath }}' && (isCollapsed = false)"
x-on:repeater-collapse.window="$event.detail === '{{ $statePath }}' && (isCollapsed = true)"
x-on:expand="isCollapsed = false"
x-sortable-item="{{ $itemKey }}"
x-on:expand="isCollapsed = false" x-sortable-item="{{ $itemKey }}"
@class([
'fi-fo-repeater-item',
'fi-fo-repeater-item-has-header' => $hasItemHeader,
])
x-bind:class="{ 'fi-collapsed': isCollapsed }"
>
]) x-bind:class="{ 'fi-collapsed': isCollapsed }">
@if ($hasItemHeader)
<div
@if ($isCollapsible)
x-on:click.stop="isCollapsed = !isCollapsed"
@endif
class="fi-fo-repeater-item-header"
>
<div @if ($isCollapsible) x-on:click.stop="isCollapsed = !isCollapsed" @endif
class="fi-fo-repeater-item-header">
@if ($reorderActionIsVisible || $moveUpActionIsVisible || $moveDownActionIsVisible)
<ul
class="fi-fo-repeater-item-header-start-actions"
>
<ul class="fi-fo-repeater-item-header-start-actions">
@if ($reorderActionIsVisible)
<li x-on:click.stop>
{{ $reorderAction->extraAttributes(['x-sortable-handle' => true], merge: true) }}
@@ -154,24 +133,20 @@
@endif
@if (filled($itemLabel))
<{{ $itemLabelHeadingTag }}
@class([
'fi-fo-repeater-item-header-label',
'fi-truncated' => $isItemLabelTruncated,
])
>
<{{ $itemLabelHeadingTag }} @class([
'fi-fo-repeater-item-header-label',
'fi-truncated' => $isItemLabelTruncated,
])>
{{ $itemLabel }}
@if ($hasItemNumbers)
{{ $loop->iteration }}
@endif
</{{ $itemLabelHeadingTag }}>
</{{ $itemLabelHeadingTag }}>
@endif
@if ($cloneActionIsVisible || $deleteActionIsVisible || $isCollapsible || $visibleExtraItemActions)
<ul
class="fi-fo-repeater-item-header-end-actions"
>
<ul class="fi-fo-repeater-item-header-end-actions">
@foreach ($visibleExtraItemActions as $extraItemAction)
<li x-on:click.stop>
{{ $extraItemAction(['item' => $itemKey]) }}
@@ -191,19 +166,13 @@
@endif
@if ($isCollapsible)
<li
class="fi-fo-repeater-item-header-collapsible-actions"
x-on:click.stop="isCollapsed = !isCollapsed"
>
<div
class="fi-fo-repeater-item-header-collapse-action"
>
<li class="fi-fo-repeater-item-header-collapsible-actions"
x-on:click.stop="isCollapsed = !isCollapsed">
<div class="fi-fo-repeater-item-header-collapse-action">
{{ $getAction('collapse') }}
</div>
<div
class="fi-fo-repeater-item-header-expand-action"
>
<div class="fi-fo-repeater-item-header-expand-action">
{{ $getAction('expand') }}
</div>
</li>
@@ -213,15 +182,12 @@
</div>
@endif
<div
x-show="! isCollapsed"
class="fi-fo-repeater-item-content"
>
<div x-show="! isCollapsed" class="fi-fo-repeater-item-content">
{{ $item }}
</div>
</li>
@if (! $loop->last)
@if (!$loop->last)
@if ($isAddable && $addBetweenAction(['afterItem' => $itemKey])->isVisible())
<li class="fi-fo-repeater-add-between-items-ctn">
<div class="fi-fo-repeater-add-between-items">
@@ -230,19 +196,13 @@
</li>
@elseif (filled($labelBetweenItems))
<li class="fi-fo-repeater-label-between-items-ctn">
<div
class="fi-fo-repeater-label-between-items-divider-before"
></div>
<div class="fi-fo-repeater-label-between-items-divider-before"></div>
<span
class="fi-fo-repeater-label-between-items"
>
<span class="fi-fo-repeater-label-between-items">
{{ $labelBetweenItems }}
</span>
<div
class="fi-fo-repeater-label-between-items-divider-after"
></div>
<div class="fi-fo-repeater-label-between-items-divider-after"></div>
</li>
@endif
@endif
@@ -251,12 +211,12 @@
@endif
@if ($isAddable && $addAction->isVisible())
<div
@class([
'fi-fo-repeater-add',
($addActionAlignment instanceof Alignment) ? ('fi-align-' . $addActionAlignment->value) : $addActionAlignment,
])
>
<div @class([
'fi-fo-repeater-add',
$addActionAlignment instanceof Alignment
? 'fi-align-' . $addActionAlignment->value
: $addActionAlignment,
])>
{{ $addAction }}
</div>
@endif
@@ -27,31 +27,24 @@
@endphp
<x-dynamic-component :component="$fieldWrapperView" :field="$field">
<div
{{
$attributes
->merge($getExtraAttributes(), escape: false)
->class(['fi-fo-simple-repeater'])
}}
>
<div {{ $attributes->merge($getExtraAttributes(), escape: false)->class(['fi-fo-simple-repeater']) }}>
@if (count($items))
<ul
x-sortable
{{
(new ComponentAttributeBag)
->grid($getGridColumns())
->merge([
<ul x-sortable
{{ new ComponentAttributeBag()->grid($getGridColumns())->merge(
[
'data-sortable-animation-duration' => $getReorderAnimationDuration(),
'x-on:end.stop' => '$wire.mountAction(\'reorder\', { items: $event.target.sortable.toArray() }, { schemaComponent: \'' . $key . '\' })',
], escape: false)
->class(['fi-fo-simple-repeater-items'])
}}
>
'x-on:end.stop' =>
'$wire.mountAction(\'reorder\', { items: $event.target.sortable.toArray() }, { schemaComponent: \'' .
$key .
'\' })',
],
escape: false,
)->class(['fi-fo-simple-repeater-items']) }}>
@foreach ($items as $itemKey => $item)
@php
$visibleExtraItemActions = array_filter(
$extraItemActions,
fn (Action $action): bool => $action(['item' => $itemKey])->isVisible(),
fn(Action $action): bool => $action(['item' => $itemKey])->isVisible(),
);
$cloneAction = $cloneAction(['item' => $itemKey]);
$cloneActionIsVisible = $isCloneable && $cloneAction->isVisible();
@@ -64,16 +57,19 @@
$reorderActionIsVisible = $isReorderableWithDragAndDrop && $reorderAction->isVisible();
@endphp
<li
wire:key="{{ $item->getLivewireKey() }}.item"
x-sortable-item="{{ $itemKey }}"
class="fi-fo-simple-repeater-item"
>
<li wire:key="{{ $item->getLivewireKey() }}.item" x-sortable-item="{{ $itemKey }}"
class="fi-fo-simple-repeater-item">
<div class="fi-fo-simple-repeater-item-content">
{{ $item }}
</div>
@if ($reorderActionIsVisible || $moveUpActionIsVisible || $moveDownActionIsVisible || $cloneActionIsVisible || $deleteActionIsVisible || $visibleExtraItemActions)
@if (
$reorderActionIsVisible ||
$moveUpActionIsVisible ||
$moveDownActionIsVisible ||
$cloneActionIsVisible ||
$deleteActionIsVisible ||
$visibleExtraItemActions)
<ul class="fi-fo-simple-repeater-item-actions">
@if ($reorderActionIsVisible)
<li x-on:click.stop>
@@ -116,12 +112,12 @@
@endif
@if ($isAddable && $addAction->isVisible())
<div
@class([
'fi-fo-simple-repeater-add',
($addActionAlignment instanceof Alignment) ? ('fi-align-' . $addActionAlignment->value) : $addActionAlignment,
])
>
<div @class([
'fi-fo-simple-repeater-add',
$addActionAlignment instanceof Alignment
? 'fi-align-' . $addActionAlignment->value
: $addActionAlignment,
])>
{{ $addAction }}
</div>
@endif
@@ -36,35 +36,27 @@
<x-dynamic-component :component="$fieldWrapperView" :field="$field">
<div
{{ $attributes
->merge($getExtraAttributes(), escape: false)
->class([
'fi-fo-table-repeater',
'fi-compact' => $isCompact,
]) }}
>
{{ $attributes->merge($getExtraAttributes(), escape: false)->class(['fi-fo-table-repeater', 'fi-compact' => $isCompact]) }}>
@if (count($items))
<table>
<thead>
<tr>
@if ((count($items) > 1) && ($isReorderableWithButtons || $isReorderableWithDragAndDrop))
<th
class="fi-fo-table-repeater-empty-header-cell"
></th>
@if (count($items) > 1 && ($isReorderableWithButtons || $isReorderableWithDragAndDrop))
<th class="fi-fo-table-repeater-empty-header-cell"></th>
@endif
@foreach ($tableColumns as $column)
<th
@class([
'fi-wrapped' => $column->canHeaderWrap(),
(($columnAlignment = $column->getAlignment()) instanceof Alignment) ? ('fi-align-' . $columnAlignment->value) : $columnAlignment,
])
@style([
('width: ' . e($columnWidth = $column->getWidth())) => filled($columnWidth),
])
>
@if (! $column->isHeaderLabelHidden())
{{ $column->getLabel() }}@if ($column->isMarkedAsRequired())<sup class="fi-fo-table-repeater-header-required-mark">*</sup>
<th @class([
'fi-wrapped' => $column->canHeaderWrap(),
($columnAlignment = $column->getAlignment()) instanceof Alignment
? 'fi-align-' . $columnAlignment->value
: $columnAlignment,
]) @style([
'width: ' . e($columnWidth = $column->getWidth()) => filled($columnWidth),
])>
@if (!$column->isHeaderLabelHidden())
{{ $column->getLabel() }}@if ($column->isMarkedAsRequired())
<sup class="fi-fo-table-repeater-header-required-mark">*</sup>
@endif
@else
<span class="fi-sr-only">
@@ -75,26 +67,27 @@
@endforeach
@if (count($extraItemActions) || $isCloneable || $isDeletable)
<th
class="fi-fo-table-repeater-empty-header-cell"
></th>
<th class="fi-fo-table-repeater-empty-header-cell"></th>
@endif
</tr>
</thead>
<tbody
x-sortable
{{ (new ComponentAttributeBag)
->merge([
'data-sortable-animation-duration' => $getReorderAnimationDuration(),
'x-on:end.stop' => '$wire.mountAction(\'reorder\', { items: $event.target.sortable.toArray() }, { schemaComponent: \'' . $key . '\' })',
], escape: false) }}
>
<tbody x-sortable
{{ new ComponentAttributeBag()->merge(
[
'data-sortable-animation-duration' => $getReorderAnimationDuration(),
'x-on:end.stop' =>
'$wire.mountAction(\'reorder\', { items: $event.target.sortable.toArray() }, { schemaComponent: \'' .
$key .
'\' })',
],
escape: false,
) }}>
@foreach ($items as $itemKey => $item)
@php
$visibleExtraItemActions = array_filter(
$extraItemActions,
fn (Action $action): bool => $action(['item' => $itemKey])->isVisible(),
fn(Action $action): bool => $action(['item' => $itemKey])->isVisible(),
);
$cloneAction = $cloneAction(['item' => $itemKey]);
$cloneActionIsVisible = $isCloneable && $cloneAction->isVisible();
@@ -108,16 +101,11 @@
$itemStatePath = $item->getStatePath();
@endphp
<tr
wire:key="{{ $item->getLivewireKey() }}.item"
x-sortable-item="{{ $itemKey }}"
>
@if ((count($items) > 1) && ($isReorderableWithButtons || $isReorderableWithDragAndDrop))
<tr wire:key="{{ $item->getLivewireKey() }}.item" x-sortable-item="{{ $itemKey }}">
@if (count($items) > 1 && ($isReorderableWithButtons || $isReorderableWithDragAndDrop))
<td>
@if ($reorderActionIsVisible || $moveUpActionIsVisible || $moveDownActionIsVisible)
<div
class="fi-fo-table-repeater-actions"
>
<div class="fi-fo-table-repeater-actions">
@if ($reorderActionIsVisible)
<div x-on:click.stop>
{{ $reorderAction->extraAttributes(['x-sortable-handle' => true], merge: true) }}
@@ -139,14 +127,18 @@
@endif
@php
$counter = 0
$counter = 0;
@endphp
@foreach ($item->getComponents(withHidden: true) as $schemaComponent)
@php
throw_unless(
$schemaComponent instanceof \Filament\Schemas\Components\Component,
new \Exception('Table repeaters must only contain schema components, but [' . $schemaComponent::class . '] was used.'),
new \Exception(
'Table repeaters must only contain schema components, but [' .
$schemaComponent::class .
'] was used.',
),
);
@endphp
@@ -155,7 +147,7 @@
{{ $schemaComponent }}
@else
@php
$counter++
$counter++;
@endphp
@if ($schemaComponent->isVisible())
@@ -164,11 +156,13 @@
$columnVerticalAlignment = $currentColumn?->getVerticalAlignment();
@endphp
<td
@class([
($columnVerticalAlignment instanceof VerticalAlignment) ? ('fi-vertical-align-' . $columnVerticalAlignment->value) : (is_string($columnVerticalAlignment) ? $columnVerticalAlignment : ''),
])
>
<td @class([
$columnVerticalAlignment instanceof VerticalAlignment
? 'fi-vertical-align-' . $columnVerticalAlignment->value
: (is_string($columnVerticalAlignment)
? $columnVerticalAlignment
: ''),
])>
{!! $schemaComponent->toSchemaHtml() !!}
</td>
@else
@@ -181,9 +175,7 @@
@if (count($extraItemActions) || $isCloneable || $isDeletable)
<td>
@if ($visibleExtraItemActions || $cloneActionIsVisible || $deleteActionIsVisible)
<div
class="fi-fo-table-repeater-actions"
>
<div class="fi-fo-table-repeater-actions">
@foreach ($visibleExtraItemActions as $extraItemAction)
<div x-on:click.stop>
{{ $extraItemAction(['item' => $itemKey]) }}
@@ -212,12 +204,12 @@
@endif
@if ($isAddable && $addAction->isVisible())
<div
@class([
'fi-fo-table-repeater-add',
($addActionAlignment instanceof Alignment) ? ('fi-align-' . $addActionAlignment->value) : $addActionAlignment,
])
>
<div @class([
'fi-fo-table-repeater-add',
$addActionAlignment instanceof Alignment
? 'fi-align-' . $addActionAlignment->value
: $addActionAlignment,
])>
{{ $addAction }}
</div>
@endif
@@ -20,72 +20,55 @@
@endphp
<x-dynamic-component :component="$fieldWrapperView" :field="$field">
<x-filament::input.wrapper
:disabled="$isDisabled"
:valid="! $errors->has($statePath)"
x-cloak
:attributes="
\Filament\Support\prepare_inherited_attributes($extraAttributeBag)
->class(['fi-fo-rich-editor'])
"
>
<div
x-load
<x-filament::input.wrapper :disabled="$isDisabled" :valid="!$errors->has($statePath)" x-cloak :attributes="\Filament\Support\prepare_inherited_attributes($extraAttributeBag)->class(['fi-fo-rich-editor'])">
<div x-load
x-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('rich-editor', 'filament/forms') }}"
x-data="richEditorFormComponent({
acceptedFileTypes: @js($fileAttachmentsAcceptedFileTypes),
acceptedFileTypesValidationMessage: @js($fileAttachmentsAcceptedFileTypes ? __('filament-forms::components.rich_editor.file_attachments_accepted_file_types_message', ['values' => implode(', ', $fileAttachmentsAcceptedFileTypes)]) : null),
activePanel: @js($getActivePanel()),
canAttachFiles: @js($hasFileAttachments()),
deleteCustomBlockButtonIconHtml: @js(\Filament\Support\generate_icon_html(\Filament\Support\Icons\Heroicon::Trash, alias: \Filament\Forms\View\FormsIconAlias::COMPONENTS_RICH_EDITOR_PANELS_CUSTOM_BLOCK_DELETE_BUTTON)->toHtml()),
editCustomBlockButtonIconHtml: @js(\Filament\Support\generate_icon_html(\Filament\Support\Icons\Heroicon::PencilSquare, alias: \Filament\Forms\View\FormsIconAlias::COMPONENTS_RICH_EDITOR_PANELS_CUSTOM_BLOCK_EDIT_BUTTON)->toHtml()),
extensions: @js($getTipTapJsExtensions()),
floatingToolbars: @js($floatingToolbars),
getMentionLabelsUsing: async (mentions) => {
return await $wire.callSchemaComponentMethod(
@js($key),
'getMentionLabelsForJs',
{ mentions },
)
},
getMentionSearchResultsUsing: async (query, char) => {
return await $wire.callSchemaComponentMethod(
@js($key),
'getMentionSearchResultsForJs',
{ search: query, char },
)
},
hasResizableImages: @js($hasResizableImages()),
isDisabled: @js($isDisabled),
label: @js($label),
isLiveDebounced: @js($isLiveDebounced()),
isLiveOnBlur: @js($isLiveOnBlur()),
key: @js($key),
linkProtocols: @js($linkProtocols),
liveDebounce: @js($getNormalizedLiveDebounce()),
livewireId: @js($this->getId()),
maxFileSize: @js($fileAttachmentsMaxSize),
maxFileSizeValidationMessage: @js($fileAttachmentsMaxSize ? trans_choice('filament-forms::components.rich_editor.file_attachments_max_size_message', $fileAttachmentsMaxSize, ['max' => $fileAttachmentsMaxSize]) : null),
mentions: @js($mentions),
mergeTags: @js($mergeTags),
noMergeTagSearchResultsMessage: @js($getNoMergeTagSearchResultsMessage()),
placeholder: @js($getPlaceholder()),
state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$statePath}')", isOptimisticallyLive: false) }},
statePath: @js($statePath),
textColors: @js($getTextColorsForJs()),
uploadingFileMessage: @js($getUploadingFileMessage()),
})"
acceptedFileTypes: @js($fileAttachmentsAcceptedFileTypes),
acceptedFileTypesValidationMessage: @js($fileAttachmentsAcceptedFileTypes ? __('filament-forms::components.rich_editor.file_attachments_accepted_file_types_message', ['values' => implode(', ', $fileAttachmentsAcceptedFileTypes)]) : null),
activePanel: @js($getActivePanel()),
canAttachFiles: @js($hasFileAttachments()),
deleteCustomBlockButtonIconHtml: @js(\Filament\Support\generate_icon_html(\Filament\Support\Icons\Heroicon::Trash, alias: \Filament\Forms\View\FormsIconAlias::COMPONENTS_RICH_EDITOR_PANELS_CUSTOM_BLOCK_DELETE_BUTTON)->toHtml()),
editCustomBlockButtonIconHtml: @js(\Filament\Support\generate_icon_html(\Filament\Support\Icons\Heroicon::PencilSquare, alias: \Filament\Forms\View\FormsIconAlias::COMPONENTS_RICH_EDITOR_PANELS_CUSTOM_BLOCK_EDIT_BUTTON)->toHtml()),
extensions: @js($getTipTapJsExtensions()),
floatingToolbars: @js($floatingToolbars),
getMentionLabelsUsing: async (mentions) => {
return await $wire.callSchemaComponentMethod(
@js($key),
'getMentionLabelsForJs', { mentions },
)
},
getMentionSearchResultsUsing: async (query, char) => {
return await $wire.callSchemaComponentMethod(
@js($key),
'getMentionSearchResultsForJs', { search: query, char },
)
},
hasResizableImages: @js($hasResizableImages()),
isDisabled: @js($isDisabled),
label: @js($label),
isLiveDebounced: @js($isLiveDebounced()),
isLiveOnBlur: @js($isLiveOnBlur()),
key: @js($key),
linkProtocols: @js($linkProtocols),
liveDebounce: @js($getNormalizedLiveDebounce()),
livewireId: @js($this->getId()),
maxFileSize: @js($fileAttachmentsMaxSize),
maxFileSizeValidationMessage: @js($fileAttachmentsMaxSize ? trans_choice('filament-forms::components.rich_editor.file_attachments_max_size_message', $fileAttachmentsMaxSize, ['max' => $fileAttachmentsMaxSize]) : null),
mentions: @js($mentions),
mergeTags: @js($mergeTags),
noMergeTagSearchResultsMessage: @js($getNoMergeTagSearchResultsMessage()),
placeholder: @js($getPlaceholder()),
state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$statePath}')", isOptimisticallyLive: false) }},
statePath: @js($statePath),
textColors: @js($getTextColorsForJs()),
uploadingFileMessage: @js($getUploadingFileMessage()),
})"
x-bind:class="{
'fi-fo-rich-editor-uploading-file': isUploadingFile,
}"
wire:ignore
wire:key="{{ $livewireKey }}.{{
substr(md5(serialize([
$isDisabled,
])), 0, 64)
}}"
>
@if ((! $isDisabled) && filled($toolbarButtons))
wire:ignore wire:key="{{ $livewireKey }}.{{ substr(md5(serialize([$isDisabled])), 0, 64) }}">
@if (!$isDisabled && filled($toolbarButtons))
<div class="fi-fo-rich-editor-toolbar">
@foreach ($toolbarButtons as $button => $buttonGroup)
<div class="fi-fo-rich-editor-toolbar-group">
@@ -101,11 +84,7 @@
</div>
@endif
<div
x-show="isUploadingFile"
x-cloak
class="fi-fo-rich-editor-uploading-file-message"
>
<div x-show="isUploadingFile" x-cloak class="fi-fo-rich-editor-uploading-file-message">
{{ \Filament\Support\generate_loading_indicator_html() }}
<span>
@@ -113,26 +92,16 @@
</span>
</div>
<div
x-show="! isUploadingFile && fileValidationMessage"
x-cloak
class="fi-fo-rich-editor-file-validation-message"
>
<span
x-text="fileValidationMessage"
x-show="! isUploadingFile && fileValidationMessage"
></span>
<div x-show="! isUploadingFile && fileValidationMessage" x-cloak
class="fi-fo-rich-editor-file-validation-message">
<span x-text="fileValidationMessage" x-show="! isUploadingFile && fileValidationMessage"></span>
</div>
<div
{{ $getExtraInputAttributeBag()->class(['fi-fo-rich-editor-main']) }}
>
<div {{ $getExtraInputAttributeBag()->class(['fi-fo-rich-editor-main']) }}>
<div class="fi-fo-rich-editor-content fi-prose" x-ref="editor">
@foreach ($floatingToolbars as $nodeName => $buttons)
<div
x-ref="floatingToolbar::{{ $nodeName }}"
class="fi-fo-rich-editor-floating-toolbar fi-not-prose"
>
<div x-ref="floatingToolbar::{{ $nodeName }}"
class="fi-fo-rich-editor-floating-toolbar fi-not-prose">
@foreach ($buttons as $button)
@if (is_string($button))
{{ $tools[$button] }}
@@ -144,30 +113,16 @@
@endforeach
</div>
@if (! $isDisabled)
<div
x-show="isPanelActive()"
x-cloak
class="fi-fo-rich-editor-panels"
>
<div
x-show="isPanelActive('customBlocks')"
x-cloak
class="fi-fo-rich-editor-panel"
>
@if (!$isDisabled)
<div x-show="isPanelActive()" x-cloak class="fi-fo-rich-editor-panels">
<div x-show="isPanelActive('customBlocks')" x-cloak class="fi-fo-rich-editor-panel">
<div class="fi-fo-rich-editor-panel-header">
<p class="fi-fo-rich-editor-panel-heading">
{{ __('filament-forms::components.rich_editor.tools.custom_blocks') }}
</p>
<div
class="fi-fo-rich-editor-panel-close-btn-ctn"
>
<button
type="button"
x-on:click="togglePanel()"
class="fi-icon-btn"
>
<div class="fi-fo-rich-editor-panel-close-btn-ctn">
<button type="button" x-on:click="togglePanel()" class="fi-icon-btn">
{{ \Filament\Support\generate_icon_html(\Filament\Support\Icons\Heroicon::XMark, alias: \Filament\Forms\View\FormsIconAlias::COMPONENTS_RICH_EDITOR_PANELS_CUSTOM_BLOCKS_CLOSE_BUTTON) }}
</button>
</div>
@@ -176,25 +131,18 @@
<div class="fi-fo-rich-editor-custom-blocks-ctn">
@foreach ($groupedCustomBlocks as $customBlockGroupLabel => $groupBlocks)
@if (filled($customBlockGroupLabel))
<h4
class="fi-fo-rich-editor-custom-blocks-group-header"
>
<h4 class="fi-fo-rich-editor-custom-blocks-group-header">
{{ $customBlockGroupLabel }}
</h4>
@endif
<div
class="fi-fo-rich-editor-custom-blocks-list"
>
<div class="fi-fo-rich-editor-custom-blocks-list">
@foreach ($groupBlocks as $block)
@php
$blockId = $block::getId();
@endphp
<button
draggable="true"
type="button"
x-data="{ isLoading: false }"
<button draggable="true" type="button" x-data="{ isLoading: false }"
x-on:click="
isLoading = true
@@ -207,13 +155,12 @@
x-on:dragstart="$event.dataTransfer.setData('customBlock', @js($blockId))"
x-on:open-modal.window="isLoading = false"
x-on:run-rich-editor-commands.window="isLoading = false"
class="fi-fo-rich-editor-custom-block-btn"
>
{{
\Filament\Support\generate_loading_indicator_html((new \Illuminate\View\ComponentAttributeBag([
class="fi-fo-rich-editor-custom-block-btn">
{{ \Filament\Support\generate_loading_indicator_html(
new \Illuminate\View\ComponentAttributeBag([
'x-show' => 'isLoading',
])))
}}
]),
) }}
{{ $block::getLabel() }}
</button>
@@ -223,24 +170,14 @@
</div>
</div>
<div
x-show="isPanelActive('mergeTags')"
x-cloak
class="fi-fo-rich-editor-panel"
>
<div x-show="isPanelActive('mergeTags')" x-cloak class="fi-fo-rich-editor-panel">
<div class="fi-fo-rich-editor-panel-header">
<p class="fi-fo-rich-editor-panel-heading">
{{ __('filament-forms::components.rich_editor.tools.merge_tags') }}
</p>
<div
class="fi-fo-rich-editor-panel-close-btn-ctn"
>
<button
type="button"
x-on:click="togglePanel()"
class="fi-icon-btn"
>
<div class="fi-fo-rich-editor-panel-close-btn-ctn">
<button type="button" x-on:click="togglePanel()" class="fi-icon-btn">
{{ \Filament\Support\generate_icon_html(\Filament\Support\Icons\Heroicon::XMark, alias: \Filament\Forms\View\FormsIconAlias::COMPONENTS_RICH_EDITOR_PANELS_MERGE_TAGS_CLOSE_BUTTON) }}
</button>
</div>
@@ -248,17 +185,11 @@
<div class="fi-fo-rich-editor-merge-tags-list">
@foreach ($mergeTags as $tagId => $tagLabel)
<button
draggable="true"
type="button"
<button draggable="true" type="button"
x-on:click="insertMergeTag(@js($tagId))"
x-on:dragstart="$event.dataTransfer.setData('mergeTag', @js($tagId))"
class="fi-fo-rich-editor-merge-tag-btn"
>
<span
data-type="mergeTag"
data-id="{{ $tagId }}"
>
class="fi-fo-rich-editor-merge-tag-btn">
<span data-type="mergeTag" data-id="{{ $tagId }}">
{{ $tagLabel }}
</span>
</button>
@@ -13,7 +13,7 @@
$isRequired = $isRequired();
$isConcealed = $isConcealed();
$isHtmlAllowed = $isHtmlAllowed();
$isNative = (! ($isSearchable || $isMultiple || $isHtmlAllowed) && $isNative());
$isNative = !($isSearchable || $isMultiple || $isHtmlAllowed) && $isNative();
$isPrefixInline = $isPrefixInline();
$isSuffixInline = $isSuffixInline();
$key = $getKey();
@@ -31,59 +31,41 @@
$livewireKey = $getLivewireKey();
@endphp
<x-dynamic-component
:component="$fieldWrapperView"
:field="$field"
class="fi-fo-select-wrp"
>
<x-filament::input.wrapper
:disabled="$isDisabled"
:inline-prefix="$isPrefixInline"
:inline-suffix="$isSuffixInline"
:prefix="$prefixLabel"
:prefix-actions="$prefixActions"
:prefix-icon="$prefixIcon"
:prefix-icon-color="$prefixIconColor"
:suffix="$suffixLabel"
:suffix-actions="$suffixActions"
:suffix-icon="$suffixIcon"
:suffix-icon-color="$suffixIconColor"
:valid="! $errors->has($statePath)"
<x-dynamic-component :component="$fieldWrapperView" :field="$field" class="fi-fo-select-wrp">
<x-filament::input.wrapper :disabled="$isDisabled" :inline-prefix="$isPrefixInline" :inline-suffix="$isSuffixInline" :prefix="$prefixLabel" :prefix-actions="$prefixActions"
:prefix-icon="$prefixIcon" :prefix-icon-color="$prefixIconColor" :suffix="$suffixLabel" :suffix-actions="$suffixActions" :suffix-icon="$suffixIcon" :suffix-icon-color="$suffixIconColor"
:valid="!$errors->has($statePath)"
:x-on:focus-input.stop="$isNative ? '$el.querySelector(\'select\')?.focus()' : '$el.querySelector(\'.fi-select-input-btn\')?.focus()'"
:attributes="
\Filament\Support\prepare_inherited_attributes($getExtraAttributeBag())
->class([
'fi-fo-select',
'fi-fo-select-has-inline-prefix' => $isPrefixInline && (count($prefixActions) || $prefixIcon || filled($prefixLabel)),
'fi-fo-select-native' => $isNative,
])
"
>
:attributes="\Filament\Support\prepare_inherited_attributes($getExtraAttributeBag())->class([
'fi-fo-select',
'fi-fo-select-has-inline-prefix' =>
$isPrefixInline && (count($prefixActions) || $prefixIcon || filled($prefixLabel)),
'fi-fo-select-native' => $isNative,
])">
@if ($isNative)
@php
$options = $getOptions();
@endphp
<select
{{
$extraInputAttributeBag
->merge([
{{ $extraInputAttributeBag->merge(
[
'autofocus' => $isAutofocused,
'disabled' => $isDisabled,
'id' => $id,
'required' => $isRequired && (! $isConcealed),
'wire:key' => $hasDynamicOptions ? ($livewireKey . '.' . substr(md5(serialize($options)), 0, 64)) : null,
'required' => $isRequired && !$isConcealed,
'wire:key' => $hasDynamicOptions ? $livewireKey . '.' . substr(md5(serialize($options)), 0, 64) : null,
$applyStateBindingModifiers('wire:model') => $statePath,
], escape: false)
->class([
'fi-select-input',
'fi-select-input-has-inline-prefix' => $isPrefixInline && (count($prefixActions) || $prefixIcon || filled($prefixLabel)),
])
}}
>
],
escape: false,
)->class([
'fi-select-input',
'fi-select-input-has-inline-prefix' =>
$isPrefixInline && (count($prefixActions) || $prefixIcon || filled($prefixLabel)),
]) }}>
@if ($canSelectPlaceholder)
<option value="">
@if (! $isDisabled)
@if (!$isDisabled)
{{ $getPlaceholder() }}
@endif
</option>
@@ -93,10 +75,7 @@
@if (is_array($label))
<optgroup label="{{ $value }}">
@foreach ($label as $groupedValue => $groupedLabel)
<option
@disabled($isOptionDisabled($groupedValue, $groupedLabel))
value="{{ $groupedValue }}"
>
<option @disabled($isOptionDisabled($groupedValue, $groupedLabel)) value="{{ $groupedValue }}">
@if ($isHtmlAllowed)
{!! $groupedLabel !!}
@else
@@ -106,10 +85,7 @@
@endforeach
</optgroup>
@else
<option
@disabled($isOptionDisabled($value, $label))
value="{{ $value }}"
>
<option @disabled($isOptionDisabled($value, $label)) value="{{ $value }}">
@if ($isHtmlAllowed)
{!! $label !!}
@else
@@ -120,102 +96,83 @@
@endforeach
</select>
@else
<div
class="fi-hidden"
x-data="{
isDisabled: @js($isDisabled),
init() {
const container = $el.nextElementSibling
container.dispatchEvent(
new CustomEvent('set-select-property', {
detail: { isDisabled: this.isDisabled },
}),
)
},
}"
></div>
<div
x-load
<div class="fi-hidden" x-data="{
isDisabled: @js($isDisabled),
init() {
const container = $el.nextElementSibling
container.dispatchEvent(
new CustomEvent('set-select-property', {
detail: { isDisabled: this.isDisabled },
}),
)
},
}"></div>
<div x-load
x-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('select', 'filament/forms') }}"
x-data="selectFormComponent({
canOptionLabelsWrap: @js($canOptionLabelsWrap),
canSelectPlaceholder: @js($canSelectPlaceholder),
getOptionLabelUsing: async () => {
return await Livewire.fireAction(
$wire.__instance,
'callSchemaComponentMethod',
[@js($key), 'getOptionLabel'],
{ async: true },
)
},
getOptionLabelsUsing: async () => {
return await Livewire.fireAction(
$wire.__instance,
'callSchemaComponentMethod',
[@js($key), 'getOptionLabelsForJs'],
{ async: true },
)
},
getOptionsUsing: async () => {
return await Livewire.fireAction(
$wire.__instance,
'callSchemaComponentMethod',
[@js($key), 'getOptionsForJs'],
{ async: true },
)
},
getSearchResultsUsing: async (search) => {
return await Livewire.fireAction(
$wire.__instance,
'callSchemaComponentMethod',
[@js($key), 'getSearchResultsForJs', { search }],
{ async: true },
)
},
hasDynamicOptions: @js($hasDynamicOptions),
hasDynamicSearchResults: @js($hasDynamicSearchResults()),
hasInitialNoOptionsMessage: @js($hasInitialNoOptionsMessage),
initialOptionLabel: @js((blank($state) || $isMultiple) ? null : $getOptionLabel()),
initialOptionLabels: @js((filled($state) && $isMultiple) ? $getOptionLabelsForJs() : []),
initialState: @js($state),
isAutofocused: @js($isAutofocused),
isDisabled: @js($isDisabled),
isHtmlAllowed: @js($isHtmlAllowed),
isMultiple: @js($isMultiple),
isReorderable: @js($isReorderable),
isSearchable: @js($isSearchable),
livewireId: @js($this->getId()),
loadingMessage: @js($getLoadingMessage()),
maxItems: @js($getMaxItems()),
maxItemsMessage: @js($getMaxItemsMessage()),
noOptionsMessage: @js($getNoOptionsMessage()),
noSearchResultsMessage: @js($getNoSearchResultsMessage()),
options: @js($getOptionsForJs()),
optionsLimit: @js($getOptionsLimit()),
placeholder: @js($getPlaceholder()),
position: @js($getPosition()),
searchDebounce: @js($getSearchDebounce()),
searchingMessage: @js($getSearchingMessage()),
searchPrompt: @js($getSearchPrompt()),
searchableOptionFields: @js($getSearchableOptionFields()),
state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$statePath}')") }},
statePath: @js($statePath),
})"
wire:ignore
wire:key="{{ $livewireKey }}.{{
substr(md5(serialize([
$isDisabled,
$isReorderable,
])), 0, 64)
}}"
canOptionLabelsWrap: @js($canOptionLabelsWrap),
canSelectPlaceholder: @js($canSelectPlaceholder),
getOptionLabelUsing: async () => {
return await Livewire.fireAction(
$wire.__instance,
'callSchemaComponentMethod',
[@js($key), 'getOptionLabel'], { async: true },
)
},
getOptionLabelsUsing: async () => {
return await Livewire.fireAction(
$wire.__instance,
'callSchemaComponentMethod',
[@js($key), 'getOptionLabelsForJs'], { async: true },
)
},
getOptionsUsing: async () => {
return await Livewire.fireAction(
$wire.__instance,
'callSchemaComponentMethod',
[@js($key), 'getOptionsForJs'], { async: true },
)
},
getSearchResultsUsing: async (search) => {
return await Livewire.fireAction(
$wire.__instance,
'callSchemaComponentMethod',
[@js($key), 'getSearchResultsForJs', { search }], { async: true },
)
},
hasDynamicOptions: @js($hasDynamicOptions),
hasDynamicSearchResults: @js($hasDynamicSearchResults()),
hasInitialNoOptionsMessage: @js($hasInitialNoOptionsMessage),
initialOptionLabel: @js(blank($state) || $isMultiple ? null : $getOptionLabel()),
initialOptionLabels: @js(filled($state) && $isMultiple ? $getOptionLabelsForJs() : []),
initialState: @js($state),
isAutofocused: @js($isAutofocused),
isDisabled: @js($isDisabled),
isHtmlAllowed: @js($isHtmlAllowed),
isMultiple: @js($isMultiple),
isReorderable: @js($isReorderable),
isSearchable: @js($isSearchable),
livewireId: @js($this->getId()),
loadingMessage: @js($getLoadingMessage()),
maxItems: @js($getMaxItems()),
maxItemsMessage: @js($getMaxItemsMessage()),
noOptionsMessage: @js($getNoOptionsMessage()),
noSearchResultsMessage: @js($getNoSearchResultsMessage()),
options: @js($getOptionsForJs()),
optionsLimit: @js($getOptionsLimit()),
placeholder: @js($getPlaceholder()),
position: @js($getPosition()),
searchDebounce: @js($getSearchDebounce()),
searchingMessage: @js($getSearchingMessage()),
searchPrompt: @js($getSearchPrompt()),
searchableOptionFields: @js($getSearchableOptionFields()),
state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$statePath}')") }},
statePath: @js($statePath),
})" wire:ignore
wire:key="{{ $livewireKey }}.{{ substr(md5(serialize([$isDisabled, $isReorderable])), 0, 64) }}"
x-on:keydown.esc="select.dropdown.isActive && $event.stopPropagation()"
x-on:set-select-property="$event.detail.isDisabled ? select.disable() : select.enable()"
{{
$attributes
->merge($getExtraAlpineAttributes(), escape: false)
->class(['fi-select-input'])
}}
>
{{ $attributes->merge($getExtraAlpineAttributes(), escape: false)->class(['fi-select-input']) }}>
<div x-ref="select"></div>
</div>
@endif
@@ -6,56 +6,43 @@
$isDisabled = $isDisabled();
@endphp
<x-dynamic-component
:component="$fieldWrapperView"
:field="$field"
:inline-label-vertical-alignment="\Filament\Support\Enums\VerticalAlignment::Center"
>
<div
x-load
<x-dynamic-component :component="$fieldWrapperView" :field="$field" :inline-label-vertical-alignment="\Filament\Support\Enums\VerticalAlignment::Center">
<div x-load
x-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('slider', 'filament/forms') }}"
x-data="sliderFormComponent({
arePipsStepped: @js($arePipsStepped()),
behavior: @js($getBehaviorForJs()),
decimalPlaces: @js($getDecimalPlaces()),
fillTrack: @js($getFillTrack()),
isDisabled: @js($isDisabled),
isRtl: @js($isRtl()),
isVertical: @js($isVertical),
maxDifference: @js($getMaxDifference()),
minDifference: @js($getMinDifference()),
maxValue: @js($getMaxValue()),
minValue: @js($getMinValue()),
nonLinearPoints: @js($getNonLinearPoints()),
pipsDensity: @js($getPipsDensity()),
pipsFilter: @js($getPipsFilterForJs()),
pipsFormatter: @js($getPipsFormatterForJs()),
pipsMode: @js($pipsMode),
pipsValues: @js($getPipsValues()),
rangePadding: @js($getRangePadding()),
state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$getStatePath()}')") }},
step: @js($getStep()),
tooltips: @js($getTooltipsForJs()),
})"
wire:ignore
wire:key="{{ $livewireKey }}.{{
substr(md5(serialize([
$isDisabled,
])), 0, 64)
}}"
{{
$attributes
->merge([
arePipsStepped: @js($arePipsStepped()),
behavior: @js($getBehaviorForJs()),
decimalPlaces: @js($getDecimalPlaces()),
fillTrack: @js($getFillTrack()),
isDisabled: @js($isDisabled),
isRtl: @js($isRtl()),
isVertical: @js($isVertical),
maxDifference: @js($getMaxDifference()),
minDifference: @js($getMinDifference()),
maxValue: @js($getMaxValue()),
minValue: @js($getMinValue()),
nonLinearPoints: @js($getNonLinearPoints()),
pipsDensity: @js($getPipsDensity()),
pipsFilter: @js($getPipsFilterForJs()),
pipsFormatter: @js($getPipsFormatterForJs()),
pipsMode: @js($pipsMode),
pipsValues: @js($getPipsValues()),
rangePadding: @js($getRangePadding()),
state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$getStatePath()}')") }},
step: @js($getStep()),
tooltips: @js($getTooltipsForJs()),
})" wire:ignore
wire:key="{{ $livewireKey }}.{{ substr(md5(serialize([$isDisabled])), 0, 64) }}"
{{ $attributes->merge(
[
'id' => $getId(),
], escape: false)
->merge($getExtraAttributes(), escape: false)
->merge($getExtraAlpineAttributes(), escape: false)
->class([
'fi-fo-slider',
'fi-fo-slider-has-pips' => $pipsMode,
'fi-fo-slider-has-tooltips' => $hasTooltips(),
'fi-fo-slider-vertical' => $isVertical,
])
}}
></div>
],
escape: false,
)->merge($getExtraAttributes(), escape: false)->merge($getExtraAlpineAttributes(), escape: false)->class([
'fi-fo-slider',
'fi-fo-slider-has-pips' => $pipsMode,
'fi-fo-slider-has-tooltips' => $hasTooltips(),
'fi-fo-slider-vertical' => $isVertical,
]) }}>
</div>
</x-dynamic-component>
@@ -8,24 +8,26 @@
<x-dynamic-component :component="$fieldWrapperView" :field="$field">
<div
{{
$attributes
->merge([
{{ $attributes->merge(
[
'id' => $id,
], escape: false)
->merge($extraAttributes, escape: false)
}}
>
@livewire(TableSelectLivewireComponent::class, [
'isDisabled' => $isDisabled(),
'maxSelectableRecords' => $getMaxItems(),
'model' => $getModel(),
'record' => $getRecord(),
'relationshipName' => $getRelationshipName(),
'shouldIgnoreRelatedRecords' => $shouldIgnoreRelatedRecords(),
'tableConfiguration' => base64_encode($getTableConfiguration()),
'tableArguments' => $getTableArguments(),
$applyStateBindingModifiers('wire:model') => $getStatePath(),
], key($getLivewireKey()))
],
escape: false,
)->merge($extraAttributes, escape: false) }}>
@livewire(
TableSelectLivewireComponent::class,
[
'isDisabled' => $isDisabled(),
'maxSelectableRecords' => $getMaxItems(),
'model' => $getModel(),
'record' => $getRecord(),
'relationshipName' => $getRelationshipName(),
'shouldIgnoreRelatedRecords' => $shouldIgnoreRelatedRecords(),
'tableConfiguration' => base64_encode($getTableConfiguration()),
'tableArguments' => $getTableArguments(),
$applyStateBindingModifiers('wire:model') => $getStatePath(),
],
key($getLivewireKey())
)
</div>
</x-dynamic-component>
@@ -7,7 +7,7 @@
$isAutofocused = $isAutofocused();
$isDisabled = $isDisabled();
$isPrefixInline = $isPrefixInline();
$isReorderable = (! $isDisabled) && $isReorderable();
$isReorderable = !$isDisabled && $isReorderable();
$isSuffixInline = $isSuffixInline();
$placeholder = $getPlaceholder();
$prefixActions = $getPrefixActions();
@@ -21,47 +21,21 @@
$suffixLabel = $getSuffixLabel();
@endphp
<x-dynamic-component
:component="$fieldWrapperView"
:field="$field"
class="fi-fo-tags-input-wrp"
>
<x-filament::input.wrapper
:disabled="$isDisabled"
:inline-prefix="$isPrefixInline"
:inline-suffix="$isSuffixInline"
:prefix="$prefixLabel"
:prefix-actions="$prefixActions"
:prefix-icon="$prefixIcon"
:prefix-icon-color="$prefixIconColor"
:suffix="$suffixLabel"
:suffix-actions="$suffixActions"
:suffix-icon="$suffixIcon"
:suffix-icon-color="$suffixIconColor"
:valid="! $errors->has($statePath)"
x-on:focus-input.stop="$el.querySelector('input')?.focus()"
:attributes="
\Filament\Support\prepare_inherited_attributes($attributes)
->merge($extraAttributes, escape: false)
->class([
'fi-fo-tags-input',
'fi-disabled' => $isDisabled,
])
"
>
<div
x-load
<x-dynamic-component :component="$fieldWrapperView" :field="$field" class="fi-fo-tags-input-wrp">
<x-filament::input.wrapper :disabled="$isDisabled" :inline-prefix="$isPrefixInline" :inline-suffix="$isSuffixInline" :prefix="$prefixLabel" :prefix-actions="$prefixActions"
:prefix-icon="$prefixIcon" :prefix-icon-color="$prefixIconColor" :suffix="$suffixLabel" :suffix-actions="$suffixActions" :suffix-icon="$suffixIcon" :suffix-icon-color="$suffixIconColor"
:valid="!$errors->has($statePath)" x-on:focus-input.stop="$el.querySelector('input')?.focus()" :attributes="\Filament\Support\prepare_inherited_attributes($attributes)
->merge($extraAttributes, escape: false)
->class(['fi-fo-tags-input', 'fi-disabled' => $isDisabled])">
<div x-load
x-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('tags-input', 'filament/forms') }}"
x-data="tagsInputFormComponent({
state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$statePath}')") }},
splitKeys: @js($getSplitKeys()),
})"
{{ $getExtraAlpineAttributeBag() }}
>
state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$statePath}')") }},
splitKeys: @js($getSplitKeys()),
})" {{ $getExtraAlpineAttributeBag() }}>
<input
{{
$extraInputAttributeBag
->merge([
{{ $extraInputAttributeBag->merge(
[
'autocomplete' => 'off',
'autofocus' => $isAutofocused,
'disabled' => $isDisabled,
@@ -70,21 +44,20 @@
'placeholder' => filled($placeholder) ? e($placeholder) : null,
'type' => 'text',
'x-bind' => 'input',
], escape: false)
->class([
'fi-input',
'fi-input-has-inline-prefix' => $isPrefixInline && (count($prefixActions) || $prefixIcon || filled($prefixLabel)),
'fi-input-has-inline-suffix' => $isSuffixInline && (count($suffixActions) || $suffixIcon || filled($suffixLabel)),
])
}}
/>
],
escape: false,
)->class([
'fi-input',
'fi-input-has-inline-prefix' =>
$isPrefixInline && (count($prefixActions) || $prefixIcon || filled($prefixLabel)),
'fi-input-has-inline-suffix' =>
$isSuffixInline && (count($suffixActions) || $suffixIcon || filled($suffixLabel)),
]) }} />
<datalist id="{{ $id }}-suggestions">
@foreach ($getSuggestions() as $suggestion)
<template
x-bind:key="@js($suggestion)"
x-if="! (state?.includes(@js($suggestion)) ?? true)"
>
<template x-bind:key="@js($suggestion)"
x-if="! (state?.includes(@js($suggestion)) ?? true)">
<option value="{{ $suggestion }}" />
</template>
@endforeach
@@ -92,37 +65,25 @@
<div wire:ignore>
<template x-cloak x-if="state?.length">
<div
@if ($isReorderable)
x-on:end.stop="reorderTags($event)"
<div @if ($isReorderable) x-on:end.stop="reorderTags($event)"
x-sortable
data-sortable-animation-duration="{{ $getReorderAnimationDuration() }}"
@endif
class="fi-fo-tags-input-tags-ctn"
>
<template
x-for="(tag, index) in state"
x-bind:key="`${tag}-${index}`"
>
<x-filament::badge
:color="$color"
:x-bind:x-sortable-item="$isReorderable ? 'index' : null"
:x-sortable-handle="$isReorderable ? '' : null"
data-sortable-animation-duration="{{ $getReorderAnimationDuration() }}" @endif
class="fi-fo-tags-input-tags-ctn">
<template x-for="(tag, index) in state" x-bind:key="`${tag}-${index}`">
<x-filament::badge :color="$color"
:x-bind:x-sortable-item="$isReorderable ? 'index' : null" :x-sortable-handle="$isReorderable ? '' : null"
@class([
'fi-reorderable' => $isReorderable,
])
>
])>
{{ $getTagPrefix() }}
<span x-text="tag"></span>
{{ $getTagSuffix() }}
<x-slot
name="deleteButton"
x-on:click.stop="deleteTag(tag)"
:x-bind:aria-label="'\'' . __('filament-forms::components.tags_input.actions.delete.label') . ': \' + tag'"
></x-slot>
<x-slot name="deleteButton" x-on:click.stop="deleteTag(tag)"
:x-bind:aria-label="'\''.__('filament-forms::components.tags_input.actions.delete.label').
': \' + tag'"></x-slot>
</x-filament::badge>
</template>
</div>
@@ -42,68 +42,48 @@
$inputAttributes = $getExtraInputAttributeBag()
->merge($extraAlpineAttributes, escape: false)
->merge([
'autocapitalize' => $getAutocapitalize(),
'autocomplete' => $getAutocomplete(),
'autofocus' => $isAutofocused(),
'disabled' => $isDisabled,
'id' => $id,
'inlinePrefix' => $isPrefixInline && (count($prefixActions) || $prefixIcon || filled($prefixLabel)),
'inlineSuffix' => $isSuffixInline && (count($suffixActions) || $suffixIcon || filled($suffixLabel)),
'inputmode' => $getInputMode(),
'list' => $datalistOptions ? $id . '-list' : null,
'max' => (! $isConcealed) ? $getMaxValue() : null,
'maxlength' => (! $isConcealed) ? $getMaxLength() : null,
'min' => (! $isConcealed) ? $getMinValue() : null,
'minlength' => (! $isConcealed) ? $getMinLength() : null,
'placeholder' => filled($placeholder) ? e($placeholder) : null,
'readonly' => $isReadOnly(),
'required' => $isRequired() && (! $isConcealed),
'step' => $getStep(),
'type' => $type,
$applyStateBindingModifiers('wire:model') => $statePath,
'x-bind:type' => $isPasswordRevealable ? 'isPasswordRevealed ? \'text\' : \'password\'' : null,
'x-mask' . ($mask instanceof \Filament\Support\RawJs ? ':dynamic' : '') => filled($mask) ? $mask : null,
], escape: false)
->merge(
[
'autocapitalize' => $getAutocapitalize(),
'autocomplete' => $getAutocomplete(),
'autofocus' => $isAutofocused(),
'disabled' => $isDisabled,
'id' => $id,
'inlinePrefix' => $isPrefixInline && (count($prefixActions) || $prefixIcon || filled($prefixLabel)),
'inlineSuffix' => $isSuffixInline && (count($suffixActions) || $suffixIcon || filled($suffixLabel)),
'inputmode' => $getInputMode(),
'list' => $datalistOptions ? $id . '-list' : null,
'max' => !$isConcealed ? $getMaxValue() : null,
'maxlength' => !$isConcealed ? $getMaxLength() : null,
'min' => !$isConcealed ? $getMinValue() : null,
'minlength' => !$isConcealed ? $getMinLength() : null,
'placeholder' => filled($placeholder) ? e($placeholder) : null,
'readonly' => $isReadOnly(),
'required' => $isRequired() && !$isConcealed,
'step' => $getStep(),
'type' => $type,
$applyStateBindingModifiers('wire:model') => $statePath,
'x-bind:type' => $isPasswordRevealable ? 'isPasswordRevealed ? \'text\' : \'password\'' : null,
'x-mask' . ($mask instanceof \Filament\Support\RawJs ? ':dynamic' : '') => filled($mask) ? $mask : null,
],
escape: false,
)
->class([
'fi-revealable' => $isPasswordRevealable,
]);
@endphp
<x-dynamic-component
:component="$fieldWrapperView"
:field="$field"
:inline-label-vertical-alignment="\Filament\Support\Enums\VerticalAlignment::Center"
>
<x-filament::input.wrapper
:disabled="$isDisabled"
:inline-prefix="$isPrefixInline"
:inline-suffix="$isSuffixInline"
:prefix="$prefixLabel"
:prefix-actions="$prefixActions"
:prefix-icon="$prefixIcon"
:prefix-icon-color="$prefixIconColor"
:suffix="$suffixLabel"
:suffix-actions="$suffixActions"
:suffix-icon="$suffixIcon"
:suffix-icon-color="$suffixIconColor"
:valid="! $errors->has($statePath)"
:x-data="$xData"
x-on:focus-input.stop="$el.querySelector('input')?.focus()"
:attributes="
\Filament\Support\prepare_inherited_attributes($extraAttributeBag)
->class(['fi-fo-text-input'])
"
>
<x-dynamic-component :component="$fieldWrapperView" :field="$field" :inline-label-vertical-alignment="\Filament\Support\Enums\VerticalAlignment::Center">
<x-filament::input.wrapper :disabled="$isDisabled" :inline-prefix="$isPrefixInline" :inline-suffix="$isSuffixInline" :prefix="$prefixLabel" :prefix-actions="$prefixActions"
:prefix-icon="$prefixIcon" :prefix-icon-color="$prefixIconColor" :suffix="$suffixLabel" :suffix-actions="$suffixActions" :suffix-icon="$suffixIcon" :suffix-icon-color="$suffixIconColor"
:valid="!$errors->has($statePath)" :x-data="$xData" x-on:focus-input.stop="$el.querySelector('input')?.focus()"
:attributes="\Filament\Support\prepare_inherited_attributes($extraAttributeBag)->class(['fi-fo-text-input'])">
<input
{{
$inputAttributes->class([
'fi-input',
'fi-input-has-inline-prefix' => $isPrefixInline && (count($prefixActions) || $prefixIcon || filled($prefixLabel)),
'fi-input-has-inline-suffix' => $isSuffixInline && (count($suffixActions) || $suffixIcon || filled($suffixLabel)),
])
}}
/>
{{ $inputAttributes->class([
'fi-input',
'fi-input-has-inline-prefix' => $isPrefixInline && (count($prefixActions) || $prefixIcon || filled($prefixLabel)),
'fi-input-has-inline-suffix' => $isSuffixInline && (count($suffixActions) || $suffixIcon || filled($suffixLabel)),
]) }} />
</x-filament::input.wrapper>
@if ($datalistOptions)
@@ -9,63 +9,46 @@
$placeholder = $getPlaceholder();
$statePath = $getStatePath();
$initialHeight = (($rows ?? 2) * 1.5) + 0.75;
$initialHeight = ($rows ?? 2) * 1.5 + 0.75;
@endphp
<x-dynamic-component
:component="$fieldWrapperView"
:field="$field"
class="fi-fo-textarea-wrp"
>
<x-filament::input.wrapper
:disabled="$isDisabled"
:valid="! $errors->has($statePath)"
:attributes="
\Filament\Support\prepare_inherited_attributes($extraAttributeBag)
->class([
'fi-fo-textarea',
'fi-autosizable' => $shouldAutosize,
])
"
>
<x-dynamic-component :component="$fieldWrapperView" :field="$field" class="fi-fo-textarea-wrp">
<x-filament::input.wrapper :disabled="$isDisabled" :valid="!$errors->has($statePath)" :attributes="\Filament\Support\prepare_inherited_attributes($extraAttributeBag)->class([
'fi-fo-textarea',
'fi-autosizable' => $shouldAutosize,
])">
<div wire:ignore.self style="height: '{{ $initialHeight . 'rem' }}'">
<textarea
x-load
<textarea x-load
x-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('textarea', 'filament/forms') }}"
x-data="textareaFormComponent({
initialHeight: @js($initialHeight),
shouldAutosize: @js($shouldAutosize),
state: $wire.$entangle('{{ $statePath }}'),
})"
@if ($shouldAutosize)
x-intersect.once="resize()"
x-on:resize.window="resize()"
@endif
initialHeight: @js($initialHeight),
shouldAutosize: @js($shouldAutosize),
state: $wire.$entangle('{{ $statePath }}'),
})"
@if ($shouldAutosize) x-intersect.once="resize()"
x-on:resize.window="resize()" @endif
x-model="state"
@if ($isGrammarlyDisabled())
data-gramm="false"
@if ($isGrammarlyDisabled()) data-gramm="false"
data-gramm_editor="false"
data-enable-grammarly="false"
@endif
data-enable-grammarly="false" @endif
{{ $getExtraAlpineAttributeBag() }}
{{
$getExtraInputAttributeBag()
->merge([
'autocomplete' => $getAutocomplete(),
'autofocus' => $isAutofocused(),
'cols' => $getCols(),
'disabled' => $isDisabled,
'id' => $getId(),
'maxlength' => (! $isConcealed) ? $getMaxLength() : null,
'minlength' => (! $isConcealed) ? $getMinLength() : null,
'placeholder' => filled($placeholder) ? e($placeholder) : null,
'readonly' => $isReadOnly(),
'required' => $isRequired() && (! $isConcealed),
'rows' => $rows,
$applyStateBindingModifiers('wire:model') => $statePath,
], escape: false)
}}
></textarea>
{{ $getExtraInputAttributeBag()->merge(
[
'autocomplete' => $getAutocomplete(),
'autofocus' => $isAutofocused(),
'cols' => $getCols(),
'disabled' => $isDisabled,
'id' => $getId(),
'maxlength' => !$isConcealed ? $getMaxLength() : null,
'minlength' => !$isConcealed ? $getMinLength() : null,
'placeholder' => filled($placeholder) ? e($placeholder) : null,
'readonly' => $isReadOnly(),
'required' => $isRequired() && !$isConcealed,
'rows' => $rows,
$applyStateBindingModifiers('wire:model') => $statePath,
],
escape: false,
) }}></textarea>
</div>
</x-filament::input.wrapper>
</x-dynamic-component>
@@ -9,15 +9,8 @@
$extraInputAttributeBag = $getExtraInputAttributeBag()->class(['fi-fo-toggle-buttons-input']);
@endphp
<x-dynamic-component
:component="$fieldWrapperView"
:field="$field"
tabindex="-1"
class="fi-fo-toggle-buttons-wrp"
>
<div
{{ $getExtraAttributeBag()->class(['fi-fo-toggle-buttons fi-btn-group']) }}
>
<x-dynamic-component :component="$fieldWrapperView" :field="$field" tabindex="-1" class="fi-fo-toggle-buttons-wrp">
<div {{ $getExtraAttributeBag()->class(['fi-fo-toggle-buttons fi-btn-group']) }}>
@foreach ($getOptions() as $value => $label)
@php
$inputId = "{$id}-{$value}";
@@ -27,29 +20,13 @@
$tooltip = $getTooltip($value);
@endphp
<input
@disabled($shouldOptionBeDisabled)
id="{{ $inputId }}"
@if (! $isMultiple)
name="{{ $id }}"
@endif
type="{{ $isMultiple ? 'checkbox' : 'radio' }}"
value="{{ $value }}"
wire:loading.attr="disabled"
{{ $wireModelAttribute }}="{{ $statePath }}"
{{ $extraInputAttributeBag }}
/>
<input @disabled($shouldOptionBeDisabled) id="{{ $inputId }}"
@if (!$isMultiple) name="{{ $id }}" @endif
type="{{ $isMultiple ? 'checkbox' : 'radio' }}" value="{{ $value }}" wire:loading.attr="disabled"
{{ $wireModelAttribute }}="{{ $statePath }}" {{ $extraInputAttributeBag }} />
<x-filament::button
:color="$color"
:disabled="$shouldOptionBeDisabled"
:for="$inputId"
grouped
:icon="$icon"
:label-sr-only="$areButtonLabelsHidden"
tag="label"
:tooltip="$tooltip"
>
<x-filament::button :color="$color" :disabled="$shouldOptionBeDisabled" :for="$inputId" grouped :icon="$icon"
:label-sr-only="$areButtonLabelsHidden" tag="label" :tooltip="$tooltip">
{{ $label }}
</x-filament::button>
@endforeach
@@ -14,22 +14,9 @@
$extraInputAttributeBag = $getExtraInputAttributeBag()->class(['fi-fo-toggle-buttons-input']);
@endphp
<x-dynamic-component
:component="$fieldWrapperView"
:field="$field"
tabindex="-1"
class="fi-fo-toggle-buttons-wrp"
>
<x-dynamic-component :component="$fieldWrapperView" :field="$field" tabindex="-1" class="fi-fo-toggle-buttons-wrp">
<div
{{
$getExtraAttributeBag()
->when(! $isInline, fn (ComponentAttributeBag $attributes) => $attributes->grid($getColumns(), $gridDirection))
->class([
'fi-fo-toggle-buttons',
'fi-inline' => $isInline,
])
}}
>
{{ $getExtraAttributeBag()->when(!$isInline, fn(ComponentAttributeBag $attributes) => $attributes->grid($getColumns(), $gridDirection))->class(['fi-fo-toggle-buttons', 'fi-inline' => $isInline]) }}>
@foreach ($getOptions() as $value => $label)
@php
$inputId = "{$id}-{$value}";
@@ -40,28 +27,13 @@
@endphp
<div class="fi-fo-toggle-buttons-btn-ctn">
<input
@if ($loop->first && $isAutofocused()) autofocus @endif
@disabled($shouldOptionBeDisabled)
id="{{ $inputId }}"
@if (! $isMultiple)
name="{{ $id }}"
@endif
type="{{ $isMultiple ? 'checkbox' : 'radio' }}"
value="{{ $value }}"
{{ $wireModelAttribute }}="{{ $statePath }}"
{{ $extraInputAttributeBag }}
/>
<input @if ($loop->first && $isAutofocused()) autofocus @endif @disabled($shouldOptionBeDisabled)
id="{{ $inputId }}" @if (!$isMultiple) name="{{ $id }}" @endif
type="{{ $isMultiple ? 'checkbox' : 'radio' }}" value="{{ $value }}"
{{ $wireModelAttribute }}="{{ $statePath }}" {{ $extraInputAttributeBag }} />
<x-filament::button
:color="$color"
:disabled="$shouldOptionBeDisabled"
:for="$inputId"
:icon="$icon"
:label-sr-only="$areButtonLabelsHidden"
tag="label"
:tooltip="$tooltip"
>
<x-filament::button :color="$color" :disabled="$shouldOptionBeDisabled" :for="$inputId" :icon="$icon"
:label-sr-only="$areButtonLabelsHidden" tag="label" :tooltip="$tooltip">
{{ $label }}
</x-filament::button>
</div>
@@ -4,39 +4,34 @@
$fieldWrapperView = $getFieldWrapperView();
$statePath = $getStatePath();
$attributes = (new ComponentAttributeBag)
->merge([
'aria-checked' => 'false',
'autofocus' => $isAutofocused(),
'disabled' => $isDisabled(),
'id' => $getId(),
'offColor' => $getOffColor() ?? 'gray',
'offIcon' => $getOffIcon(),
'onColor' => $getOnColor() ?? 'primary',
'onIcon' => $getOnIcon(),
'state' => '$wire.' . $applyStateBindingModifiers('$entangle(\'' . $statePath . '\')'),
'wire:loading.attr' => 'disabled',
'wire:target' => $statePath,
], escape: false)
$attributes = new ComponentAttributeBag()
->merge(
[
'aria-checked' => 'false',
'autofocus' => $isAutofocused(),
'disabled' => $isDisabled(),
'id' => $getId(),
'offColor' => $getOffColor() ?? 'gray',
'offIcon' => $getOffIcon(),
'onColor' => $getOnColor() ?? 'primary',
'onIcon' => $getOnIcon(),
'state' => '$wire.' . $applyStateBindingModifiers('$entangle(\'' . $statePath . '\')'),
'wire:loading.attr' => 'disabled',
'wire:target' => $statePath,
],
escape: false,
)
->merge($getExtraAttributes(), escape: false)
->merge($getExtraAlpineAttributes(), escape: false)
->class(['fi-fo-toggle']);
@endphp
<x-dynamic-component
:component="$fieldWrapperView"
:field="$field"
:inline-label-vertical-alignment="\Filament\Support\Enums\VerticalAlignment::Center"
>
<x-dynamic-component :component="$fieldWrapperView" :field="$field" :inline-label-vertical-alignment="\Filament\Support\Enums\VerticalAlignment::Center">
@if ($isInline())
<x-slot name="labelPrefix">
<x-filament::toggle
:attributes="\Filament\Support\prepare_inherited_attributes($attributes)"
/>
<x-filament::toggle :attributes="\Filament\Support\prepare_inherited_attributes($attributes)" />
</x-slot>
@else
<x-filament::toggle
:attributes="\Filament\Support\prepare_inherited_attributes($attributes)"
/>
<x-filament::toggle :attributes="\Filament\Support\prepare_inherited_attributes($attributes)" />
@endif
</x-dynamic-component>
@@ -20,8 +20,8 @@
$shouldOpenUrlInNewTab ??= $entry->shouldOpenUrlInNewTab();
}
if (! $alignment instanceof Alignment) {
$alignment = filled($alignment) ? (Alignment::tryFrom($alignment) ?? $alignment) : null;
if (!$alignment instanceof Alignment) {
$alignment = filled($alignment) ? Alignment::tryFrom($alignment) ?? $alignment : null;
}
$beforeLabelContainer = $entry?->getChildSchema($entry::BEFORE_LABEL_SCHEMA_KEY)?->toHtmlString();
@@ -31,15 +31,7 @@
@endphp
<div
{{
$attributes
->merge($entry?->getExtraEntryWrapperAttributes() ?? [], escape: false)
->class([
'fi-in-entry',
'fi-in-entry-has-inline-label' => $hasInlineLabel,
])
}}
>
{{ $attributes->merge($entry?->getExtraEntryWrapperAttributes() ?? [], escape: false)->class(['fi-in-entry', 'fi-in-entry-has-inline-label' => $hasInlineLabel]) }}>
@if ($label && $labelSrOnly)
<div class="fi-in-entry-label fi-sr-only" role="term">
{{ $label }}
@@ -49,27 +41,20 @@
<div class="fi-in-entry-label-col">
{{ $entry?->getChildSchema($entry::ABOVE_LABEL_SCHEMA_KEY) }}
@if (($label && (! $labelSrOnly)) || $beforeLabelContainer || $afterLabelContainer)
<div
@class([
'fi-in-entry-label-ctn',
($label instanceof \Illuminate\View\ComponentSlot) ? $label->attributes->get('class') : null,
])
>
@if (($label && !$labelSrOnly) || $beforeLabelContainer || $afterLabelContainer)
<div @class([
'fi-in-entry-label-ctn',
$label instanceof \Illuminate\View\ComponentSlot
? $label->attributes->get('class')
: null,
])>
{{ $beforeLabelContainer }}
@if ($label && (! $labelSrOnly))
<div
{{
(
($label instanceof \Illuminate\View\ComponentSlot)
? $label->attributes
: (new ComponentAttributeBag)
)
->class(['fi-in-entry-label'])
}}
role="term"
>
@if ($label && !$labelSrOnly)
<div {{ ($label instanceof \Illuminate\View\ComponentSlot ? $label->attributes : new ComponentAttributeBag())->class(
['fi-in-entry-label'],
) }}
role="term">
{{ $label }}
</div>
@endif
@@ -88,13 +73,15 @@
{{ $beforeContentContainer }}
@if (filled($url))
<a
{{ \Filament\Support\generate_href_html($url, $shouldOpenUrlInNewTab) }}
<a {{ \Filament\Support\generate_href_html($url, $shouldOpenUrlInNewTab) }}
@class([
'fi-in-entry-content',
(($alignment instanceof Alignment) ? "fi-align-{$alignment->value}" : (is_string($alignment) ? $alignment : '')),
])
>
$alignment instanceof Alignment
? "fi-align-{$alignment->value}"
: (is_string($alignment)
? $alignment
: ''),
])>
{{ $slot }}
</a>
@elseif (filled($action))
@@ -102,25 +89,26 @@
$wireClickAction = $action->getLivewireClickHandler();
@endphp
<button
type="button"
wire:click="{{ $wireClickAction }}"
wire:loading.attr="disabled"
wire:target="{{ $wireClickAction }}"
@class([
<button type="button" wire:click="{{ $wireClickAction }}" wire:loading.attr="disabled"
wire:target="{{ $wireClickAction }}" @class([
'fi-in-entry-content',
(($alignment instanceof Alignment) ? "fi-align-{$alignment->value}" : (is_string($alignment) ? $alignment : '')),
])
>
$alignment instanceof Alignment
? "fi-align-{$alignment->value}"
: (is_string($alignment)
? $alignment
: ''),
])>
{{ $slot }}
</button>
@else
<div
@class([
'fi-in-entry-content',
(($alignment instanceof Alignment) ? "fi-align-{$alignment->value}" : (is_string($alignment) ? $alignment : '')),
])
>
<div @class([
'fi-in-entry-content',
$alignment instanceof Alignment
? "fi-align-{$alignment->value}"
: (is_string($alignment)
? $alignment
: ''),
])>
{{ $slot }}
</div>
@endif
@@ -11,30 +11,13 @@
@endphp
<div class="fi-no-database">
<x-filament::modal
:alignment="$hasNotifications ? null : Alignment::Center"
close-button
:description="$hasNotifications ? null : __('filament-notifications::database.modal.empty.description')"
:heading="$hasNotifications ? null : __('filament-notifications::database.modal.empty.heading')"
:icon="$hasNotifications ? null : \Filament\Support\Icons\Heroicon::OutlinedBellSlash"
:icon-alias="
$hasNotifications
<x-filament::modal :alignment="$hasNotifications ? null : Alignment::Center" close-button :description="$hasNotifications ? null : __('filament-notifications::database.modal.empty.description')" :heading="$hasNotifications ? null : __('filament-notifications::database.modal.empty.heading')" :icon="$hasNotifications ? null : \Filament\Support\Icons\Heroicon::OutlinedBellSlash"
:icon-alias="$hasNotifications
? null
: \Filament\Notifications\View\NotificationsIconAlias::DATABASE_MODAL_EMPTY_STATE
"
:icon-color="$hasNotifications ? null : 'gray'"
id="database-notifications"
slide-over
:sticky-header="$hasNotifications"
teleport="body"
width="md"
class="fi-no-database"
:attributes="
new \Illuminate\View\ComponentAttributeBag([
'wire:poll.' . $pollingInterval => $pollingInterval ? '' : false,
])
"
>
: \Filament\Notifications\View\NotificationsIconAlias::DATABASE_MODAL_EMPTY_STATE" :icon-color="$hasNotifications ? null : 'gray'" id="database-notifications" slide-over :sticky-header="$hasNotifications" teleport="body"
width="md" class="fi-no-database" :attributes="new \Illuminate\View\ComponentAttributeBag([
'wire:poll.' . $pollingInterval => $pollingInterval ? '' : false,
])">
@if ($trigger = $this->getTrigger())
<x-slot name="trigger">
{{ $trigger->with(['unreadNotificationsCount' => $unreadNotificationsCount]) }}
@@ -49,12 +32,7 @@
@if ($unreadNotificationsCount)
<span
{{
(new ComponentAttributeBag)->color(BadgeComponent::class, 'primary')->class([
'fi-badge fi-size-xs',
])
}}
>
{{ new ComponentAttributeBag()->color(BadgeComponent::class, 'primary')->class(['fi-badge fi-size-xs']) }}>
{{ $unreadNotificationsCount }}
</span>
@endif
@@ -73,12 +51,10 @@
</x-slot>
@foreach ($notifications as $notification)
<div
@class([
'fi-no-notification-read-ctn' => ! $notification->unread(),
'fi-no-notification-unread-ctn' => $notification->unread(),
])
>
<div @class([
'fi-no-notification-read-ctn' => !$notification->unread(),
'fi-no-notification-unread-ctn' => $notification->unread(),
])>
{{ $this->getNotification($notification)->inline() }}
</div>
@endforeach
@@ -4,14 +4,11 @@
@endphp
<div>
<div
@class([
'fi-no',
'fi-align-' . static::$alignment->value,
'fi-vertical-align-' . static::$verticalAlignment->value,
])
role="status"
>
<div @class([
'fi-no',
'fi-align-' . static::$alignment->value,
'fi-vertical-align-' . static::$verticalAlignment->value,
]) role="status">
@foreach ($notifications as $notification)
{{ $notification }}
@endforeach
@@ -25,9 +22,9 @@
(notification) => {
setTimeout(
() =>
$wire.handleBroadcastNotification(
notification,
),
$wire.handleBroadcastNotification(
notification,
),
500,
)
},
@@ -7,12 +7,4 @@
$alt = __('filament-panels::layout.avatar.alt', ['name' => filament()->getTenantName($tenant)]);
@endphp
<x-filament::avatar
:circular="false"
:src="$src"
:alt="$alt"
:attributes="
\Filament\Support\prepare_inherited_attributes($attributes)
->class(['fi-tenant-avatar'])
"
/>
<x-filament::avatar :circular="false" :src="$src" :alt="$alt" :attributes="\Filament\Support\prepare_inherited_attributes($attributes)->class(['fi-tenant-avatar'])" />
@@ -7,11 +7,4 @@
$alt = __('filament-panels::layout.avatar.alt', ['name' => filament()->getUserName($user)]);
@endphp
<x-filament::avatar
:src="$src"
:alt="$alt"
:attributes="
\Filament\Support\prepare_inherited_attributes($attributes)
->class(['fi-user-avatar'])
"
/>
<x-filament::avatar :src="$src" :alt="$alt" :attributes="\Filament\Support\prepare_inherited_attributes($attributes)->class(['fi-user-avatar'])" />
@@ -6,14 +6,7 @@
'subheading' => null,
])
<header
{{
$attributes->class([
'fi-header',
'fi-header-has-breadcrumbs' => $breadcrumbs,
])
}}
>
<header {{ $attributes->class(['fi-header', 'fi-header-has-breadcrumbs' => $breadcrumbs]) }}>
<div>
@if ($breadcrumbs)
<x-filament::breadcrumbs :breadcrumbs="$breadcrumbs" />
@@ -37,8 +30,14 @@
</div>
@php
$beforeActions = \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::PAGE_HEADER_ACTIONS_BEFORE, scopes: $this->getRenderHookScopes());
$afterActions = \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::PAGE_HEADER_ACTIONS_AFTER, scopes: $this->getRenderHookScopes());
$beforeActions = \Filament\Support\Facades\FilamentView::renderHook(
\Filament\View\PanelsRenderHook::PAGE_HEADER_ACTIONS_BEFORE,
scopes: $this->getRenderHookScopes(),
);
$afterActions = \Filament\Support\Facades\FilamentView::renderHook(
\Filament\View\PanelsRenderHook::PAGE_HEADER_ACTIONS_AFTER,
scopes: $this->getRenderHookScopes(),
);
@endphp
@if (filled($beforeActions) || $actions || filled($afterActions))
@@ -46,10 +45,7 @@
{{ $beforeActions }}
@if ($actions)
<x-filament::actions
:actions="$actions"
:alignment="$actionsAlignment"
/>
<x-filament::actions :actions="$actions" :alignment="$actionsAlignment" />
@endif
{{ $afterActions }}
@@ -9,23 +9,20 @@
$hasTopNavigation = filament()->hasTopNavigation();
$hasNavigation = filament()->hasNavigation();
$renderHookScopes = $livewire?->getRenderHookScopes();
$maxContentWidth ??= (filament()->getMaxContentWidth() ?? Width::SevenExtraLarge);
$maxContentWidth ??= filament()->getMaxContentWidth() ?? Width::SevenExtraLarge;
if (is_string($maxContentWidth)) {
$maxContentWidth = Width::tryFrom($maxContentWidth) ?? $maxContentWidth;
}
@endphp
<x-filament-panels::layout.base
:livewire="$livewire"
@class([
'fi-body-has-navigation' => $hasNavigation,
'fi-body-has-sidebar-collapsible-on-desktop' => $isSidebarCollapsibleOnDesktop,
'fi-body-has-sidebar-fully-collapsible-on-desktop' => $isSidebarFullyCollapsibleOnDesktop,
'fi-body-has-topbar' => $hasTopbar,
'fi-body-has-top-navigation' => $hasTopNavigation,
])
>
<x-filament-panels::layout.base :livewire="$livewire" @class([
'fi-body-has-navigation' => $hasNavigation,
'fi-body-has-sidebar-collapsible-on-desktop' => $isSidebarCollapsibleOnDesktop,
'fi-body-has-sidebar-fully-collapsible-on-desktop' => $isSidebarFullyCollapsibleOnDesktop,
'fi-body-has-topbar' => $hasTopbar,
'fi-body-has-top-navigation' => $hasTopNavigation,
])>
@if ($hasTopbar)
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::TOPBAR_BEFORE, scopes: $renderHookScopes) }}
@@ -33,27 +30,14 @@
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::TOPBAR_AFTER, scopes: $renderHookScopes) }}
@elseif ($hasNavigation)
<div
@if ($isSidebarFullyCollapsibleOnDesktop)
x-data="{}"
x-bind:class="{ 'lg:fi-hidden': $store.sidebar.isOpen }"
@endif
<div @if ($isSidebarFullyCollapsibleOnDesktop) x-data="{}"
x-bind:class="{ 'lg:fi-hidden': $store.sidebar.isOpen }" @endif
@class([
'fi-layout-sidebar-toggle-btn-ctn',
'lg:fi-hidden' => ! $isSidebarFullyCollapsibleOnDesktop,
])
>
<x-filament::icon-button
color="gray"
:icon="\Filament\Support\Icons\Heroicon::OutlinedBars3"
:icon-alias="\Filament\View\PanelsIconAlias::SIDEBAR_EXPAND_BUTTON"
icon-size="lg"
:label="__('filament-panels::layout.actions.sidebar.expand.label')"
x-cloak
x-data="{}"
x-on:click="$store.sidebar.open()"
class="fi-layout-sidebar-toggle-btn"
/>
'lg:fi-hidden' => !$isSidebarFullyCollapsibleOnDesktop,
])>
<x-filament::icon-button color="gray" :icon="\Filament\Support\Icons\Heroicon::OutlinedBars3" :icon-alias="\Filament\View\PanelsIconAlias::SIDEBAR_EXPAND_BUTTON" icon-size="lg" :label="__('filament-panels::layout.actions.sidebar.expand.label')"
x-cloak x-data="{}" x-on:click="$store.sidebar.open()" class="fi-layout-sidebar-toggle-btn" />
</div>
@endif
@@ -61,21 +45,13 @@
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::LAYOUT_START, scopes: $renderHookScopes) }}
@if ($hasNavigation)
<div
x-cloak
x-data="{}"
x-on:click="$store.sidebar.close()"
x-show="$store.sidebar.isOpen"
x-transition.opacity.300ms
class="fi-sidebar-close-overlay"
></div>
<div x-cloak x-data="{}" x-on:click="$store.sidebar.close()" x-show="$store.sidebar.isOpen"
x-transition.opacity.300ms class="fi-sidebar-close-overlay"></div>
@livewire(filament()->getSidebarLivewireComponent())
@endif
<div
@if ($isSidebarCollapsibleOnDesktop)
x-data="{}"
<div @if ($isSidebarCollapsibleOnDesktop) x-data="{}"
x-bind:class="{
'fi-main-ctn-sidebar-open': $store.sidebar.isOpen,
}"
@@ -88,20 +64,18 @@
}"
x-bind:style="'display: flex; opacity:1;'"
{{-- Mimics `x-cloak`, as using `x-cloak` causes visual issues with chart widgets --}}
@elseif (! ($isSidebarCollapsibleOnDesktop || $isSidebarFullyCollapsibleOnDesktop || $hasTopNavigation || (! $hasNavigation)))
@elseif (!($isSidebarCollapsibleOnDesktop || $isSidebarFullyCollapsibleOnDesktop || $hasTopNavigation || !$hasNavigation))
x-data="{}"
x-bind:style="'display: flex; opacity:1;'" {{-- Mimics `x-cloak`, as using `x-cloak` causes visual issues with chart widgets --}}
@endif
class="fi-main-ctn"
>
x-bind:style="'display: flex; opacity:1;'" {{-- Mimics `x-cloak`, as using `x-cloak` causes visual issues with chart widgets --}} @endif
class="fi-main-ctn">
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::CONTENT_BEFORE, scopes: $renderHookScopes) }}
<main
@class([
'fi-main',
($maxContentWidth instanceof Width) ? "fi-width-{$maxContentWidth->value}" : $maxContentWidth,
])
>
<main @class([
'fi-main',
$maxContentWidth instanceof Width
? "fi-width-{$maxContentWidth->value}"
: $maxContentWidth,
])>
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::CONTENT_START, scopes: $renderHookScopes) }}
{{ $slot }}
@@ -4,7 +4,7 @@
$livewire ??= null;
$renderHookScopes = $livewire?->getRenderHookScopes();
$maxContentWidth ??= (filament()->getSimplePageMaxContentWidth() ?? Width::Large);
$maxContentWidth ??= filament()->getSimplePageMaxContentWidth() ?? Width::Large;
if (is_string($maxContentWidth)) {
$maxContentWidth = Width::tryFrom($maxContentWidth) ?? $maxContentWidth;
@@ -37,12 +37,12 @@
@endif
<div class="fi-simple-main-ctn">
<main
@class([
'fi-simple-main',
($maxContentWidth instanceof Width) ? "fi-width-{$maxContentWidth->value}" : $maxContentWidth,
])
>
<main @class([
'fi-simple-main',
$maxContentWidth instanceof Width
? "fi-width-{$maxContentWidth->value}"
: $maxContentWidth,
])>
{{ $slot }}
</main>
</div>
@@ -5,9 +5,9 @@
$darkModeBrandLogo = filament()->getDarkModeBrandLogo();
$hasDarkModeBrandLogo = filled($darkModeBrandLogo);
$getLogoClasses = fn (bool $isDarkMode): string => \Illuminate\Support\Arr::toCssClasses([
$getLogoClasses = fn(bool $isDarkMode): string => \Illuminate\Support\Arr::toCssClasses([
'fi-logo',
'fi-logo-light' => $hasDarkModeBrandLogo && (! $isDarkMode),
'fi-logo-light' => $hasDarkModeBrandLogo && !$isDarkMode,
'fi-logo-dark' => $isDarkMode,
]);
@@ -16,33 +16,14 @@
@capture($content, $logo, $isDarkMode = false)
@if ($logo instanceof \Illuminate\Contracts\Support\Htmlable)
<div
{{
$attributes
->class([$getLogoClasses($isDarkMode)])
->style([$logoStyles])
}}
>
<div {{ $attributes->class([$getLogoClasses($isDarkMode)])->style([$logoStyles]) }}>
{{ $logo }}
</div>
@elseif (filled($logo))
<img
alt="{{ __('filament-panels::layout.logo.alt', ['name' => $brandName]) }}"
src="{{ $logo }}"
{{
$attributes
->class([$getLogoClasses($isDarkMode)])
->style([$logoStyles])
}}
/>
<img alt="{{ __('filament-panels::layout.logo.alt', ['name' => $brandName]) }}" src="{{ $logo }}"
{{ $attributes->class([$getLogoClasses($isDarkMode)])->style([$logoStyles]) }} />
@else
<div
{{
$attributes->class([
$getLogoClasses($isDarkMode),
])
}}
>
<div {{ $attributes->class([$getLogoClasses($isDarkMode)]) }}>
{{ $brandName }}
</div>
@endif
@@ -11,33 +11,24 @@
@endphp
<div
{{
$attributes->class([
'fi-page',
'fi-height-full' => $fullHeight,
'fi-page-has-sub-navigation' => $subNavigation,
"fi-page-has-sub-navigation-{$subNavigationPosition->value}" => $subNavigation,
...$this->getPageClasses(),
])
}}
>
{{ $attributes->class([
'fi-page',
'fi-height-full' => $fullHeight,
'fi-page-has-sub-navigation' => $subNavigation,
"fi-page-has-sub-navigation-{$subNavigationPosition->value}" => $subNavigation,
...$this->getPageClasses(),
]) }}>
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::PAGE_START, scopes: $this->getRenderHookScopes()) }}
<div class="fi-page-header-main-ctn">
@if ($subNavigation)
<div
class="fi-page-main-sub-navigation-mobile-menu-render-hook-ctn"
>
<div class="fi-page-main-sub-navigation-mobile-menu-render-hook-ctn">
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::PAGE_SUB_NAVIGATION_MOBILE_MENU_BEFORE, scopes: $this->getRenderHookScopes()) }}
</div>
<x-filament-panels::page.sub-navigation.mobile-menu
:navigation="$subNavigation"
/>
<x-filament-panels::page.sub-navigation.mobile-menu :navigation="$subNavigation" />
<div
class="fi-page-main-sub-navigation-mobile-menu-render-hook-ctn"
>
<div class="fi-page-main-sub-navigation-mobile-menu-render-hook-ctn">
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::PAGE_SUB_NAVIGATION_MOBILE_MENU_AFTER, scopes: $this->getRenderHookScopes()) }}
</div>
@endif
@@ -54,13 +45,8 @@
@endphp
@if (filled($headerActions) || $breadcrumbs || filled($heading) || filled($subheading))
<x-filament-panels::header
:actions="$headerActions"
:actions-alignment="$headerActionsAlignment"
:breadcrumbs="$breadcrumbs"
:heading="$heading"
:subheading="$subheading"
>
<x-filament-panels::header :actions="$headerActions" :actions-alignment="$headerActionsAlignment" :breadcrumbs="$breadcrumbs" :heading="$heading"
:subheading="$subheading">
@if ($heading instanceof \Illuminate\Contracts\Support\Htmlable)
<x-slot name="heading">
{{ $heading }}
@@ -81,9 +67,7 @@
@if ($subNavigationPosition === SubNavigationPosition::Start)
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::PAGE_SUB_NAVIGATION_START_BEFORE, scopes: $this->getRenderHookScopes()) }}
<x-filament-panels::page.sub-navigation.sidebar
:navigation="$subNavigation"
/>
<x-filament-panels::page.sub-navigation.sidebar :navigation="$subNavigation" />
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::PAGE_SUB_NAVIGATION_START_AFTER, scopes: $this->getRenderHookScopes()) }}
@endif
@@ -91,9 +75,7 @@
@if ($subNavigationPosition === SubNavigationPosition::Top)
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::PAGE_SUB_NAVIGATION_TOP_BEFORE, scopes: $this->getRenderHookScopes()) }}
<x-filament-panels::page.sub-navigation.tabs
:navigation="$subNavigation"
/>
<x-filament-panels::page.sub-navigation.tabs :navigation="$subNavigation" />
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::PAGE_SUB_NAVIGATION_TOP_AFTER, scopes: $this->getRenderHookScopes()) }}
@endif
@@ -118,9 +100,7 @@
@if ($subNavigation && $subNavigationPosition === SubNavigationPosition::End)
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::PAGE_SUB_NAVIGATION_END_BEFORE, scopes: $this->getRenderHookScopes()) }}
<x-filament-panels::page.sub-navigation.sidebar
:navigation="$subNavigation"
/>
<x-filament-panels::page.sub-navigation.sidebar :navigation="$subNavigation" />
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::PAGE_SUB_NAVIGATION_END_AFTER, scopes: $this->getRenderHookScopes()) }}
@endif
@@ -131,18 +111,18 @@
@endif
</div>
@if (! ($this instanceof \Filament\Tables\Contracts\HasTable))
@if (!($this instanceof \Filament\Tables\Contracts\HasTable))
<x-filament-actions::modals />
@elseif ($this->isTableLoaded() && filled($this->defaultTableAction))
<div
wire:init="mountAction(@js($this->defaultTableAction) , @if (filled($this->defaultTableActionArguments)) @js($this->defaultTableActionArguments) @else {} @endif , @js(['table' => true, 'recordKey' => $this->defaultTableActionRecord]))"
></div>
wire:init="mountAction(@js($this->defaultTableAction) , @if (filled($this->defaultTableActionArguments)) @js($this->defaultTableActionArguments) @else {} @endif , @js(['table' => true, 'recordKey' => $this->defaultTableActionRecord]))">
</div>
@endif
@if (filled($this->defaultAction))
<div
wire:init="mountAction(@js($this->defaultAction) @if (filled($this->defaultActionArguments) || filled($this->defaultActionContext)) , @if (filled($this->defaultActionArguments)) @js($this->defaultActionArguments) @else {} @endif @endif @if (filled($this->defaultActionContext)) , @js($this->defaultActionContext) @endif)"
></div>
wire:init="mountAction(@js($this->defaultAction) @if (filled($this->defaultActionArguments) || filled($this->defaultActionContext)) , @if (filled($this->defaultActionArguments)) @js($this->defaultActionArguments) @else {} @endif @endif @if (filled($this->defaultActionContext)) , @js($this->defaultActionContext) @endif)">
</div>
@endif
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::PAGE_END, scopes: $this->getRenderHookScopes()) }}
@@ -161,13 +141,15 @@
@else
@script
<script>
setUpUnsavedDataChangesAlert({ $wire })
setUpUnsavedDataChangesAlert({
$wire
})
</script>
@endscript
@endif
@endif
@if (! app()->hasDebugModeEnabled())
@if (!app()->hasDebugModeEnabled())
@script
<script>
window.filamentErrorNotifications = @js($this->hasErrorNotifications() ? $this->getErrorNotifications() : null)
@@ -14,17 +14,13 @@
<div class="fi-simple-page-content">
@if (filled($heading) || $hasLogo || filled($subheading))
<x-filament-panels::header.simple
:heading="$heading"
:logo="$hasLogo"
:subheading="$subheading"
/>
<x-filament-panels::header.simple :heading="$heading" :logo="$hasLogo" :subheading="$subheading" />
@endif
{{ $slot }}
</div>
@if (! $this instanceof \Filament\Tables\Contracts\HasTable)
@if (!$this instanceof \Filament\Tables\Contracts\HasTable)
<x-filament-actions::modals />
@endif
@@ -1,15 +1,6 @@
@props([
'navigation',
])
@props(['navigation'])
<x-filament::dropdown
placement="bottom-start"
width="xs"
:attributes="
\Filament\Support\prepare_inherited_attributes($attributes)
->class(['fi-page-sub-navigation-dropdown'])
"
>
<x-filament::dropdown placement="bottom-start" width="xs" :attributes="\Filament\Support\prepare_inherited_attributes($attributes)->class(['fi-page-sub-navigation-dropdown'])">
<x-slot name="trigger">
@php
$activeItem = null;
@@ -27,12 +18,7 @@
}
@endphp
<x-filament::button
color="gray"
:icon="\Filament\Support\Icons\Heroicon::ChevronDown"
:icon-alias="\Filament\View\PanelsIconAlias::SUB_NAVIGATION_MOBILE_MENU_BUTTON"
icon-position="after"
>
<x-filament::button color="gray" :icon="\Filament\Support\Icons\Heroicon::ChevronDown" :icon-alias="\Filament\View\PanelsIconAlias::SUB_NAVIGATION_MOBILE_MENU_BUTTON" icon-position="after">
{{ $activeItem?->getLabel() }}
</x-filament::button>
</x-slot>
@@ -50,21 +36,16 @@
@php
$navigationItemBadge = $navigationItem->getBadge();
$navigationItemBadgeColor = $navigationItem->getBadgeColor($navigationItemBadge);
$navigationItemIcon = $navigationItem->isActive() ? ($navigationItem->getActiveIcon() ?? $navigationItem->getIcon()) : $navigationItem->getIcon();
$navigationItemIcon = $navigationItem->isActive()
? $navigationItem->getActiveIcon() ?? $navigationItem->getIcon()
: $navigationItem->getIcon();
$navigationItemUrl = $navigationItem->getUrl();
$shouldNavigationItemOpenUrlInNewTab = $navigationItem->shouldOpenUrlInNewTab();
$navigationItemExtraAttributes = $navigationItemChild->getExtraAttributeBag();
@endphp
<x-filament::dropdown.list.item
:badge="$navigationItemBadge"
:badge-color="$navigationItemBadgeColor"
:href="$navigationItemUrl"
:icon="$navigationItemIcon"
tag="a"
:target="$shouldNavigationItemOpenUrlInNewTab ? '_blank' : null"
:attributes="\Filament\Support\prepare_inherited_attributes($navigationItemExtraAttributes)"
>
<x-filament::dropdown.list.item :badge="$navigationItemBadge" :badge-color="$navigationItemBadgeColor" :href="$navigationItemUrl"
:icon="$navigationItemIcon" tag="a" :target="$shouldNavigationItemOpenUrlInNewTab ? '_blank' : null" :attributes="\Filament\Support\prepare_inherited_attributes($navigationItemExtraAttributes)">
{{ $navigationItemChild->getLabel() }}
</x-filament::dropdown.list.item>
@endforeach
@@ -1,10 +1,6 @@
@props([
'navigation',
])
@props(['navigation'])
<div
{{ $attributes->class(['fi-page-sub-navigation-sidebar-ctn']) }}
>
<div {{ $attributes->class(['fi-page-sub-navigation-sidebar-ctn']) }}>
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::PAGE_SUB_NAVIGATION_SIDEBAR_BEFORE, scopes: $this->getRenderHookScopes()) }}
<ul class="fi-page-sub-navigation-sidebar">
@@ -18,16 +14,8 @@
$navigationGroupExtraSidebarAttributeBag = $navigationGroup->getExtraSidebarAttributeBag();
@endphp
<x-filament-panels::sidebar.group
:active="$isNavigationGroupActive"
:collapsible="$isNavigationGroupCollapsible"
:icon="$navigationGroupIcon"
:items="$navigationGroupItems"
:label="$navigationGroupLabel"
:sidebar-collapsible="false"
sub-navigation
:attributes="\Filament\Support\prepare_inherited_attributes($navigationGroupExtraSidebarAttributeBag)"
/>
<x-filament-panels::sidebar.group :active="$isNavigationGroupActive" :collapsible="$isNavigationGroupCollapsible" :icon="$navigationGroupIcon" :items="$navigationGroupItems"
:label="$navigationGroupLabel" :sidebar-collapsible="false" sub-navigation :attributes="\Filament\Support\prepare_inherited_attributes($navigationGroupExtraSidebarAttributeBag)" />
@endforeach
</ul>
@@ -1,10 +1,6 @@
@props([
'navigation',
])
@props(['navigation'])
<x-filament::tabs
:attributes="\Filament\Support\prepare_inherited_attributes($attributes)->class(['fi-page-sub-navigation-tabs'])"
>
<x-filament::tabs :attributes="\Filament\Support\prepare_inherited_attributes($attributes)->class(['fi-page-sub-navigation-tabs'])">
@foreach ($navigation as $navigationGroup)
@php
$navigationGroupLabel = $navigationGroup->getLabel();
@@ -15,10 +11,7 @@
@if ($navigationGroupLabel)
<x-filament::dropdown placement="bottom-start">
<x-slot name="trigger">
<x-filament::tabs.item
:active="$isNavigationGroupActive"
:icon="$navigationGroupIcon"
>
<x-filament::tabs.item :active="$isNavigationGroupActive" :icon="$navigationGroupIcon">
{{ $navigationGroupLabel }}
</x-filament::tabs.item>
</x-slot>
@@ -29,22 +22,16 @@
$navigationItemBadge = $navigationItem->getBadge();
$navigationItemBadgeColor = $navigationItem->getBadgeColor($navigationItemBadge);
$navigationItemBadgeTooltip = $navigationItem->getBadgeTooltip($navigationItemBadge);
$navigationItemIcon = $navigationItem->isActive() ? ($navigationItem->getActiveIcon() ?? $navigationItem->getIcon()) : $navigationItem->getIcon();
$navigationItemIcon = $navigationItem->isActive()
? $navigationItem->getActiveIcon() ?? $navigationItem->getIcon()
: $navigationItem->getIcon();
$navigationItemUrl = $navigationItem->getUrl();
$shouldNavigationItemOpenUrlInNewTab = $navigationItem->shouldOpenUrlInNewTab();
$navigationItemExtraAttributes = $navigationItem->getExtraAttributeBag();
@endphp
<x-filament::dropdown.list.item
:badge="$navigationItemBadge"
:badge-color="$navigationItemBadgeColor"
:badge-tooltip="$navigationItemBadgeTooltip"
:href="$navigationItemUrl"
:icon="$navigationItemIcon"
tag="a"
:target="$shouldNavigationItemOpenUrlInNewTab ? '_blank' : null"
:attributes="\Filament\Support\prepare_inherited_attributes($navigationItemExtraAttributes)"
>
<x-filament::dropdown.list.item :badge="$navigationItemBadge" :badge-color="$navigationItemBadgeColor" :badge-tooltip="$navigationItemBadgeTooltip"
:href="$navigationItemUrl" :icon="$navigationItemIcon" tag="a" :target="$shouldNavigationItemOpenUrlInNewTab ? '_blank' : null" :attributes="\Filament\Support\prepare_inherited_attributes($navigationItemExtraAttributes)">
{{ $navigationItem->getLabel() }}
@if ($navigationItemIcon instanceof \Illuminate\Contracts\Support\Htmlable)
@@ -63,23 +50,16 @@
$navigationItemBadge = $navigationItem->getBadge();
$navigationItemBadgeColor = $navigationItem->getBadgeColor($navigationItemBadge);
$navigationItemBadgeTooltip = $navigationItem->getBadgeTooltip($navigationItemBadge);
$navigationItemIcon = $navigationItem->isActive() ? ($navigationItem->getActiveIcon() ?? $navigationItem->getIcon()) : $navigationItem->getIcon();
$navigationItemIcon = $navigationItem->isActive()
? $navigationItem->getActiveIcon() ?? $navigationItem->getIcon()
: $navigationItem->getIcon();
$navigationItemUrl = $navigationItem->getUrl();
$shouldNavigationItemOpenUrlInNewTab = $navigationItem->shouldOpenUrlInNewTab();
$navigationItemExtraAttributes = $navigationItem->getExtraAttributeBag();
@endphp
<x-filament::tabs.item
:active="$isNavigationItemActive"
:badge="$navigationItemBadge"
:badge-color="$navigationItemBadgeColor"
:badge-tooltip="$navigationItemBadgeTooltip"
:href="$navigationItemUrl"
:icon="$navigationItemIcon"
tag="a"
:target="$shouldNavigationItemOpenUrlInNewTab ? '_blank' : null"
:attributes="\Filament\Support\prepare_inherited_attributes($navigationItemExtraAttributes)"
>
<x-filament::tabs.item :active="$isNavigationItemActive" :badge="$navigationItemBadge" :badge-color="$navigationItemBadgeColor" :badge-tooltip="$navigationItemBadgeTooltip"
:href="$navigationItemUrl" :icon="$navigationItemIcon" tag="a" :target="$shouldNavigationItemOpenUrlInNewTab ? '_blank' : null" :attributes="\Filament\Support\prepare_inherited_attributes($navigationItemExtraAttributes)">
{{ $navigationItem->getLabel() }}
@if ($navigationItemIcon instanceof \Illuminate\Contracts\Support\Htmlable)
@@ -6,27 +6,21 @@
{{ \Filament\Support\generate_icon_html(\Filament\Support\Icons\Heroicon::OutlinedBell, alias: \Filament\View\PanelsIconAlias::SIDEBAR_OPEN_DATABASE_NOTIFICATIONS_BUTTON, size: \Filament\Support\Enums\IconSize::Large) }}
<span
@if ($isSidebarCollapsibleOnDesktop)
x-show="$store.sidebar.isOpen"
@if ($isSidebarCollapsibleOnDesktop) x-show="$store.sidebar.isOpen"
x-transition:enter="fi-transition-enter"
x-transition:enter-start="fi-transition-enter-start"
x-transition:enter-end="fi-transition-enter-end"
@endif
class="fi-sidebar-database-notifications-btn-label"
>
x-transition:enter-end="fi-transition-enter-end" @endif
class="fi-sidebar-database-notifications-btn-label">
{{ __('filament-panels::layout.actions.open_database_notifications.label') }}
</span>
@if ($unreadNotificationsCount)
<span
@if ($isSidebarCollapsibleOnDesktop)
x-show="$store.sidebar.isOpen"
@if ($isSidebarCollapsibleOnDesktop) x-show="$store.sidebar.isOpen"
x-transition:enter="fi-transition-enter"
x-transition:enter-start="fi-transition-enter-start"
x-transition:enter-end="fi-transition-enter-end"
@endif
class="fi-sidebar-database-notifications-btn-badge-ctn"
>
x-transition:enter-end="fi-transition-enter-end" @endif
class="fi-sidebar-database-notifications-btn-badge-ctn">
<x-filament::badge>
{{ $unreadNotificationsCount }}
</x-filament::badge>
@@ -13,31 +13,16 @@
$hasDropdown = filled($label) && filled($icon) && $sidebarCollapsible;
@endphp
<li
x-data="{ label: @js($subNavigation ? "sub_navigation_{$label}" : $label) }"
data-group-label="{{ $subNavigation ? "sub_navigation_{$label}" : $label }}"
<li x-data="{ label: @js($subNavigation ? "sub_navigation_{$label}" : $label) }" data-group-label="{{ $subNavigation ? "sub_navigation_{$label}" : $label }}"
x-bind:class="{ 'fi-collapsed': $store.sidebar.groupIsCollapsed(label) }"
{{
$attributes->class([
'fi-sidebar-group',
'fi-active' => $active,
'fi-collapsible' => $collapsible,
])
}}
>
{{ $attributes->class(['fi-sidebar-group', 'fi-active' => $active, 'fi-collapsible' => $collapsible]) }}>
@if ($label)
<div
@if ($collapsible)
x-on:click="$store.sidebar.toggleCollapsedGroup(label)"
@endif
@if ($sidebarCollapsible)
x-show="$store.sidebar.isOpen"
<div @if ($collapsible) x-on:click="$store.sidebar.toggleCollapsedGroup(label)" @endif
@if ($sidebarCollapsible) x-show="$store.sidebar.isOpen"
x-transition:enter="fi-transition-enter"
x-transition:enter-start="fi-transition-enter-start"
x-transition:enter-end="fi-transition-enter-end"
@endif
class="fi-sidebar-group-btn"
>
x-transition:enter-end="fi-transition-enter-end" @endif
class="fi-sidebar-group-btn">
@if ($icon)
{{ \Filament\Support\generate_icon_html($icon, size: \Filament\Support\Enums\IconSize::Large) }}
@endif
@@ -47,27 +32,17 @@
</span>
@if ($collapsible)
<x-filament::icon-button
color="gray"
:icon="\Filament\Support\Icons\Heroicon::ChevronUp"
:icon-alias="\Filament\View\PanelsIconAlias::SIDEBAR_GROUP_COLLAPSE_BUTTON"
:label="$label"
x-bind:aria-expanded="! $store.sidebar.groupIsCollapsed(label)"
x-on:click.stop="$store.sidebar.toggleCollapsedGroup(label)"
class="fi-sidebar-group-collapse-btn"
/>
<x-filament::icon-button color="gray" :icon="\Filament\Support\Icons\Heroicon::ChevronUp" :icon-alias="\Filament\View\PanelsIconAlias::SIDEBAR_GROUP_COLLAPSE_BUTTON" :label="$label"
x-bind:aria-expanded="!$store.sidebar.groupIsCollapsed(label)"
x-on:click.stop="$store.sidebar.toggleCollapsedGroup(label)" class="fi-sidebar-group-collapse-btn" />
@endif
</div>
@endif
@if ($hasDropdown)
<x-filament::dropdown
:placement="(__('filament-panels::layout.direction') === 'rtl') ? 'left-start' : 'right-start'"
x-show="! $store.sidebar.isOpen"
>
<x-filament::dropdown :placement="(__('filament-panels::layout.direction') === 'rtl') ? 'left-start' : 'right-start'" x-show="! $store.sidebar.isOpen">
<x-slot name="trigger">
<button
x-data="{ tooltip: false }"
<button x-data="{ tooltip: false }"
x-effect="
tooltip = $store.sidebar.isOpen
? false
@@ -77,9 +52,7 @@
theme: $store.theme,
}
"
x-tooltip.html="tooltip"
class="fi-sidebar-group-dropdown-trigger-btn"
>
x-tooltip.html="tooltip" class="fi-sidebar-group-dropdown-trigger-btn">
{{ \Filament\Support\generate_icon_html($icon, size: \Filament\Support\Enums\IconSize::Large) }}
</button>
</x-slot>
@@ -89,10 +62,7 @@
foreach ($items as $item) {
if ($childItems = $item->getChildItems()) {
$lists[] = [
$item,
...$childItems,
];
$lists[] = [$item, ...$childItems];
$lists[] = [];
continue;
@@ -127,22 +97,14 @@
$itemBadgeColor = $item->getBadgeColor($itemBadge);
$itemBadgeTooltip = $item->getBadgeTooltip($itemBadge);
$itemUrl = $item->getUrl();
$itemIcon = $itemIsActive ? ($item->getActiveIcon() ?? $item->getIcon()) : $item->getIcon();
$itemIcon = $itemIsActive ? $item->getActiveIcon() ?? $item->getIcon() : $item->getIcon();
$shouldItemOpenUrlInNewTab = $item->shouldOpenUrlInNewTab();
$itemExtraAttributes = $item->getExtraAttributeBag();
@endphp
<x-filament::dropdown.list.item
:badge="$itemBadge"
:badge-color="$itemBadgeColor"
:badge-tooltip="$itemBadgeTooltip"
:color="$itemIsActive ? 'primary' : 'gray'"
:href="$itemUrl"
:icon="$itemIcon"
tag="a"
:target="$shouldItemOpenUrlInNewTab ? '_blank' : null"
:attributes="\Filament\Support\prepare_inherited_attributes($itemExtraAttributes)"
>
<x-filament::dropdown.list.item :badge="$itemBadge" :badge-color="$itemBadgeColor" :badge-tooltip="$itemBadgeTooltip"
:color="$itemIsActive ? 'primary' : 'gray'" :href="$itemUrl" :icon="$itemIcon" tag="a" :target="$shouldItemOpenUrlInNewTab ? '_blank' : null"
:attributes="\Filament\Support\prepare_inherited_attributes($itemExtraAttributes)">
{{ $item->getLabel() }}
</x-filament::dropdown.list.item>
@endforeach
@@ -151,26 +113,20 @@
</x-filament::dropdown>
@endif
<ul
@if (filled($label))
@if ($sidebarCollapsible)
<ul @if (filled($label)) @if ($sidebarCollapsible)
x-show="$store.sidebar.isOpen ? ! $store.sidebar.groupIsCollapsed(label) : ! @js($hasDropdown)"
@else
x-show="! $store.sidebar.groupIsCollapsed(label)"
@endif
x-collapse.duration.200ms
@endif
@if ($sidebarCollapsible)
x-transition:enter="fi-transition-enter"
x-show="! $store.sidebar.groupIsCollapsed(label)" @endif
x-collapse.duration.200ms @endif
@if ($sidebarCollapsible) x-transition:enter="fi-transition-enter"
x-transition:enter-start="fi-transition-enter-start"
x-transition:enter-end="fi-transition-enter-end"
@endif
x-transition:enter-end="fi-transition-enter-end" @endif
class="fi-sidebar-group-items"
>
>
@foreach ($items as $item)
@php
$isItemChildItemsActive = $item->isChildItemsActive();
$isItemActive = (! $isItemChildItemsActive) && $item->isActive();
$isItemActive = !$isItemChildItemsActive && $item->isActive();
$itemActiveIcon = $item->getActiveIcon();
$itemBadge = $item->getBadge();
$itemBadgeColor = $item->getBadgeColor($itemBadge);
@@ -186,29 +142,19 @@
$itemIcon = null;
$itemActiveIcon = null;
} else {
throw new \Exception('Navigation group [' . $label . '] has an icon but one or more of its items also have icons. Either the group or its items can have icons, but not both. This is to ensure a proper user experience.');
throw new \Exception(
'Navigation group [' .
$label .
'] has an icon but one or more of its items also have icons. Either the group or its items can have icons, but not both. This is to ensure a proper user experience.',
);
}
}
@endphp
<x-filament-panels::sidebar.item
:active="$isItemActive"
:active-child-items="$isItemChildItemsActive"
:active-icon="$itemActiveIcon"
:badge="$itemBadge"
:badge-color="$itemBadgeColor"
:badge-tooltip="$itemBadgeTooltip"
:child-items="$itemChildItems"
:first="$loop->first"
:grouped="filled($label)"
:icon="$itemIcon"
:last="$loop->last"
:should-open-url-in-new-tab="$shouldItemOpenUrlInNewTab"
:sidebar-collapsible="$sidebarCollapsible"
:sub-navigation="$subNavigation"
:url="$itemUrl"
:attributes="\Filament\Support\prepare_inherited_attributes($itemExtraAttributes)"
>
<x-filament-panels::sidebar.item :active="$isItemActive" :active-child-items="$isItemChildItemsActive" :active-icon="$itemActiveIcon" :badge="$itemBadge"
:badge-color="$itemBadgeColor" :badge-tooltip="$itemBadgeTooltip" :child-items="$itemChildItems" :first="$loop->first" :grouped="filled($label)"
:icon="$itemIcon" :last="$loop->last" :should-open-url-in-new-tab="$shouldItemOpenUrlInNewTab" :sidebar-collapsible="$sidebarCollapsible" :sub-navigation="$subNavigation"
:url="$itemUrl" :attributes="\Filament\Support\prepare_inherited_attributes($itemExtraAttributes)">
{{ $item->getLabel() }}
@if ($itemIcon instanceof \Illuminate\Contracts\Support\Htmlable)
@@ -22,20 +22,15 @@
@endphp
<li
{{
$attributes->class([
'fi-sidebar-item',
'fi-active' => $active,
'fi-sidebar-item-has-active-child-items' => $activeChildItems,
'fi-sidebar-item-has-url' => filled($url),
])
}}
>
<a
{{ \Filament\Support\generate_href_html($url, $shouldOpenUrlInNewTab) }}
{{ $attributes->class([
'fi-sidebar-item',
'fi-active' => $active,
'fi-sidebar-item-has-active-child-items' => $activeChildItems,
'fi-sidebar-item-has-url' => filled($url),
]) }}>
<a {{ \Filament\Support\generate_href_html($url, $shouldOpenUrlInNewTab) }}
x-on:click="window.matchMedia(`(max-width: 1024px)`).matches && $store.sidebar.close()"
@if ($sidebarCollapsible && (! $subNavigation))
x-data="{ tooltip: false }"
@if ($sidebarCollapsible && !$subNavigation) x-data="{ tooltip: false }"
x-effect="
tooltip = $store.sidebar.isOpen
? false
@@ -45,35 +40,27 @@
theme: $store.theme,
}
"
x-tooltip.html="tooltip"
@endif
class="fi-sidebar-item-btn"
>
@if (filled($icon) && ((! $subGrouped) || ($sidebarCollapsible && (! $subNavigation))))
{{
\Filament\Support\generate_icon_html(($active && $activeIcon) ? $activeIcon : $icon, attributes: (new \Illuminate\View\ComponentAttributeBag([
'x-show' => ($subGrouped && $sidebarCollapsible) ? '! $store.sidebar.isOpen' : false,
]))->class(['fi-sidebar-item-icon']), size: \Filament\Support\Enums\IconSize::Large)
}}
x-tooltip.html="tooltip" @endif
class="fi-sidebar-item-btn">
@if (filled($icon) && (!$subGrouped || ($sidebarCollapsible && !$subNavigation)))
{{ \Filament\Support\generate_icon_html(
$active && $activeIcon ? $activeIcon : $icon,
attributes: new \Illuminate\View\ComponentAttributeBag([
'x-show' => $subGrouped && $sidebarCollapsible ? '! $store.sidebar.isOpen' : false,
])->class(['fi-sidebar-item-icon']),
size: \Filament\Support\Enums\IconSize::Large,
) }}
@endif
@if ((blank($icon) && $grouped) || $subGrouped)
<div
@if (filled($icon) && $subGrouped && $sidebarCollapsible && (! $subNavigation))
x-show="$store.sidebar.isOpen"
@endif
class="fi-sidebar-item-grouped-border"
>
@if (! $first)
<div
class="fi-sidebar-item-grouped-border-part-not-first"
></div>
<div @if (filled($icon) && $subGrouped && $sidebarCollapsible && !$subNavigation) x-show="$store.sidebar.isOpen" @endif
class="fi-sidebar-item-grouped-border">
@if (!$first)
<div class="fi-sidebar-item-grouped-border-part-not-first"></div>
@endif
@if (! $last)
<div
class="fi-sidebar-item-grouped-border-part-not-last"
></div>
@if (!$last)
<div class="fi-sidebar-item-grouped-border-part-not-last"></div>
@endif
<div class="fi-sidebar-item-grouped-border-part"></div>
@@ -81,31 +68,22 @@
@endif
<span
@if ($sidebarCollapsible && (! $subNavigation))
x-show="$store.sidebar.isOpen"
@if ($sidebarCollapsible && !$subNavigation) x-show="$store.sidebar.isOpen"
x-transition:enter="fi-transition-enter"
x-transition:enter-start="fi-transition-enter-start"
x-transition:enter-end="fi-transition-enter-end"
@endif
class="fi-sidebar-item-label"
>
x-transition:enter-end="fi-transition-enter-end" @endif
class="fi-sidebar-item-label">
{{ $slot }}
</span>
@if (filled($badge))
<span
@if ($sidebarCollapsible && (! $subNavigation))
x-show="$store.sidebar.isOpen"
@if ($sidebarCollapsible && !$subNavigation) x-show="$store.sidebar.isOpen"
x-transition:enter="fi-transition-enter"
x-transition:enter-start="fi-transition-enter-start"
x-transition:enter-end="fi-transition-enter-end"
@endif
class="fi-sidebar-item-badge-ctn"
>
<x-filament::badge
:color="$badgeColor"
:tooltip="$badgeTooltip"
>
x-transition:enter-end="fi-transition-enter-end" @endif
class="fi-sidebar-item-badge-ctn">
<x-filament::badge :color="$badgeColor" :tooltip="$badgeTooltip">
{{ $badge }}
</x-filament::badge>
</span>
@@ -117,7 +95,7 @@
@foreach ($childItems as $childItem)
@php
$isChildItemChildItemsActive = $childItem->isChildItemsActive();
$isChildActive = (! $isChildItemChildItemsActive) && $childItem->isActive();
$isChildActive = !$isChildItemChildItemsActive && $childItem->isActive();
$childItemActiveIcon = $childItem->getActiveIcon();
$childItemBadge = $childItem->getBadge();
$childItemBadgeColor = $childItem->getBadgeColor($childItemBadge);
@@ -128,23 +106,9 @@
$childItemExtraAttributes = $childItem->getExtraAttributeBag();
@endphp
<x-filament-panels::sidebar.item
:active="$isChildActive"
:active-child-items="$isChildItemChildItemsActive"
:active-icon="$childItemActiveIcon"
:badge="$childItemBadge"
:badge-color="$childItemBadgeColor"
:badge-tooltip="$childItemBadgeTooltip"
:first="$loop->first"
grouped
:icon="$childItemIcon"
:last="$loop->last"
:should-open-url-in-new-tab="$shouldChildItemOpenUrlInNewTab"
sub-grouped
:sub-navigation="$subNavigation"
:url="$childItemUrl"
:attributes="\Filament\Support\prepare_inherited_attributes($childItemExtraAttributes)"
>
<x-filament-panels::sidebar.item :active="$isChildActive" :active-child-items="$isChildItemChildItemsActive" :active-icon="$childItemActiveIcon" :badge="$childItemBadge"
:badge-color="$childItemBadgeColor" :badge-tooltip="$childItemBadgeTooltip" :first="$loop->first" grouped :icon="$childItemIcon" :last="$loop->last"
:should-open-url-in-new-tab="$shouldChildItemOpenUrlInNewTab" sub-grouped :sub-navigation="$subNavigation" :url="$childItemUrl" :attributes="\Filament\Support\prepare_inherited_attributes($childItemExtraAttributes)">
{{ $childItem->getLabel() }}
</x-filament-panels::sidebar.item>
@endforeach
@@ -11,15 +11,19 @@
$items = $this->getTenantMenuItems();
$canSwitchTenants = filament()->hasTenantSwitcher() && filled($tenants = array_filter(
filament()->getUserTenants(filament()->auth()->user()),
fn (\Illuminate\Database\Eloquent\Model $tenant): bool => ! $tenant->is($currentTenant),
));
$canSwitchTenants =
filament()->hasTenantSwitcher() &&
filled(
$tenants = array_filter(
filament()->getUserTenants(filament()->auth()->user()),
fn(\Illuminate\Database\Eloquent\Model $tenant): bool => !$tenant->is($currentTenant),
),
);
$isSearchable = $canSwitchTenants && (filament()->isTenantMenuSearchable() ?? (count($tenants) >= 10));
$isSearchable = $canSwitchTenants && (filament()->isTenantMenuSearchable() ?? count($tenants) >= 10);
$itemsBeforeAndAfterTenantSwitcher = collect($items)
->groupBy(fn (Action $item): bool => $canSwitchTenants && ($item->getSort() < 0), preserveKeys: true)
->groupBy(fn(Action $item): bool => $canSwitchTenants && $item->getSort() < 0, preserveKeys: true)
->all();
$itemsBeforeTenantSwitcher = $itemsBeforeAndAfterTenantSwitcher[true] ?? collect();
$itemsAfterTenantSwitcher = $itemsBeforeAndAfterTenantSwitcher[false] ?? collect();
@@ -29,19 +33,10 @@
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::TENANT_MENU_BEFORE) }}
<x-filament::dropdown
placement="bottom-start"
size
:teleport="$teleport"
:attributes="
\Filament\Support\prepare_inherited_attributes($attributes)
->class(['fi-tenant-menu'])
"
>
<x-filament::dropdown placement="bottom-start" size :teleport="$teleport" :attributes="\Filament\Support\prepare_inherited_attributes($attributes)->class(['fi-tenant-menu'])">
<x-slot name="trigger">
<button
@if ($isSidebarCollapsibleOnDesktop)
x-data="{ tooltip: false }"
@if ($isSidebarCollapsibleOnDesktop) x-data="{ tooltip: false }"
x-effect="
tooltip = $store.sidebar.isOpen
? false
@@ -51,22 +46,12 @@
theme: $store.theme,
}
"
x-tooltip.html="tooltip"
@endif
type="button"
class="fi-tenant-menu-trigger"
>
<x-filament-panels::avatar.tenant
:tenant="$currentTenant"
loading="lazy"
/>
x-tooltip.html="tooltip" @endif
type="button" class="fi-tenant-menu-trigger">
<x-filament-panels::avatar.tenant :tenant="$currentTenant" loading="lazy" />
<span
@if ($isSidebarCollapsibleOnDesktop)
x-show="$store.sidebar.isOpen"
@endif
class="fi-tenant-menu-trigger-text"
>
<span @if ($isSidebarCollapsibleOnDesktop) x-show="$store.sidebar.isOpen" @endif
class="fi-tenant-menu-trigger-text">
@if ($currentTenant instanceof \Filament\Models\Contracts\HasCurrentTenantLabel)
<span class="fi-tenant-menu-trigger-current-tenant-label">
{{ $currentTenant->getCurrentTenantLabel() }}
@@ -78,11 +63,13 @@
</span>
</span>
{{
\Filament\Support\generate_icon_html(\Filament\Support\Icons\Heroicon::ChevronDown, alias: \Filament\View\PanelsIconAlias::TENANT_MENU_TOGGLE_BUTTON, attributes: new \Illuminate\View\ComponentAttributeBag([
{{ \Filament\Support\generate_icon_html(
\Filament\Support\Icons\Heroicon::ChevronDown,
alias: \Filament\View\PanelsIconAlias::TENANT_MENU_TOGGLE_BUTTON,
attributes: new \Illuminate\View\ComponentAttributeBag([
'x-show' => $isSidebarCollapsibleOnDesktop ? '$store.sidebar.isOpen' : null,
]))
}}
]),
) }}
</button>
</x-slot>
@@ -103,12 +90,9 @@
{{ __('filament-panels::layout.tenant_menu.search_field.label') }}
</label>
<x-filament::input
x-bind:id="$id('input')"
x-model="search"
<x-filament::input x-bind:id="$id('input')" x-model="search"
placeholder="{{ __('filament-panels::layout.tenant_menu.search_field.placeholder') }}"
type="search"
/>
type="search" />
</div>
@endif
@@ -125,13 +109,8 @@
@js($tenantName).replace(/ /g, '')
.toLowerCase()
.includes(search.replace(/ /g, '').toLowerCase())
"
>
<x-filament::dropdown.list.item
:href="$tenantUrl"
:image="$tenantImage"
tag="a"
>
">
<x-filament::dropdown.list.item :href="$tenantUrl" :image="$tenantImage" tag="a">
{{ $tenantName }}
</x-filament::dropdown.list.item>
</div>

Some files were not shown because too many files have changed in this diff Show More