From f51d4f568100416c7afa1e301b96ec1231c4b6fa Mon Sep 17 00:00:00 2001 From: PeterJFB Date: Thu, 10 Mar 2022 15:19:17 +0100 Subject: [PATCH] Create new frontpage for logged in users --- app/assets/fonts/icomoon.eot | Bin app/assets/fonts/icomoon.svg | 0 app/assets/fonts/icomoon.ttf | Bin app/assets/fonts/icomoon.woff | Bin app/assets/weekly_logo.svg | 3 + app/assets/weekly_mug.svg | 6 + app/components/Header/index.js | 2 +- app/components/Poll/Poll.css | 248 +- app/components/Poll/index.js | 285 +- app/components/RandomQuote/RandomQuote.css | 28 +- app/components/RandomQuote/RandomQuote.js | 84 +- app/reducers/frontpage.js | 12 +- app/reducers/index.js | 1 + app/routes/app/AppRoute.js | 2 +- app/routes/articles/components/Overview.js | 3 +- app/routes/errors/c64.bdf | 0 app/routes/overview/IndexRoute.js | 2 +- .../overview/components/ArticleItem.css | 56 +- app/routes/overview/components/ArticleItem.js | 42 +- .../overview/components/CompactEvents.css | 31 +- .../overview/components/CompactEvents.js | 41 +- .../components/InterestgroupPlacard.css | 60 + .../components/InterestgroupPlacard.js | 55 + app/routes/overview/components/Overview.css | 206 +- app/routes/overview/components/Overview.js | 281 +- app/routes/overview/components/Pinned.css | 68 +- app/routes/overview/components/Pinned.js | 36 +- app/routes/overview/components/Placard.css | 9 + app/routes/overview/components/Placard.js | 28 + .../overview/components/PlacardButton.css | 31 + .../overview/components/PlacardButton.js | 33 + .../overview/components/ReadmePlacard.css | 34 + .../overview/components/ReadmePlacard.js | 40 + .../overview/components/WeeklyPlacard.css | 123 + .../overview/components/WeeklyPlacard.js | 69 + app/routes/overview/components/utils.js | 14 +- app/routes/polls/components/PollDetail.js | 1 + app/styles/icomoon.css | 0 app/styles/variables.css | 5 + cypress/integration/home_page_spec.js | 19 +- cypress/integration/poll_spec.js | 3 +- cypress/integration/router_spec.js | 2 +- package.json | 1 + yarn.lock | 2331 +++++++++-------- 44 files changed, 2509 insertions(+), 1786 deletions(-) mode change 100755 => 100644 app/assets/fonts/icomoon.eot mode change 100755 => 100644 app/assets/fonts/icomoon.svg mode change 100755 => 100644 app/assets/fonts/icomoon.ttf mode change 100755 => 100644 app/assets/fonts/icomoon.woff create mode 100644 app/assets/weekly_logo.svg create mode 100644 app/assets/weekly_mug.svg mode change 100755 => 100644 app/routes/errors/c64.bdf create mode 100644 app/routes/overview/components/InterestgroupPlacard.css create mode 100644 app/routes/overview/components/InterestgroupPlacard.js create mode 100644 app/routes/overview/components/Placard.css create mode 100644 app/routes/overview/components/Placard.js create mode 100644 app/routes/overview/components/PlacardButton.css create mode 100644 app/routes/overview/components/PlacardButton.js create mode 100644 app/routes/overview/components/ReadmePlacard.css create mode 100644 app/routes/overview/components/ReadmePlacard.js create mode 100644 app/routes/overview/components/WeeklyPlacard.css create mode 100644 app/routes/overview/components/WeeklyPlacard.js mode change 100755 => 100644 app/styles/icomoon.css diff --git a/app/assets/fonts/icomoon.eot b/app/assets/fonts/icomoon.eot old mode 100755 new mode 100644 diff --git a/app/assets/fonts/icomoon.svg b/app/assets/fonts/icomoon.svg old mode 100755 new mode 100644 diff --git a/app/assets/fonts/icomoon.ttf b/app/assets/fonts/icomoon.ttf old mode 100755 new mode 100644 diff --git a/app/assets/fonts/icomoon.woff b/app/assets/fonts/icomoon.woff old mode 100755 new mode 100644 diff --git a/app/assets/weekly_logo.svg b/app/assets/weekly_logo.svg new file mode 100644 index 0000000000..e32dcdeede --- /dev/null +++ b/app/assets/weekly_logo.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/weekly_mug.svg b/app/assets/weekly_mug.svg new file mode 100644 index 0000000000..575522204b --- /dev/null +++ b/app/assets/weekly_mug.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/components/Header/index.js b/app/components/Header/index.js index 181442d3ec..acee0cf12d 100644 --- a/app/components/Header/index.js +++ b/app/components/Header/index.js @@ -168,7 +168,7 @@ class Header extends Component { return (
- + {/* */}
diff --git a/app/components/Poll/Poll.css b/app/components/Poll/Poll.css index 5e955a4d6c..43388d0f32 100644 --- a/app/components/Poll/Poll.css +++ b/app/components/Poll/Poll.css @@ -1,185 +1,169 @@ -@import '~app/styles/variables.css'; - -.optionWrapper { - justify-content: center; - min-height: 120px; - cursor: pointer; - position: relative; -} - -.pollTable { +.poll { + background-color: var(--lego-placard-color); width: 100%; - font-size: 14px; -} - -.pollTable td { - border: 0; - padding: 5px; + min-width: 250px; + max-width: 500px; + overflow-y: hidden; + border-radius: 15px; + transition: 2s height; } -.pollTable .textColumn { - border-right: 1px solid #c5c5c5; - text-align: right; - padding-right: 13px; - line-height: 16px; -} - -.pollTable .graphColumn { - width: auto; - min-width: 200px; - padding-left: 13px; +.topBar { + background-color: var(--lego-red); + position: relative; + width: 100%; + height: 70px; + box-shadow: 0 4px 4px rgba(0, 0, 0, 25%); } -.poll { - composes: withShadow from '~app/styles/utilities.css'; - background: var(--lego-card-color); - padding: 15px 20px 8px; +.stats { + color: var(--lego-placard-color); + margin-top: 17px; + transform: scale(150%); } -.pollLight { - background: var(--lego-card-color); +.notAnswered { + color: var(--color-white); + font-size: 30px; + font-weight: 900; + line-height: 45px; } -.noVotes { - font-style: italic; +.headerBar { + color: var(--lego-font-color); + background-color: var(--lego-placard-color); + font-weight: 900; + text-align: center; + position: absolute; + bottom: 0; + left: 50%; + width: 80%; + height: 50px; + border-radius: 10px; + box-shadow: 0 4px 4px rgba(0, 0, 0, 25%); + transform: translate(-50%, 50%); } -.pollGraph { - animation: graph 1.2s cubic-bezier(41%, 80%, 40%, 94%); - background-color: var(--lego-red-color); - padding-left: 8px; - border-radius: 0 2px 2px 0; - font-style: italic; - font-weight: 300; - color: var(--color-white); - height: 30px; +.contentWrapper { + overflow-y: hidden; + width: 100%; + transition: 0.5s height; } -.fullGraph { - background-color: #e7e7e7; - width: 100%; +.voteOptionsWrapper { display: flex; + flex-direction: column; + align-items: center; + width: 100%; + height: fit-content; } -html[data-theme='dark'] .fullGraph { +.voteButton { color: var(--color-white); - background-color: var(--color-mono-gray-5); -} - -html[data-theme='dark'] .pollGraph { - color: var(--color-black); -} - -.pollGraph span { - vertical-align: middle; -} - -@keyframes graph { - from { - width: 1px; - } + background: var(--lego-red); + font-weight: 500; + width: 90%; + height: 37px; + padding: 5px; + margin: 2px; - to { - width: 100%; + /* Override default components/Button property */ + + .voteButton { + margin-left: 2px; } } -.pollHeader { - border-radius: 8px; - margin-bottom: 20px; - margin-left: 20px; - font-size: 16px; - color: var(--lego-font-color); -} - -.voteButton { - background: var(--lego-red-color); - color: var(--lego-color-gray-light); - border: 1px solid var(--border-gray); +.voteOptions { width: 100%; - margin: 0 !important; - font-size: 15px; - max-width: 400px; + padding-top: 35px; } -.voteButton:hover { - opacity: 0.8; +.bottomInfoWrapper { + display: flex; + flex-direction: column; + align-items: center; } -html[data-theme='dark'] .voteButton { - color: var(--color-dark-gray-3); +.totalVotesInfo { + display: flex; } -.moreOptionsLink { - justify-content: space-between; +.resultsHiddenInfo { + font-style: italic; } -.arrow { - margin-top: 9px; - cursor: pointer; - - &:hover { - transform: scale(1.5); - color: var(--color-red-3); - transition: transform 0.2s; - } +.pollTable { + width: 100%; + font-size: 14px; } -.blurContainer { - display: none; - position: absolute; - justify-content: center; +.pollTable tr { width: 100%; - height: 100%; } -.blurOverlay { - position: absolute; - z-index: 2; - color: var(--color-black); - margin-top: 25px; +.pollTable td { + border: 0; + padding: 5px; } -.optionWrapper:hover .blurContainer { - display: flex; +.pollTable .textColumn { + text-align: right; + line-height: 16px; + word-wrap: break-word; + width: fit-content; + max-width: 200px; + padding-right: 13px; + border-right: 3px solid #c5c5c5; } -.optionWrapper:hover .blurEffect { - filter: blur(3px); - pointer-events: none; +.pollTable .graphColumn { + width: auto; + min-width: 150px; + padding-left: 13px; + padding-right: 15px; } -.blurArrow { - margin-top: 40px; +.fullGraph { + display: flex; + background-color: #e7e7e7; + word-wrap: break-word; + width: 100%; } -.alignItems { - display: flex; - justify-content: center; +.pollGraph { + background-color: var(--lego-red); + font-style: italic; + font-weight: 300; + color: var(--color-white); + height: 30px; + padding-left: 8px; + animation: graph 1.2s cubic-bezier(0.41, 0.8, 0.4, 0.94); + border-radius: 0 2px 2px 0; + box-shadow: 0 4px 4px rgba(0, 0, 0, 25%); } -.answered { - margin: 15px 0; - text-align: center; - font-weight: bold; +.bottomBar { + width: 100%; + height: 70px; + background-color: var(--lego-red); } -.bottomInfo { - display: flex; - justify-content: space-between; +.arrowUp, +.arrowDown { + text-shadow: 0 2px 2px rgba(0, 0, 0, 25%); + transform: scale(250%); + color: var(--lego-placard-color); + transition: 0.8s margin-bottom; } -.resultsHidden { - font-style: italic; +.arrowUp { + margin-bottom: 25px; } -@media (--mobile-device) { - .blurContainer { - display: flex; - } +.arrowDown { + margin-bottom: 10px; +} - .blurEffect { - filter: blur(3px); - pointer-events: none; - } +.arrow:hover { + cursor: pointer; } diff --git a/app/components/Poll/index.js b/app/components/Poll/index.js index e176624232..03e73c67a5 100644 --- a/app/components/Poll/index.js +++ b/app/components/Poll/index.js @@ -1,6 +1,8 @@ // @flow -import { Component } from 'react'; +import type { ElementRef } from 'react'; + +import { createRef, Component } from 'react'; import Button from 'app/components/Button'; import styles from './Poll.css'; import type { PollEntity, OptionEntity } from 'app/reducers/polls'; @@ -16,8 +18,9 @@ type Props = { handleVote: (pollId: number, optionId: number) => Promise<*>, allowedToViewHiddenResults?: boolean, backgroundLight?: boolean, - truncate?: number, details?: boolean, + expanded: boolean, + alwaysOpen: boolean, }; type OptionEntityRatio = OptionEntity & { @@ -25,7 +28,6 @@ type OptionEntityRatio = OptionEntity & { }; type State = { - truncateOptions: boolean, shuffledOptions: Array, expanded: boolean, }; @@ -35,20 +37,17 @@ class Poll extends Component { super(props); const options = this.optionsWithPerfectRatios(props.poll.options); const shuffledOptions = this.shuffle(options); - if (props.truncate && options.length > props.truncate) { - this.state = { - truncateOptions: true, - shuffledOptions: shuffledOptions, - expanded: false, - }; - } else { - this.state = { - truncateOptions: false, - shuffledOptions: shuffledOptions, - expanded: true, - }; - } + this.state = { + shuffledOptions: shuffledOptions, + expanded: props.expanded || props.alwaysOpen, + }; } + static defaultProps = { + expanded: false, + alwaysOpen: false, + }; + + optionsRef = createRef>(); toggleTruncate = () => { this.setState({ @@ -96,158 +95,160 @@ class Poll extends Component { }; render() { + const { expanded, shuffledOptions } = this.state; const { poll, handleVote, backgroundLight, details, - truncate, allowedToViewHiddenResults, + alwaysOpen, } = this.props; - const { truncateOptions, expanded, shuffledOptions } = this.state; const { id, title, description, hasAnswered, totalVotes, resultsHidden } = poll; const options = this.optionsWithPerfectRatios(this.props.poll.options); const orderedOptions = hasAnswered ? options : shuffledOptions; - const optionsToShow = expanded - ? orderedOptions - : orderedOptions.slice(0, truncate); + const optionsToShow = expanded ? orderedOptions : orderedOptions; const showResults = !resultsHidden || allowedToViewHiddenResults; return ( -
- - - - {title} + + + {hasAnswered ? ( + + ) : ( +
?
+ )} + + + {!details && description.length !== 0 ? ( + + {title} + + ) : ( + <> {title} + )} + - - -
- {details && ( -
-

{description}

-
- )} - {hasAnswered && !showResults && ( -
- Du har svart - -
- )} - {hasAnswered && showResults && ( - - - - {optionsToShow.map(({ id, name, votes, ratio }) => { - return ( - - - + + ); + })} + +
{name} - {votes === 0 ? ( - Ingen stemmer - ) : ( -
-
-
- {ratio >= 18 && {`${ratio}%`}} -
-
- {ratio < 18 && ( - - {`${ratio}%`} + +
+ {!hasAnswered && ( + + {details && description} + {options && + optionsToShow.map((option) => ( + + ))} + + )} + {hasAnswered && !showResults && ( + + {details && description} +
+ Resultatet er skjult +
+
+ )} + {hasAnswered && showResults && ( + + {details && description} + + + {optionsToShow.map(({ id, name, votes, ratio }) => { + return ( + + + - - ); - })} - -
{name} + {votes === 0 ? ( + + Ingen stemmer + ) : ( +
+
+
+ {ratio >= 18 && {`${ratio}%`}} +
+
+ {ratio < 18 && ( + + {`${ratio}%`} + + )} +
)} - - )} -
- {resultsHidden && ( -

- Resultatet er skjult for vanlige brukere. -

- )} -
- )} - {!hasAnswered && ( - - {!expanded && ( - -

- Klikk her for å se alle alternativene. -

- +
)} - {options && - optionsToShow.map((option) => ( - +
+ - - - ))} - - )} -
-
- {truncateOptions && - (!hasAnswered || - !resultsHidden || - allowedToViewHiddenResults) && ( -
+ + Stemmer: {totalVotes} +
+ {resultsHidden && ( +
+ Resultatet er skjult for vanlige brukere.
)} +
-
- {`Stemmer: ${totalVotes}`} - {hasAnswered && !showResults && ( - - Resultatet er skjult. - - )} -
-
-
+ + + {!alwaysOpen ? ( + + ) : ( + + )} + + ); } } diff --git a/app/components/RandomQuote/RandomQuote.css b/app/components/RandomQuote/RandomQuote.css index 8aebcb4ec2..abc35163b6 100644 --- a/app/components/RandomQuote/RandomQuote.css +++ b/app/components/RandomQuote/RandomQuote.css @@ -1,22 +1,44 @@ @import '~app/styles/variables.css'; .quoteSource { - margin-top: 5px; + color: var(--lego-font-color); font-style: italic; + margin-top: 5px; } .quoteText { + color: var(--lego-font-color); font-weight: 600; } +.quoteText:hover { + color: var(--lego-link-color); +} + .quoteReactions { margin-top: 5px; } .actions { - margin: 5px 5px 5px 15px; + margin: 5px; } -.fetchNew { +.actions * { + line-height: 0; margin-bottom: 5px; } + +.actions > * + * { + margin-left: 20px; +} + +.bubbleArrow { + color: white; + position: absolute; + bottom: -35px; + left: calc(50% + 60px); +} + +html[data-theme='dark'] .bubbleArrow { + color: var(--lego-placard-color); +} diff --git a/app/components/RandomQuote/RandomQuote.js b/app/components/RandomQuote/RandomQuote.js index 64a7f908e1..111a33226a 100644 --- a/app/components/RandomQuote/RandomQuote.js +++ b/app/components/RandomQuote/RandomQuote.js @@ -10,6 +10,7 @@ import type { EmojiEntity } from 'app/reducers/emojis'; import type { ID } from 'app/models'; import NavigationLink from 'app/components/NavigationTab/NavigationLink'; import { Flex } from 'app/components/Layout'; +import { Link } from 'react-router-dom/cjs/react-router-dom.min'; type Props = { fetchRandomQuote: (Array) => Promise, @@ -49,41 +50,68 @@ const RandomQuote = (props: Props) => { } }); + const BubbleArrow = () => { + return ( + + + + ); + }; + return (
- - + + +
{currentQuote.text}
-{currentQuote.source}
-
- - - - - - + + + + +
- - {useReactions && ( -
- -
- )}
); }; diff --git a/app/reducers/frontpage.js b/app/reducers/frontpage.js index 2c47982be8..10b30de71d 100644 --- a/app/reducers/frontpage.js +++ b/app/reducers/frontpage.js @@ -5,18 +5,26 @@ import { sortBy } from 'lodash'; import { createSelector } from 'reselect'; import { selectArticles } from './articles'; import { selectEvents } from './events'; +import { groupSchema } from '.'; +import { selectGroups, selectGroupsWithType } from './groups'; +import { GroupTypeInterest } from 'app/models'; export default fetching(Frontpage.FETCH); export const selectFrontpage = createSelector( selectArticles, selectEvents, - (articles, events) => { + (state) => selectGroupsWithType(state, { groupType: GroupTypeInterest }), + (articles, events, interestGroups) => { articles = articles.map((article) => ({ ...article, documentType: 'article', })); events = events.map((event) => ({ ...event, documentType: 'event' })); + interestGroups = interestGroups.map((interestGroup) => ({ + ...interestGroup, + documentType: 'interestgroup', + })); const now = moment(); return sortBy(articles.concat(events), [ // Always sort pinned items first: @@ -28,6 +36,6 @@ export const selectFrontpage = createSelector( return Math.abs(now.diff(timeField)); }, (item) => item.id, - ]); + ]).concat(interestGroups); } ); diff --git a/app/reducers/index.js b/app/reducers/index.js index f851f9569c..52c7513409 100644 --- a/app/reducers/index.js +++ b/app/reducers/index.js @@ -233,6 +233,7 @@ export const frontpageSchema = (new schema.Entity('frontpage', { events: [eventSchema], articles: [articleSchema], poll: pollSchema, + interestgroups: [groupSchema], }): Schema); export const emojiSchema = (new schema.Entity( 'emojis', diff --git a/app/routes/app/AppRoute.js b/app/routes/app/AppRoute.js index 8302050498..5400b29fe7 100644 --- a/app/routes/app/AppRoute.js +++ b/app/routes/app/AppRoute.js @@ -69,7 +69,7 @@ class AppChildren extends PureComponent { }; return ( -
+
{this.props.statusCode ? ( diff --git a/app/routes/articles/components/Overview.js b/app/routes/articles/components/Overview.js index c7e20010b5..d094671fa0 100644 --- a/app/routes/articles/components/Overview.js +++ b/app/routes/articles/components/Overview.js @@ -32,9 +32,8 @@ const OverviewItem = ({ article }: { article: ArticleEntity }) => ( to={`/users/${article.author.username}`} className={styles.overviewAuthor} > - {' '} {article.author.fullName} - {' '} + )}