@plone/volto 18.0.0-alpha.31 → 18.0.0-alpha.33

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 (75) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/locales/ca/LC_MESSAGES/volto.po +12 -0
  3. package/locales/ca.json +1 -1
  4. package/locales/de/LC_MESSAGES/volto.po +12 -0
  5. package/locales/de.json +1 -1
  6. package/locales/en/LC_MESSAGES/volto.po +12 -0
  7. package/locales/en.json +1 -1
  8. package/locales/es/LC_MESSAGES/volto.po +12 -0
  9. package/locales/es.json +1 -1
  10. package/locales/eu/LC_MESSAGES/volto.po +12 -0
  11. package/locales/eu.json +1 -1
  12. package/locales/fi/LC_MESSAGES/volto.po +12 -0
  13. package/locales/fi.json +1 -1
  14. package/locales/fr/LC_MESSAGES/volto.po +12 -0
  15. package/locales/fr.json +1 -1
  16. package/locales/hi/LC_MESSAGES/volto.po +4989 -0
  17. package/locales/hi.json +1 -0
  18. package/locales/it/LC_MESSAGES/volto.po +12 -0
  19. package/locales/it.json +1 -1
  20. package/locales/ja/LC_MESSAGES/volto.po +12 -0
  21. package/locales/ja.json +1 -1
  22. package/locales/nl/LC_MESSAGES/volto.po +12 -0
  23. package/locales/nl.json +1 -1
  24. package/locales/pt/LC_MESSAGES/volto.po +12 -0
  25. package/locales/pt.json +1 -1
  26. package/locales/pt_BR/LC_MESSAGES/volto.po +12 -0
  27. package/locales/pt_BR.json +1 -1
  28. package/locales/ro/LC_MESSAGES/volto.po +12 -0
  29. package/locales/ro.json +1 -1
  30. package/locales/volto.pot +13 -1
  31. package/locales/zh_CN/LC_MESSAGES/volto.po +12 -0
  32. package/locales/zh_CN.json +1 -1
  33. package/package.json +6 -4
  34. package/razzle.config.js +51 -0
  35. package/src/components/manage/BlockChooser/BlockChooserSearch.jsx +1 -0
  36. package/src/components/manage/Blocks/Block/EditBlockWrapper.jsx +2 -0
  37. package/src/components/manage/Form/Form.jsx +1 -1
  38. package/src/components/manage/Sidebar/ObjectBrowserBody.jsx +158 -65
  39. package/src/components/manage/Sidebar/ObjectBrowserNav.jsx +125 -71
  40. package/src/components/manage/Widgets/IdWidget.jsx +138 -203
  41. package/src/components/manage/Widgets/TextWidget.jsx +92 -124
  42. package/src/components/manage/Widgets/TextWidget.stories.jsx +14 -3
  43. package/src/components/theme/App/App.jsx +5 -0
  44. package/src/components/theme/Footer/Footer.jsx +1 -0
  45. package/src/components/theme/Navigation/Navigation.jsx +1 -1
  46. package/src/components/theme/SlotRenderer/SlotRenderer.tsx +3 -4
  47. package/src/components/theme/View/View.jsx +5 -3
  48. package/src/components/theme/View/View.test.jsx +1 -0
  49. package/src/config/ControlPanels.js +7 -0
  50. package/src/config/config.test.js +232 -0
  51. package/src/config/server.js +0 -1
  52. package/src/constants/Languages.js +1 -0
  53. package/src/express-middleware/files.js +1 -0
  54. package/src/express-middleware/images.js +1 -0
  55. package/src/express-middleware/static.js +37 -19
  56. package/src/helpers/Api/Api.js +12 -0
  57. package/src/helpers/Api/Api.plone.rest.test.js +1 -0
  58. package/src/helpers/Api/Api.test.js +1 -0
  59. package/src/helpers/Html/Html.jsx +6 -8
  60. package/src/helpers/Slots/index.tsx +12 -5
  61. package/src/server.jsx +34 -36
  62. package/theme/themes/pastanaga/extras/blocks.less +10 -10
  63. package/theme/themes/pastanaga/extras/objectbrowser-widget.less +83 -0
  64. package/theme/themes/pastanaga/extras/widgets.less +19 -0
  65. package/types/components/manage/Sidebar/ObjectBrowserNav.d.ts +2 -1
  66. package/types/components/manage/Widgets/IdWidget.d.ts +54 -2
  67. package/types/components/manage/Widgets/TextWidget.d.ts +54 -5
  68. package/types/components/manage/Widgets/TextWidget.stories.d.ts +13 -1
  69. package/types/components/manage/Widgets/index.d.ts +2 -2
  70. package/types/config/Widgets.d.ts +1 -1
  71. package/types/config/config.test.d.ts +1 -0
  72. package/types/config/server.d.ts +0 -3
  73. package/types/constants/Languages.d.ts +1 -0
  74. package/types/helpers/Slots/index.d.ts +5 -3
  75. package/types/start-client.d.ts +1 -1
@@ -206,8 +206,10 @@ class View extends Component {
206
206
  */
207
207
  render() {
208
208
  const { views } = config;
209
- if (this.props.error && this.props.error.code === 301) {
210
- const redirect = flattenToAppURL(this.props.error.url).split('?')[0];
209
+ if ([301, 302].includes(this.props.error?.code)) {
210
+ const redirect = flattenToAppURL(this.props.error.url)
211
+ .split('?')[0]
212
+ .replace('/++api++', '');
211
213
  return <Redirect to={`${redirect}${this.props.location.search}`} />;
212
214
  } else if (this.props.error && !this.props.connectionRefused) {
213
215
  let FoundView;
@@ -235,7 +237,7 @@ class View extends Component {
235
237
  this.getViewByLayout() || this.getViewByType() || this.getViewDefault();
236
238
 
237
239
  return (
238
- <div id="view">
240
+ <div id="view" tabIndex="-1">
239
241
  <ContentMetadataTags content={this.props.content} />
240
242
  {/* Body class if displayName in component is set */}
241
243
  <BodyClass
@@ -22,6 +22,7 @@ beforeAll(() => {
22
22
  });
23
23
  config.settings.publicURL = 'https://plone.org';
24
24
  });
25
+ global.__SERVER__ = true; // eslint-disable-line no-underscore-dangle
25
26
 
26
27
  const mockStore = configureStore();
27
28
 
@@ -90,6 +90,13 @@ export const filterControlPanelsSchema = (controlpanel) => {
90
90
  'picture_variants',
91
91
  'image_captioning',
92
92
  ],
93
+ navigation: [
94
+ 'generate_tabs',
95
+ 'navigation_depth',
96
+ 'sort_tabs_on',
97
+ 'sort_tabs_reversed',
98
+ 'sitemap_depth',
99
+ ],
93
100
  };
94
101
 
95
102
  // Creates modified version of properties object
@@ -0,0 +1,232 @@
1
+ import config from '@plone/volto/registry';
2
+
3
+ const navigation_controlpanel = {
4
+ '@id': '/@controlpanels/navigation',
5
+ data: {
6
+ displayed_types: [
7
+ {
8
+ title: 'Link',
9
+ token: 'Link',
10
+ },
11
+ {
12
+ title: 'News Item',
13
+ token: 'News Item',
14
+ },
15
+ {
16
+ title: 'Folder',
17
+ token: 'Folder',
18
+ },
19
+ {
20
+ title: 'Page',
21
+ token: 'Document',
22
+ },
23
+ {
24
+ title: 'Event',
25
+ token: 'Event',
26
+ },
27
+ {
28
+ title: 'Collection',
29
+ token: 'Collection',
30
+ },
31
+ ],
32
+ filter_on_workflow: false,
33
+ generate_tabs: true,
34
+ navigation_depth: 3,
35
+ nonfolderish_tabs: true,
36
+ parent_types_not_to_query: ['TempFolder'],
37
+ root: '/',
38
+ show_excluded_items: false,
39
+ sitemap_depth: 3,
40
+ sort_tabs_on: {
41
+ title: 'Position in Parent',
42
+ token: 'getObjPositionInParent',
43
+ },
44
+ sort_tabs_reversed: false,
45
+ workflow_states_to_show: [],
46
+ },
47
+ group: 'General',
48
+ schema: {
49
+ fieldsets: [
50
+ {
51
+ behavior: 'plone',
52
+ fields: [
53
+ 'navigation_depth',
54
+ 'generate_tabs',
55
+ 'nonfolderish_tabs',
56
+ 'sort_tabs_on',
57
+ 'sort_tabs_reversed',
58
+ 'displayed_types',
59
+ 'filter_on_workflow',
60
+ 'workflow_states_to_show',
61
+ 'show_excluded_items',
62
+ 'root',
63
+ 'sitemap_depth',
64
+ 'parent_types_not_to_query',
65
+ ],
66
+ id: 'default',
67
+ title: 'Default',
68
+ },
69
+ ],
70
+ properties: {
71
+ displayed_types: {
72
+ additionalItems: true,
73
+ default: [
74
+ 'Link',
75
+ 'News Item',
76
+ 'Folder',
77
+ 'Document',
78
+ 'Event',
79
+ 'Collection',
80
+ ],
81
+ description:
82
+ 'The content types that should be shown in the navigation and site map.',
83
+ factory: 'Tuple',
84
+ items: {
85
+ description: '',
86
+ factory: 'Choice',
87
+ title: '',
88
+ type: 'string',
89
+ vocabulary: {
90
+ '@id':
91
+ 'http://localhost:3000/@vocabularies/plone.app.vocabularies.ReallyUserFriendlyTypes',
92
+ },
93
+ },
94
+ title: 'Displayed content types',
95
+ type: 'array',
96
+ uniqueItems: true,
97
+ },
98
+ filter_on_workflow: {
99
+ default: false,
100
+ description:
101
+ 'The workflow states that should be shown in the navigation and the site map.',
102
+ factory: 'Yes/No',
103
+ title: 'Filter on workflow state',
104
+ type: 'boolean',
105
+ },
106
+ generate_tabs: {
107
+ default: true,
108
+ description:
109
+ 'By default, all items created at the root level will appear as tabs. You can turn this off if you prefer manually constructing this part of the navigation.',
110
+ factory: 'Yes/No',
111
+ title: 'Automatically generate tabs',
112
+ type: 'boolean',
113
+ },
114
+ navigation_depth: {
115
+ default: 3,
116
+ description: 'Number of folder levels to show in the navigation.',
117
+ factory: 'Integer',
118
+ title: 'Navigation depth',
119
+ type: 'integer',
120
+ },
121
+ nonfolderish_tabs: {
122
+ default: true,
123
+ description:
124
+ "By default, any content item in the root of the portal will appear as a tab. If you turn this option off, only folders will be shown. This only has an effect if 'automatically generate tabs' is enabled.",
125
+ factory: 'Yes/No',
126
+ title: 'Generate tabs for items other than folders.',
127
+ type: 'boolean',
128
+ },
129
+ parent_types_not_to_query: {
130
+ additionalItems: true,
131
+ default: ['TempFolder'],
132
+ description: 'Hide content inside the following types in Navigation.',
133
+ factory: 'List',
134
+ items: {
135
+ description: '',
136
+ factory: 'Text line (String)',
137
+ title: '',
138
+ type: 'string',
139
+ },
140
+ title: 'Hide children of these types',
141
+ type: 'array',
142
+ uniqueItems: false,
143
+ },
144
+ root: {
145
+ default: '/',
146
+ description:
147
+ "Path to be used as navigation root, relative to Plone site root.Starts with '/'",
148
+ factory: 'Text line (String)',
149
+ title: 'Root',
150
+ type: 'string',
151
+ },
152
+ show_excluded_items: {
153
+ default: false,
154
+ description:
155
+ 'If an item has been excluded from navigation should it be shown in navigation when viewing content contained within it or within a subfolder.',
156
+ factory: 'Yes/No',
157
+ title:
158
+ 'Show items normally excluded from navigation if viewing their children.',
159
+ type: 'boolean',
160
+ },
161
+ sitemap_depth: {
162
+ default: 3,
163
+ description: 'Number of folder levels to show in the site map.',
164
+ factory: 'Integer',
165
+ title: 'Sitemap depth',
166
+ type: 'integer',
167
+ },
168
+ sort_tabs_on: {
169
+ choices: [
170
+ ['getObjPositionInParent', 'Position in Parent'],
171
+ ['sortable_title', 'Title'],
172
+ ['getId', 'Short Name (ID)'],
173
+ ],
174
+ default: 'getObjPositionInParent',
175
+ description: 'Index used to sort the tabs',
176
+ enum: ['getObjPositionInParent', 'sortable_title', 'getId'],
177
+ enumNames: ['Position in Parent', 'Title', 'Short Name (ID)'],
178
+ factory: 'Choice',
179
+ title: 'Sort tabs on',
180
+ type: 'string',
181
+ vocabulary: {
182
+ '@id': 'http://localhost:3000/@sources/sort_tabs_on',
183
+ },
184
+ },
185
+ sort_tabs_reversed: {
186
+ default: false,
187
+ description: 'Sort tabs in descending.',
188
+ factory: 'Yes/No',
189
+ title: 'Reversed sort order for tabs.',
190
+ type: 'boolean',
191
+ },
192
+ workflow_states_to_show: {
193
+ additionalItems: true,
194
+ default: [],
195
+ description: '',
196
+ factory: 'Tuple',
197
+ items: {
198
+ description: '',
199
+ factory: 'Choice',
200
+ title: '',
201
+ type: 'string',
202
+ vocabulary: {
203
+ '@id':
204
+ 'http://localhost:3000/@vocabularies/plone.app.vocabularies.WorkflowStates',
205
+ },
206
+ },
207
+ title: '',
208
+ type: 'array',
209
+ uniqueItems: true,
210
+ },
211
+ },
212
+ required: ['navigation_depth', 'sort_tabs_on', 'root', 'sitemap_depth'],
213
+ type: 'object',
214
+ },
215
+ title: 'Navigation',
216
+ };
217
+
218
+ test('test navigation controlpanel fields', () => {
219
+ const { filterControlPanelsSchema } = config.settings;
220
+ const result = filterControlPanelsSchema(navigation_controlpanel);
221
+ const not_in_navigation = [
222
+ 'generate_tabs',
223
+ 'navigation_depth',
224
+ 'sort_tabs_on',
225
+ 'sort_tabs_reversed',
226
+ 'sitemap_depth',
227
+ ];
228
+ const hasField = result['fieldsets'][0]['fields'].some((field) =>
229
+ not_in_navigation.includes(field),
230
+ );
231
+ expect(hasField).toBe(false);
232
+ });
@@ -18,7 +18,6 @@ const settings = {
18
18
  ],
19
19
  criticalCssPath: 'public/critical.css',
20
20
  readCriticalCss: null, // so it will be defaultReadCriticalCss
21
- extractScripts: { errorPages: false },
22
21
  staticFiles: [
23
22
  {
24
23
  id: 'root_static',
@@ -11,6 +11,7 @@ module.exports = {
11
11
  eu: 'Euskara',
12
12
  fi: 'Suomi',
13
13
  fr: 'Français',
14
+ hi: 'Hindi',
14
15
  it: 'Italiano',
15
16
  nl: 'Nederlands',
16
17
  ro: 'Română',
@@ -9,6 +9,7 @@ const HEADERS = [
9
9
  'content-type',
10
10
  'x-sendfile',
11
11
  'x-accel-redirect',
12
+ 'x-robots-tag',
12
13
  ];
13
14
 
14
15
  function filesMiddlewareFn(req, res, next) {
@@ -7,6 +7,7 @@ const HEADERS = [
7
7
  'cache-control',
8
8
  'x-sendfile',
9
9
  'x-accel-redirect',
10
+ 'x-robots-tag',
10
11
  ];
11
12
 
12
13
  function imageMiddlewareFn(req, res, next) {
@@ -1,28 +1,46 @@
1
1
  import express from 'express';
2
2
  import path from 'path';
3
+ import AddonConfigurationRegistry from '@plone/registry/src/addon-registry';
3
4
  import config from '@plone/volto/registry';
4
5
 
5
- const staticMiddlewareFn = express.static(
6
- process.env.BUILD_DIR
7
- ? path.join(process.env.BUILD_DIR, 'public')
8
- : process.env.RAZZLE_PUBLIC_DIR,
9
- {
10
- setHeaders: function (res, path) {
11
- const pathLib = require('path');
12
- const base = pathLib.resolve(process.env.RAZZLE_PUBLIC_DIR);
13
- const relpath = path.substr(base.length);
14
- config.settings.serverConfig.staticFiles.some((elem) => {
15
- if (relpath.match(elem.match)) {
16
- for (const name in elem.headers) {
17
- res.setHeader(name, elem.headers[name] || 'undefined');
18
- }
19
- return true;
6
+ const projectRootPath = path.resolve('.');
7
+ const registry = new AddonConfigurationRegistry(projectRootPath);
8
+
9
+ const staticDirectory = () => {
10
+ if (process.env.BUILD_DIR) {
11
+ return path.join(process.env.BUILD_DIR, 'public');
12
+ }
13
+ // Only for development, when Volto detects that it's working on itself (not an
14
+ // old fashioned Volto project), there are add-ons (so it's the new setup) then
15
+ // point to the public folder in the root of the setup, instead of the inner Volto
16
+ // public folder.
17
+ if (
18
+ process.env.NODE_ENV !== 'production' &&
19
+ !registry.isVoltoProject &&
20
+ registry.addonNames.length > 0
21
+ ) {
22
+ return path.join(projectRootPath, '../../../public');
23
+ }
24
+ // Is always set (Razzle does it)
25
+ return process.env.RAZZLE_PUBLIC_DIR;
26
+ };
27
+
28
+ const staticMiddlewareFn = express.static(staticDirectory(), {
29
+ setHeaders: function (res, path) {
30
+ const pathLib = require('path');
31
+ const base = pathLib.resolve(process.env.RAZZLE_PUBLIC_DIR);
32
+ const relpath = path.substr(base.length);
33
+ config.settings.serverConfig.staticFiles.some((elem) => {
34
+ if (relpath.match(elem.match)) {
35
+ for (const name in elem.headers) {
36
+ res.setHeader(name, elem.headers[name] || 'undefined');
20
37
  }
21
- return false;
22
- });
23
- },
38
+ return true;
39
+ }
40
+ return false;
41
+ });
24
42
  },
25
- );
43
+ });
26
44
 
27
45
  export default function staticsMiddleware() {
28
46
  const middleware = express.Router();
@@ -80,6 +80,10 @@ class Api {
80
80
 
81
81
  Object.keys(headers).forEach((key) => request.set(key, headers[key]));
82
82
 
83
+ if (__SERVER__ && checkUrl && ['get', 'head'].includes(method)) {
84
+ request.redirects(0);
85
+ }
86
+
83
87
  if (data) {
84
88
  request.send(data);
85
89
  }
@@ -104,6 +108,14 @@ class Api {
104
108
  url: request.xhr.responseURL,
105
109
  });
106
110
  }
111
+
112
+ if ([301, 302].includes(err?.status)) {
113
+ return reject({
114
+ code: err.status,
115
+ url: err.response.headers.location,
116
+ });
117
+ }
118
+
107
119
  return err ? reject(err) : resolve(response.body || response.text);
108
120
  });
109
121
  });
@@ -18,6 +18,7 @@ beforeAll(() => {
18
18
 
19
19
  const api = new Api();
20
20
  const { settings } = config;
21
+ global.__SERVER__ = true; // eslint-disable-line no-underscore-dangle
21
22
 
22
23
  test('get request', () => {});
23
24
 
@@ -24,6 +24,7 @@ beforeAll(() => {
24
24
 
25
25
  const api = new Api();
26
26
  const { settings } = config;
27
+ global.__SERVER__ = true; // eslint-disable-line no-underscore-dangle
27
28
 
28
29
  test('get request', () => {});
29
30
 
@@ -187,14 +187,12 @@ class Html extends Component {
187
187
  charSet="UTF-8"
188
188
  />
189
189
  {/* Add the crossorigin while in development */}
190
- {this.props.extractScripts !== false
191
- ? extractor.getScriptElements().map((elem) =>
192
- React.cloneElement(elem, {
193
- crossOrigin:
194
- process.env.NODE_ENV === 'production' ? undefined : 'true',
195
- }),
196
- )
197
- : ''}
190
+ {extractor.getScriptElements().map((elem) =>
191
+ React.cloneElement(elem, {
192
+ crossOrigin:
193
+ process.env.NODE_ENV === 'production' ? undefined : 'true',
194
+ }),
195
+ )}
198
196
  </body>
199
197
  </html>
200
198
  );
@@ -1,12 +1,19 @@
1
- import type { Content } from '@plone/types';
2
1
  import { matchPath } from 'react-router-dom';
2
+ import type { Content } from '@plone/types';
3
+ import type { Location } from 'history';
3
4
 
4
5
  export function RouteCondition(path: string, exact?: boolean) {
5
- return ({ pathname }: { pathname: string }) =>
6
- Boolean(matchPath(pathname, { path, exact }));
6
+ return ({ location }: { location: Location }) =>
7
+ Boolean(matchPath(location.pathname, { path, exact }));
7
8
  }
8
9
 
9
10
  export function ContentTypeCondition(contentType: string[]) {
10
- return ({ content }: { content: Content }) =>
11
- contentType.includes(content?.['@type']);
11
+ return ({ content, location }: { content: Content; location: Location }) => {
12
+ return (
13
+ contentType.includes(content?.['@type']) ||
14
+ contentType.some((type) => {
15
+ return location.search.includes(`type=${encodeURIComponent(type)}`);
16
+ })
17
+ );
18
+ };
12
19
  }
package/src/server.jsx CHANGED
@@ -272,50 +272,48 @@ server.get('/*', (req, res) => {
272
272
  });
273
273
  }
274
274
 
275
+ const sendHtmlResponse = (
276
+ res,
277
+ statusCode,
278
+ extractor,
279
+ markup,
280
+ store,
281
+ req,
282
+ config,
283
+ ) => {
284
+ res.status(statusCode).send(
285
+ `<!doctype html>
286
+ ${renderToString(
287
+ <Html
288
+ extractor={extractor}
289
+ markup={markup}
290
+ store={store}
291
+ criticalCss={readCriticalCss(req)}
292
+ apiPath={res.locals.detectedHost || config.settings.apiPath}
293
+ publicURL={res.locals.detectedHost || config.settings.publicURL}
294
+ />,
295
+ )}
296
+ `,
297
+ );
298
+ };
299
+
275
300
  if (context.url) {
276
301
  res.redirect(flattenToAppURL(context.url));
277
302
  } else if (context.error_code) {
278
303
  res.set({
279
304
  'Cache-Control': 'no-cache',
280
305
  });
281
-
282
- res.status(context.error_code).send(
283
- `<!doctype html>
284
- ${renderToString(
285
- <Html
286
- extractor={extractor}
287
- markup={markup}
288
- store={store}
289
- extractScripts={
290
- config.settings.serverConfig.extractScripts?.errorPages ||
291
- process.env.NODE_ENV !== 'production'
292
- }
293
- criticalCss={readCriticalCss(req)}
294
- apiPath={res.locals.detectedHost || config.settings.apiPath}
295
- publicURL={
296
- res.locals.detectedHost || config.settings.publicURL
297
- }
298
- />,
299
- )}
300
- `,
306
+ sendHtmlResponse(
307
+ res,
308
+ context.error_code,
309
+ extractor,
310
+ markup,
311
+ store,
312
+ req,
313
+ config,
301
314
  );
302
315
  } else {
303
- res.status(200).send(
304
- `<!doctype html>
305
- ${renderToString(
306
- <Html
307
- extractor={extractor}
308
- markup={markup}
309
- store={store}
310
- criticalCss={readCriticalCss(req)}
311
- apiPath={res.locals.detectedHost || config.settings.apiPath}
312
- publicURL={
313
- res.locals.detectedHost || config.settings.publicURL
314
- }
315
- />,
316
- )}
317
- `,
318
- );
316
+ sendHtmlResponse(res, 200, extractor, markup, store, req, config);
319
317
  }
320
318
  }, errorHandler)
321
319
  .catch(errorHandler);
@@ -318,6 +318,16 @@ body.has-toolbar.has-sidebar-collapsed .ui.wrapper > .ui.inner.block.full {
318
318
  0 2px 4px rgba(0, 0, 0, 0.05);
319
319
  transform: translate(-50%, 0);
320
320
 
321
+ .separator {
322
+ position: relative;
323
+ top: 5px;
324
+ display: inline-block;
325
+ height: 24px;
326
+ border-right: 1px solid #ddd;
327
+ margin: 0 0 4px 4px;
328
+ vertical-align: bottom;
329
+ }
330
+
321
331
  form {
322
332
  display: flex;
323
333
  }
@@ -591,16 +601,6 @@ body.has-toolbar.has-sidebar-collapsed .ui.wrapper > .ui.inner.block.full {
591
601
  height: 100%;
592
602
  }
593
603
 
594
- .separator {
595
- position: relative;
596
- top: 5px;
597
- display: inline-block;
598
- height: 24px;
599
- border-right: 1px solid #ddd;
600
- margin: 0 0 4px 4px;
601
- vertical-align: bottom;
602
- }
603
-
604
604
  // HTML block
605
605
  .html-editor {
606
606
  z-index: 1;
@@ -41,3 +41,86 @@
41
41
  border: none !important;
42
42
  }
43
43
  }
44
+
45
+ .object-browser {
46
+ .mode-switch {
47
+ margin-right: 8px;
48
+ cursor: pointer;
49
+ float: right;
50
+ }
51
+
52
+ header h2 {
53
+ margin: 2px 0 !important;
54
+ }
55
+
56
+ .searchResults {
57
+ margin-left: 20px;
58
+ font-size: 14px;
59
+ -webkit-font-smoothing: antialiased;
60
+ -moz-osx-font-smoothing: grayscale;
61
+ line-height: 1.5;
62
+ text-rendering: optimizeLegibility;
63
+ text-size-adjust: 100%;
64
+ }
65
+
66
+ ul.object-listing {
67
+ padding: 0;
68
+ }
69
+
70
+ .image-wrapper {
71
+ display: block;
72
+ margin: 16px;
73
+ float: left;
74
+
75
+ img,
76
+ .icon-wrapper {
77
+ background-color: #edf1f2;
78
+ cursor: pointer;
79
+ outline: 0;
80
+ }
81
+
82
+ .selected {
83
+ outline: solid 3px #517776 !important;
84
+ }
85
+
86
+ img:hover,
87
+ .icon-wrapper:hover {
88
+ outline: solid 3px rgb(187, 198, 200);
89
+ }
90
+
91
+ .image-preview,
92
+ .image-preview:hover {
93
+ display: flex;
94
+ border: 0;
95
+ border-radius: 0;
96
+ box-shadow: none;
97
+
98
+ img {
99
+ width: 200px;
100
+ height: 200px;
101
+ object-fit: contain;
102
+ }
103
+ }
104
+
105
+ .image-preview,
106
+ .image-title {
107
+ cursor: pointer;
108
+ text-align: center;
109
+ }
110
+
111
+ .image-title {
112
+ margin-top: 5px;
113
+ }
114
+
115
+ .image-title-content {
116
+ overflow: hidden;
117
+ text-overflow: ellipsis;
118
+ white-space: nowrap;
119
+ }
120
+
121
+ .icon-wrapper {
122
+ display: flex;
123
+ padding: 46px;
124
+ }
125
+ }
126
+ }