0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2026-01-07 16:22:42 +00:00

Merge branch 'master' into metadata-document-block

# Conflicts:
#	package-lock.json
This commit is contained in:
Charlie Humphreys
2021-12-07 22:09:44 -06:00
8 changed files with 9915 additions and 154 deletions

View File

@@ -3,11 +3,12 @@ h5 {
font-size: .35cm !important; font-size: .35cm !important;
} }
.taskList li { .page ul ul {
list-style-type : none; margin-left: 0px;
} }
.taskList li input { .taskList li input {
list-style-type : none;
margin-left : -0.52cm; margin-left : -0.52cm;
transform: translateY(.05cm); transform: translateY(.05cm);
filter: brightness(1.1) drop-shadow(1px 2px 1px #222); filter: brightness(1.1) drop-shadow(1px 2px 1px #222);
@@ -33,6 +34,34 @@ pre {
## changelog ## changelog
For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery). For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery).
### Tuesday 07/12/2021 - v3.0.5
{{taskList
* [x] Fixed paragraph spacing for **note** and **descriptive** boxes in V3.
Fixes issues: [#1836](https://github.com/naturalcrit/homebrewery/issues/1836)
* [x] Added a whole bunch of hotkeys:
* Page Break `CTRL + ENTER`
* Column Break `CTRL + SHIFT + ENTER`
* Bulleted Lists `CTRL + L`
* Numbered Lists `CTRL + SHIFT + L`
* Headers `CTRL + SHIFT + (1-6)`
* Underline `CTRL + U`
* Link `CTRL + K`
* Non-breaking space (\ ) `CTRL + .`
* Add Horizontal Space `CTRL + SHIFT + .`
* Remove Horizontal Space `CTRL + SHIFT + ,`
* Curly Span `CTRL + M`
* Curly Div `CTRL + SHIFT + M`
* [x] Fixed page numbers in the editor panel getting scrambled when scrolling up and down.
* [x] Faster swapping between tabs on long brews.
* [x] Better error messages for common issue with Google Drive credentials expiring.
}}
### Wednesday 17/11/2021 - v3.0.4 ### Wednesday 17/11/2021 - v3.0.4
{{taskList {{taskList
* [x] Fixed incorrect sorting of Google brews by page count and views on the user page. * [x] Fixed incorrect sorting of Google brews by page count and views on the user page.

View File

@@ -107,67 +107,69 @@ const Editor = createClass({
if(this.state.view === 'text') { if(this.state.view === 'text') {
const codeMirror = this.refs.codeEditor.codeMirror; const codeMirror = this.refs.codeEditor.codeMirror;
//reset custom text styles codeMirror.operation(()=>{ // Batch CodeMirror styling
const customHighlights = codeMirror.getAllMarks().filter((mark)=>!mark.__isFold); //Don't undo code folding //reset custom text styles
for (let i=0;i<customHighlights.length;i++) customHighlights[i].clear(); const customHighlights = codeMirror.getAllMarks().filter((mark)=>!mark.__isFold); //Don't undo code folding
for (let i=customHighlights.length - 1;i>=0;i--) customHighlights[i].clear();
const lineNumbers = _.reduce(this.props.brew.text.split('\n'), (r, line, lineNumber)=>{ let editorPageCount = 2; // start page count from page 2
//reset custom line styles _.forEach(this.props.brew.text.split('\n'), (line, lineNumber)=>{
codeMirror.removeLineClass(lineNumber, 'background');
codeMirror.removeLineClass(lineNumber, 'text');
// Legacy Codemirror styling //reset custom line styles
if(this.props.renderer == 'legacy') { codeMirror.removeLineClass(lineNumber, 'background');
if(line.includes('\\page')){ codeMirror.removeLineClass(lineNumber, 'text');
// Styling for \page breaks
if((this.props.renderer == 'legacy' && line.includes('\\page')) ||
(this.props.renderer == 'V3' && line.match(/^\\page$/))) {
// add back the original class 'background' but also add the new class '.pageline'
codeMirror.addLineClass(lineNumber, 'background', 'pageLine'); codeMirror.addLineClass(lineNumber, 'background', 'pageLine');
r.push(lineNumber); const pageCountElement = Object.assign(document.createElement('span'), {
} className : 'editor-page-count',
} textContent : editorPageCount
});
codeMirror.setBookmark({ line: lineNumber, ch: line.length }, pageCountElement);
// New Codemirror styling for V3 renderer editorPageCount += 1;
if(this.props.renderer == 'V3') { };
if(line.match(/^\\page$/)){
codeMirror.addLineClass(lineNumber, 'background', 'pageLine');
r.push(lineNumber);
}
if(line.match(/^\\column$/)){ // New Codemirror styling for V3 renderer
codeMirror.addLineClass(lineNumber, 'text', 'columnSplit'); if(this.props.renderer == 'V3') {
r.push(lineNumber); if(line.match(/^\\column$/)){
} codeMirror.addLineClass(lineNumber, 'text', 'columnSplit');
// Highlight inline spans {{content}}
if(line.includes('{{') && line.includes('}}')){
const regex = /{{(?::(?:"[\w,\-()#%. ]*"|[\w\,\-()#%.]*)|[^"'{}\s])*\s*|}}/g;
let match;
let blockCount = 0;
while ((match = regex.exec(line)) != null) {
if(match[0].startsWith('{')) {
blockCount += 1;
} else {
blockCount -= 1;
}
if(blockCount < 0) {
blockCount = 0;
continue;
}
codeMirror.markText({ line: lineNumber, ch: match.index }, { line: lineNumber, ch: match.index + match[0].length }, { className: 'inline-block' });
} }
} else if(line.trimLeft().startsWith('{{') || line.trimLeft().startsWith('}}')){
// Highlight block divs {{\n Content \n}}
let endCh = line.length+1;
const match = line.match(/^ *{{(?::(?:"[\w,\-()#%. ]*"|[\w\,\-()#%.]*)|[^"'{}\s])* *$|^ *}}$/); // Highlight inline spans {{content}}
if(match) if(line.includes('{{') && line.includes('}}')){
endCh = match.index+match[0].length; const regex = /{{(?::(?:"[\w,\-()#%. ]*"|[\w\,\-()#%.]*)|[^"'{}\s])*\s*|}}/g;
codeMirror.markText({ line: lineNumber, ch: 0 }, { line: lineNumber, ch: endCh }, { className: 'block' }); let match;
let blockCount = 0;
while ((match = regex.exec(line)) != null) {
if(match[0].startsWith('{')) {
blockCount += 1;
} else {
blockCount -= 1;
}
if(blockCount < 0) {
blockCount = 0;
continue;
}
codeMirror.markText({ line: lineNumber, ch: match.index }, { line: lineNumber, ch: match.index + match[0].length }, { className: 'inline-block' });
}
} else if(line.trimLeft().startsWith('{{') || line.trimLeft().startsWith('}}')){
// Highlight block divs {{\n Content \n}}
let endCh = line.length+1;
const match = line.match(/^ *{{(?::(?:"[\w,\-()#%. ]*"|[\w\,\-()#%.]*)|[^"'{}\s])* *$|^ *}}$/);
if(match)
endCh = match.index+match[0].length;
codeMirror.markText({ line: lineNumber, ch: 0 }, { line: lineNumber, ch: endCh }, { className: 'block' });
}
} }
} });
});
return r;
}, []);
return lineNumbers;
} }
}, },

View File

@@ -5,17 +5,13 @@
.codeEditor{ .codeEditor{
height : 100%; height : 100%;
counter-reset : page;
counter-increment : page;
.pageLine{ .pageLine{
background : #33333328; background : #33333328;
border-top : #339 solid 1px; border-top : #339 solid 1px;
&:after{ }
content : counter(page); .editor-page-count{
counter-increment : page; color : grey;
float : right; float : right;
color : gray;
}
} }
.columnSplit{ .columnSplit{
font-style : italic; font-style : italic;

View File

@@ -349,14 +349,14 @@ const EditPage = createClass({
</Nav.item>; </Nav.item>;
} }
if(this.state.errors.status == '403' && this.state.errors.response.body.errors[0].reason == 'insufficientPermissions'){ if(this.state.errors.response.req.url.match(/^\/api\/.*Google.*$/m)){
return <Nav.item className='save error' icon='fas fa-exclamation-triangle'> return <Nav.item className='save error' icon='fas fa-exclamation-triangle'>
Oops! Oops!
<div className='errorContainer' onClick={this.clearErrors}> <div className='errorContainer' onClick={this.clearErrors}>
Looks like your Google credentials have Looks like your Google credentials have
expired! Visit the log in page to sign out expired! Visit our log in page to sign out
and sign back in with Google and sign back in with Google,
to save this to Google Drive! then try saving again!
<a target='_blank' rel='noopener noreferrer' <a target='_blank' rel='noopener noreferrer'
href={`https://www.naturalcrit.com/login?redirect=${this.state.url}`}> href={`https://www.naturalcrit.com/login?redirect=${this.state.url}`}>
<div className='confirm'> <div className='confirm'>

View File

@@ -226,14 +226,14 @@ const NewPage = createClass({
</Nav.item>; </Nav.item>;
} }
if(this.state.errors.status == '403' && this.state.errors.response.body.errors[0].reason == 'insufficientPermissions'){ if(this.state.errors.response.req.url.match(/^\/api\/.*Google.*$/m)){
return <Nav.item className='save error' icon='fas fa-exclamation-triangle'> return <Nav.item className='save error' icon='fas fa-exclamation-triangle'>
Oops! Oops!
<div className='errorContainer' onClick={this.clearErrors}> <div className='errorContainer' onClick={this.clearErrors}>
Looks like your Google credentials have Looks like your Google credentials have
expired! Visit the log in page to sign out expired! Visit our log in page to sign out
and sign back in with Google and sign back in with Google,
to save this to Google Drive! then try saving again!
<a target='_blank' rel='noopener noreferrer' <a target='_blank' rel='noopener noreferrer'
href={`https://www.naturalcrit.com/login?redirect=${this.state.url}`}> href={`https://www.naturalcrit.com/login?redirect=${this.state.url}`}>
<div className='confirm'> <div className='confirm'>

9718
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -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": "3.0.4", "version": "3.0.5",
"engines": { "engines": {
"node": "16.11.x" "node": "16.11.x"
}, },
@@ -62,7 +62,7 @@
"marked": "3.0.8", "marked": "3.0.8",
"markedLegacy": "npm:marked@^0.3.19", "markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.29.1", "moment": "^2.29.1",
"mongoose": "^6.0.14", "mongoose": "^6.0.15",
"nanoid": "3.1.30", "nanoid": "3.1.30",
"nconf": "^0.11.3", "nconf": "^0.11.3",
"prop-types": "15.7.2", "prop-types": "15.7.2",
@@ -76,7 +76,7 @@
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git" "vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
}, },
"devDependencies": { "devDependencies": {
"eslint": "^8.3.0", "eslint": "^8.4.1",
"eslint-plugin-react": "^7.27.1", "eslint-plugin-react": "^7.27.1",
"pico-check": "^2.1.3" "pico-check": "^2.1.3"
} }

View File

@@ -1,3 +1,4 @@
/* eslint-disable max-lines */
require('./codeEditor.less'); require('./codeEditor.less');
const React = require('react'); const React = require('react');
const createClass = require('create-react-class'); const createClass = require('create-react-class');
@@ -74,18 +75,50 @@ const CodeEditor = createClass({
tabSize : 2, tabSize : 2,
historyEventDelay : 250, historyEventDelay : 250,
extraKeys : { extraKeys : {
'Ctrl-B' : this.makeBold, 'Ctrl-B' : this.makeBold,
'Cmd-B' : this.makeBold, 'Cmd-B' : this.makeBold,
'Ctrl-I' : this.makeItalic, 'Ctrl-I' : this.makeItalic,
'Cmd-I' : this.makeItalic, 'Cmd-I' : this.makeItalic,
'Ctrl-M' : this.makeSpan, 'Ctrl-U' : this.makeUnderline,
'Cmd-M' : this.makeSpan, 'Cmd-U' : this.makeUnderline,
'Ctrl-/' : this.makeComment, 'Ctrl-.' : this.makeNbsp,
'Cmd-/' : this.makeComment, 'Cmd-.' : this.makeNbsp,
'Ctrl-[' : this.foldAllCode, 'Shift-Ctrl-.' : this.makeSpace,
'Cmd-[' : this.foldAllCode, 'Shift-Cmd-.' : this.makeSpace,
'Ctrl-]' : this.unfoldAllCode, 'Shift-Ctrl-,' : this.removeSpace,
'Cmd-]' : this.unfoldAllCode 'Shift-Cmd-,' : this.removeSpace,
'Ctrl-M' : this.makeSpan,
'Cmd-M' : this.makeSpan,
'Shift-Ctrl-M' : this.makeDiv,
'Shift-Cmd-M' : this.makeDiv,
'Ctrl-/' : this.makeComment,
'Cmd-/' : this.makeComment,
'Ctrl-K' : this.makeLink,
'Cmd-K' : this.makeLink,
'Ctrl-L' : ()=>this.makeList('UL'),
'Cmd-L' : ()=>this.makeList('UL'),
'Shift-Ctrl-L' : ()=>this.makeList('OL'),
'Shift-Cmd-L' : ()=>this.makeList('OL'),
'Shift-Ctrl-1' : ()=>this.makeHeader(1),
'Shift-Ctrl-2' : ()=>this.makeHeader(2),
'Shift-Ctrl-3' : ()=>this.makeHeader(3),
'Shift-Ctrl-4' : ()=>this.makeHeader(4),
'Shift-Ctrl-5' : ()=>this.makeHeader(5),
'Shift-Ctrl-6' : ()=>this.makeHeader(6),
'Shift-Cmd-1' : ()=>this.makeHeader(1),
'Shift-Cmd-2' : ()=>this.makeHeader(2),
'Shift-Cmd-3' : ()=>this.makeHeader(3),
'Shift-Cmd-4' : ()=>this.makeHeader(4),
'Shift-Cmd-5' : ()=>this.makeHeader(5),
'Shift-Cmd-6' : ()=>this.makeHeader(6),
'Shift-Ctrl-Enter' : this.newColumn,
'Shift-Cmd-Enter' : this.newColumn,
'Ctrl-Enter' : this.newPage,
'Cmd-Enter' : this.newPage,
'Ctrl-[' : this.foldAllCode,
'Cmd-[' : this.foldAllCode,
'Ctrl-]' : this.unfoldAllCode,
'Cmd-]' : this.unfoldAllCode
}, },
foldGutter : true, foldGutter : true,
foldOptions : { foldOptions : {
@@ -117,6 +150,14 @@ const CodeEditor = createClass({
this.updateSize(); this.updateSize();
}, },
makeHeader : function (number) {
const selection = this.codeMirror.getSelection();
const header = Array(number).fill('#').join('');
this.codeMirror.replaceSelection(`${header} ${selection}`, 'around');
const cursor = this.codeMirror.getCursor();
this.codeMirror.setCursor({ line: cursor.line, ch: cursor.ch + selection.length + number + 1 });
},
makeBold : function() { makeBold : function() {
const selection = this.codeMirror.getSelection(), t = selection.slice(0, 2) === '**' && selection.slice(-2) === '**'; const selection = this.codeMirror.getSelection(), t = selection.slice(0, 2) === '**' && selection.slice(-2) === '**';
this.codeMirror.replaceSelection(t ? selection.slice(2, -2) : `**${selection}**`, 'around'); this.codeMirror.replaceSelection(t ? selection.slice(2, -2) : `**${selection}**`, 'around');
@@ -127,14 +168,55 @@ const CodeEditor = createClass({
}, },
makeItalic : function() { makeItalic : function() {
const selection = this.codeMirror.getSelection(), t = selection.slice(0, 1) === '_' && selection.slice(-1) === '_'; const selection = this.codeMirror.getSelection(), t = selection.slice(0, 1) === '*' && selection.slice(-1) === '*';
this.codeMirror.replaceSelection(t ? selection.slice(1, -1) : `_${selection}_`, 'around'); this.codeMirror.replaceSelection(t ? selection.slice(1, -1) : `*${selection}*`, 'around');
if(selection.length === 0){ if(selection.length === 0){
const cursor = this.codeMirror.getCursor(); const cursor = this.codeMirror.getCursor();
this.codeMirror.setCursor({ line: cursor.line, ch: cursor.ch - 1 }); this.codeMirror.setCursor({ line: cursor.line, ch: cursor.ch - 1 });
} }
}, },
makeNbsp : function() {
this.codeMirror.replaceSelection('&nbsp;', 'end');
},
makeSpace : function() {
const selection = this.codeMirror.getSelection();
const t = selection.slice(0, 8) === '{{width:' && selection.slice(0 -4) === '% }}';
if(t){
const percent = parseInt(selection.slice(8, -4)) + 10;
this.codeMirror.replaceSelection(percent < 90 ? `{{width:${percent}% }}` : '{{width:100% }}', 'around');
} else {
this.codeMirror.replaceSelection(`{{width:10% }}`, 'around');
}
},
removeSpace : function() {
const selection = this.codeMirror.getSelection();
const t = selection.slice(0, 8) === '{{width:' && selection.slice(0 -4) === '% }}';
if(t){
const percent = parseInt(selection.slice(8, -4)) - 10;
this.codeMirror.replaceSelection(percent > 10 ? `{{width:${percent}% }}` : '', 'around');
}
},
newColumn : function() {
this.codeMirror.replaceSelection('\n\\column\n\n', 'end');
},
newPage : function() {
this.codeMirror.replaceSelection('\n\\page\n\n', 'end');
},
makeUnderline : function() {
const selection = this.codeMirror.getSelection(), t = selection.slice(0, 3) === '<u>' && selection.slice(-4) === '</u>';
this.codeMirror.replaceSelection(t ? selection.slice(3, -4) : `<u>${selection}</u>`, 'around');
if(selection.length === 0){
const cursor = this.codeMirror.getCursor();
this.codeMirror.setCursor({ line: cursor.line, ch: cursor.ch - 4 });
}
},
makeSpan : function() { makeSpan : function() {
const selection = this.codeMirror.getSelection(), t = selection.slice(0, 2) === '{{' && selection.slice(-2) === '}}'; const selection = this.codeMirror.getSelection(), t = selection.slice(0, 2) === '{{' && selection.slice(-2) === '}}';
this.codeMirror.replaceSelection(t ? selection.slice(2, -2) : `{{ ${selection}}}`, 'around'); this.codeMirror.replaceSelection(t ? selection.slice(2, -2) : `{{ ${selection}}}`, 'around');
@@ -144,12 +226,72 @@ const CodeEditor = createClass({
} }
}, },
makeComment : function() { makeDiv : function() {
const selection = this.codeMirror.getSelection(), t = selection.slice(0, 4) === '<!--' && selection.slice(-3) === '-->'; const selection = this.codeMirror.getSelection(), t = selection.slice(0, 2) === '{{' && selection.slice(-2) === '}}';
this.codeMirror.replaceSelection(t ? selection.slice(4, -3) : `<!-- ${selection} -->`, 'around'); this.codeMirror.replaceSelection(t ? selection.slice(2, -2) : `{{\n${selection}\n}}`, 'around');
if(selection.length === 0){ if(selection.length === 0){
const cursor = this.codeMirror.getCursor(); const cursor = this.codeMirror.getCursor();
this.codeMirror.setCursor({ line: cursor.line, ch: cursor.ch - 4 }); this.codeMirror.setCursor({ line: cursor.line - 1, ch: cursor.ch }); // set to -2? if wanting to enter classes etc. if so, get rid of first \n when replacing selection
}
},
makeComment : function() {
let regex;
let cursorPos;
let newComment;
const selection = this.codeMirror.getSelection();
if(this.props.language === 'gfm'){
regex = /^\s*(<!--\s?)(.*?)(\s?-->)\s*$/gs;
cursorPos = 4;
newComment = `<!-- ${selection} -->`;
} else {
regex = /^\s*(\/\*\s?)(.*?)(\s?\*\/)\s*$/gs;
cursorPos = 3;
newComment = `/* ${selection} */`;
}
this.codeMirror.replaceSelection(regex.test(selection) == true ? selection.replace(regex, '$2') : newComment, 'around');
if(selection.length === 0){
const cursor = this.codeMirror.getCursor();
this.codeMirror.setCursor({ line: cursor.line, ch: cursor.ch - cursorPos });
};
},
makeLink : function() {
const isLink = /^\[(.*)\]\((.*)\)$/;
const selection = this.codeMirror.getSelection().trim();
let match;
if(match = isLink.exec(selection)){
const altText = match[1];
const url = match[2];
this.codeMirror.replaceSelection(`${altText} ${url}`);
const cursor = this.codeMirror.getCursor();
this.codeMirror.setSelection({ line: cursor.line, ch: cursor.ch - url.length }, { line: cursor.line, ch: cursor.ch });
} else {
this.codeMirror.replaceSelection(`[${selection || 'alt text'}](url)`);
const cursor = this.codeMirror.getCursor();
this.codeMirror.setSelection({ line: cursor.line, ch: cursor.ch - 4 }, { line: cursor.line, ch: cursor.ch - 1 });
}
},
makeList : function(listType) {
const selectionStart = this.codeMirror.getCursor('from'), selectionEnd = this.codeMirror.getCursor('to');
this.codeMirror.setSelection(
{ line: selectionStart.line, ch: 0 },
{ line: selectionEnd.line, ch: this.codeMirror.getLine(selectionEnd.line).length }
);
const newSelection = this.codeMirror.getSelection();
const regex = /^\d+\.\s|^-\s/gm;
if(newSelection.match(regex) != null){ // if selection IS A LIST
this.codeMirror.replaceSelection(newSelection.replace(regex, ''), 'around');
} else { // if selection IS NOT A LIST
listType == 'UL' ? this.codeMirror.replaceSelection(newSelection.replace(/^/gm, `- `), 'around') :
this.codeMirror.replaceSelection(newSelection.replace(/^/gm, (()=>{
let n = 1;
return ()=>{
return `${n++}. `;
};
})()), 'around');
} }
}, },