0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2026-01-14 21:32:41 +00:00

Merge branch 'master' into pr/1198

This commit is contained in:
Trevor Buckner
2021-03-06 22:42:15 -05:00
85 changed files with 3973 additions and 1060 deletions

View File

@@ -9,6 +9,7 @@ const { Meta } = require('vitreum/headtags');
const Nav = require('naturalcrit/nav/nav.jsx');
const Navbar = require('../../navbar/navbar.jsx');
const NewBrew = require('../../navbar/newbrew.navitem.jsx');
const ReportIssue = require('../../navbar/issue.navitem.jsx');
const PrintLink = require('../../navbar/print.navitem.jsx');
const Account = require('../../navbar/account.navitem.jsx');
@@ -41,17 +42,18 @@ const EditPage = createClass({
tags : '',
published : false,
authors : [],
systems : []
systems : [],
renderer : 'legacy'
}
};
},
getInitialState : function() {
return {
brew : this.props.brew,
brew : this.props.brew,
isSaving : false,
isPending : false,
alertRenderChange : false,
saveGoogle : this.props.brew.googleId ? true : false,
confirmGoogleTransfer : false,
errors : null,
@@ -66,6 +68,8 @@ const EditPage = createClass({
url : window.location.href
});
this.savedBrew = JSON.parse(JSON.stringify(this.props.brew)); //Deep copy
this.trySave();
window.onbeforeunload = ()=>{
if(this.state.isSaving || this.state.isPending){
@@ -101,6 +105,11 @@ const EditPage = createClass({
},
handleMetadataChange : function(metadata){
if(metadata.renderer != this.savedBrew.renderer){
this.setState({
alertRenderChange : true
});
}
this.setState((prevState)=>({
brew : _.merge({}, prevState.brew, metadata),
isPending : true,
@@ -122,8 +131,7 @@ const EditPage = createClass({
},
hasChanges : function(){
const savedBrew = this.savedBrew ? this.savedBrew : this.props.brew;
return !_.isEqual(this.state.brew, savedBrew);
return !_.isEqual(this.state.brew, this.savedBrew);
},
trySave : function(){
@@ -142,6 +150,12 @@ const EditPage = createClass({
this.clearErrors();
},
closeAlerts : function(){
this.setState({
alertRenderChange : false
});
},
toggleGoogleStorage : function(){
this.setState((prevState)=>({
saveGoogle : !prevState.saveGoogle,
@@ -294,7 +308,7 @@ const EditPage = createClass({
} catch (e){}
if(this.state.errors.status == '401'){
return <Nav.item className='save error' icon='fa-warning'>
return <Nav.item className='save error' icon='fas fa-exclamation-triangle'>
Oops!
<div className='errorContainer' onClick={this.clearErrors}>
You must be signed in to a Google account
@@ -312,7 +326,7 @@ const EditPage = createClass({
</Nav.item>;
}
return <Nav.item className='save error' icon='fa-warning'>
return <Nav.item className='save error' icon='fas fa-exclamation-triangle'>
Oops!
<div className='errorContainer'>
Looks like there was a problem saving. <br />
@@ -325,16 +339,25 @@ const EditPage = createClass({
}
if(this.state.isSaving){
return <Nav.item className='save' icon='fa-spinner fa-spin'>saving...</Nav.item>;
return <Nav.item className='save' icon='fas fa-spinner fa-spin'>saving...</Nav.item>;
}
if(this.state.isPending && this.hasChanges()){
return <Nav.item className='save' onClick={this.save} color='blue' icon='fa-save'>Save Now</Nav.item>;
return <Nav.item className='save' onClick={this.save} color='blue' icon='fas fa-save'>Save Now</Nav.item>;
}
if(!this.state.isPending && !this.state.isSaving){
return <Nav.item className='save saved'>saved.</Nav.item>;
}
},
// {this.state.alertRenderChange &&
// <div className='errorContainer' onClick={this.closeAlerts}>
// Rendering mode for this brew has been changed! Refresh the page to load the new renderer.<br />
// <div className='confirm'>
// OK
// </div>
// </div>
// }
processShareId : function() {
return this.state.brew.googleId ?
this.state.brew.googleId + this.state.brew.shareId :
@@ -350,8 +373,9 @@ const EditPage = createClass({
<Nav.section>
{this.renderGoogleDriveIcon()}
{this.renderSaveButton()}
<NewBrew />
<ReportIssue />
<Nav.item newTab={true} href={`/share/${this.processShareId()}`} color='teal' icon='fa-share-alt'>
<Nav.item newTab={true} href={`/share/${this.processShareId()}`} color='teal' icon='fas fa-share-alt'>
Share
</Nav.item>
<PrintLink shareId={this.processShareId()} />
@@ -370,12 +394,12 @@ const EditPage = createClass({
<SplitPane onDragFinish={this.handleSplitMove} ref='pane'>
<Editor
ref='editor'
value={this.state.brew.text}
brew={this.state.brew}
onChange={this.handleTextChange}
metadata={this.state.brew}
onMetadataChange={this.handleMetadataChange}
renderer={this.state.brew.renderer}
/>
<BrewRenderer text={this.state.brew.text} errors={this.state.htmlErrors} />
<BrewRenderer text={this.state.brew.text} errors={this.state.htmlErrors} renderer={this.state.brew.renderer} />
</SplitPane>
</div>
</div>;

View File

@@ -1,8 +1,14 @@
@keyframes glideDown {
0% {transform : translate(-50% + 3px, 0px);
opacity : 0;}
100% {transform : translate(-50% + 3px, 10px);
opacity : 1;}
}
.editPage{
.navItem.save{
width : 106px;
text-align : center;
position : relative;
&.saved{
cursor : initial;
color : #666;
@@ -21,12 +27,15 @@
margin : -5px;
}
.errorContainer{
animation-name: glideDown;
animation-duration: 0.4s;
position : absolute;
top : 100%;
left : 50%;
z-index : 1000;
z-index : 100000;
width : 140px;
padding : 3px;
color : white;
background-color : #333;
border : 3px solid #444;
border-radius : 5px;

View File

@@ -7,6 +7,7 @@ const { Meta } = require('vitreum/headtags');
const Nav = require('naturalcrit/nav/nav.jsx');
const Navbar = require('../../navbar/navbar.jsx');
const NewBrewItem = require('../../navbar/newbrew.navitem.jsx');
const IssueNavItem = require('../../navbar/issue.navitem.jsx');
const RecentNavItem = require('../../navbar/recent.navitem.jsx').both;
const AccountNavItem = require('../../navbar/account.navitem.jsx');
@@ -21,6 +22,9 @@ const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx');
const HomePage = createClass({
getDefaultProps : function() {
return {
brew : {
text : ''
},
welcomeText : '',
ver : '0.0.0'
};
@@ -29,13 +33,15 @@ const HomePage = createClass({
},
getInitialState : function() {
return {
text : this.props.welcomeText
brew : {
text : this.props.welcomeText
}
};
},
handleSave : function(){
request.post('/api')
.send({
text : this.state.text
text : this.state.brew.text
})
.end((err, res)=>{
if(err) return;
@@ -48,14 +54,15 @@ const HomePage = createClass({
},
handleTextChange : function(text){
this.setState({
text : text
brew : { text: text }
});
},
renderNavbar : function(){
return <Navbar ver={this.props.ver}>
<Nav.section>
<NewBrewItem />
<IssueNavItem />
<Nav.item newTab={true} href='/changelog' color='purple' icon='fa-file-text-o'>
<Nav.item newTab={true} href='/changelog' color='purple' icon='far fa-file-alt'>
Changelog
</Nav.item>
<RecentNavItem />
@@ -71,17 +78,17 @@ const HomePage = createClass({
<div className='content'>
<SplitPane onDragFinish={this.handleSplitMove} ref='pane'>
<Editor value={this.state.text} onChange={this.handleTextChange} showMetaButton={false} ref='editor'/>
<BrewRenderer text={this.state.text} />
<Editor brew={this.state.brew} onChange={this.handleTextChange} showMetaButton={false} ref='editor'/>
<BrewRenderer text={this.state.brew.text} />
</SplitPane>
</div>
<div className={cx('floatingSaveButton', { show: this.props.welcomeText != this.state.text })} onClick={this.handleSave}>
Save current <i className='fa fa-save' />
<div className={cx('floatingSaveButton', { show: this.props.welcomeText != this.state.brew.text })} onClick={this.handleSave}>
Save current <i className='fas fa-save' />
</div>
<a href='/new' className='floatingNewButton'>
Create your own <i className='fa fa-magic' />
Create your own <i className='fas fa-magic' />
</a>
</div>;
}

View File

@@ -20,9 +20,30 @@ const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx');
const KEY = 'homebrewery-new';
const NewPage = createClass({
getDefaultProps : function() {
return {
brew : {
text : '',
shareId : null,
editId : null,
createdAt : null,
updatedAt : null,
gDrive : false,
title : '',
description : '',
tags : '',
published : false,
authors : [],
systems : []
}
};
},
getInitialState : function() {
return {
metadata : {
brew : {
text : this.props.brew.text,
gDrive : false,
title : '',
description : '',
@@ -32,7 +53,6 @@ const NewPage = createClass({
systems : []
},
text : '',
isSaving : false,
saveGoogle : (global.account && global.account.googleId ? true : false),
errors : []
@@ -41,9 +61,9 @@ const NewPage = createClass({
componentDidMount : function() {
const storage = localStorage.getItem(KEY);
if(storage){
if(!this.props.brew.text && storage){
this.setState({
text : storage
brew : { text: storage }
});
}
document.addEventListener('keydown', this.handleControlKeys);
@@ -70,13 +90,13 @@ const NewPage = createClass({
handleMetadataChange : function(metadata){
this.setState({
metadata : _.merge({}, this.state.metadata, metadata)
brew : _.merge({}, this.state.brew, metadata)
});
},
handleTextChange : function(text){
this.setState({
text : text,
brew : { text: text },
errors : Markdown.validate(text)
});
localStorage.setItem(KEY, text);
@@ -92,7 +112,7 @@ const NewPage = createClass({
if(this.state.saveGoogle) {
const res = await request
.post('/api/newGoogle/')
.send(_.merge({}, this.state.metadata, { text: this.state.text }))
.send(this.state.brew)
.catch((err)=>{
console.log(err.status === 401
? 'Not signed in!'
@@ -106,9 +126,7 @@ const NewPage = createClass({
window.location = `/edit/${brew.googleId}${brew.editId}`;
} else {
request.post('/api')
.send(_.merge({}, this.state.metadata, {
text : this.state.text
}))
.send(this.state.brew)
.end((err, res)=>{
if(err){
this.setState({
@@ -122,28 +140,27 @@ const NewPage = createClass({
window.location = `/edit/${brew.editId}`;
});
}
},
renderSaveButton : function(){
if(this.state.isSaving){
return <Nav.item icon='fa-spinner fa-spin' className='saveButton'>
return <Nav.item icon='fas fa-spinner fa-spin' className='saveButton'>
save...
</Nav.item>;
} else {
return <Nav.item icon='fa-save' className='saveButton' onClick={this.save}>
return <Nav.item icon='fas fa-save' className='saveButton' onClick={this.save}>
save
</Nav.item>;
}
},
print : function(){
localStorage.setItem('print', this.state.text);
localStorage.setItem('print', this.state.brew.text);
window.open('/print?dialog=true&local=print', '_blank');
},
renderLocalPrintButton : function(){
return <Nav.item color='purple' icon='fa-file-pdf-o' onClick={this.print}>
return <Nav.item color='purple' icon='far fa-file-pdf' onClick={this.print}>
get PDF
</Nav.item>;
},
@@ -152,7 +169,7 @@ const NewPage = createClass({
return <Navbar>
<Nav.section>
<Nav.item className='brewTitle'>{this.state.metadata.title}</Nav.item>
<Nav.item className='brewTitle'>{this.state.brew.title}</Nav.item>
</Nav.section>
<Nav.section>
@@ -172,12 +189,11 @@ const NewPage = createClass({
<SplitPane onDragFinish={this.handleSplitMove} ref='pane'>
<Editor
ref='editor'
value={this.state.text}
brew={this.state.brew}
onChange={this.handleTextChange}
metadata={this.state.metadata}
onMetadataChange={this.handleMetadataChange}
/>
<BrewRenderer text={this.state.text} errors={this.state.errors} />
<BrewRenderer text={this.state.brew.text} errors={this.state.errors} />
</SplitPane>
</div>
</div>;

View File

@@ -4,6 +4,7 @@ const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames');
const { Meta } = require('vitreum/headtags');
const MarkdownLegacy = require('naturalcrit/markdownLegacy.js');
const Markdown = require('naturalcrit/markdown.js');
const PrintPage = createClass({
@@ -11,7 +12,8 @@ const PrintPage = createClass({
return {
query : {},
brew : {
text : '',
text : '',
renderer : 'legacy'
}
};
},
@@ -33,13 +35,24 @@ const PrintPage = createClass({
},
renderPages : function(){
return _.map(this.state.brewText.split('\\page'), (page, index)=>{
return <div
className='phb'
id={`p${index + 1}`}
dangerouslySetInnerHTML={{ __html: Markdown.render(page) }}
key={index} />;
});
if(this.props.brew.renderer == 'legacy') {
return _.map(this.state.brewText.split('\\page'), (page, index)=>{
return <div
className='phb'
id={`p${index + 1}`}
dangerouslySetInnerHTML={{ __html: MarkdownLegacy.render(page) }}
key={index} />;
});
} else {
return _.map(this.state.brewText.split(/^\\page/gm), (page, index)=>{
return <div
className='phb3'
id={`p${index + 1}`}
dangerouslySetInnerHTML={{ __html: Markdown.render(page) }}
key={index} />;
});
}
},
render : function(){

View File

@@ -22,7 +22,8 @@ const SharePage = createClass({
shareId : null,
createdAt : null,
updatedAt : null,
views : 0
views : 0,
renderer : ''
}
};
},
@@ -59,11 +60,11 @@ const SharePage = createClass({
<Nav.section>
<PrintLink shareId={this.processShareId()} />
<Nav.item href={`/source/${this.processShareId()}`} color='teal' icon='fa-code'>
view source
<Nav.item href={`/source/${this.processShareId()}`} color='teal' icon='fas fa-code'>
source
</Nav.item>
<Nav.item href={`/download/${this.processShareId()}`} color='red' icon='fa-download'>
download source
download
</Nav.item>
<RecentNavItem brew={this.props.brew} storageKey='view' />
<Account />
@@ -71,7 +72,7 @@ const SharePage = createClass({
</Navbar>
<div className='content'>
<BrewRenderer text={this.props.brew.text} />
<BrewRenderer text={this.props.brew.text} renderer={this.props.brew.renderer} />
</div>
</div>;
}

View File

@@ -48,7 +48,7 @@ const BrewItem = createClass({
if(!this.props.brew.editId) return;
return <a onClick={this.deleteBrew}>
<i className='fa fa-trash' />
<i className='fas fa-trash-alt' />
</a>;
},
@@ -61,7 +61,7 @@ const BrewItem = createClass({
}
return <a href={`/edit/${editLink}`} target='_blank' rel='noopener noreferrer'>
<i className='fa fa-pencil' />
<i className='fas fa-pencil-alt' />
</a>;
},
@@ -74,7 +74,7 @@ const BrewItem = createClass({
}
return <a href={`/share/${shareLink}`} target='_blank' rel='noopener noreferrer'>
<i className='fa fa-share-alt' />
<i className='fas fa-share-alt' />
</a>;
},
@@ -108,13 +108,13 @@ const BrewItem = createClass({
<div className='info'>
<span>
<i className='fa fa-user' /> {brew.authors.join(', ')}
<i className='fas fa-user' /> {brew.authors.join(', ')}
</span>
<span>
<i className='fa fa-eye' /> {brew.views}
<i className='fas fa-eye' /> {brew.views}
</span>
<span>
<i className='fa fa-refresh' /> {moment(brew.updatedAt).fromNow()}
<i className='fas fa-sync-alt' /> {moment(brew.updatedAt).fromNow()}
</span>
{this.renderGoogleDriveIcon()}
</div>

View File

@@ -22,6 +22,9 @@
font-size : 2.2em;
}
.info{
position: absolute;
bottom: 0px;
margin-bottom: 4px;
font-family : ScalySans;
font-size : 1.2em;
&>span{

View File

@@ -9,6 +9,7 @@ const Navbar = require('../../navbar/navbar.jsx');
const RecentNavItem = require('../../navbar/recent.navitem.jsx').both;
const Account = require('../../navbar/account.navitem.jsx');
const NewBrew = require('../../navbar/newbrew.navitem.jsx');
const BrewItem = require('./brewItem/brewItem.jsx');
// const brew = {
@@ -54,12 +55,13 @@ const UserPage = createClass({
return <div className='userPage page'>
<Navbar>
<Nav.section>
<NewBrew />
<RecentNavItem />
<Account />
</Nav.section>
</Navbar>
<div className='content'>
<div className='content V3'>
<div className='phb'>
<div>
<h1>{this.getUsernameWithS()} brews</h1>