apostrophe 3.4.1 → 3.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/.eslintrc +4 -0
  2. package/.scratch.md +2 -0
  3. package/CHANGELOG.md +114 -2
  4. package/README.md +1 -1
  5. package/deploy-test-count +1 -1
  6. package/index.js +125 -5
  7. package/lib/moog-require.js +41 -3
  8. package/lib/moog.js +20 -8
  9. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposAdminBarLocale.vue +42 -23
  10. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextBar.vue +30 -14
  11. package/modules/@apostrophecms/area/index.js +9 -0
  12. package/modules/@apostrophecms/area/lib/custom-tags/area.js +1 -1
  13. package/modules/@apostrophecms/area/lib/custom-tags/widget.js +1 -1
  14. package/modules/@apostrophecms/area/ui/apos/apps/AposAreas.js +3 -0
  15. package/modules/@apostrophecms/area/ui/apos/components/AposAreaWidget.vue +6 -6
  16. package/modules/@apostrophecms/asset/index.js +85 -21
  17. package/modules/@apostrophecms/asset/lib/globalIcons.js +2 -0
  18. package/modules/@apostrophecms/asset/lib/webpack/src/webpack.scss.js +5 -2
  19. package/modules/@apostrophecms/attachment/index.js +1 -0
  20. package/modules/@apostrophecms/db/index.js +5 -6
  21. package/modules/@apostrophecms/doc/index.js +13 -3
  22. package/modules/@apostrophecms/doc-type/index.js +24 -4
  23. package/modules/@apostrophecms/doc-type/ui/apos/components/AposDocContextMenu.vue +13 -1
  24. package/modules/@apostrophecms/doc-type/ui/apos/components/AposDocEditor.vue +3 -0
  25. package/modules/@apostrophecms/i18n/i18n/en.json +26 -6
  26. package/modules/@apostrophecms/i18n/i18n/es.json +382 -0
  27. package/modules/@apostrophecms/i18n/i18n/pt-BR.json +379 -0
  28. package/modules/@apostrophecms/i18n/i18n/sk.json +380 -0
  29. package/modules/@apostrophecms/i18n/index.js +10 -1
  30. package/modules/@apostrophecms/i18n/ui/apos/components/AposI18nLocalize.vue +153 -121
  31. package/modules/@apostrophecms/image/index.js +2 -1
  32. package/modules/@apostrophecms/image/ui/apos/components/AposMediaManager.vue +6 -3
  33. package/modules/@apostrophecms/image/ui/apos/components/AposMediaManagerEditor.vue +24 -13
  34. package/modules/@apostrophecms/image-widget/index.js +2 -1
  35. package/modules/@apostrophecms/image-widget/views/widget.html +12 -2
  36. package/modules/@apostrophecms/job/index.js +164 -212
  37. package/modules/@apostrophecms/login/index.js +36 -17
  38. package/modules/@apostrophecms/login/ui/apos/components/TheAposLogin.vue +8 -0
  39. package/modules/@apostrophecms/migration/index.js +1 -1
  40. package/modules/@apostrophecms/modal/ui/apos/components/AposDocsManagerToolbar.vue +151 -61
  41. package/modules/@apostrophecms/modal/ui/apos/components/AposModal.vue +6 -2
  42. package/modules/@apostrophecms/modal/ui/apos/components/AposModalConfirm.vue +9 -7
  43. package/modules/@apostrophecms/modal/ui/apos/mixins/AposDocsManagerMixin.js +12 -15
  44. package/modules/@apostrophecms/modal/ui/apos/mixins/AposEditorMixin.js +6 -0
  45. package/modules/@apostrophecms/module/index.js +1 -1
  46. package/modules/@apostrophecms/notification/index.js +116 -8
  47. package/modules/@apostrophecms/notification/ui/apos/components/AposNotification.vue +89 -11
  48. package/modules/@apostrophecms/notification/ui/apos/components/TheAposNotifications.vue +1 -1
  49. package/modules/@apostrophecms/page/index.js +37 -30
  50. package/modules/@apostrophecms/permission/index.js +1 -1
  51. package/modules/@apostrophecms/permission/ui/apos/components/AposInputRole.vue +4 -2
  52. package/modules/@apostrophecms/piece-type/index.js +178 -61
  53. package/modules/@apostrophecms/piece-type/ui/apos/components/AposDocsManager.vue +179 -47
  54. package/modules/@apostrophecms/piece-type/ui/apos/components/AposDocsManagerDisplay.vue +1 -3
  55. package/modules/@apostrophecms/piece-type/ui/apos/components/AposDocsManagerSelectBox.vue +138 -0
  56. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposRichTextWidgetEditor.vue +42 -10
  57. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapStyles.vue +3 -0
  58. package/modules/@apostrophecms/rich-text-widget/ui/apos/tiptap-extensions/Classes.js +6 -10
  59. package/modules/@apostrophecms/rich-text-widget/ui/apos/tiptap-extensions/Default.js +64 -0
  60. package/modules/@apostrophecms/rich-text-widget/ui/apos/tiptap-extensions/Document.js +15 -0
  61. package/modules/@apostrophecms/rich-text-widget/ui/apos/tiptap-extensions/Heading.js +23 -0
  62. package/modules/@apostrophecms/schema/index.js +97 -20
  63. package/modules/@apostrophecms/schema/ui/apos/components/AposArrayEditor.vue +1 -0
  64. package/modules/@apostrophecms/schema/ui/apos/components/AposInputArray.vue +4 -1
  65. package/modules/@apostrophecms/schema/ui/apos/components/AposInputAttachment.vue +11 -160
  66. package/modules/@apostrophecms/schema/ui/apos/components/AposInputRadio.vue +8 -5
  67. package/modules/@apostrophecms/schema/ui/apos/components/AposInputRelationship.vue +24 -2
  68. package/modules/@apostrophecms/schema/ui/apos/components/AposInputSelect.vue +24 -6
  69. package/modules/@apostrophecms/schema/ui/apos/components/AposInputSlug.vue +0 -4
  70. package/modules/@apostrophecms/schema/ui/apos/components/AposInputString.vue +0 -7
  71. package/modules/@apostrophecms/schema/ui/apos/components/AposSchema.vue +25 -3
  72. package/modules/@apostrophecms/schema/ui/apos/mixins/AposInputMixin.js +10 -2
  73. package/modules/@apostrophecms/task/index.js +2 -2
  74. package/modules/@apostrophecms/template/index.js +63 -36
  75. package/modules/@apostrophecms/template/lib/custom-tags/component.js +1 -1
  76. package/modules/@apostrophecms/template/lib/custom-tags/render.js +6 -2
  77. package/modules/@apostrophecms/ui/index.js +6 -2
  78. package/modules/@apostrophecms/ui/ui/apos/components/AposButton.vue +21 -3
  79. package/modules/@apostrophecms/ui/ui/apos/components/AposCellContextMenu.vue +1 -1
  80. package/modules/@apostrophecms/ui/ui/apos/components/AposFile.vue +205 -0
  81. package/modules/@apostrophecms/ui/ui/apos/components/AposIndicator.vue +5 -0
  82. package/modules/@apostrophecms/ui/ui/apos/lib/i18next.js +16 -2
  83. package/modules/@apostrophecms/ui/ui/apos/scss/global/_tables.scss +4 -3
  84. package/modules/@apostrophecms/ui/ui/apos/scss/global/_theme.scss +3 -0
  85. package/modules/@apostrophecms/ui/ui/apos/scss/global/_widgets.scss +3 -0
  86. package/modules/@apostrophecms/ui/ui/apos/scss/global/import-all.scss +2 -1
  87. package/modules/@apostrophecms/user/index.js +21 -0
  88. package/modules/@apostrophecms/util/index.js +2 -2
  89. package/modules/@apostrophecms/util/ui/src/http.js +12 -8
  90. package/modules/@apostrophecms/util/ui/src/util.js +15 -0
  91. package/modules/@apostrophecms/widget-type/index.js +1 -1
  92. package/modules/@apostrophecms/widget-type/ui/apos/components/AposWidgetEditor.vue +1 -0
  93. package/modules/@apostrophecms/widget-type/ui/apos/mixins/AposWidgetMixin.js +15 -7
  94. package/package.json +4 -4
  95. package/test/extra_node_modules/improve-global/index.js +7 -0
  96. package/test/extra_node_modules/improve-piece-type/index.js +7 -0
  97. package/test/improve-overrides.js +30 -0
  98. package/test/job.js +224 -0
  99. package/test/login.js +183 -0
  100. package/test/modules/@apostrophecms/global/index.js +8 -0
  101. package/test/modules/fragment-all/views/aux-test.html +7 -0
  102. package/test/modules/fragment-all/views/fragment.html +5 -0
  103. package/test/moog.js +47 -0
  104. package/test/package.json +5 -4
  105. package/test/pieces.js +17 -0
  106. package/test/reverse-relationship.js +170 -0
  107. package/test/subdir-project/app.js +3 -0
  108. package/test/subdir-project.js +26 -0
  109. package/test/templates.js +7 -1
  110. package/test-lib/test.js +23 -12
  111. package/test-lib/util.js +33 -0
@@ -11,16 +11,16 @@
11
11
  <template #leftRail>
12
12
  <AposModalBody class="apos-wizard__navigation">
13
13
  <template #bodyMain>
14
- <button
15
- v-for="section in visibleSections"
16
- :disabled="!completedPrevious(section.name)"
17
- :key="section.title"
18
- @click="goTo(section.name)"
19
- class="apos-wizard__navigation-item"
20
- :class="{ 'apos-state-active': isStep(section.name) }"
21
- >
22
- {{ section.title }}
23
- </button>
14
+ <ul class="apos-wizard__navigation__items">
15
+ <li
16
+ v-for="section in visibleSections"
17
+ :key="section.title"
18
+ class="apos-wizard__navigation__item"
19
+ :class="{ 'apos-is-active': isStep(section.name) }"
20
+ >
21
+ {{ section.title }}
22
+ </li>
23
+ </ul>
24
24
  </template>
25
25
  <template #footer>
26
26
  <div class="apos-modal__footer">
@@ -28,6 +28,7 @@
28
28
  type="default"
29
29
  label="apostrophe:cancel"
30
30
  @click="close"
31
+ :modifiers="[ 'block' ]"
31
32
  />
32
33
  </div>
33
34
  </template>
@@ -55,10 +56,12 @@
55
56
  }"
56
57
  v-model="wizard.values.toLocalize"
57
58
  />
58
- <p
59
- class="apos-wizard__help-text"
60
- >
61
- <InformationIcon :size="16" />
59
+ <p class="apos-wizard__help-text">
60
+ <AposIndicator
61
+ class="apos-wizard__help-text__icon"
62
+ icon="information-icon"
63
+ :icon-size="16"
64
+ />
62
65
  {{ $t('apostrophe:relatedDocsDefinition') }}
63
66
  </p>
64
67
  </fieldset>
@@ -67,20 +70,21 @@
67
70
  v-if="isStep('selectLocales')"
68
71
  class="apos-wizard__step apos-wizard__step-select-locales"
69
72
  >
70
- <label for="localeFilter" class="apos-local-filter-label">
71
- {{ $t('apostrophe:searchLocales') }}
72
- </label>
73
- <button @click.prevent="selectAll" class="apos-locale-select-all">
74
- {{ $t('apostrophe:selectAll') }}
75
- </button>
76
- <input
77
- v-model="wizard.sections.selectLocales.filter"
78
- type="text"
79
- name="localeFilter"
73
+ <AposButton
74
+ v-on="{ click: allSelected ? deselectAll : selectAll }"
75
+ class="apos-locale-select-all"
76
+ :label="allSelected ? $t('apostrophe:deselectAll') : $t('apostrophe:selectAll')"
77
+ type="quiet"
78
+ :modifiers="[ 'inline' ]"
79
+ />
80
+ <AposInputString
81
+ v-model="searchValue"
82
+ :field="searchField"
83
+ @input="updateFilter"
80
84
  class="apos-locales-filter"
81
- :placeholder="$t('apostrophe:searchLocales')"
85
+ ref="searchInput"
82
86
  />
83
- <ul class="apos-selected-locales">
87
+ <transition-group tag="ul" name="selected-list" class="apos-selected-locales">
84
88
  <li
85
89
  v-for="locale in selectedLocales"
86
90
  :key="locale.name"
@@ -90,39 +94,45 @@
90
94
  type="primary"
91
95
  @click.prevent="removeLocale(locale)"
92
96
  class="apos-locale-button"
97
+ :modifiers="[ 'small' ]"
93
98
  icon="close-icon"
94
99
  :icon-size="12"
95
100
  :label="locale.label"
96
101
  />
97
102
  </li>
98
- </ul>
103
+ </transition-group>
99
104
  <ul class="apos-locales">
100
105
  <li
101
106
  v-for="locale in filteredLocales"
102
107
  :key="locale.name"
103
108
  class="apos-locale-item"
104
109
  :class="localeClasses(locale)"
105
- @click="selectLocale(locale)"
110
+ @click="toggleLocale(locale)"
106
111
  >
107
112
  <span class="apos-locale">
108
- <FlareIcon
113
+ <AposIndicator
109
114
  v-if="isCurrentLocale(locale) && !isSelected(locale)"
115
+ icon="map-marker-icon"
110
116
  class="apos-current-locale-icon"
117
+ :icon-size="14"
111
118
  title="Default locale"
112
- :size="12"
119
+ tooltip="Current Locale"
113
120
  />
114
- <CheckIcon
121
+ <AposIndicator
115
122
  v-if="isSelected(locale)"
123
+ icon="check-bold-icon"
116
124
  class="apos-check-icon"
125
+ :icon-size="10"
117
126
  title="Currently selected locale"
118
- :size="12"
119
127
  />
120
128
  {{ locale.label }}
129
+ <span class="apos-locale-name">({{ locale.name }})</span>
121
130
  <span
122
131
  class="apos-locale-localized"
123
132
  :class="{
124
133
  'apos-state-is-localized': isLocalized(locale),
125
134
  }"
135
+ v-apos-tooltip="isLocalized(locale) ? 'Localized' : 'Not Yet Localized'"
126
136
  />
127
137
  </span>
128
138
  </li>
@@ -135,13 +145,17 @@
135
145
  >
136
146
  <ul class="apos-selected-locales">
137
147
  <li
148
+ class="apos-locale-item--selected"
138
149
  v-for="locale in selectedLocales"
139
150
  :key="locale.name"
140
- class="apos-locale-item--selected"
141
151
  >
142
- <span class="apos-locale-to-localize">{{
143
- locale.label
144
- }}</span>
152
+ <AposButton
153
+ type="primary"
154
+ class="apos-locale-to-localize"
155
+ :modifiers="[ 'small' ]"
156
+ :label="locale.label"
157
+ :disabled="true"
158
+ />
145
159
  </li>
146
160
  </ul>
147
161
 
@@ -149,11 +163,15 @@
149
163
  v-if="wizard.values.toLocalize.data !== 'thisDoc'"
150
164
  class="apos-wizard__field-group"
151
165
  >
152
- <p class="apos-wizard__field-group-heading">
166
+ <p
167
+ class="apos-wizard__field-group-heading">
153
168
  {{ $t('apostrophe:relatedDocSettings') }}
154
- <span v-apos-tooltip.top="tooltips.relatedDocSettings"
155
- ><InformationIcon :size="14"
156
- /></span>
169
+ <AposIndicator
170
+ class="apos-wizard__field-group-heading__info"
171
+ icon="information-icon"
172
+ :icon-size="14"
173
+ :tooltip="tooltips.relatedDocSettings"
174
+ />
157
175
  </p>
158
176
 
159
177
  <AposInputRadio
@@ -179,7 +197,13 @@
179
197
  :field="relatedDocTypesField"
180
198
  v-model="wizard.values.relatedDocTypesToLocalize"
181
199
  />
182
- <p v-else class="apos-wizard__field-group-heading">
200
+ <p v-else class="apos-wizard__help-text">
201
+ <AposIndicator
202
+ class="apos-wizard__help-text__icon"
203
+ icon="lightbulb-on-icon"
204
+ icon-color="var(--a-success)"
205
+ :icon-size="16"
206
+ />
183
207
  {{ $t('apostrophe:noNewRelatedDocuments') }}
184
208
  </p>
185
209
  </div>
@@ -217,17 +241,8 @@
217
241
  </template>
218
242
 
219
243
  <script>
220
- import CheckIcon from 'vue-material-design-icons/Check.vue';
221
- import FlareIcon from 'vue-material-design-icons/Flare.vue';
222
- import InformationIcon from 'vue-material-design-icons/Information.vue';
223
-
224
244
  export default {
225
245
  name: 'AposI18nLocalize',
226
- components: {
227
- CheckIcon,
228
- FlareIcon,
229
- InformationIcon
230
- },
231
246
  props: {
232
247
  doc: {
233
248
  required: true,
@@ -313,7 +328,15 @@ export default {
313
328
  // interest in new docs
314
329
  allRelatedDocs: [],
315
330
  allRelatedDocsKnown: false,
316
- docTypesSeen: []
331
+ docTypesSeen: [],
332
+ searchField: {
333
+ label: this.$t('apostrophe:searchLocales'),
334
+ placeholder: `${this.$t('apostrophe:searchLocales')}...`
335
+ },
336
+ searchValue: {
337
+ value: '',
338
+ error: false
339
+ }
317
340
  };
318
341
  return result;
319
342
  },
@@ -350,6 +373,9 @@ export default {
350
373
  selectedLocales() {
351
374
  return this.wizard.values.toLocales.data;
352
375
  },
376
+ allSelected() {
377
+ return this.selectedLocales.length === this.locales.filter(locale => !this.isCurrentLocale(locale)).length;
378
+ },
353
379
  toLocalizeChoices() {
354
380
  return [
355
381
  {
@@ -495,9 +521,20 @@ export default {
495
521
  selectAll() {
496
522
  this.wizard.values.toLocales.data = this.locales.filter(locale => !this.isCurrentLocale(locale));
497
523
  },
498
- selectLocale(locale) {
524
+ deselectAll() {
525
+ this.wizard.values.toLocales.data = [];
526
+ },
527
+ toggleLocale(locale) {
499
528
  if (!this.isSelected(locale) && !this.isCurrentLocale(locale)) {
500
529
  this.wizard.values.toLocales.data.push(locale);
530
+ } else if (this.isSelected(locale)) {
531
+ this.wizard.values.toLocales.data = this.wizard.values.toLocales.data.filter(l => l !== locale);
532
+ }
533
+ // Reset search filter
534
+ if (this.filteredLocales.length < 2) {
535
+ this.wizard.sections.selectLocales.filter = '';
536
+ this.searchValue.data = '';
537
+ this.$refs.searchInput.$el.querySelector('input').focus();
501
538
  }
502
539
  },
503
540
  removeLocale(locale) {
@@ -549,6 +586,11 @@ export default {
549
586
  }
550
587
  return module.pluralLabel || module.label || name;
551
588
  },
589
+ updateFilter(event) {
590
+ if (event && event.data !== undefined) {
591
+ this.wizard.sections.selectLocales.filter = event.data
592
+ }
593
+ },
552
594
  async submit() {
553
595
  let docs = [];
554
596
  const notifications = [];
@@ -743,8 +785,8 @@ export default {
743
785
  right: $horizontal-spacing;
744
786
  bottom: $vertical-spacing;
745
787
  left: $horizontal-spacing;
746
- height: calc(100vh - #{$vertical-spacing * 2});
747
788
  width: $width;
789
+ height: calc(100vh - #{$vertical-spacing * 2});
748
790
  }
749
791
 
750
792
  ::v-deep .apos-modal__main--with-left-rail {
@@ -752,7 +794,7 @@ export default {
752
794
  }
753
795
 
754
796
  ::v-deep .apos-modal__body-inner {
755
- padding: 30px 30px 20px 30px;
797
+ padding: $spacing-triple $spacing-triple $spacing-double;
756
798
  }
757
799
 
758
800
  ::v-deep .apos-wizard__content .apos-modal__body-footer {
@@ -770,42 +812,40 @@ export default {
770
812
  border-right: 1px solid var(--a-base-9);
771
813
  }
772
814
 
773
- .apos-wizard__navigation-item {
774
- display: block;
775
- padding: 0;
776
- text-align: left;
777
- border: none;
778
- background: transparent;
779
- cursor: pointer;
780
-
781
- &.apos-state-active {
815
+ .apos-wizard__navigation__items {
816
+ @include apos-list-reset();
817
+ padding: $spacing-base;
818
+ }
819
+ .apos-wizard__navigation__item {
820
+ @include type-small;
821
+ margin-bottom: $spacing-base + $spacing-half;
822
+ &.apos-is-active {
782
823
  color: var(--a-primary);
783
824
  }
784
-
785
- &:not(:last-of-type) {
786
- margin-bottom: $spacing-double;
787
- }
788
825
  }
789
826
 
790
827
  .apos-modal__heading {
791
828
  @include type-title;
792
- margin: 0 0 30px 0;
829
+ margin: 0 0 $spacing-double 0;
793
830
  }
794
831
 
795
832
  .apos-wizard__step {
796
- padding: 0;
833
+ position: relative;
797
834
  margin: 0;
835
+ padding: 0;
798
836
  border: none;
799
837
  }
800
838
 
801
839
  ::v-deep .apos-field--toLocalize {
802
- margin-bottom: 30px;
840
+ margin-bottom: $spacing-triple;
803
841
  }
804
842
 
805
843
  .apos-wizard__help-text {
806
844
  text-indent: -20px;
807
845
  padding-left: 20px;
808
846
  line-height: 1.25;
847
+ font-weight: 400;
848
+ color: var(--a-base-3);
809
849
 
810
850
  ::v-deep .material-design-icon {
811
851
  position: relative;
@@ -814,43 +854,14 @@ export default {
814
854
  }
815
855
  }
816
856
 
817
- .apos-local-filter-label {
818
- font-size: var(--a-type-large);
819
- }
820
-
821
857
  .apos-locale-select-all {
822
- float: right;
823
- padding: 0;
824
- font-size: var(--a-type-base);
825
- color: var(--a-primary);
826
- background: none;
827
- border: 0;
858
+ z-index: $z-index-default;
859
+ position: absolute;
860
+ right: 0;
828
861
  }
829
862
 
830
863
  .apos-locales-filter {
831
- box-sizing: border-box;
832
- width: 100%;
833
- padding: 20px;
834
- margin-top: 10px;
835
- margin-bottom: 10px;
836
- font-size: 14px;
837
- border-top: 0;
838
- border-right: 0;
839
- border-bottom: 1px solid var(--a-base-9);
840
- border-left: 0;
841
- color: var(--a-text-primary);
842
- background-color: var(--a-base-10);
843
- border-top-right-radius: var(--a-border-radius);
844
- border-top-left-radius: var(--a-border-radius);
845
-
846
- &::placeholder {
847
- color: var(--a-base-4);
848
- font-style: italic;
849
- }
850
-
851
- &:focus {
852
- outline: none;
853
- }
864
+ margin-bottom: $spacing-base;
854
865
  }
855
866
 
856
867
  .apos-selected-locales,
@@ -861,6 +872,10 @@ export default {
861
872
  margin-bottom: 0;
862
873
  }
863
874
 
875
+ .apos-selected-locales {
876
+ margin-bottom: $spacing-base;
877
+ }
878
+
864
879
  .apos-locales {
865
880
  max-height: 350px;
866
881
  overflow-y: scroll;
@@ -876,14 +891,15 @@ export default {
876
891
  }
877
892
 
878
893
  .apos-locale-button ::v-deep .apos-button {
879
- padding: 10px;
880
894
  font-size: var(--a-type-small);
881
895
  }
882
896
 
883
897
  .apos-locale-item {
898
+ @include apos-transition();
884
899
  position: relative;
885
900
  padding: 12px 35px;
886
901
  line-height: 1;
902
+ border-radius: var(--a-border-radius);
887
903
 
888
904
  &:not(.apos-current-locale) {
889
905
  cursor: pointer;
@@ -893,11 +909,15 @@ export default {
893
909
  background-color: var(--a-base-10);
894
910
  }
895
911
 
912
+ &:not(.apos-current-locale):active {
913
+ background-color: var(--a-base-9);
914
+ }
915
+
896
916
  .apos-check-icon,
897
917
  .apos-current-locale-icon {
898
918
  position: absolute;
899
919
  top: 50%;
900
- left: 20px;
920
+ left: 18px;
901
921
  transform: translateY(-50%);
902
922
  }
903
923
 
@@ -918,11 +938,12 @@ export default {
918
938
  .apos-locale-localized {
919
939
  position: relative;
920
940
  top: -1px;
941
+ left: 5px;
921
942
  display: inline-block;
922
- height: 5px;
923
- width: 5px;
943
+ width: 3px;
944
+ height: 3px;
924
945
  border: 1px solid var(--a-base-5);
925
- border-radius: 3px;
946
+ border-radius: 50%;
926
947
 
927
948
  &.apos-state-is-localized {
928
949
  background-color: var(--a-success);
@@ -938,14 +959,18 @@ export default {
938
959
  }
939
960
 
940
961
  .apos-wizard__field-group-heading {
962
+ @include type-base;
941
963
  padding-bottom: $spacing-base;
942
964
  margin-bottom: $spacing-base;
943
- font-size: var(--a-type-large);
944
- font-weight: 600;
945
965
  color: var(--a-base-3);
946
966
  border-bottom: 1px solid var(--a-base-8);
947
967
  }
948
968
 
969
+ .apos-wizard__field-group-heading__info {
970
+ position: relative;
971
+ top: 3px;
972
+ }
973
+
949
974
  .apos-wizard__step-2 {
950
975
  .apos-selected-locales,
951
976
  .apos-wizard__field-group:not(:last-of-type) {
@@ -953,16 +978,23 @@ export default {
953
978
  }
954
979
  }
955
980
 
956
- .apos-locale-to-localize {
957
- @include type-small;
958
- display: inline-block;
959
- position: relative;
960
- overflow: hidden;
961
- padding: 10px 20px;
962
- border: 1px solid var(--a-primary-dark-10);
963
- color: var(--a-white);
964
- border-radius: var(--a-border-radius);
965
- background: var(--a-primary);
966
- text-decoration: none;
981
+ .apos-wizard__header {
982
+ margin-top: $spacing-base;
983
+ }
984
+
985
+ .selected-list-enter-active, .selected-list-leave-active {
986
+ @include apos-transition($duration: 0.3s);
987
+ }
988
+ .selected-list-enter, .selected-list-leave-to {
989
+ opacity: 0;
990
+ transform: translateY(1px);
991
+ }
992
+
993
+ .apos-modal__footer {
994
+ width: 100%;
995
+ }
996
+
997
+ .apos-locale-name {
998
+ text-transform: uppercase;
967
999
  }
968
1000
  </style>
@@ -62,7 +62,8 @@ module.exports = {
62
62
  _tags: {
63
63
  type: 'relationship',
64
64
  label: 'apostrophe:tags',
65
- withType: '@apostrophecms/image-tag'
65
+ withType: '@apostrophecms/image-tag',
66
+ modifiers: [ 'no-search' ]
66
67
  }
67
68
  },
68
69
  group: {
@@ -45,10 +45,13 @@
45
45
  <template #bodyHeader>
46
46
  <AposDocsManagerToolbar
47
47
  :selected-state="selectAllState"
48
- :total-pages="totalPages" :current-page="currentPage"
49
- :filters="toolbarFilters" :labels="moduleLabels"
48
+ :total-pages="totalPages"
49
+ :current-page="currentPage"
50
+ :filters="toolbarFilters"
51
+ :labels="moduleLabels"
50
52
  :disable="relationshipErrors === 'min'"
51
- :options="{ hideSelectAll: !relationshipField }"
53
+ :displayed-items="items.length"
54
+ :checked-count="checked.length"
52
55
  @page-change="updatePage"
53
56
  @select-click="selectClick"
54
57
  @search="search"
@@ -15,17 +15,21 @@
15
15
  </div>
16
16
  <ul class="apos-media-editor__details">
17
17
  <li class="apos-media-editor__detail" v-if="createdDate">
18
- Uploaded: {{ createdDate }}
18
+ {{ $t('apostrophe:mediaCreatedDate', { createdDate }) }}
19
19
  </li>
20
20
  <li class="apos-media-editor__detail" v-if="fileSize">
21
- File Size: {{ fileSize }}
21
+ {{ $t('apostrophe:mediaFileSize', { fileSize }) }}
22
22
  </li>
23
23
  <li
24
24
  class="apos-media-editor__detail"
25
25
  v-if="activeMedia.attachment && activeMedia.attachment.width"
26
26
  >
27
- Dimensions: {{ activeMedia.attachment.width }} 𝗑
28
- {{ activeMedia.attachment.height }}
27
+ {{
28
+ $t('apostrophe:mediaDimensions', {
29
+ width: activeMedia.attachment.width,
30
+ height: activeMedia.attachment.height
31
+ })
32
+ }}
29
33
  </li>
30
34
  </ul>
31
35
  <ul class="apos-media-editor__links">
@@ -60,6 +64,7 @@
60
64
  :trigger-validation="triggerValidation"
61
65
  :doc-id="docFields.data._id"
62
66
  :following-values="followingValues()"
67
+ @validate="triggerValidate"
63
68
  @reset="$emit('modified', false)"
64
69
  ref="schema"
65
70
  :server-errors="serverErrors"
@@ -163,25 +168,31 @@ export default {
163
168
  },
164
169
  fileSize() {
165
170
  if (
166
- !this.activeMedia.attachment || !this.activeMedia.attachment.length ||
167
- !this.activeMedia.attachment.length.size
171
+ !this.activeMedia.attachment || !this.activeMedia.attachment.length
168
172
  ) {
169
173
  return '';
170
174
  }
171
-
172
- const size = this.activeMedia.attachment.length.size;
173
-
175
+ const size = this.activeMedia.attachment.length;
176
+ const formatter = new Intl.NumberFormat(apos.locale, {
177
+ maximumFractionDigits: 2
178
+ });
174
179
  if (size >= 1000000) {
175
- return `${(size / 1000000).toFixed(2)}MB`;
180
+ const formatted = formatter.format(size / 1000000);
181
+ return this.$t('apostrophe:mediaMB', {
182
+ size: formatted
183
+ });
176
184
  } else {
177
- return `${Math.round(size / 1000)}KB`;
185
+ const formatted = formatter.format(size / 1000);
186
+ return this.$t('apostrophe:mediaKB', {
187
+ size: formatted
188
+ });
178
189
  }
179
190
  },
180
191
  createdDate() {
181
192
  if (!this.activeMedia.attachment || !this.activeMedia.attachment.createdAt) {
182
193
  return '';
183
194
  }
184
- return dayjs(this.activeMedia.attachment.createdAt).format('MMM Do, YYYY');
195
+ return dayjs(this.activeMedia.attachment.createdAt).format(this.$t('apostrophe:dayjsMediaCreatedDateFormat'));
185
196
  },
186
197
  isArchived() {
187
198
  return this.media.archived;
@@ -267,6 +278,7 @@ export default {
267
278
 
268
279
  this.$nextTick(async () => {
269
280
  if (this.docFields.hasErrors) {
281
+ this.triggerValidation = false;
270
282
  await apos.notify('apostrophe:resolveErrorsBeforeSaving', {
271
283
  type: 'warning',
272
284
  icon: 'alert-circle-icon',
@@ -322,7 +334,6 @@ export default {
322
334
  this.cancel();
323
335
  },
324
336
  updateActiveAttachment(attachment) {
325
- console.info('☄️', attachment);
326
337
  this.activeMedia.attachment = attachment;
327
338
  },
328
339
  viewMedia () {
@@ -3,7 +3,8 @@ module.exports = {
3
3
  options: {
4
4
  label: 'apostrophe:image',
5
5
  className: false,
6
- icon: 'image-icon'
6
+ icon: 'image-icon',
7
+ dimensionAttrs: false
7
8
  },
8
9
  fields: {
9
10
  add: {
@@ -4,15 +4,25 @@
4
4
  {% set className = data.manager.options.className %}
5
5
  {% endif %}
6
6
 
7
+ {% if data.options.dimensionAttrs %}
8
+ {% set dimensionAttrs = data.options.dimensionAttrs %}
9
+ {% elif data.manager.options.dimensionAttrs %}
10
+ {% set dimensionAttrs = data.manager.options.dimensionAttrs %}
11
+ {% endif %}
12
+
7
13
  {% set attachment = apos.image.first(data.widget._image) %}
8
14
 
9
15
  {% if attachment %}
10
- <img{% if className %} class="{{ className }}"{% endif %}
16
+ <img {% if className %} class="{{ className }}"{% endif %}
11
17
  srcset="{{ apos.image.srcset(attachment) }}"
12
18
  src="{{ apos.attachment.url(attachment, { size: data.options.size or 'full' }) }}"
13
19
  alt="{{ attachment._alt or '' }}"
20
+ {% if dimensionAttrs %}
21
+ {% if attachment.width %} width="{{ attachment.width }}" {% endif %}
22
+ {% if attachment.height %} height="{{ attachment.height }}" {% endif %}
23
+ {% endif %}
14
24
  {% if data.contextOptions and data.contextOptions.sizes %}
15
25
  sizes="{{ data.contextOptions.sizes }}"
16
26
  {% endif %}
17
27
  />
18
- {% endif %}
28
+ {% endif %}