mirror of
https://gitlab.linphone.org/BC/public/flexisip-account-manager.git
synced 2026-04-17 19:58:27 +00:00
FIX FLEXIAPI-441 add color picker and logo uploader to space settings
This commit is contained in:
parent
40eab70d11
commit
1456e4c04a
9 changed files with 345 additions and 37 deletions
|
|
@ -24,12 +24,17 @@ use App\Http\Requests\Space\Create;
|
||||||
use App\Space;
|
use App\Space;
|
||||||
use App\Rules\Ini;
|
use App\Rules\Ini;
|
||||||
use App\Rules\Domain;
|
use App\Rules\Domain;
|
||||||
|
use App\Services\LogoService;
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
class SpaceController extends Controller
|
class SpaceController extends Controller
|
||||||
{
|
{
|
||||||
|
public function __construct(private LogoService $logoService)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
return view('admin.space.index', ['spaces' => Space::withCount('accounts')->orderBy('host')->get()]);
|
return view('admin.space.index', ['spaces' => Space::withCount('accounts')->orderBy('host')->get()]);
|
||||||
|
|
@ -156,9 +161,15 @@ class SpaceController extends Controller
|
||||||
{
|
{
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'newsletter_registration_address' => 'nullable|email',
|
'newsletter_registration_address' => 'nullable|email',
|
||||||
'custom_provisioning_entries' => ['nullable', new Ini(Space::FORBIDDEN_KEYS)]
|
'custom_provisioning_entries' => ['nullable', new Ini(Space::FORBIDDEN_KEYS)],
|
||||||
|
'logo' => ['nullable', 'image', 'mimes:jpeg,png,webp,svg', 'max:2048'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
if ($request->hasFile('logo')) {
|
||||||
|
$space->logo = $this->logoService->store($request->file('logo'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$space->theme_hue = $request->get('theme_hue');
|
||||||
$space->copyright_text = $request->get('copyright_text');
|
$space->copyright_text = $request->get('copyright_text');
|
||||||
$space->intro_registration_text = $request->get('intro_registration_text');
|
$space->intro_registration_text = $request->get('intro_registration_text');
|
||||||
$space->newsletter_registration_address = $request->get('newsletter_registration_address');
|
$space->newsletter_registration_address = $request->get('newsletter_registration_address');
|
||||||
|
|
|
||||||
12
flexiapi/app/Services/LogoService.php
Normal file
12
flexiapi/app/Services/LogoService.php
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use Illuminate\Http\UploadedFile;
|
||||||
|
|
||||||
|
class LogoService
|
||||||
|
{
|
||||||
|
public function store(UploadedFile $file): string
|
||||||
|
{
|
||||||
|
return $file->store('img', 'public');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('spaces', function (Blueprint $table) {
|
||||||
|
$table->integer('theme_hue')->nullable();
|
||||||
|
$table->string('logo')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('spaces', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('theme_hue');
|
||||||
|
$table->dropColumn('logo');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -121,6 +121,7 @@
|
||||||
"Files": "Fichiers",
|
"Files": "Fichiers",
|
||||||
"From": "Depuis",
|
"From": "Depuis",
|
||||||
"Hello":"Bonjour",
|
"Hello":"Bonjour",
|
||||||
|
"Hex" : "Hex",
|
||||||
"Host": "Hôte",
|
"Host": "Hôte",
|
||||||
"I accept the Privacy Policy": "J'accepte la Politique de Confidentialité",
|
"I accept the Privacy Policy": "J'accepte la Politique de Confidentialité",
|
||||||
"I accept the Terms and Conditions": "J'accepte les Conditions Générales",
|
"I accept the Terms and Conditions": "J'accepte les Conditions Générales",
|
||||||
|
|
@ -183,6 +184,7 @@
|
||||||
"Phone Countries": "Numéros Internationaux",
|
"Phone Countries": "Numéros Internationaux",
|
||||||
"Phone number": "Numéro de téléphone",
|
"Phone number": "Numéro de téléphone",
|
||||||
"Phone registration": "Inscription par téléphone",
|
"Phone registration": "Inscription par téléphone",
|
||||||
|
"Platform customization": "Customisation de la plateforme",
|
||||||
"Please enter the new email that you would like to link to your account.": "Veuillez entre l'adresse email que vous souhaitez lier à votre compte.",
|
"Please enter the new email that you would like to link to your account.": "Veuillez entre l'adresse email que vous souhaitez lier à votre compte.",
|
||||||
"Please enter the new phone number that you would like to link to your account.": "Veuillez entrer le numéro de téléphone que vous souhaitez lier à votre compte.",
|
"Please enter the new phone number that you would like to link to your account.": "Veuillez entrer le numéro de téléphone que vous souhaitez lier à votre compte.",
|
||||||
"Priority rule": "Rêgle prioritaire",
|
"Priority rule": "Rêgle prioritaire",
|
||||||
|
|
@ -215,9 +217,11 @@
|
||||||
"Scan the following QR Code using an authenticated device and wait a few seconds.": "Scanner le QR Code avec un appareil authentifié et attendez quelques secondes",
|
"Scan the following QR Code using an authenticated device and wait a few seconds.": "Scanner le QR Code avec un appareil authentifié et attendez quelques secondes",
|
||||||
"Search by username":"Rechercher par nom d'utilisateur",
|
"Search by username":"Rechercher par nom d'utilisateur",
|
||||||
"Search": "Rechercher",
|
"Search": "Rechercher",
|
||||||
|
"Select a color": "Sélectionner une couleur",
|
||||||
"Select a contacts list": "Sélectionner une liste de contact",
|
"Select a contacts list": "Sélectionner une liste de contact",
|
||||||
"Select a domain": "Sélectionner un domaine",
|
"Select a domain": "Sélectionner un domaine",
|
||||||
"Select a file": "Choisir un fichier",
|
"Select a file": "Choisir un fichier",
|
||||||
|
"Select an image": "Choisir une image",
|
||||||
"Send an email to the user to reset the password": "Envoyer un email à l'utilisateur pour réinitialiser son mot de passe",
|
"Send an email to the user to reset the password": "Envoyer un email à l'utilisateur pour réinitialiser son mot de passe",
|
||||||
"Send an email to the user with provisioning information": "Envoyer un email à l'utilisateur avec les informations de déploiement",
|
"Send an email to the user with provisioning information": "Envoyer un email à l'utilisateur avec les informations de déploiement",
|
||||||
"Send": "Envoyer",
|
"Send": "Envoyer",
|
||||||
|
|
@ -293,6 +297,7 @@
|
||||||
"You can now continue your registration process in the application": "Vous pouvez maintenant continuer le processus d'inscription dans l'application",
|
"You can now continue your registration process in the application": "Vous pouvez maintenant continuer le processus d'inscription dans l'application",
|
||||||
"You didn't receive the code?": "Vous n'avez pas reçu le code ?",
|
"You didn't receive the code?": "Vous n'avez pas reçu le code ?",
|
||||||
"Your account recovery code":"Votre code de récupération de compte",
|
"Your account recovery code":"Votre code de récupération de compte",
|
||||||
|
"Your color will be snapped to the nearest 500 shade" : "La couleur que vous entrez sera automatiquement remplacée par sa variante 500 la plus proche.",
|
||||||
"Your password was updated properly.": "Votre mot de passe a été mis à jour.",
|
"Your password was updated properly.": "Votre mot de passe a été mis à jour.",
|
||||||
"Your password" : "Votre mot de passe",
|
"Your password" : "Votre mot de passe",
|
||||||
"Your space :space is expiring in :count days": "Votre espace :space expire dans :count jours",
|
"Your space :space is expiring in :count days": "Votre espace :space expire dans :count jours",
|
||||||
|
|
|
||||||
71
flexiapi/public/css/form.css
vendored
71
flexiapi/public/css/form.css
vendored
|
|
@ -183,13 +183,13 @@ form div .btn.oppose {
|
||||||
right: 0;
|
right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
form div input,
|
form div input:not([type=range]),
|
||||||
form div textarea,
|
form div textarea,
|
||||||
form div select {
|
form div select {
|
||||||
padding: 1rem 2rem;
|
padding: 1rem 2rem;
|
||||||
background-color: var(--grey-1);
|
background-color: var(--grey-1);
|
||||||
border-radius: 3rem;
|
border-radius: 3rem;
|
||||||
border: 1px solid var(--grey-2);
|
border: 0.063rem solid var(--grey-2);
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
resize: vertical;
|
resize: vertical;
|
||||||
}
|
}
|
||||||
|
|
@ -261,6 +261,7 @@ input[type=number].digit {
|
||||||
height: 5rem;
|
height: 5rem;
|
||||||
-moz-appearance: textfield;
|
-moz-appearance: textfield;
|
||||||
-webkit-appearance: textfield;
|
-webkit-appearance: textfield;
|
||||||
|
appearance:textfield;
|
||||||
border-radius: 1.5rem;
|
border-radius: 1.5rem;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
|
|
@ -282,7 +283,7 @@ form div input[type=checkbox] {
|
||||||
margin-right: 1rem;
|
margin-right: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
form div input:not([type=checkbox]):not([type=radio]):not([type="number"].digit):not(.btn),
|
form div input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type="number"].digit):not(.btn),
|
||||||
form div textarea,
|
form div textarea,
|
||||||
form div select {
|
form div select {
|
||||||
margin-top: 2.5rem;
|
margin-top: 2.5rem;
|
||||||
|
|
@ -338,6 +339,70 @@ form div textarea:invalid:not(:placeholder-shown)+label {
|
||||||
color: var(--danger);
|
color: var(--danger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Image and Logo Picker */
|
||||||
|
|
||||||
|
form div .picker {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 11rem;
|
||||||
|
gap: 1.5rem;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
form canvas, .picker .color-div {
|
||||||
|
aspect-ratio: 1/1;
|
||||||
|
height: 100%;
|
||||||
|
border: 0.063rem solid var(--grey-2);
|
||||||
|
border-radius: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
form canvas {
|
||||||
|
background-color: var(--grey-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.picker .color-div {
|
||||||
|
background-color: var(--main-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
form input[type=range] {
|
||||||
|
appearance: none;
|
||||||
|
margin-top: 2.5rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
height: 1.5rem;
|
||||||
|
border-radius: 3rem;
|
||||||
|
overflow: visible;
|
||||||
|
background: linear-gradient(
|
||||||
|
to right,
|
||||||
|
hsl(0, 100%, 50%),
|
||||||
|
hsl(60, 100%, 50%),
|
||||||
|
hsl(120, 100%, 50%),
|
||||||
|
hsl(180, 100%, 50%),
|
||||||
|
hsl(240, 100%, 50%),
|
||||||
|
hsl(300, 100%, 50%),
|
||||||
|
hsl(360, 100%, 50%)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=range]::-webkit-slider-thumb {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 1.5rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 0.25rem solid var(--grey-1);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mandatory for Mozilla Firefox */
|
||||||
|
input[type=range]::-moz-range-thumb {
|
||||||
|
width: 1.25rem;
|
||||||
|
height: 1.25rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 0.25rem solid var(--grey-1);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
/* Checkbox element */
|
/* Checkbox element */
|
||||||
|
|
||||||
form div.checkbox {
|
form div.checkbox {
|
||||||
|
|
|
||||||
2
flexiapi/public/css/style.css
vendored
2
flexiapi/public/css/style.css
vendored
|
|
@ -300,7 +300,7 @@ header nav a#logo::before {
|
||||||
width: 3rem;
|
width: 3rem;
|
||||||
height: 3rem;
|
height: 3rem;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
background-image: url('../img/logo.svg');
|
background-image: var(--space-logo ,url('../img/logo.svg'));
|
||||||
background-color: var(--main-5);
|
background-color: var(--main-5);
|
||||||
background-size: 3rem;
|
background-size: 3rem;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
|
|
|
||||||
139
flexiapi/public/scripts/colorPicker.js
vendored
Normal file
139
flexiapi/public/scripts/colorPicker.js
vendored
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
// Color picker
|
||||||
|
function onColorSliderChange(input) {
|
||||||
|
const group = input.closest('.color-picker-group');
|
||||||
|
const hue = input.value;
|
||||||
|
|
||||||
|
group.querySelector('input[type=hidden]').value = hue;
|
||||||
|
group.querySelector('input[type=text]').value = hslToHex(hue, 100, 50);
|
||||||
|
group.querySelector('.color-div').style.backgroundColor = hslToHex(hue, 100, 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onColorInputChange(input) {
|
||||||
|
const hex = input.value.trim();
|
||||||
|
if (!hex.match(/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const group = input.closest('.color-picker-group');
|
||||||
|
const colorHsl = hexToHsl(hex);
|
||||||
|
group.querySelector('input[type=hidden]').value = colorHsl;
|
||||||
|
group.querySelector('input[type=range]').value = colorHsl;
|
||||||
|
group.querySelector('input[type=text]').value = hslToHex(colorHsl.h, 100, 50);
|
||||||
|
group.querySelector('.color-div').style.backgroundColor = hslToHex(colorHsl.h, 100, 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function hslToHex(h, s, l) {
|
||||||
|
s /= 100;
|
||||||
|
l /= 100;
|
||||||
|
|
||||||
|
const k = n => (n + h / 30) % 12;
|
||||||
|
const a = s * Math.min(l, 1 - l);
|
||||||
|
const f = n => Math.round(255 * (l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)))));
|
||||||
|
|
||||||
|
const toHex = v => v.toString(16).padStart(2, '0');
|
||||||
|
return `#${toHex(f(0))}${toHex(f(8))}${toHex(f(4))}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hexToHsl(hex) {
|
||||||
|
hex = hex.replace(/^#/, '');
|
||||||
|
if (hex.length === 3) hex = hex.split('').map(c => c + c).join('');
|
||||||
|
|
||||||
|
const r = parseInt(hex.slice(0, 2), 16) / 255;
|
||||||
|
const g = parseInt(hex.slice(2, 4), 16) / 255;
|
||||||
|
const b = parseInt(hex.slice(4, 6), 16) / 255;
|
||||||
|
|
||||||
|
const max = Math.max(r, g, b);
|
||||||
|
const min = Math.min(r, g, b);
|
||||||
|
const d = max - min;
|
||||||
|
let h, s;
|
||||||
|
let l = (max + min) / 2;
|
||||||
|
|
||||||
|
if (d === 0) {
|
||||||
|
h = s = 0;
|
||||||
|
} else {
|
||||||
|
s = d / (l > 0.5 ? 2 - max - min : max + min);
|
||||||
|
switch (max) {
|
||||||
|
case r: h = ((g - b) / d + (g < b ? 6 : 0)) / 6; break;
|
||||||
|
case g: h = ((b - r) / d + 2) / 6; break;
|
||||||
|
case b: h = ((r - g) / d + 4) / 6; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
h: Math.round(h * 360),
|
||||||
|
s: Math.round(s * 100),
|
||||||
|
l: Math.round(l * 100),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Image picker
|
||||||
|
function onImageLoad(input) {
|
||||||
|
const file = input.files[0];
|
||||||
|
if (!file) return;
|
||||||
|
if (!file.type.match('image.*')) {
|
||||||
|
console.log("Error: not an image");
|
||||||
|
imgInput.value = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = URL.createObjectURL(file);
|
||||||
|
const img = new Image();
|
||||||
|
|
||||||
|
const group = input.closest('.image-picker-group');
|
||||||
|
const canvas = group.querySelector('canvas');
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
|
||||||
|
img.onload = () => {
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
drawImageProp(ctx, img);
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
|
||||||
|
canvas.toBlob((blob) => {
|
||||||
|
const croppedFile = new File([blob], 'logo.png', { type: 'image/png' });
|
||||||
|
const dataTransfer = new DataTransfer();
|
||||||
|
dataTransfer.items.add(croppedFile);
|
||||||
|
input.files = dataTransfer.files; // ← remplace le fichier original
|
||||||
|
}, 'image/png');
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
img.src = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
function initImageLoader() {
|
||||||
|
document.querySelectorAll('.image-picker-group').forEach(group => {
|
||||||
|
const canvas = group.querySelector('canvas');
|
||||||
|
const rect = canvas.getBoundingClientRect();
|
||||||
|
canvas.width = rect.width;
|
||||||
|
canvas.height = rect.height;
|
||||||
|
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
ctx.fillStyle = "#4e6074";
|
||||||
|
ctx.font = "20px Noto Sans";
|
||||||
|
ctx.textBaseline = "middle";
|
||||||
|
|
||||||
|
const text = "Logo";
|
||||||
|
const textWidth = ctx.measureText(text).width;
|
||||||
|
ctx.fillText(text, (canvas.width - textWidth) / 2, canvas.height / 2);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawImageProp(ctx, img, padding = 1) {
|
||||||
|
const canvas = ctx.canvas;
|
||||||
|
const maxW = canvas.width - padding * 2;
|
||||||
|
const maxH = canvas.height - padding * 2;
|
||||||
|
|
||||||
|
const scale = Math.min(maxW / img.width, maxH / img.height);
|
||||||
|
|
||||||
|
const nw = img.width * scale;
|
||||||
|
const nh = img.height * scale;
|
||||||
|
|
||||||
|
const x = (canvas.width - nw) / 2;
|
||||||
|
const y = (canvas.height - nh) / 2;
|
||||||
|
|
||||||
|
ctx.drawImage(img, x, y, nw, nh);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", initImageLoader);
|
||||||
|
|
@ -17,12 +17,37 @@
|
||||||
@include('admin.space.head')
|
@include('admin.space.head')
|
||||||
@include('admin.space.tabs')
|
@include('admin.space.tabs')
|
||||||
|
|
||||||
<form method="POST"
|
<form method="POST" action="{{ route('admin.spaces.configuration.update', $space) }}" accept-charset="UTF-8"
|
||||||
action="{{ route('admin.spaces.configuration.update', $space) }}"
|
enctype="multipart/form-data">
|
||||||
accept-charset="UTF-8">
|
|
||||||
@csrf
|
@csrf
|
||||||
@method('put')
|
@method('put')
|
||||||
|
|
||||||
|
<h3 class="large">{{ __('Platform customization') }}</h3>
|
||||||
|
|
||||||
|
<div class="image-picker-group">
|
||||||
|
<label for="logo" style="font-weight: 700;">{{ __('Select an image') }} </label>
|
||||||
|
<div class="picker">
|
||||||
|
<canvas></canvas>
|
||||||
|
<input name="logo" type="file" accept="image/*" onchange="onImageLoad(this)">
|
||||||
|
@include('parts.errors', ['name' => 'logo'])
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="color-picker-group">
|
||||||
|
<label for="color-slider" style="font-weight: 700;">{{ __('Select a color') }} </label>
|
||||||
|
<input name="theme_hue" type="hidden" value="22">
|
||||||
|
<div class="picker">
|
||||||
|
<div class="color-div"></div>
|
||||||
|
<div>
|
||||||
|
<input type="text" value="#ff5e00" onblur="onColorInputChange(this)">
|
||||||
|
<label for="color-input">{{ __('Hex') }}</label>
|
||||||
|
<input class="range" type="range" min="0" max="360" value="22"
|
||||||
|
oninput="onColorSliderChange(this)">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span class="supporting"> {{ __('Your color will be snapped to the nearest 500 shade') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="large">
|
<div class="large">
|
||||||
<textarea name="copyright_text" id="copyright_text">{{ $space->copyright_text }}</textarea>
|
<textarea name="copyright_text" id="copyright_text">{{ $space->copyright_text }}</textarea>
|
||||||
<label for="copyright_text">{{ __('Copyright text') }}</label>
|
<label for="copyright_text">{{ __('Copyright text') }}</label>
|
||||||
|
|
@ -37,21 +62,26 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<input name="newsletter_registration_address" id="newsletter_registration_address" placeholder="email@server.tld" type="email" value="{{ $space->newsletter_registration_address }}">
|
<input name="newsletter_registration_address" id="newsletter_registration_address"
|
||||||
|
placeholder="email@server.tld" type="email" value="{{ $space->newsletter_registration_address }}">
|
||||||
<label for="newsletter_registration_address">{{ __('Newsletter registration email address') }}</label>
|
<label for="newsletter_registration_address">{{ __('Newsletter registration email address') }}</label>
|
||||||
<span class="supporting">{{ __('An email will be sent to this email when someone join the newsletter') }}</span>
|
<span
|
||||||
|
class="supporting">{{ __('An email will be sent to this email when someone join the newsletter') }}</span>
|
||||||
@include('parts.errors', ['name' => 'newsletter_registration_address'])
|
@include('parts.errors', ['name' => 'newsletter_registration_address'])
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<input name="account_proxy_registrar_address" id="account_proxy_registrar_address" placeholder="server.tld" value="{{ $space->account_proxy_registrar_address }}">
|
<input name="account_proxy_registrar_address" id="account_proxy_registrar_address" placeholder="server.tld"
|
||||||
|
value="{{ $space->account_proxy_registrar_address }}">
|
||||||
<label for="account_proxy_registrar_address">Account proxy registrar address</label>
|
<label for="account_proxy_registrar_address">Account proxy registrar address</label>
|
||||||
<span class="supporting">Will be used for informational purpose in the user panel and communication emails</span>
|
<span class="supporting">Will be used for informational purpose in the user panel and communication
|
||||||
|
emails</span>
|
||||||
@include('parts.errors', ['name' => 'account_proxy_registrar_address'])
|
@include('parts.errors', ['name' => 'account_proxy_registrar_address'])
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<input name="account_realm" @if ($space->accounts()->count() > 0)disabled @endif id="account_realm" placeholder="server.tld" value="{{ $space->account_realm }}">
|
<input name="account_realm" @if ($space->accounts()->count() > 0) disabled @endif id="account_realm"
|
||||||
|
placeholder="server.tld" value="{{ $space->account_realm }}">
|
||||||
<label for="account_realm">Account realm</label>
|
<label for="account_realm">Account realm</label>
|
||||||
<span class="supporting">A custom realm for the Space accounts</span>
|
<span class="supporting">A custom realm for the Space accounts</span>
|
||||||
@include('parts.errors', ['name' => 'account_realm'])
|
@include('parts.errors', ['name' => 'account_realm'])
|
||||||
|
|
@ -63,31 +93,52 @@
|
||||||
<textarea style="min-height: 200px;" name="custom_provisioning_entries" id="custom_provisioning_entries">{{ $space->custom_provisioning_entries }}</textarea>
|
<textarea style="min-height: 200px;" name="custom_provisioning_entries" id="custom_provisioning_entries">{{ $space->custom_provisioning_entries }}</textarea>
|
||||||
<label for="custom_provisioning_entries">{{ __('Custom entries') }}</label>
|
<label for="custom_provisioning_entries">{{ __('Custom entries') }}</label>
|
||||||
<span class="supporting">{{ __('In ini format, will complete the other settings.') }}</span>
|
<span class="supporting">{{ __('In ini format, will complete the other settings.') }}</span>
|
||||||
<span class="supporting">{{ __('Use ; to comment, key="value" to declare a complex string.') }} <a target="_blank" href="https://cheatsheets.zip/ini.html">{{ __('Checkout the cheatsheets to know how to format things correctly.') }}</a></span>
|
<span class="supporting">{{ __('Use ; to comment, key="value" to declare a complex string.') }} <a
|
||||||
|
target="_blank"
|
||||||
|
href="https://cheatsheets.zip/ini.html">{{ __('Checkout the cheatsheets to know how to format things correctly.') }}</a></span>
|
||||||
@include('parts.errors', ['name' => 'custom_provisioning_entries'])
|
@include('parts.errors', ['name' => 'custom_provisioning_entries'])
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@include('parts.form.toggle', ['object' => $space, 'key' => 'custom_provisioning_overwrite_all', 'label' => __('Allow client settings to be overwritten by the provisioning ones')])
|
@include('parts.form.toggle', [
|
||||||
|
'object' => $space,
|
||||||
|
'key' => 'custom_provisioning_overwrite_all',
|
||||||
|
'label' => __('Allow client settings to be overwritten by the provisioning ones'),
|
||||||
|
])
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@include('parts.form.toggle', ['object' => $space, 'key' => 'provisioning_use_linphone_provisioning_header', 'label' => 'Enforce X-Linphone-Provisioning header'])
|
@include('parts.form.toggle', [
|
||||||
|
'object' => $space,
|
||||||
|
'key' => 'provisioning_use_linphone_provisioning_header',
|
||||||
|
'label' => 'Enforce X-Linphone-Provisioning header',
|
||||||
|
])
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3 class="large">{{ __('Features') }}</h3>
|
<h3 class="large">{{ __('Features') }}</h3>
|
||||||
<div>
|
<div>
|
||||||
@include('parts.form.toggle', ['object' => $space, 'key' => 'public_registration', 'label' => __('Public registration')])
|
@include('parts.form.toggle', [
|
||||||
</div>
|
'object' => $space,
|
||||||
<div
|
'key' => 'public_registration',
|
||||||
@include('parts.form.toggle', ['object' => $space, 'key' => 'phone_registration', 'label' => __('Phone registration')])
|
'label' => __('Public registration'),
|
||||||
</div>
|
])
|
||||||
<div>
|
|
||||||
@include('parts.form.toggle', ['object' => $space, 'key' => 'intercom_features', 'label' => __('Intercom features')])
|
|
||||||
</div>
|
</div>
|
||||||
|
<div @include('parts.form.toggle', [
|
||||||
|
'object' => $space,
|
||||||
|
'key' => 'phone_registration',
|
||||||
|
'label' => __('Phone registration'),
|
||||||
|
]) </div>
|
||||||
|
<div>
|
||||||
|
@include('parts.form.toggle', [
|
||||||
|
'object' => $space,
|
||||||
|
'key' => 'intercom_features',
|
||||||
|
'label' => __('Intercom features'),
|
||||||
|
])
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="large">
|
<div class="large">
|
||||||
<input class="btn" type="submit" value="{{ __('Update') }}">
|
<input class="btn" type="submit" value="{{ __('Update') }}">
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
<script src="{{ asset('scripts/colorPicker.js') }}"></script>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,8 @@
|
||||||
<body class="@if (isset($welcome) && $welcome) welcome @endif">
|
<body class="@if (isset($welcome) && $welcome) welcome @endif">
|
||||||
<header>
|
<header>
|
||||||
<nav>
|
<nav>
|
||||||
<a id="logo" href="{{ route('account.home') }}"><span
|
<a id="logo" href="{{ route('account.home') }}"
|
||||||
|
@if ($space->logo) style="--space-logo: url('{{ asset('storage/' . $space->logo) }}')" @endif><span
|
||||||
class="on_desktop">{{ space()->name }}</span></a>
|
class="on_desktop">{{ space()->name }}</span></a>
|
||||||
|
|
||||||
@if (!isset($welcome) || $welcome == false)
|
@if (!isset($welcome) || $welcome == false)
|
||||||
|
|
@ -67,13 +68,13 @@
|
||||||
@if (!isset($welcome) || $welcome == false)
|
@if (!isset($welcome) || $welcome == false)
|
||||||
<section @if (isset($grid) && $grid) class="grid" @endif>
|
<section @if (isset($grid) && $grid) class="grid" @endif>
|
||||||
|
|
||||||
@hasSection('breadcrumb')
|
@hasSection('breadcrumb')
|
||||||
<nav aria-label="breadcrumb">
|
<nav aria-label="breadcrumb">
|
||||||
<ol class="breadcrumb">
|
<ol class="breadcrumb">
|
||||||
@yield('breadcrumb')
|
@yield('breadcrumb')
|
||||||
</ol>
|
</ol>
|
||||||
</nav>
|
</nav>
|
||||||
@endif
|
@endif
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@include('parts.errors')
|
@include('parts.errors')
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue