@eeacms/volto-clms-theme 1.1.39 → 1.1.40

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.
package/CHANGELOG.md CHANGED
@@ -4,7 +4,24 @@ All notable changes to this project will be documented in this file. Dates are d
4
4
 
5
5
  Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
6
6
 
7
- ### [1.1.39](https://github.com/eea/volto-clms-theme/compare/1.1.38...1.1.39) - 11 September 2023
7
+ ### [1.1.40](https://github.com/eea/volto-clms-theme/compare/1.1.39...1.1.40) - 14 September 2023
8
+
9
+ #### :rocket: New Features
10
+
11
+ - feat: cart addition modal text modifications [Ion Lizarazu - [`bf93cf5`](https://github.com/eea/volto-clms-theme/commit/bf93cf5f336cc1e905dd444b17799bd2841b1c38)]
12
+
13
+ #### :bug: Bug Fixes
14
+
15
+ - fix: useCase card style [Ion Lizarazu - [`6ac7e36`](https://github.com/eea/volto-clms-theme/commit/6ac7e360066b9f55614b59ea4a102a150c7f00ba)]
16
+
17
+ #### :hammer_and_wrench: Others
18
+
19
+ - s/CLMS portal/CLMS website [Mikel Larreategi - [`76a17d7`](https://github.com/eea/volto-clms-theme/commit/76a17d7f2ffca88c8841a85315bbac8d8324af0c)]
20
+ - remove warnings [Ion Lizarazu - [`531db38`](https://github.com/eea/volto-clms-theme/commit/531db382e69cef045486d0067788307abf10a8e4)]
21
+ - jest tests [Ion Lizarazu - [`b5e7409`](https://github.com/eea/volto-clms-theme/commit/b5e7409a24e80cebcfed79b467af437cde70f023)]
22
+ - add test [Ion Lizarazu - [`ab76914`](https://github.com/eea/volto-clms-theme/commit/ab76914e901ce9e31faa5f32762f3e13cd157dae)]
23
+ - mv CartIconCounter [Ion Lizarazu - [`8fa987f`](https://github.com/eea/volto-clms-theme/commit/8fa987fdf652912233eab4e78ec17a30a662ab73)]
24
+ ### [1.1.39](https://github.com/eea/volto-clms-theme/compare/1.1.38...1.1.39) - 12 September 2023
8
25
 
9
26
  #### :hammer_and_wrench: Others
10
27
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-clms-theme",
3
- "version": "1.1.39",
3
+ "version": "1.1.40",
4
4
  "description": "volto-clms-theme: Volto theme for CLMS site",
5
5
  "main": "src/index.js",
6
6
  "author": "CodeSyntax for the European Environment Agency",
@@ -13,8 +13,6 @@ import {
13
13
  getDatasetsByUid,
14
14
  getExtraBreadcrumbItems,
15
15
  getNutsNames,
16
- } from '../../actions';
17
- import {
18
16
  getFormatConversionTable,
19
17
  getProjections,
20
18
  getDatasetTimeseries,
@@ -1,5 +1,5 @@
1
1
  export const getAvailableConversion = (conversionTable, defaultValue) => {
2
- if (conversionTable) {
2
+ if (conversionTable && Object.keys(conversionTable).length > 0) {
3
3
  if (
4
4
  conversionTable[defaultValue] === undefined ||
5
5
  conversionTable[defaultValue] === null
@@ -46,7 +46,7 @@ const messages = defineMessages({
46
46
  description: {
47
47
  id: 'descripton',
48
48
  defaultMessage:
49
- 'API tokens are used for machine-to-machine communication with the CLMS portal API. You need to create a new API token for each application in wich you need to use the CLMS portal API. In this screen you can create a new API token, check the list of your tokens and also delete those tokens.',
49
+ 'API tokens are used for machine-to-machine communication with the CLMS website API. You need to create a new API token for each application in wich you need to use the CLMS website API. In this screen you can create a new API token, check the list of your tokens and also delete those tokens.',
50
50
  },
51
51
  createTitle: {
52
52
  id: 'create title',
@@ -89,7 +89,7 @@ export const CLMSDeleteProfileView = (props) => {
89
89
  />
90
90
  </h1>
91
91
  This action will delete your profile and your subscription
92
- settings from the CLMS portal.
92
+ settings from the CLMS website.
93
93
  <br />
94
94
  <br />
95
95
  </div>
@@ -0,0 +1,190 @@
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import { Icon } from '@plone/volto/components';
3
+ import { useDispatch, useSelector } from 'react-redux';
4
+ import { Popup, Segment, Divider, Message } from 'semantic-ui-react';
5
+ import CclButton from '@eeacms/volto-clms-theme/components/CclButton/CclButton';
6
+ import clearSVG from '@plone/volto/icons/clear.svg';
7
+ import {
8
+ getDatasetTimeseries,
9
+ getNutsNames,
10
+ getDatasetsByUid,
11
+ } from '@eeacms/volto-clms-theme/actions';
12
+ import { getCartItems } from '@eeacms/volto-clms-utils/actions';
13
+ import { Link } from 'react-router-dom';
14
+ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
15
+
16
+ export const onlyInLeft = (left, right, compareFunction) =>
17
+ left.filter(
18
+ (leftValue) =>
19
+ !right.some((rightValue) => compareFunction(leftValue, rightValue)),
20
+ );
21
+
22
+ export const CartIconCounter = () => {
23
+ const datasetTimeseries = useSelector((state) => state.datasetTimeseries);
24
+ const nutsnames = useSelector((state) => state.nutsnames);
25
+ const datasetsByUid = useSelector((state) => state.datasetsByUid);
26
+ const cartState = useSelector((state) => state.cart_items);
27
+ const cartState_ref = useRef(cartState);
28
+ const cart_icon_ref = React.useRef();
29
+ const intl = useSelector((state) => state.intl);
30
+ const user_id = useSelector((state) => state.users.user.id);
31
+ const [showPopup, setshowPopup] = useState(false);
32
+ const [cartDiff, setCartDiff] = useState(0);
33
+ const [cartDiffItems, setCartDiffItems] = useState([]);
34
+ const [hasTimeseries, setHasTimeseries] = useState(false);
35
+ const dispatch = useDispatch();
36
+ useEffect(() => {
37
+ dispatch(getCartItems(user_id));
38
+ // eslint-disable-next-line react-hooks/exhaustive-deps
39
+ }, [user_id]);
40
+
41
+ useEffect(() => {
42
+ cartDiffItems.forEach((newItem) => {
43
+ if (
44
+ !datasetTimeseries.loading &&
45
+ datasetTimeseries?.datasets[newItem.UID] === undefined
46
+ ) {
47
+ dispatch(getDatasetTimeseries(newItem.UID));
48
+ }
49
+ if (newItem.area?.type) {
50
+ dispatch(getNutsNames(newItem.area?.value));
51
+ dispatch(getDatasetsByUid(newItem.UID));
52
+ }
53
+ });
54
+ return () => {};
55
+ // eslint-disable-next-line react-hooks/exhaustive-deps
56
+ }, [cartDiffItems]);
57
+
58
+ useEffect(() => {
59
+ let hasTS = false;
60
+ if (datasetTimeseries.datasets) {
61
+ cartDiffItems.forEach((diffItem) => {
62
+ if (
63
+ datasetTimeseries.datasets[diffItem.UID] &&
64
+ datasetTimeseries.datasets[diffItem.UID].start
65
+ ) {
66
+ hasTS = true;
67
+ }
68
+ });
69
+ }
70
+ setHasTimeseries(hasTS);
71
+
72
+ return () => {};
73
+ // eslint-disable-next-line react-hooks/exhaustive-deps
74
+ }, [datasetTimeseries.datasets, datasetTimeseries.loaded, cartDiffItems]);
75
+
76
+ useEffect(() => {
77
+ if (
78
+ cartState_ref.current.set.loading &&
79
+ cartState.set.loaded &&
80
+ cartState.items.length >= cartState_ref.current.items.length
81
+ ) {
82
+ setCartDiff(cartState.items.length - cartState_ref.current.items.length);
83
+ setCartDiffItems(
84
+ onlyInLeft(
85
+ cartState.items,
86
+ cartState_ref.current.items,
87
+ (l, r) => l.unique_id === r.unique_id,
88
+ ),
89
+ );
90
+
91
+ window.scrollTo({
92
+ top: 0,
93
+ left: 0,
94
+ behavior: 'smooth',
95
+ });
96
+ !showPopup && setTimeout(() => setshowPopup(true), 900);
97
+ setTimeout(() => {
98
+ setshowPopup(false);
99
+ }, 11000);
100
+ }
101
+ cartState_ref.current = cartState;
102
+ // eslint-disable-next-line react-hooks/exhaustive-deps
103
+ }, [cartState]);
104
+ return (
105
+ cartState.items && (
106
+ <>
107
+ <Popup
108
+ context={cart_icon_ref}
109
+ open={showPopup}
110
+ position="bottom center"
111
+ flowing
112
+ >
113
+ <Segment
114
+ attached="top"
115
+ style={{ padding: 0, display: 'flex', justifyContent: 'flex-end' }}
116
+ >
117
+ <Icon
118
+ onClick={() => setshowPopup(false)}
119
+ name={clearSVG}
120
+ size={20}
121
+ style={{ cursor: 'pointer' }}
122
+ />
123
+ </Segment>
124
+ <Divider horizontal style={{ margin: 0 }}>
125
+ My cart
126
+ </Divider>
127
+ {cartDiff > 0 ? (
128
+ <Message positive>
129
+ {cartDiffItems.some((cdi) => cdi.area === '') && (
130
+ <p>
131
+ You added{' '}
132
+ <strong>
133
+ {cartDiff} new prepackaged item{cartDiff > 1 ? 's' : ''}
134
+ </strong>{' '}
135
+ to the cart.
136
+ </p>
137
+ )}
138
+ {datasetsByUid.loaded &&
139
+ nutsnames.loaded &&
140
+ cartDiffItems.map((cdi, key) => {
141
+ const ddata = datasetsByUid.loaded
142
+ ? datasetsByUid?.datasets?.items.find(
143
+ (d) => d.UID === cdi.UID,
144
+ )
145
+ : {};
146
+ return (
147
+ <p key={key}>
148
+ <strong>Name:</strong> {ddata?.title} <br />
149
+ <strong>Area:</strong>{' '}
150
+ {nutsnames?.nutsnames?.[cdi?.area?.value]}
151
+ </p>
152
+ );
153
+ })}
154
+ {hasTimeseries && (
155
+ <>
156
+ <br />
157
+ Click on Go to cart to select time interval.
158
+ </>
159
+ )}
160
+ </Message>
161
+ ) : (
162
+ <Message warning>
163
+ The items you tried to add were already added
164
+ </Message>
165
+ )}
166
+ <CclButton
167
+ mode="filled"
168
+ to={`/${intl.locale}/cart`}
169
+ style={{ width: '100%' }}
170
+ >
171
+ Go to cart
172
+ </CclButton>
173
+ </Popup>
174
+ <Link
175
+ to={`/${intl.locale}/cart`}
176
+ className="header-login-link"
177
+ ref={cart_icon_ref}
178
+ >
179
+ <FontAwesomeIcon
180
+ icon={['fas', 'shopping-cart']}
181
+ style={{ marginRight: '0.25rem', maxWidth: '1.5rem' }}
182
+ />
183
+ <strong>{cartState?.items?.length}</strong>
184
+ </Link>
185
+ </>
186
+ )
187
+ );
188
+ };
189
+
190
+ export default CartIconCounter;
@@ -0,0 +1,141 @@
1
+ import { onlyInLeft, CartIconCounter } from './CartIconCounter';
2
+ import Enzyme from 'enzyme';
3
+ import Adapter from 'enzyme-adapter-react-16';
4
+ import renderer from 'react-test-renderer';
5
+ import { MemoryRouter } from 'react-router-dom';
6
+ import { Provider } from 'react-intl-redux';
7
+ import configureStore from 'redux-mock-store';
8
+ Enzyme.configure({ adapter: new Adapter() });
9
+
10
+ describe('onlyInLeft', () => {
11
+ // Returns an array with items that are only in the left array, based on a compare function
12
+ it('should return an array with items that are only in the left array', () => {
13
+ const left = [
14
+ { id: 1, name: 'Item 1' },
15
+ { id: 2, name: 'Item 2' },
16
+ { id: 3, name: 'Item 3' },
17
+ ];
18
+ const right = [
19
+ { id: 2, name: 'Item 2' },
20
+ { id: 4, name: 'Item 4' },
21
+ ];
22
+ const compareFunction = (leftValue, rightValue) =>
23
+ leftValue.id === rightValue.id;
24
+
25
+ const result = onlyInLeft(left, right, compareFunction);
26
+
27
+ expect(result).toEqual([
28
+ { id: 1, name: 'Item 1' },
29
+ { id: 3, name: 'Item 3' },
30
+ ]);
31
+ });
32
+ // Should return an array with items that are only in the left array, based on a compare function
33
+ it('should return an array with items that are only in the left array', () => {
34
+ const left = [
35
+ { id: 1, name: 'Item 1' },
36
+ { id: 2, name: 'Item 2' },
37
+ { id: 3, name: 'Item 3' },
38
+ ];
39
+ const right = [
40
+ { id: 2, name: 'Item 2' },
41
+ { id: 4, name: 'Item 4' },
42
+ ];
43
+ const compareFunction = (leftValue, rightValue) =>
44
+ leftValue.id === rightValue.id;
45
+
46
+ const result = onlyInLeft(left, right, compareFunction);
47
+
48
+ expect(result).toEqual([
49
+ { id: 1, name: 'Item 1' },
50
+ { id: 3, name: 'Item 3' },
51
+ ]);
52
+ });
53
+ // should return an empty array if left array is empty
54
+ it('should return an empty array when left array is empty', () => {
55
+ const left = [];
56
+ const right = [
57
+ { id: 2, name: 'Item 2' },
58
+ { id: 4, name: 'Item 4' },
59
+ ];
60
+ const compareFunction = (leftValue, rightValue) =>
61
+ leftValue.id === rightValue.id;
62
+
63
+ const result = onlyInLeft(left, right, compareFunction);
64
+
65
+ expect(result).toEqual([]);
66
+ });
67
+
68
+ // should return the left array if right array is empty
69
+ it('should return the left array when the right array is empty', () => {
70
+ const left = [
71
+ { id: 1, name: 'Item 1' },
72
+ { id: 2, name: 'Item 2' },
73
+ { id: 3, name: 'Item 3' },
74
+ ];
75
+ const right = [];
76
+ const compareFunction = (leftValue, rightValue) =>
77
+ leftValue.id === rightValue.id;
78
+
79
+ const result = onlyInLeft(left, right, compareFunction);
80
+
81
+ expect(result).toEqual(left);
82
+ });
83
+ // should return an array with items that are only in the left array
84
+ it('should return an array with items that are only in the left array', () => {
85
+ const left = [
86
+ { id: 1, name: 'Item 1' },
87
+ { id: 2, name: 'Item 2' },
88
+ { id: 3, name: 'Item 3' },
89
+ ];
90
+ const right = [
91
+ { id: 2, name: 'Item 2' },
92
+ { id: 4, name: 'Item 4' },
93
+ ];
94
+ const compareFunction = (leftValue, rightValue) =>
95
+ leftValue.id === rightValue.id;
96
+
97
+ const result = onlyInLeft(left, right, compareFunction);
98
+
99
+ expect(result).toEqual([
100
+ { id: 1, name: 'Item 1' },
101
+ { id: 3, name: 'Item 3' },
102
+ ]);
103
+ });
104
+ });
105
+
106
+ const mockStore = configureStore();
107
+ describe('CartIconCounter', () => {
108
+ // Cart icon displays number of items in cart
109
+ it('should display the correct number of items in the cart', () => {
110
+ const store = mockStore({
111
+ cart_items: {
112
+ items: ['one', 'two', 'three'],
113
+ },
114
+ users: {
115
+ user: {
116
+ id: 'g678gfd678',
117
+ },
118
+ },
119
+ datasetTimeseries: {
120
+ datasets: [],
121
+ },
122
+ intl: {
123
+ locale: 'en',
124
+ messages: {},
125
+ },
126
+ });
127
+ // Render the component
128
+ const component = renderer.create(
129
+ <Provider store={store}>
130
+ <MemoryRouter>
131
+ <CartIconCounter />
132
+ </MemoryRouter>
133
+ </Provider>,
134
+ );
135
+ // const component = mount(<CartIconCounter />);
136
+
137
+ // Expect the component toBeDefined
138
+ expect(component).toBeDefined();
139
+ expect(component.toJSON().children[0].children[0]).toEqual('3');
140
+ });
141
+ });
@@ -6,12 +6,9 @@
6
6
  */
7
7
 
8
8
  import { FormattedMessage, injectIntl } from 'react-intl';
9
- import { Logo, Navigation, SearchWidget, Icon } from '@plone/volto/components';
10
- import React, { Component, useEffect, useRef, useState } from 'react';
11
- import { connect, useDispatch, useSelector } from 'react-redux';
12
- import { Popup, Segment, Divider, Message } from 'semantic-ui-react';
13
- import CclButton from '@eeacms/volto-clms-theme/components/CclButton/CclButton';
14
- import clearSVG from '@plone/volto/icons/clear.svg';
9
+ import { Logo, Navigation, SearchWidget } from '@plone/volto/components';
10
+ import React, { Component } from 'react';
11
+ import { connect, useSelector } from 'react-redux';
15
12
 
16
13
  import { BodyClass } from '@plone/volto/helpers';
17
14
  // IMPORT isnt nedded until translations are created
@@ -26,91 +23,7 @@ import { getCartItems } from '@eeacms/volto-clms-utils/actions';
26
23
  import { getUser } from '@plone/volto/actions';
27
24
  import jwtDecode from 'jwt-decode';
28
25
 
29
- const CartIconCounter = (props) => {
30
- const cartState = useSelector((state) => state.cart_items);
31
- const cartState_ref = useRef(cartState);
32
- const cart_icon_ref = React.useRef();
33
- const intl = useSelector((state) => state.intl);
34
- const user_id = useSelector((state) => state.users.user.id);
35
- const [showPopup, setshowPopup] = useState(false);
36
- const [cartDiff, setCartDiff] = useState(0);
37
- const dispatch = useDispatch();
38
- useEffect(() => {
39
- dispatch(getCartItems(user_id));
40
- // eslint-disable-next-line react-hooks/exhaustive-deps
41
- }, [user_id]);
42
- useEffect(() => {
43
- if (
44
- cartState_ref.current.set.loading &&
45
- cartState.set.loaded &&
46
- cartState.items.length >= cartState_ref.current.items.length
47
- ) {
48
- setCartDiff(cartState.items.length - cartState_ref.current.items.length);
49
- window.scrollTo({
50
- top: 0,
51
- left: 0,
52
- behavior: 'smooth',
53
- });
54
- !showPopup && setTimeout(() => setshowPopup(true), 900);
55
- setTimeout(() => setshowPopup(false), 11000);
56
- }
57
- cartState_ref.current = cartState;
58
- // eslint-disable-next-line react-hooks/exhaustive-deps
59
- }, [cartState]);
60
- return (
61
- cartState.items && (
62
- <>
63
- <Popup
64
- context={cart_icon_ref}
65
- open={showPopup}
66
- position="bottom center"
67
- >
68
- <Segment
69
- attached="top"
70
- style={{ padding: 0, display: 'flex', justifyContent: 'flex-end' }}
71
- >
72
- <Icon
73
- onClick={() => setshowPopup(false)}
74
- name={clearSVG}
75
- size={20}
76
- style={{ cursor: 'pointer' }}
77
- />
78
- </Segment>
79
- <Divider horizontal style={{ margin: 0 }}>
80
- My cart
81
- </Divider>
82
- {cartDiff > 0 ? (
83
- <Message positive>
84
- You added <strong>{cartDiff} new items</strong> to the cart
85
- </Message>
86
- ) : (
87
- <Message warning>
88
- The items you tried to add were already added
89
- </Message>
90
- )}
91
- <CclButton
92
- mode="filled"
93
- to={`/${intl.locale}/cart`}
94
- style={{ width: '100%' }}
95
- >
96
- Go to cart
97
- </CclButton>
98
- </Popup>
99
- <Link
100
- to={`/${intl.locale}/cart`}
101
- className="header-login-link"
102
- ref={cart_icon_ref}
103
- >
104
- <FontAwesomeIcon
105
- icon={['fas', 'shopping-cart']}
106
- style={{ marginRight: '0.25rem', maxWidth: '1.5rem' }}
107
- />
108
- <strong>{cartState?.items?.length}</strong>
109
- </Link>
110
- </>
111
- )
112
- );
113
- };
26
+ import CartIconCounter from '@eeacms/volto-clms-theme/components/CartIconCounter/CartIconCounter';
114
27
 
115
28
  const HeaderDropdown = ({ user }) => {
116
29
  const intl = useSelector((state) => state.intl);
@@ -0,0 +1,3 @@
1
+ @listingCardPadding: 0;
2
+ @imageMinWidth: 400px;
3
+ @imageMaxHeight: 335px;
@@ -27,18 +27,18 @@ hr {
27
27
  }
28
28
 
29
29
  hr
30
- + body:not(.contenttype-lrf:not(.section-cart):not(.section-profile):not(.section-newsletter-notification-subscription):not(.section-newsletter-notification-unsubscription):not(.section-logout))
31
- main {
30
+ + body:not(.contenttype-lrf:not(.section-cart):not(.section-profile):not(.section-newsletter-notification-subscription):not(.section-newsletter-notification-unsubscription):not(.section-logout))
31
+ main {
32
32
  margin-bottom: 2rem;
33
33
  }
34
34
 
35
35
  body:not(.contenttype-lrf:not(.section-cart):not(.section-profile):not(.section-newsletter-notification-subscription):not(.section-newsletter-notification-unsubscription):not(.section-logout))
36
- main:not(.map-main) {
36
+ main:not(.map-main) {
37
37
  min-height: 70vh;
38
38
  }
39
39
 
40
40
  .map-body:not(.contenttype-lrf:not(.section-cart):not(.section-profile):not(.section-newsletter-notification-subscription):not(.section-newsletter-notification-unsubscription):not(.section-logout))
41
- main {
41
+ main {
42
42
  margin-bottom: 0;
43
43
  }
44
44
 
@@ -169,77 +169,77 @@ body.contenttype-lrf:not(.section-cart):not(.profilecart) main .ccl-container {
169
169
  }
170
170
 
171
171
  body:not(.contenttype-lrf:not(.section-cart):not(.section-profile))
172
- main
173
- .ccl-container {
172
+ main
173
+ .ccl-container {
174
174
  max-width: 100%;
175
175
  padding: 0;
176
176
  }
177
177
 
178
178
  body:not(.contenttype-lrf:not(.section-cart):not(.section-profile))
179
- main
180
- .ccl-container
181
- .cont-w-25 {
179
+ main
180
+ .ccl-container
181
+ .cont-w-25 {
182
182
  max-width: 100%;
183
183
  flex: 0 0 100%;
184
184
  }
185
185
 
186
186
  body:not(.contenttype-lrf:not(.section-cart):not(.section-profile))
187
- main
188
- .ccl-container
189
- .cont-w-50 {
187
+ main
188
+ .ccl-container
189
+ .cont-w-50 {
190
190
  max-width: 100%;
191
191
  flex: 0 0 100%;
192
192
  }
193
193
 
194
194
  body:not(.contenttype-lrf:not(.section-cart):not(.section-profile))
195
- main
196
- .ccl-container
197
- .cont-w-75 {
195
+ main
196
+ .ccl-container
197
+ .cont-w-75 {
198
198
  max-width: 100%;
199
199
  flex: 0 0 100%;
200
200
  }
201
201
  @media (min-width: 576px) {
202
202
  body:not(.contenttype-lrf:not(.section-cart):not(.section-profile))
203
- main
204
- .ccl-container {
203
+ main
204
+ .ccl-container {
205
205
  max-width: 540px;
206
206
  }
207
207
  }
208
208
  @media (min-width: 768px) {
209
209
  body:not(.contenttype-lrf:not(.section-cart):not(.section-profile))
210
- main
211
- .ccl-container {
210
+ main
211
+ .ccl-container {
212
212
  max-width: 720px;
213
213
  }
214
214
 
215
215
  body:not(.contenttype-lrf:not(.section-cart):not(.section-profile))
216
- main
217
- .ccl-container
218
- .cont-w-25 {
216
+ main
217
+ .ccl-container
218
+ .cont-w-25 {
219
219
  max-width: 30%;
220
220
  flex: 0 0 30%;
221
221
  }
222
222
 
223
223
  body:not(.contenttype-lrf:not(.section-cart):not(.section-profile))
224
- main
225
- .ccl-container
226
- .cont-w-50 {
224
+ main
225
+ .ccl-container
226
+ .cont-w-50 {
227
227
  max-width: 50%;
228
228
  flex: 0 0 50%;
229
229
  }
230
230
 
231
231
  body:not(.contenttype-lrf:not(.section-cart):not(.section-profile))
232
- main
233
- .ccl-container
234
- .cont-w-75 {
232
+ main
233
+ .ccl-container
234
+ .cont-w-75 {
235
235
  max-width: 70%;
236
236
  flex: 0 0 70%;
237
237
  }
238
238
 
239
239
  body:not(.contenttype-lrf:not(.section-cart):not(.section-profile))
240
- main
241
- .ccl-container
242
- .cont-o-1 {
240
+ main
241
+ .ccl-container
242
+ .cont-o-1 {
243
243
  order: 1;
244
244
  }
245
245
 
@@ -253,30 +253,30 @@ body:not(.contenttype-lrf:not(.section-cart):not(.section-profile))
253
253
  }
254
254
  @media (min-width: 992px) {
255
255
  body:not(.contenttype-lrf:not(.section-cart):not(.section-profile))
256
- main
257
- .ccl-container {
256
+ main
257
+ .ccl-container {
258
258
  max-width: 960px;
259
259
  }
260
260
  }
261
261
  @media (min-width: 1200px) {
262
262
  body:not(.contenttype-lrf:not(.section-cart):not(.section-profile))
263
- main
264
- .ccl-container {
263
+ main
264
+ .ccl-container {
265
265
  max-width: 1127px;
266
266
  }
267
267
 
268
268
  body:not(.contenttype-lrf:not(.section-cart):not(.section-profile))
269
- main
270
- .ccl-container
271
- .cont-w-25 {
269
+ main
270
+ .ccl-container
271
+ .cont-w-25 {
272
272
  max-width: 25%;
273
273
  flex: 0 0 25%;
274
274
  }
275
275
 
276
276
  body:not(.contenttype-lrf:not(.section-cart):not(.section-profile))
277
- main
278
- .ccl-container
279
- .cont-w-75 {
277
+ main
278
+ .ccl-container
279
+ .cont-w-75 {
280
280
  max-width: 75%;
281
281
  flex: 0 0 75%;
282
282
  }
@@ -705,6 +705,23 @@ body:not(.contenttype-lrf:not(.section-cart):not(.section-profile))
705
705
  margin: 0 auto !important;
706
706
  }
707
707
 
708
+ .ui.fluid.card.u-card .extra.content a.ui.button {
709
+ display: inline-block;
710
+ padding: 0.3rem 1rem;
711
+ margin: 0;
712
+ appearance: none;
713
+ background: none;
714
+ color: @clmsGreen;
715
+ color: #a0b128;
716
+ cursor: pointer;
717
+ font-size: 0.85rem;
718
+ line-height: 1.5;
719
+ text-align: center;
720
+ text-decoration: none;
721
+ transition: all 0.3s ease-out;
722
+ vertical-align: middle;
723
+ }
724
+
708
725
  /* Search */
709
726
  .search-results {
710
727
  margin-bottom: 2rem;