copy buttons + version link at the top

master
Lucas Duailibe 2018-04-12 15:09:04 -03:00
parent 1c8dd0c1e7
commit 94b5ab4d6e
4 changed files with 180 additions and 83 deletions

View File

@ -1,9 +1,10 @@
import React from "react";
import { Button, LinkButton } from "./buttons";
import { Button, ClipboardButton, LinkButton } from "./buttons";
import EditorState from "./EditorState";
import { DebugPanel, InputPanel, OutputPanel } from "./panels";
import PrettierFormat from "./PrettierFormat";
import VersionLink from "./VersionLink";
import { shallowEqual } from "./helpers";
import * as urlHash from "./urlHash";
import formatMarkdown from "./markdown";
@ -92,94 +93,121 @@ class Playground extends React.Component {
if (!loaded) return "Loading...";
return (
<EditorState>
{editorState => (
<div className="playground-container">
<div className="editors-container">
<Sidebar visible={editorState.showSidebar}>
{categorizeOptions(
availableOptions,
(category, categoryOptions) => (
<SidebarCategory key={category} title={category}>
{categoryOptions.map(option => (
<Option
key={option.name}
option={option}
value={options[option.name]}
onChange={this.handleOptionValueChange}
/>
))}
</SidebarCategory>
)
)}
<SidebarCategory title="Debug">
<Checkbox
label="show AST"
checked={editorState.showAst}
onChange={editorState.toggleAst}
/>
<Checkbox
label="show doc"
checked={editorState.showDoc}
onChange={editorState.toggleDoc}
/>
</SidebarCategory>
<div className="sub-options">
<Button onClick={this.resetOptions}>Reset to defaults</Button>
</div>
</Sidebar>
<PrettierFormat
worker={this._worker}
code={content}
options={options}
debugAst={editorState.showAst}
debugDoc={editorState.showDoc}
>
{({ formatted, debugAst, debugDoc }) => (
<div className="editors">
<InputPanel
mode={getCodemirrorMode(options.parser)}
rulerColumn={options.printWidth}
value={content}
onChange={this.setContent}
<React.Fragment>
<VersionLink version={this.state.version} />
<EditorState>
{editorState => (
<div className="playground-container">
<div className="editors-container">
<Sidebar visible={editorState.showSidebar}>
{categorizeOptions(
availableOptions,
(category, categoryOptions) => (
<SidebarCategory key={category} title={category}>
{categoryOptions.map(option => (
<Option
key={option.name}
option={option}
value={options[option.name]}
onChange={this.handleOptionValueChange}
/>
))}
</SidebarCategory>
)
)}
<SidebarCategory title="Debug">
<Checkbox
label="show AST"
checked={editorState.showAst}
onChange={editorState.toggleAst}
/>
{editorState.showAst ? (
<DebugPanel value={debugAst} />
) : null}
{editorState.showDoc ? (
<DebugPanel value={debugDoc} />
) : null}
<OutputPanel
mode={getCodemirrorMode(options.parser)}
value={formatted}
rulerColumn={options.printWidth}
<Checkbox
label="show doc"
checked={editorState.showDoc}
onChange={editorState.toggleDoc}
/>
</SidebarCategory>
<div className="sub-options">
<Button onClick={this.resetOptions}>
Reset to defaults
</Button>
</div>
)}
</PrettierFormat>
</div>
<div className="bottom-bar">
<div className="bottom-bar-buttons">
<Button onClick={editorState.toggleSidebar}>
{editorState.showSidebar ? "Hide" : "Show"} options
</Button>
<Button onClick={this.clearContent}>Clear</Button>
</Sidebar>
<PrettierFormat
worker={this._worker}
code={content}
options={options}
debugAst={editorState.showAst}
debugDoc={editorState.showDoc}
>
{({ formatted, debugAst, debugDoc }) => (
<div className="editors">
<InputPanel
mode={getCodemirrorMode(options.parser)}
rulerColumn={options.printWidth}
value={content}
onChange={this.setContent}
/>
{editorState.showAst ? (
<DebugPanel value={debugAst} />
) : null}
{editorState.showDoc ? (
<DebugPanel value={debugDoc} />
) : null}
<OutputPanel
mode={getCodemirrorMode(options.parser)}
value={formatted}
rulerColumn={options.printWidth}
/>
</div>
)}
</PrettierFormat>
</div>
<div className="bottom-bar-buttons bottom-bar-buttons-right">
<Button>Copy link</Button>
<Button>Copy markdown</Button>
<LinkButton href="#" target="_blank" rel="noopener">
Report issue
</LinkButton>
<div className="bottom-bar">
<div className="bottom-bar-buttons">
<Button onClick={editorState.toggleSidebar}>
{editorState.showSidebar ? "Hide" : "Show"} options
</Button>
<Button onClick={this.clearContent}>Clear</Button>
</div>
<div className="bottom-bar-buttons bottom-bar-buttons-right">
<ClipboardButton clipboardValue={window.location.href}>
Copy link
</ClipboardButton>
<Button>Copy markdown</Button>
<LinkButton href="#" target="_blank" rel="noopener">
Report issue
</LinkButton>
</div>
</div>
</div>
</div>
)}
</EditorState>
)}
</EditorState>
</React.Fragment>
);
}
}
function createVersionLink(version) {
const link = document.createElement("a");
const match = version.match(/^\d+\.\d+\.\d+-pr.(\d+)$/);
if (match) {
link.href = "https://github.com/prettier/prettier/pull/" + match[1];
link.textContent = `PR #${match[1]}`;
} else {
if (version.match(/\.0$/)) {
link.href =
"https://github.com/prettier/prettier/releases/tag/" + version;
} else {
link.href =
"https://github.com/prettier/prettier/blob/master/CHANGELOG.md#" +
version.replace(/\./g, "");
}
link.textContent = `v${version}`;
}
return link;
}
function categorizeOptions(availableOptions, render) {
const optionsByCategory = availableOptions.reduce((acc, option) => {
let options;

View File

@ -0,0 +1,26 @@
import React from "react";
import ReactDOM from "react-dom";
const root = document.getElementById("version");
export default function({ version }) {
const match = version.match(/^\d+\.\d+\.\d+-.(\d+)$/);
let href;
if (match) {
href = `pull/${match[1]}`;
} else if (version.match(/\.0$/)) {
href = `releases/tag/${version}`;
} else {
href = `blob/master/CHANGELOG.md#${version.replace(/\./g, "")}`;
}
return ReactDOM.createPortal(
<a
href={`https://github.com/prettier/prettier/${href}`}
target="_blank"
rel="noopener"
>
{match ? `PR #${match[1]}` : `v${version}`}
</a>,
root
);
}

View File

@ -1,9 +1,51 @@
import React from "react";
import ClipboardJS from "clipboard";
export function Button(props) {
return <button type="button" className="btn" {...props} />;
}
export const Button = React.forwardRef((props, ref) => (
<button type="button" className="btn" ref={ref} {...props} />
));
export function LinkButton(props) {
return <a className="btn" $ {...props} />;
return <a className="btn" {...props} />;
}
export class ClipboardButton extends React.Component {
constructor() {
super();
this.state = { showTooltip: false, tooltipText: "" };
this.timer = null;
this.ref = React.createRef();
}
componentDidMount() {
this.clipboard = new ClipboardJS(this.ref.current, {
text: () => this.props.clipboardValue
});
this.clipboard.on("success", () => this.showTooltip("Copied!"));
this.clipboard.on("error", () => this.showTooltip("Press ctrl+c to copy"));
}
showTooltip(text) {
this.setState({ showTooltip: true, tooltipText: text }, () => {
if (this.timer) clearTimeout(this.timer);
this.timer = setTimeout(() => {
this.timer = null;
this.setState({ showTooltip: false });
}, 2000);
});
}
render() {
const rest = Object.assign({}, this.props);
delete rest.children;
return (
<Button ref={this.ref} {...rest}>
{this.state.showTooltip ? (
<span className="tooltip">{this.state.tooltipText}</span>
) : null}
{this.props.children}
</Button>
);
}
}

View File

@ -21,6 +21,7 @@ module.exports = {
]
},
externals: {
clipboard: 'ClipboardJS',
codemirror: "CodeMirror",
react: "React",
"react-dom": "ReactDOM"