0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2025-12-24 22:52:40 +00:00

Merge branch 'master' into fixThemesDefault

This commit is contained in:
G.Ambatte
2022-10-20 08:03:43 +13:00
committed by GitHub
12 changed files with 1300 additions and 2575 deletions

1
.gitignore vendored
View File

@@ -11,3 +11,4 @@ config/docker.*
todo.md
startDB.bat
startMViewer.bat
.vscode

View File

@@ -1,6 +1,7 @@
```css
h5 {
font-size: .35cm !important;
margin-top: 0.3cm;
}
.page ul ul {
@@ -14,6 +15,11 @@ h5 {
filter: brightness(1.1) drop-shadow(1px 2px 1px #222);
}
.taskList ul {
margin-bottom: 0px;
margin-top: 0px;
}
.taskList li input[checked] {
filter: sepia(100%) hue-rotate(60deg) saturate(3.5) contrast(4) brightness(1.1) drop-shadow(1px 2px 1px #222);
}
@@ -39,6 +45,68 @@ pre {
## changelog
For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery).
### Friday 19/10/2022 - v3.3.0
{{taskList
##### Calculuschild
* [x] Fix for tables broken by Chrome v106
##### G-Ambatte:
* [x] Fix Table of Contents broken by Chrome v106
Fixes issues [#2437](https://github.com/naturalcrit/homebrewery/issues/2437)
* [x] Show brew thumbnails on user page
Fixes issues [#2331](https://github.com/naturalcrit/homebrewery/issues/2331)
* [x] Allow longer URLs for brew thumbnails
Fixes issues [#2351](https://github.com/naturalcrit/homebrewery/issues/2351)
* [x] Code no longer unfolds when inserting a snippet
Fixes issues [#2135](https://github.com/naturalcrit/homebrewery/issues/2135)
* [x] Fix brew settings being lost on first save
Fixes issues [#2427](https://github.com/naturalcrit/homebrewery/issues/2427)
##### Gazook:
* [x] Several updates to bug reporting and error popups
Fixes issues [#2376](https://github.com/naturalcrit/homebrewery/issues/2376)
* [x] Fixes to userpage search bar
Fixes issues [#1675](https://github.com/naturalcrit/homebrewery/issues/1675), [#2353](https://github.com/naturalcrit/homebrewery/issues/2353)
* [x] Renderer *(legacy / V3)* now shown next to page #
Fixes issues [#1928](https://github.com/naturalcrit/homebrewery/issues/1928)
* [x] Prevent text selection when moving divider bar
Fixes issues [#1632](https://github.com/naturalcrit/homebrewery/issues/1632)
* [x] Tweak Monster Stat Block coloring
Fixes issues [#2123](https://github.com/naturalcrit/homebrewery/issues/2123)
* [x] Added dropdown button to toggle autosave
Fixes issues [#1546](https://github.com/naturalcrit/homebrewery/issues/1546)
}}
### Friday 08/09/2022 - v3.2.2
{{taskList

View File

@@ -19,11 +19,6 @@ const DEFAULT_STYLE_TEXT = dedent`
color: black;
}`;
const splice = function(str, index, inject){
return str.slice(0, index) + inject + str.slice(index);
};
const Editor = createClass({
displayName : 'Editor',
@@ -80,19 +75,7 @@ const Editor = createClass({
},
handleInject : function(injectText){
let text;
if(this.isText()) text = this.props.brew.text;
if(this.isStyle()) text = this.props.brew.style ?? DEFAULT_STYLE_TEXT;
const lines = text.split('\n');
const cursorPos = this.refs.codeEditor.getCursorPosition();
lines[cursorPos.line] = splice(lines[cursorPos.line], cursorPos.ch, injectText);
const injectLines = injectText.split('\n');
this.refs.codeEditor.setCursorPosition(cursorPos.line + injectLines.length, cursorPos.ch + injectLines[injectLines.length - 1].length);
if(this.isText()) this.props.onTextChange(lines.join('\n'));
if(this.isStyle()) this.props.onStyleChange(lines.join('\n'));
this.refs.codeEditor?.injectText(injectText, false);
},
handleViewChange : function(newView){

View File

@@ -70,7 +70,7 @@ const Account = createClass({
{global.account.username}
</Nav.item>
<Nav.item
href={`/user/${global.account.username}`}
href={`/user/${encodeURI(global.account.username)}`}
color='yellow'
icon='fas fa-beer'
>

View File

@@ -55,6 +55,18 @@
text-align : center;
text-transform : initial;
}
.save-menu {
.dropdown {
z-index: 1000;
}
.navItem i.fa-power-off {
color : red;
&.active {
color : rgb(0, 182, 52);
filter : drop-shadow(0 0 2px rgba(0, 182, 52, 0.765))
}
}
}
.patreon.navItem{
border-left : 1px solid #666;
border-right : 1px solid #666;

View File

@@ -62,7 +62,10 @@ const EditPage = createClass({
confirmGoogleTransfer : false,
errors : null,
htmlErrors : Markdown.validate(this.props.brew.text),
url : ''
url : '',
autoSave : true,
autoSaveWarning : false,
unsavedTime : new Date()
};
},
savedBrew : null,
@@ -72,9 +75,17 @@ const EditPage = createClass({
url : window.location.href
});
this.savedBrew = JSON.parse(JSON.stringify(this.props.brew)); //Deep copy
this.trySave();
this.setState({ autoSave: JSON.parse(localStorage.getItem('AUTOSAVE_ON')) }, ()=>{
if(this.state.autoSave){
this.trySave();
} else {
this.setState({ autoSaveWarning: true });
}
});
window.onbeforeunload = ()=>{
if(this.state.isSaving || this.state.isPending){
return 'You have unsaved changes!';
@@ -117,14 +128,14 @@ const EditPage = createClass({
brew : { ...prevState.brew, text: text },
isPending : true,
htmlErrors : htmlErrors
}), ()=>this.trySave());
}), ()=>{if(this.state.autoSave) this.trySave();});
},
handleStyleChange : function(style){
this.setState((prevState)=>({
brew : { ...prevState.brew, style: style },
isPending : true
}), ()=>this.trySave());
}), ()=>{if(this.state.autoSave) this.trySave();});
},
handleMetaChange : function(metadata){
@@ -134,7 +145,7 @@ const EditPage = createClass({
...metadata
},
isPending : true,
}), ()=>this.trySave());
}), ()=>{if(this.state.autoSave) this.trySave();});
},
@@ -221,8 +232,9 @@ const EditPage = createClass({
editId : this.savedBrew.editId,
shareId : this.savedBrew.shareId
},
isPending : false,
isSaving : false,
isPending : false,
isSaving : false,
unsavedTime : new Date()
}));
},
@@ -329,17 +341,55 @@ const EditPage = createClass({
</Nav.item>;
}
if(this.state.autoSaveWarning && this.hasChanges()){
this.setAutosaveWarning();
const elapsedTime = Math.round((new Date() - this.state.unsavedTime) / 1000 / 60);
const text = elapsedTime == 0 ? 'Autosave is OFF.' : `Autosave is OFF, and you haven't saved for ${elapsedTime} minutes.`;
return <Nav.item className='save error' icon='fas fa-exclamation-circle'>
Reminder...
<div className='errorContainer'>
{text}
</div>
</Nav.item>;
}
if(this.state.isSaving){
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='fas fa-save'>Save Now</Nav.item>;
}
if(!this.state.isPending && !this.state.isSaving && this.state.autoSave){
return <Nav.item className='save saved'>auto-saved.</Nav.item>;
}
if(!this.state.isPending && !this.state.isSaving){
return <Nav.item className='save saved'>saved.</Nav.item>;
}
},
handleAutoSave : function(){
if(this.warningTimer) clearTimeout(this.warningTimer);
this.setState((prevState)=>({
autoSave : !prevState.autoSave,
autoSaveWarning : prevState.autoSave
}), ()=>{
localStorage.setItem('AUTOSAVE_ON', JSON.stringify(this.state.autoSave));
});
},
setAutosaveWarning : function(){
setTimeout(()=>this.setState({ autoSaveWarning: false }), 4000); // 4 seconds to display
this.warningTimer = setTimeout(()=>{this.setState({ autoSaveWarning: true });}, 900000); // 15 minutes between warnings
this.warningTimer;
},
renderAutoSaveButton : function(){
return <Nav.item onClick={this.handleAutoSave}>
Autosave <i className={this.state.autoSave ? 'fas fa-power-off active' : 'fas fa-power-off'}></i>
</Nav.item>;
},
processShareId : function() {
return this.state.brew.googleId && !this.state.brew.stubbed ?
this.state.brew.googleId + this.state.brew.shareId :
@@ -378,7 +428,10 @@ const EditPage = createClass({
<Nav.section>
{this.renderGoogleDriveIcon()}
{this.renderSaveButton()}
<Nav.dropdown className='save-menu'>
{this.renderSaveButton()}
{this.renderAutoSaveButton()}
</Nav.dropdown>
<NewBrew />
<HelpNavItem/>
<Nav.dropdown>

View File

@@ -32,7 +32,7 @@
position : absolute;
top : 100%;
left : 50%;
z-index : 100000;
z-index : 500;
width : 140px;
padding : 3px;
color : white;

View File

@@ -38,9 +38,7 @@ const HomePage = createClass({
},
handleSave : function(){
request.post('/api')
.send({
text : this.state.brew.text
})
.send(this.state.brew)
.end((err, res)=>{
if(err) return;
const brew = res.body;

3553
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{
"name": "homebrewery",
"description": "Create authentic looking D&D homebrews using only markdown",
"version": "3.2.2",
"version": "3.3.0",
"engines": {
"node": "16.11.x"
},
@@ -51,17 +51,17 @@
]
},
"dependencies": {
"@babel/core": "^7.19.1",
"@babel/core": "^7.19.3",
"@babel/plugin-transform-runtime": "^7.19.1",
"@babel/preset-env": "^7.19.1",
"@babel/preset-env": "^7.19.4",
"@babel/preset-react": "^7.18.6",
"body-parser": "^1.20.0",
"body-parser": "^1.20.1",
"classnames": "^2.3.2",
"codemirror": "^5.65.6",
"cookie-parser": "^1.4.6",
"create-react-class": "^15.7.0",
"dedent-tabs": "^0.10.1",
"express": "^4.18.1",
"express": "^4.18.2",
"express-async-handler": "^1.2.0",
"express-static-gzip": "2.1.7",
"fs-extra": "10.1.0",
@@ -70,25 +70,25 @@
"jwt-simple": "^0.5.6",
"less": "^3.13.1",
"lodash": "^4.17.21",
"marked": "4.1.0",
"marked": "4.1.1",
"marked-extended-tables": "^1.0.5",
"markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.29.4",
"mongoose": "^6.6.1",
"mongoose": "^6.6.5",
"nanoid": "3.3.4",
"nconf": "^0.12.0",
"react": "^16.14.0",
"react-dom": "^16.14.0",
"react-frame-component": "4.1.3",
"react-router-dom": "6.3.0",
"react-router-dom": "6.4.2",
"sanitize-filename": "1.6.3",
"superagent": "^6.1.0",
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
},
"devDependencies": {
"eslint": "^8.24.0",
"eslint-plugin-react": "^7.31.8",
"jest": "^29.0.3",
"supertest": "^6.2.4"
"eslint": "^8.25.0",
"eslint-plugin-react": "^7.31.10",
"jest": "^29.2.1",
"supertest": "^6.3.0"
}
}

View File

@@ -229,6 +229,15 @@ const CodeEditor = createClass({
this.codeMirror.replaceSelection('\n\\page\n\n', 'end');
},
injectText : function(injectText, overwrite=true) {
const cm = this.codeMirror;
if(!overwrite) {
cm.setCursor(cm.getCursor('from'));
}
cm.replaceSelection(injectText, 'end');
cm.focus();
},
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');

View File

@@ -213,7 +213,9 @@ body {
tbody{
tr{
td{
padding : 0.14em 0.4em;
//padding : 0.14em 0.4em;
padding : 0px 5px; // Both of these are temporary, just to force
height : 16px; // PDF to render at same height until Chrome 108
}
&:nth-child(odd){
background-color : var(--HB_Color_Accent);
@@ -657,72 +659,78 @@ body {
//*****************************
// * TABLE OF CONTENTS
// *****************************/
.page .toc{
.page {
&:has(.toc):after {
display: none;
}
.toc {
-webkit-column-break-inside : avoid;
page-break-inside : avoid;
break-inside : avoid;
h1 {
text-align : center;
margin-bottom : 0.3cm;
}
a{
display : inline;
color : inherit;
text-decoration : none;
&:hover{
text-decoration : underline;
h1 {
text-align : center;
margin-bottom : 0.3cm;
}
}
h4 {
margin-top : 0.2cm;
line-height : 0.4cm;
& + ul li {
line-height: 1.2em;
a{
display : inline;
color : inherit;
text-decoration : none;
&:hover{
text-decoration : underline;
}
}
}
ul{
padding-left : 0;
list-style-type : none;
li + li h3 {
margin-top : 0.26cm;
line-height : 1em
h4 {
margin-top : 0.2cm;
line-height : 0.4cm;
& + ul li {
line-height: 1.2em;
}
}
h3 span:first-child::after {
border : none;
}
span {
display : table-cell;
&:first-child {
position : relative;
overflow : hidden;
&::after {
ul{
padding-left : 0;
list-style-type : none;
margin-top : 0;
a {
width : 100%;
display : flex;
flex-flow : row nowrap;
justify-content : space-between;
}
li + li h3 {
margin-top : 0.26cm;
line-height : 1em
}
h3 span:first-child::after {
border : none;
}
span {
display : contents;
&:first-child::after {
content : "";
position : absolute;
bottom : 0.08cm;
margin-left : 0.06cm; /* Spacing before dot leaders */
width : 100%;
flex : 1;
margin-left : 0.08cm; /* Spacing before dot leaders */
margin-right : 0.16cm;
border-bottom : 0.05cm dotted #000;
margin-bottom : 0.08cm;
}
&:last-child {
display : inline-block;
align-self : flex-end;
font-family : "BookInsanityRemake";
font-size : 0.34cm;
font-weight : normal;
color : #000;
}
}
&:last-child {
font-family : BookInsanityRemake;
font-size : 0.34cm;
font-weight : normal;
color : black;
text-align : right;
vertical-align : bottom; /* Keep page number bottom-aligned */
width : 1%;
padding-left : 0.06cm; /* Spacing after dot leaders */
/*white-space : nowrap; /* Uncomment if needed */
ul { /*List indent*/
margin-left : 1em;
}
}
ul { /*List indent*/
margin-left : 1em;
&.wide{
.useColumns(0.96, @fillMode: balance);
}
}
&.wide{
.useColumns(0.96, @fillMode: balance);
}
}
//*****************************