I have a dashboard ui-template which is using v-card/v-window and works, however I am looking for a way to consolidate the card data into a single object to be used in the element. When I consolidate the card data I loose any line breaks I have with the current code. My goal is to make a reusable ui template where all I need to do is send the formatted data to the ui template
<template>
<v-card class="panel" variant="tonal" rounded="xl">
<v-window v-model="activeCardIndex" show-arrows>
<v-window-item
v-for="(card, index) in cardsData"
:key="card.id"
:value="index"
>
<div class="d-flex flex-column justify-center align-center h-100 mt-5">
<v-card-title class="logo mt-n5">
📡 {{ card.title }}
</v-card-title>
<span class="api-stat-value text-center">
<div>{{ card.ble }}</div> <!-- card 0 -->
<div>{{ card.server}}</div>
<div>{{ card.switch_0}}</div> <!-- card 1 -->
<div>{{ card.switch_1}}</div>
<div>{{ card.switch_2}}</div>
<div>{{ card.switch_3}}</div>
<div>{{ card.uptime}}</div> <!-- card 2 -->
<div>{{ card.resetReason}}</div>
<div>{{ card.availableUpdates }}</div>
<div>{{ card.deviceId}}</div> <!-- card 3 -->
<div>{{ card.gen}}</div>
<div>{{ card.ip}}</div>
</span>
</div>
</v-window-item>
</v-window>
</v-card>
</template>
<script>
export default {
// Data properties
data() {
return {
// Use an index (0-based) instead of a 1-based index for the window
activeCardIndex: 0,
// Define your unique data for each card in an array of objects
cardsData: [
{ id: 1, },
{ id: 2, },
{ id: 3, },
{ id: 4, }
],
// The original `msg` payload for dynamic updates (if needed)
msg: { payload: { app: 'default' } }
};
},
// Computed property to get the total number of cards
computed: {
length() {
return this.cardsData.length;
}
},
// Methods for interactions
methods: {
nextWindow() {
// Logic to go to the next window, wrapping around if necessary
// Note: We use 0-based indexing now.
if (this.activeCardIndex === this.length - 1) {
this.activeCardIndex = 0;
} else {
this.activeCardIndex++;
}
},
prevWindow() {
// Logic to go to the previous window, wrapping around if necessary
if (this.activeCardIndex === 0) {
this.activeCardIndex = this.length - 1;
} else {
this.activeCardIndex--;
}
},
// Method to update a specific card dynamically
updateCardTitle(index, newTitle) {
if (this.cardsData[index]) {
this.cardsData[index].title = newTitle;
}
}
},
mounted() {
this.mounted = true;
if (this.$socket) {
this.$socket.on('msg-input:' + this.id, (msg) => {
this.msg.payload = msg.payload;
this.cardsData[0].title = `${msg.payload.app} Connect`
this.cardsData[0].ble = `Ble${msg.payload.ble.enable === true ? '✅' : '⛔'} LAN${msg.payload.eth === true ? '✅' : '⛔'} RPC${msg.payload.rpc === true ? '✅' : '⛔'} RPC Updates${msg.payload.rpc_ntf === true ? '✅' : '⛔'} Wifi${msg.payload.wifi === true ? '✅' : '⛔'}`
this.cardsData[0].server = `MQTT ${msg.payload.mqttserver}${msg.payload.mqtt === true ? '✅' : '⛔'}`
this.cardsData[1].title = `${msg.payload.app} Switch`
this.cardsData[1].switch_0 = `SW ${msg.payload.switchId_0} ${msg.payload.switch_0_name === null ? 'Not in use' : msg.payload.switch_0_name} - Voltage${msg.payload.autorecover_voltage_errors === false ? '✅' : '⛔' + msg.payload.autorecover_voltage_errors}`
this.cardsData[1].switch_1 = `SW ${msg.payload.switchId_1} ${msg.payload.switch_1_name === null ? 'Not in use' : msg.payload.switch_1_name}`
this.cardsData[1].switch_2 = `SW ${msg.payload.switchId_2} ${msg.payload.switch_2_name === null ? 'Not in use' : msg.payload.switch_2_name}`
this.cardsData[1].switch_3 = `SW ${msg.payload.switchId_3} ${msg.payload.switch_3_name === null ? 'Not in use' : msg.payload.switch_3_name}`
this.cardsData[2].title = `${msg.payload.app} General`
this.cardsData[2].uptime= `Up Time: ${Math.round(msg.payload.uptime / 60 / 1440)} days - Last Update: ${msg.payload.time}`
this.cardsData[2].resetReason= `Last Reset: ${msg.payload.resetreason} - Restart Required: ${msg.payload.restart_required === false ? 'No' : 'Yes'}`
this.cardsData[2].availableUpdates= `Available Updates: ${msg.payload.availableUpdates === undefined ? 'None' : msg.payload.availableUpdates}`
this.cardsData[3].title = `${msg.payload.app} Device`
this.cardsData[3].deviceId = `ID: ${msg.payload.device_id}`
this.cardsData[3].gen= `Model: ${msg.payload.model} - Gen: ${msg.payload.gen} - Ver: ${msg.payload.ver}`
this.cardsData[3].ip= `Ip: ${msg.payload.ip} - MAC: ${msg.payload.mac}`
});
}
},
};
</script>
<style scoped>
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400..900&display=swap');
v-card-text-subtitle-2 {
font-size: 1rem; /* Or use em, rem, px */
/* For responsive changes: */
/* @media (max-width: 600px) { font-size: 0.875rem; } */
}
.panel {
border: 1px solid rgb(0 255 136 / 45%); //0.5px solid rgb(0 255 136, 0.5); /* You can replace #000 with any color name or hex code */
// padding: 2px; /* Optional: add some padding so content isn't touching the border */
// background: linear-gradient(135deg, #0a0f1a 0%, #1a1f2e 50%, #0d1117 100%);
background: rgba(0, 255, 136, 0.02);
}
.logo {
font-family: 'Orbitron', sans-serif;
font-size: 1.8rem;
font-weight: 900;
background: linear-gradient(135deg, #00ff88, #00ccff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin-bottom: 8px;
color: #00ff88;
}
.api-stat-value {
font-family: 'JetBrains Mono', monospace;
font-size: 1.2rem;
color: #00ccff;
}
.v-window__left, .v-window__right {
background-color: rgba(0, 255, 136, 0.07) !important; /* Example: Semi-transparent black */
color: white !important; /* Change icon color */
position: absolute;
top: 25%;
transform: translateY(-50%);
z-index: 10;
}
.v-window__left {
left: 10px; /* Adjust from default 0 */
}
.v-window__right {
right: 10px; /* Adjust from default 0 */
}
</style>




