Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Workshops
Developer workshop
Commits
5d21477c
Commit
5d21477c
authored
Feb 27, 2020
by
Jon Moore
Browse files
Implemented skeleton event listing page
parent
3c320a02
Changes
9
Hide whitespace changes
Inline
Side-by-side
src/app/core/routes/StaticRoutes.js
View file @
5d21477c
...
...
@@ -34,6 +34,14 @@ export default [
loading
:
Loading
,
}),
},
{
path
:
'
/events-listing
'
,
exact
:
true
,
component
:
Loadable
({
loader
:
()
=>
import
(
'
~/pages/Listings/EventListing.page
'
),
loading
:
Loading
,
}),
},
// ˄˄ Do not delete these routes ˄˄
// ********************************
// {
...
...
src/app/features/events/components.styled/EventCard.styled.js
0 → 100644
View file @
5d21477c
import
styled
from
'
styled-components
'
;
const
EventCardStyled
=
styled
.
div
`
background-color: #fff;
box-shadow: 0px 0px 32px rgba(0, 1, 133, 0.08);
border-radius: 12px;
font-size: 14px;
line-height: 24px;
color: #777;
.cInner {
padding: 24px 16px;
}
.cTitle {
font-weight: bold;
font-size: 16px;
line-height: 24px;
color: #333;
margin: 0;
padding-bottom: 16px;
}
.cFlex {
display: flex;
justify-content: space-between;
margin: 0 -8px;
}
.cFlexPadding {
padding: 8px;
}
.cSection {
position: relative;
margin-top: 16px;
padding: 16px 0;
&:before {
content: '';
position: absolute;
top: 0;
left: -16px;
right: -16px;
height: 1px;
background-color: #f2f2f2;
}
}
.star {
&:before {
display: inline-block;
content: '';
background-image: url('/static/img/icons/star.svg');
width: 20px;
height: 19px;
margin-left: 8px;
vertical-align: middle;
}
}
.cStats {
margin-top: 16px;
text-align: center;
}
.cMore {
display: block;
margin-top: 32px;
padding: 16px;
text-align: center;
border: 1px solid #a8bf97;
border-radius: 24px;
font-size: 16px;
color: #333;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
`
;
export
default
EventCardStyled
;
src/app/features/events/components.styled/EventFilters.styled.js
0 → 100644
View file @
5d21477c
import
styled
,
{
css
}
from
'
styled-components
'
;
import
getIn
from
'
~/utils/getIn
'
;
import
validateProps
from
'
~/utils/validateProps
'
;
const
EventFiltersStyled
=
styled
.
div
`
${({
theme
,
filtersVisible
})
=>
{
const
mqLarge
=
getIn
([
'
layout
'
,
'
mediaQueries
'
,
'
large
'
],
theme
);
const
visuallyHidden
=
getIn
([
'
patterns
'
,
'
visuallyHidden
'
],
theme
);
validateProps
(
'
TreatmentsFiltersStyled
'
,
{
mqLarge
,
visuallyHidden
});
return
css
`
@media only screen and (min-width:
${
mqLarge
}
) {
padding-right: 32px;
}
.filterGroup:not(:first-child) {
margin-top: 24px;
}
.filterGroup .open .feToggle {
border-radius: 16px 16px 0 0;
&:after {
transform: translateY(-50%) rotate(180deg);
}
}
.feLabel {
${
visuallyHidden
}
}
.feToggle {
position: relative;
padding-right: 32px;
display: block;
width: 100%;
padding: 12px 16px;
background: rgba(163, 183, 148, 0.2);
border-radius: 16px;
border: none;
font-size: 16px;
line-height: 24px;
color: #333333;
text-align: left;
&:after {
content: '';
background-image: url('/static/img/icons/chevron_down.svg');
width: 10px;
height: 5px;
position: absolute;
right: 16px;
top: 50%;
transform: translateY(-50%);
}
}
.toggleFiltersWrap {
text-align: right;
@media only screen and (min-width:
${
mqLarge
}
) {
display: none;
}
}
.toggleFilters {
border: none;
margin-top: 24px;
background: transparent;
font-size: 14px;
color: #879b79;
text-decoration: underline;
&:after {
content: '';
display: inline-block;
margin-left: 8px;
background-image: url('/static/img/icons/chevron_down_green.svg');
width: 8px;
height: 5px;
${
filtersVisible
&&
'
transform:rotate(180deg)
'
}
}
}
${
!
filtersVisible
&&
'
.filterGroup:nth-child(1n+4) {display:none}
'
}
;
@media only screen and (min-width:
${
mqLarge
}
) {
${
!
filtersVisible
&&
'
.filterGroup:nth-child(1n+4) {display:block}
'
}
;
}
.feList {
border-top: 1px solid #fff;
list-style: none;
margin: 0;
padding: 24px 16px;
background: rgba(163, 183, 148, 0.2);
border-radius: 0 0 16px 16px;
}
.feItem:not(:first-child) {
margin-top: 24px;
}
.feItemInput {
${
visuallyHidden
}
;
}
.feItemInput:checked + .feItemLabel {
font-weight: bold;
}
`
;
}}
;
`
;
export
default
EventFiltersStyled
;
src/app/features/events/components.styled/EventListing.styled.js
0 → 100644
View file @
5d21477c
import
styled
,
{
css
}
from
'
styled-components
'
;
import
validateProps
from
'
~/utils/validateProps
'
;
import
getIn
from
'
~/utils/getIn
'
;
const
EventListingStyled
=
styled
.
div
`
${({
theme
})
=>
{
const
container
=
getIn
([
'
patterns
'
,
'
container
'
],
theme
);
const
gutter
=
getIn
([
'
layout
'
,
'
gutter
'
],
theme
);
const
mqXSmall
=
getIn
([
'
layout
'
,
'
mediaQueries
'
,
'
xsmall
'
],
theme
);
const
mqMedium
=
getIn
([
'
layout
'
,
'
mediaQueries
'
,
'
medium
'
],
theme
);
const
mqLarge
=
getIn
([
'
layout
'
,
'
mediaQueries
'
,
'
large
'
],
theme
);
const
mqXLarge
=
getIn
([
'
layout
'
,
'
mediaQueries
'
,
'
xlarge
'
],
theme
);
validateProps
(
'
EventListingStyled
'
,
{
container
,
gutter
,
mqXSmall
,
mqMedium
,
mqLarge
,
mqXLarge
,
});
return
css
`
.container {
${
container
}
}
.flexWrap {
margin: 64px -
${
gutter
}
0;
@media only screen and (min-width:
${
mqLarge
}
) {
display: flex;
align-items: flex-start;
justify-content: space-between;
}
}
.flexColMain {
margin-top: 40px;
flex-basis:
${(
100
/
12
)
*
9
}
%;
padding-bottom: 70px;
@media only screen and (min-width:
${
mqLarge
}
) {
margin-top: 0;
}
}
.flexColAside {
flex-basis:
${(
100
/
12
)
*
3
}
%;
}
.flexColPadding {
padding: 0
${
gutter
}
;
}
.resultsInfo span {
font-weight: bold;
}
.results {
margin: -24px -24px 0;
@media only screen and (min-width:
${
mqXLarge
}
) {
margin: -32px -32px 0;
}
@media only screen and (min-width:
${
mqXSmall
}
) {
display: flex;
flex-wrap: wrap;
}
}
.card {
flex-basis: 50%;
@media only screen and (min-width:
${
mqMedium
}
) {
flex-basis:
${(
100
/
3
)
*
1
}
%;
}
}
.cardPadding {
padding: 24px;
@media only screen and (min-width:
${
mqXLarge
}
) {
padding: 32px;
}
}
.downloadWrap {
text-align: right;
}
.download {
background: #c3deaf;
border-radius: 24px;
text-align: center;
padding: 16px;
width: 100%;
display: inline-block;
margin-top: 40px;
border: none;
font-size: 16px;
line-height: 24px;
color: #333;
&:first-child {
margin-right: 20px;
}
@media only screen and (min-width:
${
mqLarge
}
) {
width: auto;
}
span {
&:before {
display: inline-block;
vertical-align: middle;
margin: 0 8px;
content: '';
background-image: url('/static/img/icons/download.svg');
width: 16px;
height: 20px;
}
}
}
`
;
}}
;
`
;
export
default
EventListingStyled
;
src/app/features/events/components/EventCard.js
0 → 100644
View file @
5d21477c
import
React
from
'
react
'
;
import
PropTypes
from
'
prop-types
'
;
import
{
Link
}
from
'
react-router-dom
'
;
import
EventCardStyled
from
'
../components.styled/EventCard.styled
'
;
const
EventCard
=
({
title
,
description
,
image
,
uri
,
date
,
className
})
=>
{
return
(
<
EventCardStyled
className
=
{
className
}
>
<
div
className
=
"
cInner
"
>
{
image
&&
<
img
src
=
{
image
.
asset
.
sys
.
uri
}
alt
=
{
image
.
altText
}
/>
}
<
div
className
=
"
cTitle
"
>
<
Link
to
=
{
uri
}
title
=
{
title
}
>
{
title
}
<
/Link
>
<
/div
>
<
p
>
{
description
}
<
/p
>
<
p
>
{
date
}
<
/p
>
<
/div
>
<
/EventCardStyled
>
);
};
EventCard
.
propTypes
=
{
className
:
PropTypes
.
string
,
title
:
PropTypes
.
string
,
description
:
PropTypes
.
string
,
image
:
PropTypes
.
object
,
uri
:
PropTypes
.
string
,
date
:
PropTypes
.
object
,
};
export
default
EventCard
;
src/app/features/events/components/EventFilters.js
0 → 100644
View file @
5d21477c
import
React
,
{
useState
}
from
'
react
'
;
import
PropTypes
from
'
prop-types
'
;
import
EventFiltersStyled
from
'
../components.styled/EventFilters.styled
'
;
import
FilterEntryDropdown
from
'
~/features/listings/components/FilterEntryDropdown
'
;
const
EventFilters
=
({
className
,
filters
,
updateFilters
})
=>
{
const
[
filtersVisible
,
toggleFilters
]
=
useState
(
false
);
const
renderFilter
=
filterGroup
=>
{
switch
(
filterGroup
.
type
)
{
case
'
entry
'
:
{
return
(
<
FilterEntryDropdown
className
=
"
tfCategory
"
entries
=
{
filterGroup
.
params
.
entries
}
id
=
{
filterGroup
.
id
}
label
=
{
filterGroup
.
label
}
update
=
{
updateFilters
}
value
=
{
filterGroup
.
value
}
/
>
);
}
case
'
list
'
:
{
return
(
<
FilterEntryDropdown
className
=
"
tfCategory
"
entries
=
{
filterGroup
.
params
.
options
}
id
=
{
filterGroup
.
id
}
label
=
{
filterGroup
.
label
}
update
=
{
updateFilters
}
type
=
{
'
list
'
}
value
=
{
filterGroup
.
value
}
/
>
);
}
default
:
return
;
}
};
return
(
<
EventFiltersStyled
className
=
{
className
}
filtersVisible
=
{
filtersVisible
}
>
<
div
className
=
"
tfInner
"
>
{
filters
&&
filters
.
map
((
filterGroup
,
idx
)
=>
{
return
(
<
div
key
=
{
idx
}
className
=
"
filterGroup
"
>
{
renderFilter
(
filterGroup
)}
<
/div
>
);
})}
<
div
className
=
"
toggleFiltersWrap
"
>
<
button
onClick
=
{()
=>
toggleFilters
(
!
filtersVisible
)}
className
=
"
toggleFilters
"
>
Additional
filters
<
/button
>
<
/div
>
<
/div
>
<
/EventFiltersStyled
>
);
};
EventFilters
.
propTypes
=
{
className
:
PropTypes
.
string
,
clearFilters
:
PropTypes
.
func
,
filters
:
PropTypes
.
array
,
updateFilters
:
PropTypes
.
func
,
};
export
default
EventFilters
;
src/app/features/events/components/EventsListing.js
0 → 100644
View file @
5d21477c
import
React
from
'
react
'
;
import
PropTypes
from
'
prop-types
'
;
import
{
withRouter
}
from
'
react-router-dom
'
;
import
EventFilters
from
'
./EventFilters
'
;
import
EventListingStyled
from
'
../components.styled/EventListing.styled
'
;
import
EventCard
from
'
./EventCard
'
;
const
EventListing
=
({
className
,
filters
,
paging
,
results
,
updateFilters
,
})
=>
{
let
resultsInfo
=
null
;
if
(
paging
&&
paging
.
totalCount
>
0
)
{
const
start
=
paging
.
pageIndex
*
paging
.
pageSize
+
1
;
let
end
=
paging
.
pageSize
;
if
(
end
>
paging
.
totalCount
)
end
=
paging
.
totalCount
;
resultsInfo
=
`Displaying
${
start
}
-
${
end
}
of
${
paging
.
totalCount
}
results`
;
}
return
(
<
EventListingStyled
className
=
{
className
}
>
<
div
className
=
"
container
"
>
<
h1
className
=
"
pageTitle
"
>
Example
listing
title
<
/h1
>
{
paging
&&
(
<
div
className
=
"
resultsInfo
"
dangerouslySetInnerHTML
=
{{
__html
:
resultsInfo
}}
/
>
)}
<
div
className
=
"
flexWrap
"
>
<
aside
className
=
"
flexColAside
"
>
<
div
className
=
"
flexColPadding
"
>
<
EventFilters
filters
=
{
filters
}
updateFilters
=
{
updateFilters
}
/
>
<
/div
>
<
/aside
>
<
main
className
=
"
flexColMain
"
>
<
div
className
=
"
flexColPadding
"
>
<
div
className
=
"
results
"
>
{
results
&&
results
.
map
((
entry
,
idx
)
=>
{
return
(
<
div
key
=
{
idx
}
className
=
"
card
"
>
<
div
className
=
"
cardPadding
"
>
<
EventCard
title
=
{
entry
.
entryTitle
}
description
=
{
entry
.
entryDescription
}
image
=
{
entry
.
image
}
uri
=
{
entry
.
sys
&&
entry
.
sys
.
uri
}
/
>
<
/div
>
<
/div
>
);
})}
{
!
results
||
(
results
.
length
<
1
&&
<
p
>
No
results
found
.
<
/p>
)
}
<
/div
>
<
/div
>
<
/main
>
<
/div
>
<
/div
>
<
/EventListingStyled
>
);
};
EventListing
.
propTypes
=
{
className
:
PropTypes
.
string
,
filters
:
PropTypes
.
arrayOf
(
PropTypes
.
object
),
paging
:
PropTypes
.
object
,
results
:
PropTypes
.
arrayOf
(
PropTypes
.
object
),
updateFilters
:
PropTypes
.
func
,
};
export
default
withRouter
(
EventListing
);
src/app/features/events/stories/EventCard.stories.js
0 → 100644
View file @
5d21477c
import
React
from
'
react
'
;
import
{
storiesOf
}
from
'
@storybook/react
'
;
import
{
text
}
from
'
@storybook/addon-knobs
'
;
import
EventCard
from
'
~/features/events/components/EventCard
'
;
storiesOf
(
'
Features | Event
'
,
module
).
add
(
'
Event card
'
,
()
=>
{
return
(
<
EventCard
title
=
{
text
(
'
Title
'
,
'
Event card title
'
)}
description
=
"
Event card description
"
uri
=
"
/example-content/example-article
"
/>
);
},
{
knobs
:
{
escapeHTML
:
false
,
},
}
);
src/app/pages/Listings/EventListing.page.js
0 → 100644
View file @
5d21477c
import
React
from
'
react
'
;
import
PropTypes
from
'
prop-types
'
;
import
MainLayout
from
'
~/layouts/Main.layout
'
;
import
EventListing
from
'
~/features/events/components/EventsListing
'
;
import
ListingContainer
from
'
~/features/listings/containers/Listing.container
'
;
const
EventListingPage
=
()
=>
{
return
(
<
MainLayout
>
<
ListingContainer
config
=
{{
listingType
:
'
event
'
,
contentTypeIds
:
[
'
event
'
],
fields
:
[
'
entryTitle
'
,
'
entryDescription
'
,
'
image
'
,
'
eventCategories
'
,
],
pageSize
:
4
,
orderBy
:
{
field
:
'
datesAndTimes.from
'
,
direction
:
'
asc
'
,
},
filters
:
[
{
label
:
'
Categories
'
,
type
:
'
entry
'
,
fields
:
[
'
eventCategories[]
'
],
params
:
{
contentTypeIds
:
[
'
eventCategories
'
],
<