-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added basic Content Types functionality (#3)
* Added Sidebar component to private pages * Fix .main-container in mobile * Added Settings page * Added Settings form and functionality for site title and site description * Added basic Content Types functionality
- Loading branch information
1 parent
5a4ba43
commit afc570f
Showing
16 changed files
with
481 additions
and
138 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,17 @@ | ||
# ChaiCMS | ||
|
||
A React CMS for the JAMstack. | ||
|
||
## Roadmap | ||
|
||
[ ] Write tests for all components, actions, reducers | ||
[ ] Create site fields functionality and attach to content types | ||
[ ] Create default content types (pages, posts) on init | ||
[ ] Enforce uniqueness of slugs | ||
[ ] Create content functionality | ||
[ ] Add meta data to content types: date created, date modified, author | ||
[ ] Add media functionality - upload, simple image editing | ||
[ ] Allow upload of image for splash screen or solid color | ||
[ ] More robust user authentication with invite links, etc | ||
[ ] Look into using Hooks | ||
[ ] Build a REST API with Express to handle all CRUD actions |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import uuid from "uuid"; | ||
import database from "../firebase/firebase"; | ||
|
||
// ADD_CONTENT_TYPE | ||
export const addContentType = contentType => ({ | ||
type: "ADD_CONTENT_TYPE", | ||
contentType | ||
}); | ||
|
||
export const startAddContentType = (contentTypeData = {}) => { | ||
return (dispatch, getState) => { | ||
const { title = "", slug = "" } = contentTypeData; | ||
const contentType = { title, slug }; | ||
|
||
return database | ||
.ref(`content_types`) | ||
.push(contentType) | ||
.then(ref => { | ||
dispatch( | ||
addContentType({ | ||
id: ref.key, | ||
...contentType | ||
}) | ||
); | ||
}); | ||
}; | ||
}; | ||
|
||
// REMOVE_CONTENT_TYPE | ||
export const removeContentType = ({ id } = {}) => ({ | ||
type: "REMOVE_CONTENT_TYPE", | ||
id | ||
}); | ||
|
||
export const startRemoveContentType = ({ id } = {}) => { | ||
return (dispatch, getState) => { | ||
return database | ||
.ref(`content_types/${id}`) | ||
.remove() | ||
.then(() => { | ||
dispatch(removeContentType({ id })); | ||
}); | ||
}; | ||
}; | ||
|
||
// EDIT_CONTENT_TYPE | ||
export const editContentType = (id, updates) => ({ | ||
type: "EDIT_CONTENT_TYPE", | ||
id, | ||
updates | ||
}); | ||
|
||
export const startEditContentType = (id, updates) => { | ||
return (dispatch, getState) => { | ||
return database | ||
.ref(`content_types/${id}`) | ||
.update(updates) | ||
.then(() => { | ||
dispatch(editContentType(id, updates)); | ||
}); | ||
}; | ||
}; | ||
|
||
// SET_CONTENT_TYPES | ||
export const setContentTypes = contentTypes => ({ | ||
type: "SET_CONTENT_TYPES", | ||
contentTypes | ||
}); | ||
|
||
export const startSetContentTypes = () => { | ||
return (dispatch, getState) => { | ||
return database | ||
.ref(`content_types`) | ||
.once("value") | ||
.then(snapshot => { | ||
const contentTypes = []; | ||
snapshot.forEach(childSnapshot => { | ||
contentTypes.push({ | ||
id: childSnapshot.key, | ||
...childSnapshot.val() | ||
}); | ||
}); | ||
|
||
dispatch(setContentTypes(contentTypes)); | ||
}); | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import React from "react"; | ||
import { connect } from "react-redux"; | ||
import ContentTypeForm from "./ContentTypeForm.js"; | ||
import { startAddContentType } from "../actions/contentTypes"; | ||
|
||
export class AddContentTypePage extends React.Component { | ||
onSubmit = contentType => { | ||
this.props.startAddContentType(contentType); | ||
this.props.history.push("/content-types"); | ||
}; | ||
render() { | ||
return ( | ||
<div> | ||
<div className="page-header"> | ||
<div className="content-container"> | ||
<h1 className="page-header__title">Add Content Type</h1> | ||
</div> | ||
</div> | ||
<div className="content-container content-container--centered"> | ||
<ContentTypeForm onSubmit={this.onSubmit} /> | ||
</div> | ||
</div> | ||
); | ||
} | ||
} | ||
|
||
const mapDispatchToProps = dispatch => ({ | ||
startAddContentType: contentType => dispatch(startAddContentType(contentType)) | ||
}); | ||
|
||
export default connect( | ||
undefined, | ||
mapDispatchToProps | ||
)(AddContentTypePage); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import React from "react"; | ||
import { connect } from "react-redux"; | ||
import { Link } from "react-router-dom"; | ||
// import ContentList from "./ContentList"; | ||
|
||
export class ContentPage extends React.Component { | ||
render() { | ||
return ( | ||
<div> | ||
<div className="page-header"> | ||
<div className="content-container"> | ||
<h1 className="page-header__title"> | ||
{this.props.contentType.title} | ||
</h1> | ||
<div className="page-header__actions"> | ||
<Link | ||
className="button" | ||
to={`/content/${this.props.contentType.slug}/add`} | ||
> | ||
Add {this.props.contentType.title} | ||
</Link> | ||
</div> | ||
</div> | ||
</div> | ||
<div className="content-container">{/* <ContentList /> */}</div> | ||
</div> | ||
); | ||
} | ||
} | ||
|
||
const mapStateToProps = (state, props) => { | ||
return { | ||
contentType: state.contentTypes.find( | ||
contentType => contentType.slug === props.match.params.slug | ||
) | ||
}; | ||
}; | ||
|
||
export default connect(mapStateToProps)(ContentPage); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import React from "react"; | ||
|
||
export default class ContentTypeForm extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
|
||
this.state = { | ||
title: props.contentType ? props.contentType.title : "", | ||
slug: props.contentType ? props.contentType.slug : "", | ||
error: "" | ||
}; | ||
} | ||
useSlugify = string => { | ||
const a = "àáäâãåèéëêìíïîòóöôùúüûñçßÿœæŕśńṕẃǵǹḿǘẍźḧ·/_,:;"; | ||
const b = "aaaaaaeeeeiiiioooouuuuncsyoarsnpwgnmuxzh------"; | ||
const p = new RegExp(a.split("").join("|"), "g"); | ||
return string | ||
.toString() | ||
.toLowerCase() | ||
.replace(/\s+/g, "-") // Replace spaces with | ||
.replace(p, c => b.charAt(a.indexOf(c))) // Replace special characters | ||
.replace(/&/g, "-and-") // Replace & with ‘and’ | ||
.replace(/[^\w\-]+/g, "") // Remove all non-word characters | ||
.replace(/\-\-+/g, "-") // Replace multiple — with single - | ||
.replace(/^-+/, ""); // Trim — from start of text .replace(/-+$/, '') // Trim — from end of text | ||
}; | ||
onTitleChange = e => { | ||
const title = e.target.value; | ||
const slug = this.useSlugify(title); | ||
this.setState(() => ({ | ||
title, | ||
slug | ||
})); | ||
}; | ||
onSlugChange = e => { | ||
const slug = e.target.value; | ||
this.setState(() => ({ | ||
slug | ||
})); | ||
}; | ||
onSubmit = e => { | ||
e.preventDefault(); | ||
// TO DO: Check that slug is unique in db | ||
if (!this.state.title || !this.state.slug) { | ||
const error = "Please provide title and slug"; | ||
const success = ""; | ||
this.setState(() => ({ error, success })); | ||
} else { | ||
const error = ""; | ||
const success = "Content type saved successfully."; | ||
this.setState(() => ({ error, success })); | ||
this.props.onSubmit({ | ||
title: this.state.title, | ||
slug: this.state.slug | ||
}); | ||
} | ||
}; | ||
render() { | ||
return ( | ||
<form className="form" onSubmit={this.onSubmit}> | ||
{this.state.error && <p className="form__error">{this.state.error}</p>} | ||
{this.state.success && ( | ||
<p className="form__success">{this.state.success}</p> | ||
)} | ||
<input | ||
className="text-input" | ||
type="text" | ||
placeholder="Title" | ||
autoFocus | ||
value={this.state.title} | ||
onChange={this.onTitleChange} | ||
/> | ||
<input | ||
className="text-input" | ||
type="text" | ||
placeholder="Slug" | ||
value={this.state.slug} | ||
onChange={this.onSlugChange} | ||
/> | ||
<div> | ||
<button className="button">Save Content Type</button> | ||
</div> | ||
</form> | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import React from "react"; | ||
import { Link } from "react-router-dom"; | ||
|
||
const ContentTypeListItem = ({ id, title, slug }) => ( | ||
<Link className="list-item" to={`/content-types/edit/${id}`}> | ||
<div> | ||
<h3 className="list-item__title">{title}</h3> | ||
<span className="list-item__sub-title">{slug}</span> | ||
</div> | ||
{/* <h3 className="list-item__data">{slug}</h3> */} | ||
</Link> | ||
); | ||
|
||
export default ContentTypeListItem; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import React from "react"; | ||
import { connect } from "react-redux"; | ||
import ContentTypeListItem from "./ContentTypeListItem"; | ||
import selectContentTypes from "../selectors/contentTypes"; | ||
|
||
export const ContentTypesList = props => ( | ||
<div> | ||
<div className="list-header"> | ||
<div className="show-for-mobile">Content Types</div> | ||
<div className="show-for-desktop">Title</div> | ||
{/* <div className="show-for-desktop">Slug</div> */} | ||
</div> | ||
<div className="list-body"> | ||
{props.contentTypes.length === 0 ? ( | ||
<div className="list-item list-item--message"> | ||
<span>No content types</span> | ||
</div> | ||
) : ( | ||
props.contentTypes.map(contentType => { | ||
return <ContentTypeListItem {...contentType} key={contentType.id} />; | ||
}) | ||
)} | ||
</div> | ||
</div> | ||
); | ||
|
||
const mapStateToProps = state => { | ||
return { | ||
contentTypes: selectContentTypes(state.contentTypes) | ||
}; | ||
}; | ||
|
||
export default connect(mapStateToProps)(ContentTypesList); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import React from "react"; | ||
import { Link } from "react-router-dom"; | ||
import ContentTypesList from "./ContentTypesList"; | ||
|
||
const ContentTypesPage = () => ( | ||
<div> | ||
<div className="page-header"> | ||
<div className="content-container"> | ||
<h1 className="page-header__title">Content Types</h1> | ||
<div className="page-header__actions"> | ||
<Link className="button" to="/content-types/add"> | ||
Add Content Type | ||
</Link> | ||
</div> | ||
</div> | ||
</div> | ||
<div className="content-container"> | ||
<ContentTypesList /> | ||
</div> | ||
</div> | ||
); | ||
|
||
export default ContentTypesPage; |
Oops, something went wrong.