mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-01-27 20:23:08 +00:00
Compare commits
98 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20b719d0de | ||
|
|
8b04cc9269 | ||
|
|
96466211c7 | ||
|
|
34741291c7 | ||
|
|
fcb0cd8ee7 | ||
|
|
aafac16af2 | ||
|
|
911d1d4f9c | ||
|
|
2cd7b44e12 | ||
|
|
bfccd1d9e4 | ||
|
|
bf1bf6c191 | ||
|
|
cc5cb677a1 | ||
|
|
2dcd7101f3 | ||
|
|
f4e7e46a04 | ||
|
|
8b3b7cb5aa | ||
|
|
77081b39b4 | ||
|
|
a06236e3ff | ||
|
|
c8585775be | ||
|
|
439cdfa1ea | ||
|
|
4c36f254c4 | ||
|
|
b6815593fd | ||
|
|
84054d1aae | ||
|
|
24aec1c649 | ||
|
|
8caae18a12 | ||
|
|
3532d75365 | ||
|
|
ea81bb5ebc | ||
|
|
8d217f8785 | ||
|
|
d35db1f702 | ||
|
|
f6b058f3c9 | ||
|
|
5ab7c29b9d | ||
|
|
c5ecb9d57d | ||
|
|
d0c473878a | ||
|
|
796df9a1ac | ||
|
|
9e8e403195 | ||
|
|
a369871a06 | ||
|
|
f2f45f3657 | ||
|
|
e86ce5cf06 | ||
|
|
8d73ff6833 | ||
|
|
c4397d34f8 | ||
|
|
66c0c96a4f | ||
|
|
838b64c589 | ||
|
|
730dde730c | ||
|
|
d867aa7ce1 | ||
|
|
761597e71f | ||
|
|
4bde5fcbf8 | ||
|
|
ff0aa56ddc | ||
|
|
74f92f3e44 | ||
|
|
84285f7359 | ||
|
|
ec0de7a408 | ||
|
|
9ea99236ff | ||
|
|
f806328e75 | ||
|
|
15ac397b63 | ||
|
|
b8105eb147 | ||
|
|
31cbd9ef40 | ||
|
|
eaab6de691 | ||
|
|
d417c76c56 | ||
|
|
2f15cc5611 | ||
|
|
eb08172fb1 | ||
|
|
0cc87a4f0f | ||
|
|
004dc79eb2 | ||
|
|
a8a70c2d70 | ||
|
|
825c259fba | ||
|
|
cbbb7292d9 | ||
|
|
9519a0b4e4 | ||
|
|
9dd16b6dd5 | ||
|
|
d693301c37 | ||
|
|
fd5d142c16 | ||
|
|
ee63d2d857 | ||
|
|
7c3946fb03 | ||
|
|
3e69e8c1aa | ||
|
|
1a0bc1952c | ||
|
|
7e2c3381ae | ||
|
|
4f4ef908e0 | ||
|
|
3fe2360d92 | ||
|
|
13a2a7efd2 | ||
|
|
073fb73bde | ||
|
|
847615ef8e | ||
|
|
3583c2e776 | ||
|
|
2a753ccc7c | ||
|
|
55c529473a | ||
|
|
164f646e08 | ||
|
|
6f4962926c | ||
|
|
f18a181e2e | ||
|
|
c4bff6afa0 | ||
|
|
63e8a0d9b7 | ||
|
|
ce3fda683b | ||
|
|
9594b73b0d | ||
|
|
78ad4bea09 | ||
|
|
ed1b5252be | ||
|
|
bf27250990 | ||
|
|
bab11d692e | ||
|
|
3350b04f64 | ||
|
|
5ebba25183 | ||
|
|
8f77ac9e56 | ||
|
|
3f728e7993 | ||
|
|
3f22572f98 | ||
|
|
a52f628fdf | ||
|
|
fe63133d7c | ||
|
|
3247cab214 |
7
.bithoundrc
Normal file
7
.bithoundrc
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"unused-ignores": [
|
||||||
|
"react-dom"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/node:8.9
|
- image: circleci/node:8.9
|
||||||
- image: circleci/mongo:3.4.4
|
- image: circleci/mongo:3.4-jessie
|
||||||
|
|
||||||
working_directory: ~/repo
|
working_directory: ~/repo
|
||||||
|
|
||||||
|
|||||||
6
.dockerignore
Normal file
6
.dockerignore
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
node_modules
|
||||||
|
npm-debug.log
|
||||||
|
.git
|
||||||
|
Dockerfile
|
||||||
|
docker-compose.yml
|
||||||
|
tests
|
||||||
@@ -44,7 +44,6 @@ module.exports = {
|
|||||||
'arrow-parens' : ['warn', 'always'],
|
'arrow-parens' : ['warn', 'always'],
|
||||||
'brace-style' : ['warn', '1tbs', { allowSingleLine: true }],
|
'brace-style' : ['warn', '1tbs', { allowSingleLine: true }],
|
||||||
'jsx-quotes' : ['warn', 'prefer-single'],
|
'jsx-quotes' : ['warn', 'prefer-single'],
|
||||||
'linebreak-style' : ['warn', 'unix'],
|
|
||||||
'no-var' : 'warn',
|
'no-var' : 'warn',
|
||||||
'prefer-const' : 'warn',
|
'prefer-const' : 'warn',
|
||||||
'prefer-template' : 'warn',
|
'prefer-template' : 'warn',
|
||||||
|
|||||||
14
Dockerfile
Normal file
14
Dockerfile
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
FROM node:8
|
||||||
|
|
||||||
|
# Create app directory
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
# Bundle app source
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
ENV NODE_ENV=docker
|
||||||
|
|
||||||
|
RUN yarn
|
||||||
|
|
||||||
|
EXPOSE 8000
|
||||||
|
CMD [ "yarn", "start" ]
|
||||||
14
README.md
14
README.md
@@ -1,13 +1,13 @@
|
|||||||
# The Homebrewery
|
# The Homebrewery
|
||||||
The Homebrewery is a tool for making authnetic looking [D&D content](http://dnd.wizards.com/products/tabletop-games/rpg-products/rpg_playershandbook) using only [Markdown](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet). Check it out [here](http://homebrewery.naturalcrit.com).
|
The Homebrewery is a tool for making authentic looking [D&D content](http://dnd.wizards.com/products/tabletop-games/rpg-products/rpg_playershandbook) using only [Markdown](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet). Check it out [here](http://homebrewery.naturalcrit.com).
|
||||||
|
|
||||||
|
|
||||||
### issues, suggestions, bugs
|
### issues, suggestions, bugs
|
||||||
If you run into any issues using The Homebrewery, please submit an issues [here](/issues)
|
If you run into any issues using The Homebrewery, please submit an issue [here](/issues).
|
||||||
|
|
||||||
|
|
||||||
### local dev
|
### local dev
|
||||||
Homebrewery is open source, so feel free to clone it, tinker with it, or run your own local version.
|
The Homebrewery is open source, so feel free to clone it, tinker with it, or run your own local version.
|
||||||
|
|
||||||
#### pre-reqs
|
#### pre-reqs
|
||||||
1. install [node](https://nodejs.org/en/)
|
1. install [node](https://nodejs.org/en/)
|
||||||
@@ -20,14 +20,16 @@ Homebrewery is open source, so feel free to clone it, tinker with it, or run you
|
|||||||
1. `npm start`
|
1. `npm start`
|
||||||
|
|
||||||
#### standalone PHB stylesheet
|
#### standalone PHB stylesheet
|
||||||
If you just want the stylesheet that is generated to make pages look like they are from the PLayer's Handbook, you have find it [here](https://github.com/stolksdorf/homebrewery/blob/master/phb.standalone.css)
|
If you just want the stylesheet that is generated to make pages look like they are from the Player's Handbook, you will find it [here](https://github.com/stolksdorf/homebrewery/blob/master/phb.standalone.css).
|
||||||
|
|
||||||
If you are developing locally and would like to generate your own, follow the above steps and then run `npm run phb`.
|
If you are developing locally and would like to generate your own, follow the above steps and then run `npm run phb`.
|
||||||
|
|
||||||
### changelog
|
### changelog
|
||||||
|
|
||||||
You can check out the changelog [here](https://github.com/stolksdorf/homebrewery/blob/master/changelog.md)
|
You can check out the changelog [here](https://github.com/stolksdorf/homebrewery/blob/master/changelog.md).
|
||||||
|
|
||||||
### license
|
### license
|
||||||
|
|
||||||
This project is licensed under [MIT](./license)
|
This project is licensed under [MIT](./license). Which means you are free to use The Homebrewery in any way that you want, except for claiming that you made it yourself.
|
||||||
|
|
||||||
|
If you wish to sell or in some way gain profit for what's created on this site, it's your responsibility to ensure you have the proper licenses/rights for any images or resources used.
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ const BrewLookup = createClass({
|
|||||||
return <div className='brewRow'>
|
return <div className='brewRow'>
|
||||||
<div>{brew.title}</div>
|
<div>{brew.title}</div>
|
||||||
<div>{brew.authors.join(', ')}</div>
|
<div>{brew.authors.join(', ')}</div>
|
||||||
<div><a href={`/edit/${brew.editId}`} target='_blank'>/edit/{brew.editId}</a></div>
|
<div><a href={`/edit/${brew.editId}`} target='_blank' rel='noopener noreferrer'>/edit/{brew.editId}</a></div>
|
||||||
<div><a href={`/share/${brew.shareId}`} target='_blank'>/share/{brew.shareId}</a></div>
|
<div><a href={`/share/${brew.shareId}`} target='_blank' rel='noopener noreferrer'>/share/{brew.shareId}</a></div>
|
||||||
<div>{Moment(brew.updatedAt).fromNow()}</div>
|
<div>{Moment(brew.updatedAt).fromNow()}</div>
|
||||||
<div>{brew.views}</div>
|
<div>{brew.views}</div>
|
||||||
</div>;
|
</div>;
|
||||||
|
|||||||
@@ -17,16 +17,11 @@ const BrewSearch = createClass({
|
|||||||
return {
|
return {
|
||||||
searchTerm : '',
|
searchTerm : '',
|
||||||
brew : null,
|
brew : null,
|
||||||
searching : false
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
search : function(){
|
search : function(){
|
||||||
this.setState({
|
|
||||||
searching : true
|
|
||||||
});
|
|
||||||
|
|
||||||
request.get(`/homebrew/api/search?id=${this.state.searchTerm}`)
|
request.get(`/homebrew/api/search?id=${this.state.searchTerm}`)
|
||||||
.query({
|
.query({
|
||||||
admin_key : this.props.admin_key,
|
admin_key : this.props.admin_key,
|
||||||
@@ -35,8 +30,6 @@ const BrewSearch = createClass({
|
|||||||
console.log(err, res, res.body.brews[0]);
|
console.log(err, res, res.body.brews[0]);
|
||||||
this.setState({
|
this.setState({
|
||||||
brew : res.body.brews[0],
|
brew : res.body.brews[0],
|
||||||
|
|
||||||
searching : false
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ const HomebrewAdmin = createClass({
|
|||||||
count : 20,
|
count : 20,
|
||||||
brewCache : {},
|
brewCache : {},
|
||||||
total : 0,
|
total : 0,
|
||||||
|
|
||||||
processingOldBrews : false
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -38,9 +36,10 @@ const HomebrewAdmin = createClass({
|
|||||||
})
|
})
|
||||||
.end((err, res)=>{
|
.end((err, res)=>{
|
||||||
if(err || !res.body || !res.body.brews) return;
|
if(err || !res.body || !res.body.brews) return;
|
||||||
this.state.brewCache[page] = res.body.brews;
|
const newCache = _.extend({}, this.state.brewCache);
|
||||||
|
newCache[page] = res.body.brews;
|
||||||
this.setState({
|
this.setState({
|
||||||
brewCache : this.state.brewCache,
|
brewCache : newCache,
|
||||||
total : res.body.total,
|
total : res.body.total,
|
||||||
count : res.body.count
|
count : res.body.count
|
||||||
});
|
});
|
||||||
@@ -106,8 +105,8 @@ const HomebrewAdmin = createClass({
|
|||||||
const brews = this.state.brewCache[this.state.page] || _.times(this.state.count);
|
const brews = this.state.brewCache[this.state.page] || _.times(this.state.count);
|
||||||
return _.map(brews, (brew)=>{
|
return _.map(brews, (brew)=>{
|
||||||
return <tr className={cx('brewRow', { 'isEmpty': brew.text == 'false' })} key={brew.shareId || brew}>
|
return <tr className={cx('brewRow', { 'isEmpty': brew.text == 'false' })} key={brew.shareId || brew}>
|
||||||
<td><a href={`/edit/${brew.editId}`} target='_blank'>{brew.editId}</a></td>
|
<td><a href={`/edit/${brew.editId}`} target='_blank' rel='noopener noreferrer'>{brew.editId}</a></td>
|
||||||
<td><a href={`/share/${brew.shareId}`} target='_blank'>{brew.shareId}</a></td>
|
<td><a href={`/share/${brew.shareId}`} target='_blank' rel='noopener noreferrer'>{brew.shareId}</a></td>
|
||||||
<td>{Moment(brew.createdAt).fromNow()}</td>
|
<td>{Moment(brew.createdAt).fromNow()}</td>
|
||||||
<td>{Moment(brew.updatedAt).fromNow()}</td>
|
<td>{Moment(brew.updatedAt).fromNow()}</td>
|
||||||
<td>{Moment(brew.lastViewed).fromNow()}</td>
|
<td>{Moment(brew.lastViewed).fromNow()}</td>
|
||||||
|
|||||||
@@ -27,16 +27,11 @@ const BrewRenderer = createClass({
|
|||||||
height : 0,
|
height : 0,
|
||||||
isMounted : false,
|
isMounted : false,
|
||||||
|
|
||||||
usePPR : true,
|
|
||||||
|
|
||||||
pages : pages,
|
pages : pages,
|
||||||
usePPR : pages.length >= PPR_THRESHOLD,
|
usePPR : pages.length >= PPR_THRESHOLD,
|
||||||
|
|
||||||
errors : []
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
height : 0,
|
height : 0,
|
||||||
pageHeight : PAGE_HEIGHT,
|
|
||||||
lastRender : <div></div>,
|
lastRender : <div></div>,
|
||||||
|
|
||||||
componentDidMount : function() {
|
componentDidMount : function() {
|
||||||
@@ -48,8 +43,6 @@ const BrewRenderer = createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
componentWillReceiveProps : function(nextProps) {
|
componentWillReceiveProps : function(nextProps) {
|
||||||
if(this.refs.pages && this.refs.pages.firstChild) this.pageHeight = this.refs.pages.firstChild.clientHeight;
|
|
||||||
|
|
||||||
const pages = nextProps.text.split('\\page');
|
const pages = nextProps.text.split('\\page');
|
||||||
this.setState({
|
this.setState({
|
||||||
pages : pages,
|
pages : pages,
|
||||||
@@ -58,10 +51,6 @@ const BrewRenderer = createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
updateSize : function() {
|
updateSize : function() {
|
||||||
setTimeout(()=>{
|
|
||||||
if(this.refs.pages && this.refs.pages.firstChild) this.pageHeight = this.refs.pages.firstChild.clientHeight;
|
|
||||||
}, 1);
|
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
height : this.refs.main.parentNode.clientHeight,
|
height : this.refs.main.parentNode.clientHeight,
|
||||||
isMounted : true
|
isMounted : true
|
||||||
@@ -69,9 +58,10 @@ const BrewRenderer = createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleScroll : function(e){
|
handleScroll : function(e){
|
||||||
this.setState({
|
const target = e.target;
|
||||||
viewablePageNumber : Math.floor(e.target.scrollTop / this.pageHeight)
|
this.setState((prevState)=>({
|
||||||
});
|
viewablePageNumber : Math.floor(target.scrollTop / target.scrollHeight * prevState.pages.length)
|
||||||
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
shouldRender : function(pageText, index){
|
shouldRender : function(pageText, index){
|
||||||
@@ -134,7 +124,9 @@ const BrewRenderer = createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
render : function(){
|
render : function(){
|
||||||
return <div className='brewRenderer'
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<div className='brewRenderer'
|
||||||
onScroll={this.handleScroll}
|
onScroll={this.handleScroll}
|
||||||
ref='main'
|
ref='main'
|
||||||
style={{ height: this.state.height }}>
|
style={{ height: this.state.height }}>
|
||||||
@@ -145,9 +137,11 @@ const BrewRenderer = createClass({
|
|||||||
<div className='pages' ref='pages'>
|
<div className='pages' ref='pages'>
|
||||||
{this.renderPages()}
|
{this.renderPages()}
|
||||||
</div>
|
</div>
|
||||||
|
</div>;
|
||||||
{this.renderPageInfo()}
|
{this.renderPageInfo()}
|
||||||
{this.renderPPRmsg()}
|
{this.renderPPRmsg()}
|
||||||
</div>;
|
</React.Fragment>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -4,29 +4,8 @@
|
|||||||
position : relative;
|
position : relative;
|
||||||
}
|
}
|
||||||
.brewRenderer{
|
.brewRenderer{
|
||||||
|
will-change : transform;
|
||||||
overflow-y : scroll;
|
overflow-y : scroll;
|
||||||
.pageInfo{
|
|
||||||
position : absolute;
|
|
||||||
right : 17px;
|
|
||||||
bottom : 0;
|
|
||||||
z-index : 1000;
|
|
||||||
padding : 8px 10px;
|
|
||||||
background-color : #333;
|
|
||||||
font-size : 10px;
|
|
||||||
font-weight : 800;
|
|
||||||
color : white;
|
|
||||||
}
|
|
||||||
.ppr_msg{
|
|
||||||
position : absolute;
|
|
||||||
left : 0px;
|
|
||||||
bottom : 0;
|
|
||||||
z-index : 1000;
|
|
||||||
padding : 8px 10px;
|
|
||||||
background-color : #333;
|
|
||||||
font-size : 10px;
|
|
||||||
font-weight : 800;
|
|
||||||
color : white;
|
|
||||||
}
|
|
||||||
.pages{
|
.pages{
|
||||||
margin : 30px 0px;
|
margin : 30px 0px;
|
||||||
&>.phb{
|
&>.phb{
|
||||||
@@ -37,3 +16,25 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.pageInfo{
|
||||||
|
position : absolute;
|
||||||
|
right : 17px;
|
||||||
|
bottom : 0;
|
||||||
|
z-index : 1000;
|
||||||
|
padding : 8px 10px;
|
||||||
|
background-color : #333;
|
||||||
|
font-size : 10px;
|
||||||
|
font-weight : 800;
|
||||||
|
color : white;
|
||||||
|
}
|
||||||
|
.ppr_msg{
|
||||||
|
position : absolute;
|
||||||
|
left : 0px;
|
||||||
|
bottom : 0;
|
||||||
|
z-index : 1000;
|
||||||
|
padding : 8px 10px;
|
||||||
|
background-color : #333;
|
||||||
|
font-size : 10px;
|
||||||
|
font-weight : 800;
|
||||||
|
color : white;
|
||||||
|
}
|
||||||
@@ -68,7 +68,7 @@ const MetadataEditor = createClass({
|
|||||||
<input
|
<input
|
||||||
type='checkbox'
|
type='checkbox'
|
||||||
checked={_.includes(this.props.metadata.systems, val)}
|
checked={_.includes(this.props.metadata.systems, val)}
|
||||||
onChange={()=>this.handleSystem(val)} />
|
onChange={(e)=>this.handleSystem(val, e)} />
|
||||||
{val}
|
{val}
|
||||||
</label>;
|
</label>;
|
||||||
});
|
});
|
||||||
@@ -118,7 +118,7 @@ const MetadataEditor = createClass({
|
|||||||
return <div className='field reddit'>
|
return <div className='field reddit'>
|
||||||
<label>reddit</label>
|
<label>reddit</label>
|
||||||
<div className='value'>
|
<div className='value'>
|
||||||
<a href={this.getRedditLink()} target='_blank'>
|
<a href={this.getRedditLink()} target='_blank' rel='noopener noreferrer'>
|
||||||
<button className='publish'>
|
<button className='publish'>
|
||||||
<i className='fa fa-reddit-alien' /> share to reddit
|
<i className='fa fa-reddit-alien' /> share to reddit
|
||||||
</button>
|
</button>
|
||||||
@@ -133,18 +133,18 @@ const MetadataEditor = createClass({
|
|||||||
<label>title</label>
|
<label>title</label>
|
||||||
<input type='text' className='value'
|
<input type='text' className='value'
|
||||||
value={this.props.metadata.title}
|
value={this.props.metadata.title}
|
||||||
onChange={()=>this.handleFieldChange('title')} />
|
onChange={(e)=>this.handleFieldChange('title', e)} />
|
||||||
</div>
|
</div>
|
||||||
<div className='field description'>
|
<div className='field description'>
|
||||||
<label>description</label>
|
<label>description</label>
|
||||||
<textarea value={this.props.metadata.description} className='value'
|
<textarea value={this.props.metadata.description} className='value'
|
||||||
onChange={()=>this.handleFieldChange('description')} />
|
onChange={(e)=>this.handleFieldChange('description', e)} />
|
||||||
</div>
|
</div>
|
||||||
{/*}
|
{/*}
|
||||||
<div className='field tags'>
|
<div className='field tags'>
|
||||||
<label>tags</label>
|
<label>tags</label>
|
||||||
<textarea value={this.props.metadata.tags}
|
<textarea value={this.props.metadata.tags}
|
||||||
onChange={()=>this.handleFieldChange('tags')} />
|
onChange={(e)=>this.handleFieldChange('tags', e)} />
|
||||||
</div>
|
</div>
|
||||||
*/}
|
*/}
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ const Homebrew = createClass({
|
|||||||
},
|
},
|
||||||
render : function(){
|
render : function(){
|
||||||
return <div className='homebrew'>
|
return <div className='homebrew'>
|
||||||
<Router initialUrl={this.props.url}/>
|
<Router defaultUrl={this.props.url}/>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,7 +3,11 @@ const createClass = require('create-react-class');
|
|||||||
const Nav = require('naturalcrit/nav/nav.jsx');
|
const Nav = require('naturalcrit/nav/nav.jsx');
|
||||||
|
|
||||||
module.exports = function(props){
|
module.exports = function(props){
|
||||||
return <Nav.item newTab={true} href='https://www.reddit.com/r/homebrewery/submit?selftext=true&title=[Issue]' color='red' icon='fa-bug'>
|
return <Nav.item
|
||||||
|
newTab={true}
|
||||||
|
color='red'
|
||||||
|
icon='fa-bug'
|
||||||
|
href={`https://www.reddit.com/r/homebrewery/submit?selftext=true&title=${encodeURIComponent('[Issue] Describe Your Issue Here')}`} >
|
||||||
report issue
|
report issue
|
||||||
</Nav.item>;
|
</Nav.item>;
|
||||||
};
|
};
|
||||||
@@ -59,7 +59,7 @@ const BaseItem = createClass({
|
|||||||
if(!this.state.showDropdown) return null;
|
if(!this.state.showDropdown) return null;
|
||||||
|
|
||||||
const items = _.map(this.state.brews, (brew)=>{
|
const items = _.map(this.state.brews, (brew)=>{
|
||||||
return <a href={brew.url} className='item' key={brew.id} target='_blank'>
|
return <a href={brew.url} className='item' key={brew.id} target='_blank' rel='noopener noreferrer'>
|
||||||
<span className='title'>{brew.title}</span>
|
<span className='title'>{brew.title}</span>
|
||||||
<span className='time'>{Moment(brew.ts).fromNow()}</span>
|
<span className='time'>{Moment(brew.ts).fromNow()}</span>
|
||||||
</a>;
|
</a>;
|
||||||
@@ -172,7 +172,7 @@ module.exports = {
|
|||||||
|
|
||||||
const makeItems = (brews)=>{
|
const makeItems = (brews)=>{
|
||||||
return _.map(brews, (brew)=>{
|
return _.map(brews, (brew)=>{
|
||||||
return <a href={brew.url} className='item' key={brew.id} target='_blank'>
|
return <a href={brew.url} className='item' key={brew.id} target='_blank' rel='noopener noreferrer'>
|
||||||
<span className='title'>{brew.title}</span>
|
<span className='title'>{brew.title}</span>
|
||||||
<span className='time'>{Moment(brew.ts).fromNow()}</span>
|
<span className='time'>{Moment(brew.ts).fromNow()}</span>
|
||||||
</a>;
|
</a>;
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ const EditPage = createClass({
|
|||||||
isPending : false,
|
isPending : false,
|
||||||
errors : null,
|
errors : null,
|
||||||
htmlErrors : Markdown.validate(this.props.brew.text),
|
htmlErrors : Markdown.validate(this.props.brew.text),
|
||||||
lastUpdated : this.props.brew.updatedAt
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
savedBrew : null,
|
savedBrew : null,
|
||||||
@@ -62,9 +61,9 @@ const EditPage = createClass({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.setState({
|
this.setState((prevState)=>({
|
||||||
htmlErrors : Markdown.validate(this.state.brew.text)
|
htmlErrors : Markdown.validate(prevState.brew.text)
|
||||||
});
|
}));
|
||||||
|
|
||||||
document.addEventListener('keydown', this.handleControlKeys);
|
document.addEventListener('keydown', this.handleControlKeys);
|
||||||
},
|
},
|
||||||
@@ -91,12 +90,10 @@ const EditPage = createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleMetadataChange : function(metadata){
|
handleMetadataChange : function(metadata){
|
||||||
this.setState({
|
this.setState((prevState)=>({
|
||||||
brew : _.merge({}, this.state.brew, metadata),
|
brew : _.merge({}, prevState.brew, metadata),
|
||||||
isPending : true,
|
isPending : true,
|
||||||
}, ()=>{
|
}), ()=>this.trySave());
|
||||||
this.trySave();
|
|
||||||
});
|
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -106,22 +103,16 @@ const EditPage = createClass({
|
|||||||
let htmlErrors = this.state.htmlErrors;
|
let htmlErrors = this.state.htmlErrors;
|
||||||
if(htmlErrors.length) htmlErrors = Markdown.validate(text);
|
if(htmlErrors.length) htmlErrors = Markdown.validate(text);
|
||||||
|
|
||||||
this.setState({
|
this.setState((prevState)=>({
|
||||||
brew : _.merge({}, this.state.brew, { text: text }),
|
brew : _.merge({}, prevState.brew, { text: text }),
|
||||||
isPending : true,
|
isPending : true,
|
||||||
htmlErrors : htmlErrors
|
htmlErrors : htmlErrors
|
||||||
});
|
}), ()=>this.trySave());
|
||||||
|
|
||||||
this.trySave();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
hasChanges : function(){
|
hasChanges : function(){
|
||||||
if(this.savedBrew){
|
const savedBrew = this.savedBrew ? this.savedBrew : this.props.brew;
|
||||||
return !_.isEqual(this.state.brew, this.savedBrew);
|
return !_.isEqual(this.state.brew, savedBrew);
|
||||||
} else {
|
|
||||||
return !_.isEqual(this.state.brew, this.props.brew);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
trySave : function(){
|
trySave : function(){
|
||||||
@@ -136,11 +127,11 @@ const EditPage = createClass({
|
|||||||
save : function(){
|
save : function(){
|
||||||
if(this.debounceSave && this.debounceSave.cancel) this.debounceSave.cancel();
|
if(this.debounceSave && this.debounceSave.cancel) this.debounceSave.cancel();
|
||||||
|
|
||||||
this.setState({
|
this.setState((prevState)=>({
|
||||||
isSaving : true,
|
isSaving : true,
|
||||||
errors : null,
|
errors : null,
|
||||||
htmlErrors : Markdown.validate(this.state.brew.text)
|
htmlErrors : Markdown.validate(prevState.brew.text)
|
||||||
});
|
}));
|
||||||
|
|
||||||
request
|
request
|
||||||
.put(`/api/update/${this.props.brew.editId}`)
|
.put(`/api/update/${this.props.brew.editId}`)
|
||||||
@@ -155,7 +146,6 @@ const EditPage = createClass({
|
|||||||
this.setState({
|
this.setState({
|
||||||
isPending : false,
|
isPending : false,
|
||||||
isSaving : false,
|
isSaving : false,
|
||||||
lastUpdated : res.body.updatedAt
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -173,7 +163,8 @@ const EditPage = createClass({
|
|||||||
Oops!
|
Oops!
|
||||||
<div className='errorContainer'>
|
<div className='errorContainer'>
|
||||||
Looks like there was a problem saving. <br />
|
Looks like there was a problem saving. <br />
|
||||||
Report the issue <a target='_blank' href={`https://github.com/stolksdorf/naturalcrit/issues/new?body=${encodeURIComponent(errMsg)}`}>
|
Report the issue <a target='_blank' rel='noopener noreferrer'
|
||||||
|
href={`https://github.com/stolksdorf/naturalcrit/issues/new?body=${encodeURIComponent(errMsg)}`}>
|
||||||
here
|
here
|
||||||
</a>.
|
</a>.
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ If you are looking for more 5e Homebrew resources check out [r/UnearthedArcana](
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<img src='http://i.imgur.com/hMna6G0.png' style='position:absolute;bottom:50px;right:30px;width:280px' />
|
<img src='https://i.imgur.com/hMna6G0.png' style='position:absolute;bottom:50px;right:30px;width:280px' />
|
||||||
|
|
||||||
<div class='pageNumber'>1</div>
|
<div class='pageNumber'>1</div>
|
||||||
<div class='footnote'>PART 1 | FANCINESS</div>
|
<div class='footnote'>PART 1 | FANCINESS</div>
|
||||||
|
|||||||
@@ -22,7 +22,9 @@ const PrintPage = createClass({
|
|||||||
|
|
||||||
componentDidMount : function() {
|
componentDidMount : function() {
|
||||||
if(this.props.query.local){
|
if(this.props.query.local){
|
||||||
this.setState({ brewText: localStorage.getItem(this.props.query.local) });
|
this.setState((prevState, prevProps)=>({
|
||||||
|
brewText : localStorage.getItem(prevProps.query.local)
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.props.query.dialog) window.print();
|
if(this.props.query.dialog) window.print();
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ const BrewItem = createClass({
|
|||||||
renderEditLink : function(){
|
renderEditLink : function(){
|
||||||
if(!this.props.brew.editId) return;
|
if(!this.props.brew.editId) return;
|
||||||
|
|
||||||
return <a href={`/edit/${this.props.brew.editId}`} target='_blank'>
|
return <a href={`/edit/${this.props.brew.editId}`} target='_blank' rel='noopener noreferrer'>
|
||||||
<i className='fa fa-pencil' />
|
<i className='fa fa-pencil' />
|
||||||
</a>;
|
</a>;
|
||||||
},
|
},
|
||||||
@@ -63,7 +63,7 @@ const BrewItem = createClass({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='links'>
|
<div className='links'>
|
||||||
<a href={`/share/${brew.shareId}`} target='_blank'>
|
<a href={`/share/${brew.shareId}`} target='_blank' rel='noopener noreferrer'>
|
||||||
<i className='fa fa-share-alt' />
|
<i className='fa fa-share-alt' />
|
||||||
</a>
|
</a>
|
||||||
{this.renderEditLink()}
|
{this.renderEditLink()}
|
||||||
|
|||||||
@@ -156,6 +156,7 @@ body {
|
|||||||
margin-bottom : 1em;
|
margin-bottom : 1em;
|
||||||
font-size : 10pt;
|
font-size : 10pt;
|
||||||
thead{
|
thead{
|
||||||
|
display: table-row-group;
|
||||||
font-weight : 800;
|
font-weight : 800;
|
||||||
th{
|
th{
|
||||||
vertical-align : bottom;
|
vertical-align : bottom;
|
||||||
@@ -337,7 +338,8 @@ body {
|
|||||||
p,blockquote,table{
|
p,blockquote,table{
|
||||||
z-index : 15;
|
z-index : 15;
|
||||||
-webkit-column-break-inside : avoid;
|
-webkit-column-break-inside : avoid;
|
||||||
column-break-inside : avoid;
|
page-break-inside : avoid;
|
||||||
|
break-inside : avoid;
|
||||||
overflow: hidden; /* Firefox fix */
|
overflow: hidden; /* Firefox fix */
|
||||||
}
|
}
|
||||||
//Better spacing for spell blocks
|
//Better spacing for spell blocks
|
||||||
@@ -355,7 +357,8 @@ body {
|
|||||||
}
|
}
|
||||||
li{
|
li{
|
||||||
-webkit-column-break-inside : avoid;
|
-webkit-column-break-inside : avoid;
|
||||||
column-break-inside : avoid;
|
page-break-inside : avoid;
|
||||||
|
break-inside : avoid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//*****************************
|
//*****************************
|
||||||
@@ -380,7 +383,8 @@ body {
|
|||||||
text-indent : -1em;
|
text-indent : -1em;
|
||||||
list-style-type : none;
|
list-style-type : none;
|
||||||
-webkit-column-break-inside : auto;
|
-webkit-column-break-inside : auto;
|
||||||
column-break-inside : auto;
|
page-break-inside : auto;
|
||||||
|
break-inside : auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//*****************************
|
//*****************************
|
||||||
@@ -449,7 +453,8 @@ body {
|
|||||||
// *****************************/
|
// *****************************/
|
||||||
.phb .toc{
|
.phb .toc{
|
||||||
-webkit-column-break-inside : avoid;
|
-webkit-column-break-inside : avoid;
|
||||||
column-break-inside : avoid;
|
page-break-inside : avoid;
|
||||||
|
break-inside : avoid;
|
||||||
a{
|
a{
|
||||||
color : black;
|
color : black;
|
||||||
text-decoration : none;
|
text-decoration : none;
|
||||||
|
|||||||
17
docker-compose.yml
Normal file
17
docker-compose.yml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
version: '2'
|
||||||
|
services:
|
||||||
|
mongodb:
|
||||||
|
image: mongo:latest
|
||||||
|
volumes:
|
||||||
|
- mongodata:/data/db
|
||||||
|
homebrewery:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
image: homebrewery
|
||||||
|
environment:
|
||||||
|
MONGODB_URI: mongodb://mongodb/homebrewery
|
||||||
|
ports:
|
||||||
|
- "8000:8000"
|
||||||
|
volumes:
|
||||||
|
mongodata:
|
||||||
118
package-lock.json
generated
118
package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "homebrewery",
|
"name": "homebrewery",
|
||||||
"version": "2.7.5",
|
"version": "2.8.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -1067,9 +1067,12 @@
|
|||||||
"integrity": "sha512-MsAhsUW1GxCdgYSO6tAfZrNapmUKk7mWx/k5mFY/A1gBtkaCaNapTg+FExCw1r9yeaZhqx/xPg43xgTFH6KL5w=="
|
"integrity": "sha512-MsAhsUW1GxCdgYSO6tAfZrNapmUKk7mWx/k5mFY/A1gBtkaCaNapTg+FExCw1r9yeaZhqx/xPg43xgTFH6KL5w=="
|
||||||
},
|
},
|
||||||
"basic-auth": {
|
"basic-auth": {
|
||||||
"version": "1.1.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.0.tgz",
|
||||||
"integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ="
|
"integrity": "sha1-AV2z81PgLlY3d1X5YnQuiYHnu7o=",
|
||||||
|
"requires": {
|
||||||
|
"safe-buffer": "5.1.1"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"bcrypt-pbkdf": {
|
"bcrypt-pbkdf": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
@@ -2231,11 +2234,6 @@
|
|||||||
"is-symbol": "1.0.1"
|
"is-symbol": "1.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"es6-promise": {
|
|
||||||
"version": "3.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz",
|
|
||||||
"integrity": "sha1-7FYjOGgDKQkgcXDDlEjiREndH8Q="
|
|
||||||
},
|
|
||||||
"escape-html": {
|
"escape-html": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||||
@@ -3863,11 +3861,6 @@
|
|||||||
"os-tmpdir": "1.0.2"
|
"os-tmpdir": "1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"hooks-fixed": {
|
|
||||||
"version": "2.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/hooks-fixed/-/hooks-fixed-2.0.2.tgz",
|
|
||||||
"integrity": "sha512-YurCM4gQSetcrhwEtpQHhQ4M7Zo7poNGqY4kQGeBS6eZtOcT3tnNs01ThFa0jYBByAiYt1MjMjP/YApG0EnAvQ=="
|
|
||||||
},
|
|
||||||
"htmlescape": {
|
"htmlescape": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz",
|
||||||
@@ -4514,9 +4507,9 @@
|
|||||||
"integrity": "sha1-eeoBiRth3mto4T5nwLS1vak3spQ="
|
"integrity": "sha1-eeoBiRth3mto4T5nwLS1vak3spQ="
|
||||||
},
|
},
|
||||||
"kareem": {
|
"kareem": {
|
||||||
"version": "1.5.0",
|
"version": "2.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/kareem/-/kareem-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.0.6.tgz",
|
||||||
"integrity": "sha1-4+QQHZ3P3imXadr0tNtk2JXRdEg="
|
"integrity": "sha512-/C+l8gABdHsAIfNpykJNWmYodpTnDRyn+JhORkP2VgEf1GgdAc+oTHjVADwISwCJKta031EOIwY6+Hki5z8SpQ=="
|
||||||
},
|
},
|
||||||
"kind-of": {
|
"kind-of": {
|
||||||
"version": "3.2.2",
|
"version": "3.2.2",
|
||||||
@@ -4877,58 +4870,54 @@
|
|||||||
"integrity": "sha512-1muXCh8jb1N/gHRbn9VDUBr0GYb8A/aVcHlII9QSB68a50spqEVLIGN6KVmCOnSvJrUhC0edGgKU5ofnGXdYdg=="
|
"integrity": "sha512-1muXCh8jb1N/gHRbn9VDUBr0GYb8A/aVcHlII9QSB68a50spqEVLIGN6KVmCOnSvJrUhC0edGgKU5ofnGXdYdg=="
|
||||||
},
|
},
|
||||||
"mongodb": {
|
"mongodb": {
|
||||||
"version": "2.2.34",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-2.2.34.tgz",
|
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.0.4.tgz",
|
||||||
"integrity": "sha1-o09Zu+thdUrsQy3nLD/iFSakTBo=",
|
"integrity": "sha512-90YIIs7A4ko4kCGafxxXj3foexCAlJBC0YLwwIKgSLoE7Vni2IqUMz6HSsZ3zbXOfR1KWtxfnc0RyAMAY/ViLg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"es6-promise": "3.2.1",
|
"mongodb-core": "3.0.4"
|
||||||
"mongodb-core": "2.1.18",
|
|
||||||
"readable-stream": "2.2.7"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mongodb-core": {
|
"mongodb-core": {
|
||||||
"version": "2.1.18",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-2.1.18.tgz",
|
"resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-3.0.4.tgz",
|
||||||
"integrity": "sha1-TEYTm986HwMt7ZHbSfOO7AFlkFA=",
|
"integrity": "sha512-OTH267FjfwBdEufSnrgd+u8HuLWRuQ6p8DR0XirPl2BdlLEMh4XwjJf1RTlruILp5p2m1w8dDC8rCxibC3W8qQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"bson": "1.0.6",
|
"bson": "1.0.6",
|
||||||
"require_optional": "1.0.1"
|
"require_optional": "1.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mongoose": {
|
"mongoose": {
|
||||||
"version": "4.13.12",
|
"version": "5.0.13",
|
||||||
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-4.13.12.tgz",
|
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.0.13.tgz",
|
||||||
"integrity": "sha512-pH8NK5AYGbnPeEFFGs5ACk18vzzcy4DFT48U9kKvkfg6SI3nJZkzGfN7o1NDWjy+kP26hWyU/AMhYTfe5hSVnA==",
|
"integrity": "sha512-VCiutgdxwhTuNHIuUgMRWVYvv0GFw6FUi4j14B7um/Wcy1uhuwF552a6XVKUCth/AY8C+PjVU9fVGJ5K0JmrmQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"async": "2.1.4",
|
"async": "2.1.4",
|
||||||
"bson": "1.0.6",
|
"bson": "1.0.6",
|
||||||
"hooks-fixed": "2.0.2",
|
"kareem": "2.0.6",
|
||||||
"kareem": "1.5.0",
|
|
||||||
"lodash.get": "4.4.2",
|
"lodash.get": "4.4.2",
|
||||||
"mongodb": "2.2.34",
|
"mongodb": "3.0.4",
|
||||||
|
"mongoose-legacy-pluralize": "1.0.2",
|
||||||
"mpath": "0.3.0",
|
"mpath": "0.3.0",
|
||||||
"mpromise": "0.5.5",
|
"mquery": "3.0.0",
|
||||||
"mquery": "2.3.3",
|
|
||||||
"ms": "2.0.0",
|
"ms": "2.0.0",
|
||||||
"muri": "1.3.0",
|
|
||||||
"regexp-clone": "0.0.1",
|
"regexp-clone": "0.0.1",
|
||||||
"sliced": "1.0.1"
|
"sliced": "1.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"mongoose-legacy-pluralize": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ=="
|
||||||
|
},
|
||||||
"mpath": {
|
"mpath": {
|
||||||
"version": "0.3.0",
|
"version": "0.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.3.0.tgz",
|
||||||
"integrity": "sha1-elj3iem1/TyUUgY0FXlg8mvV70Q="
|
"integrity": "sha1-elj3iem1/TyUUgY0FXlg8mvV70Q="
|
||||||
},
|
},
|
||||||
"mpromise": {
|
|
||||||
"version": "0.5.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/mpromise/-/mpromise-0.5.5.tgz",
|
|
||||||
"integrity": "sha1-9bJCWddjrMIlewoMjG2Gb9UXMuY="
|
|
||||||
},
|
|
||||||
"mquery": {
|
"mquery": {
|
||||||
"version": "2.3.3",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/mquery/-/mquery-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/mquery/-/mquery-3.0.0.tgz",
|
||||||
"integrity": "sha512-NC8L14kn+qxJbbJ1gbcEMDxF0sC3sv+1cbRReXXwVvowcwY1y9KoVZFq0ebwARibsadu8lx8nWGvm3V0Pf0ZWQ==",
|
"integrity": "sha512-WL1Lk8v4l8VFSSwN3yCzY9TXw+fKVYKn6f+w86TRzOLSE8k1yTgGaLBPUByJQi8VcLbOdnUneFV/y3Kv874pnQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"bluebird": "3.5.0",
|
"bluebird": "3.5.0",
|
||||||
"debug": "2.6.9",
|
"debug": "2.6.9",
|
||||||
@@ -4948,11 +4937,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||||
},
|
},
|
||||||
"muri": {
|
|
||||||
"version": "1.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/muri/-/muri-1.3.0.tgz",
|
|
||||||
"integrity": "sha512-FiaFwKl864onHFFUV/a2szAl7X0fxVlSKNdhTf+BM8i8goEgYut8u5P9MqQqIYwvaMxjzVESsoEm/2kfkFH1rg=="
|
|
||||||
},
|
|
||||||
"mute-stream": {
|
"mute-stream": {
|
||||||
"version": "0.0.7",
|
"version": "0.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
|
||||||
@@ -5008,9 +4992,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"nconf": {
|
"nconf": {
|
||||||
"version": "0.8.5",
|
"version": "0.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/nconf/-/nconf-0.8.5.tgz",
|
"resolved": "https://registry.npmjs.org/nconf/-/nconf-0.10.0.tgz",
|
||||||
"integrity": "sha1-8pQeFWGVL6kGu7MjKM+I1MY155Q=",
|
"integrity": "sha512-fKiXMQrpP7CYWJQzKkPPx9hPgmq+YLDyxcG9N8RpiE9FoCkCbzD0NyW0YhE3xn3Aupe7nnDeIx4PFzYehpHT9Q==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"async": "1.5.2",
|
"async": "1.5.2",
|
||||||
"ini": "1.3.5",
|
"ini": "1.3.5",
|
||||||
@@ -6088,35 +6072,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pico-flux": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/pico-flux/-/pico-flux-1.1.0.tgz",
|
|
||||||
"integrity": "sha1-GgRFbQQValgtKo6Rhyxxk2WMC/s="
|
|
||||||
},
|
|
||||||
"pico-router": {
|
"pico-router": {
|
||||||
"version": "1.3.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/pico-router/-/pico-router-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/pico-router/-/pico-router-2.1.0.tgz",
|
||||||
"integrity": "sha512-VYvL+ycNF+xxqd/vZdBxEUw4KzYNF0EjpFto0lLllEoN0fRzPLoM76Wkx1iOFbNFKfmUbciV4ec+tdPOOxN3Dw==",
|
"integrity": "sha512-aUTyqGvqbRifVn3StnP7V8QBVcSfsbfpHt+neMgXKPLdxlfgD7kwHv6WzGZxwZ4u6/S6io89hftDy2k1kJHJLQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"create-react-class": "15.6.3",
|
"create-react-class": "15.6.3",
|
||||||
"lodash": "4.17.5",
|
"lodash": "4.17.5",
|
||||||
"react": "15.6.2",
|
"react": "16.3.1",
|
||||||
"url": "0.11.0",
|
"url": "0.11.0",
|
||||||
"url-pattern": "1.0.3"
|
"url-pattern": "1.0.3"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"react": {
|
|
||||||
"version": "15.6.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/react/-/react-15.6.2.tgz",
|
|
||||||
"integrity": "sha1-26BDSrQ5z+gvEI8PURZjkIF5qnI=",
|
|
||||||
"requires": {
|
|
||||||
"create-react-class": "15.6.3",
|
|
||||||
"fbjs": "0.8.16",
|
|
||||||
"loose-envify": "1.3.1",
|
|
||||||
"object-assign": "4.1.1",
|
|
||||||
"prop-types": "15.6.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pify": {
|
"pify": {
|
||||||
@@ -7219,11 +7184,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
|
||||||
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
|
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
|
||||||
},
|
},
|
||||||
"striptags": {
|
|
||||||
"version": "2.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/striptags/-/striptags-2.2.1.tgz",
|
|
||||||
"integrity": "sha1-TEULcI1BuL85zyTEn/I0/Gqr/TI="
|
|
||||||
},
|
|
||||||
"subarg": {
|
"subarg": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz",
|
||||||
|
|||||||
12
package.json
12
package.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "homebrewery",
|
"name": "homebrewery",
|
||||||
"description": "Create authentic looking D&D homebrews using only markdown",
|
"description": "Create authentic looking D&D homebrews using only markdown",
|
||||||
"version": "2.8.0",
|
"version": "2.8.1",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git://github.com/stolksdorf/homebrewery.git"
|
"url": "git://github.com/stolksdorf/homebrewery.git"
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"babel-preset-env": "^1.1.8",
|
"babel-preset-env": "^1.1.8",
|
||||||
"babel-preset-react": "^6.24.1",
|
"babel-preset-react": "^6.24.1",
|
||||||
"basic-auth": "^1.0.3",
|
"basic-auth": "^2.0.0",
|
||||||
"body-parser": "^1.14.2",
|
"body-parser": "^1.14.2",
|
||||||
"classnames": "^2.2.0",
|
"classnames": "^2.2.0",
|
||||||
"codemirror": "^5.22.0",
|
"codemirror": "^5.22.0",
|
||||||
@@ -49,14 +49,12 @@
|
|||||||
"lodash": "^4.11.2",
|
"lodash": "^4.11.2",
|
||||||
"marked": "^0.3.5",
|
"marked": "^0.3.5",
|
||||||
"moment": "^2.11.0",
|
"moment": "^2.11.0",
|
||||||
"mongoose": "^4.3.3",
|
"mongoose": "^5.0.13",
|
||||||
"nconf": "^0.8.4",
|
"nconf": "^0.10.0",
|
||||||
"pico-flux": "^1.1.0",
|
"pico-router": "^2.1.0",
|
||||||
"pico-router": "^1.1.0",
|
|
||||||
"react": "^16.3.1",
|
"react": "^16.3.1",
|
||||||
"react-dom": "^16.3.1",
|
"react-dom": "^16.3.1",
|
||||||
"shortid": "^2.2.4",
|
"shortid": "^2.2.4",
|
||||||
"striptags": "^2.1.1",
|
|
||||||
"superagent": "^3.8.2",
|
"superagent": "^3.8.2",
|
||||||
"vitreum": "^4.10.1"
|
"vitreum": "^4.10.1"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
"moment",
|
"moment",
|
||||||
"superagent",
|
"superagent",
|
||||||
"marked",
|
"marked",
|
||||||
"pico-router",
|
"pico-router"
|
||||||
"pico-flux"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
13
server.js
13
server.js
@@ -3,7 +3,7 @@ const jwt = require('jwt-simple');
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
app.use(express.static(`${__dirname}/build`));'';
|
app.use(express.static(`${__dirname}/build`));
|
||||||
app.use(require('body-parser').json({ limit: '25mb' }));
|
app.use(require('body-parser').json({ limit: '25mb' }));
|
||||||
app.use(require('cookie-parser')());
|
app.use(require('cookie-parser')());
|
||||||
|
|
||||||
@@ -14,12 +14,13 @@ const config = require('nconf')
|
|||||||
.file('defaults', { file: 'config/default.json' });
|
.file('defaults', { file: 'config/default.json' });
|
||||||
|
|
||||||
//DB
|
//DB
|
||||||
require('mongoose')
|
const mongoose = require('mongoose');
|
||||||
.connect(process.env.MONGODB_URI || process.env.MONGOLAB_URI || 'mongodb://localhost/naturalcrit')
|
mongoose.connect(config.get('mongodb_uri') || config.get('mongolab_uri') || 'mongodb://localhost/naturalcrit');
|
||||||
.connection.on('error', ()=>{
|
mongoose.connection.on('error', ()=>{
|
||||||
console.log('Error : Could not connect to a Mongo Database.');
|
console.log('Error : Could not connect to a Mongo Database.');
|
||||||
console.log(' If you are running locally, make sure mongodb.exe is running.');
|
console.log(' If you are running locally, make sure mongodb.exe is running.');
|
||||||
});
|
throw 'Can not connect to Mongo';
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
//Account MIddleware
|
//Account MIddleware
|
||||||
@@ -48,7 +49,7 @@ app.get('/source/:id', (req, res)=>{
|
|||||||
HomebrewModel.get({ shareId: req.params.id })
|
HomebrewModel.get({ shareId: req.params.id })
|
||||||
.then((brew)=>{
|
.then((brew)=>{
|
||||||
const text = brew.text.replaceAll('<', '<').replaceAll('>', '>');
|
const text = brew.text.replaceAll('<', '<').replaceAll('>', '>');
|
||||||
return res.send(`<code><pre>${text}</pre></code>`);
|
return res.send(`<code><pre style="white-space: pre-wrap;">${text}</pre></code>`);
|
||||||
})
|
})
|
||||||
.catch((err)=>{
|
.catch((err)=>{
|
||||||
console.log(err);
|
console.log(err);
|
||||||
|
|||||||
@@ -32,15 +32,6 @@ const RenderWarnings = createClass({
|
|||||||
</li>;
|
</li>;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
zoom : function(){
|
|
||||||
return false;
|
|
||||||
if(window.devicePixelRatio !== 1){
|
|
||||||
return <li key='zoom'>
|
|
||||||
<em>Your browser is zoomed. </em> <br />
|
|
||||||
This can cause content to jump columns.
|
|
||||||
</li>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
checkWarnings : function(){
|
checkWarnings : function(){
|
||||||
const hideDismiss = localStorage.getItem(DISMISS_KEY);
|
const hideDismiss = localStorage.getItem(DISMISS_KEY);
|
||||||
|
|||||||
@@ -30,7 +30,11 @@ const CodeEditor = createClass({
|
|||||||
value : this.props.value,
|
value : this.props.value,
|
||||||
lineNumbers : true,
|
lineNumbers : true,
|
||||||
lineWrapping : this.props.wrap,
|
lineWrapping : this.props.wrap,
|
||||||
mode : this.props.language
|
mode : this.props.language,
|
||||||
|
extraKeys : {
|
||||||
|
'Ctrl-B' : this.makeBold,
|
||||||
|
'Ctrl-I' : this.makeItalic
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.codeMirror.on('change', this.handleChange);
|
this.codeMirror.on('change', this.handleChange);
|
||||||
@@ -38,6 +42,16 @@ const CodeEditor = createClass({
|
|||||||
this.updateSize();
|
this.updateSize();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
makeBold : function() {
|
||||||
|
const selection = this.codeMirror.getSelection();
|
||||||
|
this.codeMirror.replaceSelection(`**${selection}**`, 'around');
|
||||||
|
},
|
||||||
|
|
||||||
|
makeItalic : function() {
|
||||||
|
const selection = this.codeMirror.getSelection();
|
||||||
|
this.codeMirror.replaceSelection(`*${selection}*`, 'around');
|
||||||
|
},
|
||||||
|
|
||||||
componentWillReceiveProps : function(nextProps){
|
componentWillReceiveProps : function(nextProps){
|
||||||
if(this.codeMirror && nextProps.value !== undefined && this.codeMirror.getValue() != nextProps.value) {
|
if(this.codeMirror && nextProps.value !== undefined && this.codeMirror.getValue() != nextProps.value) {
|
||||||
this.codeMirror.setValue(nextProps.value);
|
this.codeMirror.setValue(nextProps.value);
|
||||||
|
|||||||
@@ -13,6 +13,11 @@ renderer.html = function (html) {
|
|||||||
return html;
|
return html;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const sanatizeScriptTags = (content)=>{
|
||||||
|
return content
|
||||||
|
.replace(/<script/g, '<script')
|
||||||
|
.replace(/<\/script>/g, '</script>');
|
||||||
|
};
|
||||||
|
|
||||||
const tagTypes = ['div', 'span', 'a'];
|
const tagTypes = ['div', 'span', 'a'];
|
||||||
const tagRegex = new RegExp(`(${
|
const tagRegex = new RegExp(`(${
|
||||||
@@ -24,7 +29,10 @@ const tagRegex = new RegExp(`(${
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
marked : Markdown,
|
marked : Markdown,
|
||||||
render : (rawBrewText)=>{
|
render : (rawBrewText)=>{
|
||||||
return Markdown(rawBrewText, { renderer: renderer });
|
return Markdown(
|
||||||
|
sanatizeScriptTags(rawBrewText),
|
||||||
|
{ renderer: renderer }
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
validate : (rawBrewText)=>{
|
validate : (rawBrewText)=>{
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
flex-direction : row;
|
flex-direction : row;
|
||||||
.pane{
|
.pane{
|
||||||
overflow-x : hidden;
|
overflow-x : hidden;
|
||||||
|
overflow-y : hidden;
|
||||||
flex : 1;
|
flex : 1;
|
||||||
}
|
}
|
||||||
.divider{
|
.divider{
|
||||||
|
|||||||
Reference in New Issue
Block a user