Skip to content

Commit b9d72a4

Browse files
Merge pull request #5920 from topcoder-platform/mm-leaderboard-theme
Mm leaderboard theme
2 parents 6cd4fe5 + bbb0b2f commit b9d72a4

File tree

12 files changed

+116
-105
lines changed

12 files changed

+116
-105
lines changed

__tests__/shared/components/Contentful/Image/Image.jsx

Lines changed: 0 additions & 24 deletions
This file was deleted.

__tests__/shared/components/Contentful/Image/__snapshots__/Image.jsx.snap

Lines changed: 0 additions & 34 deletions
This file was deleted.

__tests__/shared/components/__snapshots__/TopcoderFooter.jsx.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ exports[`Matches shallow shapshot 1`] = `
495495
className="src-shared-components-TopcoderFooter-___style__mobile-navi-col___3BcW4"
496496
>
497497
<a
498-
href="https://www.topcoder-dev.com/ommunity/admins"
498+
href="https://www.topcoder-dev.com/community/admins"
499499
>
500500
ABOUT
501501
</a>

src/server/routes/feeds.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ routes.get('/thrive', async (req, res, next) => {
2626
limit: 20,
2727
order: '-sys.createdAt',
2828
include: 2,
29+
'sys.firstPublishedAt[exists]': true,
2930
});
3031
const feed = new RSS({
3132
title: 'Topcoder Thrive',
@@ -45,8 +46,8 @@ routes.get('/thrive', async (req, res, next) => {
4546
feed.item({
4647
title: entry.fields.title,
4748
description: ReactDOMServer.renderToString(md(entry.fields.content)),
48-
url: `https://topcoder.com/thrive/articles/${entry.fields.slug || encodeURIComponent(entry.fields.title)}?utm_source=community&utm_campaign=thrive-feed&utm_medium=promotion`,
49-
date: entry.fields.creationDate,
49+
url: `https://topcoder.com/thrive/articles/${entry.fields.slug || encodeURIComponent(entry.fields.title)}?utm_source=thrive&utm_campaign=thrive-feed&utm_medium=rss-feed`,
50+
date: entry.sys.createdAt,
5051
categories: entry.fields.tags,
5152
author: entry.fields.contentAuthor[0].fields.name,
5253
});

src/shared/components/Contentful/Article/Article.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ class Article extends React.Component {
170170
<meta name="twitter:description" content={description} />
171171
<meta name="image" property="og:image" content={fields.featuredImage ? `https:${subData.assets.items[fields.featuredImage.sys.id].fields.file.url}` : DEFAULT_BANNER_IMAGE} />
172172
<meta name="twitter:image" content={fields.featuredImage ? `https:${subData.assets.items[fields.featuredImage.sys.id].fields.file.url}` : DEFAULT_BANNER_IMAGE} />
173+
<link rel="alternate" type="application/rss+xml" title="Topcoder Thrive - RSS feed" href="https://topcoder.com/api/feeds/thrive" />
173174
</Helmet>
174175
<div className={theme.wrapper}>
175176
{/* Banner */}

src/shared/components/Contentful/Image/Image.jsx

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable max-len */
12
/**
23
* The core image rendering.
34
*/
@@ -68,12 +69,10 @@ export class ImageInner extends React.Component {
6869
theme,
6970
id,
7071
image,
71-
imageSource,
72+
imageSources,
7273
clipSvg,
7374
animation,
7475
} = this.props;
75-
76-
const imageUrl = _.get(imageSource, 'file.url');
7776
const clipSvgUrl = _.get(clipSvg, 'file.url');
7877
const imgStyle = image.extraStylesForImage ? fixStyle(image.extraStylesForImage) : {};
7978
if (clipSvgUrl) {
@@ -96,25 +95,47 @@ export class ImageInner extends React.Component {
9695
)}
9796
{
9897
animation.animateOnScroll ? (
99-
<img
100-
src={imageUrl}
101-
alt={image.alt || image.name}
102-
style={imgStyle}
103-
data-aos={animation.animateOnScroll}
104-
data-aos-once={animation.animateOnScrollOnce}
105-
data-aos-delay={animation.animateOnScrollDelay}
106-
data-aos-duration={animation.animateOnScrollDuration}
107-
data-aos-easing={animation.animateOnScrollEasing}
108-
data-aos-mirror={animation.animateOnScrollMirror}
109-
data-aos-anchor-placement={animation.animateOnScrollAnchor}
110-
data-aos-offset={animation.animateOnScrollOffset}
111-
/>
98+
<picture>
99+
<source srcSet={imageSources.source.file.url} type={imageSources.source.file.contentType} media="(min-width: 769px)" />
100+
{
101+
imageSources.sourceMobile ? (
102+
<source srcSet={imageSources.sourceMobile.file.url} type={imageSources.sourceMobile.file.contentType} media="(max-width: 768px)" />
103+
) : (
104+
<source srcSet={`${imageSources.source.file.url}?w=768`} type={imageSources.source.file.contentType} media="(max-width: 768px)" />
105+
)
106+
}
107+
<img
108+
src={`${imageSources.source.file.url}?fm=png`}
109+
alt={image.alt || image.name}
110+
style={imgStyle}
111+
data-aos={animation.animateOnScroll}
112+
data-aos-once={animation.animateOnScrollOnce}
113+
data-aos-delay={animation.animateOnScrollDelay}
114+
data-aos-duration={animation.animateOnScrollDuration}
115+
data-aos-easing={animation.animateOnScrollEasing}
116+
data-aos-mirror={animation.animateOnScrollMirror}
117+
data-aos-anchor-placement={animation.animateOnScrollAnchor}
118+
data-aos-offset={animation.animateOnScrollOffset}
119+
loading="lazy"
120+
/>
121+
</picture>
112122
) : (
113-
<img
114-
src={imageUrl}
115-
alt={image.alt || image.name}
116-
style={imgStyle}
117-
/>
123+
<picture>
124+
<source srcSet={imageSources.source.file.url} type={imageSources.source.file.contentType} media="(min-width: 769px)" />
125+
{
126+
imageSources.sourceMobile ? (
127+
<source srcSet={imageSources.sourceMobile.file.url} type={imageSources.sourceMobile.file.contentType} media="(max-width: 768px)" />
128+
) : (
129+
<source srcSet={`${imageSources.source.file.url}?w=768`} type={imageSources.source.file.contentType} media="(max-width: 768px)" />
130+
)
131+
}
132+
<img
133+
src={`${imageSources.source.file.url}?fm=png`}
134+
alt={image.alt || image.name}
135+
style={imgStyle}
136+
loading="lazy"
137+
/>
138+
</picture>
118139
)
119140
}
120141
</div>
@@ -130,7 +151,7 @@ ImageInner.defaultProps = {
130151
ImageInner.propTypes = {
131152
id: PT.string.isRequired,
132153
image: PT.shape().isRequired,
133-
imageSource: PT.shape().isRequired,
154+
imageSources: PT.shape().isRequired,
134155
clipSvg: PT.shape(),
135156
theme: PT.shape({
136157
'img-wrap': PT.string,

src/shared/components/Contentful/Image/index.jsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import LoadingIndicator from 'components/LoadingIndicator';
77
import PT from 'prop-types';
88
import React from 'react';
99
import _ from 'lodash';
10-
import { useMediaQuery } from 'react-responsive';
1110

1211
import Image from './Image';
1312
import defaultTheme from './themes/default.scss';
@@ -18,7 +17,7 @@ export default function ImageLoader(props) {
1817
const {
1918
id, preview, spaceName, environment,
2019
} = props;
21-
const isTabletOrMobile = useMediaQuery({ maxWidth: 768 });
20+
// const isTabletOrMobile = useMediaQuery({ maxWidth: 768 });
2221
return (
2322
<ContentfulLoader
2423
entryIds={id}
@@ -27,9 +26,12 @@ export default function ImageLoader(props) {
2726
environment={environment}
2827
render={(data) => {
2928
const { fields } = data.entries.items[id];
30-
const imgId = _.get(fields, isTabletOrMobile && fields.sourceMobile ? 'sourceMobile.sys.id' : 'source.sys.id');
29+
const imgId = _.get(fields, 'source.sys.id');
30+
const imgIdMobile = _.get(fields, 'sourceMobile.sys.id');
3131
const clipSvgId = _.get(fields, 'clipSvg.sys.id');
32-
const assetIds = _.compact([imgId, clipSvgId]);
32+
const assetIds = _.compact(
33+
[imgId, imgIdMobile, clipSvgId],
34+
);
3335
const animationId = _.get(fields, 'animationOnScroll.sys.id');
3436
const entryIds = [];
3537
if (animationId) {
@@ -45,16 +47,19 @@ export default function ImageLoader(props) {
4547
environment={environment}
4648
render={(assetData) => {
4749
const { items } = assetData.assets;
48-
const imgFields = _.get(items, [imgId, 'fields']);
4950
const clipSvgFields = _.get(items, [clipSvgId, 'fields']);
51+
const imageSources = {
52+
source: _.get(items, [imgId, 'fields']),
53+
sourceMobile: _.get(items, [imgIdMobile, 'fields']),
54+
};
5055
let animation = {};
5156
if (animationId) {
5257
animation = { ...assetData.entries.items[animationId].fields };
5358
}
5459
return (
5560
<Image
5661
{...props}
57-
imageSource={imgFields}
62+
imageSources={imageSources}
5863
clipSvg={clipSvgFields}
5964
image={fields}
6065
theme={defaultTheme}

src/shared/components/Contentful/Tabs/themes/vertical.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ li.tab {
5353
padding-right: 20px;
5454
border-bottom: 5px solid $gray-border-color;
5555
min-width: auto !important;
56+
white-space: nowrap;
5657

5758
&:first-child {
5859
padding-left: 7px;

src/shared/components/MMatchLeaderboard/index.jsx

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ export default class MMLeaderboard extends Component {
9494
<div className={defaultStyles.topMemberPhotoAndPlace}>
9595
<img src={member.photoUrl || DEFAULT_AVATAR_URL} className={defaultStyles.topMemberPhoto} alt={`Avatar of ${member.createdBy}`} />
9696
<div className={defaultStyles[`topMemberRank${indx + 1}`]}>{member.rank}</div>
97+
<a href={`${config.URL.BASE}/members/${member.createdBy}`} target="_blank" rel="noreferrer" style={{ color: getRatingColor(member.rating) }}>{member.createdBy}</a>
9798
</div>
9899
<div className={defaultStyles.topMemberLink}>
99100
<a href={`${config.URL.BASE}/members/${member.createdBy}`} target="_blank" rel="noreferrer" style={{ color: getRatingColor(member.rating) }}>{member.createdBy}</a>
@@ -106,6 +107,7 @@ export default class MMLeaderboard extends Component {
106107
<div className={defaultStyles.topMemberPhotoAndPlace}>
107108
<img src={data[2].photoUrl || DEFAULT_AVATAR_URL} className={defaultStyles.topMemberPhoto} alt={`Avatar of ${data[2].createdBy}`} />
108109
<div className={defaultStyles.topMemberRank3}>{data[2].rank}</div>
110+
<a href={`${config.URL.BASE}/members/${data[2].createdBy}`} target="_blank" rel="noreferrer" style={{ color: getRatingColor(data[2].rating) }}>{data[2].createdBy}</a>
109111
</div>
110112
<div className={defaultStyles.topMemberLink}>
111113
<a href={`${config.URL.BASE}/members/${data[2].createdBy}`} target="_blank" rel="noreferrer" style={{ color: getRatingColor(data[2].rating) }}>{data[2].createdBy}</a>
@@ -135,15 +137,17 @@ export default class MMLeaderboard extends Component {
135137
))}
136138
{
137139
data.length > 10 && (
138-
<PrimaryButton
139-
to={`${config.URL.BASE}/challenges/${challengeId}?tab=submissions`}
140-
openNewTab
141-
theme={{
142-
button: tc['primary-green-sm'],
143-
}}
144-
>
145-
See Full Leaderbord
146-
</PrimaryButton>
140+
<div className={defaultStyles.moreBtn}>
141+
<PrimaryButton
142+
to={`${config.URL.BASE}/challenges/${challengeId}?tab=submissions`}
143+
openNewTab
144+
theme={{
145+
button: tc['primary-green-sm'],
146+
}}
147+
>
148+
See Full Leaderbord
149+
</PrimaryButton>
150+
</div>
147151
)}
148152
</div>
149153
)}

0 commit comments

Comments
 (0)