This commit is contained in:
Víctor Losada Hernández
2026-09-28 17:34:12 +02:00
parent 5b7efa9f1f
commit 8a372c1454
21 changed files with 191 additions and 193 deletions
@@ -109,7 +109,7 @@ const BrewCleanup = ({})=>{
<td style={{ width: '200px' }}>{Moment(brew.updatedAt).fromNow()}</td>
<td>{brew.lastViewed ? Moment(brew.lastViewed).fromNow() : 'No last viewed date'}</td>
<td>{brew.googleId ? 'Google' : 'Homebrewery'}</td>
</tr>
</tr>;
})}
</tbody>
</table>
@@ -120,7 +120,7 @@ const BrewCleanup = ({})=>{
return <div className='result'>
{deleteButton && <button onClick={()=>cleanup(type)} className='remove'>
{pendingLost && type === "lost" || pendingJunk && type === "junk"
{pendingLost && type === 'lost' || pendingJunk && type === 'junk'
? <i className='fas fa-spin fa-spinner' />
: <span><i className='fas fa-times' /> Remove</span>
}
+1 -1
View File
@@ -46,7 +46,7 @@ const settingsCompartment = new Compartment();
import { generalKeymap, markdownKeymap, cssKeymap, formatCSS } from './extensions/customKeyMaps.js';
import foldOnPages from './extensions/customFolding.js';
import { customHighlightStyle , customHighlightPlugin } from './extensions/customHighlight.js';
import { customHighlightStyle, customHighlightPlugin } from './extensions/customHighlight.js';
import { legacyCustomHighlightStyle } from './extensions/legacyCustomHighlight.js';
const PAGEBREAK_REGEX_V3 = /^(?=\\page(?:break)?(?: *{[^\n{}]*})?$)/m;
@@ -14,25 +14,24 @@ export async function formatCSS(view) {
const code = empty ? fullDoc : selection;
let formatted = await prettier.format(code, {
parser: 'css',
plugins: [postcssPlugin],
parser : 'css',
plugins : [postcssPlugin],
// formatting options
tabWidth: 2,
useTabs: false,
printWidth: 100,
singleQuote: false,
trailingComma: 'all',
bracketSpacing: true,
endOfLine: 'lf'
tabWidth : 2,
useTabs : false,
printWidth : 100,
singleQuote : false,
trailingComma : 'all',
bracketSpacing : true,
endOfLine : 'lf'
});
//format manually single declaration rules to span one line.
//Prettier can't do it by default, this is crude but it works
formatted = formatted.replace(
/([^{]+)\{\s*\n\s*([^;\n]+:[^;\n]+;)\s*\n\s*\}(\s*)/g,
(_, selector, decl, whitespace) =>
`${selector} { ${decl.trim()} }${whitespace}`
/([^{]+)\{\s*\n\s*([^;\n]+:[^;\n]+;)\s*\n\s*\}(\s*)/g,
(_, selector, decl, whitespace)=>`${selector} { ${decl.trim()} }${whitespace}`
);
if(formatted === code) return true;
+1 -1
View File
@@ -7,7 +7,7 @@ const Combobox = createReactClass({
displayName : 'Combobox',
getDefaultProps : function() {
return {
id : '',
id : '',
className : '',
trigger : 'hover',
default : '',
@@ -103,8 +103,8 @@ const BrewRenderer = (props)=>{
const pagesRef = useRef(null);
const [visiblePages, setVisiblePages] = useState([]);
const [centerPage , setCenterPage ] = useState(1);
const [headerState , setHeaderState ] = useState(false);
const [centerPage, setCenterPage] = useState(1);
const [headerState, setHeaderState] = useState(false);
const [state, setState] = useState({
isMounted : false,
@@ -158,10 +158,9 @@ const BrewRenderer = (props)=>{
return false;
};
const renderDummyPage = (index)=>
<div className='phb page' id={`p${index + 1}`} key={index}>
<i className='fas fa-spinner fa-spin' />
</div>;
const renderDummyPage = (index)=><div className='phb page' id={`p${index + 1}`} key={index}>
<i className='fas fa-spinner fa-spin' />
</div>;
const renderStyle = ()=>{
const themeStyles = props.themeBundle?.joinedStyles ?? '<style>@import url("/themes/V3/Blank/style.css");</style>';
@@ -100,12 +100,12 @@ const ToolBar = ({ displayOptions, onDisplayOptionsChange, visiblePages, totalPa
<div id='preview-toolbar' className={`toolBar ${toolsVisible ? 'visible' : 'hidden'}`} role='toolbar'>
<div className='toggleButton'>
<button data-tooltip-right={`${toolsVisible ? 'Hide' : 'Show'} Preview Toolbar`}
aria-label={`${toolsVisible ? 'Hide' : 'Show'} Preview Toolbar`}
aria-label={`${toolsVisible ? 'Hide' : 'Show'} Preview Toolbar`}
onClick={()=>{ setToolsVisible(!toolsVisible); localStorage.setItem(TOOLBAR_VISIBILITY, !toolsVisible); }}>
<i aria-hidden='true' className='fas fa-glasses' />
</button>
<button data-tooltip-right={`${headerState ? 'Hide' : 'Show'} Header Navigation`}
aria-label={`${headerState ? 'Hide' : 'Show'} Header Navigation`}
aria-label={`${headerState ? 'Hide' : 'Show'} Header Navigation`}
onClick={()=>{setHeaderState(!headerState);}}>
<i aria-hidden='true' className='fas fa-rectangle-list' />
</button>
@@ -131,7 +131,7 @@ const SettingsEditor = ({ settings, updateSettings = ()=>{}, EditorThemeNameList
onChange={(e)=>handleFieldChange('fontSize', e)}
/>
<datalist id='font-sizes'>
<option value='1' />
<option value='1' />
</datalist>
</div>
+1 -1
View File
@@ -12,7 +12,7 @@ export default function(){
return ()=>{
document.removeEventListener('print:startprep', handlePrintStartPrep);
document.removeEventListener('print:finishedprep', handlePrintPrepFinished);
}
};
}, []);
const handlePrintStartPrep = ()=>{ setPrinting(true); };
+1 -1
View File
@@ -9,7 +9,7 @@ import _ from 'lodash';
import { DEFAULT_BREW_LOAD } from '../../../../server/brewDefaults.js';
import useCommonEditPageFunctions from '../../utils/commonEditPageFunctions.jsx'
import useCommonEditPageFunctions from '../../utils/commonEditPageFunctions.jsx';
import SplitPane from '@components/splitPane/splitPane.jsx';
import Editor from '../../editor/editor.jsx';
+1 -1
View File
@@ -9,7 +9,7 @@ import _ from 'lodash';
import { DEFAULT_BREW } from '../../../../server/brewDefaults.js';
import useCommonEditPageFunctions from '../../utils/commonEditPageFunctions.jsx'
import useCommonEditPageFunctions from '../../utils/commonEditPageFunctions.jsx';
import SplitPane from '@components/splitPane/splitPane.jsx';
import Editor from '../../editor/editor.jsx';
+2 -2
View File
@@ -1,4 +1,4 @@
/* eslint-disable max-lines */
import './newPage.less';
// Common imports
@@ -10,7 +10,7 @@ import _ from 'lodash';
import { DEFAULT_BREW } from '../../../../server/brewDefaults.js';
import { printCurrentBrew, fetchThemeBundle, splitTextStyleAndMetadata } from '@shared/helpers.js';
import useCommonEditPageFunctions from '../../utils/commonEditPageFunctions.jsx'
import useCommonEditPageFunctions from '../../utils/commonEditPageFunctions.jsx';
import SplitPane from '@components/splitPane/splitPane.jsx';
import Editor from '../../editor/editor.jsx';
@@ -30,11 +30,11 @@ export default function useCommonEditPageFunctions(dependencies) {
save,
} = dependencies;
const [isSaving , setIsSaving] = useState(false);
const [lastSavedTime , setLastSavedTime] = useState(new Date());
const [autoSaveEnabled , setAutoSaveEnabled] = useState(!sandbox);
const [isSaving, setIsSaving] = useState(false);
const [lastSavedTime, setLastSavedTime] = useState(new Date());
const [autoSaveEnabled, setAutoSaveEnabled] = useState(!sandbox);
const [warnUnsavedChanges, setWarnUnsavedChanges] = useState(true);
const [unsavedChanges , setUnsavedChanges] = useState(false);
const [unsavedChanges, setUnsavedChanges] = useState(false);
const unsavedChangesRef = useRef(unsavedChanges); // onBeforeUnload lives outside React and needs ref to unsavedChanges
const warnUnsavedTimeout = useRef(null); // timers live outside React and need ref to consistently track time
@@ -105,7 +105,7 @@ export default function useCommonEditPageFunctions(dependencies) {
if(field == 'metadata') localStorage.setItem(METAKEY, JSON.stringify({
renderer : value.renderer,
theme : value.theme,
lang : value.lang
lang : value.lang
}));
}
};
@@ -155,7 +155,7 @@ export default function useCommonEditPageFunctions(dependencies) {
return <Nav.item className='save error' icon='fas fa-exclamation-circle'>
Reminder...
<div className='errorContainer'>{text}</div>
<div className='errorContainer'>{text}</div>
</Nav.item>;
}
@@ -180,5 +180,5 @@ export default function useCommonEditPageFunctions(dependencies) {
renderSaveButton,
autoSaveEnabled,
unsavedChanges,
}
};
}
+8 -8
View File
@@ -44,7 +44,7 @@ export default function createAdminApi(vite) {
updatedAt : { $lt: Moment().subtract(30, 'days').toDate() },
lastViewed : { $lt: Moment().subtract(30, 'days').toDate() }
} },
{ $project: { _id: 1, textBinSize: { $binarySize: '$textBin' }, updatedAt: 1, lastViewed: 1} },
{ $project: { _id: 1, textBinSize: { $binarySize: '$textBin' }, updatedAt: 1, lastViewed: 1 } },
{ $match: { textBinSize: { $lt: 140 } } },
{ $limit: 300 }
];
@@ -52,14 +52,14 @@ export default function createAdminApi(vite) {
// Search for up to 500 unauthored brews that have not been viewed or updated in two years
const lostBrewsPipeline = [
{
$match: {
authors: [],
updatedAt: { $lt: Moment().subtract(2, 'years').toDate() },
lastViewed: { $lt: Moment().subtract(2, 'years').toDate() }
$match : {
authors : [],
updatedAt : { $lt: Moment().subtract(2, 'years').toDate() },
lastViewed : { $lt: Moment().subtract(2, 'years').toDate() }
}
},
{
$limit: 500
$limit : 500
}
];
@@ -70,7 +70,7 @@ export default function createAdminApi(vite) {
router.get('/admin/cleanupJunk', mw.adminOnly, (req, res)=>{
HomebrewModel.aggregate(junkBrewsPipeline).option({ maxTimeMS: 60000 })
.then((objs)=>res.json({ count: objs.length, brewCollection : objs }))
.then((objs)=>res.json({ count: objs.length, brewCollection: objs }))
.catch((error)=>{
console.error(error);
res.status(500).json({ error: 'Internal Server Error' });
@@ -93,7 +93,7 @@ export default function createAdminApi(vite) {
router.get('/admin/cleanupLost', mw.adminOnly, (req, res)=>{
HomebrewModel.aggregate(lostBrewsPipeline).option({ maxTimeMS: 60000 })
.then((objs)=>res.json({ count: objs.length, brewCollection : objs }))
.then((objs)=>res.json({ count: objs.length, brewCollection: objs }))
.catch((error)=>{
console.error(error);
res.status(500).json({ error: 'Internal Server Error' });
+4 -4
View File
@@ -137,7 +137,7 @@ export default async function createApp(vite) {
return res.sendFile(`robots.txt`, { root: process.cwd() });
});
//serve brew for sharepage rerender
app.get('/api/fetch/:id', asyncHandler(getBrew('share')), asyncHandler(async (req, res) => {
app.get('/api/fetch/:id', asyncHandler(getBrew('share')), asyncHandler(async (req, res)=>{
const { brew } = req;
brew.authors.includes(req.account?.username)
? sanitizeBrew(brew, 'shareAuthor')
@@ -285,9 +285,9 @@ export default async function createApp(vite) {
'<head>',
`<head>\n`
+ `<script id="props">`
+ `window.__INITIAL_PROPS__ = ` + safeProps
+ `</script>\n`
+ ogMetaTags
+ `window.__INITIAL_PROPS__ = ${safeProps
}</script>\n${
ogMetaTags}`
);
return html;
+108 -108
View File
@@ -360,25 +360,25 @@ describe('Tests for api', ()=>{
trashed : false,
updatedAt : undefined,
views : 0,
bleedSize: {
top: '.125in',
bottom: '.125in',
inner: '.125in',
outer: '.125in',
bleedSize : {
top : '.125in',
bottom : '.125in',
inner : '.125in',
outer : '.125in',
},
columns: '2',
columnGutter: '.125in',
legalAuthors: '',
license: 'None',
safetySpace: {
top: '.25in',
bottom: '.25in',
outer: '.25in',
inner: '.5in',
columns : '2',
columnGutter : '.125in',
legalAuthors : '',
license : 'None',
safetySpace : {
top : '.25in',
bottom : '.25in',
outer : '.25in',
inner : '.5in',
},
trimSize: {
width: '8.5in',
height: '11in',
trimSize : {
width : '8.5in',
height : '11in',
},
});
expect(next).toHaveBeenCalled();
@@ -471,25 +471,25 @@ describe('Tests for api', ()=>{
renderer : 'v3',
theme : 'phb',
googleId : '12345',
bleedSize: {
top: '.125in',
bottom: '.125in',
inner: '.125in',
outer: '.125in',
bleedSize : {
top : '.125in',
bottom : '.125in',
inner : '.125in',
outer : '.125in',
},
columns: '2',
columnGutter: '.125in',
legalAuthors: '',
license: 'None',
safetySpace: {
top: '.25in',
bottom: '.25in',
outer: '.25in',
inner: '.5in',
columns : '2',
columnGutter : '.125in',
legalAuthors : '',
license : 'None',
safetySpace : {
top : '.25in',
bottom : '.25in',
outer : '.25in',
inner : '.5in',
},
trimSize: {
width: '8.5in',
height: '11in',
trimSize : {
width : '8.5in',
height : '11in',
},
});
@@ -534,25 +534,25 @@ brew`);
renderer : 'v3',
theme : 'phb',
googleId : '12345',
bleedSize: {
top: '.125in',
bottom: '.125in',
inner: '.125in',
outer: '.125in',
bleedSize : {
top : '.125in',
bottom : '.125in',
inner : '.125in',
outer : '.125in',
},
columns: '2',
columnGutter: '.125in',
legalAuthors: '',
license: 'None',
safetySpace: {
top: '.25in',
bottom: '.25in',
outer: '.25in',
inner: '.5in',
columns : '2',
columnGutter : '.125in',
legalAuthors : '',
license : 'None',
safetySpace : {
top : '.25in',
bottom : '.25in',
outer : '.25in',
inner : '.5in',
},
trimSize: {
width: '8.5in',
height: '11in',
trimSize : {
width : '8.5in',
height : '11in',
},
});
@@ -687,16 +687,16 @@ brew`);
expect(res.status).toHaveBeenCalledWith(200);
expect(res.send).toHaveBeenCalledWith({
_id : '1',
authors : ['test user'],
createdAt : undefined,
description : '',
editId : expect.any(String),
gDrive : false,
pageCount : 1,
published : false,
renderer : 'V3',
lang : 'en',
_id : '1',
authors : ['test user'],
createdAt : undefined,
description : '',
editId : expect.any(String),
gDrive : false,
pageCount : 1,
published : false,
renderer : 'V3',
lang : 'en',
shareId : expect.any(String),
style : undefined,
tags : [],
@@ -708,25 +708,25 @@ brew`);
trashed : false,
updatedAt : undefined,
views : 0,
bleedSize: {
top: '.125in',
bottom: '.125in',
inner: '.125in',
outer: '.125in',
bleedSize : {
top : '.125in',
bottom : '.125in',
inner : '.125in',
outer : '.125in',
},
columns: '2',
columnGutter: '.125in',
legalAuthors: '',
license: 'None',
safetySpace: {
top: '.25in',
bottom: '.25in',
outer: '.25in',
inner: '.5in',
columns : '2',
columnGutter : '.125in',
legalAuthors : '',
license : 'None',
safetySpace : {
top : '.25in',
bottom : '.25in',
outer : '.25in',
inner : '.5in',
},
trimSize: {
width: '8.5in',
height: '11in',
trimSize : {
width : '8.5in',
height : '11in',
},
});
});
@@ -765,16 +765,16 @@ brew`);
expect(google.newGoogleBrew).toHaveBeenCalled();
expect(res.status).toHaveBeenCalledWith(200);
expect(res.send).toHaveBeenCalledWith({
_id : '1',
authors : ['test user'],
bleedSize: {
top: '.125in',
bottom: '.125in',
inner: '.125in',
outer: '.125in',
_id : '1',
authors : ['test user'],
bleedSize : {
top : '.125in',
bottom : '.125in',
inner : '.125in',
outer : '.125in',
},
columns: '2',
columnGutter: '.125in',
columns : '2',
columnGutter : '.125in',
createdAt : undefined,
description : '',
editId : expect.any(String),
@@ -784,29 +784,29 @@ brew`);
renderer : 'V3',
lang : 'en',
shareId : expect.any(String),
legalAuthors: '',
license: 'None',
safetySpace: {
top: '.25in',
bottom: '.25in',
outer: '.25in',
inner: '.5in',
legalAuthors : '',
license : 'None',
safetySpace : {
top : '.25in',
bottom : '.25in',
outer : '.25in',
inner : '.5in',
},
googleId : expect.any(String),
style : undefined,
tags : [],
text : undefined,
textBin : undefined,
theme : '5ePHB',
thumbnail : '',
title : 'asdf',
trashed : false,
trimSize: {
width: '8.5in',
height: '11in',
googleId : expect.any(String),
style : undefined,
tags : [],
text : undefined,
textBin : undefined,
theme : '5ePHB',
thumbnail : '',
title : 'asdf',
trashed : false,
trimSize : {
width : '8.5in',
height : '11in',
},
updatedAt : undefined,
views : 0
updatedAt : undefined,
views : 0
});
});
});
+21 -21
View File
@@ -47,19 +47,19 @@ describe(`brewSnippetsToJSON`, ()=>{
gen : 'I am the first brew snippet!\n',
name : 'First Brew Snippet'
}, {
gen : 'I am the second brew Snippet!',
name: 'Second Brew Snippet'
gen : 'I am the second brew Snippet!',
name : 'Second Brew Snippet'
}
]}]
] }]
};
const rendered = brewSnippetsToJSON(`Test Snippets JSON without theme snippets`, brewSnippetsBrewTest, null, true);
expect(rendered).toStrictEqual(testMenuObject);
});
it('converts raw brew snippets with theme snippets to JSON', function() {
it('converts raw brew snippets with theme snippets to JSON', function() {
const testMenuObject = {
groupName : 'Brew Snippets',
icon : 'fas fa-th-list',
icon : 'fas fa-th-list',
view : 'text',
snippets : [{
gen : '',
@@ -76,20 +76,20 @@ describe(`brewSnippetsToJSON`, ()=>{
icon : '',
name : 'Second Theme Snippet',
},
]},
{
name : 'Test Snippets JSON with theme snippets',
subsnippets : [
{
gen : 'I am the first brew snippet!\n',
name : 'First Brew Snippet'
},
{
gen : 'I am the second brew Snippet!',
name: 'Second Brew Snippet'
}
]
}]};
] },
{
name : 'Test Snippets JSON with theme snippets',
subsnippets : [
{
gen : 'I am the first brew snippet!\n',
name : 'First Brew Snippet'
},
{
gen : 'I am the second brew Snippet!',
name : 'Second Brew Snippet'
}
]
}] };
const rendered = brewSnippetsToJSON(`Test Snippets JSON with theme snippets`, brewSnippetsBrewTest, brewSnippetsThemeTest, true);
expect(rendered).toStrictEqual(testMenuObject);
});
@@ -103,8 +103,8 @@ describe(`YAMLSnippetsToText`, ()=>{
gen : 'I am the first brew snippet!\n',
name : 'First Brew Snippet'
}, {
gen : 'I am the second brew Snippet!',
name: 'Second Brew Snippet'
gen : 'I am the second brew Snippet!',
name : 'Second Brew Snippet'
}
]
}];
+1 -1
View File
@@ -1,6 +1,6 @@
import {hbfm} from 'marked-hbfm';
import { hbfm } from 'marked-hbfm';
describe('Non-Breaking Spaces Interactions', ()=>{
test('I am actually a single-line definition list!', function() {
+1 -1
View File
@@ -329,7 +329,7 @@ export default [
},
{
name : 'DTRPG Community Content',
icon : null,
icon : null,
subsnippets : [
{
name : 'Chronicle System Guild Colophon',