0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2026-01-27 09:33:08 +00:00

Compare commits

..

1 Commits

Author SHA1 Message Date
dependabot[bot]
33dadba162 Bump marked from 15.0.12 to 16.4.1
Bumps [marked](https://github.com/markedjs/marked) from 15.0.12 to 16.4.1.
- [Release notes](https://github.com/markedjs/marked/releases)
- [Changelog](https://github.com/markedjs/marked/blob/master/.releaserc.json)
- [Commits](https://github.com/markedjs/marked/compare/v15.0.12...v16.4.1)

---
updated-dependencies:
- dependency-name: marked
  dependency-version: 16.4.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-03 03:57:34 +00:00
57 changed files with 2636 additions and 2660 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -4,13 +4,13 @@ const React = require('react');
const { useState, useRef, useMemo, useEffect } = React; const { useState, useRef, useMemo, useEffect } = React;
const _ = require('lodash'); const _ = require('lodash');
const MarkdownLegacy = require('markdownLegacy.js'); const MarkdownLegacy = require('naturalcrit/markdownLegacy.js');
import Markdown from 'markdown.js'; import Markdown from 'naturalcrit/markdown.js';
const ErrorBar = require('./errorBar/errorBar.jsx'); const ErrorBar = require('./errorBar/errorBar.jsx');
const ToolBar = require('./toolBar/toolBar.jsx'); const ToolBar = require('./toolBar/toolBar.jsx');
//TODO: move to the brew renderer //TODO: move to the brew renderer
const RenderWarnings = require('client/components/renderWarnings/renderWarnings.jsx'); const RenderWarnings = require('homebrewery/renderWarnings/renderWarnings.jsx');
const NotificationPopup = require('./notificationPopup/notificationPopup.jsx'); const NotificationPopup = require('./notificationPopup/notificationPopup.jsx');
const Frame = require('react-frame-component').default; const Frame = require('react-frame-component').default;
const dedent = require('dedent-tabs').default; const dedent = require('dedent-tabs').default;

View File

@@ -1,7 +1,7 @@
require('./notificationPopup.less'); require('./notificationPopup.less');
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import request from '../../utils/request-middleware.js'; import request from '../../utils/request-middleware.js';
import Markdown from 'markdown.js'; import Markdown from 'naturalcrit/markdown.js';
import Dialog from '../../../components/dialog.jsx'; import Dialog from '../../../components/dialog.jsx';

View File

@@ -4,9 +4,9 @@ const React = require('react');
const createClass = require('create-react-class'); const createClass = require('create-react-class');
const _ = require('lodash'); const _ = require('lodash');
const dedent = require('dedent-tabs').default; const dedent = require('dedent-tabs').default;
import Markdown from '../../../shared/markdown.js'; import Markdown from '../../../shared/naturalcrit/markdown.js';
const CodeEditor = require('client/components/codeEditor/codeEditor.jsx'); const CodeEditor = require('naturalcrit/codeEditor/codeEditor.jsx');
const SnippetBar = require('./snippetbar/snippetbar.jsx'); const SnippetBar = require('./snippetbar/snippetbar.jsx');
const MetadataEditor = require('./metadataEditor/metadataEditor.jsx'); const MetadataEditor = require('./metadataEditor/metadataEditor.jsx');
@@ -58,7 +58,7 @@ const Editor = createClass({
return { return {
editorTheme : this.props.editorTheme, editorTheme : this.props.editorTheme,
view : 'text', //'text', 'style', 'meta', 'snippet' view : 'text', //'text', 'style', 'meta', 'snippet'
snippetBarHeight : 26, snippetbarHeight : 25
}; };
}, },
@@ -85,15 +85,7 @@ const Editor = createClass({
editorTheme : editorTheme editorTheme : editorTheme
}); });
} }
const snippetBar = document.querySelector('.editor > .snippetBar'); this.setState({ snippetbarHeight: document.querySelector('.editor > .snippetBar').offsetHeight });
if (!snippetBar) return;
this.resizeObserver = new ResizeObserver(entries => {
const height = document.querySelector('.editor > .snippetBar').offsetHeight;
this.setState({ snippetBarHeight: height });
});
this.resizeObserver.observe(snippetBar);
}, },
componentDidUpdate : function(prevProps, prevState, snapshot) { componentDidUpdate : function(prevProps, prevState, snapshot) {
@@ -116,10 +108,6 @@ const Editor = createClass({
} }
}, },
componentWillUnmount() {
if (this.resizeObserver) this.resizeObserver.disconnect();
},
handleControlKeys : function(e){ handleControlKeys : function(e){
if(!(e.ctrlKey && e.metaKey && e.shiftKey)) return; if(!(e.ctrlKey && e.metaKey && e.shiftKey)) return;
const LEFTARROW_KEY = 37; const LEFTARROW_KEY = 37;
@@ -420,7 +408,11 @@ const Editor = createClass({
}, },
//Called when there are changes to the editor's dimensions //Called when there are changes to the editor's dimensions
update : function(){}, update : function(){
const snipHeight = document.querySelector('.editor > .snippetBar').offsetHeight;
if(snipHeight !== this.state.snippetbarHeight)
this.setState({ snippetbarHeight: snipHeight });
},
updateEditorTheme : function(newTheme){ updateEditorTheme : function(newTheme){
window.localStorage.setItem(EDITOR_THEME_KEY, newTheme); window.localStorage.setItem(EDITOR_THEME_KEY, newTheme);
@@ -445,7 +437,7 @@ const Editor = createClass({
onChange={this.props.onBrewChange('text')} onChange={this.props.onBrewChange('text')}
editorTheme={this.state.editorTheme} editorTheme={this.state.editorTheme}
rerenderParent={this.rerenderParent} rerenderParent={this.rerenderParent}
style={{ height: `calc(100% - ${this.state.snippetBarHeight}px)` }} /> style={{ height: `calc(100% - ${this.state.snippetbarHeight}px)` }} />
</>; </>;
} }
if(this.isStyle()){ if(this.isStyle()){
@@ -459,7 +451,7 @@ const Editor = createClass({
enableFolding={true} enableFolding={true}
editorTheme={this.state.editorTheme} editorTheme={this.state.editorTheme}
rerenderParent={this.rerenderParent} rerenderParent={this.rerenderParent}
style={{ height: `calc(100% - ${this.state.snippetBarHeight}px)` }} /> style={{ height: `calc(100% - ${this.state.snippetbarHeight}px)` }} />
</>; </>;
} }
if(this.isMeta()){ if(this.isMeta()){
@@ -476,6 +468,7 @@ const Editor = createClass({
userThemes={this.props.userThemes}/> userThemes={this.props.userThemes}/>
</>; </>;
} }
if(this.isSnip()){ if(this.isSnip()){
if(!this.props.brew.snippets) { this.props.brew.snippets = DEFAULT_SNIPPET_TEXT; } if(!this.props.brew.snippets) { this.props.brew.snippets = DEFAULT_SNIPPET_TEXT; }
return <> return <>
@@ -488,7 +481,7 @@ const Editor = createClass({
enableFolding={true} enableFolding={true}
editorTheme={this.state.editorTheme} editorTheme={this.state.editorTheme}
rerenderParent={this.rerenderParent} rerenderParent={this.rerenderParent}
style={{ height: `calc(100% -${this.state.snippetBarHeight}px)` }} /> style={{ height: `calc(100% - ${this.state.snippetbarHeight}px)` }} />
</>; </>;
} }
}, },

View File

@@ -14,7 +14,7 @@
.snippets { .snippets {
display : flex; display : flex;
justify-content : flex-start; justify-content : flex-start;
min-width : 499.35px; //must be controlled every time an item is added, must be hardcoded for the wrapping as it is applied min-width : 432.18px; //must be controlled every time an item is added, must be hardcoded for the wrapping as it is applied
} }
.editors { .editors {
@@ -237,7 +237,7 @@
} }
} }
@container editor (width < 750px) { @container editor (width < 683px) {
.snippetBar { .snippetBar {
.editors { .editors {
flex : 1; flex : 1;

View File

@@ -1,6 +1,6 @@
const React = require('react'); const React = require('react');
const createClass = require('create-react-class'); const createClass = require('create-react-class');
const Nav = require('client/homebrew/navbar/nav.jsx'); const Nav = require('naturalcrit/nav/nav.jsx');
const request = require('superagent'); const request = require('superagent');
const Account = createClass({ const Account = createClass({
@@ -70,7 +70,7 @@ const Account = createClass({
{global.account.username} {global.account.username}
</Nav.item> </Nav.item>
<Nav.item <Nav.item
href={`/user/${encodeURIComponent(global.account.username)}`} href={`/user/${encodeURI(global.account.username)}`}
color='yellow' color='yellow'
icon='fas fa-beer' icon='fas fa-beer'
> >

View File

@@ -1,6 +1,6 @@
require('./error-navitem.less'); require('./error-navitem.less');
const React = require('react'); const React = require('react');
const Nav = require('client/homebrew/navbar/nav.jsx'); const Nav = require('naturalcrit/nav/nav.jsx');
const ErrorNavItem = ({ error = '', clearError })=>{ const ErrorNavItem = ({ error = '', clearError })=>{
const response = error.response; const response = error.response;

View File

@@ -1,7 +1,7 @@
const React = require('react'); const React = require('react');
const dedent = require('dedent-tabs').default; const dedent = require('dedent-tabs').default;
const Nav = require('client/homebrew/navbar/nav.jsx'); const Nav = require('naturalcrit/nav/nav.jsx');
module.exports = function(props){ module.exports = function(props){
return <Nav.dropdown> return <Nav.dropdown>

View File

@@ -2,7 +2,7 @@ const React = require('react');
const createClass = require('create-react-class'); const createClass = require('create-react-class');
const Moment = require('moment'); const Moment = require('moment');
const Nav = require('client/homebrew/navbar/nav.jsx'); const Nav = require('naturalcrit/nav/nav.jsx');
const MetadataNav = createClass({ const MetadataNav = createClass({
@@ -32,7 +32,7 @@ const MetadataNav = createClass({
return <> return <>
{this.props.brew.authors.map((author, idx, arr)=>{ {this.props.brew.authors.map((author, idx, arr)=>{
const spacer = arr.length - 1 == idx ? <></> : <span>, </span>; const spacer = arr.length - 1 == idx ? <></> : <span>, </span>;
return <span key={idx}><a className='userPageLink' href={`/user/${encodeURIComponent(author)}`}>{author}</a>{spacer}</span>; return <span key={idx}><a className='userPageLink' href={`/user/${author}`}>{author}</a>{spacer}</span>;
})} })}
</>; </>;
}, },

View File

@@ -2,7 +2,7 @@ require('./navbar.less');
const React = require('react'); const React = require('react');
const createClass = require('create-react-class'); const createClass = require('create-react-class');
const Nav = require('client/homebrew/navbar/nav.jsx'); const Nav = require('naturalcrit/nav/nav.jsx');
const PatreonNavItem = require('./patreon.navitem.jsx'); const PatreonNavItem = require('./patreon.navitem.jsx');
const Navbar = createClass({ const Navbar = createClass({

View File

@@ -1,18 +1,21 @@
const React = require('react'); const React = require('react');
const _ = require('lodash'); const _ = require('lodash');
const Nav = require('client/homebrew/navbar/nav.jsx'); const Nav = require('naturalcrit/nav/nav.jsx');
const { splitTextStyleAndMetadata } = require('../../../shared/helpers.js'); // Importing the function from helpers.js const { splitTextStyleAndMetadata } = require('../../../shared/helpers.js'); // Importing the function from helpers.js
const BREWKEY = 'HB_newPage_content'; const BREWKEY = 'homebrewery-new';
const STYLEKEY = 'HB_newPage_style'; const STYLEKEY = 'homebrewery-new-style';
const METAKEY = 'HB_newPage_meta'; const METAKEY = 'homebrewery-new-meta';
const NewBrew = ()=>{ const NewBrew = ()=>{
const handleFileChange = (e)=>{ const handleFileChange = (e)=>{
const file = e.target.files[0]; const file = e.target.files[0];
if(!file) return; if(!file) return;
if(!confirmLocalStorageChange()) return; const currentNew = localStorage.getItem(BREWKEY);
if(currentNew && !confirm(
`You have some text in the new brew space, if you load a file that text will be lost, are you sure you want to load the file?`
)) return;
const reader = new FileReader(); const reader = new FileReader();
reader.onload = (e)=>{ reader.onload = (e)=>{
@@ -34,35 +37,12 @@ const NewBrew = ()=>{
alert(`This file is invalid: ${!type ? 'Missing file extension' :`.${type} files are not supported`}. Only .txt files exported from the Homebrewery are allowed.`); alert(`This file is invalid: ${!type ? 'Missing file extension' :`.${type} files are not supported`}. Only .txt files exported from the Homebrewery are allowed.`);
console.log(file); console.log(file);
}; };
reader.readAsText(file); reader.readAsText(file);
}; };
const confirmLocalStorageChange = ()=>{
const currentText = localStorage.getItem(BREWKEY);
const currentStyle = localStorage.getItem(STYLEKEY);
const currentMeta = localStorage.getItem(METAKEY);
// TRUE if no data in any local storage key
// TRUE if data in any local storage key AND approval given
// FALSE if data in any local storage key AND approval declined
return (!(currentText || currentStyle || currentMeta) || confirm(
`You have made changes in the new brew space. If you continue, that information will be PERMANENTLY LOST.\nAre you sure you wish to continue?`
));
};
const clearLocalStorage = ()=>{
if(!confirmLocalStorageChange()) return;
localStorage.removeItem(BREWKEY);
localStorage.removeItem(STYLEKEY);
localStorage.removeItem(METAKEY);
window.location.href = '/new';
return;
};
return ( return (
<Nav.dropdown> <Nav.dropdown>
@@ -70,31 +50,24 @@ const NewBrew = ()=>{
className='new' className='new'
color='purple' color='purple'
icon='fa-solid fa-plus-square'> icon='fa-solid fa-plus-square'>
new new
</Nav.item> </Nav.item>
<Nav.item <Nav.item
className='new' className='fromBlank'
href='/new' href='/new'
newTab={true} newTab={true}
color='purple' color='purple'
icon='fa-solid fa-file'> icon='fa-solid fa-file'>
resume draft from blank
</Nav.item>
<Nav.item
className='fromBlank'
newTab={true}
color='yellow'
icon='fa-solid fa-file-circle-plus'
onClick={()=>{ clearLocalStorage(); }}>
from blank
</Nav.item> </Nav.item>
<Nav.item <Nav.item
className='fromFile' className='fromFile'
color='green' color='purple'
icon='fa-solid fa-upload' icon='fa-solid fa-upload'
onClick={()=>{ document.getElementById('uploadTxt').click(); }}> onClick={()=>{ document.getElementById('uploadTxt').click(); }}>
<input id='uploadTxt' className='newFromLocal' type='file' onChange={handleFileChange} style={{ display: 'none' }} /> <input id='uploadTxt' className='newFromLocal' type='file' onChange={handleFileChange} style={{ display: 'none' }} />
from file from file
</Nav.item> </Nav.item>
</Nav.dropdown> </Nav.dropdown>
); );

View File

@@ -1,5 +1,5 @@
const React = require('react'); const React = require('react');
const Nav = require('client/homebrew/navbar/nav.jsx'); const Nav = require('naturalcrit/nav/nav.jsx');
module.exports = function(props){ module.exports = function(props){
return <Nav.item return <Nav.item

View File

@@ -1,5 +1,5 @@
const React = require('react'); const React = require('react');
const Nav = require('client/homebrew/navbar/nav.jsx'); const Nav = require('naturalcrit/nav/nav.jsx');
const { printCurrentBrew } = require('../../../shared/helpers.js'); const { printCurrentBrew } = require('../../../shared/helpers.js');
module.exports = function(){ module.exports = function(){

View File

@@ -3,7 +3,7 @@ const createClass = require('create-react-class');
const _ = require('lodash'); const _ = require('lodash');
const Moment = require('moment'); const Moment = require('moment');
const Nav = require('client/homebrew/navbar/nav.jsx'); const Nav = require('naturalcrit/nav/nav.jsx');
const EDIT_KEY = 'HB_nav_recentlyEdited'; const EDIT_KEY = 'HB_nav_recentlyEdited';
const VIEW_KEY = 'HB_nav_recentlyViewed'; const VIEW_KEY = 'HB_nav_recentlyViewed';

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import dedent from 'dedent-tabs'; import dedent from 'dedent-tabs';
import Nav from 'client/homebrew/navbar/nav.jsx'; import Nav from 'naturalcrit/nav/nav.jsx';
const getShareId = (brew)=>( const getShareId = (brew)=>(
brew.googleId && !brew.stubbed brew.googleId && !brew.stubbed

View File

@@ -1,6 +1,6 @@
const React = require('react'); const React = require('react');
const Nav = require('client/homebrew/navbar/nav.jsx'); const Nav = require('naturalcrit/nav/nav.jsx');
module.exports = function (props) { module.exports = function (props) {
return ( return (

View File

@@ -1,7 +1,7 @@
const React = require('react'); const React = require('react');
const moment = require('moment'); const moment = require('moment');
const UIPage = require('../basePages/uiPage/uiPage.jsx'); const UIPage = require('../basePages/uiPage/uiPage.jsx');
const NaturalCritIcon = require('client/components/svg/naturalcrit-d20.svg.jsx'); const NaturalCritIcon = require('naturalcrit/svg/naturalcrit.svg.jsx');
let SAVEKEY = ''; let SAVEKEY = '';

View File

@@ -143,7 +143,7 @@ const BrewItem = ({
<span title="Username contained an email address; hidden to protect user's privacy"> <span title="Username contained an email address; hidden to protect user's privacy">
{author} {author}
</span> </span>
) : (<a href={`/user/${encodeURIComponent(author)}`}>{author}</a>)} ) : (<a href={`/user/${author}`}>{author}</a>)}
{index < brew.authors.length - 1 && ', '} {index < brew.authors.length - 1 && ', '}
</React.Fragment> </React.Fragment>
))} ))}

View File

@@ -2,12 +2,12 @@ require('./uiPage.less');
const React = require('react'); const React = require('react');
const createClass = require('create-react-class'); const createClass = require('create-react-class');
const Nav = require('client/homebrew/navbar/nav.jsx'); const Nav = require('naturalcrit/nav/nav.jsx');
const Navbar = require('client/homebrew/navbar/navbar.jsx'); const Navbar = require('../../../navbar/navbar.jsx');
const NewBrewItem = require('client/homebrew/navbar/newbrew.navitem.jsx'); const NewBrewItem = require('../../../navbar/newbrew.navitem.jsx');
const HelpNavItem = require('client/homebrew/navbar/help.navitem.jsx'); const HelpNavItem = require('../../../navbar/help.navitem.jsx');
const RecentNavItem = require('client/homebrew/navbar/recent.navitem.jsx').both; const RecentNavItem = require('../../../navbar/recent.navitem.jsx').both;
const Account = require('client/homebrew/navbar/account.navitem.jsx'); const Account = require('../../../navbar/account.navitem.jsx');
const UIPage = createClass({ const UIPage = createClass({

View File

@@ -4,7 +4,7 @@ import './editPage.less';
// Common imports // Common imports
import React, { useState, useEffect, useRef } from 'react'; import React, { useState, useEffect, useRef } from 'react';
import request from '../../utils/request-middleware.js'; import request from '../../utils/request-middleware.js';
import Markdown from 'markdown.js'; import Markdown from 'naturalcrit/markdown.js';
import _ from 'lodash'; import _ from 'lodash';
import { DEFAULT_BREW_LOAD } from '../../../../server/brewDefaults.js'; import { DEFAULT_BREW_LOAD } from '../../../../server/brewDefaults.js';
@@ -14,15 +14,15 @@ import SplitPane from 'client/components/splitPane/splitPane.jsx';
import Editor from '../../editor/editor.jsx'; import Editor from '../../editor/editor.jsx';
import BrewRenderer from '../../brewRenderer/brewRenderer.jsx'; import BrewRenderer from '../../brewRenderer/brewRenderer.jsx';
import Nav from 'client/homebrew/navbar/nav.jsx'; import Nav from 'naturalcrit/nav/nav.jsx';
import Navbar from 'client/homebrew/navbar/navbar.jsx'; import Navbar from '../../navbar/navbar.jsx';
import NewBrewItem from 'client/homebrew/navbar/newbrew.navitem.jsx'; import NewBrewItem from '../../navbar/newbrew.navitem.jsx';
import AccountNavItem from 'client/homebrew/navbar/account.navitem.jsx'; import AccountNavItem from '../../navbar/account.navitem.jsx';
import ErrorNavItem from 'client/homebrew/navbar/error-navitem.jsx'; import ErrorNavItem from '../../navbar/error-navitem.jsx';
import HelpNavItem from 'client/homebrew/navbar/help.navitem.jsx'; import HelpNavItem from '../../navbar/help.navitem.jsx';
import VaultNavItem from 'client/homebrew/navbar/vault.navitem.jsx'; import VaultNavItem from '../../navbar/vault.navitem.jsx';
import PrintNavItem from 'client/homebrew/navbar/print.navitem.jsx'; import PrintNavItem from '../../navbar/print.navitem.jsx';
import { both as RecentNavItem } from 'client/homebrew/navbar/recent.navitem.jsx'; import { both as RecentNavItem } from '../../navbar/recent.navitem.jsx';
// Page specific imports // Page specific imports
import { Meta } from 'vitreum/headtags'; import { Meta } from 'vitreum/headtags';
@@ -30,7 +30,7 @@ import { md5 } from 'hash-wasm';
import { gzipSync, strToU8 } from 'fflate'; import { gzipSync, strToU8 } from 'fflate';
import { makePatches, stringifyPatches } from '@sanity/diff-match-patch'; import { makePatches, stringifyPatches } from '@sanity/diff-match-patch';
import ShareNavItem from 'client/homebrew/navbar/share.navitem.jsx'; import ShareNavItem from '../../navbar/share.navitem.jsx';
import LockNotification from './lockNotification/lockNotification.jsx'; import LockNotification from './lockNotification/lockNotification.jsx';
import { updateHistory, versionHistoryGarbageCollection } from '../../utils/versionHistory.js'; import { updateHistory, versionHistoryGarbageCollection } from '../../utils/versionHistory.js';
import googleDriveIcon from '../../googleDrive.svg'; import googleDriveIcon from '../../googleDrive.svg';
@@ -119,10 +119,6 @@ const EditPage = (props)=>{
if(autoSaveEnabled) trySave(false, hasChange); if(autoSaveEnabled) trySave(false, hasChange);
}, [currentBrew]); }, [currentBrew]);
useEffect(()=>{
trySave(true);
}, [saveGoogle]);
const handleSplitMove = ()=>{ const handleSplitMove = ()=>{
editorRef.current?.update(); editorRef.current?.update();
}; };
@@ -183,6 +179,7 @@ const EditPage = (props)=>{
const toggleGoogleStorage = ()=>{ const toggleGoogleStorage = ()=>{
setSaveGoogle((prev)=>!prev); setSaveGoogle((prev)=>!prev);
setError(null); setError(null);
trySave(true);
}; };
const trySave = (immediate = false, hasChanges = true)=>{ const trySave = (immediate = false, hasChanges = true)=>{

View File

@@ -1,7 +1,7 @@
require('./errorPage.less'); require('./errorPage.less');
const React = require('react'); const React = require('react');
const UIPage = require('../basePages/uiPage/uiPage.jsx'); const UIPage = require('../basePages/uiPage/uiPage.jsx');
import Markdown from '../../../../shared/markdown.js'; import Markdown from '../../../../shared/naturalcrit/markdown.js';
const ErrorIndex = require('./errors/errorIndex.js'); const ErrorIndex = require('./errors/errorIndex.js');
const ErrorPage = ({ brew })=>{ const ErrorPage = ({ brew })=>{

View File

@@ -96,7 +96,7 @@ const errorIndex = (props)=>{
**Brew Title:** ${escape(props.brew.brewTitle) || 'Unable to show title'} **Brew Title:** ${escape(props.brew.brewTitle) || 'Unable to show title'}
**Current Authors:** ${props.brew.authors?.map((author)=>{return `[${author}](/user/${encodeURIComponent(author)})`;}).join(', ') || 'Unable to list authors'} **Current Authors:** ${props.brew.authors?.map((author)=>{return `[${author}](/user/${author})`;}).join(', ') || 'Unable to list authors'}
[Click here to be redirected to the brew's share page.](/share/${props.brew.shareId})`, [Click here to be redirected to the brew's share page.](/share/${props.brew.shareId})`,
@@ -111,7 +111,7 @@ const errorIndex = (props)=>{
**Brew Title:** ${escape(props.brew.brewTitle) || 'Unable to show title'} **Brew Title:** ${escape(props.brew.brewTitle) || 'Unable to show title'}
**Current Authors:** ${props.brew.authors?.map((author)=>{return `[${author}](/user/${encodeURIComponent(author)})`;}).join(', ') || 'Unable to list authors'} **Current Authors:** ${props.brew.authors?.map((author)=>{return `[${author}](/user/${author})`;}).join(', ') || 'Unable to list authors'}
[Click here to be redirected to the brew's share page.](/share/${props.brew.shareId})`, [Click here to be redirected to the brew's share page.](/share/${props.brew.shareId})`,
@@ -222,7 +222,7 @@ const errorIndex = (props)=>{
**Brew Title:** ${escape(props.brew.brewTitle)} **Brew Title:** ${escape(props.brew.brewTitle)}
**Brew Authors:** ${props.brew.authors?.map((author)=>{return `[${author}](/user/${encodeURIComponent(author)})`;}).join(', ') || 'Unable to list authors'}`, **Brew Authors:** ${props.brew.authors?.map((author)=>{return `[${author}](/user/${author})`;}).join(', ') || 'Unable to list authors'}`,
// ####### Admin page error ####### // ####### Admin page error #######
'52' : dedent` '52' : dedent`

View File

@@ -4,7 +4,7 @@ import './homePage.less';
// Common imports // Common imports
import React, { useState, useEffect, useRef } from 'react'; import React, { useState, useEffect, useRef } from 'react';
import request from '../../utils/request-middleware.js'; import request from '../../utils/request-middleware.js';
import Markdown from 'markdown.js'; import Markdown from 'naturalcrit/markdown.js';
import _ from 'lodash'; import _ from 'lodash';
import { DEFAULT_BREW } from '../../../../server/brewDefaults.js'; import { DEFAULT_BREW } from '../../../../server/brewDefaults.js';
@@ -14,15 +14,15 @@ import SplitPane from 'client/components/splitPane/splitPane.jsx';
import Editor from '../../editor/editor.jsx'; import Editor from '../../editor/editor.jsx';
import BrewRenderer from '../../brewRenderer/brewRenderer.jsx'; import BrewRenderer from '../../brewRenderer/brewRenderer.jsx';
import Nav from 'client/homebrew/navbar/nav.jsx'; import Nav from 'naturalcrit/nav/nav.jsx';
import Navbar from 'client/homebrew/navbar/navbar.jsx'; import Navbar from '../../navbar/navbar.jsx';
import NewBrewItem from 'client/homebrew/navbar/newbrew.navitem.jsx'; import NewBrewItem from '../../navbar/newbrew.navitem.jsx';
import AccountNavItem from 'client/homebrew/navbar/account.navitem.jsx'; import AccountNavItem from '../../navbar/account.navitem.jsx';
import ErrorNavItem from 'client/homebrew/navbar/error-navitem.jsx'; import ErrorNavItem from '../../navbar/error-navitem.jsx';
import HelpNavItem from 'client/homebrew/navbar/help.navitem.jsx'; import HelpNavItem from '../../navbar/help.navitem.jsx';
import VaultNavItem from 'client/homebrew/navbar/vault.navitem.jsx'; import VaultNavItem from '../../navbar/vault.navitem.jsx';
import PrintNavItem from 'client/homebrew/navbar/print.navitem.jsx'; import PrintNavItem from '../../navbar/print.navitem.jsx';
import { both as RecentNavItem } from 'client/homebrew/navbar/recent.navitem.jsx'; import { both as RecentNavItem } from '../../navbar/recent.navitem.jsx';
// Page specific imports // Page specific imports
import { Meta } from 'vitreum/headtags'; import { Meta } from 'vitreum/headtags';
@@ -53,9 +53,8 @@ const HomePage =(props)=>{
const [isSaving , setIsSaving] = useState(false); const [isSaving , setIsSaving] = useState(false);
const [autoSaveEnabled , setAutoSaveEnable] = useState(false); const [autoSaveEnabled , setAutoSaveEnable] = useState(false);
const editorRef = useRef(null); const editorRef = useRef(null);
const lastSavedBrew = useRef(_.cloneDeep(props.brew)); const lastSavedBrew = useRef(_.cloneDeep(props.brew));
const unsavedChangesRef = useRef(unsavedChanges);
useEffect(()=>{ useEffect(()=>{
fetchThemeBundle(setError, setThemeBundle, currentBrew.renderer, currentBrew.theme); fetchThemeBundle(setError, setThemeBundle, currentBrew.renderer, currentBrew.theme);
@@ -71,20 +70,12 @@ const HomePage =(props)=>{
}; };
document.addEventListener('keydown', handleControlKeys); document.addEventListener('keydown', handleControlKeys);
window.onbeforeunload = ()=>{
if(unsavedChangesRef.current)
return 'You have unsaved changes!';
};
return ()=>{ return ()=>{
document.removeEventListener('keydown', handleControlKeys); document.removeEventListener('keydown', handleControlKeys);
window.onbeforeunload = null;
}; };
}, []); }, []);
useEffect(()=>{
unsavedChangesRef.current = unsavedChanges;
}, [unsavedChanges]);
const save = ()=>{ const save = ()=>{
request.post('/api') request.post('/api')
.send(currentBrew) .send(currentBrew)

View File

@@ -4,7 +4,7 @@ import './newPage.less';
// Common imports // Common imports
import React, { useState, useEffect, useRef } from 'react'; import React, { useState, useEffect, useRef } from 'react';
import request from '../../utils/request-middleware.js'; import request from '../../utils/request-middleware.js';
import Markdown from 'markdown.js'; import Markdown from 'naturalcrit/markdown.js';
import _ from 'lodash'; import _ from 'lodash';
import { DEFAULT_BREW } from '../../../../server/brewDefaults.js'; import { DEFAULT_BREW } from '../../../../server/brewDefaults.js';
@@ -14,15 +14,15 @@ import SplitPane from 'client/components/splitPane/splitPane.jsx';
import Editor from '../../editor/editor.jsx'; import Editor from '../../editor/editor.jsx';
import BrewRenderer from '../../brewRenderer/brewRenderer.jsx'; import BrewRenderer from '../../brewRenderer/brewRenderer.jsx';
import Nav from 'client/homebrew/navbar/nav.jsx'; import Nav from 'naturalcrit/nav/nav.jsx';
import Navbar from 'client/homebrew/navbar/navbar.jsx'; import Navbar from '../../navbar/navbar.jsx';
import NewBrewItem from 'client/homebrew/navbar/newbrew.navitem.jsx'; import NewBrewItem from '../../navbar/newbrew.navitem.jsx';
import AccountNavItem from 'client/homebrew/navbar/account.navitem.jsx'; import AccountNavItem from '../../navbar/account.navitem.jsx';
import ErrorNavItem from 'client/homebrew/navbar/error-navitem.jsx'; import ErrorNavItem from '../../navbar/error-navitem.jsx';
import HelpNavItem from 'client/homebrew/navbar/help.navitem.jsx'; import HelpNavItem from '../../navbar/help.navitem.jsx';
import VaultNavItem from 'client/homebrew/navbar/vault.navitem.jsx'; import VaultNavItem from '../../navbar/vault.navitem.jsx';
import PrintNavItem from 'client/homebrew/navbar/print.navitem.jsx'; import PrintNavItem from '../../navbar/print.navitem.jsx';
import { both as RecentNavItem } from 'client/homebrew/navbar/recent.navitem.jsx'; import { both as RecentNavItem } from '../../navbar/recent.navitem.jsx';
// Page specific imports // Page specific imports
import { Meta } from 'vitreum/headtags'; import { Meta } from 'vitreum/headtags';
@@ -56,10 +56,6 @@ const NewPage = (props)=>{
const editorRef = useRef(null); const editorRef = useRef(null);
const lastSavedBrew = useRef(_.cloneDeep(props.brew)); const lastSavedBrew = useRef(_.cloneDeep(props.brew));
// const saveTimeout = useRef(null);
// const warnUnsavedTimeout = useRef(null);
const trySaveRef = useRef(trySave); // CTRL+S listener lives outside React and needs ref to use trySave with latest copy of brew
const unsavedChangesRef = useRef(unsavedChanges); // Similarly, onBeforeUnload lives outside React and needs ref to unsavedChanges
useEffect(()=>{ useEffect(()=>{
loadBrew(); loadBrew();
@@ -118,11 +114,6 @@ const NewPage = (props)=>{
if(autoSaveEnabled) trySave(false, hasChange); if(autoSaveEnabled) trySave(false, hasChange);
}, [currentBrew]); }, [currentBrew]);
useEffect(()=>{
trySaveRef.current = trySave;
unsavedChangesRef.current = unsavedChanges;
});
const handleSplitMove = ()=>{ const handleSplitMove = ()=>{
editorRef.current.update(); editorRef.current.update();
}; };
@@ -150,7 +141,7 @@ const NewPage = (props)=>{
} }
}; };
const trySave = async ()=>{ const save = async ()=>{
setIsSaving(true); setIsSaving(true);
const updatedBrew = { ...currentBrew }; const updatedBrew = { ...currentBrew };
@@ -199,7 +190,7 @@ const NewPage = (props)=>{
// #3 - Unsaved changes exist, click to save, show SAVE NOW // #3 - Unsaved changes exist, click to save, show SAVE NOW
if(unsavedChanges) if(unsavedChanges)
return <Nav.item className='save' onClick={trySave} color='blue' icon='fas fa-save'>save now</Nav.item>; return <Nav.item className='save' onClick={save} color='blue' icon='fas fa-save'>save now</Nav.item>;
// #4 - No unsaved changes, autosave is ON, show AUTO-SAVED // #4 - No unsaved changes, autosave is ON, show AUTO-SAVED
if(autoSaveEnabled) if(autoSaveEnabled)

View File

@@ -1,15 +1,12 @@
.newPage { .newPage {
.navItem.save { .navItem.save {
.fadeInRight();
.transition(opacity);
background-color : @orange; background-color : @orange;
transition:all 0.2s;
&:hover { background-color : @green; } &:hover { background-color : @green; }
&.neverSaved { &.neverSaved {
translate:-100%; .fadeOutRight();
opacity: 0; opacity: 0;
background-color :#333;
cursor:auto;
} }
} }
} }

View File

@@ -3,12 +3,12 @@ const React = require('react');
const { useState, useEffect, useCallback } = React; const { useState, useEffect, useCallback } = React;
const { Meta } = require('vitreum/headtags'); const { Meta } = require('vitreum/headtags');
const Nav = require('client/homebrew/navbar/nav.jsx'); const Nav = require('naturalcrit/nav/nav.jsx');
const Navbar = require('client/homebrew/navbar/navbar.jsx'); const Navbar = require('../../navbar/navbar.jsx');
const MetadataNav = require('client/homebrew/navbar/metadata.navitem.jsx'); const MetadataNav = require('../../navbar/metadata.navitem.jsx');
const PrintNavItem = require('client/homebrew/navbar/print.navitem.jsx'); const PrintNavItem = require('../../navbar/print.navitem.jsx');
const RecentNavItem = require('client/homebrew/navbar/recent.navitem.jsx').both; const RecentNavItem = require('../../navbar/recent.navitem.jsx').both;
const Account = require('client/homebrew/navbar/account.navitem.jsx'); const Account = require('../../navbar/account.navitem.jsx');
const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx'); const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx');
const { DEFAULT_BREW_LOAD } = require('../../../../server/brewDefaults.js'); const { DEFAULT_BREW_LOAD } = require('../../../../server/brewDefaults.js');

View File

@@ -4,14 +4,14 @@ const _ = require('lodash');
const ListPage = require('../basePages/listPage/listPage.jsx'); const ListPage = require('../basePages/listPage/listPage.jsx');
const Nav = require('client/homebrew/navbar/nav.jsx'); const Nav = require('naturalcrit/nav/nav.jsx');
const Navbar = require('client/homebrew/navbar/navbar.jsx'); const Navbar = require('../../navbar/navbar.jsx');
const RecentNavItem = require('client/homebrew/navbar/recent.navitem.jsx').both; const RecentNavItem = require('../../navbar/recent.navitem.jsx').both;
const Account = require('client/homebrew/navbar/account.navitem.jsx'); const Account = require('../../navbar/account.navitem.jsx');
const NewBrew = require('client/homebrew/navbar/newbrew.navitem.jsx'); const NewBrew = require('../../navbar/newbrew.navitem.jsx');
const HelpNavItem = require('client/homebrew/navbar/help.navitem.jsx'); const HelpNavItem = require('../../navbar/help.navitem.jsx');
const ErrorNavItem = require('client/homebrew/navbar/error-navitem.jsx'); const ErrorNavItem = require('../../navbar/error-navitem.jsx');
const VaultNavitem = require('client/homebrew/navbar/vault.navitem.jsx'); const VaultNavitem = require('../../navbar/vault.navitem.jsx');
const UserPage = (props)=>{ const UserPage = (props)=>{
props = { props = {

View File

@@ -5,12 +5,12 @@ require('./vaultPage.less');
const React = require('react'); const React = require('react');
const { useState, useEffect, useRef } = React; const { useState, useEffect, useRef } = React;
const Nav = require('client/homebrew/navbar/nav.jsx'); const Nav = require('naturalcrit/nav/nav.jsx');
const Navbar = require('client/homebrew/navbar/navbar.jsx'); const Navbar = require('../../navbar/navbar.jsx');
const RecentNavItem = require('client/homebrew/navbar/recent.navitem.jsx').both; const RecentNavItem = require('../../navbar/recent.navitem.jsx').both;
const Account = require('client/homebrew/navbar/account.navitem.jsx'); const Account = require('../../navbar/account.navitem.jsx');
const NewBrew = require('client/homebrew/navbar/newbrew.navitem.jsx'); const NewBrew = require('../../navbar/newbrew.navitem.jsx');
const HelpNavItem = require('client/homebrew/navbar/help.navitem.jsx'); const HelpNavItem = require('../../navbar/help.navitem.jsx');
const BrewItem = require('../basePages/listPage/brewItem/brewItem.jsx'); const BrewItem = require('../basePages/listPage/brewItem/brewItem.jsx');
const SplitPane = require('client/components/splitPane/splitPane.jsx'); const SplitPane = require('client/components/splitPane/splitPane.jsx');
const ErrorIndex = require('../errorPage/errors/errorIndex.js'); const ErrorIndex = require('../errorPage/errors/errorIndex.js');

307
package-lock.json generated
View File

@@ -1,28 +1,28 @@
{ {
"name": "homebrewery", "name": "homebrewery",
"version": "3.20.0", "version": "3.19.3",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "homebrewery", "name": "homebrewery",
"version": "3.20.0", "version": "3.19.3",
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/core": "^7.28.4", "@babel/core": "^7.28.4",
"@babel/plugin-transform-runtime": "^7.28.3", "@babel/plugin-transform-runtime": "^7.28.3",
"@babel/preset-env": "^7.28.3", "@babel/preset-env": "^7.28.3",
"@babel/preset-react": "^7.28.5", "@babel/preset-react": "^7.27.1",
"@babel/runtime": "^7.28.4", "@babel/runtime": "^7.28.4",
"@dmsnell/diff-match-patch": "^1.1.0", "@dmsnell/diff-match-patch": "^1.1.0",
"@googleapis/drive": "^19.2.0", "@googleapis/drive": "^18.0.0",
"@sanity/diff-match-patch": "^3.2.0", "@sanity/diff-match-patch": "^3.2.0",
"body-parser": "^2.2.0", "body-parser": "^2.2.0",
"classnames": "^2.5.1", "classnames": "^2.5.1",
"codemirror": "^5.65.6", "codemirror": "^5.65.6",
"cookie-parser": "^1.4.7", "cookie-parser": "^1.4.7",
"core-js": "^3.47.0", "core-js": "^3.46.0",
"cors": "^2.8.5", "cors": "^2.8.5",
"create-react-class": "^15.7.0", "create-react-class": "^15.7.0",
"dedent-tabs": "^0.10.3", "dedent-tabs": "^0.10.3",
@@ -34,29 +34,29 @@
"fs-extra": "11.3.2", "fs-extra": "11.3.2",
"hash-wasm": "^4.12.0", "hash-wasm": "^4.12.0",
"idb-keyval": "^6.2.2", "idb-keyval": "^6.2.2",
"js-yaml": "^4.1.1", "js-yaml": "^4.1.0",
"jwt-simple": "^0.5.6", "jwt-simple": "^0.5.6",
"less": "^3.13.1", "less": "^3.13.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"marked": "15.0.12", "marked": "16.4.1",
"marked-alignment-paragraphs": "^1.0.0", "marked-alignment-paragraphs": "^1.0.0",
"marked-definition-lists": "^1.0.1", "marked-definition-lists": "^1.0.1",
"marked-emoji": "^2.0.2", "marked-emoji": "^2.0.1",
"marked-extended-tables": "^2.0.1", "marked-extended-tables": "^2.0.1",
"marked-gfm-heading-id": "^4.1.3", "marked-gfm-heading-id": "^4.1.2",
"marked-nonbreaking-spaces": "^1.0.1", "marked-nonbreaking-spaces": "^1.0.1",
"marked-smartypants-lite": "^1.0.3", "marked-smartypants-lite": "^1.0.3",
"marked-subsuper-text": "^1.0.4", "marked-subsuper-text": "^1.0.4",
"marked-variables": "^1.0.4", "marked-variables": "^1.0.4",
"markedLegacy": "npm:marked@^0.3.19", "markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.30.1", "moment": "^2.30.1",
"mongoose": "^9.0.0", "mongoose": "^8.19.1",
"nanoid": "5.1.6", "nanoid": "5.1.6",
"nconf": "^0.13.0", "nconf": "^0.13.0",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-frame-component": "^4.1.3", "react-frame-component": "^4.1.3",
"react-router": "^7.9.6", "react-router": "^7.9.4",
"romans": "^3.1.0", "romans": "^3.1.0",
"sanitize-filename": "1.6.3", "sanitize-filename": "1.6.3",
"superagent": "^10.2.1", "superagent": "^10.2.1",
@@ -66,8 +66,8 @@
"devDependencies": { "devDependencies": {
"@stylistic/stylelint-plugin": "^4.0.0", "@stylistic/stylelint-plugin": "^4.0.0",
"babel-plugin-transform-import-meta": "^2.3.3", "babel-plugin-transform-import-meta": "^2.3.3",
"eslint": "^9.39.1", "eslint": "^9.37.0",
"eslint-plugin-jest": "^29.1.0", "eslint-plugin-jest": "^29.0.1",
"eslint-plugin-react": "^7.37.5", "eslint-plugin-react": "^7.37.5",
"globals": "^16.4.0", "globals": "^16.4.0",
"jest": "^30.2.0", "jest": "^30.2.0",
@@ -1427,9 +1427,9 @@
} }
}, },
"node_modules/@babel/plugin-transform-react-display-name": { "node_modules/@babel/plugin-transform-react-display-name": {
"version": "7.28.0", "version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.28.0.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.27.1.tgz",
"integrity": "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==", "integrity": "sha512-p9+Vl3yuHPmkirRrg021XiP+EETmPMQTLr6Ayjj85RLNEbb3Eya/4VI0vAdzQG9SEAl2Lnt7fy5lZyMzjYoZQQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-plugin-utils": "^7.27.1" "@babel/helper-plugin-utils": "^7.27.1"
@@ -1795,14 +1795,14 @@
} }
}, },
"node_modules/@babel/preset-react": { "node_modules/@babel/preset-react": {
"version": "7.28.5", "version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.28.5.tgz", "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.27.1.tgz",
"integrity": "sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ==", "integrity": "sha512-oJHWh2gLhU9dW9HHr42q0cI0/iHHXTLGe39qvpAZZzagHy0MzYLCnCVV0symeRvzmjHyVU7mw2K06E6u/JwbhA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1",
"@babel/helper-validator-option": "^7.27.1", "@babel/helper-validator-option": "^7.27.1",
"@babel/plugin-transform-react-display-name": "^7.28.0", "@babel/plugin-transform-react-display-name": "^7.27.1",
"@babel/plugin-transform-react-jsx": "^7.27.1", "@babel/plugin-transform-react-jsx": "^7.27.1",
"@babel/plugin-transform-react-jsx-development": "^7.27.1", "@babel/plugin-transform-react-jsx-development": "^7.27.1",
"@babel/plugin-transform-react-pure-annotations": "^7.27.1" "@babel/plugin-transform-react-pure-annotations": "^7.27.1"
@@ -2258,9 +2258,9 @@
} }
}, },
"node_modules/@eslint/js": { "node_modules/@eslint/js": {
"version": "9.39.1", "version": "9.39.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.0.tgz",
"integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", "integrity": "sha512-BIhe0sW91JGPiaF1mOuPy5v8NflqfjIcDNpC+LbW9f609WVRX1rArrhi6Z2ymvrAry9jw+5POTj4t2t62o8Bmw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -2295,9 +2295,9 @@
} }
}, },
"node_modules/@googleapis/drive": { "node_modules/@googleapis/drive": {
"version": "19.2.0", "version": "18.0.0",
"resolved": "https://registry.npmjs.org/@googleapis/drive/-/drive-19.2.0.tgz", "resolved": "https://registry.npmjs.org/@googleapis/drive/-/drive-18.0.0.tgz",
"integrity": "sha512-XzhQ+CNwW54umLecZLzQ5Q2RborJD1+u2YzJIT/BOpne+VJfsCyxWVG0nxYQmcGdiFXJPeW5+V3sdP/A/nt3eA==", "integrity": "sha512-nk4TirsHttwZSOjBEBjltCPDKUqwFso59G3WitNE+EGNVSVseSEq981f8Dmjq2ah0/fk3i206wuCU4PUCwcoTQ==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"googleapis-common": "^8.0.0" "googleapis-common": "^8.0.0"
@@ -3309,9 +3309,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/whatwg-url": { "node_modules/@types/whatwg-url": {
"version": "13.0.0", "version": "11.0.5",
"resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-13.0.0.tgz", "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz",
"integrity": "sha512-N8WXpbE6Wgri7KUSvrmQcqrMllKZ9uxkYWMt+mCSGwNc0Hsw9VQTW7ApqI4XNrx6/SaM2QQJCzMPDEXE058s+Q==", "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/webidl-conversions": "*" "@types/webidl-conversions": "*"
@@ -4794,12 +4794,12 @@
} }
}, },
"node_modules/bson": { "node_modules/bson": {
"version": "7.0.0", "version": "6.10.4",
"resolved": "https://registry.npmjs.org/bson/-/bson-7.0.0.tgz", "resolved": "https://registry.npmjs.org/bson/-/bson-6.10.4.tgz",
"integrity": "sha512-Kwc6Wh4lQ5OmkqqKhYGKIuELXl+EPYSCObVE6bWsp1T/cGkOCBN0I8wF/T44BiuhHyNi1mmKVPXk60d41xZ7kw==", "integrity": "sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng==",
"license": "Apache-2.0", "license": "Apache-2.0",
"engines": { "engines": {
"node": ">=20.19.0" "node": ">=16.20.1"
} }
}, },
"node_modules/buffer": { "node_modules/buffer": {
@@ -5343,9 +5343,9 @@
} }
}, },
"node_modules/core-js": { "node_modules/core-js": {
"version": "3.47.0", "version": "3.46.0",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.47.0.tgz", "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.46.0.tgz",
"integrity": "sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg==", "integrity": "sha512-vDMm9B0xnqqZ8uSBpZ8sNtRtOdmfShrvT6h2TuQGLs0Is+cR0DYbj/KWP6ALVNbWPpqA/qPLoOuppJN07humpA==",
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT", "license": "MIT",
"funding": { "funding": {
@@ -6259,9 +6259,9 @@
} }
}, },
"node_modules/eslint": { "node_modules/eslint": {
"version": "9.39.1", "version": "9.39.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.0.tgz",
"integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", "integrity": "sha512-iy2GE3MHrYTL5lrCtMZ0X1KLEKKUjmK0kzwcnefhR66txcEmXZD2YWgR5GNdcEwkNx3a0siYkSvl0vIC+Svjmg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -6271,7 +6271,7 @@
"@eslint/config-helpers": "^0.4.2", "@eslint/config-helpers": "^0.4.2",
"@eslint/core": "^0.17.0", "@eslint/core": "^0.17.0",
"@eslint/eslintrc": "^3.3.1", "@eslint/eslintrc": "^3.3.1",
"@eslint/js": "9.39.1", "@eslint/js": "9.39.0",
"@eslint/plugin-kit": "^0.4.1", "@eslint/plugin-kit": "^0.4.1",
"@humanfs/node": "^0.16.6", "@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/module-importer": "^1.0.1",
@@ -6319,9 +6319,9 @@
} }
}, },
"node_modules/eslint-plugin-jest": { "node_modules/eslint-plugin-jest": {
"version": "29.1.0", "version": "29.0.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-29.1.0.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-29.0.1.tgz",
"integrity": "sha512-LabxXbASXVjguqL+kBHTPMf3gUeSqwH4fsrEyHTY/MCs42I/p9+ctg09SJpYiD8eGaIsP6GwYr5xW6xWS9XgZg==", "integrity": "sha512-EE44T0OSMCeXhDrrdsbKAhprobKkPtJTbQz5yEktysNpHeDZTAL1SfDTNKmcFfJkY6yrQLtTKZALrD3j/Gpmiw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -8494,7 +8494,7 @@
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
"dev": true, "devOptional": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=8" "node": ">=8"
@@ -9466,9 +9466,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/js-yaml": { "node_modules/js-yaml": {
"version": "4.1.1", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"argparse": "^2.0.1" "argparse": "^2.0.1"
@@ -9691,12 +9691,12 @@
} }
}, },
"node_modules/kareem": { "node_modules/kareem": {
"version": "3.0.0", "version": "2.6.3",
"resolved": "https://registry.npmjs.org/kareem/-/kareem-3.0.0.tgz", "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz",
"integrity": "sha512-RKhaOBSPN8L7y4yAgNhDT2602G5FD6QbOIISbjN9D6mjHPeqeg7K+EB5IGSU5o81/X2Gzm3ICnAvQW3x3OP8HA==", "integrity": "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==",
"license": "Apache-2.0", "license": "Apache-2.0",
"engines": { "engines": {
"node": ">=18.0.0" "node": ">=12.0.0"
} }
}, },
"node_modules/keyv": { "node_modules/keyv": {
@@ -9996,15 +9996,15 @@
} }
}, },
"node_modules/marked": { "node_modules/marked": {
"version": "15.0.12", "version": "16.4.1",
"resolved": "https://registry.npmjs.org/marked/-/marked-15.0.12.tgz", "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.1.tgz",
"integrity": "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==", "integrity": "sha512-ntROs7RaN3EvWfy3EZi14H4YxmT6A5YvywfhO+0pm+cH/dnSQRmdAmoFIc3B9aiwTehyk7pESH4ofyBY+V5hZg==",
"license": "MIT", "license": "MIT",
"bin": { "bin": {
"marked": "bin/marked.js" "marked": "bin/marked.js"
}, },
"engines": { "engines": {
"node": ">= 18" "node": ">= 20"
} }
}, },
"node_modules/marked-alignment-paragraphs": { "node_modules/marked-alignment-paragraphs": {
@@ -10026,12 +10026,12 @@
} }
}, },
"node_modules/marked-emoji": { "node_modules/marked-emoji": {
"version": "2.0.2", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/marked-emoji/-/marked-emoji-2.0.2.tgz", "resolved": "https://registry.npmjs.org/marked-emoji/-/marked-emoji-2.0.1.tgz",
"integrity": "sha512-EFnLQn4wTyf+6pXfptkm83Z2mt3VbdEYedHBAsDpwUas5n5satsj42RGqAijBpmetgGerI1EzUuzf7NIccINUQ==", "integrity": "sha512-P+nRr02dD+yPOFhtGdaVBzp0qzwlksI2f5GumIdHW/3UadzJ5sVi78CZikiSLr9PmdtUOZodZUBNIO6k38pDMQ==",
"license": "MIT", "license": "MIT",
"peerDependencies": { "peerDependencies": {
"marked": ">=4 <18" "marked": ">=4 <17"
} }
}, },
"node_modules/marked-extended-tables": { "node_modules/marked-extended-tables": {
@@ -10044,15 +10044,15 @@
} }
}, },
"node_modules/marked-gfm-heading-id": { "node_modules/marked-gfm-heading-id": {
"version": "4.1.3", "version": "4.1.2",
"resolved": "https://registry.npmjs.org/marked-gfm-heading-id/-/marked-gfm-heading-id-4.1.3.tgz", "resolved": "https://registry.npmjs.org/marked-gfm-heading-id/-/marked-gfm-heading-id-4.1.2.tgz",
"integrity": "sha512-aR0i63LmFbuxU/gAgrgz1Ir+8HK6zAIFXMlckeKHpV+qKbYaOP95L4Ux5Gi+sKmCZU5qnN2rdKpvpb7PnUBIWg==", "integrity": "sha512-EQ1WiEGHJh0C8viU+hbXbhHyWTDgEia2i96fiSemm2wdYER6YBw/9QI5TB6YFTqFfmMOxBFXPcPJtlgD0fVV2w==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"github-slugger": "^2.0.0" "github-slugger": "^2.0.0"
}, },
"peerDependencies": { "peerDependencies": {
"marked": ">=13 <18" "marked": ">=13 <17"
} }
}, },
"node_modules/marked-nonbreaking-spaces": { "node_modules/marked-nonbreaking-spaces": {
@@ -10426,76 +10426,119 @@
} }
}, },
"node_modules/mongodb-connection-string-url": { "node_modules/mongodb-connection-string-url": {
"version": "7.0.0", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-7.0.0.tgz", "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.2.tgz",
"integrity": "sha512-irhhjRVLE20hbkRl4zpAYLnDMM+zIZnp0IDB9akAFFUZp/3XdOfwwddc7y6cNvF2WCEtfTYRwYbIfYa2kVY0og==", "integrity": "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@types/whatwg-url": "^13.0.0", "@types/whatwg-url": "^11.0.2",
"whatwg-url": "^14.1.0" "whatwg-url": "^14.1.0 || ^13.0.0"
},
"engines": {
"node": ">=20.19.0"
} }
}, },
"node_modules/mongoose": { "node_modules/mongoose": {
"version": "9.0.0", "version": "8.19.2",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-9.0.0.tgz", "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.19.2.tgz",
"integrity": "sha512-J6wTGC8/hSFpy9K6kPbKDnBNoUcX4iOGCasUrRzlSKdwdVNxdscLA4oHKOQwJlHqh/TxDNg+Uzg6koCyCKP0wA==", "integrity": "sha512-ww2T4dBV+suCbOfG5YPwj9pLCfUVyj8FEA1D3Ux1HHqutpLxGyOYEPU06iPRBW4cKr3PJfOSYsIpHWPTkz5zig==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"kareem": "3.0.0", "bson": "^6.10.4",
"mongodb": "~7.0", "kareem": "2.6.3",
"mongodb": "~6.20.0",
"mpath": "0.9.0", "mpath": "0.9.0",
"mquery": "6.0.0", "mquery": "5.0.0",
"ms": "2.1.3", "ms": "2.1.3",
"sift": "17.1.3" "sift": "17.1.3"
}, },
"engines": { "engines": {
"node": ">=20.19.0" "node": ">=16.20.1"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
"url": "https://opencollective.com/mongoose" "url": "https://opencollective.com/mongoose"
} }
}, },
"node_modules/mongoose/node_modules/gcp-metadata": { "node_modules/mongoose/node_modules/agent-base": {
"version": "7.0.1", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-7.0.1.tgz", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
"integrity": "sha512-UcO3kefx6dCcZkgcTGgVOTFb7b1LlQ02hY1omMjjrrBzkajRMCFgYOjs7J71WqnuG1k2b+9ppGL7FsOfhZMQKQ==", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"debug": "4"
},
"engines": {
"node": ">= 6.0.0"
}
},
"node_modules/mongoose/node_modules/gaxios": {
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.3.tgz",
"integrity": "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==",
"license": "Apache-2.0", "license": "Apache-2.0",
"optional": true, "optional": true,
"peer": true, "peer": true,
"dependencies": { "dependencies": {
"gaxios": "^7.0.0", "extend": "^3.0.2",
"google-logging-utils": "^1.0.0", "https-proxy-agent": "^5.0.0",
"is-stream": "^2.0.0",
"node-fetch": "^2.6.9"
},
"engines": {
"node": ">=12"
}
},
"node_modules/mongoose/node_modules/gcp-metadata": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.3.0.tgz",
"integrity": "sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==",
"license": "Apache-2.0",
"optional": true,
"peer": true,
"dependencies": {
"gaxios": "^5.0.0",
"json-bigint": "^1.0.0" "json-bigint": "^1.0.0"
}, },
"engines": { "engines": {
"node": ">=18" "node": ">=12"
}
},
"node_modules/mongoose/node_modules/https-proxy-agent": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"agent-base": "6",
"debug": "4"
},
"engines": {
"node": ">= 6"
} }
}, },
"node_modules/mongoose/node_modules/mongodb": { "node_modules/mongoose/node_modules/mongodb": {
"version": "7.0.0", "version": "6.20.0",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-7.0.0.tgz", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.20.0.tgz",
"integrity": "sha512-vG/A5cQrvGGvZm2mTnCSz1LUcbOPl83hfB6bxULKQ8oFZauyox/2xbZOoGNl+64m8VBrETkdGCDBdOsCr3F3jg==", "integrity": "sha512-Tl6MEIU3K4Rq3TSHd+sZQqRBoGlFsOgNrH5ltAcFBV62Re3Fd+FcaVf8uSEQFOJ51SDowDVttBTONMfoYWrWlQ==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@mongodb-js/saslprep": "^1.3.0", "@mongodb-js/saslprep": "^1.3.0",
"bson": "^7.0.0", "bson": "^6.10.4",
"mongodb-connection-string-url": "^7.0.0" "mongodb-connection-string-url": "^3.0.2"
}, },
"engines": { "engines": {
"node": ">=20.19.0" "node": ">=16.20.1"
}, },
"peerDependencies": { "peerDependencies": {
"@aws-sdk/credential-providers": "^3.806.0", "@aws-sdk/credential-providers": "^3.188.0",
"@mongodb-js/zstd": "^7.0.0", "@mongodb-js/zstd": "^1.1.0 || ^2.0.0",
"gcp-metadata": "^7.0.1", "gcp-metadata": "^5.2.0",
"kerberos": "^7.0.0", "kerberos": "^2.0.1",
"mongodb-client-encryption": ">=7.0.0 <7.1.0", "mongodb-client-encryption": ">=6.0.0 <7",
"snappy": "^7.3.2", "snappy": "^7.3.2",
"socks": "^2.8.6" "socks": "^2.7.1"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"@aws-sdk/credential-providers": { "@aws-sdk/credential-providers": {
@@ -10521,6 +10564,56 @@
} }
} }
}, },
"node_modules/mongoose/node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/mongoose/node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/mongoose/node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
"license": "BSD-2-Clause",
"optional": true,
"peer": true
},
"node_modules/mongoose/node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/mpath": { "node_modules/mpath": {
"version": "0.9.0", "version": "0.9.0",
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz",
@@ -10531,12 +10624,15 @@
} }
}, },
"node_modules/mquery": { "node_modules/mquery": {
"version": "6.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/mquery/-/mquery-6.0.0.tgz", "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz",
"integrity": "sha512-b2KQNsmgtkscfeDgkYMcWGn9vZI9YoXh802VDEwE6qc50zxBFQ0Oo8ROkawbPAsXCY1/Z1yp0MagqsZStPWJjw==", "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==",
"license": "MIT", "license": "MIT",
"dependencies": {
"debug": "4.x"
},
"engines": { "engines": {
"node": ">=20.19.0" "node": ">=14.0.0"
} }
}, },
"node_modules/ms": { "node_modules/ms": {
@@ -11969,9 +12065,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/react-router": { "node_modules/react-router": {
"version": "7.9.6", "version": "7.9.5",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.6.tgz", "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.5.tgz",
"integrity": "sha512-Y1tUp8clYRXpfPITyuifmSoE2vncSME18uVLgaqyxh9H35JWpIfzHo+9y3Fzh5odk/jxPW29IgLgzcdwxGqyNA==", "integrity": "sha512-JmxqrnBZ6E9hWmf02jzNn9Jm3UqyeimyiwzD69NjxGySG6lIz/1LVPsoTCwN7NBX2XjCEa1LIX5EMz1j2b6u6A==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"cookie": "^1.0.1", "cookie": "^1.0.1",
@@ -14646,8 +14742,7 @@
}, },
"node_modules/vitreum": { "node_modules/vitreum": {
"version": "6.0.4", "version": "6.0.4",
"resolved": "git+https://git@github.com/calculuschild/vitreum.git#929c351881c4229550374421c7e2890a94f4dca7", "resolved": "git+https://git@github.com/calculuschild/vitreum.git#9d55fd6fb7e85e7070de798c4f9d5b983c1b7dba",
"integrity": "sha512-dclfZIgvZU4pOeju1U7CjfGcAMNY+HwhYxF5O1cB6j9EtBrUXQh5+8XlYvNrw2XIcjWIxWcWaCpAQgJxKssfbQ==",
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {

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.20.0", "version": "3.19.3",
"type": "module", "type": "module",
"engines": { "engines": {
"npm": "^10.8.x", "npm": "^10.8.x",
@@ -44,9 +44,7 @@
"phb": "node --experimental-require-module scripts/phb.js", "phb": "node --experimental-require-module scripts/phb.js",
"prod": "set NODE_ENV=production && npm run build", "prod": "set NODE_ENV=production && npm run build",
"postinstall": "npm run build", "postinstall": "npm run build",
"start": "node --experimental-require-module server.js", "start": "node --experimental-require-module server.js"
"docker:build": "docker build -t ${DOCKERID}/homebrewery:$npm_package_version .",
"docker:publish": "docker login && docker push ${DOCKERID}/homebrewery:$npm_package_version"
}, },
"author": "stolksdorf", "author": "stolksdorf",
"license": "MIT", "license": "MIT",
@@ -88,16 +86,16 @@
"@babel/core": "^7.28.4", "@babel/core": "^7.28.4",
"@babel/plugin-transform-runtime": "^7.28.3", "@babel/plugin-transform-runtime": "^7.28.3",
"@babel/preset-env": "^7.28.3", "@babel/preset-env": "^7.28.3",
"@babel/preset-react": "^7.28.5", "@babel/preset-react": "^7.27.1",
"@babel/runtime": "^7.28.4", "@babel/runtime": "^7.28.4",
"@dmsnell/diff-match-patch": "^1.1.0", "@dmsnell/diff-match-patch": "^1.1.0",
"@googleapis/drive": "^19.2.0", "@googleapis/drive": "^18.0.0",
"@sanity/diff-match-patch": "^3.2.0", "@sanity/diff-match-patch": "^3.2.0",
"body-parser": "^2.2.0", "body-parser": "^2.2.0",
"classnames": "^2.5.1", "classnames": "^2.5.1",
"codemirror": "^5.65.6", "codemirror": "^5.65.6",
"cookie-parser": "^1.4.7", "cookie-parser": "^1.4.7",
"core-js": "^3.47.0", "core-js": "^3.46.0",
"cors": "^2.8.5", "cors": "^2.8.5",
"create-react-class": "^15.7.0", "create-react-class": "^15.7.0",
"dedent-tabs": "^0.10.3", "dedent-tabs": "^0.10.3",
@@ -109,29 +107,29 @@
"fs-extra": "11.3.2", "fs-extra": "11.3.2",
"hash-wasm": "^4.12.0", "hash-wasm": "^4.12.0",
"idb-keyval": "^6.2.2", "idb-keyval": "^6.2.2",
"js-yaml": "^4.1.1", "js-yaml": "^4.1.0",
"jwt-simple": "^0.5.6", "jwt-simple": "^0.5.6",
"less": "^3.13.1", "less": "^3.13.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"marked": "15.0.12", "marked": "16.4.1",
"marked-alignment-paragraphs": "^1.0.0", "marked-alignment-paragraphs": "^1.0.0",
"marked-definition-lists": "^1.0.1", "marked-definition-lists": "^1.0.1",
"marked-emoji": "^2.0.2", "marked-emoji": "^2.0.1",
"marked-extended-tables": "^2.0.1", "marked-extended-tables": "^2.0.1",
"marked-gfm-heading-id": "^4.1.3", "marked-gfm-heading-id": "^4.1.2",
"marked-nonbreaking-spaces": "^1.0.1", "marked-nonbreaking-spaces": "^1.0.1",
"marked-smartypants-lite": "^1.0.3", "marked-smartypants-lite": "^1.0.3",
"marked-subsuper-text": "^1.0.4", "marked-subsuper-text": "^1.0.4",
"marked-variables": "^1.0.4", "marked-variables": "^1.0.4",
"markedLegacy": "npm:marked@^0.3.19", "markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.30.1", "moment": "^2.30.1",
"mongoose": "^9.0.0", "mongoose": "^8.19.1",
"nanoid": "5.1.6", "nanoid": "5.1.6",
"nconf": "^0.13.0", "nconf": "^0.13.0",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-frame-component": "^4.1.3", "react-frame-component": "^4.1.3",
"react-router": "^7.9.6", "react-router": "^7.9.4",
"romans": "^3.1.0", "romans": "^3.1.0",
"sanitize-filename": "1.6.3", "sanitize-filename": "1.6.3",
"superagent": "^10.2.1", "superagent": "^10.2.1",
@@ -141,8 +139,8 @@
"devDependencies": { "devDependencies": {
"@stylistic/stylelint-plugin": "^4.0.0", "@stylistic/stylelint-plugin": "^4.0.0",
"babel-plugin-transform-import-meta": "^2.3.3", "babel-plugin-transform-import-meta": "^2.3.3",
"eslint": "^9.39.1", "eslint": "^9.37.0",
"eslint-plugin-jest": "^29.1.0", "eslint-plugin-jest": "^29.0.1",
"eslint-plugin-react": "^7.37.5", "eslint-plugin-react": "^7.37.5",
"globals": "^16.4.0", "globals": "^16.4.0",
"jest": "^30.2.0", "jest": "^30.2.0",

View File

@@ -4,7 +4,7 @@ import { model as HomebrewModel } from './homebrew.model.js';
import express from 'express'; import express from 'express';
import zlib from 'zlib'; import zlib from 'zlib';
import GoogleActions from './googleActions.js'; import GoogleActions from './googleActions.js';
import Markdown from '../shared/markdown.js'; import Markdown from '../shared/naturalcrit/markdown.js';
import yaml from 'js-yaml'; import yaml from 'js-yaml';
import asyncHandler from 'express-async-handler'; import asyncHandler from 'express-async-handler';
import { nanoid } from 'nanoid'; import { nanoid } from 'nanoid';

View File

@@ -3,7 +3,7 @@ const React = require('react');
const createClass = require('create-react-class'); const createClass = require('create-react-class');
const _ = require('lodash'); const _ = require('lodash');
import Dialog from '../dialog.jsx'; import Dialog from '../../../client/components/dialog.jsx';
const RenderWarnings = createClass({ const RenderWarnings = createClass({
displayName : 'RenderWarnings', displayName : 'RenderWarnings',
@@ -25,7 +25,7 @@ const RenderWarnings = createClass({
if(!isChrome){ if(!isChrome){
return <li key='chrome'> return <li key='chrome'>
<em>Built for Chrome </em> <br /> <em>Built for Chrome </em> <br />
Other browsers have not been tested for compatibility. If you Other browsers have not been tested for compatiblilty. If you
experience issues with your document not rendering or printing experience issues with your document not rendering or printing
properly, please try using the latest version of Chrome before properly, please try using the latest version of Chrome before
submitting a bug report. submitting a bug report.

View File

@@ -1,7 +1,7 @@
import diceFont from 'themes/fonts/iconFonts/diceFont.js'; import diceFont from '../../../themes/fonts/iconFonts/diceFont.js';
import elderberryInn from 'themes/fonts/iconFonts/elderberryInn.js'; import elderberryInn from '../../../themes/fonts/iconFonts/elderberryInn.js';
import fontAwesome from 'themes/fonts/iconFonts/fontAwesome.js'; import fontAwesome from '../../../themes/fonts/iconFonts/fontAwesome.js';
import gameIcons from 'themes/fonts/iconFonts/gameIcons.js'; import gameIcons from '../../../themes/fonts/iconFonts/gameIcons.js';
const emojis = { const emojis = {
...diceFont, ...diceFont,

View File

@@ -16,10 +16,10 @@ import { gfmHeadingId as MarkedGFMHeadingId, resetHeadings as MarkedGFMResetHead
import { markedEmoji as MarkedEmojis } from 'marked-emoji'; import { markedEmoji as MarkedEmojis } from 'marked-emoji';
//Icon fonts included so they can appear in emoji autosuggest dropdown //Icon fonts included so they can appear in emoji autosuggest dropdown
import diceFont from '../themes/fonts/iconFonts/diceFont.js'; import diceFont from '../../themes/fonts/iconFonts/diceFont.js';
import elderberryInn from '../themes/fonts/iconFonts/elderberryInn.js'; import elderberryInn from '../../themes/fonts/iconFonts/elderberryInn.js';
import gameIcons from '../themes/fonts/iconFonts/gameIcons.js'; import gameIcons from '../../themes/fonts/iconFonts/gameIcons.js';
import fontAwesome from '../themes/fonts/iconFonts/fontAwesome.js'; import fontAwesome from '../../themes/fonts/iconFonts/fontAwesome.js';
const renderer = new Marked.Renderer(); const renderer = new Marked.Renderer();
const tokenizer = new Marked.Tokenizer(); const tokenizer = new Marked.Tokenizer();
@@ -31,12 +31,7 @@ renderer.html = function (token) {
const openTag = html.substring(0, html.indexOf('>')+1); const openTag = html.substring(0, html.indexOf('>')+1);
html = html.substring(html.indexOf('>')+1); html = html.substring(html.indexOf('>')+1);
html = html.substring(0, html.lastIndexOf('</div>')); html = html.substring(0, html.lastIndexOf('</div>'));
return `${openTag} ${Marked.parse(html)} </div>`;
// Repeat the markdown processing for content inside the div, minus the preprocessing and postprocessing hooks which should only run once globally
const opts = Marked.defaults;
const tokens = Marked.lexer(html, opts);
Marked.walkTokens(tokens, opts.walkTokens);
return `${openTag} ${Marked.parser(tokens, opts)} </div>`;
} }
return html; return html;
}; };

View File

@@ -5,7 +5,7 @@ const createClass = require('create-react-class');
const _ = require('lodash'); const _ = require('lodash');
const cx = require('classnames'); const cx = require('classnames');
const NaturalCritIcon = require('client/components/svg/naturalcrit-d20.svg.jsx'); const NaturalCritIcon = require('naturalcrit/svg/naturalcrit.svg.jsx');
const Nav = { const Nav = {
base : createClass({ base : createClass({

View File

@@ -0,0 +1,3 @@
module.exports = function(props){
return <svg version='1.1' x='0px' y='0px' viewBox='0 0 80 100' enableBackground='new 0 0 80 80'><g><g><polygon fill='#000000' points='12.9,71.4 7.6,66.1 19.3,54.4 20.7,55.8 10.4,66.1 12.9,68.6 23.2,58.3 24.6,59.7 '/></g><g><path fill='#000000' d='M29,61.6c-1.7,0-3.4-0.7-4.6-1.9l-5.1-5.1c-2.5-2.5-2.5-6.6,0-9.2l0.7-0.7L34.3,59l-0.7,0.7 C32.4,60.9,30.8,61.6,29,61.6z M20.1,47.6c-1.1,1.7-0.9,4.1,0.6,5.6l5.1,5.1c0.8,0.8,2,1.3,3.2,1.3c0.9,0,1.7-0.2,2.4-0.7 L20.1,47.6z'/></g><g><path fill='#000000' d='M12.3,74.8c-0.8,0-1.5-0.3-2-0.8l-5.2-5.2c-0.5-0.5-0.8-1.2-0.8-2c0-0.8,0.3-1.5,0.8-2 c1.1-1.1,2.9-1.1,4,0l5.2,5.2c1.1,1.1,1.1,2.9,0,4C13.8,74.5,13.1,74.8,12.3,74.8z M7.1,65.9c-0.2,0-0.4,0.1-0.6,0.2 c-0.2,0.2-0.2,0.4-0.2,0.6s0.1,0.4,0.2,0.6l5.2,5.2c0.3,0.3,0.9,0.3,1.2,0c0.3-0.3,0.3-0.8,0-1.2l-5.2-5.2 C7.5,66,7.3,65.9,7.1,65.9z'/></g><g><polygon fill='#000000' points='31.7,58.7 30.3,57.3 70,17.6 70,9 62.4,9 23.3,49.4 21.9,48 61.6,7 72,7 72,18.4 '/></g><g><rect x='46' y='6.7' transform='matrix(0.7168 0.6973 -0.6973 0.7168 35.9716 -23.568)' fill='#000000' width='2' height='51.6'/></g><g><rect x='13' y='61' fill='#000000' width='2' height='7'/></g><g><rect x='17' y='57' fill='#000000' width='2' height='7'/></g></g><g><g><polygon fill='#000000' points='68.4,71.4 56.7,59.7 58.1,58.3 68.4,68.6 70.8,66.1 60.5,55.8 61.9,54.4 73.6,66.1 '/></g><g><path fill='#000000' d='M52.2,61.6c-1.7,0-3.4-0.7-4.6-1.9L46.9,59l14.3-14.3l0.7,0.7c2.5,2.5,2.5,6.6,0,9.2l-5.1,5.1 C55.6,60.9,53.9,61.6,52.2,61.6z M49.8,58.9c0.7,0.4,1.5,0.7,2.4,0.7c1.2,0,2.3-0.5,3.2-1.3l5.1-5.1c1.5-1.5,1.7-3.8,0.6-5.6 L49.8,58.9z'/></g><g><path fill='#000000' d='M68.9,74.8c-0.8,0-1.5-0.3-2-0.8c-1.1-1.1-1.1-2.9,0-4l5.2-5.2c1.1-1.1,2.9-1.1,4,0c0.5,0.5,0.8,1.2,0.8,2 c0,0.8-0.3,1.5-0.8,2L70.9,74C70.4,74.5,69.7,74.8,68.9,74.8z M74.2,65.9c-0.2,0-0.4,0.1-0.6,0.2l-5.2,5.2c-0.3,0.3-0.3,0.8,0,1.2 c0.3,0.3,0.9,0.3,1.2,0l5.2-5.2c0.2-0.2,0.2-0.4,0.2-0.6s-0.1-0.4-0.2-0.6C74.6,66,74.4,65.9,74.2,65.9z'/></g><g><rect x='38.6' y='52.3' transform='matrix(0.7082 0.706 -0.706 0.7082 50.8397 -16.4875)' fill='#000000' width='13.4' height='2'/></g><g><polygon fill='#000000' points='30.6,39.9 9,18.4 9,7 19.7,7 41.1,29.1 39.7,30.5 18.8,9 11,9 11,17.6 32,38.5 '/></g><g><rect x='47.8' y='43.1' transform='matrix(0.6959 0.7181 -0.7181 0.6959 48.1381 -25.5246)' fill='#000000' width='12.8' height='2'/></g><g><rect x='12' y='23.1' transform='matrix(0.6974 0.7167 -0.7167 0.6974 25.1384 -11.3825)' fill='#000000' width='28.1' height='2'/></g><g><rect x='43.8' y='46.4' transform='matrix(0.6974 0.7167 -0.7167 0.6974 48.7492 -20.5985)' fill='#000000' width='10' height='2'/></g><g><rect x='66' y='61' fill='#000000' width='2' height='7'/></g><g><rect x='62' y='57' fill='#000000' width='2' height='7'/></g></g></svg>;
};

View File

@@ -1,6 +1,6 @@
import Markdown from 'markdown.js'; import Markdown from 'naturalcrit/markdown.js';
test('Processes the markdown within an HTML block if its just a class wrapper', function() { test('Processes the markdown within an HTML block if its just a class wrapper', function() {
const source = '<div>*Bold text*</div>'; const source = '<div>*Bold text*</div>';

View File

@@ -1,6 +1,6 @@
import Markdown from 'markdown.js'; import Markdown from 'naturalcrit/markdown.js';
describe('Inline Definition Lists', ()=>{ describe('Inline Definition Lists', ()=>{
test('No Term 1 Definition', function() { test('No Term 1 Definition', function() {

View File

@@ -1,4 +1,4 @@
import Markdown from 'markdown.js'; import Markdown from 'naturalcrit/markdown.js';
const dedent = require('dedent-tabs').default; const dedent = require('dedent-tabs').default;
// Marked.js adds line returns after closing tags on some default tokens. // Marked.js adds line returns after closing tags on some default tokens.

View File

@@ -1,6 +1,6 @@
import Markdown from 'markdown.js'; import Markdown from 'naturalcrit/markdown.js';
describe('Hard Breaks', ()=>{ describe('Hard Breaks', ()=>{
test('Single Break', function() { test('Single Break', function() {

View File

@@ -1,7 +1,7 @@
/* eslint-disable max-lines */ /* eslint-disable max-lines */
const dedent = require('dedent-tabs').default; const dedent = require('dedent-tabs').default;
import Markdown from 'markdown.js'; import Markdown from 'naturalcrit/markdown.js';
// Marked.js adds line returns after closing tags on some default tokens. // Marked.js adds line returns after closing tags on some default tokens.
// This removes those line returns for comparison sake. // This removes those line returns for comparison sake.

View File

@@ -1,6 +1,6 @@
import Markdown from 'markdown.js'; import Markdown from 'naturalcrit/markdown.js';
describe('Non-Breaking Spaces Interactions', ()=>{ describe('Non-Breaking Spaces Interactions', ()=>{
test('I am actually a single-line definition list!', function() { test('I am actually a single-line definition list!', function() {

View File

@@ -1,6 +1,6 @@
import Markdown from 'markdown.js'; import Markdown from 'naturalcrit/markdown.js';
describe('Justification', ()=>{ describe('Justification', ()=>{
test('Left Justify', function() { test('Left Justify', function() {

View File

@@ -1,7 +1,7 @@
/* eslint-disable max-lines */ /* eslint-disable max-lines */
const dedent = require('dedent-tabs').default; const dedent = require('dedent-tabs').default;
import Markdown from 'markdown.js'; import Markdown from 'naturalcrit/markdown.js';
// Marked.js adds line returns after closing tags on some default tokens. // Marked.js adds line returns after closing tags on some default tokens.
// This removes those line returns for comparison sake. // This removes those line returns for comparison sake.

View File

@@ -1,4 +1,4 @@
import Markdown from '../../../../shared/markdown.js'; import Markdown from '../../../../shared/naturalcrit/markdown.js';
module.exports = { module.exports = {
createFooterFunc : function(headerSize=1){ createFooterFunc : function(headerSize=1){

View File

@@ -492,7 +492,7 @@ body { counter-reset : page-numbers 0; }
.pageNumber { left : 30px; } .pageNumber { left : 30px; }
} }
&:has(.resetCounting) { counter-set : page-numbers 1; } .resetCounting { counter-set : page-numbers 1; }
&:not(:has(.skipCounting)) { counter-increment : page-numbers; } &:not(:has(.skipCounting)) { counter-increment : page-numbers; }

View File

@@ -1,6 +1,6 @@
{ {
"name" : "UnearthedArcana", "name" : "UnearthedArcana",
"renderer" : "V3", "renderer" : "V3",
"baseTheme" : "Blank", "baseTheme" : false,
"baseSnippets" : false "baseSnippets" : false
} }

View File

@@ -39,7 +39,7 @@
"UnearthedArcana": { "UnearthedArcana": {
"name": "UnearthedArcana", "name": "UnearthedArcana",
"renderer": "V3", "renderer": "V3",
"baseTheme": "Blank", "baseTheme": false,
"baseSnippets": false, "baseSnippets": false,
"path": "UnearthedArcana" "path": "UnearthedArcana"
} }