Field.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. <template>
  2. <div class="control">
  3. <label for="name">{{ name }} (min: {{minEntries}}, max: {{maxEntries}})</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[fieldIndex]"/>
  8. <select name="name" v-if="fieldType.type === 'select'" class="fill-remaining" v-model="entry[fieldIndex]">
  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, fieldIndex)" v-on:keyup.space="toggleCheckbox(entryIndex, fieldIndex)" name="name" class="checkbox" v-if="fieldType.type === 'checkbox'" :class="{ checked: entry[fieldIndex] }" @click="toggleCheckbox(entryIndex, fieldIndex)"></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. emptyEntry.push(null);
  44. });
  45. this.entries.push(emptyEntry);
  46. },
  47. removeEntry(index) {
  48. this.entries.splice(index, 1);
  49. },
  50. toggleCheckbox(entryIndex, fieldIndex) {
  51. this.$set(this.entries[entryIndex], fieldIndex, !this.entries[entryIndex][fieldIndex]);
  52. }
  53. }
  54. };
  55. </script>
  56. <style lang="scss" scoped>
  57. .control {
  58. width: 100%;
  59. margin-bottom: 16px;
  60. label {
  61. display: block;
  62. margin-bottom: 4px;
  63. }
  64. .control-row {
  65. height: 32px;
  66. display: flex;
  67. grid-column-gap: 12px;
  68. }
  69. .control-row:not(:last-of-type) {
  70. margin-bottom: 8px;
  71. }
  72. .control-col {
  73. display: flex;
  74. button:last-of-type {
  75. border-radius: 0 5px 5px 0;
  76. }
  77. > input:not(:last-child) {
  78. border-right: none;
  79. border-top-right-radius: 0;
  80. border-bottom-right-radius: 0;
  81. }
  82. }
  83. input, select {
  84. border: solid .5px #464646;
  85. border-radius: 5px;
  86. padding: 4px;
  87. }
  88. input {
  89. width: 100%;
  90. }
  91. button {
  92. width: 32px;
  93. height: 32px;
  94. border: none;
  95. font-size: 24px;
  96. background-color: green;
  97. color: white;
  98. cursor: pointer;
  99. }
  100. button:hover, button:focus {
  101. background-color: darkgreen;
  102. }
  103. }
  104. .fill-remaining {
  105. width: 100%;
  106. width: -moz-available; /* WebKit-based browsers will ignore this. */
  107. width: -webkit-fill-available; /* Mozilla-based browsers will ignore this. */
  108. width: fill-available;
  109. }
  110. .checkbox {
  111. height: 32px;
  112. width: 32px;
  113. background-color: white;
  114. border: .5px #464646 solid;
  115. border-radius: 3px;
  116. cursor: pointer;
  117. position: relative;
  118. box-sizing: border-box;
  119. }
  120. .checkbox.checked::after {
  121. content: "";
  122. width: 26px;
  123. height: 26px;
  124. left: 2px;
  125. top: 2px;
  126. display: inline-block;
  127. position: absolute;
  128. border-radius: 3px;
  129. background-color: #69B862;
  130. }
  131. </style>