You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

337 lines
10 KiB

5 years ago
5 years ago
  1. <template lang="pug">
  2. div(v-cloak="")
  3. messages(v-bind:messages="messages")
  4. div.columns.is-multiline
  5. div.column.is-12
  6. a.button.is-primary(v-on:click="createLabel()") New label
  7. div.column.is-12(v-if="newLabel")
  8. div.box
  9. div.columns.is-multiline
  10. div.column.is-12
  11. div.tags.has-addons.mb0
  12. span.tag.is-medium(v-bind:style="{ \
  13. color: newLabel.text_color, \
  14. backgroundColor: newLabel.background_color \
  15. }") {{ newLabel.text }}
  16. span.tag.is-medium
  17. kbd {{ shortcutKey(newLabel) | simpleShortcut }}
  18. div.column
  19. div.field
  20. label.label Label name
  21. div.control
  22. input.input(
  23. type="text"
  24. placeholder="Text input"
  25. v-model="newLabel.text"
  26. )
  27. div.column
  28. div.field
  29. label.label Shortcut
  30. div.field.has-addons
  31. p.control
  32. span.select
  33. select(v-model="newLabel.prefix_key")
  34. option(value="")
  35. option(value="ctrl") Ctrl
  36. option(value="shift") Shift
  37. option(value="ctrl shift") Ctrl + Shift
  38. div.control
  39. div.select
  40. select(v-model="newLabel.suffix_key")
  41. option(disabled="", value="") key
  42. option(v-for="ch in shortKeys", v-bind:key="ch") {{ ch }}
  43. div.column
  44. div.field
  45. label.label Color
  46. div.field.has-addons
  47. div.control
  48. div.form__field
  49. div.form__input
  50. swatches(
  51. v-model="newLabel.background_color"
  52. colors="basic"
  53. show-fallback=true
  54. popover-to=""
  55. v-bind:trigger-style="{ width: '36px', height: '36px' }"
  56. )
  57. div.control
  58. a.button.random-color-button(
  59. v-on:click="setColor(newLabel)"
  60. )
  61. span.icon.is-small
  62. i.fas.fa-sync-alt
  63. div.column
  64. div.field
  65. label.label &nbsp;
  66. div.field.is-grouped
  67. p.control
  68. a.button.is-light(v-on:click="cancelCreate()") Cancel
  69. p.control
  70. a.button.is-primary(v-on:click="addLabel()") Create label
  71. div.card
  72. header.card-header
  73. p.card-header-title {{ labels.length }} labels
  74. a.card-header-icon(href="#", aria-label="more options")
  75. span.icon
  76. i.fas.fa-angle-down(aria-hidden="true")
  77. div.card-content
  78. div.mb10(v-for="label in labels", v-bind:key="label.id")
  79. div.level.is-mobile.mb0
  80. div.level-left
  81. div.level-item
  82. p.subtitle.is-5
  83. div.tags.has-addons.mb0
  84. span.tag.is-medium(v-bind:style="{ \
  85. color: label.text_color, \
  86. backgroundColor: label.background_color \
  87. }") {{ label.text }}
  88. span.tag.is-medium
  89. kbd {{ shortcutKey(label) | simpleShortcut }}
  90. div.level-right
  91. p.level-item
  92. div.field.is-grouped
  93. p.control
  94. a.button.is-text(v-on:click="editLabel(label)")
  95. span.icon.is-small
  96. i.fas.fa-pencil-alt
  97. span Edit
  98. p.control
  99. a.button.is-text(v-on:click="removeLabel(label)")
  100. span.icon.is-small
  101. i.fas.fa-trash
  102. span Delete
  103. div.columns(v-show="label === editedLabel")
  104. div.column
  105. div.field
  106. label.label Label name
  107. div.control
  108. input.input(
  109. type="text"
  110. placeholder="Text input"
  111. v-model="label.text"
  112. )
  113. div.column
  114. div.field
  115. label.label Shortcut
  116. div.field.has-addons
  117. p.control
  118. span.select
  119. select(v-model="label.prefix_key")
  120. option(value="")
  121. option(value="ctrl") Ctrl
  122. option(value="shift") Shift
  123. option(value="ctrl shift") Ctrl + Shift
  124. div.control
  125. div.select
  126. select(v-model="label.suffix_key")
  127. option(disabled="", value="") key
  128. option(v-for="ch in shortKeys", v-bind:key="ch") {{ ch }}
  129. div.column
  130. div.field
  131. label.label Color
  132. div.field.has-addons
  133. div.control
  134. div.form__field
  135. div.form__input
  136. swatches(
  137. v-model="label.background_color"
  138. colors="basic"
  139. show-fallback=true
  140. popover-to=""
  141. v-bind:trigger-style="{ width: '36px', height: '36px' }"
  142. )
  143. div.control
  144. a.button.random-color-button(
  145. v-on:click="setEditColor"
  146. )
  147. span.icon.is-small
  148. i.fas.fa-sync-alt
  149. div.column
  150. div.field
  151. label.label &nbsp;
  152. div.field.is-grouped
  153. p.control
  154. a.button.is-light(v-on:click="cancelEdit(label)") Cancel
  155. p.control
  156. a.button.is-primary(v-on:click="doneEdit(label)") Save changes
  157. </template>
  158. <style scoped>
  159. .random-color-button {
  160. height: 36px;
  161. width: 36px;
  162. background-color: transparent;
  163. color: #404040;
  164. border: none;
  165. }
  166. </style>
  167. <script>
  168. import Swatches from 'vue-swatches';
  169. import 'vue-swatches/dist/vue-swatches.min.css';
  170. import HTTP from './http';
  171. import Messages from './messages.vue';
  172. import { simpleShortcut } from './filter';
  173. export default {
  174. components: { Messages, Swatches },
  175. filters: { simpleShortcut },
  176. data: () => ({
  177. labels: [],
  178. newLabel: null,
  179. editedLabel: null,
  180. messages: [],
  181. shortKeys: 'abcdefghijklmnopqrstuvwxyz',
  182. }),
  183. created() {
  184. HTTP.get('labels').then((response) => {
  185. this.labels = response.data;
  186. this.sortLabels();
  187. });
  188. },
  189. methods: {
  190. generateColor() {
  191. const gencolor = Math.floor(Math.random() * 0xFFFFFF).toString(16);
  192. const randomColor = '#' + ('000000' + gencolor).slice(-6);
  193. return randomColor;
  194. },
  195. blackOrWhite(hexcolor) {
  196. const r = parseInt(hexcolor.substr(1, 2), 16);
  197. const g = parseInt(hexcolor.substr(3, 2), 16);
  198. const b = parseInt(hexcolor.substr(5, 2), 16);
  199. return ((((r * 299) + (g * 587) + (b * 114)) / 1000) < 128) ? '#ffffff' : '#000000';
  200. },
  201. setColor(label) {
  202. const bgColor = this.generateColor();
  203. const textColor = this.blackOrWhite(bgColor);
  204. label.background_color = bgColor;
  205. label.text_color = textColor;
  206. },
  207. setEditColor() {
  208. this.setColor(this.editedLabel);
  209. },
  210. shortcutKey(label) {
  211. let shortcut = label.suffix_key;
  212. if (label.prefix_key) {
  213. shortcut = `${label.prefix_key} ${shortcut}`;
  214. }
  215. return shortcut;
  216. },
  217. sortLabels() {
  218. return this.labels.sort((a, b) => ((a.text < b.text) ? -1 : 1));
  219. },
  220. addLabel() {
  221. if (this.newLabel.prefix_key === '') {
  222. this.newLabel.prefix_key = null;
  223. }
  224. HTTP.post('labels', this.newLabel)
  225. .then((response) => {
  226. this.cancelCreate();
  227. this.labels.push(response.data);
  228. this.sortLabels();
  229. this.messages = [];
  230. })
  231. .catch((error) => {
  232. console.log(error); // eslint-disable-line no-console
  233. if (error.response.data.non_field_errors) {
  234. error.response.data.non_field_errors.forEach((msg) => {
  235. this.messages.push(msg);
  236. });
  237. } else {
  238. this.messages.push('You cannot use same label name or shortcut key.');
  239. }
  240. });
  241. },
  242. removeLabel(label) {
  243. const labelId = label.id;
  244. HTTP.delete(`labels/${labelId}`).then(() => {
  245. const index = this.labels.indexOf(label);
  246. this.labels.splice(index, 1);
  247. });
  248. },
  249. createLabel() {
  250. this.newLabel = {
  251. text: '',
  252. prefix_key: null,
  253. suffix_key: null,
  254. background_color: '#209cee',
  255. text_color: '#ffffff',
  256. };
  257. this.setColor(this.newLabel);
  258. },
  259. cancelCreate() {
  260. this.newLabel = null;
  261. },
  262. editLabel(label) {
  263. this.beforeEditCache = Object.assign({}, label);
  264. this.editedLabel = label;
  265. },
  266. doneEdit(label) {
  267. if (!this.editedLabel) {
  268. return;
  269. }
  270. this.editedLabel = null;
  271. label.text = label.text.trim();
  272. if (!label.text) {
  273. this.removeLabel(label);
  274. }
  275. HTTP.patch(`labels/${label.id}`, label)
  276. .then(() => {
  277. this.sortLabels();
  278. this.messages = [];
  279. })
  280. .catch((error) => {
  281. console.log(error); // eslint-disable-line no-console
  282. if (error.response.data.non_field_errors) {
  283. error.response.data.non_field_errors.forEach((msg) => {
  284. this.messages.push(msg);
  285. });
  286. } else {
  287. this.messages.push('You cannot use same label name or shortcut key.');
  288. }
  289. });
  290. },
  291. cancelEdit(label) {
  292. this.editedLabel = null;
  293. Object.assign(label, this.beforeEditCache);
  294. },
  295. },
  296. };
  297. </script>