@concretecms/bedrock 1.1.3 → 1.1.8

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 (27) hide show
  1. package/assets/accordions/js/frontend.js +1 -0
  2. package/assets/accordions/scss/frontend/_frontend.scss +11 -0
  3. package/assets/accordions/scss/frontend.scss +4 -0
  4. package/assets/bedrock/scss/_frontend.scss +1 -0
  5. package/assets/bedrock/scss/_theme-context-root.scss +17 -0
  6. package/assets/cms/components/customizer/FontFamilyPageCustomizerWidget.vue +3 -3
  7. package/assets/cms/components/customizer/ThemeCustomizer.vue +2 -2
  8. package/assets/cms/components/file-manager/Chooser/ExternalFileProvider.vue +1 -0
  9. package/assets/cms/components/file-manager/Chooser/FileManager.vue +17 -4
  10. package/assets/cms/components/file-manager/Chooser/FileSets.vue +1 -0
  11. package/assets/cms/components/file-manager/Chooser/Files.vue +67 -8
  12. package/assets/cms/components/file-manager/Chooser/FolderBookmark.vue +2 -1
  13. package/assets/cms/components/file-manager/Chooser/Header.vue +52 -5
  14. package/assets/cms/components/file-manager/Chooser/RecentUploads.vue +10 -2
  15. package/assets/cms/components/file-manager/Chooser/SavedSearch.vue +1 -0
  16. package/assets/cms/components/file-manager/Chooser/Search.vue +14 -19
  17. package/assets/cms/components/file-manager/Chooser.vue +21 -4
  18. package/assets/cms/components/form/ConcreteFileInput.vue +6 -0
  19. package/assets/cms/components/form/ConcreteThemeColorInput.vue +1 -1
  20. package/assets/cms/js/jquery-awesome-rating.js +3 -3
  21. package/assets/cms/scss/_toolbar.scss +8 -0
  22. package/assets/cms/scss/bootstrap/_reboot.scss +0 -29
  23. package/assets/cms/scss/file-manager/_file-chooser.scss +10 -1
  24. package/assets/imagery/scss/frontend/_hero-image.scss +7 -0
  25. package/assets/navigation/scss/frontend/_frontend.scss +1 -0
  26. package/assets/navigation/scss/frontend/_top-navigation-bar.scss +39 -0
  27. package/package.json +2 -2
@@ -0,0 +1 @@
1
+ import 'bootstrap/js/dist/collapse'
@@ -0,0 +1,11 @@
1
+ @import 'bootstrap/scss/functions';
2
+ @import 'bootstrap/scss/variables';
3
+ @import 'bootstrap/scss/mixins';
4
+
5
+ // Base styling
6
+ @import 'bootstrap/scss/accordion';
7
+
8
+ // Reset header top margins because if this is used on old bootstrap sometimes a margin is present.
9
+ .accordion-header {
10
+ margin-top: 0;
11
+ }
@@ -0,0 +1,4 @@
1
+ // This is an entry point so it just includes the partial that includes everything else.
2
+ // That way if we want to include full support in our theme we just include the partial (rather
3
+ // than including the entry point because I think it's bad practice.)
4
+ @import 'frontend/frontend';
@@ -5,6 +5,7 @@
5
5
  @import '@fortawesome/fontawesome-free/scss/variables';
6
6
 
7
7
  // Import Theme Foundation items
8
+ @import 'theme-context-root';
8
9
  @import 'mixins';
9
10
  @import 'utilities';
10
11
  @import 'theme-grid';
@@ -0,0 +1,17 @@
1
+ // What is the purpose of this file, you ask?
2
+ // In our theme color input selector, we use CSS variables to display colors.
3
+ // e.g. var(--bs-primary)
4
+ // However, since .ccm-ui has the CMS variables attached to it, and the ::root has the
5
+ // theme bootstrap variables attached to it, the primary color shown in the color input
6
+ // Will come from .ccm-ui instead of ::root, since .ccm-ui is inside ::root.
7
+ // So instead, let's ALSO define the theme colors against the .ccm-context-theme
8
+ // class, and then wrap any controls that need to have access to theme specific variables
9
+ // within the .ccm-context-theme class.
10
+
11
+ .ccm-context-theme {
12
+
13
+ @each $color, $value in $theme-colors {
14
+ --#{$variable-prefix}#{$color}: #{$value};
15
+ }
16
+
17
+ }
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <select @change="componentUpdated" class="selectpicker" v-model="selectedFont">
3
3
  <option value="" :data-content="'<span>Default</span>'">Default</option>
4
- <option v-for="font in webFonts" :value="font" :data-content="'<span style=\'font-family: ' + font + '\'>' + font + '</span>'">{{ font }}</option>
4
+ <option v-for="font in customFonts" :value="font" :data-content="'<span style=\'font-family: ' + font + '\'>' + font + '</span>'">{{ font }}</option>
5
5
  <option v-for="font in standardFonts" :value="font" :data-content="'<span style=\'font-family: ' + font + '\'>' + font + '</span>'">{{ font }}</option>
6
6
  </select>
7
7
  </template>
@@ -42,13 +42,13 @@ export default {
42
42
  }
43
43
  },
44
44
  computed: {
45
- webFonts: function() {
45
+ customFonts: function() {
46
46
  var fonts = []
47
47
  var my = this
48
48
  this.styleValue.style.fonts.forEach(function(font) {
49
49
  fonts.push(font.name)
50
50
  })
51
- if (fonts.indexOf(my.selectedFont) === -1) {
51
+ if (fonts.indexOf(my.selectedFont) === -1 && my.standardFonts.indexOf(my.selectedFont) === -1) {
52
52
  fonts.push(my.selectedFont)
53
53
  }
54
54
  return fonts
@@ -178,7 +178,7 @@ export default {
178
178
  url: my.createNewSkinAction,
179
179
  data: {
180
180
  skinName: my.newSkinName,
181
- styles: my.customizerStyles,
181
+ styles: JSON.stringify(my.customizerStyles),
182
182
  customCss: my.customizerCustomCss,
183
183
  ccm_token: CCM_SECURITY_TOKEN
184
184
  },
@@ -301,7 +301,7 @@ export default {
301
301
  new ConcreteAjaxRequest({
302
302
  url: my.saveSkinAction,
303
303
  data: {
304
- styles: my.customizerStyles,
304
+ styles: JSON.stringify(my.customizerStyles),
305
305
  customCss: my.customizerCustomCss,
306
306
  ccm_token: CCM_SECURITY_TOKEN
307
307
  },
@@ -31,6 +31,7 @@
31
31
  </div>
32
32
  <div>
33
33
  <files v-if="keywords"
34
+ :key-prefix="'external-file-provider' + id"
34
35
  :selectedFiles.sync="selectedFiles"
35
36
  :resultsFormFactor="formFactor"
36
37
  :routePath="routePath + id + '/search/' + keywords"
@@ -1,11 +1,14 @@
1
1
  <template>
2
2
  <div>
3
3
  <chooser-header :resultsFormFactor.sync="formFactor"
4
+ :resultsSearchQuery.sync="searchQuery"
4
5
  :breadcrumb-items="breadcrumbItems"
6
+ :enable-search="searchChooserIsEnabled"
5
7
  @breadcrumbItemClick="activeFolder = $event.folderId"
6
8
  :title="title"/>
7
9
 
8
10
  <files :selectedFiles.sync="selectedFiles"
11
+ key-prefix="file-manager"
9
12
  :resultsFormFactor="formFactor"
10
13
  :routePath="routePath + activeFolder"
11
14
  :enable-pagination="true"
@@ -32,9 +35,15 @@ export default {
32
35
  selectedFiles: [],
33
36
  breadcrumbItems: [],
34
37
  routePath: '/ccm/system/file/chooser/get_folder_files/',
35
- formFactor: 'grid'
38
+ formFactor: 'grid',
39
+ searchQuery: ''
36
40
  }),
37
41
  props: {
42
+ searchChooserIsEnabled: {
43
+ type: Boolean,
44
+ required: false,
45
+ default: true
46
+ },
38
47
  resultsFormFactor: {
39
48
  type: String,
40
49
  required: false,
@@ -59,7 +68,7 @@ export default {
59
68
  },
60
69
  created() {
61
70
  this.activeFolder = this.$props.startFolder
62
- this.fetchBreadcrumb(this.activeFolder)
71
+ // this.fetchBreadcrumb(this.activeFolder) // Not sure why this is here, it leads to duplicate requests and I don't think it needs to be
63
72
  },
64
73
  methods: {
65
74
  fetchBreadcrumb(folderId = '') {
@@ -81,15 +90,19 @@ export default {
81
90
  formFactor(value) {
82
91
  this.$emit('update:resultsFormFactor', value)
83
92
  },
93
+ searchQuery(value) {
94
+ this.$emit('update:resultsSearchQuery', value)
95
+ },
84
96
  startFolder(value) {
85
97
  this.activeFolder = value
86
- this.fetchBreadcrumb(value)
98
+ // this.fetchBreadcrumb(value) // Not sure why this is here, it leads to duplicate requests and I don't think it needs to be
87
99
  }
88
100
  },
89
101
  mounted() {
90
102
  this.formFactor = this.resultsFormFactor
103
+ this.searchQuery = this.resultsSearchQuery
91
104
  this.activeFolder = this.$props.startFolder
92
- this.fetchBreadcrumb(this.activeFolder)
105
+ // this.fetchBreadcrumb(this.activeFolder) // Not sure why this is here, it leads to duplicate requests and I don't think it needs to be
93
106
  }
94
107
  }
95
108
  </script>
@@ -17,6 +17,7 @@
17
17
  </div>
18
18
  <div class="mt-3" v-show="activeSet">
19
19
  <files v-if="activeSet"
20
+ key-prefix="file-sets"
20
21
  :selectedFiles.sync="selectedFiles"
21
22
  :resultsFormFactor="formFactor"
22
23
  :routePath="routePath + activeSet"
@@ -3,10 +3,10 @@
3
3
  <svg v-if="isLoading" class="ccm-loader-dots"><use xlink:href="#icon-loader-circles" /></svg>
4
4
  <div v-if="!isLoading">
5
5
  <div class="ccm-image-cell-grid container-fluid ps-0" v-if="resultsFormFactor === 'grid'">
6
- <div v-for="row in rows" class="row text-center" :key="row.index">
7
- <div class="col-md-3" v-for="file in row" :key="(file.fID || file.treeNodeID) + 'grid'">
6
+ <div v-for="(row, index) in rows" class="row text-center" :key="keyPrefix + '-' + index">
7
+ <div class="col-md-3" v-for="file in row" :key="keyPrefix + '-' + (file.fID || file.treeNodeID) + '-grid'">
8
8
  <div class="ccm-image-cell" @click="onItemClick(file)">
9
- <label class="form-label" :for="'file-' + (file.fID || file.treeNodeID)"><span v-html="file.resultsThumbnailImg"></span></label>
9
+ <label class="form-label" :data-bs-content="getGridHoverContent(file)" :for="'file-' + (file.fID || file.treeNodeID)"><span v-html="file.resultsThumbnailImg"></span></label>
10
10
  <div class="ccm-image-cell-title pt-1">
11
11
  <div class="form-check form-check-inline">
12
12
  <input :disabled="!canChooseFile(file)" class="form-check-input" type="checkbox" v-if="multipleSelection && !file.isFolder" v-model="selectedFiles" :id="'file-' + file.fID" :value="file.fID">
@@ -19,7 +19,7 @@
19
19
  </div>
20
20
  </div>
21
21
  <div v-if="resultsFormFactor === 'list'">
22
- <table class="table ccm-image-chooser-list-view ccm-search-results-table">
22
+ <table class="table align-middle ccm-image-chooser-list-view ccm-search-results-table">
23
23
  <thead>
24
24
  <tr>
25
25
  <th></th>
@@ -33,18 +33,24 @@
33
33
  <a v-if="enableSort" href="#" @click.prevent="sortBy(dateSortColumn)">{{ i18n.uploaded }}</a>
34
34
  <span v-else>{{ i18n.uploaded }}</span>
35
35
  </th>
36
+ <th>{{ i18n.size }}</th>
37
+ <th>{{ i18n.width }}</th>
38
+ <th>{{ i18n.height }}</th>
36
39
  </tr>
37
40
  </thead>
38
41
  <tbody>
39
- <tr v-for="file in fileList" :key="(file.fID || file.treeNodeID) + 'list'" @click="onItemClick(file)">
42
+ <tr v-for="file in fileList" :key="keyPrefix + '-' + (file.fID || file.treeNodeID) + '-list'" @click="onItemClick(file)">
40
43
  <td>
41
44
  <input type="checkbox" :disabled="!canChooseFile(file)" v-if="multipleSelection && !file.isFolder" v-model="selectedFiles" :id="'file-' + file.fID" :value="file.fID">
42
45
  <input type="radio" :disabled="!canChooseFile(file)" v-if="!multipleSelection && !file.isFolder" v-model="selectedFiles" :id="'file-' + file.fID" :value="file.fID">
43
46
  </td>
44
- <td class="ccm-image-chooser-icon"><span v-html="file.resultsThumbnailImg" width="32" height="32"></span></td>
47
+ <td class="ccm-image-chooser-icon"><div :data-bs-content="getListHoverContent(file)"><span v-html="file.resultsThumbnailImg" width="32" height="32"></span></div></td>
45
48
  <td>{{file.fID}}</td>
46
49
  <td>{{file.title}}</td>
47
50
  <td>{{file.fvDateAdded}}</td>
51
+ <td>{{file.size}}</td>
52
+ <td>{{file.attributes ? file.attributes.width : ''}}</td>
53
+ <td>{{file.attributes ? file.attributes.height : ''}}</td>
48
54
  </tr>
49
55
  </tbody>
50
56
  </table>
@@ -71,7 +77,7 @@
71
77
  }
72
78
  </style>
73
79
  <script>
74
- /* global CCM_DISPATCHER_FILENAME, ConcreteAjaxRequest */
80
+ /* global CCM_DISPATCHER_FILENAME, bootstrap, ConcreteAjaxRequest */
75
81
  /* eslint-disable no-new */
76
82
  import Pagination from '../../Pagination'
77
83
 
@@ -83,7 +89,10 @@ export default {
83
89
  i18n: {
84
90
  id: 'ID',
85
91
  name: 'Name',
86
- uploaded: 'Uploaded'
92
+ uploaded: 'Uploaded',
93
+ size: 'Size',
94
+ width: 'Width',
95
+ height: 'Height'
87
96
  },
88
97
  currentPage: 1,
89
98
  rows: false,
@@ -103,6 +112,11 @@ export default {
103
112
  filters: {
104
113
  type: Array
105
114
  },
115
+ keyPrefix: {
116
+ type: String,
117
+ required: false,
118
+ default: ''
119
+ },
106
120
  enableSort: {
107
121
  type: Boolean,
108
122
  required: false,
@@ -174,6 +188,40 @@ export default {
174
188
  }
175
189
  },
176
190
  methods: {
191
+ getGridHoverContent(file) {
192
+ if (!file.isFolder) {
193
+ var title = ''
194
+ if (file.resultsThumbnailDetailImg) {
195
+ title += '<div>' + file.resultsThumbnailDetailImg + '</div>'
196
+ }
197
+ title += '<div class="text-center"><b>' + file.size + '</b></div>'
198
+ if (file.attributes && file.attributes.width && file.attributes.height) {
199
+ title += '<div class="text-center text-muted"><small>' + file.attributes.width + 'x' + file.attributes.height + '</small></div>'
200
+ }
201
+ return title
202
+ }
203
+ },
204
+ getListHoverContent(file) {
205
+ if (!file.isFolder) {
206
+ if (file.resultsThumbnailDetailImg) {
207
+ return '<div>' + file.resultsThumbnailDetailImg + '</div>'
208
+ }
209
+ }
210
+ },
211
+ setupHoverPreview() {
212
+ var $cells = $(this.$el).find('[data-bs-content]')
213
+ $cells.each(function(i) {
214
+ return new bootstrap.Popover($cells.get(i), {
215
+ container: '#ccm-tooltip-holder',
216
+ customClass: 'ccm-image-chooser-popover',
217
+ placement: 'bottom',
218
+ delay: 500,
219
+ trigger: 'hover',
220
+ fallbackPlacements: ['top'],
221
+ html: true
222
+ })
223
+ })
224
+ },
177
225
  canChooseFile(file) {
178
226
  var canChooseFile = -1
179
227
  if (this.filters) {
@@ -284,6 +332,17 @@ export default {
284
332
  }
285
333
  },
286
334
  watch: {
335
+ resultsFormFactor(value) {
336
+ var my = this
337
+ setTimeout(function() {
338
+ my.setupHoverPreview()
339
+ }, 5)
340
+ },
341
+ viewIsLoading(value) {
342
+ if (!value) {
343
+ this.setupHoverPreview()
344
+ }
345
+ },
287
346
  selectedFiles(value) {
288
347
  this.$emit('update:selectedFiles', Array.isArray(value) ? value : [value])
289
348
  },
@@ -5,7 +5,8 @@
5
5
  @breadcrumbItemClick="activeFolder = $event.folderId"
6
6
  :title="title"/>
7
7
 
8
- <files :selectedFiles.sync="selectedFiles"
8
+ <files :key-prefix="'folder-bookmark' + activeFolder"
9
+ :selectedFiles.sync="selectedFiles"
9
10
  :resultsFormFactor="formFactor"
10
11
  :routePath="routePath + activeFolder"
11
12
  :enable-pagination="true"
@@ -1,14 +1,27 @@
1
1
  <template>
2
2
  <div class="row">
3
- <div class="mb-3 col-sm-12">
4
- <header>
3
+ <div class="mb-3">
4
+ <header class="hstack align-items-start gap-3">
5
+ <div class="me-auto">
6
+ <h5>{{title}}</h5>
7
+ <breadcrumb v-if="breadcrumbItems" :breadcrumb-items="breadcrumbItems" @itemClick="onBreadcrumbItemClick" />
8
+ </div>
9
+ <form @submit.prevent="search" v-if="enableSearch">
10
+ <div class="ccm-header-search-form-input input-group input-group-sm">
11
+ <input type="text" class="form-control border-end-0" :placeholder="i18n.search"
12
+ autocomplete="false" v-model="searchText">
13
+ <button type="submit" class="input-group-icon">
14
+ <svg width="16" height="16">
15
+ <use xlink:href="#icon-search"/>
16
+ </svg>
17
+ </button>
18
+ </div>
19
+ </form>
5
20
  <button type="button" @click="toggleFormFactor" v-if="showFormFactorSelector"
6
- class="btn btn-sm float-end btn-secondary">
21
+ class="btn btn-sm btn-secondary">
7
22
  <i v-if="resultsFormFactor === 'grid'" class="fas fa-th"></i>
8
23
  <i v-if="resultsFormFactor === 'list'" class="fas fa-list"></i>
9
24
  </button>
10
- <h5>{{title}}</h5>
11
- <breadcrumb v-if="breadcrumbItems" :breadcrumb-items="breadcrumbItems" @itemClick="onBreadcrumbItemClick" />
12
25
  </header>
13
26
  </div>
14
27
  </div>
@@ -31,6 +44,14 @@ export default {
31
44
  required: false,
32
45
  default: true
33
46
  },
47
+ enableSearch: {
48
+ type: Boolean,
49
+ required: false,
50
+ default: false
51
+ },
52
+ resultsSearchQuery: {
53
+ type: String
54
+ },
34
55
  resultsFormFactor: {
35
56
  type: String,
36
57
  required: false,
@@ -42,7 +63,24 @@ export default {
42
63
  required: false
43
64
  }
44
65
  },
66
+ data() {
67
+ return {
68
+ i18n: {
69
+ search: 'Search'
70
+ },
71
+ searchText: ''
72
+ }
73
+ },
74
+ watch: {
75
+ resultsSearchQuery(value) {
76
+ this.searchText = value
77
+ }
78
+ },
45
79
  methods: {
80
+ search() {
81
+ const my = this
82
+ my.$emit('update:resultsSearchQuery', my.searchText)
83
+ },
46
84
  toggleFormFactor() {
47
85
  const my = this
48
86
  if (this.resultsFormFactor === 'grid') {
@@ -54,6 +92,15 @@ export default {
54
92
  onBreadcrumbItemClick(item) {
55
93
  this.$emit('breadcrumbItemClick', item)
56
94
  }
95
+ },
96
+ mounted() {
97
+ if (window.ccmi18n_filemanager) {
98
+ for (const key in this.i18n) {
99
+ if (window.ccmi18n_filemanager[key]) {
100
+ this.i18n[key] = window.ccmi18n_filemanager[key]
101
+ }
102
+ }
103
+ }
57
104
  }
58
105
  }
59
106
  </script>
@@ -1,8 +1,11 @@
1
1
  <template>
2
2
  <div>
3
- <chooser-header :resultsFormFactor.sync="formFactor" :title="title"/>
3
+ <chooser-header :resultsFormFactor.sync="formFactor"
4
+ :resultsSearchQuery.sync="searchQuery"
5
+ :title="title"/>
4
6
 
5
7
  <files :selectedFiles.sync="selectedFiles"
8
+ key-prefix="recent-uploads"
6
9
  :resultsFormFactor="formFactor"
7
10
  :filters="filters"
8
11
  routePath="/ccm/system/file/chooser/recent"
@@ -22,7 +25,8 @@ export default {
22
25
  },
23
26
  data: () => ({
24
27
  selectedFiles: [],
25
- formFactor: 'grid'
28
+ formFactor: 'grid',
29
+ searchQuery: ''
26
30
  }),
27
31
  props: {
28
32
  resultsFormFactor: {
@@ -49,10 +53,14 @@ export default {
49
53
  },
50
54
  formFactor(value) {
51
55
  this.$emit('update:resultsFormFactor', value)
56
+ },
57
+ searchQuery(value) {
58
+ this.$emit('update:resultsSearchQuery', value)
52
59
  }
53
60
  },
54
61
  mounted() {
55
62
  this.formFactor = this.resultsFormFactor
63
+ this.searchQuery = this.resultsSearchQuery
56
64
  }
57
65
  }
58
66
  </script>
@@ -20,6 +20,7 @@
20
20
  </div>
21
21
  <div class="mt-3" v-show="activeSearchPreset">
22
22
  <files v-if="activeSearchPreset"
23
+ key-prefix="saved-search"
23
24
  :selectedFiles.sync="selectedFiles"
24
25
  :resultsFormFactor="formFactor"
25
26
  :filters="filters"
@@ -1,22 +1,10 @@
1
1
  <template>
2
2
  <div>
3
- <chooser-header :resultsFormFactor.sync="formFactor" :title="title"/>
3
+ <chooser-header :resultsFormFactor.sync="formFactor"
4
+ :resultsSearchQuery.sync="searchQuery"
5
+ :enable-search="true"
6
+ :title="title"/>
4
7
 
5
- <div class="row mb-3">
6
- <div class="col-md-4 ms-auto">
7
- <form @submit.prevent="search">
8
- <div class="ccm-header-search-form-input input-group">
9
- <input type="text" class="form-control border-end-0" :placeholder="i18n.search"
10
- autocomplete="false" v-model="searchText">
11
- <button type="submit" class="input-group-icon">
12
- <svg width="16" height="16">
13
- <use xlink:href="#icon-search"/>
14
- </svg>
15
- </button>
16
- </div>
17
- </form>
18
- </div>
19
- </div>
20
8
  <div v-show="!keywords" class="text-center mt-5">
21
9
  <span class="search-icon my-4">
22
10
  <Icon icon="search" type="fas" color="#f4f4f4"/>
@@ -25,6 +13,7 @@
25
13
  </div>
26
14
  <div>
27
15
  <files v-if="keywords"
16
+ key-prefix="search"
28
17
  :selectedFiles.sync="selectedFiles"
29
18
  :resultsFormFactor="formFactor"
30
19
  :routePath="routePath + keywords"
@@ -50,14 +39,13 @@ export default {
50
39
  },
51
40
  data: () => ({
52
41
  i18n: {
53
- search: 'Search',
54
42
  initialSearchChooserTip: "Let's get some info on what you're looking for."
55
43
  },
56
- searchText: '',
57
44
  keywords: '',
58
45
  selectedFiles: [],
59
46
  routePath: '/ccm/system/file/chooser/search/',
60
- formFactor: 'grid'
47
+ formFactor: 'grid',
48
+ searchQuery: ''
61
49
  }),
62
50
  props: {
63
51
  resultsFormFactor: {
@@ -66,6 +54,9 @@ export default {
66
54
  default: 'grid', // grid | list
67
55
  validator: value => ['grid', 'list'].indexOf(value) !== -1
68
56
  },
57
+ resultsSearchQuery: {
58
+ type: String
59
+ },
69
60
  title: {
70
61
  type: String,
71
62
  required: true
@@ -89,6 +80,9 @@ export default {
89
80
  },
90
81
  formFactor(value) {
91
82
  this.$emit('update:resultsFormFactor', value)
83
+ },
84
+ searchQuery(value) {
85
+ this.keywords = value
92
86
  }
93
87
  },
94
88
  mounted() {
@@ -100,6 +94,7 @@ export default {
100
94
  }
101
95
  }
102
96
  this.formFactor = this.resultsFormFactor
97
+ this.searchQuery = this.resultsSearchQuery
103
98
  }
104
99
  }
105
100
  </script>
@@ -4,8 +4,8 @@
4
4
  <div class="row h-100">
5
5
  <div class="col-4 border-end p-3">
6
6
  <ul class="nav flex-column">
7
- <li class="nav-item" v-for="item in choosers" :key="item.id">
8
- <a :class="{'nav-link': true, 'active': activeNavItem.id === item.id}"
7
+ <li class="nav-item" v-for="item in choosers" :key="item.componentKey + '-' + item.id">
8
+ <a :class="{'nav-link': true, 'active': activeNavItem.id === item.id && activeNavItem.componentKey === item.componentKey}"
9
9
  @click.prevent="activateTab(item)"
10
10
  href="javascript:void(0)">
11
11
  {{item.title}}
@@ -14,8 +14,8 @@
14
14
  </ul>
15
15
  <hr>
16
16
  <ul class="nav flex-column">
17
- <li class="nav-item" v-for="item in uploaders" :key="item.id">
18
- <a :class="{'nav-link': true, 'active': activeNavItem.id === item.id}"
17
+ <li class="nav-item" v-for="item in uploaders" :key="item.componentKey + '-' + item.id">
18
+ <a :class="{'nav-link': true, 'active': activeNavItem.id === item.id && activeNavItem.componentKey === item.componentKey}"
19
19
  @click.prevent="activateTab(item)"
20
20
  href="javascript:void(0)">
21
21
  {{item.title}}
@@ -32,6 +32,8 @@
32
32
  :extraData="activeNavItem.data || {}"
33
33
  :multipleSelection="multipleSelection"
34
34
  :selectedFiles.sync="selectedFiles"
35
+ :searchChooserIsEnabled="searchChooserIsEnabled()"
36
+ :resultsSearchQuery.sync="resultsSearchQuery"
35
37
  :resultsFormFactor.sync="resultsFormFactor"
36
38
  :filesReadyToUpload.sync="filesReadyToUpload"
37
39
  :filters="filters"
@@ -86,6 +88,7 @@ export default {
86
88
  search: 'Search',
87
89
  uploadFiles: 'Upload Files'
88
90
  },
91
+ resultsSearchQuery: '',
89
92
  filesReadyToUpload: 0,
90
93
  activeNavItem: null,
91
94
  resultsFormFactor: 'grid',
@@ -155,9 +158,23 @@ export default {
155
158
  },
156
159
  uploaders() {
157
160
  this.applyLocalization()
161
+ },
162
+ resultsSearchQuery(value) {
163
+ if (value) {
164
+ this.activateTabByKey('search')
165
+ }
158
166
  }
159
167
  },
160
168
  methods: {
169
+ searchChooserIsEnabled() {
170
+ var enabled = false
171
+ this.choosers.forEach(function(chooser) {
172
+ if (chooser.id === 'search') {
173
+ enabled = true
174
+ }
175
+ })
176
+ return enabled
177
+ },
161
178
  applyLocalization() {
162
179
  if (this.choosers) {
163
180
  for (const chooser of this.choosers) {
@@ -72,6 +72,12 @@ export default {
72
72
  this.$emit('change', null)
73
73
  }
74
74
  }
75
+ if (!this.isFirstRun) {
76
+ // Fire the jQuery change event.
77
+ // @deprecated - do not use this unless you have to. Use this component directly instead and listen
78
+ // to its change event. This will be removed when the jQuery dependency is removed.
79
+ $('input[name=' + this.inputName + ']').trigger('change')
80
+ }
75
81
  this.isFirstRun = false
76
82
  }
77
83
  }
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="mb-3">
2
+ <div class="mb-3 ccm-context-theme">
3
3
  <select :name="inputName" data-select="theme-colors" data-width="100%">
4
4
  <option v-for="color in colorCollection.colors" :selected="selectedColor == color.variable" :data-content="dataContentAttribute(color)" :value="color.variable">{{ color.name }}</option>
5
5
  </select>
@@ -16,9 +16,9 @@
16
16
  var toggleStarEl
17
17
  toggleStarEl = function($star, state) {
18
18
  if (state) {
19
- return $star.removeClass('fa-star-o').addClass('fa-star')
19
+ return $star.removeClass('far').addClass('fas')
20
20
  } else {
21
- return $star.removeClass('fa-star').addClass('fa-star-o')
21
+ return $star.removeClass('fas').addClass('far')
22
22
  }
23
23
  }
24
24
  return $.fn.awesomeStarRating = function(options) {
@@ -39,7 +39,7 @@
39
39
  stars = []
40
40
  _results = []
41
41
  for (i = _i = 1; _i <= 5; i = ++_i) {
42
- $star = $('<i class="fa"></i>')
42
+ $star = $('<i class="fa-star"></i>')
43
43
  toggleStarEl($star, i <= ratingScore)
44
44
  $ratingContainer.append($star)
45
45
  stars[i] = $star
@@ -518,3 +518,11 @@ ul.ccm-mobile-menu {
518
518
  }
519
519
  }
520
520
  }
521
+
522
+ html.ccm-toolbar-visible {
523
+ .ccm-page {
524
+ // This used to be dynamically included in the theme. Now we're moving it here.
525
+ // The purpose of this code is to push the content of the page down if the toolbar appears at the top.
526
+ margin-top: 48px;
527
+ }
528
+ }
@@ -20,35 +20,6 @@
20
20
  }
21
21
 
22
22
 
23
- // Root
24
- //
25
- // Ability to the value of the root font sizes, affecting the value of `rem`.
26
- // null by default, thus nothing is generated.
27
-
28
- :root {
29
- font-size: $font-size-root;
30
-
31
- @if $enable-smooth-scroll {
32
- @media (prefers-reduced-motion: no-preference) {
33
- scroll-behavior: smooth;
34
- }
35
- }
36
- }
37
-
38
-
39
- // Body
40
- //
41
- // 1. Remove the margin in all browsers.
42
- // 2. As a best practice, apply a default `background-color`.
43
- // 3. Prevent adjustments of font size after orientation changes in iOS.
44
- // 4. Change the default tap highlight to be completely transparent in iOS.
45
-
46
- html.ccm-toolbar-visible {
47
- // We _could_ set this by setting font-size-root, but we don't really want to screw with the theme loading this
48
- // unless we know the toolbar is visible.
49
- font-size: 16px; // By setting this here, rem declarations in BS5 work off of 16px, and the base theme can do whatever it wants at body
50
- }
51
-
52
23
  .ccm-ui {
53
24
  margin: 0; // 1
54
25
  font-family: $font-family-base;
@@ -1,9 +1,18 @@
1
1
  .ccm-ui {
2
+ .ccm-image-chooser-popover {
3
+ max-width: 400px;
4
+
5
+ img {
6
+ height: auto;
7
+ margin-bottom: 1rem;
8
+ max-width: 100%;
9
+ }
10
+ }
11
+
2
12
  table.ccm-image-chooser-list-view {
3
13
  img {
4
14
  height: 32px;
5
15
  width: 32px;
6
16
  }
7
-
8
17
  }
9
18
  }
@@ -12,6 +12,13 @@ div.ccm-block-hero-image {
12
12
  width: 100%;
13
13
  }
14
14
 
15
+ div.ccm-block-hero-image-text {
16
+ align-items: center;
17
+ display: flex;
18
+ flex-direction: column;
19
+ justify-content: center;
20
+ }
21
+
15
22
  div.ccm-block-hero-image-cover {
16
23
  z-index: 2;
17
24
  }
@@ -1,5 +1,6 @@
1
1
  // Core block types
2
2
  @import 'page-list';
3
3
  @import 'rss-displayer';
4
+ @import 'top-navigation-bar';
4
5
  @import 'date-navigation';
5
6
  @import 'responsive-navigation';
@@ -0,0 +1,39 @@
1
+ @import 'bootstrap/scss/functions';
2
+ @import 'bootstrap/scss/variables';
3
+ @import 'bootstrap/scss/mixins';
4
+
5
+ // Navigation bar styling
6
+ div.ccm-block-top-navigation-bar {
7
+
8
+ @import 'bootstrap/scss/navbar';
9
+ @import 'bootstrap/scss/forms/input-group';
10
+
11
+ .navbar {
12
+ .navbar-nav {
13
+ order: 0;
14
+ }
15
+ }
16
+
17
+ // Logo/brand
18
+ .navbar-brand {
19
+ // If this is being included in a BS4 theme we need to reset some parameters
20
+ float: none;
21
+ height: auto;
22
+
23
+ img {
24
+ max-height: 38px;
25
+ }
26
+ }
27
+
28
+ // Search
29
+ form {
30
+ display: flex;
31
+ margin-left: auto;
32
+ order: 1;
33
+
34
+ .btn {
35
+ background: none;
36
+ padding: $btn-padding-x-sm $btn-padding-y-sm;
37
+ }
38
+ }
39
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@concretecms/bedrock",
3
- "version": "1.1.3",
3
+ "version": "1.1.8",
4
4
  "description": "The asset framework and dependencies for Concrete CMS.",
5
5
  "scripts": {
6
6
  "lint": "standardx \"**/*.{js,vue}\" && stylelint assets/**/*.{scss,vue}",
@@ -46,7 +46,7 @@
46
46
  "selectize-bootstrap4-theme": "^2.0.2",
47
47
  "spectrum-colorpicker": "^1.8.1",
48
48
  "tristate": "^1.2.0",
49
- "underscore": "^1.11.0",
49
+ "underscore": "^1.13",
50
50
  "v-calendar": "^1.0.8",
51
51
  "vue": "^2.6.12",
52
52
  "vue-js-toggle-button": "^1.3.3",