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.

304 lines
9.1 KiB

  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. a.button(
  49. v-bind:style="{ \
  50. color: newLabel.text_color, \
  51. backgroundColor: newLabel.background_color \
  52. }"
  53. v-on:click="setColor(newLabel)"
  54. )
  55. span.icon.is-small
  56. i.fas.fa-sync-alt
  57. div.control.is-expanded
  58. input.input(
  59. type="text"
  60. placeholder="Text input"
  61. v-model="newLabel.background_color"
  62. )
  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. a.button.has-text-white(
  135. v-bind:style="{ backgroundColor: label.background_color }"
  136. v-on:click="setColor(label)"
  137. )
  138. span.icon.is-small
  139. i.fas.fa-sync-alt
  140. div.control.is-expanded
  141. input.input(
  142. type="text"
  143. placeholder="Text input"
  144. v-model="label.background_color"
  145. )
  146. div.column
  147. div.field
  148. label.label &nbsp;
  149. div.field.is-grouped
  150. p.control
  151. a.button.is-light(v-on:click="cancelEdit(label)") Cancel
  152. p.control
  153. a.button.is-primary(v-on:click="doneEdit(label)") Save changes
  154. </template>
  155. <script>
  156. import HTTP from './http';
  157. import Messages from './messages.vue';
  158. import { simpleShortcut } from './filter';
  159. export default {
  160. components: { Messages },
  161. filters: { simpleShortcut },
  162. data: () => ({
  163. labels: [],
  164. newLabel: null,
  165. editedLabel: null,
  166. messages: [],
  167. shortKeys: 'abcdefghijklmnopqrstuvwxyz',
  168. }),
  169. created() {
  170. HTTP.get('labels').then((response) => {
  171. this.labels = response.data;
  172. this.sortLabels();
  173. });
  174. },
  175. methods: {
  176. generateColor() {
  177. const color = Math.floor(Math.random() * 0xFFFFFF).toString(16);
  178. const randomColor = '#' + ('000000' + color).slice(-6);
  179. return randomColor;
  180. },
  181. blackOrWhite(hexcolor) {
  182. const r = parseInt(hexcolor.substr(1, 2), 16);
  183. const g = parseInt(hexcolor.substr(3, 2), 16);
  184. const b = parseInt(hexcolor.substr(5, 2), 16);
  185. return ((((r * 299) + (g * 587) + (b * 114)) / 1000) < 128) ? '#ffffff' : '#000000';
  186. },
  187. setColor(label) {
  188. const bgColor = this.generateColor();
  189. const textColor = this.blackOrWhite(bgColor);
  190. label.background_color = bgColor;
  191. label.text_color = textColor;
  192. },
  193. shortcutKey(label) {
  194. let shortcut = label.suffix_key;
  195. if (label.prefix_key) {
  196. shortcut = `${label.prefix_key} ${shortcut}`;
  197. }
  198. return shortcut;
  199. },
  200. sortLabels() {
  201. return this.labels.sort((a, b) => ((a.text < b.text) ? -1 : 1));
  202. },
  203. addLabel() {
  204. HTTP.post('labels', this.newLabel)
  205. .then((response) => {
  206. this.cancelCreate();
  207. this.labels.push(response.data);
  208. this.sortLabels();
  209. this.messages = [];
  210. })
  211. .catch((error) => {
  212. console.log(error); // eslint-disable-line no-console
  213. this.messages.push('You cannot use same label name or shortcut key.');
  214. });
  215. },
  216. removeLabel(label) {
  217. const labelId = label.id;
  218. HTTP.delete(`labels/${labelId}`).then(() => {
  219. const index = this.labels.indexOf(label);
  220. this.labels.splice(index, 1);
  221. });
  222. },
  223. createLabel() {
  224. this.newLabel = {
  225. text: '',
  226. prefix_key: null,
  227. suffix_key: null,
  228. background_color: '#209cee',
  229. text_color: '#ffffff',
  230. };
  231. },
  232. cancelCreate() {
  233. this.newLabel = null;
  234. },
  235. editLabel(label) {
  236. this.beforeEditCache = Object.assign({}, label);
  237. this.editedLabel = label;
  238. },
  239. doneEdit(label) {
  240. if (!this.editedLabel) {
  241. return;
  242. }
  243. this.editedLabel = null;
  244. label.text = label.text.trim();
  245. if (!label.text) {
  246. this.removeLabel(label);
  247. }
  248. HTTP.patch(`labels/${label.id}`, label)
  249. .then(() => {
  250. this.sortLabels();
  251. this.messages = [];
  252. })
  253. .catch((error) => {
  254. console.log(error); // eslint-disable-line no-console
  255. this.messages.push('You cannot use same label name or shortcut key.');
  256. });
  257. },
  258. cancelEdit(label) {
  259. this.editedLabel = null;
  260. Object.assign(label, this.beforeEditCache);
  261. },
  262. },
  263. };
  264. </script>