Skip to content

Instantly share code, notes, and snippets.

@krukid
Last active October 1, 2019 18:25
Show Gist options
  • Save krukid/20cf337bcebd5991710842e4420d8a32 to your computer and use it in GitHub Desktop.
Save krukid/20cf337bcebd5991710842e4420d8a32 to your computer and use it in GitHub Desktop.
mint-table
import Ember from 'ember';
import { computed } from '@ember/object';
// @prop tableModel
export default Ember.Component.extend({
selectedColumn: null,
visibleColumns: computed('tableModel.columns.@each.options', function() {
return this.tableModel.columns.rejectBy('options.hidden');
}),
hiddenColumns: computed('tableModel.columns.@each.options', function() {
return this.tableModel.columns.filterBy('options.hidden');
}),
actions: {
showColumn(column) {
this.tableModel.showColumn(column);
},
hideColumn(column) {
this.tableModel.hideColumn(column);
},
restoreDefaults() {
this.tableModel.resetColumns();
},
selectColumn(column) {
if (this.selectedColumn === null) {
this.set('selectedColumn', column);
} else {
this.tableModel.moveColumn(this.selectedColumn, column);
this.set('selectedColumn', null);
}
},
},
});
import Component from '@ember/component';
import { computed } from '@ember/object';
import { textAlignClass } from 'app/utils/text';
// @prop column
export default Component.extend({
tagName: 'th',
attributeBindings: ['column.hint:title'],
classNameBindings: ['textAlignClass'],
textAlignClass: computed('column.options.align', function() {
return textAlignClass(this.get('column.options.align'));
}),
});
import Component from '@ember/component';
import { computed } from '@ember/object';
import { textAlignClass } from 'app/utils/text';
// @prop column
// @prop row
export default Component.extend({
tagName: 'td',
classNameBindings: ['textAlignClass'],
fields: computed('column', function() {
return this.column.fields.split(':');
}),
data: computed('fields', 'row', function() {
return this.fields.map(f => this.row[f]);
}),
textAlignClass: computed('column.options.align', function() {
return textAlignClass(this.get('column.options.align'));
}),
});
import TableItem from '../mint-table-item';
import { computed } from '@ember/object';
export default TableItem.extend({
time: computed.alias('data.0'),
formattedTime: computed('time', function() {
return new Date(this.time).toUTCString();
}),
});
import TableItem from '../mint-table-item';
import { computed } from '@ember/object';
export default TableItem.extend({
text: computed.alias('data.0'),
});
import TableItem from '../mint-table-item';
import { computed } from '@ember/object';
import { stateColorClass } from 'app/utils/colors';
export default TableItem.extend({
id: computed.alias('data.0'),
state: computed.alias('data.1'),
classNameBindings: ['stateColorClass'],
stateColorClass: computed('state', function() {
return stateColorClass(this.state);
}),
});
import Ember from 'ember';
import { computed } from '@ember/object';
// @prop tableModel
export default Ember.Component.extend({
visibleColumns: computed('tableModel.columns.@each.options', function() {
return this.tableModel.columns.rejectBy('options.hidden');
}),
});
import TableItem from '../mint-table-item';
import { computed } from '@ember/object';
export default TableItem.extend({
text: computed.alias('data.0'),
});
import TableItem from '../mint-table-item';
import { computed } from '@ember/object';
export default TableItem.extend({
features: computed.alias('data.0'),
isPlusAccount: computed.equal('features.plus_state', 'unlocked'),
isVerifiedAccount: computed.alias('features.verified'),
isPrivateAccount: computed.alias('features.private_account'),
});
import TableItem from '../mint-table-item';
import { computed } from '@ember/object';
export default TableItem.extend({
followerCount: computed.alias('data.0'),
friendCount: computed.alias('data.1'),
});
import Controller from '@ember/controller';
import TableModel from 'app/utils/table-model';
import { userColumns } from 'app/utils/table-columns';
export default Controller.extend({
tableModel: null,
tableData: null,
loadTableData() {
this.set('tableData', [
{id: 1, state: 'active', name: 'Mike', username: 'mikoo.lol89', email: 'mike@foo.com', country_code: 'LV', create_time: new Date().getTime(), follower_count: 3, friend_count: 0, features: {plus_state: 'locked', verified: true}},
{id: 2, state: 'banned', name: 'Dick', username: 'dikless1', email: 'dick@foo.com', country_code: 'US', create_time: new Date().getTime(), follower_count: 0, friend_count: 15, features: {plus_state: 'unlocked', private_account: true}},
{id: 3, state: 'deactivated', name: 'Luke', username: 'skystr0ll3r', email: 'luke@foo.com', country_code: 'EN', create_time: new Date().getTime(), follower_count: 10, friend_count: 2, features: {plus_state: 'locked', verified: true, private_account: true}},
{id: 4, state: 'deleted', name: 'Jack', username: 'j4khammer', email: 'jack@foo.com', country_code: 'RU', create_time: new Date().getTime(), follower_count: 23, friend_count: 11, features: {plus_state: 'locked'}},
]);
},
createTableModel() {
this.set('tableModel', new TableModel({
name: 'aboutData',
columns: userColumns,
data: this.tableData,
}));
},
init() {
this._super(...arguments);
this.loadTableData();
this.createTableModel();
},
});
import Ember from 'ember';
export default Ember.Controller.extend({
appName: 'Ember Twiddle'
});
import Controller from '@ember/controller';
import TableModel from 'app/utils/table-model';
import { userColumns } from 'app/utils/table-columns';
export default Controller.extend({
tableModel: null,
tableData: null,
loadTableData() {
this.set('tableData', [
{id: 1, state: 'active', name: 'Mike', username: 'mikoo.lol89', email: 'mike@foo.com', country_code: 'LV', create_time: new Date().getTime(), follower_count: 3, friend_count: 0, features: {plus_state: 'locked', verified: true}},
{id: 2, state: 'banned', name: 'Dick', username: 'dikless1', email: 'dick@foo.com', country_code: 'US', create_time: new Date().getTime(), follower_count: 0, friend_count: 15, features: {plus_state: 'unlocked', private_account: true}},
{id: 3, state: 'deactivated', name: 'Luke', username: 'skystr0ll3r', email: 'luke@foo.com', country_code: 'EN', create_time: new Date().getTime(), follower_count: 10, friend_count: 2, features: {plus_state: 'locked', verified: true, private_account: true}},
{id: 4, state: 'deleted', name: 'Jack', username: 'j4khammer', email: 'jack@foo.com', country_code: 'RU', create_time: new Date().getTime(), follower_count: 23, friend_count: 11, features: {plus_state: 'locked'}},
]);
},
createTableModel() {
this.set('tableModel', new TableModel({
name: 'homeData',
columns: userColumns,
data: this.tableData,
}));
},
init() {
this._super(...arguments);
this.loadTableData();
this.createTableModel();
},
});
import Ember from 'ember';
export function eq([a, b]/*, hash*/) {
return a === b;
}
export default Ember.Helper.helper(eq);
import EmberRouter from '@ember/routing/router';
import config from './config/environment';
const Router = EmberRouter.extend({
location: 'none',
rootURL: config.rootURL,
});
Router.map(function() {
this.route('about');
this.route('user', {path: 'user/:id'});
});
export default Router;
@import 'https://cdnjs.cloudflare.com/ajax/libs/uikit/3.2.0/css/uikit.min.css';
body {
margin: 0;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 12pt;
}
.uk-table th[title] {
text-decoration: underline dotted;
}
.mint-color--green {
background: green;
color: white;
}
.mint-color--red {
background: red;
color: white;
}
.mint-color--gray {
background: gray;
color: white;
}
.mint-color--orange {
background: orange;
color: white;
}
.mint-table__divider {
border-right: solid 1px #e5e5e5;
margin: 0 20px;
}
<div class="uk-container uk-padding">
<h1 class="uk-heading-small">Welcome to About</h1>
<p>
About table data below
</p>
<p>
{{mint-table tableModel=tableModel}}
</p>
<p>
Edit home table columns
</p>
<p>
{{mint-table-editor tableModel=tableModel}}
</p>
</div>
<nav class="uk-navbar-container">
<div class="uk-navbar-left">
<ul class="uk-navbar-nav">
{{#link-to "index" activeClass="uk-active" tagName="li"}}<a>Home</a>{{/link-to}}
{{#link-to "about" activeClass="uk-active" tagName="li"}}<a>About</a>{{/link-to}}
</ul>
</div>
</nav>
{{outlet}}
<div class="uk-section uk-section-muted uk-padding-remove-vertical">
<div class="uk-padding">
<div class="uk-flex uk-flex-between uk-flex-stretch">
<div class="uk-flex-1">
<ul class="uk-list uk-list-divider">
{{#each hiddenColumns as |column|}}
<li
class={{if (eq column selectedColumn) "uk-background-primary"}}
{{action "selectColumn" column}}
>
<a href="#" {{action "showColumn" column}}>➡️</a>
{{column.label}} &ndash; {{column.options.index}}
</li>
{{/each}}
</ul>
</div>
<div class="mint-table__divider"></div>
<div class="uk-flex-1">
<ul class="uk-list uk-list-divider">
{{#each visibleColumns as |column|}}
<li
class={{if (eq column selectedColumn) "uk-background-primary"}}
{{action "selectColumn" column}}
>
<a href="#" {{action "hideColumn" column}}>⬅️</a>
{{column.label}} &ndash; {{column.options.index}}
</li>
{{/each}}
</ul>
</div>
</div>
</div>
</div>
<a href="#" {{action "restoreDefaults"}}>Restore defaults</a>
<table class="uk-table uk-table-small">
<thead>
<tr>
{{#each visibleColumns as |column|}}
{{mint-table-head column=column}}
{{/each}}
</tr>
</thead>
<tbody>
{{#each tableModel.data as |row|}}
<tr>
{{#each visibleColumns as |column|}}
{{component
(concat 'mint-table/' column.component)
column=column
row=row
}}
{{/each}}
</tr>
{{/each}}
</tbody>
</table>
{{if isPlusAccount "💰"}}
{{if isVerifiedAccount "⭐️"}}
{{if isPrivateAccount "🔒"}}
<div class="uk-container uk-padding">
<h1 class="uk-heading-small">Welcome to Home</h1>
<p>
Home table data below
</p>
<p>
{{mint-table tableModel=tableModel}}
</p>
<p>
Edit home table columns
</p>
<p>
{{mint-table-editor tableModel=tableModel}}
</p>
</div>
<div class="uk-container uk-padding">
<h1 class="uk-heading-small">Welcome to User</h1>
<p>user</p>
</div>
{
"version": "0.15.1",
"EmberENV": {
"FEATURES": {}
},
"options": {
"use_pods": false,
"enable-testing": false
},
"dependencies": {
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js",
"ember": "3.4.3",
"ember-template-compiler": "3.4.3",
"ember-testing": "3.4.3"
},
"addons": {
"ember-data": "3.4.2"
}
}
export function stateColorClass(state) {
switch (state) {
case 'active':
return 'mint-color--green';
case 'banned':
return 'mint-color--red';
case 'deleted':
return 'mint-color--gray';
case 'deactivated':
return 'mint-color--orange';
}
}
export const userColumns = [
{fields: 'id:state', component: 'id-state', label: 'ID', options: {align: 'center'}},
{fields: 'name', component: 'free-text', label: 'Name'},
{fields: 'id:username', component: 'user-link', label: 'Username'},
{fields: 'email', component: 'free-text', label: 'Email', options: {hidden: true}},
{fields: 'country_code', component: 'short-text', label: 'CTRY', hint: 'Registration country', options: {hidden: true}},
{fields: 'create_time', component: 'date-time', label: 'Created'},
{fields: 'follower_count:friend_count', component: 'user-followings', label: 'FWR/FWG', hint: 'Number of followers / followings', options: {align: 'center'}},
{fields: 'features', component: 'user-features', label: 'FEAT', hint: 'Account features', options: {hidden: true, align: 'center'}},
];
import { get, set } from '@ember/object';
import { copy } from '@ember/object/internals';
export default class TableModel {
constructor({name, columns, data}) {
this.name = name;
this.defaultColumns = columns;
this.data = data;
this.storageKey = `tableModel#${name}`;
this.loadColumns();
}
getColumnKey({component, fields}) {
return `${component}%${fields}`;
}
setColumnOptions(column, options) {
set(column, 'options', {...column.options, ...options});
}
cloneColumns() {
// return copy(this.defaultColumns, true);
return this.defaultColumns.map(column => ({...column}));
}
createColumns(options) {
const columns = this.cloneColumns();
columns.forEach((column, index) => {
const key = this.getColumnKey(column);
this.setColumnOptions(column, {index, ...options[key]});
});
set(this, 'columns', columns.sortBy('options.index'));
}
loadColumns() {
// const storage = window.localStorage.getItem(this.storageKey);
const storage = `
{
"user-link%id:username": {"hidden": true, "index": -1},
"free-text%name": {"hidden": true, "index": 100}
}
`;
const options = storage ? JSON.parse(storage) : {};
this.createColumns(options);
}
saveColumns() {
const options = this.columns.reduce((obj, column, index) => {
const key = this.getColumnKey(column);
obj[key] = {...column.options, index};
return obj;
}, {});
const storage = JSON.stringify(options);
// window.localStorage.setItem(this.storageKey, storage);
}
resetColumns() {
// window.localStorage.removeItem(this.storageKey);
this.createColumns({});
}
showColumn(column) {
this.setColumnOptions(column, {hidden: false});
this.saveColumns();
}
hideColumn(column) {
this.setColumnOptions(column, {hidden: true});
this.saveColumns();
}
moveColumn(sourceColumn, targetColumn) {
const movedColumns = [];
this.columns.forEach(column => {
if (column === sourceColumn) {
movedColumns.push(targetColumn);
} else if (column === targetColumn) {
movedColumns.push(sourceColumn);
} else {
movedColumns.push(column);
}
});
const sourceOptions = sourceColumn.options;
this.setColumnOptions(sourceColumn, {
hidden: targetColumn.options.hidden,
index: targetColumn.options.index,
});
this.setColumnOptions(targetColumn, {
hidden: sourceOptions.hidden,
index: sourceOptions.index,
});
set(this, 'columns', movedColumns);
}
}
export function textAlignClass(align) {
switch (align) {
case 'right':
return 'uk-text-right';
case 'center':
return 'uk-text-center';
default:
return 'uk-text-left';
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment