Skip to content

Commit

Permalink
Text Editor: Custom Styles & Tweet Embeds (#70)
Browse files Browse the repository at this point in the history
* Text Editor: Custom Styles & Tweet Embeds (#69)

* WIP: Tweets

* WIP: tweet

* Tweets almost work without proper styling

* Tweet display with lesser bugs

* Tweet Embedding

* Embedding Tweets

* v0.2.6-alpha.0

* Font changes

* TextEditor: Custom styling and Tweet embed

* Reverted packages

* v0.2.7-alpha.0

* v0.2.6

* Correct version of rich text

* v0.2.7

* Install only latest

* v0.2.8

* v0.2.9

Co-authored-by: Rajat Saxena <[email protected]>
  • Loading branch information
rajat1saxena and Rajat Saxena authored Sep 11, 2020
1 parent ec9bd3d commit 2d7afa1
Show file tree
Hide file tree
Showing 31 changed files with 303 additions and 33 deletions.
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"packages": [
"packages/*"
],
"version": "0.2.5",
"version": "0.2.9",
"useWorkspaces": true,
"npmClient": "yarn"
}
4 changes: 2 additions & 2 deletions packages/api/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@courselit/api",
"version": "0.2.5",
"version": "0.2.9",
"main": "./src/index.js",
"license": "MIT",
"author": {
Expand All @@ -16,7 +16,7 @@
"start": "node src"
},
"dependencies": {
"@courselit/thumbnail": "^0.2.5",
"@courselit/thumbnail": "^0.2.9",
"base-64": "^0.1.0",
"bcryptjs": "^2.4.3",
"body-parser": "^1.19.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/app/components/Admin/CourseEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import AppDialog from "../Public/AppDialog.js";
import LessonEditor from "./LessonEditor.js";
import AppMessage from "../../models/app-message.js";
import { BACKEND, MIMETYPE_IMAGE } from "../../config/constants.js";
import TextEditor from "@courselit/rich-text";
import TextEditor from "../Public/RichText.js";

const useStyles = makeStyles((theme) => ({
title: {
Expand Down
2 changes: 1 addition & 1 deletion packages/app/components/Admin/CourseItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from "react";
import PropTypes from "prop-types";
import Link from "next/link";
import { creatorCourse } from "../../types";
import TextEditor from "@courselit/rich-text";
import TextEditor from "../Public/RichText.js";
import { URL_EXTENTION_COURSES } from "../../config/constants.js";
import { CardContent, Card, Grid, Typography } from "@material-ui/core";
import { makeStyles } from "@material-ui/styles";
Expand Down
2 changes: 1 addition & 1 deletion packages/app/components/Admin/CoursesManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ const Courses = (props) => {
<Grid item>
<Button
variant="contained"
color={courseEditorVisible ? "" : "primary"}
color={courseEditorVisible ? "secondary" : "primary"}
onClick={() => showEditor()}
>
{courseEditorVisible ? <Done /> : <Add />}
Expand Down
2 changes: 1 addition & 1 deletion packages/app/components/Admin/LessonEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import { networkAction, setAppMessage } from "../../redux/actions";
import { connect } from "react-redux";
import AppDialog from "../Public/AppDialog";
import AppMessage from "../../models/app-message.js";
import TextEditor from "@courselit/rich-text";
import TextEditor from "../Public/RichText.js";

const useStyles = makeStyles((theme) => ({
formControl: {
Expand Down
4 changes: 2 additions & 2 deletions packages/app/components/Public/Article.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from "react";
import { Typography, Grid } from "@material-ui/core";
import Link from "next/link";
import TextEditor from "@courselit/rich-text";
import TextEditor from "./RichText.js";
import PropTypes from "prop-types";
import { makeStyles } from "@material-ui/styles";
import { MEDIA_BACKEND } from "../../config/constants.js";
Expand Down Expand Up @@ -107,7 +107,7 @@ const Article = (props) => {
</Grid>
</div>
)}
{courseDescriptionHydrated && (
{courseDescriptionHydrated && process.browser && (
<TextEditor
initialContentState={TextEditor.hydrate(course.description)}
readOnly={true}
Expand Down
2 changes: 1 addition & 1 deletion packages/app/components/Public/LessonViewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { ENROLL_IN_THE_COURSE, USER_ERROR_HEADER } from "../../config/strings";
import { makeStyles } from "@material-ui/styles";
import { lesson, authProps, profileProps } from "../../types";
import { formulateMediaUrl } from "../../lib/utils.js";
import TextEditor from "@courselit/rich-text";
import TextEditor from "./RichText.js";

const useStyles = makeStyles((theme) => ({
notEnrolledHeader: {
Expand Down
29 changes: 29 additions & 0 deletions packages/app/components/Public/RichText.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from "react";
import PropTypes from "prop-types";
import TextEditor from "@courselit/rich-text";
import { useTheme } from "@material-ui/styles";

const RichText = (props) => {
const theme = useTheme();

return (
<TextEditor
initialContentState={props.initialContentState}
onChange={props.onChange}
readOnly={props.readOnly}
styles={theme.richText}
/>
);
};

RichText.hydrate = TextEditor.hydrate;
RichText.stringify = TextEditor.stringify;
RichText.emptyState = TextEditor.emptyState;

RichText.propTypes = {
initialContentState: PropTypes.any,
onChange: PropTypes.func,
readOnly: PropTypes.bool,
};

export default RichText;
4 changes: 2 additions & 2 deletions packages/app/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@courselit/app",
"version": "0.2.5",
"version": "0.2.9",
"main": "index.js",
"license": "MIT",
"author": {
Expand All @@ -17,7 +17,7 @@
},
"dependencies": {
"@babel/runtime": "^7.8.3",
"@courselit/rich-text": "^0.2.5",
"@courselit/rich-text": "^0.2.9",
"@material-ui/core": "^4.8.1",
"@material-ui/icons": "^4.4.1",
"@material-ui/styles": "^4.7.1",
Expand Down
99 changes: 99 additions & 0 deletions packages/rich-text/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,102 @@
# Rich Text Editor & Displayer

A full-fledged rich text editor and displayer for React apps, built using DraftJS.

## Styling

Pass in an object containing styling information to the `styles` prop in order to override the default styles.

```
<TextEditor
initialContentState={TextEditor.hydrate(course.description)}
readOnly={true}
styles={{text: {fontSize: 30}}}
/>
```

The following object details the default styles and what all components you can target from your custom styles.

```
{
controls: {
container: {
display: "flex",
flexDirection: "column",
border: "1px solid #eee",
},
editor: {
maxHeight: "50vh",
overflowX: "none",
overflowY: "scroll",
padding: 10,
},
toolbar: {
padding: 10,
background: "#f7f7f7",
display: "flex",
flexDirection: "row",
alignItems: "center",
},
toolbarInput: {
background: "rgb(179 188 255)",
padding: 10,
},
toolbarButton: {
border: "none",
background: "transparent",
padding: 10,
"&:hover": {
background: "#585858",
},
fontWeight: "bold",
fontSize: 16,
},
},
media: {
container: {
display: "flex",
justifyContent: "center",
},
img: {
maxWidth: "100%",
},
},
code: {
background: "rgb(45, 45, 45)",
color: "#e2e7ff",
padding: "10px 16px",
borderRadius: 2,
fontFamily: '"Fira Code", monospace',
},
blockquote: {
fontStyle: "italic",
fontFamily: "serif",
marginTop: 10,
marginBottom: 10,
borderLeft: "5px solid rgb(179 188 255)",
paddingLeft: 10,
fontSize: "1.6em",
color: "rgb(58 58 58)",
},
text: {
textAlign: "justify",
lineHeight: "1.8em",
fontSize: "1.2em",
fontFamily: 'Open Sans, "Helvetica Neue", Helvetica, Arial, sans-serif'
},
}
```

## Integrations

### YouTube Videos

Paste video's URL in to the editor and it will be embedded.

### Tweets

Paste any tweet's URL in the editor and the tweet will be embedded.

## Known issues

1. While editing, making changes to a tweet's URL might show previous content. The workaround is to delete the tweet URL entirely and then paste the new URL.
7 changes: 4 additions & 3 deletions packages/rich-text/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@courselit/rich-text",
"version": "0.2.5",
"version": "0.2.9",
"description": "Edit and display rich text in React apps. Built using DraftJS.",
"keywords": [
"rte",
Expand Down Expand Up @@ -35,8 +35,9 @@
"url": "https://github.com/codelitdev/courselit/issues"
},
"dependencies": {
"draft-js": "^0.11.6",
"prop-types": "^15.7.2"
"draft-js": "^0.11.7",
"prop-types": "^15.7.2",
"react-tweet-embed": "^1.2.2"
},
"peerDependencies": {
"react": "^16.13.1",
Expand Down
82 changes: 82 additions & 0 deletions packages/rich-text/src/Decorators/Tweet.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* Decorator for tweets.
*/
import React, { createRef, useEffect } from "react";
import PropTypes from "prop-types";

const styles = {
container: {
textAlign: "center",
},
iframeContainer: {
position: "relative",
overflow: "hidden",
"& iframe": {
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "100%",
},
},
link: {
display: "hidden",
marginTop: "1em",
color: "#676767",
fontSize: ".8em",
},
};

const Tweet = (props) => {
const tweetRef = createRef();

useEffect(() => {
if (!window.twttr) {
window.twttr = twitterFunc(document, "script", "twitter-wjs");
}
}, []);

/* eslint-disable one-var */
const twitterFunc = function (d, s, id) {
var js,
fjs = d.getElementsByTagName(s)[0],
t = window.twttr || {};
if (d.getElementById(id)) return t;
js = d.createElement(s);
js.id = id;
js.src = "https://platform.twitter.com/widgets.js";
fjs.parentNode.insertBefore(js, fjs);
t._e = [];
t.ready = function (f) {
t._e.push(f);
};
return t;
};
/* eslint-enable one-var */

useEffect(() => {
const tokens = props.decoratedText.split("/");
window.twttr.ready((twttr) => {
twttr.widgets.createTweet(tokens[tokens.length - 1], tweetRef.current, {
theme: "dark",
align: "center",
});
});
}, [props.decoratedText]);

return (
<div style={styles.container}>
<div ref={tweetRef} style={styles.iframeContainer} />
<a href={props.decoratedText} style={styles.link}>
{props.children}
</a>
</div>
);
};

Tweet.propTypes = {
decoratedText: PropTypes.string,
children: PropTypes.array,
};

export default Tweet;
1 change: 1 addition & 0 deletions packages/rich-text/src/Decorators/YouTube.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const styles = {
display: "block",
marginTop: "1em",
color: "#676767",
fontSize: ".8em",
},
};

Expand Down
Loading

0 comments on commit 2d7afa1

Please sign in to comment.