Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Faithlife social share to share links to faithlife, email, facebook and twitter #50

Merged
merged 7 commits into from
Sep 27, 2018
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions catalog/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
DropZone,
GroupSelector,
GroupSelectorModal,
ShareDialog,
} from '../components/main.js';
import { BaseButton } from '../components/button/base-button.jsx';
import { BootstrapContainer } from '../components/utils';
Expand Down Expand Up @@ -425,6 +426,40 @@ const pages = [
},
],
},
{
title: 'Share Dialog',
pages: [
{
path: '/share-dialog/variations',
title: 'Share Dialog Variations',
content: pageLoader(() => import('./share-dialog/variations.md')),
imports: {
Input: Bootstrap.Input,
Modal,
ModalFooter,
Button,
delayPromise,
ShareDialog,
ModalDemo: styled.div`
font-family: 'Source Sans Pro';
color: #333333;

.wide-content {
width: 600px;
}

.button-container {
margin-right: 16px;
}

.stacked-content {
width: 240px;
}
`,
},
},
],
},
];

ReactDOM.render(
Expand Down
7 changes: 7 additions & 0 deletions catalog/share-dialog/documentation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
This documentation is automatically generated from jsdoc comments.

```react
noSource: true
---
<DocgenTable component={Modal} />
```
16 changes: 16 additions & 0 deletions catalog/share-dialog/variations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
## Share Dialog with default footer

```react
showSource: true
state: { isOpen: false, shareUrl: 'https://examplecommunity.church/', message: 'Checkout our awesome church website' }
---
<ModalDemo>
<Button primary medium onClick={() => setState({ isOpen: true })}>Open a modal!</Button>
<ShareDialog
isOpen={state.isOpen}
shareUrl={state.shareUrl}
message={state.message}
onClose={() => setState({ isOpen: false })}
/>
</ModalDemo>
```
57 changes: 57 additions & 0 deletions components/icons/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,60 @@ export const VideoFileIcon = props => (
</g>
</svg>
);

export const ShareToFaithlifeIcon = props => (
<svg {...props} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g fill="none" fillRule="evenodd">
<rect width="24" height="24" fill="#5FBC39" rx="2" />
<path
fill="#FFF"
d="M12.767 21.975c-.011.027-.05.034-.07.012-.295-.301-2.015-2.01-4.585-3.63-1.475-.968-2.052-1.567-2.22-1.761-.023-.027 0-.066.036-.064.172.009.57.022 1.073-.008.033-.002.05-.036.033-.061-.216-.308-1.256-1.841-1.33-3.559-.001-.03.034-.05.062-.035.158.082.588.291 1.136.442.03.008.06-.017.053-.046-.081-.357-.446-2.15-.077-3.969.007-.032.05-.044.073-.02.11.112.385.361.869.622.022.012.052.002.06-.02.118-.314.868-2.217 2.132-3.358.025-.022.067-.008.072.023.553 3.364 3.69 4.13 5.172 7.092.995 1.988-.265 3.08-.68 3.37-.034.024-.013.075.03.071 2.367-.178 3.347-2.164 3.603-2.797.017-.04.08-.03.082.013.167 4.684-3.94 4.962-4.59 4.98a.336.336 0 0 1-.158-.034c-3.712-1.834-3.695-5.488-3.656-6.179.001-.021-.031-.027-.04-.008-1.866 4.178 1.347 6.54 2.492 7.573.458.414.661.78.428 1.351zm.616-19.96c.03-.032.086-.009.08.033-.083.638-.273 3.327 2.052 5.665 2.614 2.607 2.33 4.596 1.398 6.444-.021.042-.09.028-.088-.02.017-.497-.128-1.528-1.948-3.39-2.88-2.95-4.9-5.121-1.494-8.732z"
/>
</g>
</svg>
);

export const ShareToFacebookIcon = props => (
<svg {...props} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g fill="none" fillRule="evenodd">
<rect width="24" height="24" fill="#3B5998" rx="2" />
<path
fill="#FFF"
d="M13.253 20.989v-9.001h2.523l.334-3.102h-2.857l.004-1.553c0-.809.078-1.242 1.258-1.242h1.577V2.989H13.57c-3.031 0-4.098 1.505-4.098 4.035v1.862h-1.89v3.102h1.89v9h3.782z"
/>
</g>
</svg>
);

export const ShareToTwitterIcon = props => (
<svg {...props} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g fill="none" fillRule="evenodd">
<rect width="24" height="24" fill="#55ACEE" rx="2" />
<path
fill="#FFF"
d="M12.178 9.346l.035.583-.59-.071c-2.144-.274-4.018-1.202-5.61-2.761l-.777-.773-.2.57c-.425 1.274-.154 2.618.73 3.523.472.5.365.57-.448.273-.283-.095-.53-.166-.554-.13-.082.083.2 1.166.425 1.594.306.595.93 1.178 1.614 1.523l.578.274-.684.012c-.66 0-.683.012-.613.261.236.774 1.167 1.595 2.204 1.952l.731.25-.636.38a6.636 6.636 0 0 1-3.159.881c-.53.012-.967.06-.967.095 0 .12 1.438.786 2.275 1.047 2.51.774 5.493.44 7.732-.88 1.591-.94 3.182-2.808 3.925-4.617.4-.964.801-2.725.801-3.57 0-.547.036-.618.696-1.273.389-.38.754-.797.825-.916.118-.226.106-.226-.495-.024-1.002.357-1.144.31-.649-.226.366-.38.802-1.07.802-1.273 0-.036-.177.024-.377.13-.212.12-.684.298-1.037.405l-.637.203-.577-.393c-.319-.214-.767-.452-1.002-.524-.601-.166-1.52-.142-2.063.048-1.473.535-2.404 1.916-2.298 3.427z"
/>
</g>
</svg>
);

export const ShareToEmailIcon = props => (
<svg {...props} xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g fill="none" fillRule="evenodd">
<rect width="24" height="24" fill="#7A7A7A" rx="2" />
<path
fill="#fff"
d="M4 7a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v1.174L12 12 4 8.087V7zm7.5 6.665c.28.123.72.123 1 0L20 10v7a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-7l7.5 3.665z"
/>
</g>
</svg>
);

export const ShareIcon = props => (
<svg {...props} xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
<g fill="#505050" fillRule="nonzero">
<path d="M11.25 0H6v1.5h3.45L4.725 6.225l1.05 1.05L10.5 2.55V6H12V.75c0-.45-.3-.75-.75-.75z" />
<path d="M10.5 12H.75C.3 12 0 11.7 0 11.25V1.5C0 1.05.3.75.75.75h3v1.5H1.5v8.25h8.25V8.25h1.5v3c0 .45-.3.75-.75.75z" />
</g>
</svg>
);
72 changes: 72 additions & 0 deletions components/input/component.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { applyVariations } from '../utils';
import * as Styled from './styled.jsx';

export class Input extends PureComponent {
static propTypes = {
value: PropTypes.string,
placeholder: PropTypes.string,
type: PropTypes.string,
readOnly: PropTypes.bool,
autoFocus: PropTypes.bool,
disabled: PropTypes.bool,
onChange: PropTypes.func,
onClick: PropTypes.func,
onEnter: PropTypes.func,
/** Medium variation */
medium: PropTypes.bool,
/** Small variation */
small: PropTypes.bool,
/** Large variation */
large: PropTypes.bool,
};

handleChange = () => {
const { onChange } = this.props;
if (onChange) {
onChange();
}
};

handleKeyPress = e => {
const { onEnter } = this.props;
if (onEnter && e.key === 'Enter') {
onEnter();
}
};

render() {
const {
value,
placeholder,
readOnly,
type,
autoFocus,
onClick,
disabled,
...inputProps
} = this.props;

const { component: MappedStyledComponent, filteredProps } = applyVariations(
Styled.Input, // this is required but we don't want it in the generated docs so don't include it above
Styled.variationMap,
inputProps,
);

return (
<MappedStyledComponent
type={type || 'text'}
autoFocus={autoFocus}
readOnly={readOnly}
disabled={disabled}
value={value || ''}
placeholder={placeholder || ''}
onChange={this.handleChange}
onClick={onClick}
onKeyPress={this.handleKeyPress}
{...filteredProps || {}}
/>
);
}
}
40 changes: 40 additions & 0 deletions components/input/styled.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import styled from 'styled-components';
import { thickness, fonts, inputColors, colors } from '../shared-styles';
import { resetStyles } from '../utils';

export const Input = styled.input`
${resetStyles};

${fonts.ui16};
border-radius: 3px;
border: 1px solid ${inputColors.inputBorderColor};
padding: ${thickness.eight} 0 ${thickness.eight} ${thickness.eight};

&:focus {
border-color: ${inputColors.inputFocusedBorderColor};
box-shadow: 0 0 0 2px ${inputColors.inputFocusedShadowColor};
outline: 0;
}

&:disabled {
opacity: 0.5;
}

&:read-only {
background: ${colors.gray22};
}
`;

export const variationMap = {
small: component => component.extend`
${fonts.ui14};
padding: 6px 0 6px ${thickness.eight};
`,
medium: component => component.extend`
${fonts.ui16};
`,
large: component => component.extend`
padding: 13px 0 11px 12px;
${fonts.ui16};
`,
};
1 change: 1 addition & 0 deletions components/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ export { FilesSection } from './files-section/component.jsx';
export { DropZone } from './drop-zone/component.jsx';
export { GroupSelector } from './group-selector/component.jsx';
export { GroupSelectorModal } from './group-selector/modal/component.jsx';
export { ShareDialog } from './share-dialog/component.jsx';
49 changes: 49 additions & 0 deletions components/share-dialog/component.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Modal } from '../modal/modal.jsx';
import {
FaithlifeShareButton,
TwitterShareButton,
FacebookShareButton,
EmailShareButton,
} from './social-share-buttons.jsx';
import { CopyToClipboard } from './copy-to-clipboard.jsx';
import * as Styled from './styled.jsx';

/**
* ShareDialog
*/
export class ShareDialog extends React.Component {
static propTypes = {
shareUrl: PropTypes.string.isRequired,
onClose: PropTypes.func.isRequired,
message: PropTypes.string,
isOpen: PropTypes.bool,
modalTitle: PropTypes.string,
copyButtonText: PropTypes.string,
};

render() {
const { shareUrl, message, onClose, isOpen, modalTitle, copyButtonText } = this.props;

const encodedShareUrl = encodeURIComponent(shareUrl);
const encodedMessage = message ? encodeURIComponent(message) : '';

return (
<Modal
withoutFooter
isOpen={isOpen}
onClose={onClose}
title={modalTitle || 'Share this page'}
>
<Styled.ShareContainer>
<FaithlifeShareButton encodedShareUrl={encodedShareUrl} encodedMessage={encodedMessage} />
<TwitterShareButton encodedShareUrl={encodedShareUrl} encodedMessage={encodedMessage} />
<FacebookShareButton encodedShareUrl={encodedShareUrl} />
<EmailShareButton encodedShareUrl={encodedShareUrl} encodedMessage={encodedMessage} />
<CopyToClipboard copyValue={shareUrl} copyButtonText={copyButtonText} />
</Styled.ShareContainer>
</Modal>
);
}
}
66 changes: 66 additions & 0 deletions components/share-dialog/copy-to-clipboard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React from 'react';
import PropTypes from 'prop-types';
import Clipboard from 'clipboard';
import debounce from 'lodash.debounce';
import { Button } from '../button/component.jsx';
import { Input } from '../input/component.jsx';
import * as Styled from './styled.jsx';

export class CopyToClipboard extends React.Component {
static propTypes = {
copyValue: PropTypes.string.isRequired,
copyButtonText: PropTypes.string,
hideInput: PropTypes.bool,
};

button = React.createRef();
state = {
showFeedback: false,
};

componentDidMount() {
const button = this.button.current;

this.clipboard = new Clipboard(button);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This instance needs to be cleaned up in componentWillUnmount:

componentWillUnmount() {
  this.clipboard.destroy();
}


this.clipboard.on('success', () => {
this.showFeedback();
});
}

componentWillUnmount() {
this.clipboard.destroy();
}

showFeedback = () => {
this.setState({ showFeedback: true });
this.hideFeedback();
};

hideFeedback = debounce(() => {
this.setState({ showFeedback: false });
}, 2000);

selectSelf = e => e.target.select();

render() {
const { copyValue, copyButtonText, hideInput } = this.props;
const { showFeedback } = this.state;

return (
<Styled.ShareContainer>
{!hideInput && (
<Styled.CopyContainer>
<Input small type="text" readOnly value={copyValue} onClick={this.selectSelf} />
</Styled.CopyContainer>
)}
<div>
<Button small ref={this.button} data-clipboard-text={copyValue} primary>
{copyButtonText || 'Copy'}
</Button>
{showFeedback && <Styled.Copied>Copied!</Styled.Copied>}
</div>
</Styled.ShareContainer>
);
}
}
Loading