Skip to content

Commit 1a762c8

Browse files
authored
Merge pull request #68 from makepanic/issues/15
feat(items): use ember light table with sorting capabilities
2 parents b835d6b + b924e00 commit 1a762c8

30 files changed

+390
-87
lines changed

.eslintrc.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,7 @@ module.exports = {
1414
env: {
1515
browser: true
1616
},
17-
rules: {}
17+
rules: {
18+
'ember-suave/no-const-outside-module-scope': 'off'
19+
}
1820
};

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,7 @@
1515
/libpeerconnection.log
1616
npm-debug.log*
1717
testem.log
18+
19+
# intellij data
20+
.idea
21+
*.iml

app/breakpoints.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export default {
2+
mobile: '(max-width: 767px)',
3+
tablet: '(min-width: 768px) and (max-width: 991px)',
4+
desktop: '(min-width: 992px) and (max-width: 1200px)'
5+
};

app/components/cell-project.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import Ember from 'ember';
2+
3+
const { Component } = Ember;
4+
5+
export default Component.extend({
6+
});

app/components/cell-title.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import Ember from 'ember';
2+
3+
const { Component } = Ember;
4+
5+
export default Component.extend({
6+
});

app/components/issues-table.js

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import Ember from 'ember';
2+
import Table from 'ember-light-table';
3+
import moment from 'moment';
4+
5+
const { Component, computed, observer } = Ember;
6+
7+
export default Component.extend({
8+
table: undefined,
9+
enableSync: true,
10+
11+
sort: 'updatedAt',
12+
dir: 'desc',
13+
14+
sortedModel: computed.sort('issues', 'sortBy').readOnly(),
15+
sortBy: computed('dir', 'sort', function() {
16+
return [
17+
`${this.get('sort')}:${this.get('dir')}`,
18+
// always also sort by updatedAt to be "stable"
19+
`updatedAt:${this.get('dir')}`
20+
];
21+
}).readOnly(),
22+
23+
sortedModelChanged: observer('sortedModel.[]', function() {
24+
this.get('table').setRows(this.get('sortedModel'));
25+
}),
26+
27+
columns: computed(function() {
28+
return [{
29+
label: 'Project',
30+
valuePath: 'project',
31+
cellComponent: 'cell-project'
32+
}, {
33+
label: 'Title',
34+
valuePath: 'title',
35+
cellComponent: 'cell-title'
36+
}, {
37+
label: 'Working On',
38+
valuePath: 'workingOn'
39+
}, {
40+
label: 'Updated At',
41+
valuePath: 'updatedAt',
42+
format: (rawValue) => moment(rawValue).format('MM-DD-YYYY')
43+
}];
44+
}),
45+
46+
init() {
47+
this._super(...arguments);
48+
49+
let table = new Table(this.get('columns'), this.get('sortedModel'), {
50+
enableSync: false
51+
});
52+
53+
let sortColumn = table.get('allColumns').findBy('valuePath', this.get('sort'));
54+
55+
// Setup initial sort column
56+
if (sortColumn) {
57+
sortColumn.set('sorted', true);
58+
}
59+
60+
this.set('table', table);
61+
},
62+
63+
actions: {
64+
onColumnClick(data) {
65+
const { valuePath } = data;
66+
const sort = this.get('sort');
67+
68+
if (valuePath === sort) {
69+
this.set('dir', this.get('dir') === 'desc' ? 'asc' : 'desc');
70+
} else {
71+
this.set('sort', valuePath);
72+
this.set('dir', 'desc');
73+
}
74+
75+
this.get('onSortChanged')([this.get('sort'), this.get('dir')]);
76+
}
77+
}
78+
});

app/controllers/items.js

+7
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,16 @@ import Ember from 'ember';
33
const { Controller, computed } = Ember;
44

55
export default Controller.extend({
6+
queryParams: ['sort', 'dir'],
7+
sort: 'updatedAt',
8+
dir: 'desc',
9+
610
openIssues: computed.filterBy('model', 'state', 'open'),
711

812
actions: {
13+
onSortChanged([sort, dir]) {
14+
this.setProperties({ sort, dir });
15+
},
916
createDummyIssue() {
1017
// create a dummy issue (for dev/testing purposes)
1118
let closedIssue = this.store.createRecord('issue', {

app/initializers/responsive.js

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { initialize } from 'ember-responsive/initializers/responsive';
2+
3+
/**
4+
* Ember responsive initializer
5+
*
6+
* Supports auto injecting media service app-wide.
7+
*
8+
* Generated by the ember-responsive addon. Customize initialize to change
9+
* injection.
10+
* @public
11+
*/
12+
13+
export default {
14+
name: 'responsive',
15+
initialize
16+
};

app/styles/components/_all.scss

+1
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@
77
@import "highlight";
88
@import "toc";
99
@import "old-version-warning";
10+
@import "ember-light-table";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.ember-light-table{
2+
.lt-head {
3+
table{
4+
margin-bottom: 0;
5+
}
6+
}
7+
}

app/styles/fonts/fontello-codes.css

100755100644
+11-9
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11

2-
.icon-search:before { content: '\e804'; } /* '' */
3-
.icon-cancel:before { content: '\e802'; } /* '' */
4-
.icon-link:before { content: '\e803'; } /* '' */
5-
.icon-pencil:before { content: '\e801'; } /* '' */
6-
.icon-fork:before { content: '\e800'; } /* '' */
7-
.icon-github:before { content: '\e806'; } /* '' */
8-
.icon-gplus:before { content: '\e807'; } /* '' */
9-
.icon-twitter:before { content: '\e805'; } /* '' */
10-
.icon-attention-circled:before { content: '\e808'; } /* '' */
2+
.icon-search:before { content: '\e800'; } /* '' */
3+
.icon-cancel:before { content: '\e801'; } /* '' */
4+
.icon-link:before { content: '\e802'; } /* '' */
5+
.icon-pencil:before { content: '\e803'; } /* '' */
6+
.icon-attention-circled:before { content: '\e804'; } /* '' */
7+
.icon-twitter:before { content: '\f099'; } /* '' */
8+
.icon-gplus:before { content: '\f0d5'; } /* '' */
9+
.icon-sort-down:before { content: '\f0dd'; } /* '' */
10+
.icon-sort-up:before { content: '\f0de'; } /* '' */
11+
.icon-github:before { content: '\f113'; } /* '' */
12+
.icon-fork:before { content: '\f126'; } /* '' */

app/styles/fonts/fontello-embedded.css

100755100644
+17-15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/styles/fonts/fontello-ie7-codes.css

100755100644
+11-9
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11

2-
.icon-search { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
3-
.icon-cancel { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
4-
.icon-link { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
5-
.icon-pencil { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
6-
.icon-fork { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
7-
.icon-github { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
8-
.icon-gplus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
9-
.icon-twitter { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
10-
.icon-attention-circled { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
2+
.icon-search { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
3+
.icon-cancel { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
4+
.icon-link { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
5+
.icon-pencil { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
6+
.icon-attention-circled { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
7+
.icon-twitter { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
8+
.icon-gplus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
9+
.icon-sort-down { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
10+
.icon-sort-up { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
11+
.icon-github { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
12+
.icon-fork { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }

app/styles/fonts/fontello-ie7.css

100755100644
+11-9
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@
1010
/* font-size: 120%; */
1111
}
1212

13-
.icon-search { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
14-
.icon-cancel { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
15-
.icon-link { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
16-
.icon-pencil { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
17-
.icon-fork { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
18-
.icon-github { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
19-
.icon-gplus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
20-
.icon-twitter { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
21-
.icon-attention-circled { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
13+
.icon-search { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
14+
.icon-cancel { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
15+
.icon-link { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
16+
.icon-pencil { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
17+
.icon-attention-circled { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
18+
.icon-twitter { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
19+
.icon-gplus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
20+
.icon-sort-down { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
21+
.icon-sort-up { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
22+
.icon-github { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
23+
.icon-fork { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }

app/styles/fonts/fontello.scss

100755100644
+30-23
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
@font-face {
22
font-family: 'fontello';
3-
src: font-url('../../fonts/fontello.eot?36004245');
4-
src: font-url('../../fonts/fontello.eot?36004245#iefix') format('embedded-opentype'),
5-
font-url('../../fonts/fontello.woff?36004245') format('woff'),
6-
font-url('../../fonts/fontello.ttf?36004245') format('truetype'),
7-
font-url('../../fonts/fontello.svg?36004245#fontello') format('svg');
3+
src: url('../font/fontello.eot?43643500');
4+
src: url('../font/fontello.eot?43643500#iefix') format('embedded-opentype'),
5+
url('../font/fontello.woff2?43643500') format('woff2'),
6+
url('../font/fontello.woff?43643500') format('woff'),
7+
url('../font/fontello.ttf?43643500') format('truetype'),
8+
url('../font/fontello.svg?43643500#fontello') format('svg');
89
font-weight: normal;
910
font-style: normal;
1011
}
@@ -14,48 +15,54 @@
1415
@media screen and (-webkit-min-device-pixel-ratio:0) {
1516
@font-face {
1617
font-family: 'fontello';
17-
src: url('../font/fontello.svg?60624967#fontello') format('svg');
18+
src: url('../font/fontello.svg?43643500#fontello') format('svg');
1819
}
1920
}
2021
*/
21-
22+
2223
[class^="icon-"]:before, [class*=" icon-"]:before {
2324
font-family: "fontello";
2425
font-style: normal;
2526
font-weight: normal;
2627
speak: none;
27-
28+
2829
display: inline-block;
2930
text-decoration: inherit;
3031
width: 1em;
3132
margin-right: .2em;
3233
text-align: center;
3334
/* opacity: .8; */
34-
35+
3536
/* For safety - reset parent styles, that can break glyph codes*/
3637
font-variant: normal;
3738
text-transform: none;
38-
39+
3940
/* fix buttons height, for twitter bootstrap */
4041
line-height: 1em;
41-
42+
4243
/* Animation center compensation - margins should be symmetric */
4344
/* remove if not needed */
4445
margin-left: .2em;
45-
46+
4647
/* you can be more comfortable with increased icons size */
4748
/* font-size: 120%; */
48-
49+
50+
/* Font smoothing. That was taken from TWBS */
51+
-webkit-font-smoothing: antialiased;
52+
-moz-osx-font-smoothing: grayscale;
53+
4954
/* Uncomment for 3D effect */
5055
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
5156
}
52-
53-
.icon-search:before { content: '\e804'; } /* '' */
54-
.icon-cancel:before { content: '\e802'; } /* '' */
55-
.icon-link:before { content: '\e803'; } /* '' */
56-
.icon-pencil:before { content: '\e801'; } /* '' */
57-
.icon-fork:before { content: '\e800'; } /* '' */
58-
.icon-github:before { content: '\e806'; } /* '' */
59-
.icon-gplus:before { content: '\e807'; } /* '' */
60-
.icon-twitter:before { content: '\e805'; } /* '' */
61-
.icon-attention-circled:before { content: '\e808'; } /* '' */
57+
58+
.icon-search:before { content: '\e800'; } /* '' */
59+
.icon-cancel:before { content: '\e801'; } /* '' */
60+
.icon-link:before { content: '\e802'; } /* '' */
61+
.icon-pencil:before { content: '\e803'; } /* '' */
62+
.icon-attention-circled:before { content: '\e804'; } /* '' */
63+
.icon-twitter:before { content: '\f099'; } /* '' */
64+
.icon-gplus:before { content: '\f0d5'; } /* '' */
65+
.icon-sort-down:before { content: '\f0dd'; } /* '' */
66+
.icon-sort-up:before { content: '\f0de'; } /* '' */
67+
.icon-github:before { content: '\f113'; } /* '' */
68+
.icon-fork:before { content: '\f126'; } /* '' */
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<a href="{{row.projectLink}}" rel="noopener noreferrer" target="_blank">{{row.project}}</a>
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<a href="{{row.link}}" rel="noopener noreferrer" target="_blank">{{row.title}}</a>
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{{#light-table table as |t|}}
2+
{{t.head
3+
iconAscending='icon-sort-down'
4+
iconDescending='icon-sort-up'
5+
onColumnClick=(action 'onColumnClick')
6+
}}
7+
{{#t.body
8+
canSelect=false
9+
as |body|
10+
}}
11+
{{#if isLoading}}
12+
{{#body.loader}}
13+
{{table-loader}}
14+
{{/body.loader}}
15+
{{/if}}
16+
{{/t.body}}
17+
18+
{{/light-table}}

app/templates/items.hbs

+7-18
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,9 @@
11
<p>The items below could all use some love and attention. Please, grab one!</p>
2-
<table>
3-
<thead>
4-
<tr>
5-
<th>Project</th>
6-
<th>Title</th>
7-
<th>Working On</th>
8-
</tr>
9-
</thead>
10-
<tbody>
11-
{{#each openIssues as |item|}}
12-
<tr>
13-
<td><a href="{{item.projectLink}}" target="_blank">{{item.project}}</a></td>
14-
<td><a href="{{item.link}}" target="_blank">{{item.title}}</a></td>
15-
<td></td>
16-
</tr>
17-
{{/each}}
18-
</tbody>
19-
</table>
2+
3+
{{issues-table
4+
issues=openIssues
5+
sort=sort
6+
dir=dir
7+
onSortChanged=(action 'onSortChanged')}}
8+
209
{{outlet}}

mirage/factories/issue.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ export default Factory.extend({
77
number(i) {
88
return `${i + 3000}`;
99
},
10-
org: faker.random.arrayElement(['ember-cli', 'emberjs', 'ember-learn']),
11-
repo: faker.random.arrayElement(['ember.js', 'guides', 'ember-cli', 'data']),
12-
state: faker.random.arrayElement(['open', 'closed']),
10+
org: () => faker.random.arrayElement(['ember-cli', 'emberjs', 'ember-learn']),
11+
repo: () => faker.random.arrayElement(['ember.js', 'guides', 'ember-cli', 'data']),
12+
state: () => faker.random.arrayElement(['open', 'closed']),
1313
title: faker.hacker.phrase,
1414

1515
createdAt: faker.date.recent,

0 commit comments

Comments
 (0)