Field.vue 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. <template>
  2. <div class="control">
  3. <label for="name">{{ name }}</label>
  4. <button v-if="entries.length === 0" @click="addEntry()" type="button">+</button>
  5. <div class="control-row" v-for="(entry, entryIndex) in entries">
  6. <div class="control-col" v-for="(fieldType, fieldIndex) in fieldTypes" :class="{ 'fill-remaining': fieldType.fill }">
  7. <input name="name" type="text" v-if="fieldType.type === 'text'" v-model="entry[fieldType.fieldTypeId]"/>
  8. <select name="name" v-if="fieldType.type === 'select'" class="fill-remaining" v-model="entry[fieldType.fieldTypeId]">
  9. <option v-for="option in fieldType.options" :value="option.value">{{option.text}}</option>
  10. </select>
  11. <div tabindex="0" v-on:keyup.enter="toggleCheckbox(entryIndex, fieldType.fieldTypeId)" v-on:keyup.space="toggleCheckbox(entryIndex, fieldType.fieldTypeId)" name="name" class="checkbox" v-if="fieldType.type === 'checkbox'" :class="{ checked: entry[fieldType.fieldTypeId] }" @click="toggleCheckbox(entryIndex, fieldType.fieldTypeId)"></div>
  12. <button v-if="fieldType.extraButtons" v-for="buttonInfo in fieldType.extraButtons" type="button" :class="[buttonInfo.style]">{{buttonInfo.icon}}</button>
  13. <button v-if="entryIndex + 1 === entries.length && entryIndex + 1 < maxEntries && fieldIndex + 1 === fieldTypes.length" @click="addEntry()" type="button">+</button>
  14. <button v-if="entries.length > minEntries && fieldIndex + 1 === fieldTypes.length" @click="removeEntry(entryIndex)" type="button">-</button>
  15. </div>
  16. </div>
  17. </div>
  18. </template>
  19. <script>
  20. function Field() {
  21. }
  22. export default {
  23. data: function() {
  24. return {
  25. entries: [...this.initialEntries]
  26. };
  27. },
  28. methods: {
  29. },
  30. props: {
  31. name: String,
  32. fieldTypes: Array,
  33. minEntries: Number,
  34. maxEntries: Number,
  35. initialEntries: Array
  36. },
  37. mounted() {
  38. },
  39. methods: {
  40. addEntry() {
  41. let emptyEntry = {};
  42. this.fieldTypes.forEach((fieldType) => {
  43. if (fieldType.type === "text" || fieldType.type === "select") emptyEntry[fieldType.fieldTypeId] = "";
  44. else if (fieldType.type === "checkbox") emptyEntry[fieldType.fieldTypeId] = false;
  45. });
  46. this.entries.push(emptyEntry);
  47. },
  48. removeEntry(index) {
  49. this.entries.splice(index, 1);
  50. },
  51. toggleCheckbox(entryIndex, fieldTypeId) {
  52. this.entries[entryIndex][fieldTypeId] = !this.entries[entryIndex][fieldTypeId];
  53. }
  54. }
  55. };
  56. </script>
  57. <style lang="scss" scoped>
  58. .control {
  59. width: 100%;
  60. margin-bottom: 16px;
  61. label {
  62. display: block;
  63. margin-bottom: 4px;
  64. }
  65. .control-row {
  66. height: 32px;
  67. display: flex;
  68. grid-column-gap: 12px;
  69. }
  70. .control-row:not(:last-of-type) {
  71. margin-bottom: 8px;
  72. }
  73. .control-col {
  74. display: flex;
  75. button:last-of-type {
  76. border-radius: 0 5px 5px 0;
  77. }
  78. > input:not(:last-child) {
  79. border-right: none;
  80. border-top-right-radius: 0;
  81. border-bottom-right-radius: 0;
  82. }
  83. }
  84. input, select {
  85. border: solid .5px #464646;
  86. border-radius: 5px;
  87. padding: 4px;
  88. }
  89. input {
  90. width: 100%;
  91. }
  92. button {
  93. width: 32px;
  94. height: 32px;
  95. border: none;
  96. font-size: 24px;
  97. background-color: green;
  98. color: white;
  99. cursor: pointer;
  100. }
  101. button:hover, button:focus {
  102. background-color: darkgreen;
  103. }
  104. }
  105. .fill-remaining {
  106. width: 100%;
  107. width: -moz-available; /* WebKit-based browsers will ignore this. */
  108. width: -webkit-fill-available; /* Mozilla-based browsers will ignore this. */
  109. width: fill-available;
  110. }
  111. .checkbox {
  112. height: 32px;
  113. width: 32px;
  114. background-color: white;
  115. border: .5px #464646 solid;
  116. border-radius: 3px;
  117. cursor: pointer;
  118. position: relative;
  119. box-sizing: border-box;
  120. }
  121. .checkbox.checked::after {
  122. content: "";
  123. width: 26px;
  124. height: 26px;
  125. left: 2px;
  126. top: 2px;
  127. display: inline-block;
  128. position: absolute;
  129. border-radius: 3px;
  130. background-color: #69B862;
  131. }
  132. </style>