Files
baseui/src/components/my-table.vue

321 lines
8.8 KiB
Vue

<template>
<div class="cms_table">
<!-- Header -->
<div class="table_header">
<div v-for="(col, i) in columns"
:class="['table_cell', {['sortable']: col.orderBy, [`align-${col.align}`]: col.align}]"
:key="i">
<!-- Column with sorting -->
<div @click="orderBy(col.orderBy)" v-if="col.orderBy">
{{ col.heading }}
<i class="icon icon-angle-up" aria-hidden="true" v-if="currentOrderBy !== col.orderBy"></i>
<i class="icon icon-angle-circled-down" aria-hidden="true" v-else-if="currentOrderDesc"></i>
<i class="icon icon-angle-circled-up" aria-hidden="true" v-else></i>
</div>
<!-- Column without sorting -->
<div v-else>{{ col.heading }}</div>
</div>
<div class="table_cell cell_settings" v-if="actions.length"></div>
</div>
<!-- Content -->
<div class="table_content" is="transition-group" name="list">
<div class="table_row" v-for="(row, ri) in rows" :key="ri">
<!-- Row content -->
<div v-for="(col, ci) in columns"
:class="['table_cell', {[`align-${col.align}`]: col.align}]"
:key="ci + 'c'">
<span v-if="col.prop" :title="getProp(row, col.prop)">{{ getProp(row, col.prop) }}</span>
<span v-else-if="col.render">{{ col.render(row) }}</span>
</div>
<!-- Row actions -->
<div class="table_cell cell_settings" v-if="actions.length" ref="row_actions">
<ul class="actions_container">
<li v-for="(a, i) in actions" :title="a.title" @click="a.action(row)" :key="i">
<i :class="['icon', a.icon]"></i>
</li>
</ul>
<div title="Open actions" class="actions_btn" @click="toggleActions">
<i class="icon icon-cog" aria-hidden="true"></i>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'My-Table',
props: {
actions: {
type: Array,
default() {
return [ ];
}
},
columns: {
type: Array,
default() {
return [ ];
}
},
rows: {
type: Array,
default() {
return [ ];
}
},
currentOrderBy: {
type: String
},
currentOrderDesc: {
type: Boolean
}
},
data() {
return {
}
},
methods: {
orderBy(col) {
console.log(col);
this.$emit('sort', {
orderBy: col,
orderDesc: false
});
},
getProp(row, prop) {
let props = prop.split('.');
let val = row;
props.forEach((p) => {
if (typeof val == 'object') {
val = val[p];
}
});
return val;
},
toggleActions(event) {
const parent = event.currentTarget.parentNode;
this.$refs.row_actions.forEach((item) => {
if (item !== parent)
item.classList.remove("open")
});
parent.classList.toggle("open");
}
}
}
</script>
<style lang="less">
@import "~mixins";
.list-item {
display: inline-block;
margin-right: 10px;
}
.list-enter-active, .list-leave-active {
transition: all 0.2s;
}
.list-enter, .list-leave-to /* .list-leave-active below version 2.1.8 */ {
opacity: 0;
transform: translateY(30px);
}
/*--------------------------------------------------------------
# Content Tables
--------------------------------------------------------------*/
.cms_table {
.table_header{
display: none;
}
.table_row{
position: relative;
background: white;
&:nth-child(even) {
background: @gray_light;
}
}
.table_cell {
font-size: 13px;
padding: 10px 15px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
@media (min-width: @screen-sm-min) {
.cms_table{
display: table;
table-layout: fixed;
width: 100%;
overflow: hidden;
border-collapse: collapse;
.table_header, .table_content{margin: 0px -25px;}
.table_header{
display: table-header-group;
}
.table_content{
display: table-row-group;
}
.table_row{
display: table-row;
position: relative;
background: white;
&:nth-child(even) {
background: @gray_light;
}
}
.table_cell {
display: table-cell;
vertical-align: middle;
font-size: 13px;
padding: 10px 15px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
&.sortable:hover{cursor: pointer;}
&.align-center{text-align: center;}
&.align-left{text-align: left;}
&.align-right{text-align: right;}
}
}
}
/* === Other cell types === */
/*.cell_checkbox {width:40px;}
.cell_image {width:120px; line-height:0;} .cell_image img {width:100%;}
.cell_title {position:relative;}
.cell_title a {color:#000;} .cell_title a:hover {color:#28b78d;}*/
/*.cell_date {}
.cell_author {}
.cell_category {}
.cell_status {position:relative; padding-left:20px;}
.cell_status:before {
content:"";
display:block;
position:absolute;
left:0px; top:50%;
margin-top:-5px;
width:12px; height:12px;
border-radius:100%;
background:#88c87a;
}
.cell_status_online {color:#28b78d;} .cell_status_online:before {background-color:#28b78d;}
.cell_status_offline {color:#ea5e5d;} .cell_status_offline:before {background-color:#ea5e5d;}
.cell_status_remaining {color:#5fb1e9;} .cell_status_remaining:before {background-color:#5fb1e9;}
.cell_status_expired {color:#eba760;} .cell_status_expired:before {background-color:#eba760;}
*/
/* === Cell settings === */
.cell_settings {
.clearfix();
.actions_btn{
display: none;
}
.icon {
font-size: 16px;
}
.actions_container{
list-style-type: none;
.icon:hover{
cursor: pointer;
color: @cms_brand_primary;
}
}
li {
display: inline-block;
padding-right: 5px;
}
}
@media (min-width: @screen-sm-min) {
.cell_settings {
position: relative;
width: 22.4px + 2*15px;
text-align: right;
overflow: visible !important;
.actions_btn{
position: relative;
display: block;
z-index: 20;
&:hover{
cursor: pointer;
color: @cms_brand_primary;
}
}
.actions_container {
position: absolute;
padding: 5px 10px;
top: 50%;
margin-top: -16px;
right: 7px;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s;
color: white;
background: @cms_brand_primary;
border-radius: 20px;
li {
&:last-child{
border-right: 1px solid white;
padding-right: 10px;
margin-right: 26px;
.icon:before{
margin-right: 0;
}
}
}
.icon:hover{
cursor: pointer;
color: @text_color;
}
}
&.open {
.actions_btn {color: white; &:hover{color: black;}}
.actions_container {
pointer-events: all;
z-index: 10;
opacity: 1;
}
}
}
}
</style>