diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..c6c8b362 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/.gitattributes b/.gitattributes index fcadb2cf..ab2a5332 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,3 @@ * text eol=lf +*.png binary +*.ttf binary \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..aff82a10 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..13f33ea3 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,29 @@ +name: Vite Tests + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [18.x] + # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + + steps: + - uses: actions/checkout@v4 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: "npm" + - name: Install dependencies + run: npm ci + - name: Run tests + run: npm run test + - name: Build project + run: npm run build --if-present + env: + VITE_API_BASE_URL: dummy + VITE_KEYCLOAK_URL: dummy diff --git a/index.html b/index.html index 3eb0a629..561c4b04 100644 --- a/index.html +++ b/index.html @@ -8,6 +8,9 @@ + + + @@ -34,8 +37,8 @@ Bannergress - - + + + + + diff --git a/src/App.less b/src/App.less index b0c753c7..e47dbaad 100644 --- a/src/App.less +++ b/src/App.less @@ -1,67 +1,14 @@ @import 'antd/dist/antd.compact.less'; @import 'antd/dist/antd.dark.less'; -@primary-color: #1DA57A; -@link-color: #1DA57A; -@body-background: #0b0c0d; -@card-head-padding: 0.6rem; -@card-padding-base: 0.6rem; -@border-color-base: #004f4a; - -::-webkit-scrollbar { - width: 4px; - height: 4px; - background: transparent; -} - -::-webkit-scrollbar-thumb { - background: #969696; -} - -.mt-1 { - margin-top: 1rem; -} - -.pl-1 { - padding-left: 1rem; -} - -.pr-1 { - padding-right: 1rem; -} - -.footer-main { - text-align: center; - background-color: #000; - padding: 1.5rem 0; - width: 100%; -} - -.leaflet-container { - margin: unset; -} - -.leaflet-container { - height: 100%; -} - -body, -.ant-layout { - background: #1B1B1B; -} - -body, -.ant-menu, -.ant-input, -.ant-card, -.ant-card-head-title { - font-size: 16px; -} +@import './assets/style/variables.less'; +@import './assets/style/helper.less'; +@import './assets/style/ant-override.less'; #root { height: 100%; - &>.ant-layout { + & > .ant-layout { height: 100%; } } @@ -69,67 +16,8 @@ body, .main { height: 100%; - &>.container { + & > .container { height: 100%; overflow: auto; } } - -.ant-card { - border-radius: 5px; -} - -h1 { - font-size: 36px; - margin: 0.5em 0 0.3em; -} - -h2 { - font-size: 20px; -} - -h3 { - font-size: 16px; - font-weight: bold; - margin: 1em 0 0.05em; -} - -.top-menu, -.bottom-menu { - background: black; - padding: 5px 10px; - - .brand-menu { - max-width: 329px; - flex: 1; - } -} - -/* Make a button look like a link */ -.link-button { - background-color: transparent; - border: none; - cursor: pointer; - display: inline; - margin: 0; - padding: 0; -} - -.warning-text { - color: @color-warning; -} - -.error-text { - color: @color-error; -} - -.subtitle { - color: #888888; -} - -@color-todo: #FFE381; -@color-done: #70C03F; -@color-blacklist: #EF5555; -@color-pin: #6832DA; -@color-warning: #FFB21D; -@color-error: #EF5555; diff --git a/src/App.tsx b/src/App.tsx index b03f394f..c30cad6e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -21,6 +21,7 @@ import { CreateBanner } from './pages/create-banner' import { PreviewBanner } from './pages/preview-banner' import { PrivateRoute } from './components/login/private-route' import { Help } from './pages/help' +import { Error } from './pages/error' import { Account } from './pages/account' import MenuMain from './components/menu-main' import Navbar from './components/navbar' @@ -80,6 +81,7 @@ const App: React.FC = () => { /> + - - - - - - + + + + + + + diff --git a/src/img/icons/warningtriangle.svg b/src/assets/img/icons/warningtriangle.svg similarity index 100% rename from src/img/icons/warningtriangle.svg rename to src/assets/img/icons/warningtriangle.svg diff --git a/src/img/logo/logo192.png b/src/assets/img/logo/logo192.png similarity index 100% rename from src/img/logo/logo192.png rename to src/assets/img/logo/logo192.png diff --git a/src/img/logo/logo64.png b/src/assets/img/logo/logo64.png similarity index 100% rename from src/img/logo/logo64.png rename to src/assets/img/logo/logo64.png diff --git a/src/assets/style/ant-override.less b/src/assets/style/ant-override.less new file mode 100644 index 00000000..eab98e6c --- /dev/null +++ b/src/assets/style/ant-override.less @@ -0,0 +1,25 @@ +body, +.ant-layout { + background: var(--color-light-black); +} + +body, +.ant-menu, +.ant-input, +.ant-card, +.ant-card-head-title { + font-size: 16px; +} + +.ant-card { + border-radius: 5px; +} + +a { + color: var(--link-color); + + &:active, + &:hover { + color: var(--link-color); + } +} diff --git a/src/assets/style/helper.less b/src/assets/style/helper.less new file mode 100644 index 00000000..1076e8fd --- /dev/null +++ b/src/assets/style/helper.less @@ -0,0 +1,4 @@ +@import './helper/button.less'; +@import './helper/class.less'; +@import './helper/color.less'; +@import './helper/text.less'; diff --git a/src/assets/style/helper/button.less b/src/assets/style/helper/button.less new file mode 100644 index 00000000..de6c15a3 --- /dev/null +++ b/src/assets/style/helper/button.less @@ -0,0 +1,60 @@ +.bg-button { + align-items: center; + background-clip: content-box, border-box !important; + background-origin: border-box !important; + border: solid 2px transparent !important; + box-shadow: 2px 1000px 1px var(--color-black) inset !important; + display: flex; + justify-content: center; + transition: linear-gradient ease 0.6s; + + &.bg-button-default { + background-image: linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, 0)), + linear-gradient(180deg, var(--color-border-dark), var(--color-border-light)) !important; + + @media (hover: hover) and (pointer: fine) { + &:hover { + background-image: linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, 0)), + linear-gradient(0deg, var(--color-border-dark), var(--color-border-light)) !important; + } + } + } +} + +.button-default { + background-clip: content-box, border-box !important; + background-color: var(--color-dark-gray); + background-image: linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, 0)), linear-gradient(180deg, var(--color-border-dark), var(--color-border-light)) !important; + background-origin: border-box !important; + border-radius: 4px; + border: solid 2px transparent !important; + box-shadow: 2px 1000px 1px var(--color-light-black) inset !important; + color: var(--color-white) !important; + display: block; + margin: 0 !important; + text-align: center; + transition: linear-gradient ease 0.6s; + width: 100%; + + @media (hover: hover) and (pointer: fine) { + &:hover { + background-image: linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, 0)), + linear-gradient(0deg, var(--color-border-dark), var(--color-border-light)) !important; + } + } +} + +.positive-action-button { + background: var(--color-positive-green) !important; + color: var(--color-white) !important; + padding: 0.5em 2em; + border: none; + border-radius: 5px; + cursor: pointer; + + &:disabled { + background: var(--color-gray); + color: var(--color-light-gray); + cursor: not-allowed; + } +} diff --git a/src/assets/style/helper/class.less b/src/assets/style/helper/class.less new file mode 100644 index 00000000..979bc29f --- /dev/null +++ b/src/assets/style/helper/class.less @@ -0,0 +1,40 @@ +.mt-1 { + margin-top: 1rem; +} + +.p-1 { + padding: 1rem; +} + +.pl-1 { + padding-left: 1rem; +} + +.pr-1 { + padding-right: 1rem; +} + +.px1 { + padding-left: 1rem; + padding-right: 1rem; +} + +.nobr { + white-space: nowrap; +} + +.page-container { + height: 100%; + display: flex; + flex-direction: column; + justify-content: space-between; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; +} + +.leaflet-container { + margin: unset; + height: 100%; +} diff --git a/src/assets/style/helper/color.less b/src/assets/style/helper/color.less new file mode 100644 index 00000000..11c7f80e --- /dev/null +++ b/src/assets/style/helper/color.less @@ -0,0 +1,11 @@ +.warning-text { + color: var(--color-warning); +} + +.error-text { + color: var(--color-error); +} + +.subtitle { + color: var(--color-gray); +} diff --git a/src/assets/style/helper/text.less b/src/assets/style/helper/text.less new file mode 100644 index 00000000..64d4db8f --- /dev/null +++ b/src/assets/style/helper/text.less @@ -0,0 +1,14 @@ +h1 { + font-size: 36px; + margin: 0.5em 0 0.3em; +} + +h2 { + font-size: 20px; +} + +h3 { + font-size: 16px; + font-weight: bold; + margin: 1em 0 0.05em; +} diff --git a/src/assets/style/mobile.less b/src/assets/style/mobile.less new file mode 100644 index 00000000..600c4469 --- /dev/null +++ b/src/assets/style/mobile.less @@ -0,0 +1,19 @@ +@mobile-detection: ~' screen and (max-width: 880px) '; + +.hide-on-mobile { + @media only @mobile-detection { + display: none !important; + } +} + +.banner-count-place { + @media only @mobile-detection { + display: none; + } +} + +.hide-on-desktop { + @media not @mobile-detection { + display: none !important; + } +} diff --git a/src/assets/style/variables.less b/src/assets/style/variables.less new file mode 100644 index 00000000..f4832056 --- /dev/null +++ b/src/assets/style/variables.less @@ -0,0 +1,37 @@ +:root { + --color-white: #fff; + --color-white-light: #eaeaea; + --color-black: #000; + --color-light-black: #1b1b1b; + --color-gray: #888888; + --color-light-gray: #d3d3d3; + --color-dark-gray: #2e2e2e; + + --color-todo: #ffe381; + --color-done: #70c03f; + --color-blacklist: #ef5555; + --color-pin: #6832da; + --color-warning: #ffb21d; + --color-error: #ef5555; + --color-missing: #ff2f2f; + + --primary-color: #1da57a; + --link-color: #1da57a; + --color-active-green: #0ca589; + + --body-background: #0b0c0d; + --border-color-base: #004f4a; + --scrollbar-color: #969696; + + --card-head-padding: 0.6rem; + --card-padding-base: 0.6rem; + + --color-panel-bg: #404040; + --color-border-dark: #109393; + --color-positive-green: #077561; + --color-border-light: #15d4b2; + --color-positive-green-light: #16d4b2; + + --color-enlightened: #02bf02; + --color-resistance: #0492d0; +} diff --git a/src/components/Issues-list/IssueCard.tsx b/src/components/Issues-list/IssueCard.tsx index ec447ceb..ec243117 100644 --- a/src/components/Issues-list/IssueCard.tsx +++ b/src/components/Issues-list/IssueCard.tsx @@ -2,7 +2,7 @@ import { Button } from 'antd' import React, { FC } from 'react' import { Issue } from './Issue' -import SVGCross from '../../img/icons/cross.svg?react' +import SVGCross from '../../assets/img/icons/cross.svg?react' const IssueCard: FC = ({ issue, onCloseIssue }) => { const onClose = () => { diff --git a/src/components/Issues-list/issues.less b/src/components/Issues-list/issues.less index 67889985..1dd569d3 100644 --- a/src/components/Issues-list/issues.less +++ b/src/components/Issues-list/issues.less @@ -5,18 +5,18 @@ } .issue-card { - background: rgba(46, 46, 46, 0.9); + background: rgba(var(--color-dark-gray), 0.9); border-radius: 4px; padding: 10px 20px; font-size: 14px; line-height: 2.5; - + &.issue-error { - color: #FF2F2F; + color: var(--color-error); } &.issue-warning { - color: #FFB21D; + color: var(--color-warning); } button { @@ -25,7 +25,7 @@ padding: 10px 0; path { - fill: lightgrey; + fill: var(--color-light-gray); } } -} \ No newline at end of file +} diff --git a/src/components/advanced-options/AdvancedOptions.tsx b/src/components/advanced-options/AdvancedOptions.tsx index 3bcba4e6..491fbb22 100644 --- a/src/components/advanced-options/AdvancedOptions.tsx +++ b/src/components/advanced-options/AdvancedOptions.tsx @@ -3,7 +3,7 @@ import { Col, Radio, Row, Slider, Tooltip } from 'antd' import { Trans, useTranslation } from 'react-i18next' import { BannerType } from '../../features/banner' -import SVGHelp from '../../img/icons/help-round.svg?react' +import SVGHelp from '../../assets/img/icons/help-round.svg?react' import './advanced-options.less' import { DatePicker } from '../date-picker/DatePicker' diff --git a/src/components/advanced-options/advanced-options.less b/src/components/advanced-options/advanced-options.less index cd690057..861337aa 100644 --- a/src/components/advanced-options/advanced-options.less +++ b/src/components/advanced-options/advanced-options.less @@ -1,5 +1,4 @@ .banner-advanced-options { - h4 { display: flex; column-gap: 5px; @@ -8,13 +7,22 @@ align-self: flex-start; path { - fill: white; + fill: var(--color-white); } } } - .ant-col { - align-self: center; + .ant { + &-col { + align-self: center; + } + + &-slider { + &-track, + &-handle { + background-color: var(--link-color) !important; + } + } } label { @@ -22,16 +30,16 @@ } .date-picker-hidden { - position: absolute; - visibility: hidden; - width: 0; height: 0; + position: absolute; right: 0; top: 0; + visibility: hidden; + width: 0; } .date-picker-visible { - width: 100%; margin-bottom: 5px; + width: 100%; } -} \ No newline at end of file +} diff --git a/src/components/agent/agent.less b/src/components/agent/agent.less index 2c2896ec..5047a61e 100644 --- a/src/components/agent/agent.less +++ b/src/components/agent/agent.less @@ -1,7 +1,7 @@ -.faction-enlightened { - color: #02bf02; -} - -.faction-resistance { - color: #0492d0; -} +.faction-enlightened { + color: var(--color-enlightened); +} + +.faction-resistance { + color: var(--color-resistance); +} diff --git a/src/components/algorithm-detection-chooser/AlgorithmDetectionChooser.tsx b/src/components/algorithm-detection-chooser/AlgorithmDetectionChooser.tsx index 2a74fdb1..314dc828 100644 --- a/src/components/algorithm-detection-chooser/AlgorithmDetectionChooser.tsx +++ b/src/components/algorithm-detection-chooser/AlgorithmDetectionChooser.tsx @@ -2,7 +2,7 @@ import React, { FC } from 'react' import { Radio, Tooltip } from 'antd' import { Trans, useTranslation } from 'react-i18next' -import SVGHelp from '../../img/icons/help-round.svg?react' +import SVGHelp from '../../assets/img/icons/help-round.svg?react' import './algorithm-detection-chooser.less' diff --git a/src/components/algorithm-detection-chooser/algorithm-detection-chooser.less b/src/components/algorithm-detection-chooser/algorithm-detection-chooser.less index e9ffbef0..9a8f4b7f 100644 --- a/src/components/algorithm-detection-chooser/algorithm-detection-chooser.less +++ b/src/components/algorithm-detection-chooser/algorithm-detection-chooser.less @@ -12,7 +12,7 @@ align-self: flex-start; path { - fill: white; + fill: var(--color-white); } } } @@ -26,36 +26,36 @@ &.display-false { display: none; } - } - - .lds-ellipsis div { - position: absolute; - top: 0px; - width: 8px; - height: 8px; - border-radius: 50%; - background: #fff; - animation-timing-function: cubic-bezier(0, 1, 1, 0); - } - .lds-ellipsis div:nth-child(1) { - left: 0px; - animation: lds-ellipsis1 0.6s infinite; - } + div { + position: absolute; + top: 0; + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--color-white); + animation-timing-function: cubic-bezier(0, 1, 1, 0); + + &:nth-child(1) { + left: 0; + animation: lds-ellipsis1 0.6s infinite; + } - .lds-ellipsis div:nth-child(2) { - left: 0px; - animation: lds-ellipsis2 0.6s infinite; - } + &:nth-child(2) { + left: 0; + animation: lds-ellipsis2 0.6s infinite; + } - .lds-ellipsis div:nth-child(3) { - left: 16px; - animation: lds-ellipsis2 0.6s infinite; - } + &:nth-child(3) { + left: 16px; + animation: lds-ellipsis2 0.6s infinite; + } - .lds-ellipsis div:nth-child(4) { - left: 32px; - animation: lds-ellipsis3 0.6s infinite; + &:nth-child(4) { + left: 32px; + animation: lds-ellipsis3 0.6s infinite; + } + } } @keyframes lds-ellipsis1 { @@ -87,4 +87,4 @@ transform: translate(16px, 0); } } -} \ No newline at end of file +} diff --git a/src/components/announcement/announcement.less b/src/components/announcement/announcement.less index ac7fe353..2adb76c1 100644 --- a/src/components/announcement/announcement.less +++ b/src/components/announcement/announcement.less @@ -1,8 +1,8 @@ -.announcement-item { - background: #2e2e2e; - border-radius: 5px; - padding: 20px; - color: white; - margin-bottom: 10px; - line-height: 19px; -} +.announcement-item { + background: var(--color-dark-gray); + border-radius: 5px; + padding: 20px; + color: white; + margin-bottom: 10px; + line-height: 19px; +} diff --git a/src/components/banner-card/BannerCard.tsx b/src/components/banner-card/BannerCard.tsx index 66310e52..1af9697b 100644 --- a/src/components/banner-card/BannerCard.tsx +++ b/src/components/banner-card/BannerCard.tsx @@ -10,9 +10,9 @@ import { import { createBrowseUri } from '../../features/place' import { Distance } from '../distance/Distance' import BannerPicture from './BannerPicture' -import SVGExplorer from '../../img/icons/explorer.svg?react' -import SVGWarningTriangle from '../../img/icons/warningtriangle.svg?react' -import SVGPointer from '../../img/icons/pointer.svg?react' +import SVGExplorer from '../../assets/img/icons/explorer.svg?react' +import SVGWarningTriangle from '../../assets/img/icons/warningtriangle.svg?react' +import SVGPointer from '../../assets/img/icons/pointer.svg?react' import './banner-card.less' diff --git a/src/components/banner-card/BannerPicture.tsx b/src/components/banner-card/BannerPicture.tsx index 10321f58..ae1ca696 100644 --- a/src/components/banner-card/BannerPicture.tsx +++ b/src/components/banner-card/BannerPicture.tsx @@ -5,7 +5,7 @@ import Scrollbars from 'react-custom-scrollbars-2' import { Trans } from 'react-i18next' import { useLoaded } from '../../hooks/Loaded' -import SVGMinimize from '../../img/icons/minimize.svg?react' +import SVGMinimize from '../../assets/img/icons/minimize.svg?react' const getImageAnimation = ( innerDiv: HTMLDivElement | null, diff --git a/src/components/banner-card/banner-card.less b/src/components/banner-card/banner-card.less index d2fb9716..62fe673d 100644 --- a/src/components/banner-card/banner-card.less +++ b/src/components/banner-card/banner-card.less @@ -1,9 +1,12 @@ @import url(../../App.less); -// Start Temporary styles for list types. Not final yet. +@mobile-detection: ~' screen and (max-width: 880px) '; +@mobile-l-detection: ~' screen and (min-width: 426px) '; + +// Start Temporary styles for list types. Not final yet. .list-style-background() { - content: " "; + content: ' '; z-index: 10; display: block; position: absolute; @@ -15,24 +18,6 @@ border-radius: 5px; } -.banner-card.list-style-todo:after { - .list-style-background(); - background: rgba(@color-todo, 0.05); - border: 1px solid @color-todo; -} - -.banner-card.list-style-done:after { - .list-style-background(); - background: rgba(@color-done, 0.05); - border: 1px solid @color-done; -} - -.banner-card.list-style-blacklist:after { - .list-style-background(); - background: rgba(@color-blacklist, 0.05); - border: 1px solid @color-blacklist; -} - // End temporary Styles ^^ .banner-circle { @@ -42,28 +27,53 @@ width: 60px; height: 60px; border-radius: 50%; - background-color: grey; + background-color: var(--color-gray); margin-right: 8px; margin-top: 8px; } .banner-card { - background: #2e2e2e; + background: var(--color-dark-gray); border-radius: 5px; - border: #2e2e2e 2px solid; + border: var(--color-dark-gray) 2px solid; padding: 18px; - color: white; + color: var(--color-white); position: relative; &.selected { - border-color: #16d4b2; + border-color: var(--color-positive-green-light); + } + + &.list-style { + &-todo { + &:after { + .list-style-background(); + background: rgba(var(--color-todo), 0.05); + border: 1px solid var(--color-todo); + } + } + + &-done { + &:after { + .list-style-background(); + background: rgba(var(--color-done), 0.05); + border: 1px solid var(--color-done); + } + } + + &-blacklist { + &:after { + .list-style-background(); + background: rgba(var(--color-blacklist), 0.05); + border: 1px solid var(--color-blacklist); + } + } } .icon { width: 0.9rem; height: 0.9rem; } - } .banner-card-modal { @@ -73,7 +83,7 @@ height: 100%; width: 100%; display: flex; - background-color: #2e2e2e; + background-color: var(--color-dark-gray); .ant-modal-body { width: 100%; @@ -106,7 +116,6 @@ &.full-size { img { max-height: initial; - max-width: initial; } } } @@ -114,11 +123,11 @@ .close-button { position: absolute; bottom: 15px; - background-color: #2e2e2e; + background-color: var(--color-dark-gray); right: 15px; border: none; line-height: 1em; - color: white !important; + color: var(--color-white) !important; svg, span { @@ -137,10 +146,14 @@ position: relative; display: flex; + @media only @mobile-l-detection { + height: 200px; + } + .offline-overlay{ font-size: 24px; line-height: 18px; - color: #DDDDDD; + color: var(--color-light-gray); position: absolute; left: -20px; @@ -152,9 +165,9 @@ flex-direction: column; justify-content: center; - pointer-events: none; - - .offline-overlay-line { + pointer-events: none; + + .offline-overlay-line { justify-content: center; align-items: center; width: 100%; @@ -181,7 +194,7 @@ .banner-info-item { font-size: 14px; line-height: 18px; - color: #DDDDDD; + color: var(--color-light-gray); margin-top: 4px; display: flex; @@ -195,7 +208,7 @@ } .banner-info-item.warning { - color: @color-blacklist; + color: var(--color-blacklist); } @@ -206,6 +219,21 @@ align-items: center; justify-content: center; overflow: hidden; + @media only @mobile-detection { + height: auto; + aspect-ratio: 2; + } + &.banner-lines-1 { + @media only @mobile-detection { + aspect-ratio: 6; + } + } + + &.banner-lines-2 { + @media only @mobile-detection { + aspect-ratio: 3; + } + } } .banner-card-picture-inner { @@ -241,11 +269,11 @@ display: flex; flex-direction: column; align-items: flex-end; - padding: 0px; + padding: 0; margin-top: 10px; a { - border: 1px solid white; + border: 1px solid var(--color-white); box-sizing: border-box; border-radius: 4px; padding: 5px 10px; @@ -254,8 +282,7 @@ } } - -// Support for browsers that don't support aspect-ratio yet. +// Support for browsers that don't support aspect-ratio yet. // Can be removed once this feature is implemented in all major browsers @supports (aspect-ratio: 1/1) { diff --git a/src/components/banner-edit-tools/BannerEditTools.tsx b/src/components/banner-edit-tools/BannerEditTools.tsx index f0e876a3..d2aadf1d 100644 --- a/src/components/banner-edit-tools/BannerEditTools.tsx +++ b/src/components/banner-edit-tools/BannerEditTools.tsx @@ -39,21 +39,33 @@ export const BannerEditTools: FC = ({ banner }) => { const buttons = [] if (creatorPluginAvailable) { buttons.push( - ) } if (owner || authenticated) { buttons.push( - ) } if (authenticated) { buttons.push( - ) diff --git a/src/components/banner-edit-tools/banner-edit-tools.less b/src/components/banner-edit-tools/banner-edit-tools.less index 38567945..ef836a50 100644 --- a/src/components/banner-edit-tools/banner-edit-tools.less +++ b/src/components/banner-edit-tools/banner-edit-tools.less @@ -14,7 +14,7 @@ &.positive-action-button { border-color: transparent; - background-color: #077561; + background-color: var(--color-positive-green); } &.negative-action-button { diff --git a/src/components/banner-info-card/BannerInfoCard.tsx b/src/components/banner-info-card/BannerInfoCard.tsx index 8cf29942..466ff1ec 100644 --- a/src/components/banner-info-card/BannerInfoCard.tsx +++ b/src/components/banner-info-card/BannerInfoCard.tsx @@ -1,6 +1,7 @@ import React, { FC, Fragment } from 'react' import _ from 'underscore' import { LatLng } from 'leaflet' +import Markdown from 'react-markdown' import { Trans, useTranslation } from 'react-i18next' import { TFunction } from 'i18next' import { Tooltip } from 'antd' @@ -25,13 +26,13 @@ import IfUserLoggedIn from '../login/if-user-logged-in' import IfUserLoggedOut from '../login/if-user-logged-out' import LoginButton from '../login/login-button' import { hasLatLng } from '../map-detail/showBannerRouteOnMap' -import SVGList from '../../img/icons/list.svg?react' -import SVGExplorer from '../../img/icons/explorer.svg?react' -import SVGTimer from '../../img/icons/timer.svg?react' -import SVGHand from '../../img/icons/hand.svg?react' -import SVGCompass from '../../img/icons/compass.svg?react' -import SVGChecked from '../../img/icons/checked.svg?react' -import SVGOffline from '../../img/icons/offline.svg?react' +import SVGList from '../../assets/img/icons/list.svg?react' +import SVGExplorer from '../../assets/img/icons/explorer.svg?react' +import SVGTimer from '../../assets/img/icons/timer.svg?react' +import SVGHand from '../../assets/img/icons/hand.svg?react' +import SVGCompass from '../../assets/img/icons/compass.svg?react' +import SVGChecked from '../../assets/img/icons/checked.svg?react' +import SVGOffline from '../../assets/img/icons/offline.svg?react' import i18n from '../../i18n' import './banner-info-card.less' @@ -282,7 +283,7 @@ const getInGameTime = (banner: Banner, t: TFunction) => {
{totalTimeInMS === 0 ? ( - {t('banners.missingData')} + {t('missingData')} ) : ( @@ -399,11 +400,34 @@ const getStartPointButton = (banner: Banner, t: TFunction) => { const BannerInfoCard: FC = ({ banner }) => { const { t } = useTranslation() + const allowedElements = [ + 'p', + 'br', + 'b', + 'strong', + 'em', + 'ul', + 'ol', + 'li', + 'a', + ] return (
{getEvent(banner, t)} - {banner.warning &&

{banner.warning}

} - {banner.description &&

{banner.description}

} + {banner.warning && ( + + {banner.warning} + + )} + {banner.description && ( + + {banner.description} + + )} {getCreatedBy(banner, t)}

diff --git a/src/components/banner-info-card/banner-info-card.less b/src/components/banner-info-card/banner-info-card.less index 4cb11b7b..993fd617 100644 --- a/src/components/banner-info-card/banner-info-card.less +++ b/src/components/banner-info-card/banner-info-card.less @@ -1,5 +1,5 @@ .banner-info-card { - background: #2E2E2E; + background: var(--color-dark-gray); border-radius: 4px; padding: 15px; font-size: 16px; @@ -67,27 +67,25 @@ .banner-info-button { margin: 0 !important; - background-color: #2e2e2e; - border: none; + background-color: var(--color-dark-gray); display: block; border-radius: 4px; padding: 10px; width: 100%; margin-top: 15px !important; - box-shadow: 0 0 2px 0 rgba(157, 96, 212, 0.5) !important; border: solid 2px transparent !important; background-origin: border-box !important; background-clip: content-box, border-box !important; - box-shadow: 2px 1000px 1px #2e2e2e inset !important; + box-shadow: 2px 1000px 1px var(--color-dark-gray) inset !important; transition: linear-gradient ease 0.6s; text-align: center; color: white; - background-image: linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, 0)), linear-gradient(180deg, #109393, #15D4B2) !important; + background-image: linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, 0)), linear-gradient(180deg, var(--color-border-dark), var(--color-border-light)) !important; @media (hover: hover) and (pointer: fine) { &:hover { - background-image: linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, 0)), linear-gradient(0deg, #109393, #15D4B2) !important; + background-image: linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, 0)), linear-gradient(0deg, var(--color-border-dark), var(--color-border-light)) !important; } } } -} \ No newline at end of file +} diff --git a/src/components/banner-info-mobile-switch/BannerInfoMobileSwitch.tsx b/src/components/banner-info-mobile-switch/BannerInfoMobileSwitch.tsx index 6d29a438..2f12c708 100644 --- a/src/components/banner-info-mobile-switch/BannerInfoMobileSwitch.tsx +++ b/src/components/banner-info-mobile-switch/BannerInfoMobileSwitch.tsx @@ -2,7 +2,7 @@ import React, { FC } from 'react' import { useTranslation } from 'react-i18next' import { useHistory } from 'react-router' -import SVGBackArrow from '../../img/icons/back-arrow.svg?react' +import SVGBackArrow from '../../assets/img/icons/back-arrow.svg?react' import './banner-info-mobile-switch.less' diff --git a/src/components/banner-info-mobile-switch/banner-info-mobile-switch.less b/src/components/banner-info-mobile-switch/banner-info-mobile-switch.less index 230fa9c4..b2d84d6a 100644 --- a/src/components/banner-info-mobile-switch/banner-info-mobile-switch.less +++ b/src/components/banner-info-mobile-switch/banner-info-mobile-switch.less @@ -1,77 +1,75 @@ -.banner-info-mobile-switch{ - display: flex; - flex-direction: column; - background-color: black; - padding-bottom: 5px; - padding-right: 10px; - padding-left: 10px; - font-weight: 400; +.banner-info-mobile-switch { + display: flex; + flex-direction: column; + background-color: black; + padding-bottom: 5px; + padding-right: 10px; + padding-left: 10px; + font-weight: 400; - .banner-info-mobile-switch-back { - flex: 0; - - svg{ - height: 1em; - margin-top: 5px; - } - } - - .mobile-switch-title-row { - align-items: center; - display: flex; - flex-direction: row; - padding-top: 5px; - padding-bottom: 5px; + .banner-info-mobile-switch-back { + flex: 0; + svg { + height: 1em; + margin-top: 5px; } + } - .mobile-switch-tabs-row { - align-items: center; - display: flex; - flex-direction: row; - } + .mobile-switch-title-row { + align-items: center; + display: flex; + flex-direction: row; + padding-top: 5px; + padding-bottom: 5px; + } - .mobile-switch-title { - width: 100%; - font-size: 20px; - white-space: nowrap; - overflow-x: hidden; - text-overflow: ellipsis; - } + .mobile-switch-tabs-row { + align-items: center; + display: flex; + flex-direction: row; + } - button { - background-color: transparent; - outline: none; - border: none; - cursor: pointer; - width: 33%; - font-size: 16px; + .mobile-switch-title { + width: 100%; + font-size: 20px; + white-space: nowrap; + overflow-x: hidden; + text-overflow: ellipsis; + } + button { + background-color: transparent; + outline: none; + border: none; + cursor: pointer; + width: 33%; + font-size: 16px; - &.active { - border-radius: 4px; - border: 2px solid #0ca589 !important; - } + &.active { + border-radius: 4px; + border: 2px solid var(--color-active-green) !important; } + } - .positive-action-button { - background: #077561; - color: white; - padding: 0.5em 2em; - border: none; - border-radius: 5px; - cursor: pointer; - - &:disabled { - background: gray; - color: lightgray; - cursor: not-allowed; - } - } + .positive-action-button { + background: var(--color-positive-green); + color: var(--color-white); + padding: 0.5em 2em; + border: none; + border-radius: 5px; + cursor: pointer; - .mobile-switch-submit-button { - flex-grow: 0; - white-space:nowrap; - width: auto; + &:disabled { + background: var(--color-gray); + color: var(--color-light-gray); + cursor: not-allowed; } -} \ No newline at end of file + } + + .mobile-switch-submit-button { + flex-grow: 0; + white-space: nowrap; + width: auto; + } +} diff --git a/src/components/banner-info-overview/banner-info-overview.less b/src/components/banner-info-overview/banner-info-overview.less index ab90015c..2d356d69 100644 --- a/src/components/banner-info-overview/banner-info-overview.less +++ b/src/components/banner-info-overview/banner-info-overview.less @@ -9,7 +9,6 @@ display: flex; flex-direction: column; flex-grow: 1; - width: 100%; padding-right: 4px; width: 370px; @@ -24,12 +23,12 @@ // Hide line below the buttons .ant-tabs-nav::before { border: none; - } + } - // Hide overflow button. We don't need it. - // The screen is never too small to show both buttons + // Hide overflow button. We don't need it. + // The screen is never too small to show both buttons // If we leave it, the screen flackers when resizing the window - // because it is constantly shown and hidden. An alternative would be to + // because it is constantly shown and hidden. An alternative would be to // make the width of the ant-tabs-nav-list smaller or givt it a right margin // or padding .ant-tabs-nav-more { @@ -38,7 +37,7 @@ .ant-tabs-nav-list { width: 100%; - background-color: #2e2e2e; + background-color: var(--color-dark-gray); .ant-tabs-ink-bar { display: none; @@ -46,31 +45,29 @@ .ant-tabs-tab { margin: 0 !important; - background-color: #2e2e2e; - border: none; + background-color: var(--color-dark-gray); border-radius: 4px; width: 100%; - box-shadow: 0 0 2px 0 rgba(157, 96, 212, 0.5) !important; border: solid 2px transparent !important; background-origin: border-box !important; background-clip: content-box, border-box !important; - box-shadow: 2px 1000px 1px #2e2e2e inset !important; + box-shadow: 2px 1000px 1px var(--color-dark-gray) inset !important; transition: linear-gradient ease 0.6s; font-size: 16px; .ant-tabs-tab-btn { text-align: center; - color: white; + color: var(--color-white); width: 100%; } } .ant-tabs-tab-active { - background-image: linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, 0)), linear-gradient(180deg, #109393, #15D4B2) !important; + background-image: linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, 0)), linear-gradient(180deg, var(--color-border-dark), var(--color-border-light)) !important; @media (hover: hover) and (pointer: fine) { &:hover { - background-image: linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, 0)), linear-gradient(0deg, #109393, #15D4B2) !important; + background-image: linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, 0)), linear-gradient(0deg, var(--color-border-dark), var(--color-border-light)) !important; } } } diff --git a/src/components/banner-info-with-map/BannerInfoWithMap.tsx b/src/components/banner-info-with-map/BannerInfoWithMap.tsx index 596e1381..e167817e 100644 --- a/src/components/banner-info-with-map/BannerInfoWithMap.tsx +++ b/src/components/banner-info-with-map/BannerInfoWithMap.tsx @@ -12,7 +12,7 @@ import { } from '../banner-info-mobile-switch' import { MapDetail } from '../map-detail' import { IssuesList, Issue } from '../Issues-list' -import SVGBackArrow from '../../img/icons/back-arrow.svg?react' +import SVGBackArrow from '../../assets/img/icons/back-arrow.svg?react' import './banner-info-with-map.less' @@ -64,7 +64,7 @@ class BannerInfoWithMap extends React.Component< this.setState({ expanded: false, expandedMissionIndexes: [] }) } else { let missionIndexes: Array = [] - if (banner && banner.missions) { + if (banner?.missions) { missionIndexes = mapMissions( banner.missions, (mission, index) => mission && index @@ -120,13 +120,13 @@ class BannerInfoWithMap extends React.Component< desktopView, } = this.state - const infoPaneClassName = mobileView !== 'map' ? '' : 'hide-on-mobile' + const infoPaneClassName = mobileView === 'map' ? 'hide-on-mobile' : '' const infoPaneViewClassName = `banner-info-left-pane-${mobileView}` const mapPaneClassName = mobileView === 'map' ? '' : 'hide-on-mobile' this.viewWasMapBefore = this.viewWasMapBefore || mobileView === 'map' - if (banner && banner.missions) { + if (banner?.missions) { const bounds = getBannerBounds(banner) const issues: Array = [] if (!bounds) { diff --git a/src/components/banner-info-with-map/banner-info-with-map.less b/src/components/banner-info-with-map/banner-info-with-map.less index 725d1b4a..9694203e 100644 --- a/src/components/banner-info-with-map/banner-info-with-map.less +++ b/src/components/banner-info-with-map/banner-info-with-map.less @@ -1,3 +1,5 @@ +@mobile-detection: ~' screen and (max-width: 880px) '; + .banner-info-with-map-container { height: 100%; display: flex; @@ -5,6 +7,82 @@ padding-left: 40px; padding-bottom: 40px; padding-right: 40px; + + @media only @mobile-detection { + display: flex !important; + flex-direction: column !important; + height: inherit !important; + padding: 0 !important; + } + + .banner-info-with-map { + @media only @mobile-detection { + margin: 0 !important; + padding: 0 !important; + justify-content: center !important; + height: 100% !important; + overflow-y: auto !important; + } + + .banner-info { + @media only @mobile-detection { + min-height: 0 !important; + padding: 0.6em !important; + width: 100% !important; + max-width: 864px !important; + min-width: 320px !important; + height: auto !important; + overflow-y: unset !important; + } + } + + .banner-info-left-pane-missions { + .banner-card { + @media only @mobile-detection { + display: none !important; + } + } + } + + .mission-card { + @media only @mobile-detection { + max-width: none !important; + } + } + + .banner-info-additional { + @media only @mobile-detection { + height: 100% !important; + } + } + + .leaflet-container { + @media only @mobile-detection { + height: 100% !important; + width: 100% !important; + min-height: 0 !important; + } + } + } + + .banner-info-card { + @media only @mobile-detection { + margin-top: 0 !important; + } + } + + .ant-tabs-nav { + @media only @mobile-detection { + display: none !important; + margin: none !important; + } + } + + .ant-tabs-tabpane { + @media only @mobile-detection { + margin-top: 0; + } + } } .banner-info-with-map-goback { diff --git a/src/components/banner-list-type-control/BannerListTypeControl.tsx b/src/components/banner-list-type-control/BannerListTypeControl.tsx index ba9dee13..31152f70 100644 --- a/src/components/banner-list-type-control/BannerListTypeControl.tsx +++ b/src/components/banner-list-type-control/BannerListTypeControl.tsx @@ -2,9 +2,9 @@ import React, { FC } from 'react' import { Trans, useTranslation } from 'react-i18next' import { BannerListType } from '../../features/banner' -import SVGTodo from '../../img/icons/todo.svg?react' -import SVGDone from '../../img/icons/done.svg?react' -import SVGBlacklist from '../../img/icons/blacklist.svg?react' +import SVGTodo from '../../assets/img/icons/todo.svg?react' +import SVGDone from '../../assets/img/icons/done.svg?react' +import SVGBlacklist from '../../assets/img/icons/blacklist.svg?react' import './banner-list-type-control.less' diff --git a/src/components/banner-list-type-control/banner-list-type-control.less b/src/components/banner-list-type-control/banner-list-type-control.less index 9b4e421b..60310309 100644 --- a/src/components/banner-list-type-control/banner-list-type-control.less +++ b/src/components/banner-list-type-control/banner-list-type-control.less @@ -1,59 +1,65 @@ +@import '../../assets/style/variables.less'; @import '../../App.less'; .banner-list-type-control { - width: 100%; - display: flex; - flex-direction: row; - padding: 5px; - gap: 1em; - - .banner-list-type { - flex: 1; - - text-align: center; - vertical-align: middle; - - cursor: pointer; - - background: none; - outline: none; - border: none; - - svg { - height: 1.1em; - width:1.1em; - margin-right: 5px; - align-self: center; - - position: relative; - top: .125em; - } - } + display: flex; + flex-direction: row; + gap: 1em; + padding: 5px; + width: 100%; - .banner-list-type-todo.active { - color: @color-todo; - } + .banner-list-type { + background: none; + border: none; + cursor: pointer; + flex: 1; + outline: none; + text-align: center; + vertical-align: middle; - .banner-list-type-done.active { - color: @color-done; + svg { + align-self: center; + height: 1.1em; + margin-right: 5px; + position: relative; + top: 0.125em; + width: 1.1em; + } } - .banner-list-type-blacklist.active { - color: @color-blacklist; + .banner-list-type-todo { + &:hover { + @media (hover: hover) and (pointer: fine) { + color: var(--color-todo); + } + } + + &.active { + color: var(--color-todo); + } } - @media (hover: hover) and (pointer: fine) { - .banner-list-type-todo:hover { - color: @color-todo; + .banner-list-type-done { + &:hover { + @media (hover: hover) and (pointer: fine) { + color: var(--color-done); + } + } + + &.active { + color: var(--color-done); + } + } + + .banner-list-type-blacklist { + &:hover { + @media (hover: hover) and (pointer: fine) { + color: var(--color-blacklist); + } + } + + &.active { + color: var(--color-blacklist); } - - .banner-list-type-done:hover { - color: @color-done; - } - - .banner-list-type-blacklist:hover { - color: @color-blacklist; - } - } -} \ No newline at end of file +} diff --git a/src/components/banner-list-type-navigation/banner-list-type-navigation.less b/src/components/banner-list-type-navigation/banner-list-type-navigation.less index c6e200af..83eb400d 100644 --- a/src/components/banner-list-type-navigation/banner-list-type-navigation.less +++ b/src/components/banner-list-type-navigation/banner-list-type-navigation.less @@ -1,7 +1,6 @@ @import '../../App.less'; .banner-list-type-navigation { - margin-bottom: 20px; button { @@ -22,11 +21,11 @@ .active { font-size: 36px; - color: #FFFFFF; + color: var(--color-white); } .inactive { font-size: 28px; - color: #DDDDDD; + color: var(--color-light-gray); } -} \ No newline at end of file +} diff --git a/src/components/banner-list/BannerList.tsx b/src/components/banner-list/BannerList.tsx index 017ac428..9939dd03 100644 --- a/src/components/banner-list/BannerList.tsx +++ b/src/components/banner-list/BannerList.tsx @@ -15,7 +15,7 @@ const BannerList: FC = ({ loadMoreBanners, selectedBannerId, onSelectBanner, - applyBannerListStlyes, + applyBannerListStyles, hideBlacklisted, showDetailsButton, }) => { @@ -84,7 +84,7 @@ const BannerList: FC = ({ : undefined } linkStartPlace={false} - applyBannerListStlye={applyBannerListStlyes} + applyBannerListStlye={applyBannerListStyles} /> ) return ( @@ -117,7 +117,7 @@ export interface BannerListProps { selectedBannerId?: string loadMoreBanners?: () => Promise onSelectBanner?: (banner: Banner) => void - applyBannerListStlyes: boolean + applyBannerListStyles: boolean hideBlacklisted: boolean showDetailsButton: boolean } diff --git a/src/components/banner-list/banner-list.less b/src/components/banner-list/banner-list.less index 0d514c3f..e4dc6727 100644 --- a/src/components/banner-list/banner-list.less +++ b/src/components/banner-list/banner-list.less @@ -1,23 +1,42 @@ -.banner-list { - display: flex; - align-content: flex-start; - flex-wrap: wrap; - align-items: flex-start; - flex-direction: row; - column-gap: 20px; - row-gap: 20px; - - .banner-list-entry { - max-width: 90vw; - width: 360px; - } - - .banner-card-link { - height: 100%; - width: 100%; - border: none; - background: none; - text-align: initial; - font-size: initial; - } -} +@mobile-xs-detection: ~' screen and (max-width: 321px) '; +@mobile-detection: ~' screen and (max-width: 880px) '; + +.banner-list { + display: flex; + align-content: flex-start; + flex-wrap: wrap; + align-items: flex-start; + flex-direction: row; + column-gap: 20px; + row-gap: 20px; + + @media only @mobile-xs-detection { + justify-content: center; + } + + @media only @mobile-detection { + justify-content: center; + } + + .banner-list-entry { + max-width: 90vw; + width: 360px; + + @media only @mobile-xs-detection { + width: 296px; + } + + @media only @mobile-detection { + width: 360px; + } + } + + .banner-card-link { + height: 100%; + width: 100%; + border: none; + background: none; + text-align: initial; + font-size: initial; + } +} diff --git a/src/components/banner-order-chooser/BannerOrderChooser.tsx b/src/components/banner-order-chooser/BannerOrderChooser.tsx index 88463896..d78bbfe2 100644 --- a/src/components/banner-order-chooser/BannerOrderChooser.tsx +++ b/src/components/banner-order-chooser/BannerOrderChooser.tsx @@ -2,7 +2,7 @@ import { Modal } from 'antd' import React, { FC, useEffect, useState } from 'react' import { Trans, useTranslation } from 'react-i18next' -import SVGBackArrowSmall from '../../img/icons/back-arrow-small.svg?react' +import SVGBackArrowSmall from '../../assets/img/icons/back-arrow-small.svg?react' import './banner-order-chooser.less' import { BannerFilter, BannerOrder } from '../../features/banner/filter' @@ -19,7 +19,6 @@ const BannerOrderChooser: FC = ({ }) => { const [open, setOpen] = useState(false) const [loadingLocation, setLoadingLocation] = useState(false) - const [currentFilter, setCurrentFilter] = useState(filter) const { t } = useTranslation() useEffect(() => { if (loadingLocation) { @@ -27,7 +26,7 @@ const BannerOrderChooser: FC = ({ (pos) => { setLoadingLocation(false) updateFilter({ - ...currentFilter, + ...filter, orderBy: 'proximityStartPoint', orderDirection: 'ASC', proximityLatitude: pos.coords.latitude, @@ -40,7 +39,7 @@ const BannerOrderChooser: FC = ({ { maximumAge: 0, enableHighAccuracy: true } ) } - }) + }, [loadingLocation, setLoadingLocation, filter]) const show = () => { setOpen(true) @@ -52,7 +51,6 @@ const BannerOrderChooser: FC = ({ } const updateFilter = (newFilter: BannerFilter) => { - setCurrentFilter(newFilter) onFilterChanged(newFilter) } @@ -68,51 +66,51 @@ const BannerOrderChooser: FC = ({ } const onOrderClicked = (type: BannerOrder) => { - if (type !== currentFilter.orderBy) { + if (type !== filter.orderBy) { if (type === 'proximityStartPoint') { setLoadingLocation(true) } else { updateFilter({ - ...currentFilter, + ...filter, orderBy: type, orderDirection: getDefaultDirection(type), proximityLatitude: undefined, proximityLongitude: undefined, }) } - } else if (hasBothDirections(currentFilter.orderBy)) { + } else if (hasBothDirections(filter.orderBy)) { updateFilter({ - ...currentFilter, - orderDirection: currentFilter.orderDirection === 'ASC' ? 'DESC' : 'ASC', + ...filter, + orderDirection: filter.orderDirection === 'ASC' ? 'DESC' : 'ASC', }) } } const onOfficialChanged = (includeUnofficial: boolean) => { updateFilter({ - ...currentFilter, + ...filter, onlyOfficialMissions: includeUnofficial ? undefined : true, }) } const onOnlineChanged = (showOffline: boolean) => { updateFilter({ - ...currentFilter, + ...filter, online: showOffline ? undefined : true, }) } const getButtonClass = (type: BannerOrder) => { let classNames = 'order-button' - if (type === currentFilter.orderBy) { + if (type === filter.orderBy) { classNames += ' selected' } return classNames } const getButtonDirection = (type: BannerOrder) => { - return type === currentFilter.orderBy - ? currentFilter.orderDirection + return type === filter.orderBy + ? filter.orderDirection : getDefaultDirection(type) } @@ -147,16 +145,13 @@ const BannerOrderChooser: FC = ({

{t('order.showOfflineBanners')}

- +
{includeOfficial && (

{t('order.showUnofficialBanners')}

@@ -190,8 +185,8 @@ const BannerOrderChooser: FC = ({ components={{ order: ( ), }} @@ -199,10 +194,10 @@ const BannerOrderChooser: FC = ({ {' / '} )} - {currentFilter.online + {filter.online ? t('order.text.excludeOffline') : t('order.text.includeOffline')} - {currentFilter.onlyOfficialMissions && ( + {filter.onlyOfficialMissions && ( <> {' / '} {t('order.onlyOfficial')} diff --git a/src/components/banner-order-chooser/Order.tsx b/src/components/banner-order-chooser/Order.tsx index 263b4730..a3165bbb 100644 --- a/src/components/banner-order-chooser/Order.tsx +++ b/src/components/banner-order-chooser/Order.tsx @@ -1,7 +1,7 @@ import React, { FC } from 'react' import { Trans, useTranslation } from 'react-i18next' -import SVGUpArrow from '../../img/icons/up-arrow.svg?react' +import SVGUpArrow from '../../assets/img/icons/up-arrow.svg?react' import './order.less' import { BannerOrder, BannerOrderDirection } from '../../features/banner/filter' @@ -9,6 +9,7 @@ import { BannerOrder, BannerOrderDirection } from '../../features/banner/filter' export const hasBothDirections = (type: BannerOrder) => { switch (type) { case 'relevance': + case 'proximityStartPoint': return false default: return true diff --git a/src/components/banner-order-chooser/banner-order-chooser.less b/src/components/banner-order-chooser/banner-order-chooser.less index 3518afc8..2770eb8f 100644 --- a/src/components/banner-order-chooser/banner-order-chooser.less +++ b/src/components/banner-order-chooser/banner-order-chooser.less @@ -16,7 +16,7 @@ cursor: pointer; &.selected { - background-image: linear-gradient(180deg, #109393, #15D4B2); + background-image: linear-gradient(180deg, var(--color-border-dark), var(--color-border-light)); padding: 2px; .order-button-inner { @@ -25,7 +25,7 @@ } .order-button-inner { - background-color: #1B1B1B; + background-color: var(--color-light-black); border-radius: 4px; flex: 1; padding: 5px 10px; diff --git a/src/components/banners-accordion/BannersAccordion.tsx b/src/components/banners-accordion/BannersAccordion.tsx index ca0f7e36..6f39c6a7 100644 --- a/src/components/banners-accordion/BannersAccordion.tsx +++ b/src/components/banners-accordion/BannersAccordion.tsx @@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next' import { Banner } from '../../features/banner' import BannerCard from '../banner-card' import BannerList from '../banner-list' -import SVGTriangle from '../../img/icons/triangle.svg?react' +import SVGTriangle from '../../assets/img/icons/triangle.svg?react' import './banners-accordion.less' import BannerOrderChooser from '../banner-order-chooser' @@ -78,7 +78,7 @@ const BannerAccordion: FC = ({ hasMoreBanners={hasMoreBanners} onSelectBanner={onSelectBannerCallback} loadMoreBanners={loadMoreBanners} - applyBannerListStlyes + applyBannerListStyles hideBlacklisted showDetailsButton /> diff --git a/src/components/banners-accordion/banners-accordion.less b/src/components/banners-accordion/banners-accordion.less index 17d3500c..ac62c812 100644 --- a/src/components/banners-accordion/banners-accordion.less +++ b/src/components/banners-accordion/banners-accordion.less @@ -3,7 +3,7 @@ bottom: 0; height: 40px; width: 100%; - background-color: #1B1B1B; + background-color: var(--color-light-black); flex-direction: column; .filter-and-sort { @@ -32,7 +32,7 @@ margin: 0 10px; overflow-y: scroll; } - + &.expanded { height: 100%; max-height: 100%; @@ -58,4 +58,4 @@ } } -} \ No newline at end of file +} diff --git a/src/components/date-picker/DatePicker.tsx b/src/components/date-picker/DatePicker.tsx index 0277b693..97ac9468 100644 --- a/src/components/date-picker/DatePicker.tsx +++ b/src/components/date-picker/DatePicker.tsx @@ -2,7 +2,7 @@ import React, { ChangeEvent, useRef } from 'react' import { PlainDate } from '../plain-date' -import SVGEdit from '../../img/icons/edit.svg?react' +import SVGEdit from '../../assets/img/icons/edit.svg?react' export const DatePicker: React.FC = ({ value, diff --git a/src/components/duration/Duration.tsx b/src/components/duration/Duration.tsx index 25205183..b666fad4 100644 --- a/src/components/duration/Duration.tsx +++ b/src/components/duration/Duration.tsx @@ -12,8 +12,12 @@ const toPrecisionByFactor = (x: number, base: number, precision: number) => { } const roundDuration = (durationSeconds: number) => { + if (durationSeconds < 100) { + // Less than 100 seconds + return toPrecisionByFactor(durationSeconds, 1, 1) + } if (durationSeconds < SECONDS_IN_MINUTE * 10) { - // Less than 10 minutes + // Between 100 seconds and 10 minutes return toPrecisionByFactor(durationSeconds, 1, 2) } if (durationSeconds < SECONDS_IN_HOUR * 10) { diff --git a/src/components/events-preview/EventsPreview.tsx b/src/components/events-preview/EventsPreview.tsx index b3e59bdc..986b27b0 100644 --- a/src/components/events-preview/EventsPreview.tsx +++ b/src/components/events-preview/EventsPreview.tsx @@ -26,7 +26,7 @@ const EventsPreview: React.FC = () => { hasMoreBanners={false} hideBlacklisted={false} showDetailsButton={false} - applyBannerListStlyes={true} + applyBannerListStyles={true} /> {data.length >= 4 && (
diff --git a/src/components/faq-question/faq-question.less b/src/components/faq-question/faq-question.less index 58d9d92f..dcbbeaae 100644 --- a/src/components/faq-question/faq-question.less +++ b/src/components/faq-question/faq-question.less @@ -1,16 +1,16 @@ .faq-question { - background-color: #2e2e2e; + background-color: var(--color-dark-gray); border-radius: 5px; .faq-question-title { background: none; border: none; - padding: 15px; + color: var(--color-white); cursor: pointer; - width: 100%; - text-align: left; display: block; - color: white; + padding: 15px; + text-align: left; + width: 100%; } .faq-question-answer { diff --git a/src/components/footer-main/FooterMain.tsx b/src/components/footer-main/FooterMain.tsx index bdad4922..bda81fad 100644 --- a/src/components/footer-main/FooterMain.tsx +++ b/src/components/footer-main/FooterMain.tsx @@ -3,28 +3,14 @@ import { Trans } from 'react-i18next' import { getExternalLinkAttributes } from '../../features/utils' -// import SVGInstagram from '../../img/icons/instagram.svg?react' -// import SVGTwitter from '../../img/icons/twitter.svg?react' -import SVGTelegram from '../../img/icons/telegram-bg.svg?react' -import SVGIngress from '../../img/icons/intel.svg?react' +import SVGTelegram from '../../assets/img/icons/telegram-bg.svg?react' +import SVGIngress from '../../assets/img/icons/intel.svg?react' import './footer.less' const FooterMain: React.FC = () => (
- {/* - - - - - */} diff --git a/src/components/footer-main/footer.less b/src/components/footer-main/footer.less index d0e98943..e65b20a7 100644 --- a/src/components/footer-main/footer.less +++ b/src/components/footer-main/footer.less @@ -1,4 +1,9 @@ .footer-main { + text-align: center; + background-color: var(--color-black); + padding: 1.5rem 0; + width: 100%; + .footer-links { padding-bottom: 1em; display: flex; @@ -6,18 +11,18 @@ column-gap: 25px; width: 100%; justify-content: center; - svg { - width: 20px; - height: 20px; - path { - fill: white; - fill-opacity: 1 !important; - } + + svg { + width: 20px; + height: 20px; + path { + fill: var(--color-white); + fill-opacity: 1 !important; } - + } } .footer-disclaimers { font-size: 12px; } -} \ No newline at end of file +} diff --git a/src/components/infinite-banner-list/InfiniteBannerList.tsx b/src/components/infinite-banner-list/InfiniteBannerList.tsx index d519f7b8..e3b91f93 100644 --- a/src/components/infinite-banner-list/InfiniteBannerList.tsx +++ b/src/components/infinite-banner-list/InfiniteBannerList.tsx @@ -1,4 +1,4 @@ -import { FC, useState } from 'react' +import { FC, useEffect, useState } from 'react' import { BannerFilter } from '../../features/banner/filter' import { useBannerList } from '../../features/banner/hooks' import BannerList from '../banner-list' @@ -19,6 +19,10 @@ const InfiniteBannerList: FC = ({ setMaxPages(1) } + useEffect(() => { + onFilterChanged(initialFilter) + }, [initialFilter]) + return (
= ({ setMaxPages(maxPages + 1) } }} - applyBannerListStlyes + applyBannerListStyles hideBlacklisted={false} showDetailsButton={false} /> diff --git a/src/components/loading-overlay/LoadingOverlay.tsx b/src/components/loading-overlay/LoadingOverlay.tsx index 8448c7ac..d02912ac 100644 --- a/src/components/loading-overlay/LoadingOverlay.tsx +++ b/src/components/loading-overlay/LoadingOverlay.tsx @@ -1,115 +1,43 @@ /* eslint-disable i18next/no-literal-string */ -import React, { Component, RefObject } from 'react' +import { FC, useEffect, useRef } from 'react' import { CSSTransition } from 'react-transition-group' import Spinner from './Spinner' -// import STYLES from './styles' import './loading-overlay.less' -class LoadingOverlay extends Component< - LoadingOverlayProps, - LoadingOverlayState -> { - private wrapper: RefObject - - constructor(props: LoadingOverlayProps) { - super(props) - this.wrapper = React.createRef() - } - - // componentDidMount() { - // if (this.wrapper.current) { - // const wrapperStyle = window.getComputedStyle(this.wrapper.current) - // const overflowCSS = ['overflow', 'overflowX', 'overflowY'].reduce( - // (m, i) => { - // if (wrapperStyle[i] !== 'visible') m[i] = 'hidden' - // return m - // }, - // {} - // ) - // this.setState({ overflowCSS }) - // } - // } - - componentDidUpdate() { - const { active } = this.props - if (active && this.wrapper.current) this.wrapper.current.scrollTop = 0 - } - - /** - * Return an emotion css object for a given element key - * If a custom style was provided via props, run it with - * the base css obj. - */ - // getStyles = (key, providedState) => { - // const base = STYLES[key](providedState, this.props) - // const custom = this.props.styles[key] - // if (!custom) return base - // return typeof custom === 'function' ? custom(base, this.props) : custom - // } - - /** - * Convenience cx wrapper to add prefix classes to each of the child - * elements for styling purposes. - */ - // cx = (names, ...args) => { - // const arr = Array.isArray(names) ? names : [names] - // return cx( - // ...arr.map((name) => - // name ? `${this.props.classNamePrefix}${name}` : '' - // ), - // ...args - // ) - // } - - render() { - const { children, className, active, fadeSpeed, spinner, text } = this.props - - return ( -
= ({ active, text }) => { + const ref = useRef(null) + useEffect(() => { + if (active && ref.current) ref.current.scrollTop = 0 + }, [active, ref]) + return ( +
+ - -
-
- <> - {spinner && - (typeof spinner === 'boolean' ? : spinner)} - {text} - -
+
+
+ <> + + {text} +
- - {children} -
- ) - } +
+
+
+ ) } export interface LoadingOverlayProps { active: boolean - fadeSpeed: number - className?: string - classNamePrefix?: string - spinner: boolean | React.Component - text: React.Component | string - styles?: CSSStyleDeclaration - children?: React.ReactNode + text: string } -interface LoadingOverlayState {} - -// LoadingOverlayWrapper.defaultProps = { -// classNamePrefix: '_loading_overlay_', -// fadeSpeed: 500, -// styles: {}, -// } - export default LoadingOverlay diff --git a/src/components/loading-overlay/loading-overlay.less b/src/components/loading-overlay/loading-overlay.less index a2b68208..203f2c8a 100644 --- a/src/components/loading-overlay/loading-overlay.less +++ b/src/components/loading-overlay/loading-overlay.less @@ -1,4 +1,3 @@ - .loading-overlay { .overlay { max-width: initial; @@ -10,8 +9,8 @@ display: flex; text-align: center; font-size: 1.2em; - color: #FFF; - background: rgba(0, 0, 0, 0.7); + color: var(--color-white); + background: rgba(var(--color-black), 0.7); z-index: 2000; transition: 1 500ms ease-in; } @@ -24,11 +23,13 @@ margin: 0 auto 10px auto; width: 50px; max-height: 100%; + &:before { - content: ""; + content: ''; display: block; padding-top: 100%; } + & svg { animation: rotate(0deg) 2s linear infinite; height: 100%; @@ -40,12 +41,13 @@ left: 0; right: 0; margin: auto; + & circle { animation: spinnerDash 1.5s ease-in-out infinite; - stroke-dasharray: 1,200; + stroke-dasharray: 1, 200; stroke-dashoffset: 0; stroke-linecap: round; - stroke: #FFF; + stroke: var(--color-white); } } } @@ -53,30 +55,30 @@ @keyframes spinnerDash { 0% { - stroke-dasharray: 1,200; + stroke-dasharray: 1, 200; stroke-dashoffset: 0; } 50% { - stroke-dasharray: 89,200; + stroke-dasharray: 89, 200; stroke-dashoffset: -35px; } 100% { - stroke-dasharray: 89,200; + stroke-dasharray: 89, 200; stroke-dashoffset: -124px; } } @-webkit-keyframes spinnerDash { 0% { - stroke-dasharray: 1,200; + stroke-dasharray: 1, 200; stroke-dashoffset: 0; } 50% { - stroke-dasharray: 89,200; + stroke-dasharray: 89, 200; stroke-dashoffset: -35px; } 100% { - stroke-dasharray: 89,200; + stroke-dasharray: 89, 200; stroke-dashoffset: -124px; } -} \ No newline at end of file +} diff --git a/src/components/login/login-in-navbar/Login-in-navbar.less b/src/components/login/login-in-navbar/Login-in-navbar.less index 2d529e7e..fb716579 100644 --- a/src/components/login/login-in-navbar/Login-in-navbar.less +++ b/src/components/login/login-in-navbar/Login-in-navbar.less @@ -3,10 +3,10 @@ height: 34px; margin: 0; padding: 0; - border: 1px #0ca589 solid; + border: 1px var(--color-active-green) solid; border-radius: 2px; background-color: transparent; text-align: center; cursor: pointer; display: inline; -} \ No newline at end of file +} diff --git a/src/components/login/private-route/PrivateRoute.tsx b/src/components/login/private-route/PrivateRoute.tsx index 25dbe242..4971ff1a 100644 --- a/src/components/login/private-route/PrivateRoute.tsx +++ b/src/components/login/private-route/PrivateRoute.tsx @@ -20,14 +20,7 @@ export const PrivateRoute: React.FC = ({ {...rest} render={(props) => { if (!initialized) { - return ( - - ) + return } if (authenticated) { return diff --git a/src/components/map-detail/MarkerLabels.tsx b/src/components/map-detail/MarkerLabels.tsx index 9b330177..4bde28af 100644 --- a/src/components/map-detail/MarkerLabels.tsx +++ b/src/components/map-detail/MarkerLabels.tsx @@ -7,8 +7,8 @@ import { getMarkerData, isHiddenMission, } from './MarkerData' -import CheckeredFlagSVG from '../../img/icons/checkered-flag.svg?react' -import EyeOffSVG from '../../img/icons/eye-off-outline.svg?react' +import CheckeredFlagSVG from '../../assets/img/icons/checkered-flag.svg?react' +import EyeOffSVG from '../../assets/img/icons/eye-off-outline.svg?react' const getEndMarkerLabel = () => { return ( diff --git a/src/components/map-detail/map.less b/src/components/map-detail/map.less index a343a111..87428435 100644 --- a/src/components/map-detail/map.less +++ b/src/components/map-detail/map.less @@ -18,14 +18,18 @@ margin-left: -13px; margin-top: -13px; border-radius: 80px; - border: 2px solid rgba(0, 0, 0, 0.4); + border: 2px solid rgba(var(--color-black), 0.4); background-clip: padding-box; display: flex; align-items: center; justify-content: center; - color: rgb(255, 255, 255); - text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; - background-color: @color-pin; + color: var(--color-white); + text-shadow: + -1px 0 var(--color-black), + 0 1px var(--color-black), + 1px 0 var(--color-black), + 0 -1px var(--color-black); + background-color: var(--color-pin); font-size: 12px; font-weight: bold; } @@ -56,7 +60,7 @@ .marker-pin-medium-true { .marker-pin-medium; - background-color: rgb(22, 212, 178); + background-color: var(--color-positive-green-light); } .marker-pin-false { @@ -65,54 +69,69 @@ .marker-pin-true { .marker-pin; - background-color: rgb(22, 212, 178); + background-color: var(--color-positive-green-light); } .marker-pin-medium-false.marker-pin-todo { - background-color: @color-todo; + background-color: var(--color-todo); } .marker-pin-medium-false.marker-pin-done { - background-color: @color-done; + background-color: var(--color-done); } .marker-pin-medium-false.marker-pin-done-todo { - background-image: linear-gradient( -45deg, @color-done 50%, @color-todo 50%); + background-image: linear-gradient( + -45deg, + var(--color-done) 50%, + var(--color-todo) 50% + ); } .marker-pin-medium-false.marker-pin-normal-todo { - background-image: linear-gradient( -45deg, @color-pin 50%, @color-todo 50%); + background-image: linear-gradient( + -45deg, + var(--color-pin) 50%, + var(--color-todo) 50% + ); } .marker-pin-medium-false.marker-pin-normal-done { - background-image: linear-gradient( -45deg, @color-pin 50%, @color-done 50%); + background-image: linear-gradient( + -45deg, + var(--color-pin) 50%, + var(--color-done) 50% + ); } .marker-pin-medium-false.marker-pin-all { - background-image: conic-gradient(@color-pin 0 33%, @color-done 0 66%, @color-todo 0); + background-image: conic-gradient( + var(--color-pin) 0 33%, + var(--color-done) 0 66%, + var(--color-todo) 0 + ); } .square-marker-pin { - display: flex; align-items: center; - justify-content: center; - - width: 20px !important; - height: 20px !important; - margin-left: -6px; - margin-top: -6px; - border: 2px solid rgba(0, 0, 0, 0.4); background-clip: padding-box; - background-color: rgb(22, 212, 177); + background-color: var(--color-positive-green-light); + border: 2px solid rgba(var(--color-black), 0.4); + display: flex; font-size: 12px; font-weight: bold; + height: 20px !important; + justify-content: center; + margin-left: -6px; + margin-top: -6px; + width: 20px !important; } .color-green { - background-color: rgb(22, 212, 177); + background-color: var(--color-positive-green-light); } .color-blue { - background-color: @color-pin; + background-color: var(--color-pin); } .marker-poi-pin { @@ -125,4 +144,3 @@ margin-left: -7px; margin-top: -7px; } - diff --git a/src/components/menu-main/MenuMain.tsx b/src/components/menu-main/MenuMain.tsx index 360dfcfd..9f76f316 100644 --- a/src/components/menu-main/MenuMain.tsx +++ b/src/components/menu-main/MenuMain.tsx @@ -2,11 +2,11 @@ import React from 'react' import { NavLink } from 'react-router-dom' import { useTranslation } from 'react-i18next' -import SVGHome from '../../img/icons/home.svg?react' -import SVGBrowse from '../../img/icons/browse.svg?react' -import SVGMap from '../../img/icons/map.svg?react' -import SVGHelp from '../../img/icons/help.svg?react' -import SVGAdd from '../../img/icons/add.svg?react' +import SVGHome from '../../assets/img/icons/home.svg?react' +import SVGBrowse from '../../assets/img/icons/browse.svg?react' +import SVGMap from '../../assets/img/icons/map.svg?react' +import SVGHelp from '../../assets/img/icons/help.svg?react' +import SVGAdd from '../../assets/img/icons/add.svg?react' import './menu-main.less' diff --git a/src/components/menu-main/menu-main.less b/src/components/menu-main/menu-main.less index 1a81c18f..7db00e69 100644 --- a/src/components/menu-main/menu-main.less +++ b/src/components/menu-main/menu-main.less @@ -1,3 +1,5 @@ +@mobile-detection: ~' screen and (max-width: 880px) '; + .menu-main { display: flex; @@ -6,31 +8,31 @@ flex-direction: column; align-items: center; justify-content: center; - color: #eaeaea; + color: var(--color-white-light); padding: 5px; min-width: 70px; - transition: background-color .3s; - - & > .icon { - fill: #eaeaea; + transition: background-color 0.3s; + + &.active { + color: var(--color-active-green); + + & > .icon { + fill: var(--color-active-green); + } } - } - & > a.active { - color: #0ca589; - & > .icon { - fill: #0ca589; + fill: var(--color-white-light); } } @media (hover: hover) and (pointer: fine) { & a:hover { - background: rgba(29,165,122,.3); - color: white; - + background: rgba(29, 165, 122, 0.3); + color: var(--color-white); + & > .icon { - fill: white; + fill: var(--color-white); } } } @@ -39,9 +41,32 @@ width: 24px; height: 24px; } - } -.bottom-menu .menu-main > a { - flex-grow: 1; +.bottom-menu { + background: var(--color-black); + padding: 5px 10px; + display: none; + + @media only @mobile-detection { + display: block; + } + + .menu-main { + > a { + flex-grow: 1; + } + + a { + @media only @mobile-detection { + flex: 1; + min-width: 0 !important; + } + } + } + + .brand-menu { + max-width: 329px; + flex: 1; + } } diff --git a/src/components/menu-user/MenuUser.tsx b/src/components/menu-user/MenuUser.tsx index 4a24feeb..6e105135 100644 --- a/src/components/menu-user/MenuUser.tsx +++ b/src/components/menu-user/MenuUser.tsx @@ -4,7 +4,7 @@ import { Button, Dropdown, Menu } from 'antd' import { useTranslation } from 'react-i18next' import UserPicture from '../login/user-picture' -import SVGUpArrow from '../../img/icons/up-arrow.svg?react' +import SVGUpArrow from '../../assets/img/icons/up-arrow.svg?react' import './menu-user.less' diff --git a/src/components/mission-card/MissionCard.tsx b/src/components/mission-card/MissionCard.tsx index a3c031ac..0836d046 100644 --- a/src/components/mission-card/MissionCard.tsx +++ b/src/components/mission-card/MissionCard.tsx @@ -4,7 +4,7 @@ import { Mission } from '../../features/mission' import MissionImage from '../mission-image/MissionImage' import StepList from '../step-list' import MissionInfo from '../mission-info' -import SVGChevron from '../../img/icons/chevron.svg?react' +import SVGChevron from '../../assets/img/icons/chevron.svg?react' import './mission-card.less' diff --git a/src/components/mission-card/mission-card.less b/src/components/mission-card/mission-card.less index 01cb708d..6f5c2e07 100644 --- a/src/components/mission-card/mission-card.less +++ b/src/components/mission-card/mission-card.less @@ -5,7 +5,7 @@ margin-top: 0; } margin-top: 1rem; - background: #2e2e2e; + background: var(--color-dark-gray); border-radius: 5px; border: none; // max-width: 400px; diff --git a/src/components/mission-image/mission-image.less b/src/components/mission-image/mission-image.less index eb335734..45d900b2 100644 --- a/src/components/mission-image/mission-image.less +++ b/src/components/mission-image/mission-image.less @@ -1,11 +1,11 @@ .mission-image { - width: 50px; - height: 50px; - border-radius: 50%; - background-repeat: no-repeat; - background-size: 100%; - border: 2px solid #f19e24; - padding: 2px 17px; - font-size: 26px; - font-weight: 700; + background-repeat: no-repeat; + background-size: 100%; + border-radius: 50%; + border: 2px solid var(--color-warning); + font-size: 26px; + font-weight: 700; + height: 50px; + padding: 2px 17px; + width: 50px; } diff --git a/src/components/mission-info/MissionInfo.tsx b/src/components/mission-info/MissionInfo.tsx index 197c0f27..d1b664ab 100644 --- a/src/components/mission-info/MissionInfo.tsx +++ b/src/components/mission-info/MissionInfo.tsx @@ -10,9 +10,9 @@ import { getExternalLinkAttributes } from '../../features/utils' import { Duration } from '../duration/Duration' import { Distance } from '../distance/Distance' -import SVGExplorer from '../../img/icons/explorer.svg?react' -import SVGTimer from '../../img/icons/timer.svg?react' -import SVGIntel from '../../img/icons/intel.svg?react' +import SVGExplorer from '../../assets/img/icons/explorer.svg?react' +import SVGTimer from '../../assets/img/icons/timer.svg?react' +import SVGIntel from '../../assets/img/icons/intel.svg?react' import './mission-info.less' import { isMobile } from '../../features/utils/os' diff --git a/src/components/mission-info/mission-info.less b/src/components/mission-info/mission-info.less index fa1e52bf..2601d96b 100644 --- a/src/components/mission-info/mission-info.less +++ b/src/components/mission-info/mission-info.less @@ -8,20 +8,20 @@ height: 1.2em; min-width: 2em; } - + .mission-info-markedoffline { - color: #FF2F2F; + color: var(--color-missing); } - + .mission-info-intel { display: flex; flex-direction: row; - color: #15D4B2; + color: var(--color-border-light); align-content: center; a { - color: #15D4B2; + color: var(--color-border-light); text-decoration: underline; display: flex; align-items: center; diff --git a/src/components/navbar/Navbar.less b/src/components/navbar/Navbar.less index fa1db540..f72c19b7 100644 --- a/src/components/navbar/Navbar.less +++ b/src/components/navbar/Navbar.less @@ -1,8 +1,12 @@ +@mobile-detection: ~' screen and (max-width: 880px) '; + .top-menu { display: flex; flex-direction: row; justify-content: space-between; align-items: center; + background: var(--color-black); + padding: 5px 10px; > div { display: flex; @@ -13,6 +17,17 @@ width: 250px; } } + + .menu-main { + @media only @mobile-detection { + display: none; + } + } + + .brand-menu { + max-width: 329px; + flex: 1; + } } .brand-logo { @@ -23,6 +38,10 @@ background-size: contain; background-repeat: no-repeat; background-position: left center; + + @media only @mobile-detection { + width: 50vw; + } } .mobile-search-bar { @@ -33,11 +52,11 @@ display: flex; } -.mobile-search-button-container{ +.mobile-search-button-container { display: flex; min-width: 70px; height: 60px; - transition: background-color .3s; + transition: background-color 0.3s; .mobile-search-button { background: none; @@ -51,30 +70,29 @@ display: flex; justify-content: center; align-items: center; - + height: 100%; width: 100%; - - .search-button-icon - { + + .search-button-icon { width: 24px; height: 24px; - fill: #eaeaea; - } - } + fill: var(--color-white-light); + } + } } .mobile-search-button-container.active { - .search-button-icon{ - fill: #0ca589; + .search-button-icon { + fill: var(--color-active-green); } } @media (hover: hover) and (pointer: fine) { .mobile-search-button-container:hover { - background: rgba(29,165,122,.3); - .search-button-icon{ - fill: white; + background: rgba(29, 165, 122, 0.3); + .search-button-icon { + fill: white; } } } diff --git a/src/components/navbar/Navbar.tsx b/src/components/navbar/Navbar.tsx index ffc08739..1f467a50 100644 --- a/src/components/navbar/Navbar.tsx +++ b/src/components/navbar/Navbar.tsx @@ -1,108 +1,84 @@ -import React from 'react' -import { generatePath } from 'react-router' -import { RouteComponentProps, withRouter, NavLink } from 'react-router-dom' -import { Location } from 'history' -import { withTranslation, WithTranslationProps } from 'react-i18next' +import { FC, useEffect, useState } from 'react' +import { generatePath, useHistory, useLocation } from 'react-router' +import { NavLink } from 'react-router-dom' +import { useTranslation } from 'react-i18next' import LoginInNavbar from '../login/login-in-navbar' import SearchInput from '../search-input' import MenuMain from '../menu-main' -import Logo from '../../img/logo/logo64.png' -import SVGSearch from '../../img/icons/search.svg?react' +import Logo from '../../assets/img/logo/logo64.png' +import SVGSearch from '../../assets/img/icons/search.svg?react' import './Navbar.less' -export class Navbar extends React.Component { - constructor(props: NavBarProps) { - super(props) - - this.state = { - mobileSearchBarActive: false, +const Navbar: FC = ({ className }) => { + const [mobileSearchBarActive, setMobileSearchBarActive] = useState(false) + const { t } = useTranslation() + const history = useHistory() + const location = useLocation() + const mobileSearchBarActiveClassName = mobileSearchBarActive ? 'active' : '' + const insideSearch = location.pathname.startsWith('/search/') + useEffect(() => { + if (!insideSearch) { + setMobileSearchBarActive(false) } + }, [insideSearch]) - const { history } = this.props - history.listen(this.locationListen.bind(this)) - } - - locationListen(location: Location) { - // Hide Mobile search bar when navigating away from search + const callSearch = (value: string) => { + const trimmedValue = value.trim() - if (!location.pathname.startsWith('/search/')) { - const { mobileSearchBarActive } = this.state - if (mobileSearchBarActive) { - this.setState({ mobileSearchBarActive: false }) - } + if (trimmedValue !== '') { + const path = generatePath('/search/:term', { term: trimmedValue }) + history.push(path) } } - toggleMobileSeachBar() { - const { mobileSearchBarActive } = this.state - this.setState({ mobileSearchBarActive: !mobileSearchBarActive }) + const toggleMobileSeachBar = () => { + setMobileSearchBarActive(!mobileSearchBarActive) } - render() { - const { history, className, i18n } = this.props - - const callSearch = (value: string) => { - const trimmedValue = encodeURIComponent(value.trim()) - - if (trimmedValue !== '') { - const path = generatePath('/search/:term', { term: trimmedValue }) - history.push(path) - } - } - - const { mobileSearchBarActive } = this.state - const mobileSearchBarActiveClassName = mobileSearchBarActive ? 'active' : '' - - return ( - <> -
- -
-   -
-
- -
-
+
+ +
+   +
+
+ +
+
+ -
-
- -
- + +
-
- {mobileSearchBarActive && ( -
- +
+
- )} - - ) - } + +
+
+ {mobileSearchBarActive && ( +
+ +
+ )} + + ) } export type NavBarProps = { className?: string -} & RouteComponentProps & - WithTranslationProps - -export interface NavBarState { - mobileSearchBarActive: Boolean } -export default withRouter(withTranslation()(Navbar)) +export default Navbar diff --git a/src/components/place-accordion/PlaceAccordionEntry.tsx b/src/components/place-accordion/PlaceAccordionEntry.tsx index 8e7a24a5..36225b3e 100644 --- a/src/components/place-accordion/PlaceAccordionEntry.tsx +++ b/src/components/place-accordion/PlaceAccordionEntry.tsx @@ -5,7 +5,7 @@ import { Place } from '../../features/place' import PlaceEntry from '../place-list/PlaceEntry' import './place-accordion-entry.less' -import SVGArea from '../../img/icons/area.svg?react' +import SVGArea from '../../assets/img/icons/area.svg?react' export const PlaceAccordionEntry: FC = ({ place, diff --git a/src/components/place-accordion/PlaceAccordionPage.tsx b/src/components/place-accordion/PlaceAccordionPage.tsx index 63f60572..06df6176 100644 --- a/src/components/place-accordion/PlaceAccordionPage.tsx +++ b/src/components/place-accordion/PlaceAccordionPage.tsx @@ -6,8 +6,8 @@ import { Place } from '../../features/place' import { RootState } from '../../storeTypes' import PlaceEntry from '../place-list/PlaceEntry' import { PlaceAccordionEntry } from './PlaceAccordionEntry' -import TriangleUpSVG from '../../img/icons/triangle.svg?react' -import TriangleDownSVG from '../../img/icons/triangle-down.svg?react' +import TriangleUpSVG from '../../assets/img/icons/triangle.svg?react' +import TriangleDownSVG from '../../assets/img/icons/triangle-down.svg?react' import './place-accordion-page.less' diff --git a/src/components/place-accordion/place-accordion.less b/src/components/place-accordion/place-accordion.less index 3cf227bf..84c75690 100644 --- a/src/components/place-accordion/place-accordion.less +++ b/src/components/place-accordion/place-accordion.less @@ -1,3 +1,3 @@ .place-accordion { - background: #2E2E2E; + background: var(--color-dark-gray); } diff --git a/src/components/place-list-flat/place-card.less b/src/components/place-list-flat/place-card.less index 4fbbad98..c7f9b555 100644 --- a/src/components/place-list-flat/place-card.less +++ b/src/components/place-list-flat/place-card.less @@ -1,7 +1,7 @@ .place-card { - background: #2e2e2e; + background: var(--color-dark-gray); border-radius: 5px; - border: #2e2e2e 2px solid; + border: var(--color-dark-gray) 2px solid; padding: 15px; color: white; } @@ -26,7 +26,7 @@ .place-card-name { - white-space: nowrap; + white-space: nowrap; text-overflow: ellipsis; font-weight: 700; overflow-x: hidden; @@ -39,7 +39,7 @@ } .place-card-number-of-banners { - white-space: nowrap; + white-space: nowrap; } .place-card-formatted-address { @@ -60,8 +60,8 @@ } .place-card-icon { - color: #EAEAEA; - fill: #EAEAEA; + color: var(--color-white-light); + fill: var(--color-white-light); margin-right: 1em; height: 1.5em; } diff --git a/src/components/place-list/PlaceEntry.tsx b/src/components/place-list/PlaceEntry.tsx index a93bc917..01ac2a02 100644 --- a/src/components/place-list/PlaceEntry.tsx +++ b/src/components/place-list/PlaceEntry.tsx @@ -4,8 +4,8 @@ import { Place } from '../../features/place' import './place-entry.less' -import SVGLocality from '../../img/icons/locality.svg?react' -import SVGArea from '../../img/icons/area.svg?react' +import SVGLocality from '../../assets/img/icons/locality.svg?react' +import SVGArea from '../../assets/img/icons/area.svg?react' const PlaceEntry: FC = ({ place, diff --git a/src/components/place-list/place-entry.less b/src/components/place-list/place-entry.less index f2045042..4f5b1024 100644 --- a/src/components/place-list/place-entry.less +++ b/src/components/place-list/place-entry.less @@ -3,12 +3,12 @@ } .place-icon { - fill: #eaeaea; + fill: var(--color-white-light); width: 1.1em; height: 1.1em; } @font-face { font-family: 'NotoColorEmoji'; - src: local('NotoColorEmoji'), url(./../../fonts/NotoColorEmoji.ttf) format('truetype'); + src: local('NotoColorEmoji'), url(./../../assets/fonts/NotoColorEmoji.ttf) format('truetype'); } diff --git a/src/components/place-list/place-list.less b/src/components/place-list/place-list.less index bfc5c75f..74f2eddc 100644 --- a/src/components/place-list/place-list.less +++ b/src/components/place-list/place-list.less @@ -1,24 +1,41 @@ .places-list-item { - white-space: nowrap; - text-overflow: ellipsis; + column-gap: 0.3em; cursor: pointer; overflow: hidden; - display: flex; - align-items: baseline; - column-gap: 0.3em; + text-overflow: ellipsis; } .places-list { padding-top: 5em; padding-left: 2em; padding-right: 1em; + + h2 + h2 { + min-width: 270px; + } } .places-list-child { + align-items: center; + display: grid; margin-left: 1em; + grid-template-columns: 1fr 180px 50px; + + .place-flag { + grid-column: 1 / 2; + } .place-name { + grid-column: 2 / 3; overflow: hidden; text-overflow: ellipsis; } + + .place-number-of-banners { + grid-column: 3 / 3; + } + + .place-name + .place-number-of-banners { + grid-column: 3 / 3; + } } diff --git a/src/components/recent-banners/RecentBanners.tsx b/src/components/recent-banners/RecentBanners.tsx index ad7c38ab..a77f847f 100644 --- a/src/components/recent-banners/RecentBanners.tsx +++ b/src/components/recent-banners/RecentBanners.tsx @@ -45,19 +45,14 @@ export const RecentBanners: FC = ({ return (
- +

{titleList}

diff --git a/src/components/search-input/SearchInput.tsx b/src/components/search-input/SearchInput.tsx index cb40f91e..dd72b406 100644 --- a/src/components/search-input/SearchInput.tsx +++ b/src/components/search-input/SearchInput.tsx @@ -2,7 +2,7 @@ import React, { FormEvent, Fragment, FC, useRef } from 'react' import { message } from 'antd' import { useTranslation } from 'react-i18next' -import SVGSearch from '../../img/icons/search.svg?react' +import SVGSearch from '../../assets/img/icons/search.svg?react' import './search-input.less' diff --git a/src/components/search-input/search-input.less b/src/components/search-input/search-input.less index d0dc2670..27d9d0fd 100644 --- a/src/components/search-input/search-input.less +++ b/src/components/search-input/search-input.less @@ -1,5 +1,5 @@ .search-input-button-highlighted() { - background: #077561; + background: var(--color-positive-green); fill: white; } @@ -8,18 +8,18 @@ flex-direction: row; width: 100%; - .search-input { + .search-input { padding:5px; padding-left: 10px; - background: #404040; + background: var(--color-panel-bg); border-radius: 4px 0px 0px 4px; border: none; width: 100%; &:focus { - background: #6A6A6A; + background: var(--color-gray); outline: none; - color: white; + color: var(--color-white); } &:focus + .search-input-button { @@ -27,15 +27,15 @@ } &::placeholder { - color: #AAAAAA; + color: var(--color-light-gray); font-size: 12px; } } - .search-input-button { + .search-input-button { display: flex; flex-direction: column; - background: #888888; + background: var(--color-gray); border-radius: 0px 4px 4px 0px; border: none; cursor: pointer; @@ -43,14 +43,14 @@ align-items: center; padding-left: 12px; padding-right: 12px; - fill: #1B1B1B; + fill: var(--color-light-black); @media (hover: hover) and (pointer: fine) { &:hover { .search-input-button-highlighted() } } - + &:focus { .search-input-button-highlighted() } @@ -62,4 +62,4 @@ width: 17.49px; height: 17.49px; } -} \ No newline at end of file +} diff --git a/src/components/search-mission-card/SearchMissionCard.tsx b/src/components/search-mission-card/SearchMissionCard.tsx index ef7d18e9..7c724db9 100644 --- a/src/components/search-mission-card/SearchMissionCard.tsx +++ b/src/components/search-mission-card/SearchMissionCard.tsx @@ -6,7 +6,7 @@ import { getExternalLinkAttributes } from '../../features/utils' import { Agent } from '../agent/Agent' import MissionImage from '../mission-image/MissionImage' import PlaceHolderMission from './PlaceHolderMission' -import SVGIntel from '../../img/icons/intel.svg?react' +import SVGIntel from '../../assets/img/icons/intel.svg?react' import './search-mission-card.less' diff --git a/src/components/search-mission-card/search-mission-card.less b/src/components/search-mission-card/search-mission-card.less index cc94e04f..d23d7b43 100644 --- a/src/components/search-mission-card/search-mission-card.less +++ b/src/components/search-mission-card/search-mission-card.less @@ -1,10 +1,8 @@ -@import "../../index"; +@import '../../index'; .search-mission-card { margin-top: 1rem; - background-color: @color-panel-bg; - margin-top: 1rem; - background-color: #404040; + background-color: var(--color-panel-bg); border-radius: 5px; display: flex; column-gap: 15px; @@ -25,12 +23,15 @@ word-break: break-word; &.placeholder { - color: #808080; + color: var(--color-gray); } } .mission-agent { font-size: 14px; + border: none; + text-align: left; + padding: 0; } .icon { @@ -58,10 +59,4 @@ cursor: pointer; flex-shrink: 0; } - - .mission-agent { - border: none; - text-align: left; - padding: 0; - } -} \ No newline at end of file +} diff --git a/src/components/search-mission-list/SearchMissionList.tsx b/src/components/search-mission-list/SearchMissionList.tsx index c6bf9040..b08e4e63 100644 --- a/src/components/search-mission-list/SearchMissionList.tsx +++ b/src/components/search-mission-list/SearchMissionList.tsx @@ -57,12 +57,7 @@ const SearchMissionList: FC = ({ {hasMoreMissions && !initial && ( - + )} diff --git a/src/components/step-card/step-card.less b/src/components/step-card/step-card.less index a0d55eb9..be3e9609 100644 --- a/src/components/step-card/step-card.less +++ b/src/components/step-card/step-card.less @@ -24,7 +24,7 @@ .step-card-unavailable { text-decoration: line-through; - color: #6f6f6f; + color: var(--color-gray); } .step-card-hidden { diff --git a/src/components/step-list/step-list.less b/src/components/step-list/step-list.less index 58d7a11a..e25291e0 100644 --- a/src/components/step-list/step-list.less +++ b/src/components/step-list/step-list.less @@ -2,6 +2,6 @@ .step-list { .ant-layout { - background-color: @color-panel-bg !important; + background-color: var(--color-panel-bg) !important; } } diff --git a/src/components/switch/switch.less b/src/components/switch/switch.less index 4d86c986..54813bea 100644 --- a/src/components/switch/switch.less +++ b/src/components/switch/switch.less @@ -1,15 +1,15 @@ .bg-switch { border-radius: 4px; - background-color: white; + background-color: var(--color-white); padding: 1px; width: 48px; height: 28px; .ant-switch { - background-color: #1f1f1f; + background-color: var(--color-dark-gray); border-radius: 3px; border: 1px solid; - border-color: #1f1f1f; + border-color: var(--color-dark-gray); width: 46px; height: 26px; } @@ -18,11 +18,11 @@ border-radius: 1px; width: 16px; height: 20px; - background-color: #808080; + background-color: var(--color-gray); } &.bg-switch-selected { - background-image: linear-gradient(180deg, #109393, #15D4B2); + background-image: linear-gradient(180deg, var(--color-border-dark), var(--color-border-light)); .ant-switch { border-color: transparent; @@ -30,7 +30,7 @@ } .ant-switch-handle::before { - background-color: #15D4B2; + background-color: var(--color-border-light); } } } diff --git a/src/components/user-banner-list-preview/UserBannerListPreview.tsx b/src/components/user-banner-list-preview/UserBannerListPreview.tsx index f9e011f4..d6bbfbca 100644 --- a/src/components/user-banner-list-preview/UserBannerListPreview.tsx +++ b/src/components/user-banner-list-preview/UserBannerListPreview.tsx @@ -96,7 +96,7 @@ class UserBannerListPreview extends React.Component< diff --git a/src/components/user-banner-list-preview/user-banner-list-preview.less b/src/components/user-banner-list-preview/user-banner-list-preview.less index b9ac4541..6c6857b7 100644 --- a/src/components/user-banner-list-preview/user-banner-list-preview.less +++ b/src/components/user-banner-list-preview/user-banner-list-preview.less @@ -8,14 +8,14 @@ display: flex; color: white; - background-color: #1B1B1B; + background-color: var(--color-light-black); border-radius: 4px; padding: 5px 10px; } border-radius: 5px; display: flex; - background-image: linear-gradient(180deg, #109393, #15D4B2); + background-image: linear-gradient(180deg, var(--color-border-dark), var(--color-border-light)); padding: 2px; } - + diff --git a/src/components/verify-account/VerifyAccount.tsx b/src/components/verify-account/VerifyAccount.tsx index 6d214d3a..08bc31e9 100644 --- a/src/components/verify-account/VerifyAccount.tsx +++ b/src/components/verify-account/VerifyAccount.tsx @@ -109,17 +109,19 @@ const VerifyAccount: React.FC = ({ }, [dispatchWithLoading, refreshToken, setIssues]) const onUnlinkUser = useCallback(() => { - dispatchWithLoading(unlinkUser(), undefined, (err) => - setIssues([ - { - key: 'unlink', - message: err.message, - type: 'error', - field: 'verify', - }, - ]) - ) - }, [dispatchWithLoading, setIssues]) + if (confirm(t('account.linking.unlinkWarning'))) { + dispatchWithLoading(unlinkUser(), undefined, (err) => + setIssues([ + { + key: 'unlink', + message: err.message, + type: 'error', + field: 'verify', + }, + ]) + ) + } + }, [dispatchWithLoading, setIssues, t]) const onAbort = useCallback(() => { if (currentUser.verificationAgent) { @@ -152,6 +154,7 @@ const VerifyAccount: React.FC = ({ @@ -166,6 +169,7 @@ const VerifyAccount: React.FC = ({ @@ -264,7 +268,7 @@ const VerifyAccount: React.FC = ({ {t('buttons.back')}
@@ -286,12 +290,7 @@ const VerifyAccount: React.FC = ({ return (
- +

{t('account.linking.title')}

{!isAccountLinked(currentUser) &&

{t('account.linking.none')}

} diff --git a/src/components/verify-account/verify-account.less b/src/components/verify-account/verify-account.less index 365462fc..3c0b1907 100644 --- a/src/components/verify-account/verify-account.less +++ b/src/components/verify-account/verify-account.less @@ -1,4 +1,5 @@ @import '../../index.less'; +@import '../../assets/style/helper/button.less'; .account-linking { width: 100%; @@ -58,4 +59,4 @@ .claim-button { .positive-action-button; } -} \ No newline at end of file +} diff --git a/src/features/banner/filter.ts b/src/features/banner/filter.ts index 993aed63..d70e4e3a 100644 --- a/src/features/banner/filter.ts +++ b/src/features/banner/filter.ts @@ -1,3 +1,5 @@ +import { BannerListType } from './types' + export type BannerOrder = | 'relevance' | 'listAdded' @@ -18,4 +20,6 @@ export type BannerFilter = { maxEventTimestamp?: string proximityLatitude?: number proximityLongitude?: number + author?: string + listTypes?: BannerListType } diff --git a/src/features/banner/reducer.spec.ts b/src/features/banner/reducer.spec.ts deleted file mode 100644 index ea6ee966..00000000 --- a/src/features/banner/reducer.spec.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { - BannerActionTypes, - LOAD_BANNER, - LOAD_RECENT_BANNERS, -} from './actionTypes' -import bannerReducer from './reducer' -import { BannerState } from './types' - -describe('features > banner > bannerReducer', () => { - it(`load banner, if ${LOAD_BANNER} action is provided`, () => { - const initialState: BannerState = { - banners: [], - fullBanners: [], - recentBanners: [], - browsedBanners: [], - searchBanners: [], - agentBanners: [], - userBannerListBanners: [], - canBrowseMore: true, - canSearchMore: true, - hasMoreAgentBanners: true, - hasMoreUserBannerListBanners: true, - createdBanner: undefined, - mapBanners: [], - } - - const expectedState: BannerState = { - banners: [ - { - id: '1', - title: 'Banner 1', - numberOfMissions: 0, - numberOfSubmittedMissions: 0, - numberOfDisabledMissions: 0, - startLatitude: 0, - startLongitude: 0, - lengthMeters: 0, - formattedAddress: '', - picture: '', - }, - ], - fullBanners: [], - recentBanners: [], - browsedBanners: [], - searchBanners: [], - agentBanners: [], - userBannerListBanners: [], - canBrowseMore: true, - canSearchMore: true, - hasMoreAgentBanners: true, - hasMoreUserBannerListBanners: true, - createdBanner: undefined, - mapBanners: [], - } - - const action: BannerActionTypes = { - type: LOAD_BANNER, - payload: { - id: '1', - title: 'Banner 1', - numberOfMissions: 0, - startLatitude: 0, - startLongitude: 0, - lengthMeters: 0, - formattedAddress: '', - picture: '', - }, - } - - expect(bannerReducer(initialState, action)).toEqual(expectedState) - }) - it(`load recent banners, if ${LOAD_RECENT_BANNERS} action is provided`, () => { - const initialState: BannerState = { - banners: [], - fullBanners: [], - recentBanners: [], - browsedBanners: [], - searchBanners: [], - agentBanners: [], - userBannerListBanners: [], - canBrowseMore: true, - canSearchMore: true, - hasMoreAgentBanners: true, - hasMoreUserBannerListBanners: true, - createdBanner: undefined, - mapBanners: [], - } - - const expectedState: BannerState = { - banners: [], - fullBanners: [], - recentBanners: [ - { - id: '1', - title: 'Banner 1', - numberOfMissions: 0, - numberOfDisabledMissions: 0, - numberOfSubmittedMissions: 0, - startLatitude: 0, - startLongitude: 0, - lengthMeters: 0, - formattedAddress: '', - picture: '', - }, - ], - browsedBanners: [], - searchBanners: [], - agentBanners: [], - userBannerListBanners: [], - canBrowseMore: true, - canSearchMore: true, - hasMoreAgentBanners: true, - hasMoreUserBannerListBanners: true, - createdBanner: undefined, - mapBanners: [], - } - - const action: BannerActionTypes = { - type: LOAD_RECENT_BANNERS, - payload: [ - { - id: '1', - title: 'Banner 1', - numberOfMissions: 0, - startLatitude: 0, - startLongitude: 0, - lengthMeters: 0, - formattedAddress: '', - picture: '', - }, - ], - } - - expect(bannerReducer(initialState, action)).toEqual(expectedState) - }) -}) diff --git a/src/features/place/reducer.spec.ts b/src/features/place/reducer.spec.ts index 20563e23..305108d1 100644 --- a/src/features/place/reducer.spec.ts +++ b/src/features/place/reducer.spec.ts @@ -19,6 +19,9 @@ describe('features > place > placeReducer', () => { const expectedState = { countries: [{ id: '1' }], administrativeAreas: {}, + allPlaces: { '1': { id: '1' } }, + canSearchMore: false, + searchPlaces: [], } const action: PlaceActionTypes = { @@ -38,7 +41,7 @@ describe('features > place > placeReducer', () => { } const expectedState = { - allPlaces: [], + allPlaces: { '1': { id: '1' } }, countries: [], administrativeAreas: { de: [{ id: '1' }] }, searchPlaces: [], diff --git a/src/i18n.ts b/src/i18n.ts index e778ad78..86433b43 100644 --- a/src/i18n.ts +++ b/src/i18n.ts @@ -10,18 +10,13 @@ const supportedLngs = { const getLanguageToUse = () => { const languages = navigator.languages - console.log('preferred language order:', JSON.stringify(languages)) for (const language of languages) { for (const pair of Object.entries(supportedLngs)) { const code = pair[0] const regex = pair[1] - if (regex.test(language)) { - console.log('using language:', code) - return code - } + if (language.match(regex)) return code } } - console.log('using fallback language: en') return 'en' } diff --git a/src/index.less b/src/index.less index 221ea247..3a8908f4 100644 --- a/src/index.less +++ b/src/index.less @@ -1,102 +1,17 @@ body { margin: 0; - font-family: 'Roboto', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + font-family: + 'Roboto', + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + 'Oxygen', + 'Ubuntu', + 'Cantarell', + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } - -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; -} - -.px1 { - padding-left: 1rem; - padding-right: 1rem; -} - -.p-1 { - padding: 1rem; -} - -.group { - display: flex; - justify-content: space-between; -} - -@color-panel-bg: #404040; - -.bg-button { - box-shadow: 0 0 2px 0 rgba(157, 96, 212, 0.5) !important; - border: solid 2px transparent !important; - background-origin: border-box !important; - background-clip: content-box, border-box !important; - box-shadow: 2px 1000px 1px #000 inset !important; - transition: linear-gradient ease 0.6s; - display: flex; - align-items: center; - justify-content: center; - - &.bg-button-default { - background-image: linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, 0)), linear-gradient(180deg, #109393, #15D4B2) !important; - - @media (hover: hover) and (pointer: fine) { - &:hover { - background-image: linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, 0)), linear-gradient(0deg, #109393, #15D4B2) !important; - } - } - } -} - -.button-default { - margin: 0 !important; - background-color: #2e2e2e; - border: none; - display: block; - border-radius: 4px; - width: 100%; - box-shadow: 0 0 2px 0 rgba(157, 96, 212, 0.5) !important; - border: solid 2px transparent !important; - background-origin: border-box !important; - background-clip: content-box, border-box !important; - box-shadow: 2px 1000px 1px #1B1B1B inset !important; - transition: linear-gradient ease 0.6s; - text-align: center; - color: white !important; - background-image: linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, 0)), linear-gradient(180deg, #109393, #15D4B2) !important; - - @media (hover: hover) and (pointer: fine) { - &:hover { - background-image: linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, 0)), linear-gradient(0deg, #109393, #15D4B2) !important; - } - } -} - -.positive-action-button { - background: #077561 !important; - color: white !important; - padding: 0.5em 2em; - border: none; - border-radius: 5px; - cursor: pointer; - - &:disabled { - background: gray; - color: lightgray; - cursor: not-allowed; - } - -} - -.page-container { - height: 100%; - display: flex; - flex-direction: column; - justify-content: space-between; -} - -.nobr { - white-space: nowrap; -} diff --git a/src/index.tsx b/src/index.tsx index 56f03a45..077343b0 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -6,7 +6,7 @@ import App from './App' import { store, persistor } from './store' import './index.less' -import './mobile.less' +import './assets/style/mobile.less' import '@fontsource/roboto/400.css' import '@fontsource/roboto/400-italic.css' diff --git a/src/locales/de/translation.json b/src/locales/de/translation.json index f49cd37c..31634b33 100644 --- a/src/locales/de/translation.json +++ b/src/locales/de/translation.json @@ -6,6 +6,7 @@ "title": "Ingress Account-Verknüpfung", "change": "Verknüpften Account ändern", "unlink": "Verknüpfung aufheben", + "unlinkWarning": "Da das Ingress Community Forum eingestellt wird, wirst du deinen Account ab dem 1. April 2024 nicht mehr mit deinem Bannergress-Profil verknüpfen können. Trotzdem fortfahren?", "link": "Ingress-Account verknüpfen", "none": "Kein Account mit deinem Bannergress-Profil verknüpft", "linked": "Verknüpfter Account: ", @@ -71,10 +72,10 @@ "step3": { "title": "<0>3 Informationen", "bannerTitle": "Banner-Titel", - "description": "Beschreibung", + "description": "Beschreibung ", "warning": { - "title": "Warnungstext", - "subtitle": "Wird in einer auffallenderen Farbe angezeigt" + "title": "Warnungstext ", + "subtitle": "Wird in einer auffallenderen Farbe angezeigt. Markdown wird unterstützt." }, "plannedOfflineDate": { "title": "Geplantes Offline-Datum", @@ -90,6 +91,7 @@ }, "options": "Optionen", "help": { + "markdown": "

Dieses Feld unterstützt einfaches Markdown. Die folgenden Formattierungsoptionen sind möglich:

", "banner": "Banner: Menge von Missionen, die in der richtigen Reihenfolge abgeschlossen werden muss, um ein Gesamtbild in deinem Scanner zu erzeugen.", "collection": "Sammlung: Menge von Missionen, die in einer beliebigen Reihenfolge abgeschlossen werden kann, weil sie kein Gesamtbild darstellen." }, @@ -243,7 +245,7 @@ "title": "Häufig gefragt", "question1": { "title": "Was ist bannergress.com?", - "answer": "

Nach dem Verlust unserer beliebten Ingress-Fansite haben sich einige Agents zusammengetan, um dieses Projekt auf die Beine zu stellen.

  • alle einbinden
  • Open Source werden (bald)
  • dauerhafte Bibliothek für Banner sein
  • nie aufhören, weiterzuentwickeln
" + "answer": "

Nach dem Verlust unserer beliebten Ingress-Fansite haben sich einige Agents zusammengetan, um dieses Projekt auf die Beine zu stellen. Das Ziel dieses Projektes ist es:

  • alle einzubinden
  • Open Source zu sein
  • die dauerhafte Bibliothek für Banner sein
  • nie aufzuhören, weiterzuentwickeln
" }, "question2": { "title": "Wie bekomme ich Ingress-Missionen nach bannergress.com? (Teil 1: Installation)", @@ -262,12 +264,12 @@ "answer": "

...das Tool zum Erstellen von Missionen?

...ein Werkzeug zum Schneiden von Bildern?


..die IITC-CE?

...das Bannergress-Plugin?

...ein IITC-Plugin, das mehr als 25 Missionen anzeigt?

" }, "question6": { - "title": "How do I get my own Ingress missions to bannergress.com, using the Ingress Mission Creator?", - "answer": "
  1. You need either the IITC Button browser add-on or Tampermonkey.
  2. Install the bannergress creator plugin.
  3. Open the mission creator (you may be asked to log into your Ingress account). Then, click on “Sync with Bannergress” in the menu (you may be asked to log into your Bannergress account).
" + "title": "Wie bekomme ich meine eigenen Ingress-Missionen auf bannergress.com, indem ich den Ingress Mission Creator benutze?", + "answer": "
  1. Sie benötigen entweder das IITC Button browser add-on oder Tampermonkey.
  2. Installieren Sie das bannergress creator plugin.
  3. Öffnen Sie den the mission creator (Sie werden möglicherweise aufgefordert, sich in Ihr Ingress-Konto einzuloggen). Klicken Sie dann im Menü auf „Sync with Bannergress“ (Sie werden eventuell aufgefordert, sich in Ihr Bannergress-Konto einzuloggen).
" }, "question7": { - "title": "How can I edit my own banners?", - "answer": "
Bannergress needs to know your Ingress agent name before it can provide you with edit permissions:
  1. Sign into Bannergress.
  2. Open your Bannergress account page.
  3. Click on \"Link Ingress Account\" and follow the instructions.
After that, you have an edit button on all banners that you own.
" + "title": "Wie kann ich meine eigenen Banner bearbeiten?", + "answer": "
Bannergress muss den Namen Ihres Ingress-Agenten kennen, bevor es Ihnen Bearbeitungsrechte erteilen kann:
  1. Melden Sie sich bei Bannergress an.
  2. Öffnen Sie Ihre Bannergress Kontoseite.
  3. Klicken Sie auf \"Link Ingress Account\" und folgen Sie den Anweisungen.
Danach haben Sie auf allen Bannern, die Sie besitzen, eine Schaltfläche zum Bearbeiten.
" } }, "help": { @@ -288,6 +290,10 @@ } } }, + "error": { + "title": "Fehler die Seite wurde nicht gefunden", + "newestBanners": "Versuche mit den neuesten Bannern zu beginnen" + }, "search": { "title": "Suche nach: {{searchTerm}}", "button": "Suchen", @@ -378,4 +384,4 @@ "eventAt": "Event am .", "eventFromTo": "Event vom bis ." } -} \ No newline at end of file +} diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index df853d16..b038bd98 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -6,6 +6,7 @@ "title": "Ingress account linking", "change": "Change Linked Account", "unlink": "Unlink Account", + "unlinkWarning": "Due to the shutdown of the Ingress Community Forum, you won't be able to link your account after April 1st, 2024. Continue anyway?", "link": "Link Ingress Account", "none": "No account linked to your Bannergress profile", "linked": "Account linked: ", @@ -71,10 +72,10 @@ "step3": { "title": "<0>3 Information", "bannerTitle": "Banner Title", - "description": "Description", + "description": "Description ", "warning": { - "title": "Warning Text", - "subtitle": "Displays in a more noticeable color" + "title": "Warning Text ", + "subtitle": "Displays in a more noticeable color." }, "plannedOfflineDate": { "title": "Planned Offline Date", @@ -90,6 +91,7 @@ }, "options": "Options", "help": { + "markdown": "

You can use basic Markdown in this field. The following formatting options are supported:

", "banner": "Banner: Collection of missions that must be completed in sequence to complete the picture in your profile.", "collection": "Collection: Collection of missions that can be completed in any order as they don't form a picture." }, @@ -244,7 +246,7 @@ "title": "Frequently Asked", "question1": { "title": "What is bannergress.com?", - "answer": "

After the horrific loss of our favorite Ingress fan page, some agents came together to start this project.

  • get everyone involved
  • be open source (soon™)
  • be the long-term solution for finding banners
  • never stop developing
" + "answer": "

After the horrific loss of our favorite Ingress fan page, some agents came together to start this project. The aim of the project is to:

  • get everyone involved
  • be open source
  • be the long-term solution for finding banners
  • never stop developing
" }, "question2": { "title": "How do I get Ingress missions to bannergress.com? (Part 1: setup)", @@ -289,6 +291,10 @@ } } }, + "error": { + "title": "Error the page was not found", + "newestBanners": "Try to start with the newest banners" + }, "search": { "title": "Search for {{searchTerm}}", "button": "Search", @@ -380,4 +386,4 @@ "eventAt": "Event at .", "eventFromTo": "Event from to ." } -} \ No newline at end of file +} diff --git a/src/locales/es/translation.json b/src/locales/es/translation.json index c742ebd1..dfad28e8 100644 --- a/src/locales/es/translation.json +++ b/src/locales/es/translation.json @@ -6,6 +6,7 @@ "title": "Vincular cuenta de Ingress", "change": "Cambiar cuenta asociada", "unlink": "Desvincular cuenta", + "unlinkWarning": "Debido al cierre de Foto de la Comunidad de Ingress, no podrás enlazar tu cuenta después del 1 de abril de 2024. ¿Quieres continuar igualmente?", "link": "Vincular cuenta de Ingress", "none": "No tienes cuenta de Ingress asociada a la de Bannergress", "linked": "Cuenta asociada: ", @@ -71,9 +72,14 @@ "step3": { "title": "<0>3 Información", "bannerTitle": "Título", - "description": "Descripción", + "description": "Descripción ", + "warning": { + "title": "Texto de advertencia ", + "subtitle": "Se muestra en un color más fácil de notar." + }, "options": "Opciones", "help": { + "markdown": "

Puedes usar Markdown básico en este campo. Las siguientes opciones de formato están disponibles:

", "banner": "Banner: Colección de misiones que se han de completar seguidas para formar una imagen completa en tu perfil.", "collection": "Colección: Colección de misiones que se pueden completar en cualquier orden." }, @@ -219,7 +225,7 @@ "title": "Preguntas frecuentes", "question1": { "title": "What is bannergress.com?", - "answer": "

After the horrific loss of our favorite Ingress fan page, some agents came together to start this project.

  • get everyone involved
  • be open source (soon™)
  • be the long-term solution for finding banners
  • never stop developing
" + "answer": "

After the horrific loss of our favorite Ingress fan page, some agents came together to start this project. The aim of the project is to:

  • get everyone involved
  • be open source
  • be the long-term solution for finding banners
  • never stop developing
" }, "question2": { "title": "How do I get Ingress missions to bannergress.com? (Part 1: setup)", @@ -264,6 +270,10 @@ } } }, + "error": { + "title": "Error la página no fue encontrada", + "newestBanners": "Intenta empezar con los banners más nuevos" + }, "search": { "title": "Buscando {{searchTerm}}", "button": "Bucar", @@ -283,6 +293,7 @@ "missing_other": "faltan {{count}}", "markedOffline": "Misión marcada como no disponible", "viewOnIntel": "Ver misión en el Intel de Ingress", + "viewInScanner": "Vista en el Escaner", "inBanner": "Misiones en el banner", "placeholder": "Misión de relleno {{index}}", "notFound": "No se han encontrado misiones", @@ -354,4 +365,4 @@ "eventAt": "Evento el .", "eventFromTo": "Evento del al ." } -} \ No newline at end of file +} diff --git a/src/mobile.less b/src/mobile.less deleted file mode 100644 index c03c2d7b..00000000 --- a/src/mobile.less +++ /dev/null @@ -1,168 +0,0 @@ -.bottom-menu { - display: none; -} - -@mobile-detection: ~" screen and (max-width: 880px) "; -@mobile-xs-detection: ~" screen and (max-width: 321px) "; -@mobile-l-detection: ~" screen and (min-width: 426px) "; - -@media only @mobile-xs-detection { - .banner-list { - justify-content: center; - .banner-list-entry { - width: 296px; - } - } -} - -@media only @mobile-l-detection { - .banner-card-picture-container { - height: 200px; - } -} - -@media only @mobile-detection { - .hide-on-mobile { - display: none !important; - } - - .brand-logo { - width: 50vw; - } - - .banner-info-page { - height: 100%; - - .banner-card-title { - display: none !important; - } - .banner-info-overview .banner-info-container { - padding-right: unset; - width: 320px; - } - } - - .banner-info-with-map-container { - display: flex !important; - flex-direction: column !important; - height: inherit !important; - padding: 0 !important; - - .banner-info-with-map { - margin: 0 !important; - padding: 0 !important; - justify-content: center !important; - height: 100% !important; - overflow-y: auto !important; - - .banner-info { - min-height: 0 !important; - padding: 0.6em !important; - width: 100% !important; - max-width: 864px !important; - min-width: 320px !important; - height: auto !important; - overflow-y: unset !important; - } - - .banner-info-left-pane-missions { - .banner-card { - display: none !important; - } - } - - .mission-card { - max-width: none !important; - } - - .banner-info-additional { - height: 100% !important; - } - - .leaflet-container { - height: 100% !important; - width: 100% !important; - min-height: 0 !important; - } - } - - .banner-info-card { - margin-top: 0 !important; - } - - .ant-tabs-nav { - display: none !important; - margin: none !important; - } - - .ant-tabs-tabpane { - margin-top: 0; - } - } - - .banner-count-place { - display: none; - } - - .browser { - .place-accordion { - display: block; - } - - .places-list { - display: none; - } - } - - .bottom-menu { - display: block; - - .menu-main { - a { - flex: 1; - min-width: 0 !important; - } - } - } - - .top-menu .menu-main { - display: none; - } - - .map-explorer { - width: 100% !important; - height: 100%; - display: flex; - flex-direction: column; - } - - .banner-card-picture { - height: auto; - aspect-ratio: 2; - - &.banner-lines-1 { - aspect-ratio: 6; - } - - &.banner-lines-2 { - aspect-ratio: 3; - } - } - - .announcement-and-recent-banners { - margin: 0.4rem; - } - - .banner-list { - justify-content: center; - .banner-list-entry { - width: 360px; - } - } -} - -@media not @mobile-detection { - .hide-on-desktop { - display: none !important; - } -} diff --git a/src/pages/agent/Agent.tsx b/src/pages/agent/Agent.tsx index 28e5f3b6..74bc0eea 100644 --- a/src/pages/agent/Agent.tsx +++ b/src/pages/agent/Agent.tsx @@ -1,209 +1,47 @@ -import React, { Fragment } from 'react' -import { connect } from 'react-redux' -import { Row, Layout } from 'antd' -import { withRouter, RouteComponentProps } from 'react-router-dom' +import { FC, Fragment } from 'react' +import { useParams } from 'react-router-dom' import { Helmet } from 'react-helmet' -import { Trans } from 'react-i18next' +import { useTranslation } from 'react-i18next' -import { RootState } from '../../storeTypes' -import { - Banner, - getAgentBanners, - getHasMoreAgentBanners, - loadAgentBanners as loadAgentBannersAction, -} from '../../features/banner' - -import { withAuthenticated } from '../../hocs/WithAuthenticated' - -import BannerOrderChooser from '../../components/banner-order-chooser' -import BannerList from '../../components/banner-list' import FooterMain from '../../components/footer-main' import LoginRequired from '../../components/login/login-required' - -import './agent.less' +import InfiniteBannerList from '../../components/infinite-banner-list/InfiniteBannerList' import { BannerFilter } from '../../features/banner/filter' -class Agent extends React.Component { - constructor(props: AgentProps) { - super(props) - this.state = { - filter: { - orderBy: 'created', - orderDirection: 'DESC', - online: true, - }, - agentName: '', - pageBanners: 0, - bannersStatus: 'initial', - } - } - - static getDerivedStateFromProps(props: AgentProps, state: AgentState) { - const { match } = props - const { agentName } = state - const newAgentName = decodeURIComponent(match.params.agentName) - - if (agentName !== newAgentName) { - return { - agentName: newAgentName, - pageBanners: 0, - } - } - - return null - } - - componentDidMount() { - const { filter, agentName } = this.state - - this.doFetchBanners(agentName, filter, 0) - } - - componentDidUpdate(prevProps: AgentProps, prevState: AgentState) { - const { authenticated: prevAuthenticated } = prevProps - const { authenticated } = this.props - - const { agentName: prevAgentName } = prevState - const { agentName, filter } = this.state - - if (prevAgentName !== agentName || prevAuthenticated !== authenticated) { - this.doFetchBanners(agentName, filter, 0) - } - } - - onFilterChanged = (filter: BannerFilter) => { - const { agentName } = this.state - this.setState({ - filter, - pageBanners: 0, - }) - this.doFetchBanners(agentName, filter, 0) - } - - onLoadMoreBanners = () => { - const { fetchBanners } = this.props - const { filter, pageBanners, agentName } = this.state - this.setState({ pageBanners: pageBanners + 1 }) - return fetchBanners(agentName, filter, pageBanners + 1) - } - - getPageTitle() { - const { agentName } = this.state - const title = `Agent ${agentName}` - return title - } - - async doFetchBanners( - agentName: string, - filter: BannerFilter, - pageBanners: number - ) { - const { fetchBanners, authenticated } = this.props - - if (authenticated) { - this.setState({ bannersStatus: 'loading' }) - await fetchBanners(agentName, filter, pageBanners) - this.setState({ bannersStatus: 'success' }) - } - } - - render() { - const title: string = this.getPageTitle() - const { bannersStatus, filter } = this.state - const { banners, hasMoreBanners } = this.props - - return ( - - - {title} - -
-
-

{title}

- - -

- Banners -

- - - - - - {bannersStatus === 'success' && ( - <> - {banners.length > 0 && ( - <> - - - - - )} - - {banners.length === 0 && ( - <> - - - No banners found - - - - )} - - )} +import './agent.less' - {(bannersStatus === 'initial' || - bannersStatus === 'loading') && ( - Loading... - )} - -
-
- +const Agent: FC = () => { + const { agentName } = useParams<{ agentName: string }>() + const { t } = useTranslation() + const title = `Agent ${agentName}` + + const initialFilter: BannerFilter = { + author: agentName, + orderBy: 'created', + orderDirection: 'DESC', + online: true, + } + + return ( + + + {title} + +
+
+

{title}

+ +

{t('banners.title')}

+ +
- - ) - } -} - -export interface AgentProps extends RouteComponentProps<{ agentName: string }> { - banners: Array - hasMoreBanners: Boolean - fetchBanners: ( - agentName: string, - filter: BannerFilter, - pageBanners: number - ) => Promise - authenticated: Boolean -} - -interface AgentState { - filter: BannerFilter - agentName: string - pageBanners: number - bannersStatus: 'initial' | 'success' | 'loading' | 'error' -} - -const mapStateToProps = (state: RootState) => ({ - banners: getAgentBanners(state), - hasMoreBanners: getHasMoreAgentBanners(state), -}) - -const mapDispatchToProps = { - fetchBanners: loadAgentBannersAction, + +
+
+ ) } -export default connect( - mapStateToProps, - mapDispatchToProps -)(withAuthenticated(withRouter(Agent))) +export default Agent diff --git a/src/pages/banner-info/BannerInfo.tsx b/src/pages/banner-info/BannerInfo.tsx index 164fe531..af7e9ddd 100644 --- a/src/pages/banner-info/BannerInfo.tsx +++ b/src/pages/banner-info/BannerInfo.tsx @@ -66,14 +66,7 @@ class BannerInfo extends React.Component { ) } if (status !== 'error') { - return ( - - ) + return } return ( No banners found with that id diff --git a/src/pages/banner-info/banner-info.less b/src/pages/banner-info/banner-info.less index 680c79d1..6e96e01c 100644 --- a/src/pages/banner-info/banner-info.less +++ b/src/pages/banner-info/banner-info.less @@ -1,3 +1,24 @@ +@mobile-detection: ~" screen and (max-width: 880px) "; + .banner-info-page { height: 100%; -} \ No newline at end of file + + @media only @mobile-detection { + height: 100%; + } + + .banner-card-title { + @media only @mobile-detection { + display: none !important; + } + } + + .banner-info-overview { + .banner-info-container { + @media only @mobile-detection { + padding-right: unset; + width: 320px; + } + } + } +} diff --git a/src/pages/browser/Browser.tsx b/src/pages/browser/Browser.tsx index 5a9e54c4..07917aa2 100644 --- a/src/pages/browser/Browser.tsx +++ b/src/pages/browser/Browser.tsx @@ -26,7 +26,7 @@ import BannerList from '../../components/banner-list' import BannerOrderChooser from '../../components/banner-order-chooser' import FooterMain from '../../components/footer-main' import { PlaceAccordion } from '../../components/place-accordion/PlaceAccordion' -import SVGMap from '../../img/icons/map.svg?react' +import SVGMap from '../../assets/img/icons/map.svg?react' import './browser.less' import LoadingOverlay from '../../components/loading-overlay' @@ -178,14 +178,7 @@ class Browser extends React.Component { const { filter, selectedPlaceId, status } = this.state if (status === 'initial') { - return ( - - ) + return } let administrativeAreas: Array | null = null @@ -281,7 +274,7 @@ class Browser extends React.Component { banners={banners} hasMoreBanners={hasMore} loadMoreBanners={this.onLoadMoreBanners} - applyBannerListStlyes + applyBannerListStyles hideBlacklisted showDetailsButton={false} /> diff --git a/src/pages/browser/browser.less b/src/pages/browser/browser.less index 104895d2..a89ea3b8 100644 --- a/src/pages/browser/browser.less +++ b/src/pages/browser/browser.less @@ -1,10 +1,12 @@ +@mobile-detection: ~" screen and (max-width: 880px) "; + .browser-icon { - color: #EAEAEA; - fill: #EAEAEA; - vertical-align: middle; - margin-left: 0.5em; - height: 0.9em; - } + color: var(--color-white-light); + fill: var(--color-white-light); + vertical-align: middle; + margin-left: 0.5em; + height: 0.9em; +} .browser { display: flex; @@ -12,10 +14,18 @@ .places-list { flex: 1; max-width: 400px; + + @media only @mobile-detection { + display: none; + } } .place-accordion { display: none; + + @media only @mobile-detection { + display: block; + } } .places-banners { diff --git a/src/pages/create-banner/CreateBanner.tsx b/src/pages/create-banner/CreateBanner.tsx index bb4ad688..001a3f47 100644 --- a/src/pages/create-banner/CreateBanner.tsx +++ b/src/pages/create-banner/CreateBanner.tsx @@ -2,7 +2,7 @@ import React from 'react' import { connect } from 'react-redux' import { withRouter, RouteComponentProps, Prompt } from 'react-router-dom' import { Beforeunload } from 'react-beforeunload' -import { Input, InputNumber, Button } from 'antd' +import { Input, InputNumber, Button, Tooltip } from 'antd' import { Helmet } from 'react-helmet' import _ from 'underscore' import Scrollbars from 'react-custom-scrollbars-2' @@ -45,8 +45,9 @@ import { import AdvancedOptions from '../../components/advanced-options' import { IssuesList } from '../../components/Issues-list' import LoginRequired from '../../components/login/login-required' -import SVGRightArrow from '../../img/icons/right_arrow.svg?react' -import SVGCross from '../../img/icons/cross.svg?react' +import SVGRightArrow from '../../assets/img/icons/right_arrow.svg?react' +import SVGCross from '../../assets/img/icons/cross.svg?react' +import SVGHelp from '../../assets/img/icons/help-round.svg?react' import { getBannerIssues, MAX_MISSIONS } from './getBannerIssues' import './create-banner.less' @@ -775,6 +776,20 @@ class CreateBanner extends React.Component< bannerTitle, detectedLength ) + const markdownHelp = ( + , + code: , + pre:
,
+          p: 

, + ul: