ffplayout/frontend/pages/message.vue

456 lines
18 KiB
Vue

<template>
<div>
<div class="flex flex-col items-center pt-10 px-8">
<div class="mt-2 w-full max-w-4xl">
<div class="flex flex-col xs:flex-row w-full gap-4">
<div class="grow xs:max-w-72">
<select
v-model="selected"
class="select select-sm select-bordered w-full"
@change="onChange($event)"
>
<option v-for="item in presets" :key="item.name">{{ item.name }}</option>
</select>
</div>
<div class="join">
<button
class="btn btn-sm join-item btn-primary"
:title="t('message.savePreset')"
@click="savePreset()"
>
<i class="bi-cloud-upload" />
</button>
<button
class="btn btn-sm join-item btn-primary"
:title="t('message.newPreset')"
@click="showCreateModal = true"
>
<i class="bi-file-plus" />
</button>
<button
class="btn btn-sm join-item btn-primary"
:title="t('message.delPreset')"
@click="showDeleteModal = true"
>
<i class="bi-file-minus" />
</button>
</div>
</div>
<form class="my-6 w-full" @submit.prevent="submitMessage">
<textarea
v-model="form.text"
class="textarea textarea-bordered w-full"
rows="4"
:placeholder="t('message.placeholder')"
/>
<div class="mt-2 grid xs:grid-cols-[auto_150px_150px] gap-4">
<div class="grow">
<div class="form-control">
<label class="cursor-pointer p-0">
<div class="label">
<span class="label-text">{{ t('message.xAxis') }}</span>
</div>
<input
v-model="form.x"
class="input input-sm input-bordered w-full"
type="text"
placeholder="X"
required
/>
</label>
</div>
<div class="form-control">
<label class="cursor-pointer p-0">
<div class="label">
<span class="label-text">{{ t('message.yAxis') }}</span>
</div>
<input
v-model="form.y"
class="input input-sm input-bordered w-full"
type="text"
placeholder="Y"
required
/>
</label>
</div>
</div>
<div class="xs:mt-10">
<div class="form-control">
<label class="label cursor-pointer p-0">
<span class="label-text">{{ t('message.showBox') }}</span>
<input
v-model="form.showBox"
type="checkbox"
class="checkbox checkbox-xs rounded-sm"
/>
</label>
</div>
<label class="mt-2 form-control w-full">
<div class="label">
<span class="label-text">{{ t('message.boxColor') }}</span>
</div>
<input
v-model="form.boxColor"
type="color"
class="input input-sm input-bordered w-full p-1"
required
/>
</label>
</div>
<label class="form-control w-full xs:mt-[68px]">
<div class="label">
<span class="label-text">{{ t('message.boxAlpha') }}</span>
</div>
<input
v-model="form.boxAlpha"
type="number"
min="0"
max="1"
step="0.01"
class="input input-sm input-bordered w-full"
required
/>
</label>
</div>
<div class="grid xs:grid-cols-[150px_150px_auto] gap-4 mt-2">
<div>
<label class="form-control w-full">
<div class="label">
<span class="label-text">{{ t('message.size') }}</span>
</div>
<input
v-model="form.fontSize"
type="number"
class="input input-sm input-bordered w-full"
required
/>
</label>
<label class="form-control w-full mt-2">
<div class="label">
<span class="label-text">{{ t('message.fontColor') }}</span>
</div>
<input
v-model="form.fontColor"
type="color"
class="input input-sm input-bordered w-full p-1"
required
/>
</label>
</div>
<div>
<label class="form-control w-full">
<div class="label">
<span class="label-text">{{ t('message.spacing') }}</span>
</div>
<input
v-model="form.fontSpacing"
type="number"
class="input input-sm input-bordered w-full"
required
/>
</label>
<label class="form-control w-full mt-2">
<div class="label">
<span class="label-text">{{ t('message.fontAlpha') }}</span>
</div>
<input
v-model="form.fontAlpha"
type="number"
class="input input-sm input-bordered w-full"
min="0"
max="1"
step="0.01"
required
/>
</label>
</div>
<div class="grow">
<label class="form-control w-full">
<div class="label">
<span class="label-text">{{ t('message.overallAlpha') }}</span>
</div>
<input
v-model="form.overallAlpha"
type="text"
class="input input-sm input-bordered w-full"
required
/>
</label>
<label class="form-control w-full xs:max-w-[150px] mt-2">
<div class="label">
<span class="label-text">{{ t('message.borderWidth') }}</span>
</div>
<input
v-model="form.border"
type="number"
class="input input-sm input-bordered w-full"
required
/>
</label>
</div>
</div>
<div class="mt-5">
<button class="btn btn-primary send-btn" type="submit">{{ t('message.send') }}</button>
</div>
</form>
</div>
</div>
<GenericModal :show="showCreateModal" :title="t('message.newPreset')" :modal-action="createNewPreset">
<label class="form-control w-full">
<div class="label">
<span class="label-text">{{ t('message.name') }}</span>
</div>
<input v-model="newPresetName" type="text" class="input input-bordered w-full" />
</label>
</GenericModal>
<GenericModal
:show="showDeleteModal"
:title="t('message.delPreset')"
:text="`${t('message.delText')}: <strong> ${selected}</strong>?`"
:modal-action="deletePreset"
/>
</div>
</template>
<script setup lang="ts">
const { t } = useI18n()
const authStore = useAuth()
const configStore = useConfig()
const indexStore = useIndex()
const { i } = storeToRefs(useConfig())
const { numberToHex, hexToNumber } = stringFormatter()
useHead({
title: 'Messages | ffplayout',
})
interface PresetName {
name: string
value: number
}
const form = ref({
id: 0,
name: '',
text: '',
x: '0',
y: '0',
fontSize: 24,
fontSpacing: 4,
fontColor: '#ffffff',
fontAlpha: 1.0,
showBox: true,
boxColor: '#000000',
boxAlpha: 0.8,
border: 4,
overallAlpha: '1',
})
const showCreateModal = ref(false)
const showDeleteModal = ref(false)
const selected = ref(null)
const newPresetName = ref('')
const presets = ref([] as PresetName[])
onMounted(() => {
getPreset(-1)
})
watch([i], () => {
nextTick(() => {
getPreset(-1)
})
})
async function getPreset(index: number) {
fetch(`/api/presets/${configStore.channels[configStore.i].id}`, {
method: 'GET',
headers: authStore.authHeader,
})
.then((response) => response.json())
.then((data) => {
if (index === -1) {
presets.value = [{ value: -1, name: '' }]
for (let i = 0; i < data.length; i++) {
const elem = data[i]
presets.value.push({ value: i, name: elem.name })
}
form.value = {
id: 0,
name: '',
text: '',
x: '0',
y: '0',
fontSize: 24,
fontSpacing: 4,
fontColor: '#ffffff',
fontAlpha: 1.0,
showBox: true,
boxColor: '#000000',
boxAlpha: 0.8,
border: 4,
overallAlpha: '1',
}
} else {
const fColor = data[index].fontcolor.split('@')
const bColor = data[index].boxcolor.split('@')
form.value = {
id: data[index].id,
name: data[index].name,
text: data[index].text,
x: data[index].x,
y: data[index].y,
fontSize: data[index].fontsize,
fontSpacing: data[index].line_spacing,
fontColor: fColor[0],
fontAlpha: fColor[1] ? hexToNumber(fColor[1]) : 1.0,
showBox: data[index].box === '1' ? true : false,
boxColor: bColor[0],
boxAlpha: bColor[1] ? hexToNumber(bColor[1]) : 1.0,
border: data[index].boxborderw,
overallAlpha: data[index].alpha,
}
}
})
}
function onChange(event: any) {
selected.value = event.target.value
getPreset(event.target.selectedIndex - 1)
}
async function savePreset() {
if (selected.value) {
const preset = {
id: form.value.id,
name: form.value.name,
text: form.value.text,
x: form.value.x,
y: form.value.y,
fontsize: form.value.fontSize,
line_spacing: form.value.fontSpacing,
fontcolor:
form.value.fontAlpha === 1
? form.value.fontColor
: form.value.fontColor + '@' + numberToHex(form.value.fontAlpha),
box: form.value.showBox ? '1' : '0',
boxcolor:
form.value.boxAlpha === 1
? form.value.boxColor
: form.value.boxColor + '@' + numberToHex(form.value.boxAlpha),
boxborderw: form.value.border,
alpha: form.value.overallAlpha,
channel_id: configStore.channels[configStore.i].id,
}
const response = await fetch(`/api/presets/${configStore.channels[configStore.i].id}/${form.value.id}`, {
method: 'PUT',
headers: { ...configStore.contentType, ...authStore.authHeader },
body: JSON.stringify(preset),
})
if (response.status === 200) {
indexStore.msgAlert('success', t('message.saveDone'), 2)
} else {
indexStore.msgAlert('error', t('message.saveFailed'), 2)
}
}
}
async function createNewPreset(create: boolean) {
showCreateModal.value = false
if (create) {
const preset = {
name: newPresetName.value,
text: form.value.text,
x: form.value.x.toString(),
y: form.value.y.toString(),
fontsize: form.value.fontSize.toString(),
line_spacing: form.value.fontSpacing.toString(),
fontcolor:
form.value.fontAlpha === 1
? form.value.fontColor
: form.value.fontColor + '@' + numberToHex(form.value.fontAlpha),
box: form.value.showBox ? '1' : '0',
boxcolor:
form.value.boxAlpha === 1
? form.value.boxColor
: form.value.boxColor + '@' + numberToHex(form.value.boxAlpha),
boxborderw: form.value.border.toString(),
alpha: form.value.overallAlpha.toString(),
channel_id: configStore.channels[configStore.i].id,
}
const response = await fetch(`/api/presets/${configStore.channels[configStore.i].id}/`, {
method: 'POST',
headers: { ...configStore.contentType, ...authStore.authHeader },
body: JSON.stringify(preset),
})
if (response.status === 200) {
indexStore.msgAlert('success', t('message.saveDone'), 2)
getPreset(-1)
} else {
indexStore.msgAlert('error', t('message.saveFailed'), 2)
}
}
newPresetName.value = ''
}
async function deletePreset(del: boolean) {
showDeleteModal.value = false
if (del && selected.value && selected.value !== '') {
await fetch(`/api/presets/${configStore.channels[configStore.i].id}/${form.value.id}`, {
method: 'DELETE',
headers: authStore.authHeader,
})
getPreset(-1)
}
}
async function submitMessage() {
const obj = {
text: form.value.text,
x: form.value.x.toString(),
y: form.value.y.toString(),
fontsize: form.value.fontSize.toString(),
line_spacing: form.value.fontSpacing.toString(),
fontcolor: form.value.fontColor + '@' + numberToHex(form.value.fontAlpha),
alpha: form.value.overallAlpha.toString(),
box: form.value.showBox ? '1' : '0',
boxcolor: form.value.boxColor + '@' + numberToHex(form.value.boxAlpha),
boxborderw: form.value.border.toString(),
}
const response = await fetch(`/api/control/${configStore.channels[configStore.i].id}/text/`, {
method: 'POST',
headers: { ...configStore.contentType, ...authStore.authHeader },
body: JSON.stringify(obj),
})
if (response.status === 200) {
indexStore.msgAlert('success', t('message.sendDone'), 2)
} else {
indexStore.msgAlert('error', t('message.sendFailed'), 2)
}
}
</script>