initial upload

This commit is contained in:
Kai Waggeling 2025-05-17 16:23:48 +02:00
parent ac114da487
commit 7c1cfdff51
63 changed files with 6883 additions and 0 deletions

17
ui/error.njk Normal file
View file

@ -0,0 +1,17 @@
{% extends "./master.njk" %}
{% block content %}
<div class="container">
<div class="d-flex align-items-center justify-content-center py-5">
<div class="text-center">
<h1 class="display-1 fw-bold">{{ Error.Code }}</h1>
<p class="fs-3"> <span class="text-danger">Opps!</span> {{ Error.Title }}</p>
<p class="lead">
{{ Error.Message }}
</p>
<a href="{{ Error.Link }}" class="btn btn-primary">Go Back</a>
</div>
</div>
</div>
{% endblock %}

352
ui/labelEditor.bak.njk Normal file
View file

@ -0,0 +1,352 @@
{% extends "./master.njk" %}
{% block content %}
{# Input Section #}
<script type="text/javascript">
var InitLabelData = {{ LabelData | dump }}
</script>
<div class="container">
<div class="row row-cols-2 g-4">
<div class="col-4">
{# Label Data #}
<div class="card shadow w-100 mb-4">
<div class="card-header py-3">
<p class="text-primary m-0 fw-bold">Label Settings</p>
</div>
<div class="card-body px-3 py-3 d-flex flex-column" style="gap: 1rem">
<div class="col-12">
<label class="form-label">Label Name</label>
<input type="text" class="form-control label-input" placeholder="Label Name" v-model="LabelEditor.name">
</div>
<div class="row">
<div class="col-6">
<label class="form-label">Label Width</label>
<div class="col-6 input-group">
<input type="text" class="form-control" placeholder="0" v-model="LabelEditor.size.width">
<a class="btn btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">mm</a>
<ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item">mm</a></li>
<li><a class="dropdown-item">inch</a></li>
</ul>
</div>
</div>
<div class="col-6">
<label class="form-label">Label Height</label>
<div class="col-6 input-group">
<input type="text" class="form-control" placeholder="22" v-model="LabelEditor.size.height">
<a class="btn btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">mm</a>
<ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item">mm</a></li>
<li><a class="dropdown-item">inch</a></li>
</ul>
</div>
</div>
</div>
{# <div class="row">
<div class="col-6">
<label class="form-label">Printer Resolution</label>
<div class="col-6 input-group">
<select class="form-select" v-model="LabelEditor.size.resolution">
<option value="203">203 dpi</option>
<option value="300">300 dpi</option>
<option value="600">600 dpi</option>
</select>
</div>
</div>
</div> #}
<div class="col-12 d-flex" style="gap: 1rem">
<a class="btn btn-outline-primary">
<i class="me-2 ti ti-device-floppy"></i>Save
</a>
</div>
</div>
</div>
{# Variables #}
<div class="card shadow w-100">
<div class="card-header py-3">
<p class="text-primary m-0 fw-bold">Variables</p>
</div>
<div class="card-body px-3 py-3">
<div class="col-12">
<table class="table m-0">
<thead>
<tr>
<th class="col-auto px-1">Name</th>
<th class="col-auto px-1">Regex</th>
<th class="col-auto px-1">
</th>
</tr>
</thead>
<tbody>
<tr v-for="(Variable, VIndex) in LabelEditor.variables">
<td class="px-1 py-2">
<input type="text" class="form-control" placeholder="Name" v-model="Variable.name">
</td>
<td class="px-1 py-2">
<input type="text" class="form-control" placeholder="Name" v-model="Variable.regex">
</td>
<td class="px-1 py-2 d-flex justify-content-end" style="gap: 0.6rem;">
<a class="btn btn-sm btn-outline-danger" @click="DeleteVariable(VIndex)" data-bs-toggle="tooltip" title="Delete Variable">
<i class="ti ti-trash"></i>
</a>
</td>
</tr>
</tbody>
</table>
</div>
<div class="col-12 mt-3 d-flex" style="gap: 1rem">
<a class="btn btn-outline-primary" @click="AddVariable">
<i class="me-2 ti ti-code-plus"></i>Add
</a>
</div>
</div>
</div>
</div>
{# Label Queue #}
<div class="col-8">
{# <div class="row"> #}
<div class="col-12 d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-4 mb-3 border-bottom">
<h1 class="h2 m-0">Elements</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<div class="btn-group">
<button type="button" class="btn btn-outline-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
Add Element
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#" @click="AddElement('text')">Text</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#" @click="AddElement('box')">Box</a></li>
<li><a class="dropdown-item" href="#" @click="AddElement('ellipse')">Ellipse</a></li>
<li><a class="dropdown-item" href="#" @click="AddElement('line')">Line</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#" @click="AddElement('code39')">Code 39</a></li>
<li><a class="dropdown-item" href="#" @click="AddElement('code128')">Code 128</a></li>
<li><a class="dropdown-item" href="#" @click="AddElement('codeQR')">QRCode</a></li>
</ul>
</div>
{# <a class="btn btn-outline-primary" @click="CreateLabel()">
<i class="me-2 ti ti-playlist-add"></i>Add Label
</a> #}
</div>
</div>
{# Element List #}
<div class="col-12">
<div class="row row-cols-1 row-cols-lg-2 g-4">
<div class="col" v-for="(Element, ElementIndex) in LabelEditor.elements">
<div class="col card border-primary shadow">
<div class="card-header px-3 py-3" v-if="Element.type == 'text'">
Text
</div>
<div class="card-header px-3 py-3" v-if="Element.type == 'box'">
Graphical Box
</div>
<div class="card-header px-3 py-3" v-if="Element.type == 'ellipse'">
Graphical Ellipse
</div>
<div class="card-header px-3 py-3" v-if="Element.type == 'code39'">
Code 39
</div>
<div class="card-header px-3 py-3" v-if="Element.type == 'code128'">
Code 128
</div>
<div class="card-body px-3 py-3">
<div class="row mb-3">
<div class="col-6">
<label class="form-label">Position X</label>
<div class="col-6 input-group">
<input type="text" class="form-control" placeholder="0" v-model="Element.originX">
<span class="input-group-text">mm</span>
</div>
</div>
<div class="col-6">
<label class="form-label">Position Y</label>
<div class="col-6 input-group">
<input type="text" class="form-control" placeholder="0" v-model="Element.originY">
<span class="input-group-text">mm</span>
</div>
</div>
</div>
<div class="col-12 mb-3">
<label class="form-label">Alignment</label>
<select class="form-select" v-model="Element.originAlign">
<option value="0">Align Left</option>
<option value="1">Align Right</option>
<option value="2">Align Auto</option>
</select>
</div>
{# Text #}
<div class="col-12 mb-3" v-if="Element.type == 'text'">
<label class="form-label">Text Content</label>
<input type="text" class="form-control label-input" v-model="Element.content">
</div>
<div class="col-12 mb-3" v-if="Element.type == 'text'">
<label class="form-label">Font Type</label>
<input type="text" class="form-control label-input" v-model="Element.fontType">
</div>
<div class="col-12 mb-3" v-if="Element.type == 'text'">
<label class="form-label">Font Height</label>
<input type="text" class="form-control label-input" v-model="Element.fontHeight">
</div>
{# Box #}
<div class="row mb-3" v-if="Element.type == 'box' || Element.type == 'ellipse'">
<div class="col-6">
<label class="form-label">Width</label>
<div class="col-6 input-group">
<input type="text" class="form-control" placeholder="0" v-model="Element.width">
<span class="input-group-text">mm</span>
</div>
</div>
<div class="col-6">
<label class="form-label">Height</label>
<div class="col-6 input-group">
<input type="text" class="form-control" placeholder="0" v-model="Element.height">
<span class="input-group-text">mm</span>
</div>
</div>
</div>
{# Box #}
<div class="row mb-3" v-if="Element.type == 'box'">
<div class="col-6">
<label class="form-label">Border With</label>
<div class="col-6 input-group">
<input type="text" class="form-control" placeholder="0" v-model="Element.borderWidth">
<span class="input-group-text">dots</span>
</div>
</div>
<div class="col-6">
<label class="form-label">Boder Radius</label>
<select class="form-select" v-model="Element.borderRadius">
<option value="0">No Rounding</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">Heavy Rounding</option>
</select>
</div>
</div>
<div class="col-12 mb-3" v-if="Element.type == 'box'">
<label class="form-label">Border Color</label>
<select class="form-select" v-model="Element.borderColor">
<option value="B">Black</option>
<option value="W">White</option>
</select>
</div>
{# Ellipse #}
<div class="row mb-3" v-if="Element.type == 'ellipse'">
<div class="col-6">
<label class="form-label">Border With</label>
<div class="col-6 input-group">
<input type="text" class="form-control" placeholder="0" v-model="Element.borderWidth">
<span class="input-group-text">dots</span>
</div>
</div>
<div class="col-6">
<label class="form-label">Border Color</label>
<select class="form-select" v-model="Element.borderColor">
<option value="B">Black</option>
<option value="W">White</option>
</select>
</div>
</div>
{# Code 39 & Code 128 #}
<div class="row mb-3" v-if="Element.type == 'code39' || Element.type == 'code128'">
<div class="col-12">
<label class="form-label">Content</label>
<input type="text" class="form-control" placeholder="0" v-model="Element.content">
</div>
</div>
<div class="row mb-3" v-if="Element.type == 'code39' || Element.type == 'code128'">
<div class="col-6">
<label class="form-label">Line Width</label>
<div class="col-6 input-group">
<input type="number" step="1" min="1" max="100" class="form-control" placeholder="0" v-model="Element.codeWidth">
<span class="input-group-text">dots</span>
</div>
</div>
<div class="col-6">
<label class="form-label">Width Ratio</label>
<div class="col-6 input-group">
<input type="number" step="0.1" min="2.0" max="3.0" class="form-control" placeholder="0" v-model="Element.widthRatio">
<span class="input-group-text">x</span>
</div>
</div>
</div>
<div class="row mb-3" v-if="Element.type == 'code39' || Element.type == 'code128'">
<div class="col-6">
<label class="form-label">Code Height</label>
<div class="col-6 input-group">
<input type="number" step="1" min="1" max="10000" class="form-control" placeholder="0" v-model="Element.codeHeight">
<span class="input-group-text">dots</span>
</div>
</div>
</div>
{# Actions #}
<div class="col-12 d-flex" style="gap: 0.6rem">
<a class="btn btn-outline-danger" @click="DeleteElement(ElementIndex)">
<i class="ti ti-trash me-2"></i>Delete
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{# <div class="card shadow w-100">
<div class="card-header py-3">
<p class="text-primary m-0 fw-bold">Document Elements</p>
</div>
<div class="card-body px-3 py-3">
<div class="card col-6" v-for="(Element, ElementIndex) in LabelEditor.elements">
<div class="card-body px-3 py-3" v-if="Element.type == 'text'">
<div class="col-12">
<label class="form-label">Text Value</label>
<input type="text" class="form-control label-input" v-model="Element.value">
</div>
<div class="col-12">
<label class="form-label">Font Name</label>
<input type="text" class="form-control label-input" v-model="Element.fontName">
</div>
<div class="col-12">
<label class="form-label">Font Height</label>
<input type="text" class="form-control label-input" v-model="Element.fontHeight">
</div>
</div>
</div>
<div class="col-12 text-center" v-if="LabelEditor.elements.length == 0">
<span>Füge Template-Objekte zu deinem Label hinzu.</span>
</div>
<div class="col-12 mt-3 d-flex" style="gap: 1rem">
<div class="btn-group">
<button type="button" class="btn btn-outline-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
Add Element
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#" @click="AddTextElement()">Text</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#">Box</a></li>
<li><a class="dropdown-item" href="#">Circle</a></li>
<li><a class="dropdown-item" href="#">Line</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#">QRCode</a></li>
</ul>
</div>
</div>
</div>
</div> #}
</div>
</div>
</div>
<script src="/labelEditor.app.js"></script>
{% endblock %}

78
ui/master.njk Normal file
View file

@ -0,0 +1,78 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Label Print</title>
<link rel="icon" type="image/x-icon" href="/img/Favicon.ico">
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="/css/tabler-icons.min.css">
<script src="/js/jquery-3.6.4.min.js"></script>
<script src="/js/bootstrap.bundle.min.js"></script>
<script src="/js/vue.global.prod.js"></script>
<style>
body,
html {
width: 100svw;
height: 100svh;
user-select: none;
background: var(--bs-body-bg);
}
</style>
</head>
<body>
<header>
<div class="navbar navbar-dark bg-dark shadow-sm py-3">
<div class="container">
<div class="navbar-brand d-flex align-items-center">
<img src="/img/AO-Logo.svg" style="height: 2rem; margin-right: 1rem;">
<strong>Label Print</strong>
</div>
<div class="d-flex flex-row flex-nowrap" style="gap: 1rem">
<div class="btn-group">
<button type="button" class="btn btn-outline-light dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
<i class="ti ti-stack-2 me-2"></i>Queues
</button>
<ul class="dropdown-menu dropdown-menu-end mt-1">
{% for Queue in QueueList %}
<li><a class="dropdown-item" href="/queue/{{ Queue.id }}">{{ Queue.name }}</a></li>
{% endfor %}
</ul>
</div>
<div class="btn-group">
<button type="button" class="btn btn-outline-light dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
<i class="ti ti-settings me-2"></i>Settings
</button>
<ul class="dropdown-menu dropdown-menu-end mt-1">
<li><a class="dropdown-item" href="/templates">
<i class="ti ti-template me-2"></i>Templates
</a></li>
<li><a class="dropdown-item" href="/media">
<i class="ti ti-toilet-paper me-2"></i>Media
</a></li>
<li><a class="dropdown-item" href="/queue">
<i class="ti ti-stack-2 me-2"></i>Queue
</a></li>
<li><a class="dropdown-item" href="/printer">
<i class="ti ti-printer me-2"></i>Printer
</a></li>
<li><a class="dropdown-item" href="/apps">
<i class="ti ti-share me-2"></i>Apps
</a></li>
</ul>
</div>
</div>
</div>
</div>
</header>
<main class="py-5">
<!-- Page Content -->
{% block content %}{% endblock %}
</main>
</body>
</html>

213
ui/printer.njk Normal file
View file

@ -0,0 +1,213 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Label Print</title>
<link rel="icon" type="image/x-icon" href="/img/Favicon.ico">
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="/css/tabler-icons.min.css">
<script src="/js/jquery-3.6.4.min.js"></script>
<style>
body,
html {
width: 100svw;
height: 100svh;
user-select: none;
background: var(--bs-body-bg);
}
</style>
</head>
<body>
<header>
<div class="navbar navbar-dark bg-dark shadow-sm">
<div class="container">
<div class="navbar-brand d-flex align-items-center">
<img src="/img/AO-Logo.svg" style="height: 2rem; margin-right: 1rem;">
<strong>Label Print</strong>
</div>
</div>
</div>
</header>
<main class="py-5">
<!-- Settings -->
<div class="py-2">
<div class="container" style="max-width: 60rem">
<div class="card shadow m-4">
<div class="card-header py-3">
<p class="text-primary m-0 fw-bold">Settings</p>
</div>
<div class="card-body px-2 py-3 d-flex flex-row">
<div class="col-6 px-2">
<label for="selectLabel" class="form-label">Label</label>
<select class="form-select" id="selectLabel">
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
</div>
<div class="col-6 px-2">
<label for="selectPrinter" class="form-label">Printer</label>
<select class="form-select" id="selectPrinter">
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
</div>
</div>
</div>
</div>
</div>
<!-- Printer List -->
<div class="py-2">
<div class="container" style="max-width: 60rem">
<div class="card shadow m-4">
<div class="card-header py-3">
<p class="text-primary m-0 fw-bold">Printer</p>
</div>
<div class="card-body p-0">
<div class="table-responsive table mt-2" id="dataTable" role="grid"
aria-describedby="dataTable_info">
<table class="table my-0" id="dataTable">
<thead>
<tr>
<th class="col-9 ps-5">Name</th>
<th class="pe-5 py-2 d-flex justify-content-end">
<a class="btn btn-outline-primary" data-bs-toggle="modal"
@click="CreatePrinter()">
<i class="ti ti-plus"></i>
</a>
</th>
</tr>
</thead>
<tfoot>
<tr v-for="Printer in PrinterList">
<td class="ps-5 py-2">
{{ Printer.name }}
</td>
<td class="pe-5 py-2 d-flex justify-content-end" style="gap: 0.6rem;">
<a class="btn btn-outline-primary" @click="" data-bs-toggle="tooltip"
title="Select Printer">
<i class="ti ti-printer"></i>
</a>
<a class="btn btn-outline-primary" @click="EditPrinter(Printer.uid)"
data-bs-toggle="tooltip" title="Edit Printer">
<i class="ti ti-settings"></i>
</a>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- Label Modal -->
<div class="modal fade" id="labelModal" tabindex="-1" data-bs-backdrop="static" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="labelModalLabel" v-if="LabelEditor.uid == null">Create Label
</h1>
<h1 class="modal-title fs-5" id="labelModalLabel" v-if="LabelEditor.uid != null">Label {{
LabelEditor.uid }}</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body mx-2">
<div class="mb-3">
<label for="labelNameInput" class="form-label">Label Name</label>
<input type="text" class="form-control" id="labelNameInput" placeholder="Useful Label 1"
v-model="LabelEditor.name">
</div>
<div class="row">
<div class="col-6 mb-3">
<label for="labelWidth" class="form-label">Label Width</label>
<input type="text" class="form-control" id="labelWidth" placeholder="10.0.0.1"
v-model="LabelEditor.size.width">
</div>
<div class="col-6 mb-3">
<label for="labelHeight" class="form-label">Label Height</label>
<input type="text" class="form-control" id="labelHeight" placeholder="9100"
v-model="LabelEditor.size.height">
</div>
</div>
<div class="mb-3">
<label for="templateInput" class="form-label">Template</label>
<textarea class="form-control" id="templateInput" rows="10"
v-model="LabelEditor.template"></textarea>
</div>
</div>
<div class="modal-footer">
<a class="btn btn-outline-danger" @click="DeleteLabel()" title="Delete Label">
<i class="me-2 ti ti-trash"></i>Delete
</a>
<a class="btn btn-outline-primary" @click="SaveLabel()" title="Save Label">
<i class="me-2 ti ti-device-floppy"></i>Save
</a>
</div>
</div>
</div>
</div>
<!-- Printer Modal -->
<div class="modal fade" id="printerModal" tabindex="-1" data-bs-backdrop="static" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="labelModalLabel" v-if="PrinterEditor.uid == null">Create
Printer</h1>
<h1 class="modal-title fs-5" id="labelModalLabel" v-if="PrinterEditor.uid != null">Printer {{
PrinterEditor.uid }}</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body mx-2">
<div class="mb-3">
<label for="printerNameInput" class="form-label">Printer Name</label>
<input type="text" class="form-control" id="printerNameInput" placeholder="Useful Printer 1"
v-model="PrinterEditor.name">
</div>
<div class="row">
<div class="col-8 mb-3">
<label for="printerDPIInput" class="form-label">Printer IP-Address</label>
<input type="text" class="form-control" id="printerDPIInput" placeholder="10.0.0.1"
v-model="PrinterEditor.socketaddr">
</div>
<div class="col-4 mb-3">
<label for="printerDPIInput" class="form-label">Printer Port</label>
<input type="text" class="form-control" id="printerDPIInput" placeholder="9100"
v-model="PrinterEditor.socketport">
</div>
</div>
<div class="mb-3">
<label for="printerDPIInput" class="form-label">Printer DPI</label>
<input type="text" class="form-control" id="printerDPIInput" placeholder="203"
v-model="PrinterEditor.dpi">
</div>
</div>
<div class="modal-footer">
<a class="btn btn-outline-danger" @click="DeletePrinter()" title="Delete Printer">
<i class="me-2 ti ti-trash"></i>Delete
</a>
<a class="btn btn-outline-primary" @click="SavePrinter()" title="Save Printer">
<i class="me-2 ti ti-device-floppy"></i>Save
</a>
</div>
</div>
</div>
</div>
</main>
<script src="/js/bootstrap.bundle.min.js"></script>
<script src="/js/vue.global.prod.js"></script>
<script src="/settings.app.js"></script>
</body>
</html>

113
ui/queue.njk Normal file
View file

@ -0,0 +1,113 @@
{% extends "./master.njk" %}
{% block content %}
{# Input Section #}
<div class="container">
<div class="row row-cols-2 g-4">
{# Header #}
<div class="col-12 d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-4 mb-3 border-bottom">
<h1 class="h2 m-0">
<i class="ti ti-stack-2 me-5"></i>Queue: {{ queueData.name }}
</h1>
<div class="btn-toolbar mb-2 mb-md-0 d-flex gap-2">
<a class="btn btn-outline-primary" @click="">
<i class="me-2 ti ti-printer"></i>Print Next
</a>
<a class="btn btn-outline-primary" @click="">
<i class="me-2 ti ti-printer"></i>Print All
</a>
</div>
</div>
<div class="col-4">
{# Settings #}
<div class="card shadow w-100 mb-4">
<div class="card-header py-3">
<p class="text-primary m-0 fw-bold">Settings</p>
</div>
<div class="card-body">
<div class="d-flex flex-column gap-3">
<div class="col-12">
<label for="selectTemplate" class="form-label">Template</label>
<select class="form-select" id="selectTemplate" v-model="CurrentTemplate">
<option v-for="template in templates" :value="template.id">{% raw %}{{ template.name }}{% endraw %}</option>
</select>
</div>
<div class="col-12">
<label for="selectPrinter" class="form-label">Printer</label>
<select class="form-select" id="selectPrinter" v-model="queueData.printerId">
<option v-for="printer in printers" :value="printer.id">{% raw %}{{ printer.name }}{% endraw %}</option>
</select>
</div>
<div class="col-12 mt-1">
<a :class="['w-100', 'btn', Settings.AutoPrint ? 'btn-outline-success' : 'btn-outline-danger']" @click="ToggleAutoPrint()">
<i :class="['ti', 'me-2', Settings.AutoPrint ? 'ti-check' : 'ti-x']"></i>Auto. Print
</a>
</div>
</div>
</div>
</div>
{# Input #}
<div class="card shadow w-100 mt-4">
<div class="card-header py-3">
<p class="text-primary m-0 fw-bold">Input</p>
</div>
<div class="card-body px-2 py-3 d-flex flex-column" style="gap: 1rem">
<div class="col-12 px-2" v-for="FieldName in Object.keys(LabelData)">
<label for="printerDPIInput" class="form-label">{% raw %}{{ FieldName }}{% endraw %}</label>
<input type="text" class="form-control label-input" :placeholder="FieldName" v-model="LabelData[FieldName]" @keyup.enter="ContinueFieldInput()">
</div>
<div class="col-12 px-2 d-flex" style="gap: 1rem">
<a class="btn btn-outline-primary">
<i class="me-2 ti ti-device-floppy"></i>Save
</a>
</div>
</div>
</div>
</div>
{# Label Queue #}
<div class="col-8">
<div class="row row-cols-1 row-cols-md-2 g-4">
<div class="col" v-for="Label, LabelIndex in LabelQueue">
<div class="col card border-primary shadow">
<div class="card-body px-0">
<table class="table my-0" id="dataTable">
<thead>
<tr>
<th class="ps-4">Variable</th>
<th class="ps-0">Wert</th>
</tr>
</thead>
<tfoot>
<tr v-for="Field in Object.entries(Label.Fields)">
<td class="ps-4 py-2">{% raw %}{{ Field[0] }}{% endraw %}</td>
<td class="ps-0 py-2">{% raw %}{{ Field[1] }}{% endraw %}</td>
</tr>
</tfoot>
</table>
<div class="d-flex pt-3 px-4" style="gap: 0.6rem">
<a class="btn btn-outline-primary">
<i class="ti ti-printer me-2"></i>Print
</a>
<a class="btn btn-outline-danger" @click="DeleteLabel(LabelIndex)">
<i class="ti ti-trash me-2"></i>Delete
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
var queueData = {{ queueData | dump }}
var printers = {{ printers | dump }}
var templates = {{ templates | dump }}
</script>
<script src="/api.js"></script>
<script src="/app.queue.js"></script>
{% endblock %}

152
ui/settings.apps.njk Normal file
View file

@ -0,0 +1,152 @@
{% extends "./master.njk" %}
{% block content %}
{# Input Section #}
<div class="container">
<div class="row row-cols-2 g-4">
<div class="col-12 d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-4 mb-3 border-bottom">
<h1 class="h2 m-0">Application Tokens</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<a class="btn btn-outline-primary" @click="CreateMedia()">
<i class="me-2 ti ti-playlist-add"></i>Add Application
</a>
</div>
</div>
{# Media List #}
<table class="table align-middle">
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Token</th>
<th scope="col">Expires</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="mediaData, mediaIndex in mediaList">
<td>{% raw %}{{ mediaData.name }}{% endraw %}</td>
<td>
<span class="badge text-bg-info user-select-all">sadlokfgjaskoldfjnosdaf</span>
</td>
<td>2023-11-01 12:00:00</td>
<td>
<a class="btn btn-outline-primary" @click="EditMedia(mediaData.uid)">
<i class="ti ti-printer me-2"></i>Edit
</a>
<a class="btn btn-outline-danger" @click="DeleteMedia(mediaData.uid)">
<i class="ti ti-trash me-2"></i>Delete
</a>
</td>
</tr>
</tbody>
</table>
<!-- <div class="col-12">
<div class="row row-cols-1 row-cols-md-2 g-4">
<div class="col" v-for="mediaData, mediaIndex in mediaList">
<div class="col card border-primary shadow">
<div class="card-header py-3">
<p class="text-primary m-0 fw-bold">{% raw %}{{ mediaData.name }}{% endraw %}</p>
</div>
<div class="card-body px-0">
<div class="container">
<span>
sadlokfgjaskoldfjnosdaf
</span>
</div>
</div>
<div class="card-footer text-body-secondary">
<div class="d-flex justify-content-end" style="gap: 0.6rem">
<a class="btn btn-outline-primary" @click="EditMedia(mediaData.uid)">
<i class="ti ti-printer me-2"></i>Edit
</a>
<a class="btn btn-outline-danger" @click="DeleteMedia(mediaData.uid)">
<i class="ti ti-trash me-2"></i>Delete
</a>
</div>
</div>
</div>
</div>
</div>
</div> -->
</div>
</div>
{# add Media Modal #}
<div class="modal fade" id="addMediaModal" data-bs-backdrop="static" aria-hidden="true" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="labelModalLabel" v-if="mediaEditor.uid == null">Create Media</h1>
<h1 class="modal-title fs-5" id="labelModalLabel" v-if="mediaEditor.uid != null">Media {% raw %}{{ mediaEditor.uid }}{% endraw %}</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body mx-2 d-flex flex-column" style="gap: 1rem">
<div class="col-12">
<label class="form-label">Media Name</label>
<input type="text" class="form-control label-input" placeholder="Media Name" v-model="mediaEditor.name">
</div>
<div class="row">
<div class="col-6">
<label class="form-label">Number of Columns</label>
<div class="col-6 input-group">
<input type="text" class="form-control" placeholder="3" v-model="mediaEditor.numColumns">
</div>
</div>
<div class="col-6">
<label class="form-label">Column Spacing</label>
<div class="col-6 input-group">
<input type="text" class="form-control" placeholder="2" v-model="mediaEditor.columnSpacing">
<span class="input-group-text">mm</span>
</div>
</div>
</div>
{# <div class="row">
<div class="col-6">
<label class="form-label">Label Width</label>
<div class="col-6 input-group">
<input type="text" class="form-control" placeholder="0" v-model="mediaEditor.labelWidth">
<span class="input-group-text">mm</span>
</div>
</div>
<div class="col-6">
<label class="form-label">Label Height</label>
<div class="col-6 input-group">
<input type="text" class="form-control" placeholder="22" v-model="mediaEditor.labelHeight">
<span class="input-group-text">mm</span>
</div>
</div>
</div> #}
<div class="col-12 d-flex" style="gap: 1rem">
<a class="btn btn-outline-primary" @click="SaveMedia()">
<i class="me-2 ti ti-device-floppy"></i>Save
</a>
</div>
</div>
</div>
</div>
</div>
{# delete Media Confirmation Modal #}
<div class="modal fade" id="deleteMediaModal" data-bs-backdrop="static" aria-hidden="true" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-body mx-2 d-flex flex-column" style="gap: 1rem">
<h5 class="mb-0">Delete Media</h5>
<p class="mb-0">Are you sure you want to delete Media {% raw %}{{ mediaEditor.name }}{% endraw %}?</p>
</div>
<div class="modal-footer flex-nowrap p-0">
<a class="btn btn-lg btn-link fs-6 text-decoration-none col-6 m-0 rounded-0 border-end" @click="DeleteMedia(mediaEditor.uid, true)">
<strong>Delete</strong>
</a>
<a class="btn btn-lg btn-link fs-6 text-decoration-none col-6 m-0 rounded-0" data-bs-dismiss="modal">
Cancel
</a>
</div>
</div>
</div>
</div>
<script src="/app.queue.list.js"></script>
{% endblock %}

141
ui/settings.media.njk Normal file
View file

@ -0,0 +1,141 @@
{% extends "./master.njk" %}
{% block content %}
{# Input Section #}
<div class="container">
<div class="row row-cols-2 g-4">
<div class="col-12 d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-4 mb-3 border-bottom">
<h1 class="h2 m-0">
<i class="ti ti-toilet-paper me-5"></i>Media Settings
</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<a class="btn btn-outline-primary" @click="CreateMedium()">
<i class="me-2 ti ti-playlist-add"></i>Add Media
</a>
</div>
</div>
{# Media List #}
<div class="col-12">
<div class="row row-cols-1 row-cols-md-2 row-cols-xl-3 g-4">
<div :class="['col', medium.id == null ? 'd-none': '']" v-for="(medium, index) in mediaList">
<div class="col card border-primary shadow">
<div class="card-header py-3">
<p class="text-primary m-0 fw-bold">{% raw %}{{ medium.name }}{% endraw %}</p>
</div>
<div class="card-body">
<table class="table table-middle table-borderless my-0">
<tbody>
<tr title="number of columns in a row">
<td class="py-2" title="Number of Columns">
<i class="ti ti-columns-2 me-2"></i>Columns:
</td>
<td class="py-2" title="Number of Columns">
{% raw %}{{ medium.columns }}{% endraw %}
</td>
</tr>
<tr title="spacing between columns in mm">
<td class="py-2" title="Spacing between Columns">
<i class="ti ti-spacing-horizontal me-2"></i>Spacing:
</td>
<td class="py-2" title="Spacing between Columns">
{% raw %}{{ medium.spacing }}{% endraw %} mm
</td>
</tr>
<tr title="width of a row in mm">
<td class="py-2" title="Spacing between Columns">
<i class="ti ti-arrow-autofit-width me-2"></i>Row Width:
</td>
<td class="py-2" title="Spacing between Columns">
{% raw %}{{ medium.width }}{% endraw %} mm
</td>
</tr>
</tbody>
</table>
</div>
<div class="card-footer text-body-secondary">
<div class="d-flex justify-content-end" style="gap: 0.6rem">
<a class="btn btn-outline-primary" @click="EditMedium(index)">
<i class="ti ti-printer me-2"></i>Edit
</a>
<a class="btn btn-outline-danger" @click="DeleteMedium(index)">
<i class="ti ti-trash me-2"></i>Delete
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{# add Media Modal #}
<div class="modal fade" id="addMediaModal" data-bs-backdrop="static" aria-hidden="true" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content" v-if="mediaIndex != null">
<div class="modal-header">
<h1 class="modal-title fs-5" id="labelModalLabel" v-if="mediaList[mediaIndex].id == null">Create Media</h1>
<h1 class="modal-title fs-5" id="labelModalLabel" v-if="mediaList[mediaIndex].id != null">Media {% raw %}{{ mediaList[mediaIndex].id }}{% endraw %}</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body mx-2 d-flex flex-column" style="gap: 1rem">
<div class="col-12">
<label class="form-label">Media Name</label>
<input type="text" class="form-control label-input" placeholder="Media Name" v-model="mediaList[mediaIndex].name">
</div>
<div class="row">
<div class="col-6" title="number of columns in a row">
<label class="form-label">Number of Columns</label>
<div class="col-6 input-group">
<input type="text" class="form-control" placeholder="3" v-model="mediaList[mediaIndex].columns">
</div>
</div>
<div class="col-6" title="spacing between columns in mm">
<label class="form-label">Column Spacing</label>
<div class="col-6 input-group">
<input type="text" class="form-control" placeholder="2" v-model="mediaList[mediaIndex].spacing">
<span class="input-group-text">mm</span>
</div>
</div>
<div class="col-6" title="width of a row in mm">
<label class="form-label">Row Width</label>
<div class="col-6 input-group">
<input type="text" class="form-control" placeholder="2" v-model="mediaList[mediaIndex].width">
<span class="input-group-text">mm</span>
</div>
</div>
</div>
<div class="col-12 d-flex" style="gap: 1rem">
<a class="btn btn-outline-primary" @click="SaveMedium(mediaIndex)">
<i class="me-2 ti ti-device-floppy"></i>Save
</a>
</div>
</div>
</div>
</div>
</div>
{# delete Media Confirmation Modal #}
<div class="modal fade" id="deleteMediaModal" data-bs-backdrop="static" aria-hidden="true" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content" v-if="mediaIndex != null">
<div class="modal-body mx-2 d-flex flex-column" style="gap: 1rem">
<h5 class="mb-0">Delete Media</h5>
<p class="mb-0">Are you sure you want to delete Media {% raw %}{{ mediaList[mediaIndex].name }}{% endraw %}?</p>
</div>
<div class="modal-footer flex-nowrap p-0">
<a class="btn btn-lg btn-link fs-6 text-decoration-none col-6 m-0 rounded-0 border-end" @click="DeleteMedium(mediaIndex, true)">
<strong>Delete</strong>
</a>
<a class="btn btn-lg btn-link fs-6 text-decoration-none col-6 m-0 rounded-0" data-bs-dismiss="modal">
Cancel
</a>
</div>
</div>
</div>
</div>
<script src="/api.js"></script>
<script src="/app.media.js"></script>
{% endblock %}

129
ui/settings.printers.njk Normal file
View file

@ -0,0 +1,129 @@
{% extends "./master.njk" %}
{% block content %}
<div class="container">
<div class="row row-cols-2 g-4">
<div class="col-12 d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-4 mb-3 border-bottom">
<h1 class="h2 m-0">
<i class="ti ti-printer me-5"></i>Printer Settings
</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<a class="btn btn-outline-primary" @click="CreatePrinter()">
<i class="me-2 ti ti-playlist-add"></i>Add Printer
</a>
</div>
</div>
{# Printer List #}
<div class="col-12">
<div class="row row-cols-1 row-cols-md-2 row-cols-xl-3 g-4">
<div class="col" v-for="printerData, printerIndex in printerList">
<div class="col card border-primary shadow">
<div class="card-header py-3">
<p class="text-primary m-0 fw-bold">{% raw %}{{ printerData.name }}{% endraw %}</p>
</div>
<div class="card-body">
<table class="table table-middle table-borderless my-0">
<tbody>
<tr>
<td class="ps-4 py-2">Type:</td>
<td class="ps-0 py-2">{% raw %}{{ printerData.type }}{% endraw %}</td>
</tr>
<tr>
<td class="ps-4 py-2">Density:</td>
<td class="ps-0 py-2">{% raw %}{{ printerData.density }}{% endraw %} dpi</td>
</tr>
<tr>
<td class="ps-4 py-2">Address:</td>
<td class="ps-0 py-2">{% raw %}{{ printerData.socket_addr }}{% endraw %}</td>
</tr>
<tr>
<td class="ps-4 py-2">Port:</td>
<td class="ps-0 py-2">{% raw %}{{ printerData.socket_port }}{% endraw %}</td>
</tr>
</tbody>
</table>
</div>
<div class="card-footer text-body-secondary">
<div class="d-flex justify-content-end" style="gap: 0.6rem">
<a class="btn btn-outline-primary" @click="EditPrinter(printerData.id)">
<i class="ti ti-printer me-2"></i>Edit
</a>
<a class="btn btn-outline-danger" @click="DeletePrinter(printerData.id)">
<i class="ti ti-trash me-2"></i>Delete
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{# Printer Settings Modal #}
<div class="modal fade" id="printerSettingsModal" tabindex="-1" data-bs-backdrop="static" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="labelModalLabel" v-if="printerEditor.uid == null">Create Printer</h1>
<h1 class="modal-title fs-5" id="labelModalLabel" v-if="printerEditor.uid != null">Printer {% raw %}{{ printerEditor.id }}{% endraw %}</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body mx-2">
<div class="mb-3">
<label for="printerNameInput" class="form-label">Printer Name</label>
<input type="text" class="form-control" id="printerNameInput" placeholder="Useful Printer 1" v-model="printerEditor.name">
</div>
<div class="row">
<div class="col-8 mb-3">
<label for="printerDPIInput" class="form-label">Printer IP-Address</label>
<input type="text" class="form-control" id="printerDPIInput" placeholder="10.0.0.1" v-model="printerEditor.socket_addr">
</div>
<div class="col-4 mb-3">
<label for="printerDPIInput" class="form-label">Printer Port</label>
<input type="text" class="form-control" id="printerDPIInput" placeholder="9100" v-model="printerEditor.socket_port">
</div>
</div>
<div class="mb-3">
<label for="printerDensityInput" class="form-label">Printer Density</label>
<select class="form-select" id="printerDensityInput" v-model="printerEditor.density">
<option value="203">203 dpi (8 dpmm)</option>
<option value="300">300 dpi (12 dpmm)</option>
</select>
</div>
</div>
<div class="modal-footer">
{# <a class="btn btn-outline-danger" @click="DeletePrinter()" title="Delete Printer">
<i class="me-2 ti ti-trash"></i>Delete
</a> #}
<a class="btn btn-outline-primary" @click="SavePrinter()" title="Save Printer">
<i class="me-2 ti ti-device-floppy"></i>Save
</a>
</div>
</div>
</div>
</div>
{# Printer delete Confirmation Modal #}
<div class="modal fade" id="printerDeleteModal" data-bs-backdrop="static" aria-hidden="true" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-body mx-2 d-flex flex-column" style="gap: 1rem">
<h5 class="mb-0">Delete Media</h5>
<p class="mb-0">Are you sure you want to delete Printer {% raw %}{{ printerEditor.name }}{% endraw %}?</p>
</div>
<div class="modal-footer flex-nowrap p-0">
<a class="btn btn-lg btn-link fs-6 text-decoration-none col-6 m-0 rounded-0 border-end" @click="DeletePrinter(printerEditor.id, true)">
<strong>Delete</strong>
</a>
<a class="btn btn-lg btn-link fs-6 text-decoration-none col-6 m-0 rounded-0" data-bs-dismiss="modal">
Cancel
</a>
</div>
</div>
</div>
</div>
<script src="/app.printers.js"></script>
{% endblock %}

107
ui/settings.queues.njk Normal file
View file

@ -0,0 +1,107 @@
{% extends "./master.njk" %}
{% block content %}
<div class="container">
<div class="row row-cols-2 g-4">
<div class="col-12 d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-4 mb-3 border-bottom">
<h1 class="h2 m-0">
<i class="ti ti-stack-2 me-5"></i>Queue Settings
</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<a class="btn btn-outline-primary" @click="CreateQueue()">
<i class="me-2 ti ti-playlist-add"></i>Add Queue
</a>
</div>
</div>
{# Queue List #}
<div class="col-12">
<div class="row row-cols-1 row-cols-md-2 row-cols-xl-3 g-4">
<div class="col" v-for="queueData, queueIndex in queueList">
<div class="col card border-primary shadow">
<div class="card-header py-3">
<p class="text-primary m-0 fw-bold">{% raw %}{{ queueData.name }}{% endraw %}</p>
</div>
<div class="card-body">
<table class="table table-middle table-borderless my-0">
<tbody>
<tr>
<td class="py-2 col-4">
<i class="ti ti-printer me-2"></i>Printer:
</td>
<td class="py-2">{% raw %}{{ GetPrinterById(queueData.printerId) }}{% endraw %}</td>
</tr>
</tbody>
</table>
</div>
<div class="card-footer text-body-secondary">
<div class="d-flex justify-content-end" style="gap: 0.6rem">
<a class="btn btn-outline-primary" @click="EditQueue(queueData.id)">
<i class="ti ti-list-details me-2"></i>Edit
</a>
<a class="btn btn-outline-danger" @click="DeleteQueue(queueData.id)">
<i class="ti ti-trash me-2"></i>Delete
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{# queue Settings Modal #}
<div class="modal fade" id="QueueSettingsModal" tabindex="-1" data-bs-backdrop="static" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="labelModalLabel" v-if="queueEditor.uid == null">Create queue</h1>
<h1 class="modal-title fs-5" id="labelModalLabel" v-if="queueEditor.uid != null">Queue {% raw %}{{ queueEditor.id }}{% endraw %}</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body mx-2">
<div class="mb-3">
<label for="queueNameInput" class="form-label">Queue Name</label>
<input type="text" class="form-control" id="queueNameInput" placeholder="Useful queue 1" v-model="queueEditor.name">
</div>
<div class="mb-3">
<label for="queuePrinterInput" class="form-label">Queue Printer</label>
<select class="form-select" id="queuePrinterInput" v-model="queueEditor.printerId">
<option value="null">- Kein Drucker -</option>
<option :value="printer.id" v-for="printer in printerList">{% raw %}{{ printer.name }}{% endraw %}</option>
</select>
</div>
</div>
<div class="modal-footer">
<a class="btn btn-outline-primary" @click="SaveQueue()" title="Save Queue">
<i class="me-2 ti ti-device-floppy"></i>Save
</a>
</div>
</div>
</div>
</div>
{# queue delete Confirmation Modal #}
<div class="modal fade" id="QueueDeleteModal" data-bs-backdrop="static" aria-hidden="true" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-body mx-2 d-flex flex-column" style="gap: 1rem">
<h5 class="mb-0">Delete Queue</h5>
<p class="mb-0">Are you sure you want to delete queue {% raw %}{{ queueEditor.name }}{% endraw %}?</p>
</div>
<div class="modal-footer flex-nowrap p-0">
<a class="btn btn-lg btn-link fs-6 text-decoration-none col-6 m-0 rounded-0 border-end" @click="DeleteQueue(queueEditor.id, true)">
<strong>Delete</strong>
</a>
<a class="btn btn-lg btn-link fs-6 text-decoration-none col-6 m-0 rounded-0" data-bs-dismiss="modal">
Cancel
</a>
</div>
</div>
</div>
</div>
<script src="/api.js"></script>
<script src="/app.queues.js"></script>
{% endblock %}

410
ui/settings.template.njk Normal file
View file

@ -0,0 +1,410 @@
{% extends "./master.njk" %}
{% block content %}
{# Input Section #}
<script type="text/javascript">
var template = {{ template | dump }}
</script>
<div class="container">
<div class="row gx-4 gy-2">
<div class="col-12">
<div class="card shadow w-100 mb-4">
<div class="card-header py-3">
<p class="text-primary m-0 fw-bold">Label Settings</p>
</div>
<div class="card-body p-3 row gx-4 gy-3">
<div class="col-lg-6 col-12">
<label class="form-label">Label Name</label>
<input type="text" class="form-control label-input" placeholder="Label Name" v-model="template.name">
</div>
<div class="col-lg-3 col-6">
<label class="form-label">Label Width</label>
<div class="col-6 input-group">
<input type="text" class="form-control" placeholder="0" v-model="template.width">
<span class="input-group-text">mm</span>
</div>
</div>
<div class="col-lg-3 col-6">
<label class="form-label">Label Height</label>
<div class="col-6 input-group">
<input type="text" class="form-control" placeholder="22" v-model="template.height">
<span class="input-group-text">mm</span>
</div>
</div>
<div class="col-lg-12 col-12 d-flex justify-content-end">
<a class="btn btn-primary" @click="SaveTemplate()">
<i class="me-2 ti ti-device-floppy"></i>Save
</a>
</div>
</div>
</div>
</div>
{# Template Variables #}
<div class="col-12 col-lg-4">
{# Variables Header #}
<div class="col-12 d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-4 mb-3 border-bottom">
<h1 class="h2 m-0">Variables</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<a class="btn btn-outline-primary" @click="AddVariable()">
<i class="me-2 ti ti-playlist-add"></i>Add
</a>
</div>
</div>
{# Variables #}
<div class="row gy-3">
<div :class="['col-12','gy-3', variable.id == null ? 'd-none': '']" v-for="(variable, index) in template.variables">
<div class="card shadow w-100">
<div class="card-header py-3">
<p class="text-primary m-0 fw-bold">{% raw %}{{ variable.name }}{% endraw %}</p>
</div>
<div class="card-body px-3 py-3">
<div class="row gy-3">
<div class="col-12">
<kbd>{% raw %}{{ variable.regex }}{% endraw %}</kbd>
</div>
{# Actions #}
<div class="col-12 d-flex justify-content-end">
<a class="btn btn-outline-danger me-2" @click="DeleteVariable(index)">
<i class="ti ti-trash me-2"></i>Delete
</a>
<a class="btn btn-outline-primary" @click="EditVariable(index)">
<i class="ti ti-pencil me-2"></i>Edit
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{# Template Elements #}
<div class="col-12 col-lg-8">
{# <div class="row"> #}
<div class="col-12 d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-4 mb-3 border-bottom">
<h1 class="h2 m-0">Elements</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<div class="btn-group">
<button type="button" class="btn btn-outline-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
Add
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item" href="#" @click="AddElement('text')">Text</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#" @click="AddElement('box')">Box</a></li>
<li><a class="dropdown-item" href="#" @click="AddElement('ellipse')">Ellipse</a></li>
{# <li><a class="dropdown-item" href="#" @click="AddElement('line')">Line</a></li> #}
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#" @click="AddElement('code39')">Code 39</a></li>
<li><a class="dropdown-item" href="#" @click="AddElement('code128')">Code 128</a></li>
<li><a class="dropdown-item" href="#" @click="AddElement('codeQR')">QRCode</a></li>
</ul>
</div>
</div>
</div>
{# Element List #}
<div class="col-12">
<div class="row row-cols-1 row-cols-lg-2 g-4">
<div :class="['col', element.id == null ? 'd-none': '']" v-for="(element, elementIndex) in template.elements">
<div class="col card border-primary shadow">
<div class="card-header px-3 py-3">
<p class="text-primary m-0 fw-bold">{% raw %}{{ element.name }}{% endraw %}</p>
</div>
<div class="card-body">
<table class="table table-middle table-borderless my-0">
<tbody>
<tr>
<td class="py-2" title="Number of Columns">
<i class="ti ti-augmented-reality me-2"></i>Type:
</td>
<td class="py-2" title="Number of Columns">
{% raw %}{{ GetElementTypeName(element.type) }}{% endraw %}
</td>
</tr>
<tr>
<td class="py-2" title="Number of Columns">
<i class="ti ti-layout-align-left me-2"></i>Position X:
</td>
<td class="py-2" title="Number of Columns">
{% raw %}{{ element.config.originX }}{% endraw %}
</td>
</tr>
<tr>
<td class="py-2" title="Number of Columns">
<i class="ti ti-layout-align-top me-2"></i>Position Y:
</td>
<td class="py-2" title="Number of Columns">
{% raw %}{{ element.config.originY }}{% endraw %}
</td>
</tr>
</tbody>
</table>
</div>
<div class="card-footer text-body-secondary">
<div class="d-flex justify-content-end" style="gap: 0.6rem">
<a class="btn btn-outline-primary" @click="EditElement(elementIndex)">
<i class="ti ti-printer me-2"></i>Edit
</a>
<a class="btn btn-outline-danger" @click="DeleteElement(elementIndex)">
<i class="ti ti-trash me-2"></i>Delete
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{# Variable Settings Modal #}
<div class="modal fade" id="VariableSettingsModal" tabindex="-1" data-bs-backdrop="static" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content" v-if="variableIndex != null">
<div class="modal-header">
<h1 class="modal-title fs-5" v-if="template.variables[variableIndex].id == null">Create Variable</h1>
<h1 class="modal-title fs-5" v-if="template.variables[variableIndex].id != null">Edit Variable</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body mx-2">
<div class="mb-3" title="the internal name of the variable">
<label for="VariableNameInput" class="form-label">Name</label>
<input type="text" class="form-control" id="VariableNameInput" placeholder="Variable Name" v-model="template.variables[variableIndex].name">
</div>
<div class="mb-3" title="a label for the variable that is displayed on dialogs">
<label for="VariableLabelInput" class="form-label">Label</label>
<input type="text" class="form-control" id="VariableLabelInput" placeholder="Variable Name" v-model="template.variables[variableIndex].label">
</div>
<div class="mb-3" title="regex to check if input is valid">
<label for="VariableRegexInput" class="form-label">Check Value Regex</label>
<input type="text" class="form-control" id="VariableRegexInput" placeholder="Regex like ^.*$" v-model="template.variables[variableIndex].regex">
</div>
<div class="mb-3" title="an example for the input that is displayed on dialogs">
<label for="VariableExampleInput" class="form-label">Value Example</label>
<input type="text" class="form-control" id="VariableExampleInput" placeholder="just a example" v-model="template.variables[variableIndex].example">
</div>
<div class="mb-3" title="a default value for the input that is used on dialogs">
<label for="VariableDefaultInput" class="form-label">Default Value</label>
<input type="text" class="form-control" id="VariableDefaultInput" placeholder="default value" v-model="template.variables[variableIndex].default">
</div>
</div>
<div class="modal-footer">
<a class="btn btn-outline-primary" @click="SaveVariable(variableIndex)" title="Save Variable">
<i class="me-2 ti ti-device-floppy"></i>Save
</a>
</div>
</div>
</div>
</div>
{# Variable delete Confirmation Modal #}
<div class="modal fade" id="DeleteVariableModal" data-bs-backdrop="static" aria-hidden="true" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content" v-if="variableIndex != null">
<div class="modal-body mx-2 d-flex flex-column" style="gap: 1rem">
<h5 class="mb-0">Delete Variable</h5>
<p class="mb-0">Are you sure you want to delete Variable {% raw %}{{ template.variables[variableIndex].name }}{% endraw %}?</p>
</div>
<div class="modal-footer flex-nowrap p-0">
<a class="btn btn-lg btn-link fs-6 text-decoration-none col-6 m-0 rounded-0 border-end" @click="DeleteVariable(variableIndex, true)">
<strong>Delete</strong>
</a>
<a class="btn btn-lg btn-link fs-6 text-decoration-none col-6 m-0 rounded-0" data-bs-dismiss="modal">
Cancel
</a>
</div>
</div>
</div>
</div>
{# Element Settings Modal #}
<div class="modal fade" id="ElementSettingsModal" tabindex="-1" data-bs-backdrop="static" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content" v-if="elementIndex != null">
<div class="modal-header">
<h1 class="modal-title fs-5" v-if="template.elements[elementIndex].id == null">Create Element</h1>
<h1 class="modal-title fs-5" v-if="template.elements[elementIndex].id != null">Edit Element</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body mx-2">
{# Default Element Settings #}
<div class="mb-3">
<label for="ElementTypeInput" class="form-label">Element Type</label>
<input type="text" class="form-control" id="ElementTypeInput" placeholder="Element Type" v-model="template.elements[elementIndex].name">
</div>
{# <div class="mb-3">
<label for="ElementTypeInput" class="form-label">Element Type</label>
<input type="text" class="form-control" id="ElementTypeInput" placeholder="Element Type" v-model="template.elements[elementIndex].type" disabled readonly>
</div> #}
<div class="row mb-3">
<div class="col-6">
<label class="form-label">Position X</label>
<div class="col-6 input-group">
<input type="text" class="form-control" placeholder="0" v-model="template.elements[elementIndex].config.originX">
<span class="input-group-text">mm</span>
</div>
</div>
<div class="col-6">
<label class="form-label">Position Y</label>
<div class="col-6 input-group">
<input type="text" class="form-control" placeholder="0" v-model="template.elements[elementIndex].config.originY">
<span class="input-group-text">mm</span>
</div>
</div>
</div>
<div class="mb-3">
<label class="form-label">Alignment</label>
<select class="form-select" v-model="template.elements[elementIndex].config.originAlign">
<option value="0">Align Left</option>
<option value="1">Align Right</option>
<option value="2">Align Auto</option>
</select>
</div>
{# Text Element Settings #}
<div class="mb-3" v-if="template.elements[elementIndex].type == 'text'">
<label class="form-label">Text Content</label>
<input type="text" class="form-control" v-model="template.elements[elementIndex].config.content">
</div>
<div class="row mb-3" v-if="template.elements[elementIndex].type == 'text'">
<div class="col-6">
<label class="form-label">Font Type</label>
<input type="text" class="form-control" v-model="template.elements[elementIndex].config.fontType">
</div>
<div class="col-6">
<label class="form-label">Font Height</label>
<div class="col-6 input-group">
<input type="text" class="form-control" v-model="template.elements[elementIndex].config.fontHeight">
<span class="input-group-text">mm</span>
</div>
</div>
</div>
{# Box / Ellipse Element Settings #}
<div class="row mb-3" v-if="template.elements[elementIndex].type == 'box' || template.elements[elementIndex].type == 'ellipse'">
<div class="col-6">
<label class="form-label">Width</label>
<div class="col-6 input-group">
<input type="text" class="form-control" placeholder="0" v-model="template.elements[elementIndex].config.width">
<span class="input-group-text">mm</span>
</div>
</div>
<div class="col-6">
<label class="form-label">Height</label>
<div class="col-6 input-group">
<input type="text" class="form-control" placeholder="0" v-model="template.elements[elementIndex].config.height">
<span class="input-group-text">mm</span>
</div>
</div>
</div>
{# Box Element Settings #}
<div class="row mb-3" v-if="template.elements[elementIndex].type == 'box' || template.elements[elementIndex].type == 'ellipse'">
<div class="col-6">
<label class="form-label">Border With</label>
<div class="col-6 input-group">
<input type="text" class="form-control" placeholder="0" v-model="template.elements[elementIndex].config.borderWidth">
<span class="input-group-text">dots</span>
</div>
</div>
<div class="col-6">
<label class="form-label">Border Color</label>
<select class="form-select" v-model="template.elements[elementIndex].config.borderColor">
<option value="B">Black</option>
<option value="W">White</option>
</select>
</div>
</div>
<div class="mb-3" v-if="template.elements[elementIndex].type == 'box'">
<label class="form-label">Boder Radius</label>
<select class="form-select" v-model="template.elements[elementIndex].config.borderRadius">
<option value="0">No Rounding</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">Heavy Rounding</option>
</select>
</div>
{# Code 39 & Code 128 #}
<div class="row mb-3" v-if="template.elements[elementIndex].type == 'code39' || template.elements[elementIndex].type == 'code128'">
<div class="col-12">
<label class="form-label">Content</label>
<input type="text" class="form-control" placeholder="0" v-model="template.elements[elementIndex].config.content">
</div>
</div>
<div class="row mb-3" v-if="template.elements[elementIndex].type == 'code39' || template.elements[elementIndex].type == 'code128'">
<div class="col-6">
<label class="form-label">Line Width</label>
<div class="col-6 input-group">
<input type="number" step="1" min="1" max="100" class="form-control" placeholder="0" v-model="template.elements[elementIndex].config.codeWidth">
<span class="input-group-text">dots</span>
</div>
</div>
<div class="col-6">
<label class="form-label">Width Ratio</label>
<div class="col-6 input-group">
<input type="number" step="0.1" min="2.0" max="3.0" class="form-control" placeholder="0" v-model="template.elements[elementIndex].config.widthRatio">
<span class="input-group-text">x</span>
</div>
</div>
</div>
<div class="row mb-3" v-if="template.elements[elementIndex].type == 'code39' || template.elements[elementIndex].type == 'code128'">
<div class="col-6">
<label class="form-label">Code Height</label>
<div class="col-6 input-group">
<input type="number" step="1" min="1" max="10000" class="form-control" placeholder="0" v-model="template.elements[elementIndex].config.codeHeight">
<span class="input-group-text">dots</span>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<a class="btn btn-outline-primary" @click="SaveElement(elementIndex)" title="Save Element">
<i class="me-2 ti ti-device-floppy"></i>Save
</a>
</div>
</div>
</div>
</div>
{# Element delete Confirmation Modal #}
<div class="modal fade" id="DeleteElementModal" data-bs-backdrop="static" aria-hidden="true" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content" v-if="elementIndex != null">
<div class="modal-body mx-2 d-flex flex-column" style="gap: 1rem">
<h5 class="mb-0">Delete Element</h5>
<p class="mb-0">Are you sure you want to delete Element {% raw %}{{ template.elements[elementIndex].name }}{% endraw %}?</p>
</div>
<div class="modal-footer flex-nowrap p-0">
<a class="btn btn-lg btn-link fs-6 text-decoration-none col-6 m-0 rounded-0 border-end" @click="DeleteElement(elementIndex, true)">
<strong>Delete</strong>
</a>
<a class="btn btn-lg btn-link fs-6 text-decoration-none col-6 m-0 rounded-0" data-bs-dismiss="modal">
Cancel
</a>
</div>
</div>
</div>
</div>
<div class="toast-container position-fixed bottom-0 end-0 p-3">
<div id="toast-template-saved" class="toast align-items-center text-bg-success border-0" role="alert" aria-live="assertive" aria-atomic="true">
<div class="d-flex">
<div class="toast-body">
template saved
</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
</div>
</div>
<script src="/api.js"></script>
<script src="/app.template.js"></script>
{% endblock %}

76
ui/settings.templates.njk Normal file
View file

@ -0,0 +1,76 @@
{% extends "./master.njk" %}
{% block content %}
<div class="container">
<div class="row row-cols-2 g-4">
<div class="col-12 d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-4 mb-3 border-bottom">
<h1 class="h2 m-0">
<i class="ti ti-template me-5"></i>Template Settings
</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<a class="btn btn-outline-primary" @click="CreateTemplate()">
<i class="me-2 ti ti-playlist-add"></i>Add Template
</a>
</div>
</div>
{# Template List #}
<div class="col-12">
<div class="row row-cols-1 row-cols-md-2 row-cols-xl-3 g-4">
<div class="col" v-for="(template, index) in templateList">
<div class="col card border-primary shadow">
<div class="card-header py-3">
<p class="text-primary m-0 fw-bold">{% raw %}{{ template.name }}{% endraw %}</p>
</div>
<div class="card-body px-0">
<table class="table my-0">
<tfoot>
<tr>
<td class="ps-4 py-2">Number of Elements:</td>
<td class="ps-0 py-2">{% raw %}{{ template.elements.length }}{% endraw %}</td>
</tr>
<tr>
<td class="ps-4 py-2">Number of Variables:</td>
<td class="ps-0 py-2">{% raw %}{{ template.variables.length }}{% endraw %}</td>
</tr>
</tfoot>
</table>
<div class="d-flex pt-3 px-4" style="gap: 0.6rem">
<a class="btn btn-outline-primary" @click="EditTemplate(index)">
<i class="ti ti-printer me-2"></i>Edit
</a>
<a class="btn btn-outline-danger" @click="DeleteTemplate(index)">
<i class="ti ti-trash me-2"></i>Delete
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{# Template delete Confirmation Modal #}
<div class="modal fade" id="DeleteTemplateModal" data-bs-backdrop="static" aria-hidden="true" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content" v-if="templateIndex != null">
<div class="modal-body mx-2 d-flex flex-column" style="gap: 1rem">
<h5 class="mb-0">Delete Template</h5>
<p class="mb-0">Are you sure you want to delete Template {% raw %}{{ templateList[templateIndex].name }}{% endraw %}?</p>
</div>
<div class="modal-footer flex-nowrap p-0">
<a class="btn btn-lg btn-link fs-6 text-decoration-none col-6 m-0 rounded-0 border-end" @click="DeleteTemplate(templateIndex, true)">
<strong>Delete</strong>
</a>
<a class="btn btn-lg btn-link fs-6 text-decoration-none col-6 m-0 rounded-0" data-bs-dismiss="modal">
Cancel
</a>
</div>
</div>
</div>
</div>
<script src="/api.js"></script>
<script src="/app.templates.js"></script>
{% endblock %}