Manual mails can be sent
This commit is contained in:
@@ -12,8 +12,6 @@ class CertificateOfConductionCheckCommand {
|
||||
public function execute() : CertificateOfConductionCheckResponse {
|
||||
$response = new CertificateOfConductionCheckResponse();
|
||||
|
||||
|
||||
|
||||
$localGroup = str_replace('Stamm ', '', $this->request->participant->localGroup()->first()->name);
|
||||
|
||||
$apiResponse = Http::acceptJson()
|
||||
|
||||
@@ -190,6 +190,7 @@ class DetailsController extends CommonController {
|
||||
|
||||
return response()->json([
|
||||
'participants' => $participants,
|
||||
'listType' => $listType,
|
||||
'event' => $event->toResource()->toArray($request)
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Event\Controllers\MailCompose;
|
||||
|
||||
use App\Scopes\CommonController;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ByGroupController extends CommonController
|
||||
{
|
||||
public function __invoke(string $eventIdentifier, string $groupType, Request $request) {
|
||||
$event = $this->events->getByIdentifier($eventIdentifier, true);
|
||||
$recipients = [];
|
||||
switch ($groupType) {
|
||||
case 'by-local-group':
|
||||
$participants = $this->eventParticipants->groupByLocalGroup($event, $request, $request->input('groupName'));
|
||||
$recipients = $this->eventParticipants->getMailAddresses($participants[$request->input('groupName')]);
|
||||
break;
|
||||
case 'by-participation-group':
|
||||
$participants = $this->eventParticipants->groupByParticipationType($event, $request, $request->input('groupName'));
|
||||
$recipients = $this->eventParticipants->getMailAddresses($participants[$request->input('groupName')]);
|
||||
break;
|
||||
case 'signed-off':
|
||||
$participants = $this->eventParticipants->getSignedOffParticipants($event, $request, $request->input('groupName'));
|
||||
$recipients = $this->eventParticipants->getMailAddresses($participants[$request->input('groupName')]);
|
||||
break;
|
||||
default:
|
||||
$participants = $this->eventParticipants->getForList($event, $request);
|
||||
$recipients = $this->eventParticipants->getMailAddresses($participants);
|
||||
|
||||
}
|
||||
|
||||
return response()->json(['recipients' => $recipients]);
|
||||
}
|
||||
}
|
||||
66
app/Domains/Event/Controllers/MailCompose/SendController.php
Normal file
66
app/Domains/Event/Controllers/MailCompose/SendController.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Event\Controllers\MailCompose;
|
||||
|
||||
use App\Mail\ManualMails\ManualMailsCommonMail;
|
||||
use App\Mail\ManualMails\ManualMailsReportMail;
|
||||
use App\Mail\ParticipantCocMails\ParticipantCocCompleteMail;
|
||||
use App\Scopes\CommonController;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
class SendController extends CommonController
|
||||
{
|
||||
public function __invoke(string $eventIdentifier, Request $request) {
|
||||
$recipients = $request->input('recipients')
|
||||
|> function (string $value) : string { return str_replace(';', ',', $value); }
|
||||
|> function (string $value) : array { return explode( ',', $value); };
|
||||
|
||||
$event = $this->events->getByIdentifier($eventIdentifier, true)->toResource()->toArray($request);
|
||||
$sentRecipients = [];
|
||||
$allOkay = true;
|
||||
$subject = $request->input('subject') ?? 'Neue Nachricht zu Veranstaltung "' . $event['name'] . '"';
|
||||
|
||||
foreach ($recipients as $recipient) {
|
||||
if (in_array($recipient, $sentRecipients)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sentRecipients[] = $recipient;
|
||||
try {
|
||||
Mail::to(trim($recipient))->send(new ManualMailsCommonMail(
|
||||
mailSubject: $subject,
|
||||
message: $request->input('message'),
|
||||
event: $event,
|
||||
));
|
||||
} catch (\Exception $e) {
|
||||
$allOkay = false;
|
||||
}
|
||||
}
|
||||
|
||||
$user = auth()->user();
|
||||
$reportSubject = sprintf('Sendebericht für Nachricht mit Betreff "%s"', $subject);
|
||||
|
||||
Mail::to($user->email)->send(new ManualMailsReportMail(
|
||||
mailSubject: $reportSubject,
|
||||
message: $request->input('message'),
|
||||
event: $event,
|
||||
originalRecipients: $sentRecipients
|
||||
));
|
||||
|
||||
if ($allOkay) {
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => sprintf(
|
||||
'E-Mail wurde erfolgreich an %1$s Personen versendet. Du hast eine Kopie an deine Mail-Adresse erhalten.',
|
||||
count($sentRecipients)
|
||||
),
|
||||
]);
|
||||
} else {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Es gab einen Fehler beim Versenden der Nachrichten.'
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
use App\Domains\Event\Controllers\CreateController;
|
||||
use App\Domains\Event\Controllers\DetailsController;
|
||||
use App\Domains\Event\Controllers\MailCompose\ByGroupController;
|
||||
use App\Domains\Event\Controllers\MailCompose\SendController;
|
||||
use App\Domains\Event\Controllers\ParticipantController;
|
||||
use App\Domains\Event\Controllers\ParticipantPaymentController;
|
||||
use App\Domains\Event\Controllers\ParticipantReSignOnController;
|
||||
@@ -21,6 +23,11 @@ Route::prefix('api/v1')
|
||||
Route::middleware(['auth'])->group(function () {
|
||||
Route::post('/create', [CreateController::class, 'doCreate']);
|
||||
|
||||
Route::prefix('{eventIdentifier}/mailing')->group(function () {
|
||||
Route::post('/compose/to-group/{groupType}', ByGroupController::class);
|
||||
Route::post('/send', SendController::class);
|
||||
});
|
||||
|
||||
Route::prefix('/details/{eventId}') ->group(function () {
|
||||
Route::get('/summary', [DetailsController::class, 'summary']);
|
||||
|
||||
|
||||
104
app/Domains/Event/Views/Partials/MailCompose.vue
Normal file
104
app/Domains/Event/Views/Partials/MailCompose.vue
Normal file
@@ -0,0 +1,104 @@
|
||||
<script setup>
|
||||
import {onMounted, reactive, ref} from "vue";
|
||||
import {useAjax} from "../../../../../resources/js/components/ajaxHandler.js";
|
||||
import TextEditor from "../../../../Views/Components/TextEditor.vue";
|
||||
import ErrorText from "../../../../Views/Components/ErrorText.vue";
|
||||
import {toast} from "vue3-toastify";
|
||||
const { request } = useAjax();
|
||||
|
||||
|
||||
const props = defineProps({
|
||||
event: Object,
|
||||
mailToType: String,
|
||||
recipientIdentifier: String,
|
||||
})
|
||||
|
||||
const data = reactive({
|
||||
recipients: null,
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
const groupTypes = ['all', 'signed-off', 'by-local-group', 'by-participation-group'];
|
||||
|
||||
if (!groupTypes.includes(props.mailToType)) {
|
||||
console.error('Unknown recipient identifier:', props.recipientIdentifier);
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await request('/api/v1/event/' + props.event.identifier + '/mailing/compose/to-group/' + props.mailToType, {
|
||||
method: "POST",
|
||||
body: {
|
||||
groupName: props.recipientIdentifier
|
||||
}
|
||||
});
|
||||
|
||||
data.recipients = response.recipients;
|
||||
form.recipients = data.recipients.join(', ');
|
||||
});
|
||||
|
||||
const errorMessage = ref(null)
|
||||
|
||||
const emit = defineEmits([
|
||||
'closeComposer',
|
||||
|
||||
]);
|
||||
|
||||
function close() {
|
||||
emit('closeComposer');
|
||||
}
|
||||
|
||||
|
||||
async function sendMail() {
|
||||
const response = await request('/api/v1/event/' + props.event.identifier + '/mailing/send', {
|
||||
method: "POST",
|
||||
body: {
|
||||
recipients: form.recipients,
|
||||
subject: form.subject,
|
||||
message: form.message,
|
||||
}
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
close();
|
||||
toast.success(response.message)
|
||||
|
||||
} else {
|
||||
errorMessage.value = response.message
|
||||
toast.error(response.message)
|
||||
}
|
||||
}
|
||||
|
||||
const form = reactive({
|
||||
recipients: '',
|
||||
sendCopy: true,
|
||||
subject: '',
|
||||
message: '',
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h2>E-Mail senden</h2>
|
||||
<div style="display: flex; flex-direction: column; gap: 12px;">
|
||||
<div>
|
||||
<label style="font-weight: bold">Empfänger*innen</label>
|
||||
<textarea v-model="form.recipients" placeholder="Senden an" style="width: 100%;" rows="3"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<label style="font-weight: bold">Betreff</label>
|
||||
<input type="text" v-model="form.subject" placeholder="Betreff" style="width: 100%;" />
|
||||
</div><br /><br />
|
||||
<div>
|
||||
<label style="font-weight: bold">Nachricht</label>
|
||||
<TextEditor v-model="form.message" />
|
||||
</div>
|
||||
<strong><ErrorText :message="errorMessage" /></strong>
|
||||
|
||||
</div>
|
||||
|
||||
<input type="button" @click="sendMail" value="Senden" class="" />
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -5,6 +5,8 @@
|
||||
import CommonSettings from "./CommonSettings.vue";
|
||||
import EventManagement from "./EventManagement.vue";
|
||||
import Modal from "../../../../Views/Components/Modal.vue";
|
||||
import MailCompose from "./MailCompose.vue";
|
||||
import FullScreenModal from "../../../../Views/Components/FullScreenModal.vue";
|
||||
|
||||
const props = defineProps({
|
||||
data: Object,
|
||||
@@ -47,6 +49,11 @@
|
||||
Object.assign(dynamicProps, data);
|
||||
});
|
||||
|
||||
const mailCompose = ref(false);
|
||||
|
||||
function mailToGroup() {
|
||||
mailCompose.value = true
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -85,7 +92,7 @@
|
||||
</a><br/>
|
||||
<input type="button" class="fix-button" value="Zahlungserinnerung senden" /><br/>
|
||||
<input type="button" class="deny-button" value="Letzte Mahnung senden" /><br/>
|
||||
<input type="button" value="Rundmail senden" /><br/>
|
||||
<input type="button" value="Rundmail senden" @click="mailToGroup" /><br/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="event-flexbox-row bottom">
|
||||
@@ -130,6 +137,14 @@
|
||||
</table>
|
||||
</Modal>
|
||||
|
||||
<FullScreenModal
|
||||
:show="mailCompose"
|
||||
title="E-Mail senden"
|
||||
@close="mailCompose = false"
|
||||
>
|
||||
<MailCompose @closeComposer="mailCompose = false" :event="dynamicProps.event" mailToType="all" recipientIdentifier="Alle Teilnehmenden" />
|
||||
</FullScreenModal>
|
||||
|
||||
</template>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
import { computed, reactive, ref } from "vue";
|
||||
import Modal from "../../../../Views/Components/Modal.vue";
|
||||
import ParticipantData from "./ParticipantData.vue";
|
||||
import MailCompose from "./MailCompose.vue";
|
||||
import {toast} from "vue3-toastify";
|
||||
import {useAjax} from "../../../../../resources/js/components/ajaxHandler.js";
|
||||
import {format, getDay, getMonth, getYear} from "date-fns";
|
||||
import AmountInput from "../../../../Views/Components/AmountInput.vue";
|
||||
import FullScreenModal from "../../../../Views/Components/FullScreenModal.vue";
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
@@ -14,6 +16,7 @@ const props = defineProps({
|
||||
localGroups: {},
|
||||
participants: {},
|
||||
event: {},
|
||||
listType: '',
|
||||
}),
|
||||
},
|
||||
});
|
||||
@@ -31,6 +34,8 @@ const showParticipantDetails = ref(false);
|
||||
const showParticipant = ref(null);
|
||||
const editMode = ref(false);
|
||||
|
||||
const mailCompose = ref(false);
|
||||
|
||||
const openCancelDialog = ref(false);
|
||||
const openPartialPaymentDialogSwitch = ref(false);
|
||||
|
||||
@@ -42,8 +47,6 @@ function openParticipantDetails(input) {
|
||||
editMode.value = false;
|
||||
}
|
||||
|
||||
console.log(props.data.participants)
|
||||
|
||||
async function saveParticipant(formData) {
|
||||
if (!showParticipant.value?.identifier) {
|
||||
return;
|
||||
@@ -283,6 +286,15 @@ async function execPartialPayment() {
|
||||
openPartialPaymentDialogSwitch.value = false;
|
||||
}
|
||||
|
||||
const mailToType = ref('')
|
||||
const recipientIdentifier = ref('')
|
||||
|
||||
function mailToGroup(groupKey) {
|
||||
recipientIdentifier.value = groupKey;
|
||||
mailToType.value = props.data.listType;
|
||||
mailCompose.value = true
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -383,7 +395,7 @@ async function execPartialPayment() {
|
||||
27 Jahre und älter: <strong>{{ getAgeCounts(participants)['27+'] ?? 0 }}</strong>
|
||||
</td>
|
||||
<td>
|
||||
E-Mail an Gruppe senden
|
||||
<input type="button" class="button" @click="mailToGroup(groupKey)" value="E-Mail an Gruppe senden" />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -394,7 +406,7 @@ async function execPartialPayment() {
|
||||
<Modal
|
||||
:show="showParticipantDetails"
|
||||
title="Anmeldedetails ansehen"
|
||||
@close="showParticipantDetails = false;toast.success('HALLO');"
|
||||
@close="showParticipantDetails = false;"
|
||||
>
|
||||
<ParticipantData
|
||||
@cancelParticipation="openCancelParticipationDialog"
|
||||
@@ -433,6 +445,13 @@ async function execPartialPayment() {
|
||||
<button class="button" @click="execPartialPayment()">Teilbetrag buchen</button>
|
||||
</Modal>
|
||||
|
||||
<FullScreenModal
|
||||
:show="mailCompose"
|
||||
title="E-Mail senden"
|
||||
@close="mailCompose = false"
|
||||
>
|
||||
<MailCompose @closeComposer="mailCompose = false" :event="event" :mailToType="mailToType" :recipientIdentifier="recipientIdentifier" />
|
||||
</FullScreenModal>
|
||||
|
||||
|
||||
|
||||
|
||||
59
app/Mail/ManualMails/ManualMailsCommonMail.php
Normal file
59
app/Mail/ManualMails/ManualMailsCommonMail.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail\ManualMails;
|
||||
|
||||
use App\Models\Event;
|
||||
use App\Models\EventParticipant;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Attachment;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
|
||||
class ManualMailsCommonMail extends Mailable {
|
||||
public function __construct(
|
||||
private string $mailSubject,
|
||||
private string $message,
|
||||
private array $event,
|
||||
|
||||
)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message envelope.
|
||||
*/
|
||||
public function envelope(): Envelope
|
||||
{
|
||||
return new Envelope(
|
||||
subject: $this->mailSubject,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message content definition.
|
||||
*/
|
||||
public function content(): Content
|
||||
{
|
||||
return new Content(
|
||||
view: 'emails.events.manual_mail',
|
||||
with: [
|
||||
'mailMessage' => ($this->message),
|
||||
'eventTitle' => $this->event['name'],
|
||||
'eventEmail' => $this->event['email'],
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the attachments for the message.
|
||||
*
|
||||
* @return array<int, Attachment>
|
||||
*/
|
||||
public function attachments(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
62
app/Mail/ManualMails/ManualMailsReportMail.php
Normal file
62
app/Mail/ManualMails/ManualMailsReportMail.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail\ManualMails;
|
||||
|
||||
use App\Models\Event;
|
||||
use App\Models\EventParticipant;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Attachment;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
|
||||
class ManualMailsReportMail extends Mailable {
|
||||
public function __construct(
|
||||
private string $mailSubject,
|
||||
private string $message,
|
||||
private array $event,
|
||||
private array $originalRecipients,
|
||||
|
||||
)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message envelope.
|
||||
*/
|
||||
public function envelope(): Envelope
|
||||
{
|
||||
return new Envelope(
|
||||
subject: $this->mailSubject,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message content definition.
|
||||
*/
|
||||
public function content(): Content
|
||||
{
|
||||
return new Content(
|
||||
view: 'emails.events.manual_mail_report',
|
||||
with: [
|
||||
'mailMessage' => ($this->message),
|
||||
'eventTitle' => $this->event['name'],
|
||||
'eventEmail' => $this->event['email'],
|
||||
'recipients' => implode('<br />', $this->originalRecipients),
|
||||
'countRecipients' => count($this->originalRecipients),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the attachments for the message.
|
||||
*
|
||||
* @return array<int, Attachment>
|
||||
*/
|
||||
public function attachments(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -39,31 +39,37 @@ class EventParticipantRepository {
|
||||
return $participant;
|
||||
}
|
||||
|
||||
public function groupByLocalGroup(Event $event, Request $request) : array {
|
||||
public function groupByLocalGroup(Event $event, Request $request, ?string $filter = null) : array {
|
||||
$allParticipants = $this->getForList($event, $request);
|
||||
$participants = [];
|
||||
foreach ($allParticipants as $participant) {
|
||||
$participants[$participant['localgroup']][] = $participant;
|
||||
if ($filter === null || $participant['localgroup'] === $filter) {
|
||||
$participants[$participant['localgroup']][] = $participant;
|
||||
}
|
||||
}
|
||||
|
||||
return $participants;
|
||||
}
|
||||
|
||||
public function groupByParticipationType(Event $event, Request $request) : array {
|
||||
public function groupByParticipationType(Event $event, Request $request, ?string $filter = null) : array {
|
||||
$allParticipants = $this->getForList($event, $request);
|
||||
$participants = [];
|
||||
foreach ($allParticipants as $participant) {
|
||||
$participants[$participant['participationType']][] = $participant;
|
||||
if ($filter === null || $participant['participationType'] === $filter) {
|
||||
$participants[$participant['participationType']][] = $participant;
|
||||
}
|
||||
}
|
||||
|
||||
return $participants;
|
||||
}
|
||||
|
||||
public function getSignedOffParticipants(Event $event, Request $request) : array {
|
||||
public function getSignedOffParticipants(Event $event, Request $request, ?string $filter = null) : array {
|
||||
$allParticipants = $this->getForList($event, $request, true);
|
||||
$participants = [];
|
||||
foreach ($allParticipants as $participant) {
|
||||
$participants[$participant['participationType']][] = $participant;
|
||||
if ($filter === null || $participant['participationType'] === $filter) {
|
||||
$participants[$participant['participationType']][] = $participant;
|
||||
}
|
||||
}
|
||||
|
||||
return $participants;
|
||||
@@ -147,4 +153,18 @@ class EventParticipantRepository {
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getMailAddresses(array $participants) : array {
|
||||
$mailAddresses = [];
|
||||
foreach ($participants as $participant) {
|
||||
if (!in_array($participant['email_1'], $mailAddresses)) {
|
||||
$mailAddresses[] = $participant['email_1'];
|
||||
}
|
||||
|
||||
if ($participant['email_2'] !== null && !in_array($participant['email_2'], $mailAddresses)) {
|
||||
$mailAddresses[] = $participant['email_2'];
|
||||
}
|
||||
}
|
||||
return $mailAddresses;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,26 +40,29 @@ function close() {
|
||||
|
||||
// ESC-Key & Focus-Trap
|
||||
function handleKeyDown(e) {
|
||||
if (e.key === 'Escape') {
|
||||
close()
|
||||
}
|
||||
if (e.key === 'Tab' && modalRef.value) {
|
||||
const focusable = modalRef.value.querySelectorAll(
|
||||
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
|
||||
)
|
||||
if (focusable.length === 0) return
|
||||
|
||||
const first = focusable[0]
|
||||
const last = focusable[focusable.length - 1]
|
||||
|
||||
if (e.shiftKey && document.activeElement === first) {
|
||||
e.preventDefault()
|
||||
last.focus()
|
||||
} else if (!e.shiftKey && document.activeElement === last) {
|
||||
e.preventDefault()
|
||||
first.focus()
|
||||
if (e.key === 'Escape') {
|
||||
close()
|
||||
}
|
||||
if (e.key === 'Tab' && modalRef.value) {
|
||||
// Wenn der Fokus in einem iframe (z.B. TinyMCE) liegt, nicht eingreifen
|
||||
if (document.activeElement?.tagName === 'IFRAME') return
|
||||
|
||||
const focusable = modalRef.value.querySelectorAll(
|
||||
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"]), iframe'
|
||||
)
|
||||
if (focusable.length === 0) return
|
||||
|
||||
const first = focusable[0]
|
||||
const last = focusable[focusable.length - 1]
|
||||
|
||||
if (e.shiftKey && document.activeElement === first) {
|
||||
e.preventDefault()
|
||||
last.focus()
|
||||
} else if (!e.shiftKey && document.activeElement === last) {
|
||||
e.preventDefault()
|
||||
first.focus()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Body-Scroll sperren
|
||||
@@ -87,27 +90,27 @@ onUnmounted(() => {
|
||||
|
||||
<style scoped>
|
||||
.full-screen-modal-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.full-screen-modal-content {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
position: absolute;
|
||||
top: 30px;
|
||||
bottom: 30px;
|
||||
left: 30px;
|
||||
right: 30px;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
|
||||
outline: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
position: absolute;
|
||||
top: 30px;
|
||||
bottom: 30px;
|
||||
left: 30px;
|
||||
right: 30px;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
|
||||
outline: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.full-screen-modal-body {
|
||||
|
||||
31
app/Views/Components/TextEditor.vue
Normal file
31
app/Views/Components/TextEditor.vue
Normal file
@@ -0,0 +1,31 @@
|
||||
<script setup>
|
||||
import Editor from '@tinymce/tinymce-vue';
|
||||
|
||||
const model = defineModel()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Editor
|
||||
v-model="model"
|
||||
tinymce-script-src="/tinymce/tinymce.min.js"
|
||||
license-key="gpl"
|
||||
:init="{
|
||||
license_key: 'gpl',
|
||||
base_url: '/tinymce',
|
||||
suffix: '.min',
|
||||
menubar: true,
|
||||
plugins: 'link code table lists',
|
||||
toolbar: 'undo redo | blocks bold italic underline | bullist numlist | link | table',
|
||||
language: 'de',
|
||||
language_url: '/tinymce/langs/de.js',
|
||||
ui_mode: 'split',
|
||||
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.tox .tox-promotion {
|
||||
display: none !important;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user