mirror of
https://github.com/DJ2LS/FreeDATA
synced 2024-05-14 08:04:33 +00:00
Merge remote-tracking branch 'origin/develop' into develop
# Conflicts: # gui/package.json
This commit is contained in:
commit
d8df718645
100
gui/package.json
100
gui/package.json
|
@ -32,57 +32,57 @@
|
|||
},
|
||||
"homepage": "https://freedata.app",
|
||||
"dependencies": {
|
||||
"@electron/asar": "^3.2.8",
|
||||
"@electron/notarize": "^2.2.0",
|
||||
"@electron/universal": "^2.0.1",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@vueuse/electron": "^10.7.0",
|
||||
"blob-util": "^2.0.2",
|
||||
"bootstrap": "^5.3.2",
|
||||
"bootstrap-icons": "^1.11.2",
|
||||
"bootswatch": "^5.3.2",
|
||||
"browser-image-compression": "^2.0.2",
|
||||
"chart.js": "^4.4.1",
|
||||
"chartjs-plugin-annotation": "^3.0.1",
|
||||
"electron-log": "^5.0.1",
|
||||
"electron-updater": "^6.1.7",
|
||||
"emoji-picker-element": "^1.20.1",
|
||||
"emoji-picker-element-data": "^1.6.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"gridstack": "^10.0.0",
|
||||
"mime": "^4.0.0",
|
||||
"pinia": "^2.1.7",
|
||||
"pouchdb": "^8.0.1",
|
||||
"pouchdb-browser": "^8.0.1",
|
||||
"pouchdb-find": "^8.0.1",
|
||||
"pouchdb-upsert": "^2.2.0",
|
||||
"qth-locator": "^2.1.0",
|
||||
"sass": "^1.69.5",
|
||||
"socket.io": "^4.7.2",
|
||||
"uuid": "^9.0.1",
|
||||
"vue": "^3.3.4",
|
||||
"vue-chartjs": "^5.2.0",
|
||||
"vuemoji-picker": "^0.2.0"
|
||||
"@electron/asar": "3.2.7",
|
||||
"@electron/notarize": "2.1.0",
|
||||
"@electron/universal": "2.0.0",
|
||||
"@popperjs/core": "2.11.8",
|
||||
"@vueuse/electron": "10.4.1",
|
||||
"blob-util": "2.0.2",
|
||||
"bootstrap": "5.3.1",
|
||||
"bootstrap-icons": "1.10.5",
|
||||
"bootswatch": "5.3.1",
|
||||
"browser-image-compression": "2.0.2",
|
||||
"chart.js": "4.4.1",
|
||||
"chartjs-plugin-annotation": "3.0.1",
|
||||
"electron-log": "5.0.0",
|
||||
"electron-updater": "6.1.7",
|
||||
"emoji-picker-element": "1.20.1",
|
||||
"emoji-picker-element-data": "1.4.0",
|
||||
"file-saver": "2.0.5",
|
||||
"gridstack": "10.0.0",
|
||||
"mime": "4.0.0",
|
||||
"pinia": "2.1.6",
|
||||
"pouchdb": "8.0.1",
|
||||
"pouchdb-browser": "8.0.1",
|
||||
"pouchdb-find": "8.0.1",
|
||||
"pouchdb-upsert": "2.2.0",
|
||||
"qth-locator": "2.1.0",
|
||||
"sass": "1.66.1",
|
||||
"socket.io": "4.7.2",
|
||||
"uuid": "9.0.0",
|
||||
"vue": "3.3.4",
|
||||
"vue-chartjs": "5.2.0",
|
||||
"vuemoji-picker": "0.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^6.13.2",
|
||||
"@vitejs/plugin-vue": "^4.5.2",
|
||||
"electron": "^27.1.3",
|
||||
"electron-builder": "^24.9.1",
|
||||
"eslint": "^8.55.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-config-standard-with-typescript": "^40.0.0",
|
||||
"eslint-plugin-import": "^2.29.0",
|
||||
"eslint-plugin-n": "^16.3.1",
|
||||
"eslint-plugin-prettier": "^5.0.1",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"eslint-plugin-vue": "^9.19.2",
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^5.0.7",
|
||||
"vite-plugin-electron": "^0.15.4",
|
||||
"vite-plugin-electron-renderer": "^0.14.5",
|
||||
"vitest": "^0.34.6",
|
||||
"vue": "^3.3.4",
|
||||
"vue-tsc": "^1.8.25"
|
||||
"@typescript-eslint/eslint-plugin": "6.7.4",
|
||||
"@vitejs/plugin-vue": "4.5.2",
|
||||
"electron": "28.0.0",
|
||||
"electron-builder": "24.6.3",
|
||||
"eslint": "8.50.0",
|
||||
"eslint-config-prettier": "9.0.0",
|
||||
"eslint-config-standard-with-typescript": "40.0.0",
|
||||
"eslint-plugin-import": "2.28.1",
|
||||
"eslint-plugin-n": "16.1.0",
|
||||
"eslint-plugin-prettier": "5.0.0",
|
||||
"eslint-plugin-promise": "6.1.1",
|
||||
"eslint-plugin-vue": "9.17.0",
|
||||
"typescript": "5.2.2",
|
||||
"vite": "5.0.4",
|
||||
"vite-plugin-electron": "0.15.4",
|
||||
"vite-plugin-electron-renderer": "0.14.5",
|
||||
"vitest": "1.0.2",
|
||||
"vue": "3.3.4",
|
||||
"vue-tsc": "1.4.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, onMounted, reactive, nextTick, shallowRef } from "vue";
|
||||
import { ref, onMounted, nextTick, shallowRef, render, h } from "vue";
|
||||
import { Modal } from "bootstrap";
|
||||
import { setActivePinia } from "pinia";
|
||||
import pinia from "../store/index";
|
||||
|
@ -8,68 +8,125 @@ import "../../node_modules/gridstack/dist/gridstack.min.css";
|
|||
import { GridStack } from "gridstack";
|
||||
import { settingsStore as settings } from "../store/settingsStore.js";
|
||||
|
||||
import active_heard_stations from "./grid_active_heard_stations.vue";
|
||||
import mini_heard_stations from "./grid_active_heard_stations_mini.vue";
|
||||
import active_stats from "./grid_active_stats.vue";
|
||||
import active_audio_level from "./grid_active_audio.vue";
|
||||
import active_rig_control from "./grid_active_rig_control.vue";
|
||||
import active_broadcats from "./grid_active_broadcasts.vue";
|
||||
import s_meter from "./grid_s-meter.vue";
|
||||
import dbfs_meter from "./grid_dbfs.vue";
|
||||
import grid_activities from "./grid_activities.vue";
|
||||
import active_heard_stations from "./grid/grid_active_heard_stations.vue";
|
||||
import mini_heard_stations from "./grid/grid_active_heard_stations_mini.vue";
|
||||
import active_stats from "./grid/grid_active_stats.vue";
|
||||
import active_audio_level from "./grid/grid_active_audio.vue";
|
||||
import active_rig_control from "./grid/grid_active_rig_control.vue";
|
||||
import active_broadcats from "./grid/grid_active_broadcasts.vue";
|
||||
import s_meter from "./grid/grid_s-meter.vue";
|
||||
import dbfs_meter from "./grid/grid_dbfs.vue";
|
||||
import grid_activities from "./grid/grid_activities.vue";
|
||||
import grid_button from "./grid/button.vue";
|
||||
import { stateDispatcher } from "../js/eventHandler";
|
||||
|
||||
let count = ref(0);
|
||||
let info = ref("");
|
||||
let gridFloat = ref(false);
|
||||
let color = ref("black");
|
||||
let gridInfo = ref("");
|
||||
let grid = null; // DO NOT use ref(null) as proxies GS will break all logic when comparing structures... see https://github.com/gridstack/gridstack.js/issues/2115
|
||||
let items = ref([]);
|
||||
class gridWidget {
|
||||
//Contains the vue component
|
||||
component2;
|
||||
//Initial size and location if autoplace is false
|
||||
size;
|
||||
//Text for dynamic button
|
||||
text;
|
||||
constructor(component, size, text) {
|
||||
//if true add when quick fill button is clicked
|
||||
quickFill;
|
||||
//Auto place; true to add where ever it fits; false uses position information
|
||||
autoPlace;
|
||||
//Category to place in widget picker
|
||||
category;
|
||||
constructor(component, size, text, quickfill, autoPlace, category) {
|
||||
this.component2 = component;
|
||||
this.size = size;
|
||||
this.text = text;
|
||||
this.quickFill = quickfill;
|
||||
this.autoPlace = autoPlace;
|
||||
this.category = category;
|
||||
}
|
||||
}
|
||||
const gridWidgets = [
|
||||
new gridWidget(
|
||||
active_heard_stations,
|
||||
{ x: 0, y: 0, w: 7, h: 20 },
|
||||
"Heard stations",
|
||||
{ x: 0, y: 0, w: 16, h: 40 },
|
||||
"Detailed heard stations list",
|
||||
true,
|
||||
true,
|
||||
"Activity",
|
||||
),
|
||||
new gridWidget(
|
||||
active_stats,
|
||||
{ x: 0, y: 0, w: 4, h: 35 },
|
||||
{ x: 16, y: 26, w: 8, h: 69 },
|
||||
"Stats (waterfall, etc)",
|
||||
true,
|
||||
true,
|
||||
"Stats",
|
||||
),
|
||||
new gridWidget(
|
||||
active_audio_level,
|
||||
{ x: 16, y: 0, w: 8, h: 26 },
|
||||
"Audio main",
|
||||
true,
|
||||
true,
|
||||
"Audio",
|
||||
),
|
||||
new gridWidget(active_audio_level, { x: 0, y: 0, w: 4, h: 13 }, "Audio"),
|
||||
new gridWidget(
|
||||
active_rig_control,
|
||||
{ x: 0, y: 0, w: 6, h: 12 },
|
||||
"Rig control",
|
||||
{ x: 6, y: 40, w: 10, h: 30 },
|
||||
"Rig control main",
|
||||
true,
|
||||
true,
|
||||
"Rig",
|
||||
),
|
||||
new gridWidget(
|
||||
active_broadcats,
|
||||
{ x: 6, y: 70, w: 10, h: 25 },
|
||||
"Broadcats main",
|
||||
true,
|
||||
true,
|
||||
"Broadcasts",
|
||||
),
|
||||
new gridWidget(active_broadcats, { x: 1, y: 1, w: 4, h: 12 }, "Broadcats"),
|
||||
new gridWidget(
|
||||
mini_heard_stations,
|
||||
{ x: 1, y: 1, w: 3, h: 27 },
|
||||
"Mini Heard stations",
|
||||
{ x: 1, y: 1, w: 6, h: 54 },
|
||||
"Mini heard stations list",
|
||||
false,
|
||||
true,
|
||||
"Activity",
|
||||
),
|
||||
new gridWidget(
|
||||
s_meter,
|
||||
{ x: 1, y: 1, w: 4, h: 8 },
|
||||
"S-Meter",
|
||||
false,
|
||||
true,
|
||||
"Rig",
|
||||
),
|
||||
new gridWidget(
|
||||
dbfs_meter,
|
||||
{ x: 1, y: 1, w: 4, h: 8 },
|
||||
"Dbfs Meter",
|
||||
false,
|
||||
true,
|
||||
"Audio",
|
||||
),
|
||||
new gridWidget(
|
||||
grid_activities,
|
||||
{ x: 0, y: 40, w: 6, h: 55 },
|
||||
"Activities list",
|
||||
true,
|
||||
true,
|
||||
"Activity",
|
||||
),
|
||||
new gridWidget(s_meter, { x: 1, y: 1, w: 2, h: 4 }, "S-Meter"),
|
||||
new gridWidget(dbfs_meter, { x: 1, y: 1, w: 2, h: 4 }, "Dbfs Meter"),
|
||||
new gridWidget(grid_activities, { x: 1, y: 1, w: 3, h: 27 }, "Activities"),
|
||||
];
|
||||
onMounted(() => {
|
||||
grid = GridStack.init({
|
||||
// DO NOT user grid.value = GridStack.init(), see above
|
||||
// DO NOT use grid.value = GridStack.init(), see above
|
||||
float: true,
|
||||
cellHeight: "10px",
|
||||
cellHeight: "5px",
|
||||
minRow: 50,
|
||||
margin: 5,
|
||||
column: 24,
|
||||
draggable: {
|
||||
scroll: true,
|
||||
},
|
||||
|
@ -80,25 +137,57 @@ onMounted(() => {
|
|||
|
||||
grid.on("dragstop", function (event, element) {
|
||||
const node = element.gridstackNode;
|
||||
info.value = `you just dragged node #${node.id} to ${node.x},${node.y} – good job!`;
|
||||
console.info(
|
||||
`Moved #${node.id} to ${node.x}.${node.y}. Dimensions: ${node.w}x${node.h}`,
|
||||
);
|
||||
});
|
||||
|
||||
grid.on("change", onChange);
|
||||
// gridFloat.value = grid.float();
|
||||
|
||||
gridWidgets.forEach((gw) => {
|
||||
//Dynamically add widgets to widget menu
|
||||
let dom = document.getElementById("otherBod");
|
||||
switch (gw.category) {
|
||||
case "Activity":
|
||||
dom = document.getElementById("actBody");
|
||||
break;
|
||||
case "Stats":
|
||||
dom = document.getElementById("statsBody");
|
||||
break;
|
||||
case "Audio":
|
||||
dom = document.getElementById("audioBody");
|
||||
break;
|
||||
case "Rig":
|
||||
dom = document.getElementById("rigBody");
|
||||
break;
|
||||
case "Broadcasts":
|
||||
dom = document.getElementById("bcBody");
|
||||
break;
|
||||
default:
|
||||
console.error("Uknown widget category: " + gw.category);
|
||||
break;
|
||||
}
|
||||
var index = gridWidgets.findIndex((w) => gw.text == w.text);
|
||||
dom.insertAdjacentHTML("beforeend", `<div id="gridbtn-${index}""></div>`);
|
||||
let dom2 = document.getElementById(`gridbtn-${index}`);
|
||||
let vueComponent = h(grid_button, { btnText: gw.text, btnID: index });
|
||||
render(vueComponent, dom2);
|
||||
});
|
||||
window.addEventListener(
|
||||
"add-widget",
|
||||
function (eventdata) {
|
||||
let data = eventdata.detail;
|
||||
addNewWidget2(gridWidgets[data]);
|
||||
},
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
function changeFloat() {
|
||||
gridFloat.value = !gridFloat.value;
|
||||
grid.float(gridFloat.value);
|
||||
}
|
||||
|
||||
function onChange(event, changeItems) {
|
||||
updateInfo();
|
||||
// update item position
|
||||
changeItems.forEach((item) => {
|
||||
var widget = items.value.find((w) => w.id == item.id);
|
||||
if (!widget) {
|
||||
alert("Widget not found: " + item.id);
|
||||
console.error("Widget not found: " + item.id);
|
||||
return;
|
||||
}
|
||||
widget.x = item.x;
|
||||
|
@ -107,52 +196,53 @@ function onChange(event, changeItems) {
|
|||
widget.h = item.h;
|
||||
});
|
||||
}
|
||||
|
||||
function addNewWidget2(componentToAdd) {
|
||||
const node = items[count.value] || { ...componentToAdd.size };
|
||||
node.id = "w_" + count.value++;
|
||||
node.component2 = shallowRef({ ...componentToAdd.component2 });
|
||||
node.autoPlace = componentToAdd.autoPlace;
|
||||
items.value.push(node);
|
||||
nextTick(() => {
|
||||
grid.makeWidget(node.id);
|
||||
updateInfo();
|
||||
});
|
||||
}
|
||||
|
||||
function removeLastWidget() {
|
||||
if (count.value == 0) return;
|
||||
var id = `w_${count.value - 1}`;
|
||||
var index = items.value.findIndex((w) => w.id == id);
|
||||
if (index < 0) return;
|
||||
var removed = items.value[index];
|
||||
remove(removed);
|
||||
}
|
||||
|
||||
function remove(widget) {
|
||||
var index = items.value.findIndex((w) => w.id == widget.id);
|
||||
items.value.splice(index, 1);
|
||||
const selector = `#${widget.id}`;
|
||||
grid.removeWidget(selector, false);
|
||||
updateInfo();
|
||||
}
|
||||
|
||||
function updateInfo() {
|
||||
color.value =
|
||||
grid.engine.nodes.length == items.value.length ? "black" : "red";
|
||||
gridInfo.value = `Grid engine: ${grid.engine.nodes.length}, widgets: ${items.value.length}`;
|
||||
}
|
||||
function showModal() {
|
||||
new Modal("#tileModal", {}).show();
|
||||
function clearAllItems() {
|
||||
grid.removeAll(false);
|
||||
count.value = 0;
|
||||
items.value = [];
|
||||
}
|
||||
function quickfill() {
|
||||
gridWidgets.forEach(async (gw) => {
|
||||
await addNewWidget2(gw);
|
||||
if (gw.quickFill === true) {
|
||||
gw.autoPlace = false;
|
||||
await addNewWidget2(gw);
|
||||
//Reset autoplace value
|
||||
gw.autoPlace = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button type="button" @click="showModal">Add Widget pos [0,0]</button>
|
||||
<button type="button" @click="quickfill">Quickfill</button>
|
||||
<button
|
||||
class="btn btn-secondary fixed-middle-right rounded-0 rounded-start-4 p-1 pt-4 pb-4"
|
||||
type="button"
|
||||
data-bs-toggle="offcanvas"
|
||||
data-bs-target="#offcanvasGridItems"
|
||||
aria-controls="offcanvasGridItems"
|
||||
>
|
||||
<i class="bi bi-grip-vertical h5"></i>
|
||||
</button>
|
||||
|
||||
<div class="grid-container vh-100">
|
||||
<div class="grid-stack">
|
||||
<div
|
||||
|
@ -165,7 +255,7 @@ function quickfill() {
|
|||
:gs-id="w.id"
|
||||
:id="w.id"
|
||||
:key="w.id"
|
||||
:gs-auto-position="true"
|
||||
:gs-auto-position="w.autoPlace"
|
||||
>
|
||||
<div class="grid-stack-item-content">
|
||||
<button
|
||||
|
@ -177,81 +267,208 @@ function quickfill() {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="tileModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Add grid tile</h5>
|
||||
<button
|
||||
type="button"
|
||||
class="btn-close"
|
||||
data-bs-dismiss="modal"
|
||||
aria-label="Close"
|
||||
></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<div
|
||||
class="offcanvas offcanvas-end"
|
||||
data-bs-scroll="true"
|
||||
data-bs-backdrop="true"
|
||||
tabindex="-1"
|
||||
id="offcanvasGridItems"
|
||||
aria-labelledby="offcanvasGridItemsLabel"
|
||||
>
|
||||
<div class="offcanvas-header">
|
||||
<h5 class="offcanvas-title" id="offcanvasGridItemsLabel">
|
||||
Manage grid widgets
|
||||
</h5>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn-close"
|
||||
data-bs-dismiss="offcanvas"
|
||||
aria-label="Close"
|
||||
></button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<p>
|
||||
Grid widgets allow you to customize the display for your own usage. Here
|
||||
you may add additional widgets to fit your needs. You can move and
|
||||
resize the individual widgets!
|
||||
</p>
|
||||
<div>
|
||||
<button
|
||||
class="btn btn-sm btn-outline-primary"
|
||||
type="button"
|
||||
@click="quickfill"
|
||||
>
|
||||
Fill grid with common widgets
|
||||
</button>
|
||||
</div>
|
||||
<hr />
|
||||
<!-- Begin widget selector -->
|
||||
<div class="accordion" id="accordionExample">
|
||||
<!-- Heard Stations -->
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingHeardStations">
|
||||
<button
|
||||
class="accordion-button"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#collapseHeardStations"
|
||||
aria-expanded="true"
|
||||
aria-controls="collapseHeardStations"
|
||||
>
|
||||
<strong>Activity</strong>
|
||||
</button>
|
||||
</h2>
|
||||
<div
|
||||
class="btn-group"
|
||||
role="group"
|
||||
aria-label="Basic outlined example"
|
||||
id="collapseHeardStations"
|
||||
class="accordion-collapse collapse show"
|
||||
aria-labelledby="headingHeardStations"
|
||||
data-bs-parent="#accordionExample"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
@click="addNewWidget2(gridWidgets[0])"
|
||||
class="btn btn-outline-secondary"
|
||||
data-bs-dismiss="modal"
|
||||
>
|
||||
Heard station list
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@click="addNewWidget2(gridWidgets[1])"
|
||||
class="btn btn-outline-secondary"
|
||||
data-bs-dismiss="modal"
|
||||
>
|
||||
Stats (waterfall, etc)
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@click="addNewWidget2(gridWidgets[2])"
|
||||
class="btn btn-outline-secondary"
|
||||
data-bs-dismiss="modal"
|
||||
>
|
||||
Audio
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@click="addNewWidget2(gridWidgets[4])"
|
||||
class="btn btn-outline-secondary"
|
||||
data-bs-dismiss="modal"
|
||||
>
|
||||
Broadcasts
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@click="addNewWidget2(gridWidgets[3])"
|
||||
class="btn btn-outline-secondary"
|
||||
data-bs-dismiss="modal"
|
||||
>
|
||||
Rig Control
|
||||
</button>
|
||||
<div class="accordion-body" id="actBody"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary"
|
||||
data-bs-dismiss="modal"
|
||||
|
||||
<!-- Activities -->
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingActivities">
|
||||
<button
|
||||
class="accordion-button collapsed"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#collapseActivities"
|
||||
aria-expanded="false"
|
||||
aria-controls="collapseActivities"
|
||||
>
|
||||
<strong>Audio</strong>
|
||||
</button>
|
||||
</h2>
|
||||
<div
|
||||
id="collapseActivities"
|
||||
class="accordion-collapse collapse"
|
||||
aria-labelledby="headingActivities"
|
||||
data-bs-parent="#accordionExample"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary">Save changes</button>
|
||||
<div class="accordion-body" id="audioBody"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Broadcasts -->
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingBroadcasts">
|
||||
<button
|
||||
class="accordion-button collapsed"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#collapseBroadcasts"
|
||||
aria-expanded="false"
|
||||
aria-controls="collapseBroadcasts"
|
||||
>
|
||||
<strong>Broadcasts</strong>
|
||||
</button>
|
||||
</h2>
|
||||
<div
|
||||
id="collapseBroadcasts"
|
||||
class="accordion-collapse collapse"
|
||||
aria-labelledby="headingBroadcasts"
|
||||
data-bs-parent="#accordionExample"
|
||||
>
|
||||
<div class="accordion-body" id="bcBody"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Radio Control -->
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingRadioControl">
|
||||
<button
|
||||
class="accordion-button collapsed"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#collapseRadioControl"
|
||||
aria-expanded="false"
|
||||
aria-controls="collapseRadioControl"
|
||||
>
|
||||
<strong>Radio Control</strong>
|
||||
</button>
|
||||
</h2>
|
||||
<div
|
||||
id="collapseRadioControl"
|
||||
class="accordion-collapse collapse"
|
||||
aria-labelledby="headingRadioControl"
|
||||
data-bs-parent="#accordionExample"
|
||||
>
|
||||
<div class="accordion-body" id="rigBody"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Audio Control -->
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingAudioControl">
|
||||
<button
|
||||
class="accordion-button collapsed"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#collapseAudioControl"
|
||||
aria-expanded="false"
|
||||
aria-controls="collapseAudioControl"
|
||||
>
|
||||
<strong>Statistics</strong>
|
||||
</button>
|
||||
</h2>
|
||||
<div
|
||||
id="collapseAudioControl"
|
||||
class="accordion-collapse collapse"
|
||||
aria-labelledby="headingAudioControl"
|
||||
data-bs-parent="#accordionExample"
|
||||
>
|
||||
<div class="accordion-body" id="statsBody"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Statistics -->
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingStatistics">
|
||||
<button
|
||||
class="accordion-button collapsed"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#collapseStatistics"
|
||||
aria-expanded="false"
|
||||
aria-controls="collapseStatistics"
|
||||
>
|
||||
<strong>Other</strong>
|
||||
</button>
|
||||
</h2>
|
||||
<div
|
||||
id="collapseStatistics"
|
||||
class="accordion-collapse collapse"
|
||||
aria-labelledby="headingStatistics"
|
||||
data-bs-parent="#accordionExample"
|
||||
>
|
||||
<div class="accordion-body" id="otherBod"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<button
|
||||
class="btn btn-sm btn-outline-warning"
|
||||
type="button"
|
||||
@click="clearAllItems"
|
||||
>
|
||||
Clear grid
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.fixed-middle-right {
|
||||
position: fixed; /* Fixed/sticky position */
|
||||
top: 50%; /* Position at the middle of the viewport */
|
||||
right: 0px; /* Place the button 20px from the right */
|
||||
transform: translateY(-50%); /* Adjust for exact vertical centering */
|
||||
z-index: 999; /* Ensure it's on top of other elements */
|
||||
}
|
||||
|
||||
.grid-stack-item {
|
||||
text-align: center;
|
||||
overflow: auto;
|
||||
|
@ -267,4 +484,145 @@ function quickfill() {
|
|||
.grid-container {
|
||||
overflow-y: auto;
|
||||
}
|
||||
.gs-24 > .grid-stack-item {
|
||||
width: 4.167%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-x="1"] {
|
||||
left: 4.167%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-w="2"] {
|
||||
width: 8.333%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-x="2"] {
|
||||
left: 8.333%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-w="3"] {
|
||||
width: 12.5%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-x="3"] {
|
||||
left: 12.5%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-w="4"] {
|
||||
width: 16.667%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-x="4"] {
|
||||
left: 16.667%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-w="5"] {
|
||||
width: 20.833%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-x="5"] {
|
||||
left: 20.833%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-w="6"] {
|
||||
width: 25%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-x="6"] {
|
||||
left: 25%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-w="7"] {
|
||||
width: 29.167%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-x="7"] {
|
||||
left: 29.167%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-w="8"] {
|
||||
width: 33.333%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-x="8"] {
|
||||
left: 33.333%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-w="9"] {
|
||||
width: 37.5%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-x="9"] {
|
||||
left: 37.5%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-w="10"] {
|
||||
width: 41.667%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-x="10"] {
|
||||
left: 41.667%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-w="11"] {
|
||||
width: 45.833%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-x="11"] {
|
||||
left: 45.833%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-w="12"] {
|
||||
width: 50%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-x="12"] {
|
||||
left: 50%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-w="13"] {
|
||||
width: 54.167%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-x="13"] {
|
||||
left: 54.167%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-w="14"] {
|
||||
width: 58.333%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-x="14"] {
|
||||
left: 58.333%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-w="15"] {
|
||||
width: 62.5%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-x="15"] {
|
||||
left: 62.5%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-w="16"] {
|
||||
width: 66.667%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-x="16"] {
|
||||
left: 66.667%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-w="17"] {
|
||||
width: 70.833%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-x="17"] {
|
||||
left: 70.833%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-w="18"] {
|
||||
width: 75%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-x="18"] {
|
||||
left: 75%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-w="19"] {
|
||||
width: 79.167%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-x="19"] {
|
||||
left: 79.167%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-w="20"] {
|
||||
width: 83.333%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-x="20"] {
|
||||
left: 83.333%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-w="21"] {
|
||||
width: 87.5%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-x="21"] {
|
||||
left: 87.5%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-w="22"] {
|
||||
width: 91.667%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-x="22"] {
|
||||
left: 91.667%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-w="23"] {
|
||||
width: 95.833%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-x="23"] {
|
||||
left: 95.833%;
|
||||
}
|
||||
.gs-24 > .grid-stack-item[gs-w="24"] {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
|
13
gui/src/components/grid/button.vue
Normal file
13
gui/src/components/grid/button.vue
Normal file
|
@ -0,0 +1,13 @@
|
|||
<script setup lang="ts">
|
||||
import { defineProps } from "vue";
|
||||
const props = defineProps(["btnText", "btnID"]);
|
||||
|
||||
function emitClick() {
|
||||
window.dispatchEvent(new CustomEvent("add-widget", { detail: props.btnID }));
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<button class="btn btn-small btn-outline-secondary" v-on:click="emitClick">
|
||||
{{ btnText }}
|
||||
</button>
|
||||
</template>
|
|
@ -1,12 +1,12 @@
|
|||
<script setup lang="ts">
|
||||
import { setActivePinia } from "pinia";
|
||||
import pinia from "../store/index";
|
||||
import pinia from "../../store/index";
|
||||
setActivePinia(pinia);
|
||||
|
||||
import { useStateStore } from "../store/stateStore.js";
|
||||
import { useStateStore } from "../../store/stateStore.js";
|
||||
const state = useStateStore(pinia);
|
||||
|
||||
import { record_audio } from "../js/sock";
|
||||
import { record_audio } from "../../js/sock";
|
||||
|
||||
function startStopRecordAudio() {
|
||||
record_audio();
|
|
@ -1,15 +1,15 @@
|
|||
<script setup lang="ts">
|
||||
|
||||
import { setActivePinia } from "pinia";
|
||||
import pinia from "../store/index";
|
||||
import pinia from "../../store/index";
|
||||
setActivePinia(pinia);
|
||||
|
||||
import { settingsStore as settings} from "../store/settingsStore.js";
|
||||
import { settingsStore as settings} from "../../store/settingsStore.js";
|
||||
|
||||
import { useStateStore } from "../store/stateStore.js";
|
||||
import { useStateStore } from "../../store/stateStore.js";
|
||||
const state = useStateStore(pinia);
|
||||
|
||||
import { sendModemCQ, sendModemPing, setModemBeacon } from "../js/api.js";
|
||||
import { sendModemCQ, sendModemPing, setModemBeacon } from "../../js/api.js";
|
||||
|
||||
function transmitPing() {
|
||||
sendModemPing((<HTMLInputElement>document.getElementById("dxCall")).value);
|
|
@ -3,12 +3,12 @@
|
|||
const { distance } = require("qth-locator");
|
||||
|
||||
import { setActivePinia } from "pinia";
|
||||
import pinia from "../store/index";
|
||||
import pinia from "../../store/index";
|
||||
setActivePinia(pinia);
|
||||
|
||||
import { settingsStore as settings } from "../store/settingsStore.js";
|
||||
import { settingsStore as settings } from "../../store/settingsStore.js";
|
||||
|
||||
import { useStateStore } from "../store/stateStore.js";
|
||||
import { useStateStore } from "../../store/stateStore.js";
|
||||
const state = useStateStore(pinia);
|
||||
|
||||
function getDateTime(timestampRaw) {
|
|
@ -3,12 +3,12 @@
|
|||
const { distance } = require("qth-locator");
|
||||
|
||||
import { setActivePinia } from "pinia";
|
||||
import pinia from "../store/index";
|
||||
import pinia from "../../store/index";
|
||||
setActivePinia(pinia);
|
||||
|
||||
import { settingsStore as settings } from "../store/settingsStore.js";
|
||||
import { settingsStore as settings } from "../../store/settingsStore.js";
|
||||
|
||||
import { useStateStore } from "../store/stateStore.js";
|
||||
import { useStateStore } from "../../store/stateStore.js";
|
||||
const state = useStateStore(pinia);
|
||||
|
||||
function getDateTime(timestampRaw) {
|
|
@ -1,9 +1,9 @@
|
|||
<script setup lang="ts">
|
||||
import { setActivePinia } from "pinia";
|
||||
import pinia from "../store/index";
|
||||
import pinia from "../../store/index";
|
||||
setActivePinia(pinia);
|
||||
|
||||
import { useStateStore } from "../store/stateStore.js";
|
||||
import { useStateStore } from "../../store/stateStore.js";
|
||||
const state = useStateStore(pinia);
|
||||
|
||||
function updateFrequencyAndApply(frequency) {
|
|
@ -1,14 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
// @ts-nocheck
|
||||
// reason for no check is, that we have some mixing of typescript and chart js which seems to be not to be fixed that easy
|
||||
import { initWaterfall } from "../js/waterfallHandler.js";
|
||||
import { initWaterfall } from "../../js/waterfallHandler.js";
|
||||
import { setActivePinia } from "pinia";
|
||||
import pinia from "../store/index";
|
||||
import pinia from "../../store/index";
|
||||
setActivePinia(pinia);
|
||||
|
||||
import { settingsStore as settings } from "../store/settingsStore.js";
|
||||
import { settingsStore as settings } from "../../store/settingsStore.js";
|
||||
|
||||
import { useStateStore } from "../store/stateStore.js";
|
||||
import { useStateStore } from "../../store/stateStore.js";
|
||||
const state = useStateStore(pinia);
|
||||
|
||||
import {
|
|
@ -1,9 +1,9 @@
|
|||
<script setup lang="ts">
|
||||
import { setActivePinia } from "pinia";
|
||||
import pinia from "../store/index";
|
||||
import pinia from "../../store/index";
|
||||
setActivePinia(pinia);
|
||||
|
||||
import { useStateStore } from "../store/stateStore.js";
|
||||
import { useStateStore } from "../../store/stateStore.js";
|
||||
const state = useStateStore(pinia);
|
||||
|
||||
function getDateTime(timestampRaw) {
|
|
@ -1,9 +1,9 @@
|
|||
<script setup lang="ts">
|
||||
import { setActivePinia } from "pinia";
|
||||
import pinia from "../store/index";
|
||||
import pinia from "../../store/index";
|
||||
setActivePinia(pinia);
|
||||
|
||||
import { useStateStore } from "../store/stateStore.js";
|
||||
import { useStateStore } from "../../store/stateStore.js";
|
||||
const state = useStateStore(pinia);
|
||||
</script>
|
||||
<template>
|
|
@ -1,9 +1,9 @@
|
|||
<script setup lang="ts">
|
||||
import { setActivePinia } from "pinia";
|
||||
import pinia from "../store/index";
|
||||
import pinia from "../../store/index";
|
||||
setActivePinia(pinia);
|
||||
|
||||
import { useStateStore } from "../store/stateStore.js";
|
||||
import { useStateStore } from "../../store/stateStore.js";
|
||||
const state = useStateStore(pinia);
|
||||
</script>
|
||||
<template>
|
|
@ -145,7 +145,9 @@ function stopAllTransmissions() {
|
|||
<div class="col-sm min-vh-100 m-0 p-0">
|
||||
<!-- content -->
|
||||
|
||||
<!-- TODO: Remove the top navbar entirely if not needed
|
||||
<main_top_navbar />
|
||||
-->
|
||||
|
||||
<div class="tab-content" id="nav-tabContent-settings">
|
||||
<div
|
||||
|
|
|
@ -23,7 +23,7 @@ export function connectionFailed(endpoint, event) {
|
|||
}
|
||||
export function stateDispatcher(data) {
|
||||
data = JSON.parse(data);
|
||||
console.log(data);
|
||||
//console.log(data);
|
||||
|
||||
stateStore.modem_connection = "connected";
|
||||
|
||||
|
|
Loading…
Reference in a new issue