Skip to content

Instantly share code, notes, and snippets.

@Timtech4u
Created May 17, 2017 03:38
Show Gist options
  • Save Timtech4u/0fefa3a4e8f07f20cc3f097360e47bf6 to your computer and use it in GitHub Desktop.
Save Timtech4u/0fefa3a4e8f07f20cc3f097360e47bf6 to your computer and use it in GitHub Desktop.
Vue.JS - Advanced Data Grid Component
<script type="text/x-template" id="dropdown-template">
<div class="dropdown" v-show="show" v-bind:class="originClass" transition="dropdown">
<slot>No dropdown content!</slot>
</div>
</script>
<script type="text/x-template" id="datagrid-template">
<table id="{{ id }}" class="table-striped datagrid">
<thead>
<tr>
<th class="datagrid-toggle-column" v-if="allowSelection">
<div class="toggle toggle-checkbox">
<input type="checkbox" id="allrows" name="allrows" v-model="selectAll">
<label for="allrows"></label>
</div>
</th>
<th v-for="(index, column) in columns" v-bind:style="{ width: getCellWidth(column) }">
<div class="control-group">
<div class="datagrid-header control control-fill" v-on:click="sortBy(column)">
<span>{{ column.name }}</span>
<span class="material-icons icon" v-show="sortingKey === column.key">{{ sortingDirection === 1 ? 'expand_more' : 'expand_less' }}</span>
</div>
<div class="button-group control" v-if="showOptions && index === (columns.length - 1)">
<a id="{{ id }}-options" class="icon-button">
<span class="material-icons icon">settings</span>
</a>
<dropdown v-bind:for="id + '-options'" origin="top left" v-bind:preserve-state="true">
<datagrid-options v-bind:grid-id="id" v-bind:columns="columns" v-bind:allow-selection.sync="allowSelection" v-bind:allow-edit.sync="allowEdit" v-bind:data-filter.sync="dataFilter" v-bind:grouping-column.sync="groupingColumn" v-bind:show-advanced-options="showAdvancedOptions">
</datagrid-options>
</dropdown>
</div>
</div>
</th>
</tr>
</thead>
<tbody v-for="(groupName, groupData) in data | filterBy dataFilter | orderBy sortingKey sortingDirection | groupBy groupingColumn.key">
<tr v-if="groupData.length === 0">
<td class="text-centre" colspan="{{ columnSpan }}"><strong>No Results</strong></td>
</tr>
<tr class="table-group-header" v-if="groupingColumn">
<td colspan="{{ columnSpan }}">{{ formatData(groupingColumn, groupName) }}</td>
</tr>
<tr v-for="(index, row) in groupData">
<td class="datagrid-toggle-column" v-if="allowSelection">
<div class="toggle toggle-checkbox">
<input type="checkbox" id="{{ getControlId(groupName, index) }}" name="{{ getControlId(groupName, index) }}" v-bind:value="row" v-model="selectedRows">
<label for="{{ getControlId(groupName, index) }}"></label>
</div>
</td>
<td v-for="column in columns">
<partial v-bind:name="getCellTemplate(column)"></partial>
</td>
</tr>
</tbody>
<tfoot v-if="showFooter">
<tr>
<td colspan="{{ columnSpan }}">
<ul class="chips">
<li class="chip chip-removable" v-show="selectedRows.length > 0" transition="chip">
<span class="chip-title">Selection</span>
<span class="chip-subtitle">{{ selectedRows.length }} rows selected</span>
<a class="chip-remove-button" v-on:click="resetSelection()"></a>
</li>
<li class="chip chip-removable" v-show="dataFilter" transition="chip">
<span class="chip-title">Filtering on</span>
<span class="chip-subtitle">{{ dataFilter }}</span>
<a class="chip-remove-button" v-on:click="resetFilter()"></a>
</li>
<li class="chip chip-removable" v-show="groupingColumn" transition="chip">
<span class="chip-title">Grouping on</span>
<span class="chip-subtitle">{{ groupingColumn.name }}</span>
<a class="chip-remove-button" v-on:click="resetGrouping()"></a>
</li>
</ul>
</td>
</tr>
</tfoot>
</table>
</script>
<script type="text/x-template" id="datagrid-options-template">
<div class="datagrid-options">
<div class="datagrid-options-row">
<input type="search" placeholder="Filter this dataset" v-model="dataFilter" />
</div>
<div class="datagrid-options-row" v-if="showAdvancedOptions">
<div class="toggle toggle-switch">
<input type="checkbox" id="{{ gridId }}-allow-selection" name="{{ gridId }}-allow-selection" value="" v-model="allowSelection">
<label for="{{ gridId }}-allow-selection"></label>
</div>
<label for="{{ gridId }}-allow-selection">Allow Selection</label>
<div class="toggle toggle-switch">
<input type="checkbox" id="{{ gridId }}-allow-edit" name="{{ gridId }}-allow-edit" value="" v-model="allowEdit">
<label for="{{ gridId }}-allow-edit"></label>
</div>
<label for="{{ gridId }}-allow-edit">Allow Edit</label>
</div>
<div class="table-wrapper datagrid-options-row">
<table>
<thead>
<tr>
<th>Column</th>
<th>Group By</th>
</tr>
</thead>
<tbody>
<tr>
<td>All</td>
<td class="text-centre">
<div class="toggle toggle-radio">
<input type="radio" id="all" name="group-by" value="" v-model="groupingColumn">
<label for="all"></label>
</div>
</td>
</tr>
<tr v-for="column in columns">
<td>{{ column.name }}</td>
<td class="text-centre">
<div class="toggle toggle-radio">
<input type="radio" id="{{ getControlName(column.key, 'grp') }}" name="group-by" v-bind:value="column" v-model="groupingColumn">
<label for="{{ getControlName(column.key, 'grp') }}"></label>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</script>
<div id="index" class="container">
<section>
<h1>Vue.JS Datagrid</h1>
</section>
<section>
<strong>Note:</strong> This datagrid uses version 1 of Vue. Version 2 has since been released and I have written a new datagrid component targeting version 2. See the updated version of this datagrid here:
<a href="https://codepen.io/andrewcourtice/full/woQzpa/" target="_blank">https://codepen.io/andrewcourtice/full/woQzpa/</a>
</section>
<section>
<h2>Features</h2>
<ul>
<li>Sorting (Click column header)</li>
<li>Grouping (Use the advanced options)</li>
<li>Filtering</li>
<li>Toggle cell editing</li>
<li>Toggle row selection</li>
<li>Custom cell templates (override default for whole grid or just a specific column)</li>
<li>Custom filters for cell content</li>
</ul>
</section>
<section>
<div class="table-wrapper">
<datagrid id="customers-grid"
v-bind:columns="customers.columns"
v-bind:data="customers.data"
v-bind:show-advanced-options="true">
</datagrid>
</div>
</section>
</div>
Vue.filter("groupBy", function(value, key) {
var groups = {
data: value
};
if (key) {
groups = {};
for (var i = 0; i < value.length; i++) {
var row = value[i];
var cell = row[key];
if (!groups.hasOwnProperty(cell)) {
groups[cell] = [];
}
groups[cell].push(row);
}
}
return groups;
});
Vue.filter("date", function(value, format) {
var date = moment(value);
if (!date.isValid()) {
return value;
}
return date.format(format);
});
Vue.component("dropdown", {
template: "#dropdown-template",
props: {
for: {
type: String,
required: true
},
origin: {
type: String,
default: "top right"
},
preserveState: {
type: Boolean,
default: false
}
},
computed: {
originClass: function() {
switch (this.origin) {
case "top left":
return "dropdown-top-left";
case "bottom left":
return "dropdown-bottom-left";
case "bottom right":
return "dropdown-bottom-right";
}
}
},
data: function() {
return {
show: false
};
},
ready: function() {
var _this = this;
var element = document.getElementById(_this.for);
var hide = function(event) {
event.stopPropagation();
if (!(_this.preserveState && _this.$el.contains(event.target))) {
_this.show = false;
document.body.removeEventListener("click", hide);
}
};
var show = function(event) {
event.preventDefault();
event.stopPropagation();
var dropdowns = [].slice.call(document.querySelectorAll(".dropdown"));
dropdowns.forEach(function(dropdown) {
dropdown.__vue__.show = false;
});
if (!_this.show) {
_this.show = true;
document.body.addEventListener("click", hide);
}
};
element.addEventListener("click", show);
}
});
Vue.component("datagridOptions", {
template: "#datagrid-options-template",
props: {
gridId: {
type: String,
required: true
},
columns: {
type: Array,
required: true
},
allowSelection: {
type: Boolean
},
allowEdit: {
type: Boolean
},
groupingColumn: {
type: Object,
required: true
},
dataFilter: {
type: String,
required: true
},
showAdvancedOptions: {
type: Boolean
}
},
methods: {
getControlName(columnKey, suffix) {
return this.gridId + "-" + columnKey + "-" + suffix;
}
}
});
Vue.component("datagrid", {
template: "#datagrid-template",
components: ["datagridOptions"],
props: {
id: {
type: String,
required: true
},
columns: {
type: Array,
required: true
},
data: {
type: Array
},
cellTemplate: {
type: String,
required: false,
default: "defaultGridCell"
},
allowSelection: {
type: Boolean,
required: false,
default: false
},
allowEdit: {
type: Boolean,
required: false,
default: false
},
showDefaultOptions: {
type: Boolean,
required: false,
default: true
},
showAdvancedOptions: {
type: Boolean,
required: false,
default: false
}
},
computed: {
columnSpan: function() {
return this.allowSelection ? this.columns.length + 1 : this.columns.length;
},
showOptions: function() {
return this.showDefaultOptions || this.showAdvancedOptions;
},
showFooter: function() {
return this.dataFilter || this.groupingColumn || this.selectedRows.length > 0;
}
},
data: function() {
return {
sortingKey: null,
sortingDirection: 1,
groupingColumn: null,
dataFilter: null,
selectedRows: [],
selectAll: false
};
},
methods: {
getCellTemplate: function(column) {
return this.allowEdit ? "editableGridCell" : (column.template || this.cellTemplate);
},
getCellWidth: function(column) {
if (!column.width) {
return;
}
return column.width + (isNaN(column.width) ? "" : "%");
},
getControlId: function(groupName, index, suffix) {
return groupName + "-" + index + (suffix ? "-" + suffix : "");
},
sortBy: function(column) {
if (column.key === this.sortingKey) {
this.sortingDirection *= -1;
return;
}
this.sortingKey = column.key;
this.sortingDirection = 1;
},
groupBy: function(column) {
this.groupingColumn = column;
},
resetFilter() {
this.dataFilter = null;
},
resetGrouping() {
this.groupingColumn = null;
},
resetSelection() {
this.selectedRows = [];
this.selectAll = false;
},
formatData: function(column, value) {
if (column.hasOwnProperty("filter")) {
var filter = Vue.filter(column.filter.name);
var args = [].concat(value, column.filter.args);
return filter.apply(this, args);
}
return value;
}
},
watch: {
"selectAll": function(value) {
this.selectedRows = value ? [].concat(this.data) : [];
}
}
});
Vue.partial("defaultGridCell", "<span>{{ formatData(column, row[column.key]) }}</span>");
Vue.partial("editableGridCell", "<input type=\"text\" v-model=\"row[column.key]\" lazy/>");
Vue.partial("linkedGridCell", "<a href=\"http://www.google.com?q={{ row.GivenName }}\"><partial name=\"defaultGridCell\"></partial></a>");
var vue = new Vue({
el: "#index",
data: {
customers: {
columns: [{
key: "GivenName",
name: "Given Name",
template: "linkedGridCell"
}, {
key: "Surname",
name: "Surname"
}, {
key: "Email",
name: "Email",
width: 33
}, {
key: "DateOfBirth",
name: "Date of Birth",
filter: {
name: "date",
args: ["DD MMMM YYYY"]
}
}],
data: [{
"ID": 0,
"GivenName": "John",
"Surname": "Smith",
"DateOfBirth": "1986-10-03T00:00:00",
"Email": "john.smith@smithsteel.com",
"JobTitle": "Co-Founder and CEO",
"Company": "Smith Steel Pty Ltd"
}, {
"ID": 1,
"GivenName": "Jane",
"Surname": "Smith",
"DateOfBirth": "1988-05-28T00:00:00",
"Email": "jane.smith@smithsteel.com",
"JobTitle": "Co-Founder and CEO",
"Company": "Smith Steel Pty Ltd"
}, {
"ID": 2,
"GivenName": "Richard",
"Surname": "Swanston",
"DateOfBirth": "1972-08-15T00:00:00",
"Email": "rswanston@telco.com",
"JobTitle": "Purchasing Officer",
"Company": "Cortana Mining Co"
}, {
"ID": 3,
"GivenName": "Robert",
"Surname": "Brown",
"DateOfBirth": "1968-01-18T00:00:00",
"Email": "robbrown@othertelco.com",
"JobTitle": "Sales Manager",
"Company": "Powerhouse Marketing"
}, {
"ID": 4,
"GivenName": "Phillip",
"Surname": "Zucco",
"DateOfBirth": "1991-06-28T00:00:00",
"Email": "phil.zucco@workplace.com",
"JobTitle": "Applications Developer",
"Company": "Workplace Pty Ltd"
}, {
"ID": 5,
"GivenName": "James",
"Surname": "Caldwell",
"DateOfBirth": "1988-07-27T00:00:00",
"Email": "james.caldwell@random.com",
"JobTitle": "Purchasing Officer",
"Company": "Random Industries Ltd."
}, {
"ID": 6,
"GivenName": "Rachael",
"Surname": "O'Reilly",
"DateOfBirth": "1972-08-15T00:00:00",
"Email": "roreilly@energy.com",
"JobTitle": "Workplace Health and Safety Officer",
"Company": "Energy Company"
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.18/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.12.0/moment.min.js"></script>
$layout_containerWidth: 1160px;
$layout_scrollbarWidth: 17px;
$font_Family: "Open Sans", sans-serif;
$font_TypographyRatio: 1.25;
$font_SizeRoot: 14px;
$font_SizeMinor: round($font_SizeRoot * (1 / $font_TypographyRatio));
$font_LineHeight: 1.45;
/* Colours */
$colour_Font: #414550;
$colour_FontLight: lighten($colour_Font, 20%);
$colour_FontDark: darken($colour_Font, 5%);
$colour_FontInverted: #ffffff;
$colour_Accent: #2196f3;
$colour_AccentDark: darken($colour_Accent, 10%);
$colour_Danger: #DE6060;
$colour_DangerDark: darken($colour_Danger, 10%);
$colour_Background: #ffffff;
$colour_BackgroundHeader: #fafafc;
$colour_BackgroundHeaderDark: darken($colour_BackgroundHeader, 2.5%);
$colour_BackgroundStripe: #fdfdfd;
$colour_Border: #dddddd;
$colour_BorderLight: #eeeeee;
/* Borders */
$border_Radius: 2px;
/* Inputs */
$text_Inputs: 'input:not([type="submit"]):not([type="checkbox"]):not([type="radio"])';
@function pow($base, $exponent: 2) {
$value: $base;
@for $i from 1 through ($exponent - 1) {
$value: ($value * $base);
}
@return $value;
}
/* Some defaults */
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
html {
font-size: $font_SizeRoot;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
* {
-moz-box-sizing: inherit;
-webkit-box-sizing: inherit;
box-sizing: inherit;
&:before,
&:after {
@extend *;
}
}
body {
font-family: $font_Family;
font-weight: 400;
line-height: $font_LineHeight;
color: $colour_Font;
background-color: $colour_Background;
}
section,
footer {
margin-top: 64px;
}
a {
color: $colour_Accent;
text-decoration: none;
&:hover {
color: $colour_AccentDark;
}
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0.75em 0;
line-height: $font_LineHeight;
font-weight: 600;
color: $colour_FontDark;
}
h1 {
margin-top: 0;
font-size: round($font_SizeRoot * pow($font_TypographyRatio, 4));
}
h2 {
font-size: round($font_SizeRoot * pow($font_TypographyRatio, 3));
}
ul,
ol {
padding-left: 30px;
}
li {
list-style: disc;
}
strong {
font-weight: 600;
}
.text-centre {
text-align: center;
}
/* Containers */
.container {
width: $layout_containerWidth;
margin: 0 auto;
padding: 0 15px;
&.container-fluid {
width: 100%;
}
}
.control-group {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-flex-wrap: nowrap;
-ms-flex-wrap: nowrap;
flex-wrap: nowrap;
-webkit-box-pack: start;
-webkit-justify-content: flex-start;
-ms-flex-pack: start;
justify-content: flex-start;
-webkit-box-align: center;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
}
.control {
-webkit-flex-shrink: 0;
-ms-flex-negative: 0;
flex-shrink: 0;
-webkit-box-flex: 0;
-webkit-flex-grow: 0;
-ms-flex-positive: 0;
flex-grow: 0;
margin-left: 0;
margin-right: 10px;
&:last-child {
margin-right: 0;
}
&.control-right {
margin-left: auto;
&:first-child {
margin-right: 0;
}
}
&.control-fill {
-webkit-box-flex: 1;
-webkit-flex-grow: 1;
-ms-flex-positive: 1;
flex-grow: 1;
-webkit-flex-shrink: 1;
-ms-flex-negative: 1;
flex-shrink: 1;
}
}
/* Icons */
.icon {
display: inline-block;
font-size: 18px;
vertical-align: text-bottom;
&.icon-24 {
font-size: 24px;
}
&.icon-36 {
font-size: 36px;
}
&.icon-48 {
font-size: 48px;
}
}
/* Buttons */
.icon-button {
display: inline-block;
margin: 0 5px;
color: $colour_FontLight;
cursor: pointer;
outline: none;
background: none;
border: none;
text-align: center;
line-height: 1em;
&:hover {
color: $colour_FontDark;
}
&.button-accent {
&:hover {
color: $colour_AccentDark;
}
}
}
.button-group {
display: inline-block;
position: relative;
margin-right: 5px;
& .button {
margin: 0;
}
}
/* Inputs */
#{ $text_Inputs },
select,
textarea {
width: 100%;
min-width: 150px;
padding: 10px 12px;
font-family: inherit;
font-size: $font_SizeRoot;
line-height: $font_LineHeight;
color: $colour_Font;
background-color: $colour_Background;
border: 1px solid $colour_Border;
border-radius: $border_Radius;
outline: none;
-webkit-transition: border 150ms ease-out;
-moz-transition: border 150ms ease-out;
-o-transition: border 150ms ease-out;
transition: border 150ms ease-out;
&:focus {
border-color: $colour_Accent;
}
&:disabled {
background-color: $colour_BackgroundHeader;
cursor: not-allowed;
}
&:invalid {
border-color: $colour_Danger;
& + .validation-message {
display: block;
}
}
}
#{ $text_Inputs },
select {
height: 42px;
}
input[type="checkbox"],
input[type="radio"] {
opacity: 0;
}
.toggle {
display: inline-block;
position: relative;
margin-right: 5px;
background-color: $colour_BackgroundHeader;
border: 1px solid $colour_Border;
vertical-align: text-bottom;
& label {
position: absolute;
display: block;
content: " ";
margin: 0;
cursor: pointer;
}
& + label {
display: inline-block;
margin: 0 15px 0 0;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
}
.toggle-switch {
width: 32px;
height: 18px;
border-radius: 12px;
& label {
top: 0;
left: 0;
width: 32px;
height: 18px;
&:after {
position: absolute;
display: block;
content: " ";
width: 12px;
height: 12px;
top: 2px;
left: 2px;
background-color: $colour_FontLight;
border-radius: 50%;
-webkit-transition: all 200ms ease-out;
-moz-transition: all 200ms ease-out;
-o-transition: all 200ms ease-out;
transition: all 200ms ease-out;
}
}
&:hover {
& label {
&:after {
background-color: $colour_Accent;
}
}
}
& input[type="checkbox"] {
&:focus {
& label {
&:after {
background-color: $colour_Accent;
}
}
}
&:checked {
& + label {
&:after {
left: 16px;
background-color: $colour_Accent;
}
}
}
&:disabled {
& + label {
&:after {
background-color: $colour_FontLight;
}
}
}
}
}
.toggle-checkbox {
width: 18px;
height: 18px;
border: none;
& label {
width: 18px;
height: 18px;
top: 0;
left: 0;
border: 1px solid $colour_Border;
border-radius: $border_Radius;
-webkit-transition: border 150ms ease-out;
-moz-transition: border 150ms ease-out;
-o-transition: border 150ms ease-out;
transition: border 150ms ease-out;
&:after {
position: absolute;
display: block;
content: " ";
width: 6px;
height: 12px;
top: 1px;
left: 5px;
border-right: 3px solid transparent;
border-bottom: 3px solid transparent;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
-o-transform: rotate(45deg);
transform: rotate(45deg);
-webkit-transition: all 200ms ease-out;
-moz-transition: all 200ms ease-out;
-o-transition: all 200ms ease-out;
transition: all 200ms ease-out;
}
&:hover {
border-color: $colour_Accent;
}
}
& input[type="checkbox"] {
&:focus {
& label {
border-color: $colour_Accent;
}
}
&:checked {
& + label {
background-color: $colour_Accent;
border-color: $colour_Accent;
&:after {
border-color: $colour_Background;
}
}
}
}
}
.toggle-radio {
width: 18px;
height: 18px;
border-radius: 50%;
-webkit-transition: border 150ms ease-out;
-moz-transition: border 150ms ease-out;
-o-transition: border 150ms ease-out;
transition: border 150ms ease-out;
& label {
top: 0;
left: 0;
width: 18px;
height: 18px;
&:after {
position: absolute;
display: block;
content: " ";
width: 10px;
height: 10px;
top: 3px;
left: 3px;
background-color: $colour_FontLight;
border-radius: 50%;
-webkit-transition: all 200ms ease-out;
-moz-transition: all 200ms ease-out;
-o-transition: all 200ms ease-out;
transition: all 200ms ease-out;
}
}
&:hover {
border-color: $colour_Accent;
}
& input[type="radio"] {
&:focus {
& label {
&:after {
background-color: $colour_Accent;
}
}
}
&:checked {
& + label {
&:after {
background-color: $colour_Accent;
}
}
}
}
}
/* Tables */
.table-wrapper {
background-color: $colour_Background;
border: 1px solid $colour_Border;
border-radius: $border_Radius;
&.table-wrapper-responsive {
max-width: 100%;
overflow-x: auto;
& table,
& .table {
table-layout: auto;
width: auto;
min-width: 100%;
}
}
& table,
& .table {
border: none;
}
}
table,
.table {
display: table;
table-layout: fixed;
border-collapse: collapse;
border-spacing: 0;
width: 100%;
border: 1px solid $colour_Border;
}
.table-striped {
& tbody,
& .tbody {
& tr,
& .tr {
&:nth-child(odd) {
& td,
& .td {
background-color: $colour_BackgroundStripe;
}
}
}
}
}
thead,
.thead {
display: table-header-group;
}
tbody,
.tbody {
display: table-row-group;
&:last-of-type {
& tr {
&:last-child {
& td,
& .td {
border-bottom: none;
}
}
}
}
& td,
& .td {
border-bottom: 1px solid $colour_BorderLight;
& > #{ $text_Inputs } {
background-color: transparent;
border: none;
height: auto;
padding: 0;
}
}
}
tfoot,
.tfoot {
display: table-footer-group;
& td,
& .td {
background-color: $colour_BackgroundHeader;
border-top: 1px solid $colour_Border;
}
}
th,
.th,
td,
.td {
display: table-cell;
padding: 8px 15px;
text-align: left;
vertical-align: middle;
&:not(:last-of-type) {
border-right: 1px solid $colour_Border;
}
}
th,
.th {
padding: 15px;
font-weight: 600;
color: $colour_FontDark;
background-color: $colour_BackgroundHeader;
border-bottom: 1px solid $colour_Border;
white-space: nowrap;
& .toggle {
background-color: $colour_Background;
}
}
tr,
.tr {
&.table-group-header {
& td {
font-weight: 600;
background-color: $colour_BackgroundHeader;
}
}
}
/* Dropdown */
.dropdown {
position: absolute;
top: 100%;
left: 0;
min-width: 150px;
margin-top: 5px;
background-color: $colour_Background;
border: 1px solid $colour_Border;
border-radius: $border_Radius;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.15);
-webkit-transform-origin: top left;
-moz-transform-origin: top left;
-ms-transform-origin: top left;
-o-transform-origin: top left;
transform-origin: top left;
z-index: 98;
overflow: hidden;
overflow-y: auto;
&.dropdown-top-left,
&.dropdown-bottom-left {
left: auto;
right: 0;
}
&.dropdown-bottom-left,
&.dropdown-bottom-right {
top: auto;
bottom: 100%;
margin-top: 0;
margin-bottom: 5px;
}
&.dropdown-top-left {
-webkit-transform-origin: top right;
-moz-transform-origin: top right;
-ms-transform-origin: top right;
-o-transform-origin: top right;
transform-origin: top right;
}
&.dropdown-bottom-left {
left: auto;
right: 0;
-webkit-transform-origin: bottom right;
-moz-transform-origin: bottom right;
-ms-transform-origin: bottom right;
-o-transform-origin: bottom right;
transform-origin: bottom right;
}
&.dropdown-bottom-right {
-webkit-transform-origin: bottom left;
-moz-transform-origin: bottom left;
-ms-transform-origin: bottom left;
-o-transform-origin: bottom left;
transform-origin: bottom left;
}
& .menu-item {
padding: 10px 15px;
cursor: pointer;
&:hover {
background-color: $colour_BackgroundHeaderDark;
}
}
}
.dropdown-transition {
-webkit-transition: opacity 100ms ease-out, transform 100ms ease-out;
-moz-transition: opacity 100ms ease-out, transform 100ms ease-out;
-moz-transition: opacity 100ms ease-out, transform 100ms ease-out;
-o-transition: opacity 100ms ease-out, transform 100ms ease-out;
transition: opacity 100ms ease-out, transform 100ms ease-out;
opacity: 1;
-webkit-transform: translate(0, 0) scale(1);
-moz-transform: translate(0, 0) scale(1);
-ms-transform: translate(0, 0) scale(1);
-o-transform: translate(0, 0) scale(1);
transform: translate(0, 0) scale(1);
}
.dropdown-enter,
.dropdown-leave {
opacity: 0;
-webkit-transform: translate(0, -15px) scale(0.85);
-moz-transform: translate(0, -15px) scale(0.85);
-ms-transform: translate(0, -15px) scale(0.85);
-o-transform: translate(0, -15px) scale(0.85);
transform: translate(0, -15px) scale(0.85);
}
/* Chips */
.chips {
display: inline-block;
margin: 0;
padding: 0;
list-style: none;
}
.chip {
display: inline-block;
position: relative;
margin: 5px 5px 5px 0;
padding: 5px 15px;
font-size: $font_SizeRoot;
font-weight: 600;
line-height: $font_LineHeight;
color: $colour_FontDark;
background-color: $colour_BackgroundHeader;
border: 1px solid $colour_Border;
border-radius: $border_Radius;
vertical-align: middle;
&.chip-removable {
padding-right: 48px;
}
&.chip-accent,
&.chip-business,
&.chip-danger,
&.chip-warning,
&.chip-success {
& .chip-title,
& .chip-subtitle {
color: $colour_FontInverted;
}
& .chip-remove-button {
&:before,
&:after {
background-color: $colour_FontInverted;
}
}
}
&.chip-accent {
background-color: $colour_Accent;
border-color: $colour_Accent;
& .chip-remove-button {
&:hover {
background-color: $colour_AccentDark;
}
}
}
}
.chip-title,
.chip-subtitle {
display: block;
}
.chip-title {
font-size: $font_SizeRoot;
font-weight: 600;
color: $colour_FontDark;
}
.chip-subtitle {
font-size: $font_SizeMinor;
font-weight: 400;
color: $colour_FontLight;
}
.chip-remove-button {
position: absolute;
top: 50%;
right: 15px;
width: 18px;
height: 18px;
margin-top: -9px;
cursor: pointer;
border-radius: $border_Radius;
-moz-transition: background 150ms ease-out;
-o-transition: background 150ms ease-out;
-webkit-transition: background 150ms ease-out;
transition: background 150ms ease-out;
&:before,
&:after {
display: block;
position: absolute;
content: " ";
top: 50%;
left: 50%;
width: 16px;
height: 2px;
margin-top: -1px;
margin-left: -8px;
background-color: $colour_Font;
-moz-transform-origin: center center;
-ms-transform-origin: center center;
-o-transform-origin: center center;
-webkit-transform-origin: center center;
transform-origin: center center;
-moz-transition: background 150ms ease-out;
-o-transition: background 150ms ease-out;
-webkit-transition: background 150ms ease-out;
transition: background 150ms ease-out;
}
&:before {
-moz-transform: rotate(-45deg);
-ms-transform: rotate(-45deg);
-o-transform: rotate(-45deg);
-webkit-transform: rotate(-45deg);
transform: rotate(-45deg);
}
&:after {
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
-o-transform: rotate(45deg);
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
}
&:hover {
background-color: $colour_Accent;
&:before,
&:after {
background-color: $colour_FontInverted;
}
}
}
.chip-transition {
-webkit-transition: transform 100ms ease-out;
-moz-transition: transform 100ms ease-out;
-o-transition: transform 100ms ease-out;
transition: transform 100ms ease-out;
opacity: 1;
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1);
}
.chip-enter,
.chip-leave {
opacity: 0;
-webkit-transform: scale(0);
-moz-transform: scale(0);
-ms-transform: scale(0);
-o-transform: scale(0);
transform: scale(0);
}
/* Datagrid */
.datagrid {
& .chip {
background-color: $colour_Background;
}
}
.datagrid-header {
cursor: pointer;
-moz-user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
user-select: none;
}
.datagrid-toggle-column {
width: 64px;
text-align: center;
& .toggle {
margin: 0;
}
}
.datagrid-options {
padding: 15px;
& table,
& .table {
table-layout: auto;
}
}
.datagrid-options-row {
&:not(:first-child) {
margin-top: 15px;
}
}
#index {
margin-bottom: 64px;
}
@media screen and (max-width: #{ $layout_containerWidth + $layout_scrollbarWidth }) {
.container {
width: 100% !important;
}
}
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,300,400italic,600,600italic,700" rel="stylesheet" />
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment