Tighten up styles for the recommended badges (#8062)
This commit is contained in:
Родитель
6412f24eeb
Коммит
d2fb74c09a
|
@ -70,7 +70,7 @@ export class AddonBadgesBase extends React.Component<InternalProps> {
|
|||
_config.get('enableFeatureRecommendedBadges') &&
|
||||
addon.is_recommended &&
|
||||
clientApp !== CLIENT_APP_ANDROID ? (
|
||||
<RecommendedBadge />
|
||||
<RecommendedBadge size="large" />
|
||||
) : null}
|
||||
{showFeaturedBadge ? (
|
||||
<Badge type="featured" label={getFeaturedText(addon.type)} />
|
||||
|
|
|
@ -144,7 +144,7 @@ export class SearchResultBase extends React.Component<InternalProps> {
|
|||
addon &&
|
||||
addon.is_recommended &&
|
||||
clientApp !== CLIENT_APP_ANDROID ? (
|
||||
<RecommendedBadge />
|
||||
<RecommendedBadge size="small" />
|
||||
) : null}
|
||||
</h2>
|
||||
{summary}
|
||||
|
|
|
@ -94,9 +94,12 @@ $icon-default-size: 32px;
|
|||
.SearchResult-name {
|
||||
@include font-medium();
|
||||
|
||||
align-items: flex-start;
|
||||
color: $type-black;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
flex-wrap: wrap;
|
||||
font-size: $font-size-m-smaller;
|
||||
line-height: 1.2;
|
||||
margin: 0;
|
||||
|
@ -106,7 +109,19 @@ $icon-default-size: 32px;
|
|||
word-wrap: break-word;
|
||||
|
||||
.RecommendedBadge {
|
||||
@include margin-start(8px);
|
||||
justify-content: flex-start;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
@include respond-to(extraLarge) {
|
||||
flex-direction: row;
|
||||
margin-top: 0;
|
||||
|
||||
.RecommendedBadge {
|
||||
@include margin-start(8px);
|
||||
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.SearchResult-link:focus &,
|
||||
|
|
|
@ -5,6 +5,7 @@ import makeClassName from 'classnames';
|
|||
|
||||
import translate from 'core/i18n/translate';
|
||||
import Icon from 'ui/components/Icon';
|
||||
import IconRecommendedBadge from 'ui/components/IconRecommendedBadge';
|
||||
import LoadingText from 'ui/components/LoadingText';
|
||||
import type { I18nType } from 'core/types/i18n';
|
||||
|
||||
|
@ -44,10 +45,10 @@ export const SearchSuggestionBase = ({
|
|||
{loading ? <LoadingText minWidth={20} range={12} /> : name}
|
||||
</span>
|
||||
{_config.get('enableFeatureRecommendedBadges') && isRecommended && (
|
||||
<Icon
|
||||
<IconRecommendedBadge
|
||||
alt={i18n.gettext('Recommended')}
|
||||
className="SearchSuggestion-icon-recommended"
|
||||
name="recommended-circle"
|
||||
size="small"
|
||||
/>
|
||||
)}
|
||||
<Icon
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
<svg width="20" height="20" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>Group 16 Copy 2</title>
|
||||
<!--
|
||||
The color #ff9400 is equivalent to the photon color orange-50
|
||||
https://design.firefox.com/photon/visuals/color.html#orange
|
||||
-->
|
||||
<circle cx="10" cy="10" fill="#ff9400" r="10"></circle>
|
||||
<g fill="#FFFFFF" fill-rule="nonzero">
|
||||
<path d="M15.449999809265137,3.999999523162842 H4.550000190734863 C4.25,3.999999523162842 4,4.219999313354492 4,4.499999523162842 V6.999999523162842 c0,1.100000023841858 0.9800000190734863,2 2.180000066757202,2 h0.05000000074505806 a3.6700000762939453,3.6700000762939453 0 0 0 3.2200000286102295,2.9600000381469727 V13.499999523162842 h1.100000023841858 V11.959999561309814 A3.6700000762939453,3.6700000762939453 0 0 0 13.770000457763672,8.999999523162842 h0.05000000074505806 C15.020000457763672,8.999999523162842 16,8.099998950958252 16,6.999999523162842 V4.499999523162842 c0,-0.2800000011920929 -0.23999999463558197,-0.5 -0.550000011920929,-0.5 zM5.099999904632568,6.999999523162842 V4.999999523162842 h1.100000023841858 v3 c-0.6100000143051147,0 -1.100000023841858,-0.44999998807907104 -1.100000023841858,-1 zm9.819999694824219,0 c0,0.550000011920929 -0.49000000953674316,1 -1.100000023841858,1 V4.999999523162842 h1.100000023841858 v2 zM11.100000381469727,13.999999523162842 H8.899999618530273 c-2.7200000286102295,0 -2.7200000286102295,2 -2.7200000286102295,2 h7.639999866485596 s0,-2 -2.7300000190734863,-2 z" id="svg_3"/>
|
||||
</g>
|
||||
</svg>
|
До Ширина: | Высота: | Размер: 1.4 KiB |
|
@ -1 +0,0 @@
|
|||
<svg width="12" height="12" xmlns="http://www.w3.org/2000/svg"><title>Group 16 Copy 2</title><g fill="#FFFFFF" fill-rule="nonzero"><path d="M11.45 0H.55C.25 0 0 .22 0 .5V3c0 1.1.98 2 2.18 2h.05a3.67 3.67 0 0 0 3.22 2.96V9.5h1.1V7.96A3.67 3.67 0 0 0 9.77 5h.05C11.02 5 12 4.1 12 3V.5c0-.28-.24-.5-.55-.5zM1.1 3V1h1.1v3c-.61 0-1.1-.45-1.1-1zm9.82 0c0 .55-.49 1-1.1 1V1h1.1v2zM7.1 10H4.9c-2.72 0-2.72 2-2.72 2h7.64s0-2-2.73-2z"/></g></svg>
|
До Ширина: | Высота: | Размер: 436 B |
|
@ -327,14 +327,3 @@
|
|||
height: 12px;
|
||||
width: 12px;
|
||||
}
|
||||
|
||||
.Icon-recommended {
|
||||
@include icon($name: 'recommended');
|
||||
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
}
|
||||
|
||||
.Icon-recommended-circle {
|
||||
@include icon($name: 'recommended-circle');
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/* @flow */
|
||||
import * as React from 'react';
|
||||
import makeClassName from 'classnames';
|
||||
|
||||
import Icon from 'ui/components/Icon';
|
||||
import type { Props as IconProps } from 'ui/components/Icon';
|
||||
|
||||
import './styles.scss';
|
||||
|
||||
export type RecommendedBadgeSize = 'large' | 'small';
|
||||
|
||||
type Props = {|
|
||||
alt?: $PropertyType<IconProps, 'alt'>,
|
||||
className?: string,
|
||||
size: RecommendedBadgeSize,
|
||||
|};
|
||||
|
||||
const IconRecommendedBadge = ({ className, size, ...iconProps }: Props) => {
|
||||
return (
|
||||
<Icon
|
||||
{...iconProps}
|
||||
className={makeClassName('IconRecommendedBadge', className, {
|
||||
'IconRecommendedBadge-large': size === 'large',
|
||||
'IconRecommendedBadge-small': size === 'small',
|
||||
})}
|
||||
name="inline-content"
|
||||
>
|
||||
<svg
|
||||
className="IconRecommendedBadge-svg"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<circle
|
||||
className="IconRecommendedBadge-shellPath"
|
||||
cx="50%"
|
||||
cy="50%"
|
||||
r="50%"
|
||||
/>
|
||||
<g fillRule="nonzero">
|
||||
<path
|
||||
className="IconRecommendedBadge-iconPath"
|
||||
d="M15.449999809265137,3.999999523162842 H4.550000190734863 C4.25,3.999999523162842 4,4.219999313354492 4,4.499999523162842 V6.999999523162842 c0,1.100000023841858 0.9800000190734863,2 2.180000066757202,2 h0.05000000074505806 a3.6700000762939453,3.6700000762939453 0 0 0 3.2200000286102295,2.9600000381469727 V13.499999523162842 h1.100000023841858 V11.959999561309814 A3.6700000762939453,3.6700000762939453 0 0 0 13.770000457763672,8.999999523162842 h0.05000000074505806 C15.020000457763672,8.999999523162842 16,8.099998950958252 16,6.999999523162842 V4.499999523162842 c0,-0.2800000011920929 -0.23999999463558197,-0.5 -0.550000011920929,-0.5 zM5.099999904632568,6.999999523162842 V4.999999523162842 h1.100000023841858 v3 c-0.6100000143051147,0 -1.100000023841858,-0.44999998807907104 -1.100000023841858,-1 zm9.819999694824219,0 c0,0.550000011920929 -0.49000000953674316,1 -1.100000023841858,1 V4.999999523162842 h1.100000023841858 v2 zM11.100000381469727,13.999999523162842 H8.899999618530273 c-2.7200000286102295,0 -2.7200000286102295,2 -2.7200000286102295,2 h7.639999866485596 s0,-2 -2.7300000190734863,-2 z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</Icon>
|
||||
);
|
||||
};
|
||||
|
||||
export default IconRecommendedBadge;
|
|
@ -0,0 +1,51 @@
|
|||
@import '~ui/css/styles';
|
||||
@import '~ui/components/Icon/vars';
|
||||
|
||||
$icon-recommended-large-size: 24px;
|
||||
$icon-recommended-small-size: 16px;
|
||||
|
||||
.IconRecommendedBadge {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
height: auto;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.IconRecommendedBadge-svg {
|
||||
box-sizing: border-box;
|
||||
height: $default-icon-size;
|
||||
width: $default-icon-size;
|
||||
}
|
||||
|
||||
.IconRecommendedBadge-shellPath {
|
||||
fill: $orange-50;
|
||||
}
|
||||
|
||||
.IconRecommendedBadge-iconPath {
|
||||
fill: $white;
|
||||
transform-origin: 50% 50%;
|
||||
}
|
||||
|
||||
.IconRecommendedBadge-large {
|
||||
.IconRecommendedBadge-svg {
|
||||
height: $icon-recommended-large-size;
|
||||
width: $icon-recommended-large-size;
|
||||
}
|
||||
|
||||
.IconRecommendedBadge-iconPath {
|
||||
// Nudge the trophy into the center of the circle.
|
||||
transform: translate(2px, 2.5px) scale(1.1);
|
||||
}
|
||||
}
|
||||
|
||||
.IconRecommendedBadge-small {
|
||||
.IconRecommendedBadge-svg {
|
||||
height: $icon-recommended-small-size;
|
||||
width: $icon-recommended-small-size;
|
||||
}
|
||||
|
||||
.IconRecommendedBadge-iconPath {
|
||||
// Nudge the trophy into the center of the circle.
|
||||
transform: translate(-1.5px, -1.5px) scale(0.8);
|
||||
}
|
||||
}
|
|
@ -1,25 +1,34 @@
|
|||
/* @flow */
|
||||
import makeClassName from 'classnames';
|
||||
import * as React from 'react';
|
||||
import { compose } from 'redux';
|
||||
|
||||
import translate from 'core/i18n/translate';
|
||||
import Icon from 'ui/components/Icon';
|
||||
import IconRecommendedBadge from 'ui/components/IconRecommendedBadge';
|
||||
import type { RecommendedBadgeSize } from 'ui/components/IconRecommendedBadge';
|
||||
import type { I18nType } from 'core/types/i18n';
|
||||
|
||||
import './styles.scss';
|
||||
|
||||
type Props = {};
|
||||
type Props = {|
|
||||
size: RecommendedBadgeSize,
|
||||
|};
|
||||
|
||||
type InternalProps = {|
|
||||
...Props,
|
||||
i18n: I18nType,
|
||||
|};
|
||||
|
||||
export const RecommendedBadgeBase = (props: InternalProps) => {
|
||||
const { i18n } = props;
|
||||
|
||||
export const RecommendedBadgeBase = ({ i18n, size }: InternalProps) => {
|
||||
const label = i18n.gettext('Recommended');
|
||||
|
||||
return (
|
||||
<div className="RecommendedBadge">
|
||||
<div
|
||||
className={makeClassName('RecommendedBadge', {
|
||||
'RecommendedBadge-large': size === 'large',
|
||||
'RecommendedBadge-small': size === 'small',
|
||||
})}
|
||||
>
|
||||
<a
|
||||
className="RecommendedBadge-link"
|
||||
href="https://support.mozilla.org/"
|
||||
|
@ -29,9 +38,7 @@ export const RecommendedBadgeBase = (props: InternalProps) => {
|
|||
'Firefox only recommends extensions that meet our standards for security and performance.',
|
||||
)}
|
||||
>
|
||||
<span className="RecommendedBadge-icon">
|
||||
<Icon alt={label} name="recommended" />
|
||||
</span>
|
||||
<IconRecommendedBadge alt={label} size={size} />
|
||||
<span className="RecommendedBadge-label">{label}</span>
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
@ -1,61 +1,63 @@
|
|||
@import '~ui/css/styles';
|
||||
|
||||
$recommended-text-color: $orange-50;
|
||||
$recommended-hover-color: $orange-60;
|
||||
@import '~ui/components/IconRecommendedBadge/styles';
|
||||
|
||||
.RecommendedBadge {
|
||||
align-items: center;
|
||||
color: $recommended-text-color;
|
||||
align-items: flex-start;
|
||||
color: $orange-50;
|
||||
display: flex;
|
||||
font-size: $font-size-m-smaller;
|
||||
font-size: $font-size-micro;
|
||||
margin-bottom: 6px;
|
||||
|
||||
&.RecommendedBadge-large {
|
||||
font-size: $font-size-m-smaller;
|
||||
}
|
||||
|
||||
@include respond-to(large) {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
a,
|
||||
a:link,
|
||||
a:visited {
|
||||
color: $recommended-text-color;
|
||||
.RecommendedBadge-link {
|
||||
align-items: center;
|
||||
border: 1px solid $orange-50;
|
||||
border-radius: 20px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
max-height: $icon-recommended-small-size;
|
||||
|
||||
.RecommendedBadge-large & {
|
||||
max-height: $icon-recommended-large-size;
|
||||
}
|
||||
|
||||
&,
|
||||
&:link,
|
||||
&:visited {
|
||||
color: $orange-50;
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:active,
|
||||
a:focus,
|
||||
a:hover {
|
||||
border-color: $recommended-hover-color;
|
||||
color: $recommended-hover-color;
|
||||
&:active,
|
||||
&:focus,
|
||||
&:hover {
|
||||
border-color: $orange-60;
|
||||
color: $orange-60;
|
||||
|
||||
.RecommendedBadge-icon {
|
||||
background-color: $recommended-hover-color;
|
||||
.IconRecommendedBadge-shellPath {
|
||||
fill: $orange-60;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.RecommendedBadge-link {
|
||||
@include padding-end(10px);
|
||||
|
||||
border: 1px solid $recommended-text-color;
|
||||
border-radius: 20px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.RecommendedBadge-icon {
|
||||
@include margin-end(6px);
|
||||
@include padding-end(0);
|
||||
@include padding-start(4px);
|
||||
|
||||
background-color: $recommended-text-color;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
height: 22px;
|
||||
padding-bottom: 4px;
|
||||
padding-top: 2px;
|
||||
width: 22px;
|
||||
}
|
||||
|
||||
.RecommendedBadge-label {
|
||||
@include margin-start(2px);
|
||||
@include margin-end(8px);
|
||||
|
||||
.RecommendedBadge-large & {
|
||||
@include margin-start(6px);
|
||||
}
|
||||
|
||||
color: $orange-80;
|
||||
}
|
||||
|
|
|
@ -7,5 +7,6 @@ import './setup/styles.scss';
|
|||
// Components
|
||||
import './ui/Badge';
|
||||
import './ui/Button';
|
||||
import './ui/IconRecommendedBadge';
|
||||
import './ui/Rating';
|
||||
import './ui/RecommendedBadge';
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/* @flow */
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
|
||||
import IconRecommendedBadge from 'ui/components/IconRecommendedBadge';
|
||||
|
||||
const render = ({ size = 'large' } = {}) => {
|
||||
return <IconRecommendedBadge size={size} />;
|
||||
};
|
||||
|
||||
storiesOf('IconRecommendedBadge', module).addWithChapters('all variants', {
|
||||
chapters: [
|
||||
{
|
||||
sections: [
|
||||
{
|
||||
title: 'size="large"',
|
||||
sectionFn: () => render({ size: 'large' }),
|
||||
},
|
||||
{
|
||||
title: 'size="small"',
|
||||
sectionFn: () => render({ size: 'small' }),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
|
@ -3,8 +3,34 @@ import React from 'react';
|
|||
import { storiesOf } from '@storybook/react';
|
||||
import { fakeI18n } from 'tests/unit/helpers';
|
||||
|
||||
import RecommendedBadge from 'ui/components/RecommendedBadge';
|
||||
import { RecommendedBadgeBase } from 'ui/components/RecommendedBadge';
|
||||
|
||||
storiesOf('RecommendedBadge', module).add('default', () => (
|
||||
<RecommendedBadge i18n={fakeI18n({ includeJedSpy: false })} />
|
||||
));
|
||||
const render = (moreProps = {}) => {
|
||||
const props = {
|
||||
size: 'large',
|
||||
...moreProps,
|
||||
};
|
||||
return (
|
||||
<RecommendedBadgeBase
|
||||
i18n={fakeI18n({ includeJedSpy: false })}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
storiesOf('RecommendedBadge', module).addWithChapters('all variants', {
|
||||
chapters: [
|
||||
{
|
||||
sections: [
|
||||
{
|
||||
title: 'size="large"',
|
||||
sectionFn: () => render({ size: 'large' }),
|
||||
},
|
||||
{
|
||||
title: 'size="small"',
|
||||
sectionFn: () => render({ size: 'small' }),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -75,7 +75,6 @@ describe(__filename, () => {
|
|||
};
|
||||
const root = shallowComponent(props);
|
||||
|
||||
expect(root.find(Icon)).toHaveLength(2);
|
||||
expect(root.find('.SearchSuggestion-icon-recommended')).toHaveLength(1);
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
import { shallow } from 'enzyme';
|
||||
import * as React from 'react';
|
||||
|
||||
import Icon from 'ui/components/Icon';
|
||||
import IconRecommendedBadge from 'ui/components/IconRecommendedBadge';
|
||||
|
||||
describe(__filename, () => {
|
||||
const render = (moreProps = {}) => {
|
||||
const props = {
|
||||
size: 'large',
|
||||
...moreProps,
|
||||
};
|
||||
return shallow(<IconRecommendedBadge {...props} />);
|
||||
};
|
||||
|
||||
it.each([
|
||||
['IconRecommendedBadge-large', 'large'],
|
||||
['IconRecommendedBadge-small', 'small'],
|
||||
])('adds the class "%s" for size="%s"', (className, size) => {
|
||||
const root = render({ size });
|
||||
|
||||
expect(root).toHaveClassName(className);
|
||||
});
|
||||
|
||||
it('adds a custom class', () => {
|
||||
const className = 'MyCoolBadge';
|
||||
const root = render({ className });
|
||||
|
||||
expect(root).toHaveClassName(className);
|
||||
});
|
||||
|
||||
it('adds an alt property', () => {
|
||||
const alt = 'This is a badge';
|
||||
const root = render({ alt });
|
||||
|
||||
expect(root.find(Icon)).toHaveProp('alt', alt);
|
||||
});
|
||||
});
|
|
@ -4,17 +4,26 @@ import { fakeI18n, shallowUntilTarget } from 'tests/unit/helpers';
|
|||
import RecommendedBadge, {
|
||||
RecommendedBadgeBase,
|
||||
} from 'ui/components/RecommendedBadge';
|
||||
import Icon from 'ui/components/Icon';
|
||||
|
||||
describe(__filename, () => {
|
||||
it('renders a badge', () => {
|
||||
const root = shallowUntilTarget(
|
||||
<RecommendedBadge i18n={fakeI18n()} />,
|
||||
const render = (moreProps = {}) => {
|
||||
const props = {
|
||||
i18n: fakeI18n(),
|
||||
size: 'large',
|
||||
...moreProps,
|
||||
};
|
||||
return shallowUntilTarget(
|
||||
<RecommendedBadge {...props} />,
|
||||
RecommendedBadgeBase,
|
||||
);
|
||||
const label = 'Recommended';
|
||||
};
|
||||
|
||||
expect(root.find(Icon)).toHaveProp('alt', label);
|
||||
expect(root.find('.RecommendedBadge-label')).toIncludeText(label);
|
||||
it.each([
|
||||
['RecommendedBadge-large', 'large'],
|
||||
['RecommendedBadge-small', 'small'],
|
||||
])('adds the class "%s" for size="%s"', (className, size) => {
|
||||
const root = render({ size });
|
||||
|
||||
expect(root).toHaveClassName(className);
|
||||
});
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче