Browse Source

Change project UI from card type to list type

pull/32/head
Hironsan 6 years ago
parent
commit
550dbab37f
8 changed files with 173 additions and 124 deletions
  1. BIN
      app/db.sqlite3
  2. 2
      app/server/static/bundle/projects.js
  3. 49
      app/server/static/css/forum.css
  4. BIN
      app/server/static/images/cat-1045782_640.jpg
  5. BIN
      app/server/static/images/cat-3449999_640.jpg
  6. BIN
      app/server/static/images/tiger-768574_640.jpg
  7. 51
      app/server/static/js/projects.js
  8. 195
      app/server/templates/projects.html

BIN
app/db.sqlite3

2
app/server/static/bundle/projects.js

@ -460,7 +460,7 @@ eval("var g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn th
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.js\");\n/* harmony import */ var axios__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! axios */ \"./node_modules/axios/index.js\");\n/* harmony import */ var axios__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(axios__WEBPACK_IMPORTED_MODULE_1__);\n\n\n\naxios__WEBPACK_IMPORTED_MODULE_1___default.a.defaults.xsrfCookieName = 'csrftoken';\naxios__WEBPACK_IMPORTED_MODULE_1___default.a.defaults.xsrfHeaderName = 'X-CSRFToken';\nconst baseUrl = window.location.href.split('/').slice(0, 3).join('/');\n\n\nconst vm = new vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"]({\n el: '#projects_root',\n delimiters: ['[[', ']]'],\n data: {\n items: [],\n selectedType: 'All',\n isActive: false,\n isDelete: false,\n project: null,\n },\n\n methods: {\n getProjects() {\n axios__WEBPACK_IMPORTED_MODULE_1___default.a.get(`${baseUrl}/api/projects`).then((response) => {\n this.items = response.data;\n });\n },\n\n deleteProject() {\n axios__WEBPACK_IMPORTED_MODULE_1___default.a.delete(`${baseUrl}/api/projects/${this.project.id}/`).then((response) => {\n this.isDelete = false;\n const index = this.items.indexOf(this.project);\n this.items.splice(index, 1);\n });\n },\n\n setProject(project) {\n this.project = project;\n this.isDelete = true;\n },\n\n updateSelectedType(type) {\n this.selectedType = type;\n },\n },\n\n computed: {\n uniqueProjectTypes() {\n const types = [];\n for (let i = 0; i < this.items.length; i++) {\n const item = this.items[i];\n types.push(item.project_type);\n }\n const uniqueTypes = Array.from(new Set(types));\n\n return uniqueTypes;\n },\n\n filteredProjects() {\n // filter projects\n const projects = [];\n for (let i = 0; i < this.items.length; i++) {\n const item = this.items[i];\n if ((this.selectedType === 'All') || (item.project_type === this.selectedType)) {\n projects.push(item);\n }\n }\n // create nested projects\n const nestedProjects = [];\n for (let i = 0; i < Math.ceil(projects.length / 3); i++) {\n const p = projects.slice(i * 3, (i + 1) * 3);\n nestedProjects.push(p);\n }\n return nestedProjects;\n },\n },\n\n created() {\n this.getProjects();\n },\n});\n\n\n//# sourceURL=webpack:///./static/js/projects.js?");
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.js\");\n/* harmony import */ var axios__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! axios */ \"./node_modules/axios/index.js\");\n/* harmony import */ var axios__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(axios__WEBPACK_IMPORTED_MODULE_1__);\n\n\n\naxios__WEBPACK_IMPORTED_MODULE_1___default.a.defaults.xsrfCookieName = 'csrftoken';\naxios__WEBPACK_IMPORTED_MODULE_1___default.a.defaults.xsrfHeaderName = 'X-CSRFToken';\nconst baseUrl = window.location.href.split('/').slice(0, 3).join('/');\n\n\nconst vm = new vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"]({\n el: '#projects_root',\n delimiters: ['[[', ']]'],\n data: {\n items: [],\n isActive: false,\n isDelete: false,\n project: null,\n selected: 'All Project',\n },\n\n methods: {\n\n deleteProject() {\n axios__WEBPACK_IMPORTED_MODULE_1___default.a.delete(`${baseUrl}/api/projects/${this.project.id}/`).then((response) => {\n this.isDelete = false;\n const index = this.items.indexOf(this.project);\n this.items.splice(index, 1);\n });\n },\n\n setProject(project) {\n this.project = project;\n this.isDelete = true;\n },\n\n matchType(projectType) {\n if (projectType === 'DocumentClassification') {\n return this.selected === 'Text Classification';\n }\n if (projectType === 'SequenceLabeling') {\n return this.selected === 'Sequence Labeling';\n }\n if (projectType === 'Seq2seq') {\n return this.selected === 'Seq2seq';\n }\n return false;\n },\n },\n\n computed: {\n selectedProjects() {\n const projects = [];\n for (let item of this.items) {\n if ((this.selected === 'All Project') || this.matchType(item.project_type)) {\n projects.push(item);\n }\n }\n return projects;\n },\n },\n\n created() {\n axios__WEBPACK_IMPORTED_MODULE_1___default.a.get(`${baseUrl}/api/projects`).then((response) => {\n this.items = response.data;\n });\n },\n});\n\n\n//# sourceURL=webpack:///./static/js/projects.js?");
/***/ })

49
app/server/static/css/forum.css

@ -365,6 +365,10 @@ p {
padding-left: 100px;
}
.pl15r {
padding-left: 1.5rem !important;
}
/* Padding Right */
@ -690,4 +694,49 @@ p {
margin-right: 110px;
}
.dataset-item__main {
display: inline-block;
-webkit-box-flex: 2;
-ms-flex: 2 2 66%;
flex: 2 2 66%;
overflow: hidden;
margin: 0 8px 0 8px;
}
.dataset-item__main-title {
font-size: 16px;
font-weight: 500;
line-height: 22px;
}
.dataset-item__main-subtitle {
color: rgba(0,0,0,.55);
font-size: 12px;
font-weight: 400;
line-height: 22px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.dataset-item__main-info {
color: rgba(0,0,0,.4);
font-size: 12px;
font-weight: 400;
line-height: 22px;
}
.is-vertical {
vertical-align:middle !important;
}
.project-thumbnail {
border-radius: 4px;
}
.thumbnail-wrapper {
width:66px;
height:66px;
display:inline-block;
}
[v-cloak] { display: none; }

BIN
app/server/static/images/cat-1045782_640.jpg

Before After
Width: 640  |  Height: 437  |  Size: 132 KiB Width: 436  |  Height: 436  |  Size: 104 KiB

BIN
app/server/static/images/cat-3449999_640.jpg

Before After
Width: 640  |  Height: 426  |  Size: 79 KiB Width: 426  |  Height: 426  |  Size: 65 KiB

BIN
app/server/static/images/tiger-768574_640.jpg

Before After
Width: 640  |  Height: 426  |  Size: 82 KiB Width: 425  |  Height: 426  |  Size: 68 KiB

51
app/server/static/js/projects.js

@ -11,18 +11,13 @@ const vm = new Vue({
delimiters: ['[[', ']]'],
data: {
items: [],
selectedType: 'All',
isActive: false,
isDelete: false,
project: null,
selected: 'All Project',
},
methods: {
getProjects() {
axios.get(`${baseUrl}/api/projects`).then((response) => {
this.items = response.data;
});
},
deleteProject() {
axios.delete(`${baseUrl}/api/projects/${this.project.id}/`).then((response) => {
@ -37,43 +32,35 @@ const vm = new Vue({
this.isDelete = true;
},
updateSelectedType(type) {
this.selectedType = type;
matchType(projectType) {
if (projectType === 'DocumentClassification') {
return this.selected === 'Text Classification';
}
if (projectType === 'SequenceLabeling') {
return this.selected === 'Sequence Labeling';
}
if (projectType === 'Seq2seq') {
return this.selected === 'Seq2seq';
}
return false;
},
},
computed: {
uniqueProjectTypes() {
const types = [];
for (let i = 0; i < this.items.length; i++) {
const item = this.items[i];
types.push(item.project_type);
}
const uniqueTypes = Array.from(new Set(types));
return uniqueTypes;
},
filteredProjects() {
// filter projects
selectedProjects() {
const projects = [];
for (let i = 0; i < this.items.length; i++) {
const item = this.items[i];
if ((this.selectedType === 'All') || (item.project_type === this.selectedType)) {
for (let item of this.items) {
if ((this.selected === 'All Project') || this.matchType(item.project_type)) {
projects.push(item);
}
}
// create nested projects
const nestedProjects = [];
for (let i = 0; i < Math.ceil(projects.length / 3); i++) {
const p = projects.slice(i * 3, (i + 1) * 3);
nestedProjects.push(p);
}
return nestedProjects;
return projects;
},
},
created() {
this.getProjects();
axios.get(`${baseUrl}/api/projects`).then((response) => {
this.items = response.data;
});
},
});

195
app/server/templates/projects.html

@ -6,7 +6,7 @@
<section class="hero project-image">
<div class="container">
<div class="columns">
<div class="column is-12">
<div class="column is-10 is-offset-1">
<h1 class="title is-1 has-text-white">
Hello, {{ user.get_username | title }}.
</h1>
@ -25,105 +25,118 @@
</div>
</section>
<div class="container">
<div class="columns mt0">
<div class="column is-3">
<aside class="menu">
<p class="menu-label">
Categories
</p>
<ul class="menu-list">
<li>
<a v-bind:class="{active: selectedType == 'All' }" v-on:click="updateSelectedType('All')">All</a>
</li>
<li v-for="t in uniqueProjectTypes">
<a v-bind:class="{active: t == selectedType }" v-on:click="updateSelectedType(t)">[[ t ]]</a>
</li>
</ul>
</aside>
</div>
<div class="column is-9">
<!-- Modal card for creating project. -->
<div class="modal" :class="{ 'is-active': isActive }">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Create Project</p>
<button class="delete" aria-label="close" @click="isActive=!isActive"></button>
</header>
<form method="post">
{% csrf_token %}
<section class="modal-card-body">
{% for hidden_field in form.hidden_fields %} {{ hidden_field }} {% endfor %} {% for field in form.visible_fields %}
<div class="field">
{{ field.label_tag }}
<div class="control">
{% render_field field class="input select-height" %}
</div>
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text }}</small>
{% endif %}
</div>
{% endfor %}
</section>
<footer class="modal-card-foot pt20 pb20 pr20 pl20 has-background-white-ter">
<button class="button is-primary">Create</button>
<button class="button" @click="isActive=!isActive">Cancel</button>
</footer>
</form>
<!-- Modal card for creating project. -->
<div class="modal" :class="{ 'is-active': isActive }">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Create Project</p>
<button class="delete" aria-label="close" @click="isActive=!isActive"></button>
</header>
<form method="post">
{% csrf_token %}
<section class="modal-card-body">
{% for hidden_field in form.hidden_fields %}
{{ hidden_field }}
{% endfor %}
{% for field in form.visible_fields %}
<div class="field">
{{ field.label_tag }}
<div class="control">
{% render_field field class="input select-height" %}
</div>
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text }}</small>
{% endif %}
</div>
</div>
{% endfor %}
</section>
<footer class="modal-card-foot pt20 pb20 pr20 pl20 has-background-white-ter">
<button class="button is-primary">Create</button>
<button class="button" @click="isActive=!isActive">Cancel</button>
</footer>
</form>
</div>
</div>
<div class="columns features" v-for="projects in filteredProjects">
<div class="column is-4" v-for="project in projects">
<div class="modal" :class="{ 'is-active': isDelete }">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Delete Project</p>
<button class="delete" aria-label="close" @click="isDelete=!isDelete"></button>
</header>
<section class="modal-card-body">
Are you sure you want to delete project?
</section>
<footer class="modal-card-foot pt20 pb20 pr20 pl20 has-background-white-ter">
<button class="button is-danger" @click="deleteProject()">Delete</button>
<button class="button" @click="isDelete=!isDelete">Cancel</button>
</footer>
</div>
</div>
<div class="card is-shady">
<div class="card-image">
<figure class="image is-4by3">
<img v-bind:src="project.image" alt="Placeholder image">
</figure>
</div>
<div class="card-content">
<div class="content">
<h4>
<a v-bind:href="'/projects/' + project.id">[[ project.name ]]</a>
</h4>
<p>
[[ project.description.slice(0, 50) ]]
</p>
</div>
</div>
{% if user.is_superuser %}
<!-- Modal card for creating project. -->
<div class="modal" :class="{ 'is-active': isDelete }">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Delete Project</p>
<button class="delete" aria-label="close" @click="isDelete=!isDelete"></button>
</header>
<section class="modal-card-body">
Are you sure you want to delete project?
</section>
<footer class="modal-card-foot pt20 pb20 pr20 pl20 has-background-white-ter">
<button class="button is-danger" @click="deleteProject()">Delete</button>
<button class="button" @click="isDelete=!isDelete">Cancel</button>
</footer>
</div>
</div>
<div class="card-footer">
<a v-bind:href="'/projects/' + project.id + '/docs'" class="card-footer-item">Edit</a>
<a href="#1" class="card-footer-item has-text-danger has-text-weight-bold" @click="setProject(project)">Delete</a>
<section class="hero">
<div class="container">
<div class="columns">
<div class="column is-10 is-offset-1">
<div class="card events-card">
<header class="card-header">
<p class="card-header-title">
[[ items.length ]] Projects
</p>
<div class="field card-header-icon">
<div class="control">
<div class="select">
<select v-model="selected">
<option selected>All Project</option>
<option>Text Classification</option>
<option>Sequence Labeling</option>
<option>Seq2seq</option>
</select>
</div>
{% endif %}
</div>
</div>
</header>
<div class="card-table">
<div class="content">
<table class="table is-fullwidth">
<tbody>
<tr v-for="project in selectedProjects">
<td class="pl15r">
<div class="thumbnail-wrapper is-vertical">
<img class="project-thumbnail" v-bind:src="project.image">
</div>
<div class="dataset-item__main is-vertical">
<div class="dataset-item__main-title">
<div class="dataset-item__main-title-link dataset-item__link">
<a v-bind:href="'/projects/' + project.id" class="has-text-black">[[ project.name ]]</a>
</div>
</div>
<div class="dataset-item__main-subtitle">
[[ project.description ]]
</div>
<div class="dataset-item__main-info">
<span class="dataset-item__main-update">updated <span title="Sun Nov 04 2018 07:35:07 GMT+0900 (日本標準時)">11
days ago</span></span></div>
</div>
</td>
<td class="is-vertical"><span class="tag is-normal">[[ project.project_type ]]</span></td>
{% if user.is_superuser %}
<td class="is-vertical"><a v-bind:href="'/projects/' + project.id + '/docs'">Edit</a></td>
<td class="is-vertical"><a class="has-text-danger" @click="setProject(project)">Delete</a></td>
{% endif %}
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
{% endblock %}
{% block footer %}

Loading…
Cancel
Save