Fix Medium embedding workflow (#707)

* fix url encoding to support direct pastes to medium

* move check for object keys length to getQueryStringState

* remove url parse from GistContainer

* use useMemo instead of memo

* remove decode()

* add copy URL button to export menu
main
Michael Fix 6 years ago committed by GitHub
parent 9ddb821fa4
commit b5ae198312
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -63,8 +63,7 @@ class Editor extends React.Component {
async componentDidMount() { async componentDidMount() {
const { asPath = '' } = this.props.router const { asPath = '' } = this.props.router
const { query } = url.parse(asPath, true) const { query } = url.parse(asPath, true)
const queryParams = getQueryStringState(query) const initialState = getQueryStringState(query)
const initialState = Object.keys(queryParams).length ? queryParams : {}
const newState = { const newState = {
// Load from localStorage // Load from localStorage

@ -15,6 +15,8 @@ const toIFrame = url =>
</iframe> </iframe>
` `
const toURL = url => encodeURI(`https://carbon.now.sh/embed${url}`)
const MAX_PAYLOAD_SIZE = 5e6 // bytes const MAX_PAYLOAD_SIZE = 5e6 // bytes
function verifyPayloadSize(str) { function verifyPayloadSize(str) {
if (typeof str !== 'string') return true if (typeof str !== 'string') return true
@ -22,20 +24,23 @@ function verifyPayloadSize(str) {
return new Blob([str]).size < MAX_PAYLOAD_SIZE return new Blob([str]).size < MAX_PAYLOAD_SIZE
} }
const CopyEmbed = withRouter( const CopyEmbed = withRouter(({ router: { asPath }, mapper, title, margin }) => {
React.memo( const text = React.useMemo(() => mapper(asPath), [mapper, asPath])
({ router: { asPath } }) => { const { onClick, copied } = useCopyTextHandler(text)
const { onClick, copied } = useCopyTextHandler(toIFrame(asPath))
return ( return (
<Button onClick={onClick} center color={COLORS.PURPLE} padding="12px 16px" flex="1 0 68px"> <Button
{copied ? 'Copied!' : 'Copy Embed'} onClick={onClick}
center
hoverColor={COLORS.PURPLE}
color={COLORS.DARK_PURPLE}
margin={margin}
style={{ minWidth: 48 }}
>
{copied ? 'Copied!' : title}
</Button> </Button>
) )
}, })
(prevProps, nextProps) => prevProps.router.asPath === nextProps.router.asPath
)
)
const popoutStyle = { width: '280px', right: 0 } const popoutStyle = { width: '280px', right: 0 }
@ -102,7 +107,13 @@ class ExportMenu extends React.PureComponent {
<Button center color={COLORS.PURPLE} onClick={this.handleExport('open')}> <Button center color={COLORS.PURPLE} onClick={this.handleExport('open')}>
Open Open
</Button> </Button>
<CopyEmbed /> <div className="save-container">
<span>Copy embed</span>
<div>
<CopyEmbed title="URL" mapper={toURL} margin="0 4px 0 0" />
<CopyEmbed title="IFrame" mapper={toIFrame} margin="0 0 0 4px" />
</div>
</div>
<div className="save-container"> <div className="save-container">
<span>Save as</span> <span>Save as</span>
<div> <div>
@ -175,6 +186,11 @@ class ExportMenu extends React.PureComponent {
display: flex; display: flex;
flex: 1; flex: 1;
} }
.save-container:first-of-type {
padding: 12px 12px;
border-right: 1px solid ${COLORS.PURPLE};
}
`} `}
</style> </style>
</div> </div>

@ -1,5 +1,4 @@
import React from 'react' import React from 'react'
import url from 'url'
import { withRouter } from 'next/router' import { withRouter } from 'next/router'
import { escapeHtml } from '../lib/util' import { escapeHtml } from '../lib/util'
@ -9,8 +8,7 @@ class GistContainer extends React.Component {
static contextType = ApiContext static contextType = ApiContext
async componentDidMount() { async componentDidMount() {
const { asPath = '' } = this.props.router const { pathname } = this.props.router
const { pathname } = url.parse(asPath, true)
const path = escapeHtml(pathname.split('/').pop()) const path = escapeHtml(pathname.split('/').pop())
let newState = {} let newState = {}

@ -62,7 +62,7 @@ export const deserializeState = serializedState => {
return JSON.parse(decodeURIComponent(stateString)) return JSON.parse(decodeURIComponent(stateString))
} }
export const getQueryStringState = query => { const getQueryStringObject = query => {
if (query.state) { if (query.state) {
return deserializeState(query.state) return deserializeState(query.state)
} }
@ -77,9 +77,16 @@ export const getQueryStringState = query => {
return state return state
} }
export const getQueryStringState = query => {
const queryParams = getQueryStringObject(query)
return Object.keys(queryParams).length ? queryParams : {}
}
export const updateQueryString = (router, state) => { export const updateQueryString = (router, state) => {
const mappedState = mapper.map(reverseMappings, state) const mappedState = mapper.map(reverseMappings, state)
serializeCode(mappedState) serializeCode(mappedState)
// calls `encodeURIComponent` on each key internally
// const query = qs.stringify(mappedState)
router.replace( router.replace(
{ {

@ -56,16 +56,15 @@ class Embed extends React.Component {
handleUpdate = updates => { handleUpdate = updates => {
const { asPath = '' } = this.props.router const { asPath = '' } = this.props.router
const { query } = url.parse(asPath, true) const { query } = url.parse(asPath, true)
const queryParams = getQueryStringState(query) const initialState = getQueryStringState(query)
const initialState = Object.keys(queryParams).length ? queryParams : {}
this.setState( this.setState(
{ {
...initialState, ...initialState,
...updates, ...updates,
id: query.id, id: query.id,
copyable: queryParams.copy !== false, copyable: initialState.copy !== false,
readOnly: queryParams.readonly !== false, readOnly: initialState.readonly !== false,
mounted: true mounted: true
}, },
this.postMessage this.postMessage

Loading…
Cancel
Save