Added 'share button group' style + example on /styleguide (#3352)

* added 'share button group' style + example on /styleguide

* turned share-button-group into a React component

* removed redundant code

* fixed linting errors

* code improvement

* Update source/js/components/share-button-group/share-button-group.jsx

Co-Authored-By: Pomax <pomax@nihongoresources.com>

* Update source/js/components/share-button-group/share-button-group.jsx

Co-Authored-By: Pomax <pomax@nihongoresources.com>

* Update source/js/components/share-button-group/share-button-group.jsx

Co-Authored-By: Pomax <pomax@nihongoresources.com>

* from <hr /> to <hr>

* js/jsx improvements

* code & language improvement

* code improvement

* added tooltip to 'copy link' button

* updated tooltip text
This commit is contained in:
Mavis Ou 2019-07-09 16:26:40 -07:00 коммит произвёл GitHub
Родитель cbf1dcedfc
Коммит 9308847bba
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
12 изменённых файлов: 417 добавлений и 1 удалений

Просмотреть файл

@ -307,6 +307,38 @@
</div>
</div>
<h2 class="h1-heading mt-5">Share Button Group</h2>
<hr class="hr-emphasis">
<h3 class="h2-heading mt-5">Full version</h3>
<hr>
<div class="mb-5">
<div class="share-button-group-wrapper"></div>
</div>
<h3 class="h2-heading mt-5">Full Version & Stacked</h3>
<hr>
<div class="mb-5">
<div class="share-button-group-wrapper" data-layout="stacked"></div>
</div>
<h3 class="h2-heading mt-5">Mini Version</h3>
<hr>
<div class="mb-5">
<div class="share-button-group-wrapper" data-version="mini"></div>
</div>
<h3 class="h2-heading mt-5">Mini Version & Stacked</h3>
<hr>
<div class="mb-5">
<div class="share-button-group-wrapper" data-version="mini" data-layout="stacked"></div>
</div>
</div>
</div>
</div>

Просмотреть файл

@ -0,0 +1 @@
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><path d="M13.605 3.287L9.252 7.86a1.75 1.75 0 0 1-2.54-.004l-4.277-4.53a.59.59 0 0 0-.041-.038c.06-.012.122-.017.185-.017h10.847c.06 0 .12.005.179.016zm.81.84c.007.047.01.095.01.144v7.333c0 .05-.003.098-.01.146l-3.717-3.717 3.717-3.906zm-.812 8.461c-.057.01-.117.016-.177.016H2.579c-.062 0-.123-.006-.182-.017l3.705-3.705a2.917 2.917 0 0 0 3.781-.014l3.72 3.72zM1.59 11.746a1.009 1.009 0 0 1-.01-.142V4.27c0-.048.003-.095.01-.14l3.699 3.916-3.699 3.699z" fill="#FFF" fill-rule="evenodd"/></svg>

После

Ширина:  |  Высота:  |  Размер: 557 B

Просмотреть файл

@ -0,0 +1 @@
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path id="a" d="M0 0h14v13.915H0z"/></defs><g transform="translate(1 1)" fill="#fff" fill-rule="evenodd"><mask id="b"><use xlink:href="#a"/></mask><path d="M14 7a7 7 0 1 0-8.094 6.915V9.023H4.13V7h1.777V5.458c0-1.755 1.045-2.724 2.644-2.724.766 0 1.567.137 1.567.137v1.723h-.882c-.87 0-1.141.54-1.141 1.093V7h1.941l-.31 2.023H8.094v4.892A7.002 7.002 0 0 0 14 7" mask="url(#b)"/></g></svg>

После

Ширина:  |  Высота:  |  Размер: 500 B

Просмотреть файл

@ -0,0 +1 @@
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><g stroke="#FFF" stroke-width="2" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"><path d="M14 4l-8 8M6 12L2.005 8.005"/></g></svg>

После

Ширина:  |  Высота:  |  Размер: 225 B

Просмотреть файл

@ -0,0 +1 @@
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><g stroke="#ffffff" stroke-width="1.5" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"><path d="M9.201 8.598a3 3 0 0 1-4.523.324l-1.799-1.8a3 3 0 0 1 4.24-4.24l1.033 1.025"/><path d="M6.802 7.399a3 3 0 0 1 4.523-.324l1.8 1.8a3 3 0 0 1-4.242 4.24l-1.025-1.026"/></g></svg>

После

Ширина:  |  Высота:  |  Размер: 366 B

Просмотреть файл

@ -0,0 +1 @@
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><path d="M13.353 5.896c0-.12 0-.24-.008-.359a5.683 5.683 0 0 0 1.408-1.438 5.689 5.689 0 0 1-1.62.437A2.799 2.799 0 0 0 14.372 3a5.71 5.71 0 0 1-1.792.674 2.856 2.856 0 0 0-3.992-.12 2.754 2.754 0 0 0-.817 2.654 8.057 8.057 0 0 1-5.815-2.902 2.754 2.754 0 0 0 .874 3.708 2.834 2.834 0 0 1-1.28-.348v.035c0 1.323.947 2.461 2.263 2.723a2.85 2.85 0 0 1-1.274.048 2.82 2.82 0 0 0 2.636 1.93A5.718 5.718 0 0 1 1 12.551a8.082 8.082 0 0 0 4.325 1.246c5.19.002 8.028-4.23 8.028-7.902z" fill="#ffffff" fill-rule="evenodd"/></svg>

После

Ширина:  |  Высота:  |  Размер: 584 B

Просмотреть файл

@ -0,0 +1,162 @@
import React from "react";
import classNames from "classnames";
import copyToClipboard from "../../copy-to-clipboard";
export default class ShareButtonGroup extends React.Component {
constructor(props) {
super(props);
this.state = {
linkCopied: false
};
}
componentDidMount() {
if (this.props.whenLoaded) {
this.props.whenLoaded();
}
}
renderFacebookButton() {
let label =
this.props.version === `mini` ? (
<span class="sr-only">Share on Facebook</span>
) : (
`Faceook`
);
let link = this.props.link || ``;
return (
<a
class="btn btn-secondary btn-share facebook-share"
href={`https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(
`https://${link}`
)}`}
>
{label}
</a>
);
}
renderTwitterButton() {
let shareText = this.props.shareText || ``;
let label =
this.props.version === `mini` ? (
<span class="sr-only">Share on Twitter</span>
) : (
`Twitter`
);
return (
<a
class="btn btn-secondary btn-share twitter-share"
href={`https://twitter.com/intent/tweet?text=${encodeURIComponent(
shareText
)}`}
>
{label}
</a>
);
}
renderEmailButton() {
let shareText = this.props.shareText || ``;
let label =
this.props.version === `mini` ? (
<span class="sr-only">Share by email</span>
) : (
`Email`
);
return (
<a
class="btn btn-secondary btn-share email-share"
href={`mailto:?&body=${encodeURIComponent(shareText)}`}
>
{label}
</a>
);
}
handleLinkButtonClick(event) {
event.preventDefault();
copyToClipboard(event.target, window.location.href);
this.setState({
linkCopied: true
});
}
renderLinkButton() {
let tooltip = this.state.linkCopied
? `Copied`
: `Copy page URL to clipboard`;
let label = this.state.linkCopied ? `Copied` : `Copy`;
label =
this.props.version === `mini` ? (
<span class="sr-only">{label} page link</span>
) : (
label
);
let classes = classNames(`btn btn-secondary btn-share link-share`, {
copied: this.state.linkCopied
});
return (
<a
class={classes}
href="#"
onClick={event => this.handleLinkButtonClick(event)}
title={tooltip}
>
{label}
</a>
);
}
renderRectangleButtons() {
let classes = classNames(`share-button-group rectangle`, {
stacked: this.props.layout === `stacked`
});
return (
<div className={classes}>
<div className="subgroup">
{this.renderFacebookButton()}
{this.renderTwitterButton()}
</div>
<div className="subgroup">
{this.renderEmailButton()}
{this.renderLinkButton()}
</div>
</div>
);
}
renderCircleButtons() {
let classes = classNames(`share-button-group circle`, {
stacked: this.props.layout === `stacked`
});
return (
<div className={classes}>
{this.renderFacebookButton()}
{this.renderTwitterButton()}
{this.renderEmailButton()}
{this.renderLinkButton()}
</div>
);
}
render() {
return (
<React.Fragment>
{this.props.version === `mini`
? this.renderCircleButtons()
: this.renderRectangleButtons()}
</React.Fragment>
);
}
}

Просмотреть файл

@ -0,0 +1,113 @@
.share-button-group {
@mixin stacked-rectangle() {
flex-direction: column;
.subgroup:not(:last-child) {
margin-bottom: 16px;
}
.btn {
&:last-child {
margin-right: 0;
}
}
.subgroup {
flex: 0;
}
}
display: flex;
&.rectangle {
@media (max-width: $bp-md) {
@include stacked-rectangle();
}
&.stacked {
@include stacked-rectangle();
}
.btn {
width: 130px;
&::before {
position: relative;
top: 3px;
display: inline-block;
margin-right: 8px;
}
}
}
&.circle {
&.stacked {
flex-direction: column;
.btn:not(:last-child) {
margin-bottom: 16px;
}
}
.btn {
width: 36px;
height: 36px;
border-radius: 50%;
padding: 0;
&::before {
transform: translate(50%, 50%);
}
}
}
.btn {
margin-right: 16px;
@include hover-focus-active {
&::before {
filter: brightness(1);
}
}
&::before {
filter: brightness(0);
content: " ";
display: block;
width: 16px;
height: 16px;
background: no-repeat 0 0 / contain;
transition: filter 0.2s ease-in-out;
}
&.facebook-share {
&::before {
background-image: url(../_images/glyphs/social-share/facebook-share.svg);
}
}
&.twitter-share {
&::before {
background-image: url(../_images/glyphs/social-share/twitter-share.svg);
}
}
&.email-share {
&::before {
background-image: url(../_images/glyphs/social-share/email-share.svg);
}
}
&.link-share {
&::before {
background-image: url(../_images/glyphs/social-share/link-share.svg);
}
&.copied {
&::before {
background-image: url(../_images/glyphs/social-share/link-share-copied.svg);
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,83 @@
const copyToClipboard = (linkElement, textToCopy) => {
let textArea = document.createElement(`textarea`);
textArea.setAttribute(`contenteditable`, true);
textArea.setAttribute(`readonly`, false);
//
// *** This styling is an extra step which is likely not required. ***
//
// Why is it here? To ensure:
// 1. the element is able to have focus and selection.
// 2. if element was to flash render it has minimal visual impact.
// 3. less flakyness with selection and copying which **might** occur if
// the textarea element is not visible.
//
// The likelihood is the element won't even render, not even a flash,
// so some of these are just precautions. However in IE the element
// is visible whilst the popup box asking the user for permission for
// the web page to copy to the clipboard.
//
// Place in top-left corner of screen regardless of scroll position.
textArea.style.position = `fixed`;
textArea.style.top = 0;
textArea.style.left = 0;
// Ensure it has a small width and height. Setting to 1px / 1em
// doesn't work as this gives a negative w/h on some browsers.
textArea.style.width = `2em`;
textArea.style.height = `2em`;
// We don't need padding, reducing the size if it does flash render.
textArea.style.padding = 0;
// Clean up any borders.
textArea.style.border = `none`;
textArea.style.outline = `none`;
textArea.style.boxShadow = `none`;
// Avoid flash of white box if rendered for any reason.
textArea.style.background = `transparent`;
textArea.value = textToCopy;
document.body.appendChild(textArea);
textArea.focus();
// Simply running textArea.select() and document.execCommand(`copy`) won't work on iOS Safari
// Below is the suggested solution to make copying and pasting working more cross-platform
// For details see https://stackoverflow.com/a/34046084
let range = document.createRange();
let selection = window.getSelection();
range.selectNodeContents(textArea);
selection.removeAllRanges();
selection.addRange(range);
textArea.setSelectionRange(0, textArea.value.length);
try {
document.execCommand(`copy`);
let target = linkElement;
if (target.dataset && target.dataset.successText) {
let defaultText = target.innerText;
target.innerText = target.dataset.successText;
target.classList.add(`copied`);
setTimeout(() => {
target.innerText = defaultText;
target.classList.remove(`copied`);
}, 3000);
}
} catch (err) {
console.error(`Copy failed.`);
}
document.body.removeChild(textArea);
};
export default copyToClipboard;

Просмотреть файл

@ -11,6 +11,7 @@ import MemberNotice from "./components/member-notice/member-notice.jsx";
import MultipageNavMobile from "./components/multipage-nav-mobile/multipage-nav-mobile.jsx";
import News from "./components/news/news.jsx";
import PulseProjectList from "./components/pulse-project-list/pulse-project-list.jsx";
import ShareButtonGroup from "./components/share-button-group/share-button-group.jsx";
import injectDonateModal from "./donate-modal/donate-modal.jsx";
@ -351,6 +352,25 @@ let main = {
);
});
// Share button group
let shareButtonGroups = document.querySelectorAll(
`.share-button-group-wrapper`
);
if (shareButtonGroups) {
shareButtonGroups.forEach(element => {
var props = element.dataset;
apps.push(
new Promise(resolve => {
ReactDOM.render(
<ShareButtonGroup {...props} whenLoaded={() => resolve()} />,
element
);
})
);
});
}
//Profile Directory Filter-Bar GA
const filters = document.querySelectorAll(

Просмотреть файл

@ -84,7 +84,7 @@
}
// append external link glyph
.btn-secondary[href*="//"]:not([href*="foundation.mozilla.org"]) {
.btn-secondary[href*="//"]:not([href*="foundation.mozilla.org"]):not(.btn-share) {
display: inline-flex;
align-items: center;

Просмотреть файл

@ -27,6 +27,7 @@ $bp-xl: #{map-get($grid-breakpoints, xl)}; // >= 1200px
@import "../js/components/pulse-project-list/pulse-project-list";
@import "../js/components/fellow-list/directory-filter-bar";
@import "../js/components/petition/petition";
@import "../js/components/share-button-group/share-button-group";
// Special react component