Initial commit
This commit is contained in:
commit
444c69672f
|
@ -0,0 +1,104 @@
|
|||
<?php
|
||||
|
||||
namespace Zoomyboy\Owncloud;
|
||||
|
||||
use Backend;
|
||||
use Backend\Models\UserRole;
|
||||
use System\Classes\PluginBase;
|
||||
use Zoomyboy\Owncloud\Components\Confirm;
|
||||
use Zoomyboy\Owncloud\Components\Form;
|
||||
use Zoomyboy\Owncloud\Models\Settings;
|
||||
|
||||
/**
|
||||
* owncloud Plugin Information File.
|
||||
*/
|
||||
class Plugin extends PluginBase
|
||||
{
|
||||
/**
|
||||
* Returns information about this plugin.
|
||||
*/
|
||||
public function pluginDetails(): array
|
||||
{
|
||||
return [
|
||||
'name' => 'zoomyboy.owncloud::lang.plugin.name',
|
||||
'description' => 'zoomyboy.owncloud::lang.plugin.description',
|
||||
'author' => 'zoomyboy',
|
||||
'icon' => 'icon-leaf',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Register method, called when the plugin is first registered.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Boot method, called right before the request route.
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers any frontend components implemented in this plugin.
|
||||
*/
|
||||
public function registerComponents(): array
|
||||
{
|
||||
return [
|
||||
Form::class => 'owncloud_form',
|
||||
Confirm::class => 'owncloud_confirm',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers any backend permissions used by this plugin.
|
||||
*/
|
||||
public function registerPermissions(): array
|
||||
{
|
||||
return []; // Remove this line to activate
|
||||
|
||||
return [
|
||||
'zoomyboy.owncloud.some_permission' => [
|
||||
'tab' => 'zoomyboy.owncloud::lang.plugin.name',
|
||||
'label' => 'zoomyboy.owncloud::lang.permissions.some_permission',
|
||||
'roles' => [UserRole::CODE_DEVELOPER, UserRole::CODE_PUBLISHER],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers backend navigation items for this plugin.
|
||||
*/
|
||||
public function registerNavigation(): array
|
||||
{
|
||||
return []; // Remove this line to activate
|
||||
|
||||
return [
|
||||
'owncloud' => [
|
||||
'label' => 'zoomyboy.owncloud::lang.plugin.name',
|
||||
'url' => Backend::url('zoomyboy/owncloud/mycontroller'),
|
||||
'icon' => 'icon-leaf',
|
||||
'permissions' => ['zoomyboy.owncloud.*'],
|
||||
'order' => 500,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function registerSettings(): array
|
||||
{
|
||||
return [
|
||||
'settings' => [
|
||||
'label' => 'Owncloud Settings',
|
||||
'description' => 'Owncloud Zugangsdaten',
|
||||
'category' => 'Services',
|
||||
'icon' => 'icon-cog',
|
||||
'class' => Settings::class,
|
||||
'order' => 500,
|
||||
'keywords' => 'owncloud api',
|
||||
'permissions' => [],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
var toastedOptions = {
|
||||
position: "bottom-right",
|
||||
duration: 3000,
|
||||
fitToScreen: false,
|
||||
fullWidth: false,
|
||||
theme: "material",
|
||||
};
|
||||
|
||||
export default function (toasted) {
|
||||
var toasted = new toasted(toastedOptions);
|
||||
|
||||
return {
|
||||
loading: false,
|
||||
data: {
|
||||
firstname: "",
|
||||
lastname: "",
|
||||
username: "",
|
||||
email: "",
|
||||
group: null,
|
||||
function: '',
|
||||
oc_groups: [],
|
||||
},
|
||||
oc_groups: [],
|
||||
finished: false,
|
||||
submitRequest: null,
|
||||
errorFields: [],
|
||||
groups: [
|
||||
{ id: "Gallier", name: "Gallier (Wuppertal)" },
|
||||
{ id: "Gandalf", name: "Gandalf (SG-Mangenberg)" },
|
||||
{ id: "Gravenrode", name: "Gravenrode (SG-Gräfrath)" },
|
||||
{ id: "Lennep", name: "Lennep (RS-Lennep)" },
|
||||
{ id: "Silva", name: "Silva (SG-Wald)" },
|
||||
{ id: "Sugambrer", name: "Sugambrer (SG-Höhscheid)" },
|
||||
{ id: "Tenkterer", name: "Tenkterer (SG-Löhdorf)" },
|
||||
{ id: "von Berg", name: "von Berg (SG-Ohligs)" },
|
||||
],
|
||||
submit() {
|
||||
var _self = this;
|
||||
this.loading = true;
|
||||
var promise = fetch(window.location.href, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
"X-WINTER-REQUEST-HANDLER": this.submitRequest,
|
||||
"X-WINTER-REQUEST-PARTIALS": [],
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
},
|
||||
body: JSON.stringify(this.data),
|
||||
});
|
||||
|
||||
promise.then(function (response) {
|
||||
_self.loading = false;
|
||||
if (response.status === 422) {
|
||||
response.json().then((errors) => {
|
||||
Object.keys(errors).forEach((field) => {
|
||||
toasted.error(errors[field].join("<br>"));
|
||||
});
|
||||
});
|
||||
}
|
||||
if (response.status === 201) {
|
||||
_self.finished = true;
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
namespace Zoomyboy\Owncloud\Components;
|
||||
|
||||
use Cms\Classes\ComponentBase;
|
||||
use GuzzleHttp\Client;
|
||||
use Mail;
|
||||
use Zoomyboy\Owncloud\Models\Settings;
|
||||
|
||||
class Confirm extends ComponentBase
|
||||
{
|
||||
/**
|
||||
* Gets the details for the component.
|
||||
*/
|
||||
public function componentDetails()
|
||||
{
|
||||
return [
|
||||
'name' => 'Confirm Component',
|
||||
'description' => 'No description provided yet...',
|
||||
];
|
||||
}
|
||||
|
||||
public function onRun(): void
|
||||
{
|
||||
$b = base64_decode($this->property('payload'));
|
||||
|
||||
if (!$b) {
|
||||
return;
|
||||
}
|
||||
|
||||
$b = json_decode($b, true);
|
||||
|
||||
if (!$b) {
|
||||
return;
|
||||
}
|
||||
|
||||
$password = str_random(32);
|
||||
$auth = base64_encode(Settings::get('username').':'.Settings::get('password'));
|
||||
$client = new Client(['base_uri' => Settings::get('url'), 'headers' => ['Authorization' => 'Basic '.$auth, 'Content-Type' => 'application/x-www-form-urlencoded']]);
|
||||
$client->post('/ocs/v1.php/cloud/users', [
|
||||
'form_params' => [
|
||||
'groups' => array_merge($b['oc_groups'], Settings::get('force_groups')),
|
||||
'userid' => $b['username'],
|
||||
'password' => $password,
|
||||
],
|
||||
]);
|
||||
|
||||
Mail::send('owncloud_confirm', [
|
||||
'password' => $password,
|
||||
'payload' => $b,
|
||||
], function ($message) use ($b) {
|
||||
$message->to($b['email'], $b['firstname'].' '.$b['lastname']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the properties provided by the component.
|
||||
*/
|
||||
public function defineProperties()
|
||||
{
|
||||
return [
|
||||
'payload' => [
|
||||
'label' => 'Payload',
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
<?php
|
||||
|
||||
namespace Zoomyboy\Owncloud\Components;
|
||||
|
||||
use Cache;
|
||||
use Cms\Classes\ComponentBase;
|
||||
use GuzzleHttp\Client;
|
||||
use Illuminate\Support\Facades\Lang;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Input;
|
||||
use Mail;
|
||||
use Winter\Storm\Support\Facades\Validator;
|
||||
use Zoomyboy\Owncloud\Models\Settings;
|
||||
|
||||
class Form extends ComponentBase
|
||||
{
|
||||
public array $groups = [];
|
||||
|
||||
/**
|
||||
* Gets the details for the component.
|
||||
*/
|
||||
public function componentDetails()
|
||||
{
|
||||
return [
|
||||
'name' => 'Form Component',
|
||||
'description' => 'No description provided yet...',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the properties provided by the component.
|
||||
*/
|
||||
public function defineProperties()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function onRun(): void
|
||||
{
|
||||
$groups = Cache::remember('oc_groupsa', 1, function () {
|
||||
return $this->getGroups();
|
||||
});
|
||||
$this->groups = collect($groups)
|
||||
->filter(fn ($g) => !in_array($g, Settings::get('force_groups')))
|
||||
->filter(fn ($g) => !in_array($g, Settings::get('disallowed_groups')))
|
||||
->map(fn ($group) => ['id' => $group, 'name' => $group])
|
||||
->toArray();
|
||||
}
|
||||
|
||||
public function onSubmit()
|
||||
{
|
||||
$rules = [
|
||||
'firstname' => 'required|string|max:255',
|
||||
'lastname' => 'required|string|max:255',
|
||||
'username' => ['required', 'string', 'max:255', 'regex:/^[a-zA-Z0-9]+$/', Rule::notIn($this->getUsers())],
|
||||
'email' => 'required|email|string|max:255',
|
||||
'group' => 'required|string|max:255',
|
||||
'function' => 'required|string|max:255',
|
||||
'oc_groups' => 'present|array',
|
||||
'oc_groups.*' => 'string',
|
||||
];
|
||||
$validator = Validator::make(Input::all(), $rules, [
|
||||
'username.not_in' => 'OwnCloud Nutzername wird bereits verwendet.',
|
||||
'username.regex' => 'OwnCloud Nutzername darf nur aus Buchstaben und Zahlen bestehen',
|
||||
], Lang::get('zoomyboy.owncloud::validation.attributes'));
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->json($validator->errors(), 422);
|
||||
}
|
||||
|
||||
$payload = base64_encode(json_encode($validator->validated()));
|
||||
Mail::send('owncloud_request', [
|
||||
'link' => url('/owncloud-confirm/'.$payload),
|
||||
'payload' => $validator->validated(),
|
||||
], function ($message) {
|
||||
foreach (Settings::get('admins') as $admin) {
|
||||
$message->to($admin);
|
||||
}
|
||||
});
|
||||
|
||||
dd('I');
|
||||
|
||||
return response()->json([], 201);
|
||||
}
|
||||
|
||||
private function getGroups(): array
|
||||
{
|
||||
$response = $this->getClient()->get('/ocs/v1.php/cloud/groups');
|
||||
|
||||
$r = [];
|
||||
$xml = simplexml_load_string((string) $response->getBody());
|
||||
foreach ($xml->xpath('/ocs/data/groups/element') as $element) {
|
||||
$r[] = (string) $element;
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
private function getUsers(): array
|
||||
{
|
||||
$response = $this->getClient()->get('/ocs/v1.php/cloud/users');
|
||||
|
||||
$r = [];
|
||||
$xml = simplexml_load_string((string) $response->getBody());
|
||||
foreach ($xml->xpath('/ocs/data/users/element') as $element) {
|
||||
$r[] = (string) $element;
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
private function getClient(): Client
|
||||
{
|
||||
$auth = base64_encode(Settings::get('username').':'.Settings::get('password'));
|
||||
|
||||
return new Client(['base_uri' => Settings::get('url'), 'headers' => ['Authorization' => 'Basic '.$auth]]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
Zugang wurde erstellt.
|
|
@ -0,0 +1,3 @@
|
|||
<p>This is the default markup for component Form</p>
|
||||
|
||||
<small>You can delete this file if you want</small>
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'plugin' => [
|
||||
'name' => 'owncloud',
|
||||
'description' => 'No description provided yet...',
|
||||
],
|
||||
'permissions' => [
|
||||
'some_permission' => 'Some permission',
|
||||
],
|
||||
'models' => [
|
||||
'general' => [
|
||||
'id' => 'ID',
|
||||
'created_at' => 'Created At',
|
||||
'updated_at' => 'Updated At',
|
||||
],
|
||||
'request' => [
|
||||
'label' => 'Request',
|
||||
'label_plural' => 'Requests',
|
||||
],
|
||||
],
|
||||
];
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'attributes' => [
|
||||
'firstname' => 'Vorname',
|
||||
'username' => 'OwnCloud Nutzername',
|
||||
'lastname' => 'Nachname',
|
||||
'email' => 'E-Mail-Adresse',
|
||||
'group' => 'Stamm',
|
||||
'function' => 'Funktion',
|
||||
],
|
||||
];
|
|
@ -0,0 +1,74 @@
|
|||
<?php namespace Zoomyboy\Owncloud\Models;
|
||||
|
||||
use Model;
|
||||
|
||||
/**
|
||||
* Request Model
|
||||
*/
|
||||
class Request extends Model
|
||||
{
|
||||
use \Winter\Storm\Database\Traits\Validation;
|
||||
|
||||
/**
|
||||
* @var string The database table used by the model.
|
||||
*/
|
||||
public $table = 'zoomyboy_owncloud_requests';
|
||||
|
||||
/**
|
||||
* @var array Guarded fields
|
||||
*/
|
||||
protected $guarded = ['*'];
|
||||
|
||||
/**
|
||||
* @var array Fillable fields
|
||||
*/
|
||||
protected $fillable = [];
|
||||
|
||||
/**
|
||||
* @var array Validation rules for attributes
|
||||
*/
|
||||
public $rules = [];
|
||||
|
||||
/**
|
||||
* @var array Attributes to be cast to native types
|
||||
*/
|
||||
protected $casts = [];
|
||||
|
||||
/**
|
||||
* @var array Attributes to be cast to JSON
|
||||
*/
|
||||
protected $jsonable = [];
|
||||
|
||||
/**
|
||||
* @var array Attributes to be appended to the API representation of the model (ex. toArray())
|
||||
*/
|
||||
protected $appends = [];
|
||||
|
||||
/**
|
||||
* @var array Attributes to be removed from the API representation of the model (ex. toArray())
|
||||
*/
|
||||
protected $hidden = [];
|
||||
|
||||
/**
|
||||
* @var array Attributes to be cast to Argon (Carbon) instances
|
||||
*/
|
||||
protected $dates = [
|
||||
'created_at',
|
||||
'updated_at',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array Relations
|
||||
*/
|
||||
public $hasOne = [];
|
||||
public $hasMany = [];
|
||||
public $hasOneThrough = [];
|
||||
public $hasManyThrough = [];
|
||||
public $belongsTo = [];
|
||||
public $belongsToMany = [];
|
||||
public $morphTo = [];
|
||||
public $morphOne = [];
|
||||
public $morphMany = [];
|
||||
public $attachOne = [];
|
||||
public $attachMany = [];
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace Zoomyboy\Owncloud\Models;
|
||||
|
||||
use Model;
|
||||
|
||||
class Settings extends Model
|
||||
{
|
||||
public $implement = ['System.Behaviors.SettingsModel'];
|
||||
|
||||
public $settingsCode = 'zoomyboy_owncloud_settings';
|
||||
|
||||
public $settingsFields = 'fields.yaml';
|
||||
|
||||
public $settingsCacheTtl = 3600;
|
||||
|
||||
public function groups(): array
|
||||
{
|
||||
return [
|
||||
];
|
||||
}
|
||||
|
||||
public function users(): array
|
||||
{
|
||||
return [
|
||||
];
|
||||
}
|
||||
|
||||
public function createUser(): void
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
# ===================================
|
||||
# List Column Definitions
|
||||
# ===================================
|
||||
|
||||
columns:
|
||||
id:
|
||||
label: 'zoomyboy.owncloud::lang.models.general.id'
|
||||
searchable: true
|
||||
created_at:
|
||||
label: 'zoomyboy.owncloud::lang.models.general.created_at'
|
||||
type: datetime
|
||||
searchable: true
|
||||
sortable: true
|
||||
invisible: true
|
||||
updated_at:
|
||||
label: 'zoomyboy.owncloud::lang.models.general.updated_at'
|
||||
type: datetime
|
||||
searchable: true
|
||||
sortable: true
|
|
@ -0,0 +1,8 @@
|
|||
# ===================================
|
||||
# Form Field Definitions
|
||||
# ===================================
|
||||
|
||||
fields:
|
||||
id:
|
||||
label: 'zoomyboy.owncloud::lang.models.general.id'
|
||||
disabled: true
|
|
@ -0,0 +1,20 @@
|
|||
fields:
|
||||
url:
|
||||
label: URL
|
||||
username:
|
||||
label: Benutzername
|
||||
password:
|
||||
label: Passwort
|
||||
force_groups:
|
||||
label: Diese Gruppen immer zuweisen
|
||||
type: taglist
|
||||
mode: array
|
||||
disallowed_groups:
|
||||
label: Diese Gruppen niccht erlauben
|
||||
type: taglist
|
||||
mode: array
|
||||
admins:
|
||||
label: Anfrage an diese E-Mail-Adressen
|
||||
type: taglist
|
||||
mode: array
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
'1.0.0':
|
||||
- 'First version of owncloud'
|
|
@ -0,0 +1,88 @@
|
|||
{% macro field(context, name, label, required, type) %}
|
||||
<label class="w-full border border-solid border-gray-500 focus-within:border-primary rounded-lg relative flex">
|
||||
<input name="{{name}}" type="{{type|default('text')}}" id="{{name}}" placeholder=" " class="bg-white rounded-lg focus:outline-none text-gray-600 text-left placeholder-white peer py-1 px-2 sm:py-2 text-sm sm:text-base sm:px-3 w-full" x-model="data.{{name}}" />
|
||||
<span
|
||||
class="transition-all duration-200 absolute text-gray-600 left-2 flex bg-white items-center -top-3 px-1 peer-placeholder-shown:bottom-0 peer-placeholder-shown:-top-0
|
||||
text-xs xs:text-sm peer-placeholder-shown:text-sm xs:peer-placeholder-shown:text-base peer-focus:text-xs xs:peer-focus:text-sm
|
||||
peer-focus:-top-3 peer-focus:bottom-auto "
|
||||
>{{label}} {% if required %} <span class="text-red-800 ml-1">*</span> {% endif %}</span
|
||||
>
|
||||
</label>
|
||||
{% endmacro %}
|
||||
{% macro textarea(context, name, label, required, type) %}
|
||||
<label class="w-full border border-solid border-gray-500 focus-within:border-primary rounded-lg relative flex">
|
||||
<textarea name="{{name}}" rows="6" id="{{name}}" class="bg-white rounded-lg focus:outline-none text-gray-600 text-left placeholder-white peer py-1 px-2 sm:py-2 text-sm sm:text-base sm:px-3 w-full" x-model="data.{{name}}">
|
||||
</textarea>
|
||||
<span
|
||||
class="transition-all duration-200 absolute text-gray-600 left-2 flex bg-white items-center -top-3 px-1 text-xs xs:text-sm"
|
||||
>{{label}} {% if required %} <span class="text-red-800 ml-1">*</span> {% endif %}</span
|
||||
>
|
||||
</label>
|
||||
{% endmacro %}
|
||||
{% macro select(context, name, label, required, options) %}
|
||||
<label class="w-full border border-solid border-gray-500 focus-within:border-primary rounded-lg relative flex" for="{{name}}">
|
||||
<select name="{{name}}" id="{{name}}" class="bg-white rounded-lg focus:outline-none text-gray-600 text-left peer py-1 px-2 sm:py-2 text-sm sm:text-base sm:px-3 w-full" x-model="data.{{name}}">
|
||||
<option :selected="data.{{name}} === ''" value="">-- kein --</option>
|
||||
<template x-for="model in {{options}}">
|
||||
<option :selected="data.{{name}} === model.id" :value="model.id" x-text="model.name"></option>
|
||||
</template>
|
||||
</select>
|
||||
<span
|
||||
class="absolute text-gray-600 left-2 flex bg-white items-center -top-3 px-1 text-xs xs:text-sm"
|
||||
>{{label}} {% if required %} <span class="text-red-800 ml-1">*</span> {% endif %}</span
|
||||
>
|
||||
</label>
|
||||
{% endmacro %}
|
||||
{% macro radio(context, name, label, required, options) %}
|
||||
<div>
|
||||
<span
|
||||
class="text-gray-600 text-sm"
|
||||
>{{label}} {% if required %} <span class="text-red-800 ml-1">*</span> {% endif %}</span
|
||||
>
|
||||
<div class="grid grid-cols-2 sm:grid-cols-1 gap-2">
|
||||
<template x-for="option, index in {{options}}">
|
||||
<label :for="`{{name}}-${index}`" class="block relative flex items-center">
|
||||
<input type="radio" name="{{name}}" :value="option.name" x-model="data.{{name}}" class="peer absolute invisible" :id="`{{name}}-${index}`" />
|
||||
<span class="border-neutral-400 border-4 border-solid peer-checked:border-primary absolute left-0 w-6 h-6 rounded-full block"></span>
|
||||
<span class="peer-checked:bg-primary left-2 w-2 h-2 absolute rounded-full block"></span>
|
||||
<span class="pl-8" x-text="option.name"></span>
|
||||
</label>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
{% macro yesno(context, name, label, required) %}
|
||||
<div>
|
||||
<div class="flex flex-col space-y-1">
|
||||
<label for="{{name}}" class="block relative flex items-center">
|
||||
<input type="checkbox" name="{{name}}" x-model="data.{{name}}" class="peer absolute invisible" id="{{name}}" />
|
||||
<span class="border-neutral-400 border-4 border-solid peer-checked:border-primary absolute left-0 w-6 h-6 rounded block"></span>
|
||||
<span class="peer-checked:bg-primary left-2 w-2 h-2 absolute rounded-sm block"></span>
|
||||
<span class="pl-8 text-sm">{{label}} {% if required %} <span class="text-red-800 ml-1">*</span> {% endif %}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
{% macro checkboxes(context, name, label, required, options, settings) %}
|
||||
<div>
|
||||
<span
|
||||
class="text-gray-600 flex text-sm"
|
||||
>{{label}} {% if required %} <span class="text-red-800 ml-1">*</span> {% endif %}</span
|
||||
>
|
||||
<div class="mt-2 grid gap-2 grid-cols-[repeat(auto-fill,minmax(150px,1fr))]">
|
||||
<template x-for="option, index in {{options}}">
|
||||
<label :for="`{{name}}-${index}`" class="block relative flex items-center">
|
||||
<input type="checkbox" name="{{name}}[]" :value="option.id" x-model="data.{{name}}" {% if settings.after %} @change="{{settings.after}}" {% endif %} class="peer absolute invisible" :id="`{{name}}-${index}`" />
|
||||
<span class="border-neutral-400 border-4 border-solid peer-checked:border-primary absolute left-0 w-6 h-6 rounded block"></span>
|
||||
<span class="peer-checked:bg-primary left-2 w-2 h-2 absolute rounded-sm block"></span>
|
||||
<span class="pl-8 text-sm sm:text-base flex flex-col">
|
||||
<span x-text="option.name" class="block" class="leading-none"></span>
|
||||
<template x-if="option.hint">
|
||||
<span class="text-xs leading-none text-gray-500" x-text="option.hint"></span>
|
||||
</template>
|
||||
</span>
|
||||
</label>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
Loading…
Reference in New Issue