initial commit
This commit is contained in:
commit
c5376f64e0
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/lib/
|
||||
/node_modules/
|
1
.npmignore
Normal file
1
.npmignore
Normal file
|
@ -0,0 +1 @@
|
|||
/highcharts-assets/
|
77
CODE_OF_CONDUCT.md
Normal file
77
CODE_OF_CONDUCT.md
Normal file
|
@ -0,0 +1,77 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at mail@nilsnh.no. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
https://www.contributor-covenant.org/faq
|
||||
|
21
LICENSE.md
Normal file
21
LICENSE.md
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019 Nils Norman Haukås
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
84
README.md
Normal file
84
README.md
Normal file
|
@ -0,0 +1,84 @@
|
|||
# Highcharts editor input plugin for Sanity CMS
|
||||
|
||||
This plugin let's you embed the [Highcharts Editor](https://www.highcharts.com/blog/products/highcharts-editor/) within Sanity.
|
||||
|
||||
## Installation
|
||||
|
||||
1. Run `sanity install sanity-plugin-highcharts-editor` to install the plugin.
|
||||
1. Copy the `highcharts-assets/` folder into your Sanity project's static folder like so `/static/highcharts-assets/`.
|
||||
1. Run `sanity start`
|
||||
|
||||
## Usage
|
||||
|
||||
Prerequisite: Knowledge of [how Sanity does rich text](https://www.sanity.io/docs/content-studio/what-you-need-to-know-about-block-text).
|
||||
|
||||
After installing the plugin. In your schema where you define block content you can add:
|
||||
|
||||
```javascript
|
||||
export default {
|
||||
name: "content",
|
||||
type: "array",
|
||||
title: "Content",
|
||||
of: [
|
||||
{
|
||||
type: "block"
|
||||
},
|
||||
{
|
||||
type: "highcharts"
|
||||
}
|
||||
]
|
||||
};
|
||||
```
|
||||
|
||||
If all works correctly you should now be able to create charts with the Sanity studio.
|
||||
|
||||
See [HighchartsType.js](src/HighchartsType.js), to see what data fields is saved.
|
||||
|
||||
## How to display the chart
|
||||
|
||||
Prerequisite: Knowledge of [presenting portable text](https://www.sanity.io/docs/presenting-block-text). Based on the serializer example found there, we can add a serializer that either outputs `svgStr` directly, or outputs `jsonStr` with [HighchartsReact](https://github.com/highcharts/highcharts-react) like so:
|
||||
|
||||
```javascript
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import Highcharts from "highcharts";
|
||||
import HighchartsReact from "highcharts-react-official";
|
||||
import BlockContent from "@sanity/block-content-to-react";
|
||||
import initSanityClient from "@sanity/client";
|
||||
|
||||
const client = initSanityClient({
|
||||
projectId: "<your project id>",
|
||||
dataset: "<some dataset>",
|
||||
useCdn: true
|
||||
});
|
||||
|
||||
const serializers = {
|
||||
types: {
|
||||
highcharts: ({ node: { jsonStr = "" } = {} }) => {
|
||||
try {
|
||||
const options = JSON.parse(jsonStr);
|
||||
return <HighchartsReact highcharts={Highcharts} options={options} />;
|
||||
} catch (e) {
|
||||
console.log("Failed to load highcharts options", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
client.fetch('*[_type == "post"][0]').then(post => {
|
||||
ReactDOM.render(
|
||||
<BlockContent blocks={post.content} serializers={serializers} />,
|
||||
document.getElementById("root")
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
This plugin is licensed under the [MIT license](LICENSE.md).
|
||||
|
||||
**Please note:** While the Highcharts editor is MIT licensed, Highcharts.js itself requires a [paid license](https://shop.highsoft.com/highcharts/). If you're a non-profit organization you can apply to get a free license.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms.
|
19
babel.config.js
Normal file
19
babel.config.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
module.exports = function(api) {
|
||||
api.cache(true);
|
||||
return {
|
||||
presets: [
|
||||
"@babel/preset-react",
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
useBuiltIns: "entry",
|
||||
targets: ["last 1 version", "> 1%"]
|
||||
}
|
||||
]
|
||||
],
|
||||
plugins: [
|
||||
"@babel/plugin-proposal-class-properties",
|
||||
"react-hot-loader/babel"
|
||||
]
|
||||
};
|
||||
};
|
BIN
highcharts-assets/help/dataImport.gif
Normal file
BIN
highcharts-assets/help/dataImport.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 68 KiB |
47
highcharts-assets/highcharts-editor.complete.min.js
vendored
Normal file
47
highcharts-assets/highcharts-editor.complete.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
highcharts-assets/highcharts-editor.min.css
vendored
Normal file
1
highcharts-assets/highcharts-editor.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
59
highcharts-assets/highcharts-iframe-content.html
Normal file
59
highcharts-assets/highcharts-iframe-content.html
Normal file
|
@ -0,0 +1,59 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Highcharts Editor</title>
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<!-- Specify version to prevent issues on update -->
|
||||
<script src="https://code.highcharts.com/7.0.3/highcharts.js" type="text/javascript"></script>
|
||||
<script src="https://code.highcharts.com/7.0.3/highcharts-more.js" type="text/javascript"></script>
|
||||
<script src="https://code.highcharts.com/7.0.3/highcharts-3d.js" type="text/javascript"></script>
|
||||
<script src="https://code.highcharts.com/7.0.3/modules/accessibility.js" type="text/javascript"></script>
|
||||
<script src="https://code.highcharts.com/7.0.3/modules/annotations.js" type="text/javascript"></script>
|
||||
<script src="https://code.highcharts.com/7.0.3/modules/boost.js" type="text/javascript"></script>
|
||||
<script src="https://code.highcharts.com/7.0.3/modules/broken-axis.js" type="text/javascript"></script>
|
||||
<script src="https://code.highcharts.com/7.0.3/modules/data.js" type="text/javascript"></script>
|
||||
<script src="https://code.highcharts.com/7.0.3/modules/exporting.js" type="text/javascript"></script>
|
||||
<script src="https://code.highcharts.com/7.0.3/modules/drilldown.js" type="text/javascript"></script>
|
||||
<script src="https://code.highcharts.com/7.0.3/modules/funnel.js" type="text/javascript"></script>
|
||||
<script src="https://code.highcharts.com/7.0.3/modules/heatmap.js" type="text/javascript"></script>
|
||||
<script src="https://code.highcharts.com/7.0.3/modules/no-data-to-display.js" type="text/javascript"></script>
|
||||
<script src="https://code.highcharts.com/7.0.3/modules/offline-exporting.js" type="text/javascript"></script>
|
||||
<script src="https://code.highcharts.com/7.0.3/modules/solid-gauge.js" type="text/javascript"></script>
|
||||
<script src="https://code.highcharts.com/7.0.3/modules/treemap.js" type="text/javascript"></script>
|
||||
|
||||
<script src="highcharts-editor.complete.min.js"></script>
|
||||
<link href="highcharts-editor.min.css" type="text/css" rel="stylesheet"/>
|
||||
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width:100%;
|
||||
height:100%;
|
||||
background:#F5F5F5;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
// Highcharts is loaded and ready to be instantiated
|
||||
highed.ready(function () {
|
||||
var intervalID = setInterval(function () {
|
||||
// we need to wait for our custom component to have added a callback
|
||||
// before we can instantiate the editor and call the callback.
|
||||
if (window.editorReadyCallback) {
|
||||
clearInterval(intervalID)
|
||||
var editorInstance = highed.Editor(document.body)
|
||||
window.editorReadyCallback(editorInstance)
|
||||
}
|
||||
}, 200)
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
3265
package-lock.json
generated
Normal file
3265
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
25
package.json
Normal file
25
package.json
Normal file
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"name": "sanity-plugin-highcharts-editor",
|
||||
"version": "1.0.0",
|
||||
"description": "Add Highcharts editor to Sanity.",
|
||||
"main": "./lib/index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"build": "babel src --out-dir lib --copy-files --source-map",
|
||||
"deploy": "npm run build && npm publish"
|
||||
},
|
||||
"author": "Nils Norman Haukås <mail@nilsnh.no> (https://nilsnh.no/)",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": "16.x"
|
||||
},
|
||||
"homepage": "https://github.com/nilsnh/sanity-plugin-highcharts-editor#readme",
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.2.3",
|
||||
"@babel/core": "^7.3.3",
|
||||
"@babel/plugin-proposal-class-properties": "^7.3.3",
|
||||
"@babel/preset-env": "^7.3.1",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"react-hot-loader": "^4.7.1"
|
||||
}
|
||||
}
|
12
sanity.json
Normal file
12
sanity.json
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"paths": {
|
||||
"source": "./src",
|
||||
"compiled": "./lib"
|
||||
},
|
||||
"parts": [
|
||||
{
|
||||
"implements": "part:@sanity/base/schema-type",
|
||||
"path": "HighchartsType.js"
|
||||
}
|
||||
]
|
||||
}
|
95
src/HighchartsInput.js
Normal file
95
src/HighchartsInput.js
Normal file
|
@ -0,0 +1,95 @@
|
|||
import React from "react";
|
||||
import PatchEvent, {
|
||||
setIfMissing,
|
||||
set,
|
||||
unset
|
||||
} from "part:@sanity/form-builder/patch-event";
|
||||
|
||||
export default class HighchartsInput extends React.Component {
|
||||
state = {
|
||||
// Reference to editor instance running inside iframe.
|
||||
editor: null,
|
||||
// We store svg and html representations of the chart in local state. When
|
||||
// unmounting we save that date to Sanity. This solves an issue with distorted
|
||||
// graphs caused by doing graph exports right as the modal was closing.
|
||||
svgStr: "",
|
||||
htmlStr: ""
|
||||
};
|
||||
|
||||
componentWillUnmount() {
|
||||
// when unloading we save the iframe data.
|
||||
this.saveProjectData();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const mountNode = document.getElementById("highed-mountpoint");
|
||||
const iframe = document.createElement("iframe");
|
||||
iframe.setAttribute("width", "100%");
|
||||
iframe.setAttribute("height", "800px");
|
||||
iframe.setAttribute("id", "highed-editor");
|
||||
iframe.setAttribute(
|
||||
"src",
|
||||
"/static/highcharts-assets/highcharts-iframe-content.html"
|
||||
);
|
||||
iframe.onload = () => this.onEditorIframeLoaded(iframe);
|
||||
mountNode.appendChild(iframe);
|
||||
}
|
||||
|
||||
chartChangeHandler = () => {
|
||||
const { editor } = this.state;
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
svgStr: editor.getEmbeddableSVG(),
|
||||
htmlStr: editor.getEmbeddableHTML()
|
||||
});
|
||||
};
|
||||
|
||||
onEditorIframeLoaded = iframe => {
|
||||
iframe.contentWindow.editorReadyCallback = editor => {
|
||||
window.highchartsEditorInstance = editor;
|
||||
editor.on("ChartChangedLately", this.chartChangeHandler);
|
||||
this.setState({ editor }, this.loadProjectData);
|
||||
};
|
||||
};
|
||||
|
||||
loadProjectData = () => {
|
||||
const { editor } = this.state;
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
const { value: { editorConfigWithData } = {} } = this.props;
|
||||
if (!editorConfigWithData) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
editor.chart.loadProject(JSON.parse(editorConfigWithData));
|
||||
} catch (e) {
|
||||
console.log("Failed to load higcharts editor", e);
|
||||
}
|
||||
};
|
||||
|
||||
saveProjectData = () => {
|
||||
const { editor, htmlStr, svgStr } = this.state;
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
const jsonStr = JSON.stringify(editor.chart.options.full);
|
||||
const editorConfigWithData = editor.chart.toProjectStr();
|
||||
const patches = PatchEvent.from([
|
||||
setIfMissing({}),
|
||||
jsonStr ? set(jsonStr, ["jsonStr"]) : unset(["jsonStr"]),
|
||||
editorConfigWithData
|
||||
? set(editorConfigWithData, ["editorConfigWithData"])
|
||||
: unset(["editorConfigWithData"]),
|
||||
htmlStr ? set(htmlStr, ["htmlStr"]) : unset(["htmlStr"]),
|
||||
svgStr ? set(svgStr, ["svgStr"]) : unset(["svgStr"])
|
||||
]);
|
||||
this.props.onChange(patches);
|
||||
};
|
||||
|
||||
render() {
|
||||
return <div id="highed-mountpoint" />;
|
||||
}
|
||||
}
|
3
src/HighchartsPreview.css
Normal file
3
src/HighchartsPreview.css
Normal file
|
@ -0,0 +1,3 @@
|
|||
.chartSvg svg {
|
||||
width: 100%;
|
||||
}
|
16
src/HighchartsPreview.js
Normal file
16
src/HighchartsPreview.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
import React from "react";
|
||||
import styles from "./HighchartsPreview.css";
|
||||
|
||||
const HighChartsPreview = ({ value: { svgStr } = {} }) => {
|
||||
if (!svgStr) {
|
||||
return <p>No chart data to load</p>;
|
||||
}
|
||||
return (
|
||||
<div
|
||||
className={styles.chartSvg}
|
||||
dangerouslySetInnerHTML={{ __html: svgStr }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default HighChartsPreview;
|
22
src/HighchartsType.js
Normal file
22
src/HighchartsType.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
import HighchartsInput from "./HighchartsInput";
|
||||
import HighchartsPreview from "./HighchartsPreview";
|
||||
|
||||
export default {
|
||||
name: "highcharts",
|
||||
title: "Highcharts",
|
||||
type: "object",
|
||||
inputComponent: HighchartsInput,
|
||||
preview: {
|
||||
select: { svgStr: "svgStr" },
|
||||
component: HighchartsPreview
|
||||
},
|
||||
options: {
|
||||
editModal: "fullscreen"
|
||||
},
|
||||
fields: [
|
||||
{ name: "htmlStr", readOnly: true, type: "string" },
|
||||
{ name: "jsonStr", readOnly: true, type: "string" },
|
||||
{ name: "svgStr", readOnly: true, type: "string" },
|
||||
{ name: "editorConfigWithData", readOnly: true, type: "string" }
|
||||
]
|
||||
};
|
Loading…
Reference in a new issue