Skip to content

Instantly share code, notes, and snippets.

@srdjan
Created March 23, 2024 14:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save srdjan/3fff522055dbc30303a570cf80c47316 to your computer and use it in GitHub Desktop.
Save srdjan/3fff522055dbc30303a570cf80c47316 to your computer and use it in GitHub Desktop.
Status Board
<dashboard class="dashboard">
<dashboard-header title="Datacenter">
<dashboard-clock digital="true" binary="true" />
</dashboard-header>
<server-list>
<server v-for="(server, index) in servers" :class="{ 'has-failed': !server.status }" :type="server.type" @click.native="updateServerStatus(index)">
<span slot="name" class="data">{{server.name}}</span>
<span slot="status" class="data signal">{{server.status ? 'ONLINE' : 'OFFLINE'}}</span>
<span slot="adr" class="data">{{server.adr}}</span>
</server>
</server-list>
</dashboard>
const store = new Vuex.Store({
state: {
// initial state
servers: [
{ name: 'Lorem', status: true, adr: '192.168.0.24'},
{ name: 'Ipsum', status: true, adr: '192.168.0.25', type: 'database'},
{ name: 'Dolor', status: true, adr: '192.168.0.26', type: 'database'},
{ name: 'Adipiscing', status: true, adr: '192.168.0.37'},
{ name: 'Eiusmod', status: true, adr: '192.168.0.17'},
{ name: 'Cupidatat', status: true, adr: '192.168.0.23'},
{ name: 'Reprehenderit', status: true, adr: '192.168.0.47'},
{ name: 'Typhoon', status: true, adr: '192.168.0.127'}
]
},
mutations: {
UPDATE_SERVER_STATUS(state, payload) {
state.servers[payload].status ^= true;
}
},
actions: {
serverStatus ({commit}, server) {
commit('UPDATE_SERVER_STATUS', server)
}
}
})
Vue.component('dashboard-clock', {
props: {
digital: {
default: true,
type: Boolean
},
binary: {
default: false,
type: Boolean
}
},
data() {
return {
time: ''
}
},
template: `
<div class='dashboard-clock'>
<div v-if="digital" class="dashboard-clock-digital">{{time}}</div>
<table v-if="binary" class="dashboard-clock-binary">
<tr class='hours'>
<td v-for='n in 6'></td>
</tr>
<tr class='minutes'>
<td v-for='n in 6'></td>
</tr>
<tr class='seconds'>
<td v-for='n in 6'></td>
</tr>
</table>
</div>
`,
mounted: function(){
window.setInterval(this.render, 1000);
},
methods: {
render() {
const d = new Date();
const h = d.getHours();
const m = d.getMinutes();
const s = d.getSeconds();
this.time= `${this.addZero(h)} : ${this.addZero(m)} : ${this.addZero(s)}`;
this.light(this.convert(s), '.seconds');
this.light(this.convert(m), '.minutes');
this.light(this.convert(h), '.hours');
},
convert(num) {
let bin = "";
let conv = [];
while(num > 0) {
bin = num%2 + bin;
num = Math.floor(num/2);
}
conv = bin.split('');
while(conv.length < 6){
conv.unshift("0");
}
return conv;
},
light(array, type){
$(type+' td').attr('class','num0');
for(var i =0; i<array.length; i++){
$(type +' td:eq('+i+')').attr('class','num'+array[i]);
}
},
addZero(i) {
if (i < 10) {
i = "0" + i;
}
return i;
}
}
})
Vue.component('dashboard-header', {
props: ['title'],
template: `
<header class="dashboard-header">
<h1 class="dashboard-title">{{title}}</h1>
<slot></slot>
</header>
`
})
Vue.component('server-list', {
template: '<div class="server-list"><slot></slot></div>'
})
Vue.component('server', {
props: ['type'],
template: `
<div class="server">
<div class="server-icon fa"
:class="'fa-' + (type === 'database' ? 'tasks' : 'globe')">
</div>
<ul class="server-details">
<li>Hostname:<slot name="name"></slot></li>
<li>Status:<slot name="status"></slot></li>
<li>Address:<slot name="adr"></slot></li>
</ul>
</div>`
})
//Vue.use(Vuex);
const dashboard = new Vue({
el: 'dashboard',
data: () => {
return {
servers: store.state.servers
}
},
methods: {
updateServerStatus(server) {
store.dispatch('serverStatus', server);
}
},
mounted() {
setInterval(() =>
store.dispatch('serverStatus',
Math.floor(Math.random() * (this.servers.length - 0) + 0)
), 5000);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/2.0.0/vuex.min.js"></script>
@import url("https://fonts.googleapis.com/css?family=Lato:300,300italic");
@import url("https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css");
$cGood: #2eb35a;
$cAlert: #d22c32;
$orange: #ff6b23;
$blue: #54c6fb;
* {
user-select: none;
cursor: default;
}
html{
font-size: 62.5%;
color: #c1c6cb;
background-color: #15202e;
}
body {
padding: 20px 50px;
}
body::-webkit-scrollbar {
width: 5px;
}
::-webkit-scrollbar-track {
background: #110d0d;
}
::-webkit-scrollbar-thumb {
background: #888;
}
.dashboard {
display: block;
max-width: 1024px;
margin: 0 auto;
&-header {
display: flex;
align-items: center;
font-family: 'Lato', sans-serif;
text-transform: uppercase;
}
&-title {
flex: 1;
font-size: 2.5rem;
}
&-clock {
display: flex;
align-items: center;
&-digital {
font-weight: bold;
font-size: 2.5rem;
}
&-binary {
margin-left: 8px;
border-collapse:separate;
td {
height: .4rem;
width: .4rem;
background-color: rgba(255, 255, 255, .2);
border-radius:50%;
}
.num1 {
background-color: $cGood;
}
}
}
}
.server {
display: flex;
align-items: center;
padding: 10px 0;
border: 1px solid rgba(255, 255, 255, .1);
border-radius: 4px;
white-space: nowrap;
background-color: rgba(255, 255, 255, .1);
&-icon {
display: inline-block;
font-size: 2.5rem;
margin: 0 2rem;
}
&-details {
flex: 1;
display: block;
list-style: none;
margin: 0;
padding: 0;
li {
display: block;
font-size: 1.2rem;
line-height: 1.5;
color: #7e8794;
&:last-child {
.data {
font-weight: normal;
color: rgba(230, 245, 255, .32)
}
}
}
.data {
display: block;
margin: -1.7rem 0 0 0;
padding: 0 1rem 0 0;
font-weight: 600;
text-align: right;
color: #c1c6cb;
}
.signal {
color: $cGood;
&::before {
content: '';
display: inline-block;
width: .6rem;
height: .6rem;
background-color: currentColor;
border-radius: 50%;
margin-right: .5rem;
margin-top: -.2rem;
vertical-align: middle;
}
}
}
&-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(25rem, 1fr));
grid-gap: 2rem;
}
&.has-failed {
box-shadow: 0px 4px 15px rgba(0, 0, 0, .2);
border-color: $cAlert;
animation: alertblink 2s ease-in-out infinite;
.server-icon,
.signal {
color: $cAlert;
}
&:hover {
background-color: rgba($cAlert, .2);
animation: none;
}
}
}
@keyframes alertblink {
0% {
background: rgba($cAlert, 0);
}
50% {
background: rgba($cAlert, 0.2);
}
100% {
background: rgba($cAlert, 0);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment