diff --git a/src/components/icons/alert-message-o.tsx b/src/components/icons/alert-message-o.tsx new file mode 100644 index 000000000..a634afcdb --- /dev/null +++ b/src/components/icons/alert-message-o.tsx @@ -0,0 +1,18 @@ +// THIS FILE IS AUTOGENERATED, DO NOT MODIFY MANUALLY +/* tslint:disable */ +/* This Source Code Form is subject to the terms of the Mozilla Public +* License. v. 2.0. If a copy of the MPL was not distributed with this file. +* You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import * as React from 'react' +import GenerateComponentForGraphic from './template' + +// Direct access to SVG +export const Graphic = ( + + + +) + +// Styled Component for SVG +export default GenerateComponentForGraphic(Graphic) diff --git a/src/components/icons/index.tsx b/src/components/icons/index.tsx index f5a72a36b..65bdc1581 100644 --- a/src/components/icons/index.tsx +++ b/src/components/icons/index.tsx @@ -18,6 +18,7 @@ function RotatedIconComponent ( // simple export { default as AlertCircleIcon } from './alert-circle' +export { default as AlertMessageIcon } from './alert-message-o' export const ArrowLeftIcon = RotatedIconComponent(ArrowIcon, 0) export const ArrowRightIcon = RotatedIconComponent(ArrowIcon, 180) export const ArrowDownIcon = RotatedIconComponent(ArrowIcon, -90) diff --git a/src/features/shields/data/index.ts b/src/features/shields/data/index.ts new file mode 100644 index 000000000..b6985db94 --- /dev/null +++ b/src/features/shields/data/index.ts @@ -0,0 +1,27 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License. v. 2.0. If a copy of the MPL was not distributed with this file. + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +export const dummyData = { + thirdPartyCookiesBlocked: '2', + thirdPartyScriptsBlocked: '2', + thirdPartyDeviceRecognitionBlocked: '2', + pishingMalwareBlocked: '2', + connectionsEncrypted: '2', + noScriptsResouces: { + 'https://imasdk.googleapis.com/js/sdkloader/ima3.js': { + actuallyBlocked: true, + willBlock: true, + userInteracted: true + }, + 'https://scripts.dailymail.co.uk/rta2/v-0.37.min.js': { + actuallyBlocked: true, + willBlock: true, + userInteracted: true + } + }, + otherBlockedResources: [ + 'https://aaaa.com/abcdefghijklmnopqrstuwxyz/123456789', + 'https://bbbb.com/abcdefghijklmnopqrstuwxyz/123456789' + ] +} diff --git a/src/features/shields/display.ts b/src/features/shields/display.ts index 5c3166d95..588690eea 100644 --- a/src/features/shields/display.ts +++ b/src/features/shields/display.ts @@ -136,13 +136,14 @@ export const Link = styled<{}, 'button'>('button')` font-size: 13px; font-weight: 500; display: inline-block; + text-align: left; + width: fit-content; &:hover { text-decoration: underline; } &:focus { - outline-offset: 6px; outline-color: ${p => p.theme.color.brandBrave}; outline-width: 2px; } diff --git a/src/features/shields/index.ts b/src/features/shields/index.ts index 3bc88eea3..3daa63902 100644 --- a/src/features/shields/index.ts +++ b/src/features/shields/index.ts @@ -12,8 +12,12 @@ export { SiteInfo, // Controls BlockedInfoRow, + BlockedInfoRowDetails, + BlockedInfoRowSummary, BlockedInfoRowSingle, + BlockedInfoRowSingleText, BlockedInfoRowForSelect, + BlockedInfoRowForSelectSummary, BlockedInfoRowData, BlockedInfoRowDataForSelect, // footer @@ -31,7 +35,15 @@ export { BlockedListItemSummary, BlockedListFooter, BlockedListFooterWithOptions, - DisabledContentView + DisabledContentView, + // Static content + StaticHeader, + StaticResourcesControls, + StaticResourcesContainer, + // Overlay + Overlay, + WarningText, + WarningModal } from './structure' export { @@ -58,6 +70,7 @@ export { ShieldsButton } from './display' -export { ArrowDownIcon, ArrowUpIcon, ShieldIcon } from './media' +export { ArrowDownIcon, ArrowUpIcon, ShieldIcon, WarningIcon } from './media' export { Toggle } from './toggle' export { SelectBox } from './select' +export { dummyData } from './data' diff --git a/src/features/shields/media/index.ts b/src/features/shields/media/index.ts index 774024296..8c4a994ee 100644 --- a/src/features/shields/media/index.ts +++ b/src/features/shields/media/index.ts @@ -4,7 +4,7 @@ import styled from '../../../theme' import { StyledComponentClass } from 'styled-components' -import { CaratStrongDownIcon, ShieldAlertIcon } from '../../../components/icons' +import { CaratStrongDownIcon, ShieldAlertIcon, AlertMessageIcon } from '../../../components/icons' import { ComponentType } from 'react' @@ -26,11 +26,21 @@ export const ShieldIcon = styled(ShieldAlertIcon as ComponentType)` color: ${p => p.theme.color.lionLogo}; ` +export const WarningIcon = styled(AlertMessageIcon as ComponentType)` + box-sizing: border-box; + display: block; + width: 48px; + height: auto; + margin: 0 auto 12px; + color: ${p => p.theme.color.lionLogo}; +` + export const ArrowDownIcon = styled(CaratStrongDownIcon as ComponentType)` width: 24px; height: 24px; padding: 4px; color: ${p => p.theme.color.text}; + pointer-events: none; &:focus { outline-width: 2px; diff --git a/src/features/shields/select/index.ts b/src/features/shields/select/index.ts index 716bf9fc2..9c05110d6 100644 --- a/src/features/shields/select/index.ts +++ b/src/features/shields/select/index.ts @@ -11,6 +11,7 @@ export interface SelectBoxProps { multiple?: boolean autoFocus?: boolean disabled?: boolean + readOnly?: boolean value?: string onChange?: (e: any) => void children: React.ReactNode @@ -32,6 +33,7 @@ export const SelectBox = styled('select')` line-height: 18px; font-family: ${p => p.theme.fontFamily.heading}; border: 1px solid ${p => p.theme.color.inputBorder}; + pointer-events: ${p => p.readOnly && 'none'}; background: url(${caratUrl}) 97% / 16px no-repeat transparent; /* avoid text overflow w/ carat */ -webkit-padding-start: 10px; diff --git a/src/features/shields/structure/index.ts b/src/features/shields/structure/index.ts index b81cb7fb6..df77c8c32 100644 --- a/src/features/shields/structure/index.ts +++ b/src/features/shields/structure/index.ts @@ -71,10 +71,14 @@ export const SiteOverview = styled('div')` padding: 32px 0; ` -export const TotalBlockedStats = styled<{}, 'section'>('section')` +interface TotalBlockedStatsProps { + size?: 'large' +} + +export const TotalBlockedStats = styled('section')` box-sizing: border-box; display: grid; - grid-template-columns: 80px 140px; + grid-template-columns: ${p => p.size === 'large' ? '80px 210px' : '80px 140px'}; align-items: center; margin: 0px auto 5px; grid-gap: 10px; @@ -85,7 +89,7 @@ export const SiteInfo = styled<{}, 'div'>('div')` display: grid; grid-template-columns: auto 1fr; align-items: center; - margin: 0px auto 5px; + margin: 0px auto 7px; gap: 8px; ` @@ -122,19 +126,55 @@ export const BlockedInfoRow = styled('div')` } ` +export const BlockedInfoRowDetails = styled('details')` + box-sizing: border-box; +` + +export const BlockedInfoRowSummary = styled(BlockedInfoRow.withComponent('summary'))` + &::-webkit-details-marker { + display: none; + } + + &:focus { + outline-color: ${p => p.theme.color.brandBrave}; + outline-offset: -3px; + outline-width: 2px; + } +` + export const BlockedInfoRowSingle = styled(BlockedInfoRow)` padding: 8px 24px 8px 74px; cursor: default; grid-template-columns: 1fr; ` +export const BlockedInfoRowSingleText = styled(BlockedInfoRow)` + padding: 14px 24px 14px 84px; + cursor: default; + grid-template-columns: 1fr; +` + export const BlockedInfoRowForSelect = styled(BlockedInfoRow)` grid-template-columns: auto 1fr; padding-right: 24px; ` +export const BlockedInfoRowForSelectSummary = styled(BlockedInfoRowForSelect.withComponent('summary'))` + &::-webkit-details-marker { + display: none; + } + + &:focus { + outline-color: ${p => p.theme.color.brandBrave}; + outline-offset: -3px; + outline-width: 2px; + } + + box-sizing: border-box; +` + interface BlockedInfoRowDataProps { - disabled: boolean + disabled?: boolean } export const BlockedInfoRowData = styled('div')` @@ -194,6 +234,9 @@ export const BlockedInfoRowDataForSelect = styled(BlockedInfoRowData)` */ export const MainFooter = styled<{}, 'div'>('div')` box-sizing: border-box; + position: relative; + display: grid; + grid-gap: 16px; padding: 24px; ` @@ -246,10 +289,14 @@ export const BlockedListSummary = styled('su } ` -export const BlockedListStatic = styled<{}, 'ul'>('ul')` +interface BlockedListStaticProps { + fixedHeight?: boolean +} + +export const BlockedListStatic = styled('ul')` box-sizing: border-box; list-style-type: none; - height: 328px; + height: ${p => p.fixedHeight && '358px'}; overflow: auto; padding: 0 0 0 24px; margin: 0; @@ -387,3 +434,56 @@ export const DisabledContentView = styled<{}, 'section'>('section')` max-width: 80%; margin: 5px auto 8px; ` + +/** + * Static panel (learn more overlay) + */ +export const StaticHeader = styled<{}, 'header'>('header')` + padding: 0 20px 10px 24px; + line-height: 18px; +` + +export const StaticResourcesControls = styled<{}, 'div'>('div')` + box-sizing: border-box; + position: relative; + height: 216px; + overflow: auto; +` + +export const StaticResourcesContainer = styled<{}, 'div'>('div')` + box-sizing: border-box; + position: absolute; + width: 100%; +` + +/** + * Modals and overlays + */ +export const Overlay = styled<{}, 'div'>('div')` + box-sizing: border-box; + position: absolute; + z-index: 5; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + padding: 0 44px; + background-color: ${p => p.theme.color.modalOverlayBackground} +` +export const WarningText = styled<{}, 'p'>('p')` + margin: 0 0 24px; + line-height: 18px; +` + +export const WarningModal = styled<{}, 'div'>('div')` + box-sizing: border-box; + display: flex; + flex-direction: column; + align-items: center; + justify-content: space-between; + text-align: center; + min-height: 100px; +` diff --git a/src/theme/shields-dark.ts b/src/theme/shields-dark.ts index 52df0f7bf..8ac8cfee9 100644 --- a/src/theme/shields-dark.ts +++ b/src/theme/shields-dark.ts @@ -12,9 +12,9 @@ const shieldsDarkTheme: ITheme = { panelBackground: '#17171F', panelBackgroundSecondary: colors.grey900, inputBorder: colors.grey700, - separatorLine: colors.grey800 + separatorLine: colors.grey800, + modalOverlayBackground: 'rgba(33, 37, 41, 70%)' } - } export default shieldsDarkTheme diff --git a/src/theme/shields-light.ts b/src/theme/shields-light.ts index af3a4c408..a9d32e6bc 100644 --- a/src/theme/shields-light.ts +++ b/src/theme/shields-light.ts @@ -8,7 +8,8 @@ const shieldsLightTheme: ITheme = { color: { ...defaultTheme.color, text: colors.neutral900, - panelBackgroundSecondary: colors.neutral000 + panelBackgroundSecondary: colors.neutral000, + modalOverlayBackground: 'rgba(255, 255, 255, 70%)' } } diff --git a/stories/features/shields/components/controls/adsTrackersControl.tsx b/stories/features/shields/components/advancedView/controls/adsTrackersControl.tsx similarity index 92% rename from stories/features/shields/components/controls/adsTrackersControl.tsx rename to stories/features/shields/components/advancedView/controls/adsTrackersControl.tsx index b02a7bab7..07c156af4 100644 --- a/stories/features/shields/components/controls/adsTrackersControl.tsx +++ b/stories/features/shields/components/advancedView/controls/adsTrackersControl.tsx @@ -12,17 +12,17 @@ import { BlockedInfoRowStats, BlockedInfoRowText, Toggle -} from '../../../../../src/features/shields' +} from '../../../../../../src/features/shields' // Group Components -import StaticList from '../list/static' +import StaticList from '../overlays/staticOverlay' // Fake data -import { getLocale } from '../../fakeLocale' -import data from '../../fakeData' +import { getLocale } from '../../../fakeLocale' +import data from '../../../fakeData' // Helpers -import { getTabIndexValueBasedOnProps } from '../../helpers' +import { getTabIndexValueBasedOnProps } from '../../../helpers' interface Props { favicon: string diff --git a/stories/features/shields/components/controls/cookiesControl.tsx b/stories/features/shields/components/advancedView/controls/cookiesControl.tsx similarity index 93% rename from stories/features/shields/components/controls/cookiesControl.tsx rename to stories/features/shields/components/advancedView/controls/cookiesControl.tsx index 18daa63cd..99b889714 100644 --- a/stories/features/shields/components/controls/cookiesControl.tsx +++ b/stories/features/shields/components/advancedView/controls/cookiesControl.tsx @@ -5,10 +5,10 @@ import * as React from 'react' // Feature-specific components -import { BlockedInfoRowSingle, SelectBox } from '../../../../../src/features/shields' +import { BlockedInfoRowSingle, SelectBox } from '../../../../../../src/features/shields' // Fake data -import { getLocale } from '../../fakeLocale' +import { getLocale } from '../../../fakeLocale' interface Props { isBlockedListOpen: boolean diff --git a/stories/features/shields/components/controls/deviceRecognitionControl.tsx b/stories/features/shields/components/advancedView/controls/deviceRecognitionControl.tsx similarity index 92% rename from stories/features/shields/components/controls/deviceRecognitionControl.tsx rename to stories/features/shields/components/advancedView/controls/deviceRecognitionControl.tsx index c17c26528..eb3bf3df0 100644 --- a/stories/features/shields/components/controls/deviceRecognitionControl.tsx +++ b/stories/features/shields/components/advancedView/controls/deviceRecognitionControl.tsx @@ -11,17 +11,17 @@ import { ArrowDownIcon, BlockedInfoRowStats, SelectBox -} from '../../../../../src/features/shields' +} from '../../../../../../src/features/shields' // Group Components -import StaticList from '../list/static' +import StaticList from '../overlays/staticOverlay' // Fake data -import { getLocale } from '../../fakeLocale' -import data from '../../fakeData' +import { getLocale } from '../../../fakeLocale' +import data from '../../../fakeData' // Helpers -import { getTabIndexValueBasedOnProps } from '../../helpers' +import { getTabIndexValueBasedOnProps } from '../../../helpers' interface Props { favicon: string diff --git a/stories/features/shields/components/controls/httpsUpgradesControl.tsx b/stories/features/shields/components/advancedView/controls/httpsUpgradesControl.tsx similarity index 92% rename from stories/features/shields/components/controls/httpsUpgradesControl.tsx rename to stories/features/shields/components/advancedView/controls/httpsUpgradesControl.tsx index a1c37f0dd..b728f38ca 100644 --- a/stories/features/shields/components/controls/httpsUpgradesControl.tsx +++ b/stories/features/shields/components/advancedView/controls/httpsUpgradesControl.tsx @@ -12,17 +12,17 @@ import { BlockedInfoRowStats, BlockedInfoRowText, Toggle -} from '../../../../../src/features/shields' +} from '../../../../../../src/features/shields' // Group Components -import StaticList from '../list/static' +import StaticList from '../overlays/staticOverlay' // Fake data -import { getLocale } from '../../fakeLocale' -import data from '../../fakeData' +import { getLocale } from '../../../fakeLocale' +import data from '../../../fakeData' // Helpers -import { getTabIndexValueBasedOnProps } from '../../helpers' +import { getTabIndexValueBasedOnProps } from '../../../helpers' interface Props { favicon: string diff --git a/stories/features/shields/components/controls/scriptsControl.tsx b/stories/features/shields/components/advancedView/controls/scriptsControl.tsx similarity index 92% rename from stories/features/shields/components/controls/scriptsControl.tsx rename to stories/features/shields/components/advancedView/controls/scriptsControl.tsx index c98534ba7..d6d253038 100644 --- a/stories/features/shields/components/controls/scriptsControl.tsx +++ b/stories/features/shields/components/advancedView/controls/scriptsControl.tsx @@ -13,17 +13,17 @@ import { BlockedInfoRowText, Toggle, LinkAction -} from '../../../../../src/features/shields' +} from '../../../../../../src/features/shields' // Group Components -import NoScriptDetails from '../list/noScriptDetails' +import NoScriptOverlay from '../overlays/noScriptOverlay' // Fake data -import { getLocale } from '../../fakeLocale' -import data from '../../fakeData' +import { getLocale } from '../../../fakeLocale' +import data from '../../../fakeData' // Helpers -import { getTabIndexValueBasedOnProps } from '../../helpers' +import { getTabIndexValueBasedOnProps } from '../../../helpers' interface Props { favicon: string @@ -108,7 +108,7 @@ export default class ScriptsControls extends React.PureComponent { { scriptsBlockedOpen && - void + fakeOnChangeShieldsEnabled: () => void } export default class Header extends React.PureComponent { @@ -69,7 +69,13 @@ export default class Header extends React.PureComponent { } render () { - const { fakeOnChange, enabled, favicon, hostname, isBlockedListOpen } = this.props + const { + enabled, + favicon, + hostname, + isBlockedListOpen, + fakeOnChangeShieldsEnabled + } = this.props return ( @@ -83,7 +89,7 @@ export default class Header extends React.PureComponent { {enabled ? {getLocale('enabledMessage')} : null} - + diff --git a/stories/features/shields/components/advancedView/index.tsx b/stories/features/shields/components/advancedView/index.tsx new file mode 100644 index 000000000..8629dc63e --- /dev/null +++ b/stories/features/shields/components/advancedView/index.tsx @@ -0,0 +1,103 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import * as React from 'react' + +// Feature-specific components +import { ShieldsPanel } from '../../../../../src/features/shields' + +// Components group +import Header from './header' +import InterfaceControls from './interfaceControls' +import PrivacyControls from './privacyControls' +import Footer from '../shared/footer' +import WebCompatWarning from './overlays/webCompatWarningOverlay' + +interface Props { + enabled: boolean + firstAccess: boolean + hostname: string + advancedView: boolean + favicon: string + adsTrackersBlocked: number + httpsUpgrades: number + scriptsBlocked: number + fingerprintingBlocked: number + fakeOnChangeShieldsEnabled: () => void + fakeOnChangeAdvancedView: () => void + fakeToggleFirstAccess: () => void +} + +interface State { + isBlockedListOpen: boolean +} + +export default class ShieldsAdvancedView extends React.PureComponent { + constructor (props: Props) { + super(props) + this.state = { isBlockedListOpen: false } + } + setBlockedListOpen = () => { + this.setState({ isBlockedListOpen: !this.state.isBlockedListOpen }) + } + render () { + const { + enabled, + firstAccess, + favicon, + hostname, + adsTrackersBlocked, + httpsUpgrades, + scriptsBlocked, + fingerprintingBlocked, + fakeOnChangeShieldsEnabled, + fakeOnChangeAdvancedView, + fakeToggleFirstAccess + } = this.props + const { isBlockedListOpen } = this.state + return ( + + {firstAccess ? : null} + + { + enabled ? ( + <> + + + > + ) : null + } + + + ) + } +} diff --git a/stories/features/shields/components/interfaceControls.tsx b/stories/features/shields/components/advancedView/interfaceControls.tsx similarity index 100% rename from stories/features/shields/components/interfaceControls.tsx rename to stories/features/shields/components/advancedView/interfaceControls.tsx diff --git a/stories/features/shields/components/list/noScriptDetails.tsx b/stories/features/shields/components/advancedView/overlays/noScriptOverlay.tsx similarity index 92% rename from stories/features/shields/components/list/noScriptDetails.tsx rename to stories/features/shields/components/advancedView/overlays/noScriptOverlay.tsx index 34e6dcd76..25158d84d 100644 --- a/stories/features/shields/components/list/noScriptDetails.tsx +++ b/stories/features/shields/components/advancedView/overlays/noScriptOverlay.tsx @@ -6,17 +6,17 @@ import * as React from 'react' // Components -import NoScriptList from './noScriptList' +import NoScriptList from '../../shared/resourcesBlockedList/scriptResourcesList' // Types -import { NoScriptInfoInterface } from '../../types' +import { NoScriptInfoInterface } from '../../../types' // Helpers import { generateNoScriptInfoDataStructure, filterNoScriptInfoByBlockedState, getBlockAllText -} from '../../helpers' +} from '../../../helpers' import { BlockedListHeader, @@ -33,10 +33,10 @@ import { BlockedListItemHeaderStats, BlockedListItemHeaderText, ShieldsButton -} from '../../../../../src/features/shields' +} from '../../../../../../src/features/shields' // Helpers -import { getLocale } from '../../fakeLocale' +import { getLocale } from '../../../fakeLocale' interface Props { favicon: string @@ -88,7 +88,7 @@ export default class CoreFeature extends React.PureComponent { {getLocale('scriptsOnThisSite')} - + { this.blockedScriptsLength > 0 && ( <> diff --git a/stories/features/shields/components/list/static.tsx b/stories/features/shields/components/advancedView/overlays/staticOverlay.tsx similarity index 70% rename from stories/features/shields/components/list/static.tsx rename to stories/features/shields/components/advancedView/overlays/staticOverlay.tsx index 064443076..76a454191 100644 --- a/stories/features/shields/components/list/static.tsx +++ b/stories/features/shields/components/advancedView/overlays/staticOverlay.tsx @@ -7,9 +7,8 @@ import * as React from 'react' import { BlockedListHeader, BlockedListSummary, - BlockedListContent, BlockedListStatic, - BlockedListItem, + BlockedListContent, BlockedListFooter, ArrowUpIcon, Favicon, @@ -17,13 +16,13 @@ import { BlockedInfoRowStats, BlockedListSummaryText, ShieldsButton -} from '../../../../../src/features/shields' +} from '../../../../../../src/features/shields' -// Helpers -import { stripProtocolFromUrl } from '../../helpers' +// Group components +import StaticResourcesList from '../../shared/resourcesBlockedList/staticResourcesList' // Fake data -import { getLocale } from '../../fakeLocale' +import { getLocale } from '../../../fakeLocale' interface Props { favicon: string @@ -46,12 +45,12 @@ export default class StaticList extends React.PureComponent { - {stats > 99 ? '99+' : stats} - {name} - - - {list.map((item, index) => {stripProtocolFromUrl(item)})} - + {stats > 99 ? '99+' : stats} + {name} + + + + diff --git a/stories/features/shields/components/advancedView/overlays/webCompatWarningOverlay.tsx b/stories/features/shields/components/advancedView/overlays/webCompatWarningOverlay.tsx new file mode 100644 index 000000000..bf6fc1e0d --- /dev/null +++ b/stories/features/shields/components/advancedView/overlays/webCompatWarningOverlay.tsx @@ -0,0 +1,48 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import * as React from 'react' + +// Feature-specific components +import { + Overlay, + WarningModal, + WarningIcon, + WarningText, + ShieldsButton +} from '../../../../../../src/features/shields' + +// Shared components +import { Card } from '../../../../../../src/components' + +// Helpers +import { getLocale } from '../../../fakeLocale' + +interface Props { + onConfirm: () => void +} + +export default class WebCompatWarning extends React.PureComponent { + render () { + const { onConfirm } = this.props + return ( + + + + + + {getLocale('webCompatWarning')} + + + + + + ) + } +} diff --git a/stories/features/shields/components/privacyControls.tsx b/stories/features/shields/components/advancedView/privacyControls.tsx similarity index 100% rename from stories/features/shields/components/privacyControls.tsx rename to stories/features/shields/components/advancedView/privacyControls.tsx diff --git a/stories/features/shields/components/readOnlyView/controls/adsTrackersControl.tsx b/stories/features/shields/components/readOnlyView/controls/adsTrackersControl.tsx new file mode 100644 index 000000000..37c0899b3 --- /dev/null +++ b/stories/features/shields/components/readOnlyView/controls/adsTrackersControl.tsx @@ -0,0 +1,59 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import * as React from 'react' + +// Feature-specific components +import { + BlockedInfoRowText, + BlockedInfoRowData, + BlockedInfoRowDetails, + BlockedInfoRowSummary, + ArrowUpIcon, + ArrowDownIcon, + BlockedInfoRowStats, + BlockedListStatic, + dummyData +} from '../../../../../../src/features/shields' + +// Group components +import StaticResourcesList from '../../shared/resourcesBlockedList/staticResourcesList' + +// Helpers +import { getLocale } from '../../../fakeLocale' + +interface State { + dummyThirdPartyTrackersBlockedOpen: boolean +} + +export default class AdsTrackersControl extends React.PureComponent<{}, State> { + constructor (props: {}) { + super(props) + this.state = { dummyThirdPartyTrackersBlockedOpen: false } + } + onClickFakeThirdPartyTrackersBlocked = () => { + this.setState({ dummyThirdPartyTrackersBlockedOpen: !this.state.dummyThirdPartyTrackersBlockedOpen }) + } + render () { + const { dummyThirdPartyTrackersBlockedOpen } = this.state + return ( + + + + { + dummyThirdPartyTrackersBlockedOpen + ? + : + } + {2} + {getLocale('thirdPartyTrackersBlocked')} + + + + + + + ) + } +} diff --git a/stories/features/shields/components/readOnlyView/controls/cookiesControl.tsx b/stories/features/shields/components/readOnlyView/controls/cookiesControl.tsx new file mode 100644 index 000000000..0954617dd --- /dev/null +++ b/stories/features/shields/components/readOnlyView/controls/cookiesControl.tsx @@ -0,0 +1,26 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import * as React from 'react' + +// Feature-specific components +import { + BlockedInfoRowSingleText, + BlockedInfoRowText +} from '../../../../../../src/features/shields' + +// Helpers +import { getLocale } from '../../../fakeLocale' + +export default class AdsTrackersControl extends React.PureComponent<{}, {}> { + render () { + return ( + + + {getLocale('thirdPartyCookiesBlocked')} + + + ) + } +} diff --git a/stories/features/shields/components/readOnlyView/controls/deviceRecognitionControl.tsx b/stories/features/shields/components/readOnlyView/controls/deviceRecognitionControl.tsx new file mode 100644 index 000000000..9a5ae3a36 --- /dev/null +++ b/stories/features/shields/components/readOnlyView/controls/deviceRecognitionControl.tsx @@ -0,0 +1,62 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import * as React from 'react' + +// Feature-specific components +import { + BlockedInfoRowDetails, + BlockedInfoRowSummary, + BlockedInfoRowData, + ArrowUpIcon, + ArrowDownIcon, + BlockedInfoRowStats, + BlockedInfoRowText, + BlockedListStatic, + dummyData +} from '../../../../../../src/features/shields' + +// Group components +import StaticResourcesList from '../../shared/resourcesBlockedList/staticResourcesList' + +// Helpers +import { getLocale } from '../../../fakeLocale' + +interface State { + dummyThirdPartyFingerprintingBlockedOpen: boolean +} + +export default class AdsTrackersControl extends React.PureComponent<{}, State> { + constructor (props: {}) { + super(props) + this.state = { dummyThirdPartyFingerprintingBlockedOpen: false } + } + + onClickFakeThirdPartyFingerprintingBlocked = () => { + this.setState({ dummyThirdPartyFingerprintingBlockedOpen: !this.state.dummyThirdPartyFingerprintingBlockedOpen }) + } + render () { + const { dummyThirdPartyFingerprintingBlockedOpen } = this.state + return ( + + + + { + dummyThirdPartyFingerprintingBlockedOpen + ? + : + } + {2} + + {getLocale('thirdPartyFingerprintingBlocked')} + + + + + + + + ) + } +} diff --git a/stories/features/shields/components/readOnlyView/controls/httpsUpgradesControl.tsx b/stories/features/shields/components/readOnlyView/controls/httpsUpgradesControl.tsx new file mode 100644 index 000000000..fbb26ff0a --- /dev/null +++ b/stories/features/shields/components/readOnlyView/controls/httpsUpgradesControl.tsx @@ -0,0 +1,61 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import * as React from 'react' + +// Feature-specific components +import { + BlockedInfoRowText, + BlockedInfoRowData, + BlockedInfoRowDetails, + BlockedInfoRowSummary, + ArrowUpIcon, + ArrowDownIcon, + BlockedInfoRowStats, + BlockedListStatic, + dummyData +} from '../../../../../../src/features/shields' + +// Group components +import StaticResourcesList from '../../shared/resourcesBlockedList/staticResourcesList' + +// Helpers +import { getLocale } from '../../../fakeLocale' + +interface State { + dummyConnectionsUpgradedHTTPSOpen: boolean +} + +export default class AdsTrackersControl extends React.PureComponent<{}, State> { + constructor (props: {}) { + super(props) + this.state = { dummyConnectionsUpgradedHTTPSOpen: false } + } + + onClickFakeConnectionsUpgradedHTTPS = () => { + this.setState({ dummyConnectionsUpgradedHTTPSOpen: !this.state.dummyConnectionsUpgradedHTTPSOpen }) + } + + render () { + const { dummyConnectionsUpgradedHTTPSOpen } = this.state + return ( + + + + { + dummyConnectionsUpgradedHTTPSOpen + ? + : + } + {2} + {getLocale('connectionsUpgradedHTTPSCapital')} + + + + + + + ) + } +} diff --git a/stories/features/shields/components/readOnlyView/controls/scriptsControl.tsx b/stories/features/shields/components/readOnlyView/controls/scriptsControl.tsx new file mode 100644 index 000000000..7e70da9bf --- /dev/null +++ b/stories/features/shields/components/readOnlyView/controls/scriptsControl.tsx @@ -0,0 +1,65 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import * as React from 'react' + +// Feature-specific components +import { + BlockedInfoRowText, + BlockedInfoRowData, + BlockedInfoRowDetails, + BlockedInfoRowSummary, + ArrowUpIcon, + ArrowDownIcon, + BlockedInfoRowStats, + BlockedListStatic, + dummyData +} from '../../../../../../src/features/shields' + +// Group components +import StaticResourcesList from '../../shared/resourcesBlockedList/staticResourcesList' + +// Helpers +import { getLocale } from '../../../fakeLocale' +import { generateNoScriptInfoDataStructure } from '../../../helpers' + +interface State { + dummyScriptsBlockedOpen: boolean +} + +export default class AdsTrackersControl extends React.PureComponent<{}, State> { + constructor (props: {}) { + super(props) + this.state = { dummyScriptsBlockedOpen: false } + } + get generateNoScriptInfo () { + return generateNoScriptInfoDataStructure(dummyData.noScriptsResouces) + } + onClickFakeScriptsBlocked = () => { + this.setState({ dummyScriptsBlockedOpen: !this.state.dummyScriptsBlockedOpen }) + } + render () { + const { dummyScriptsBlockedOpen } = this.state + return ( + + + + { + dummyScriptsBlockedOpen + ? + : + } + {2} + + {getLocale('scriptsBlocked')} + + + + + + + + ) + } +} diff --git a/stories/features/shields/components/readOnlyView/index.tsx b/stories/features/shields/components/readOnlyView/index.tsx new file mode 100644 index 000000000..3dba4b1bd --- /dev/null +++ b/stories/features/shields/components/readOnlyView/index.tsx @@ -0,0 +1,58 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import * as React from 'react' + +// Feature-specific components +import { + ShieldsPanel, + BlockedListHeader, + Favicon, + SiteInfoText, + StaticHeader, + StaticResourcesControls, + StaticResourcesContainer, + BlockedInfoRowText, + BlockedListFooter, + ShieldsButton +} from '../../../../../src/features/shields' + +// Group components +import InterfaceControls from './interfaceControls' +import PrivacyControls from './privacyControls' + +// Helpers +import { getLocale } from '../../fakeLocale' + +interface Props { + hostname: string + favicon: string + onClose: (event?: any) => void +} + +export default class ShieldsReadOnlyView extends React.PureComponent { + render () { + const { favicon, hostname, onClose } = this.props + return ( + + + + {hostname} + + + {getLocale('shieldsExplanation')} + + + + + + + + + + + + ) + } +} diff --git a/stories/features/shields/components/readOnlyView/interfaceControls.tsx b/stories/features/shields/components/readOnlyView/interfaceControls.tsx new file mode 100644 index 000000000..a6790c757 --- /dev/null +++ b/stories/features/shields/components/readOnlyView/interfaceControls.tsx @@ -0,0 +1,20 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import * as React from 'react' + +// Group components +import AdsTrackersControl from './controls/adsTrackersControl' +import HTTPSUpgradesControl from './controls/httpsUpgradesControl' + +export default class InterfaceControls extends React.PureComponent<{}, {}> { + render () { + return ( + <> + + + > + ) + } +} diff --git a/stories/features/shields/components/readOnlyView/privacyControls.tsx b/stories/features/shields/components/readOnlyView/privacyControls.tsx new file mode 100644 index 000000000..c4bdc83ec --- /dev/null +++ b/stories/features/shields/components/readOnlyView/privacyControls.tsx @@ -0,0 +1,22 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import * as React from 'react' + +// Group components +import ScriptsControl from './controls/scriptsControl' +import CookiesControl from './controls/cookiesControl' +import DeviceRecognitionControl from './controls/deviceRecognitionControl' + +export default class PrivacyControls extends React.PureComponent<{}, {}> { + render () { + return ( + <> + + + + > + ) + } +} diff --git a/stories/features/shields/components/footer.tsx b/stories/features/shields/components/shared/footer.tsx similarity index 56% rename from stories/features/shields/components/footer.tsx rename to stories/features/shields/components/shared/footer.tsx index c1787f7d3..eba8c1e3a 100644 --- a/stories/features/shields/components/footer.tsx +++ b/stories/features/shields/components/shared/footer.tsx @@ -4,20 +4,25 @@ import * as React from 'react' -import { MainFooter, Link } from '../../../../src/features/shields' +import { MainFooter, Link } from '../../../../../src/features/shields' // Fake data -import { getLocale } from '../fakeLocale' +import { getLocale } from '../../fakeLocale' interface Props { isBlockedListOpen: boolean + advancedView: boolean + fakeOnChangeAdvancedView: () => void } export default class Footer extends React.PureComponent { render () { - const { isBlockedListOpen } = this.props + const { isBlockedListOpen, advancedView, fakeOnChangeAdvancedView } = this.props return ( + + {advancedView ? getLocale('simpleView') : getLocale('advancedView')} + diff --git a/stories/features/shields/components/list/noScriptList.tsx b/stories/features/shields/components/shared/resourcesBlockedList/scriptResourcesList.tsx similarity index 96% rename from stories/features/shields/components/list/noScriptList.tsx rename to stories/features/shields/components/shared/resourcesBlockedList/scriptResourcesList.tsx index a0d56178f..0ba1af27a 100644 --- a/stories/features/shields/components/list/noScriptList.tsx +++ b/stories/features/shields/components/shared/resourcesBlockedList/scriptResourcesList.tsx @@ -11,10 +11,10 @@ import { BlockedListItemSummary, BlockedListItemWithOptions, LinkAction -} from '../../../../../src/features/shields' +} from '../../../../../../src/features/shields' // Types -import { NoScriptInfoInterface } from '../../types' +import { NoScriptInfoInterface } from '../../../types' // Helpers import { @@ -23,7 +23,7 @@ import { getHostname, checkEveryItemIsBlockedOrAllowed, stripProtocolFromUrl -} from '../../helpers' +} from '../../../helpers' interface Props { noScriptInfo: Array diff --git a/stories/features/shields/components/shared/resourcesBlockedList/staticResourcesList.tsx b/stories/features/shields/components/shared/resourcesBlockedList/staticResourcesList.tsx new file mode 100644 index 000000000..479be5a1b --- /dev/null +++ b/stories/features/shields/components/shared/resourcesBlockedList/staticResourcesList.tsx @@ -0,0 +1,24 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import * as React from 'react' + +// Feature-specific components +import { BlockedListItem } from '../../../../../../src/features/shields' + +// Helpers +import { stripProtocolFromUrl } from '../../../helpers' + +interface Props { + list: any[] +} + +export default class StaticResourcesList extends React.PureComponent { + render () { + const { list } = this.props + return list.map((item, index) => + {stripProtocolFromUrl(item)} + ) + } +} diff --git a/stories/features/shields/components/simpleView/header.tsx b/stories/features/shields/components/simpleView/header.tsx new file mode 100644 index 000000000..12738a70e --- /dev/null +++ b/stories/features/shields/components/simpleView/header.tsx @@ -0,0 +1,105 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import * as React from 'react' + +// Feature-specific components +import { + ShieldsHeader, + MainToggle, + TotalBlockedStats, + SiteOverview, + SiteInfo, + MainToggleHeading, + MainToggleText, + Link, + ToggleStateText, + Favicon, + SiteInfoText, + TotalBlockedStatsNumber, + TotalBlockedStatsText, + DisabledContentView, + ShieldIcon, + DisabledContentText, + Toggle + } from '../../../../../src/features/shields' + +// Fake data +import { getLocale } from '../../fakeLocale' + +interface Props { + enabled: boolean + favicon: string + hostname: string + isBlockedListOpen: boolean + adsTrackersBlocked: number + scriptsBlocked: number + httpsUpgrades: number + fingerprintingBlocked: number + fakeOnChangeShieldsEnabled: () => void + fakeOnChangeReadOnlyView: () => void +} + +export default class Header extends React.PureComponent { + get totalBlocked () { + const { adsTrackersBlocked, httpsUpgrades, scriptsBlocked, fingerprintingBlocked } = this.props + const total = adsTrackersBlocked + httpsUpgrades + scriptsBlocked + fingerprintingBlocked + if (!total) { + return 0 + } + return total > 99 ? '99+' : total + } + + render () { + const { + enabled, + favicon, + hostname, + isBlockedListOpen, + fakeOnChangeReadOnlyView, + fakeOnChangeShieldsEnabled + } = this.props + return ( + + + + + {getLocale('shields')} + + {enabled ? ` ${getLocale('up')} ` : ` ${getLocale('down')} `} + + {getLocale('forThisSite')} + + {enabled ? {getLocale('enabledMessage')} : null} + + + + + + + {hostname} + + { + enabled + ? ( + + {this.totalBlocked} + + {`${getLocale('blockedResoucesExplanation')} `} + {getLocale('learnMore')} + + + ) + : ( + + + {getLocale('disabledMessage')} + + ) + } + + + ) + } +} diff --git a/stories/features/shields/components/simpleView/index.tsx b/stories/features/shields/components/simpleView/index.tsx new file mode 100644 index 000000000..02c17dbaa --- /dev/null +++ b/stories/features/shields/components/simpleView/index.tsx @@ -0,0 +1,76 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import * as React from 'react' + +// Feature-specific components +import { ShieldsPanel } from '../../../../../src/features/shields' + +// Components group +import Header from './header' +import Footer from '../shared/footer' + +interface Props { + enabled: boolean + hostname: string + advancedView: boolean + favicon: string + adsTrackersBlocked: number + httpsUpgrades: number + scriptsBlocked: number + fingerprintingBlocked: number + fakeOnChangeShieldsEnabled: () => void + fakeOnChangeAdvancedView: () => void + fakeOnChangeReadOnlyView: () => void +} + +interface State { + isBlockedListOpen: boolean +} + +export default class ShieldsSimpleView extends React.PureComponent { + constructor (props: Props) { + super(props) + this.state = { isBlockedListOpen: false } + } + setBlockedListOpen = () => { + this.setState({ isBlockedListOpen: !this.state.isBlockedListOpen }) + } + render () { + const { + enabled, + favicon, + hostname, + adsTrackersBlocked, + httpsUpgrades, + scriptsBlocked, + fingerprintingBlocked, + fakeOnChangeShieldsEnabled, + fakeOnChangeReadOnlyView, + fakeOnChangeAdvancedView + } = this.props + const { isBlockedListOpen } = this.state + return ( + + + + + ) + } +} diff --git a/stories/features/shields/fakeLocale.ts b/stories/features/shields/fakeLocale.ts index 20841867e..f7b0b144a 100644 --- a/stories/features/shields/fakeLocale.ts +++ b/stories/features/shields/fakeLocale.ts @@ -44,7 +44,17 @@ const locale: { [key: string]: string } = { cancel: 'Cancel', goBack: 'Go back', applyOnce: 'Apply once', - changeDefaults: 'Change global shield defaults' + learnMore: 'Learn more', + changeDefaults: 'Change global shield defaults', + advancedView: 'Advanced View', + simpleView: 'Simple View', + // Read only view + shieldsExplanation: 'Sites often include cookies and scripts which try to identify you and your deviec (often embedded into ads). They want to work out who you are and follow you accross the web — tracking what you do on every site. Brave blocks these things so that you can browse without being followed around.', + // Simple view + blockedResoucesExplanation: 'Cross-site trackers and other creepy things blocked', + // Web Compat Overlay + webCompatWarning: 'Changing Shield settings in this view will affect web compatibility on this site.', + gotIt: 'Got it' } export default locale diff --git a/stories/features/shields/index.tsx b/stories/features/shields/index.tsx index 50ab052bb..5e2c4199b 100644 --- a/stories/features/shields/index.tsx +++ b/stories/features/shields/index.tsx @@ -4,24 +4,24 @@ import * as React from 'react' -// Feature-specific components -import { ShieldsPanel } from '../../../src/features/shields' - // Components group -import Header from './components/header' -import InterfaceControls from './components/interfaceControls' -import PrivacyControls from './components/privacyControls' -import Footer from './components/footer' +import SimpleView from './components/simpleView' +import AdvancedView from './components/advancedView' interface Props { enabled: boolean + firstAccess: boolean hostname: string + advancedView: boolean favicon: string adsTrackersBlocked: number httpsUpgrades: number scriptsBlocked: number fingerprintingBlocked: number - fakeOnChange: () => void + fakeOnChangeShieldsEnabled: () => void + fakeOnChangeAdvancedView: () => void + fakeOnChangeReadOnlyView: () => void + fakeToggleFirstAccess: () => void } interface State { @@ -33,58 +33,57 @@ export default class Shields extends React.PureComponent { super(props) this.state = { isBlockedListOpen: false } } + setBlockedListOpen = () => { this.setState({ isBlockedListOpen: !this.state.isBlockedListOpen }) } + render () { const { enabled, - favicon, + firstAccess, hostname, + favicon, adsTrackersBlocked, httpsUpgrades, scriptsBlocked, fingerprintingBlocked, - fakeOnChange + fakeOnChangeShieldsEnabled, + fakeOnChangeAdvancedView, + fakeOnChangeReadOnlyView, + fakeToggleFirstAccess } = this.props - const { isBlockedListOpen } = this.state - return ( - - + ) : ( + - { - enabled ? ( - <> - - - > - ) : null - } - - - ) + ) } } diff --git a/stories/features/shields/story.tsx b/stories/features/shields/story.tsx index 8ed61257d..cdc96bb72 100644 --- a/stories/features/shields/story.tsx +++ b/stories/features/shields/story.tsx @@ -14,6 +14,7 @@ const favicon = require('../../assets/img/fake_favicon.png') // Components import Shields from './index' +import ShieldsReadOnlyView from './components/readOnlyView' // Themes const themes = [shieldsLightTheme, shieldsDarkTheme] @@ -21,22 +22,47 @@ const themes = [shieldsLightTheme, shieldsDarkTheme] storiesOf('Feature Components/Shields', module) .addDecorator(withThemesProvider(themes)) .addDecorator(withKnobs) - .add('Enabled', withState({ enabled: true }, (store) => { - const fakeOnChange = () => { + .add('Panel', withState({ enabled: true, advancedView: false, readOnlyView: false, firstAccess: true }, (store) => { + const fakeOnChangeShieldsEnabled = () => { store.set({ enabled: !store.state.enabled }) } + const fakeOnChangeAdvancedView = () => { + store.set({ advancedView: !store.state.advancedView }) + } + const fakeOnChangeReadOnlyView = () => { + store.set({ readOnlyView: !store.state.readOnlyView }) + } + const fakeToggleFirstAccess = () => { + store.set({ firstAccess: !store.state.firstAccess }) + } return ( - - + { + store.state.readOnlyView + ? ( + + ) : ( + + ) + } + ) }))