0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2026-08-06 11:07:37 +00:00

Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Gazook89
2026-04-08 22:02:08 -05:00
42 changed files with 1346 additions and 1355 deletions
+29 -3
View File
@@ -85,14 +85,40 @@ pre {
} }
.page .df { .page .df {
font-size: 2em; font-size: 2em;
vertical-align: middle; vertical-align: middle;
} }
``` ```
## changelog ## changelog
For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery). For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery).
### Saturday 4/04/2026 - v3.21.0
{{taskList
##### Gazook89
* [x] Allow custom {{openSans **:fas_table_list: SNIPPETS**}} to be inserted mid-line
##### abquintic
* [x] Move example snippet images out of imgur (for folks without imgur access)
##### 5e-Cleric
* [x] Add auto-suggest to tag entry input box
* [x] Replace all example artwork with
* [x] Added tooltips to the {{openSans :fas_circle_info: **Properties**}} menu
* [x] Removed {{openSans **SYSTEMS**}} checkboxes from {{openSans :fas_circle_info: **Properties**}} menu; instead {{openSans **TAGS**}} should be used for this purpose
* [x] Replace all AI-generated art with public domain art
* [x] Major backend refactor to use Vite
##### A1Asriel (new contributor!)
* [x] Add fix for column breaks on Firefox
Fixes issues [#543](https://github.com/naturalcrit/homebrewery/issues/543), [#2473](https://github.com/naturalcrit/homebrewery/issues/2473), [#3712](https://github.com/naturalcrit/homebrewery/issues/3712)
##### G-Ambatte, abquintic, 5e-Cleric
* [x] Multiple other backend fixes and refactors
}}
### Friday 1/11/2026 - v3.20.1 ### Friday 1/11/2026 - v3.20.1
{{taskList {{taskList
@@ -2358,4 +2384,4 @@ Massive changelog incoming:
* Added `phb.standalone.css` plus a build system for creating it * Added `phb.standalone.css` plus a build system for creating it
* Added page numbers and footer text * Added page numbers and footer text
* Page accent now flips each page * Page accent now flips each page
+6 -2
View File
@@ -16,6 +16,7 @@ const CodeEditor = createReactClass({
value : '', value : '',
wrap : true, wrap : true,
onChange : ()=>{}, onChange : ()=>{},
onReady : ()=>{},
enableFolding : true, enableFolding : true,
editorTheme : 'default' editorTheme : 'default'
}; };
@@ -177,7 +178,7 @@ const CodeEditor = createReactClass({
// return el; // return el;
// } // }
}); });
this.props.onReady?.(this.codeMirror);
// Add custom behaviors (auto-close curlies and auto-complete emojis) // Add custom behaviors (auto-close curlies and auto-complete emojis)
closeTag.autoCloseCurlyBraces(CodeMirror, this.codeMirror); closeTag.autoCloseCurlyBraces(CodeMirror, this.codeMirror);
autoCompleteEmoji.showAutocompleteEmoji(CodeMirror, this.codeMirror); autoCompleteEmoji.showAutocompleteEmoji(CodeMirror, this.codeMirror);
@@ -189,7 +190,8 @@ const CodeEditor = createReactClass({
// Use for GFM tabs that use common hot-keys // Use for GFM tabs that use common hot-keys
isGFM : function() { isGFM : function() {
if((this.isGFM()) || (this.props.tab === 'brewSnippets')) return true; console.log(this.props.tab);
if( this.props.tab === 'brewText' || this.props.tab === 'brewSnippets') return true;
return false; return false;
}, },
@@ -226,7 +228,9 @@ const CodeEditor = createReactClass({
}, },
makeBold : function() { makeBold : function() {
console.log('hello');
if(!this.isGFM()) return; if(!this.isGFM()) return;
console.log(this.isGFM());
const selection = this.codeMirror?.getSelection(), t = selection.slice(0, 2) === '**' && selection.slice(-2) === '**'; const selection = this.codeMirror?.getSelection(), t = selection.slice(0, 2) === '**' && selection.slice(-2) === '**';
this.codeMirror?.replaceSelection(t ? selection.slice(2, -2) : `**${selection}**`, 'around'); this.codeMirror?.replaceSelection(t ? selection.slice(2, -2) : `**${selection}**`, 'around');
if(selection.length === 0){ if(selection.length === 0){
@@ -33,7 +33,7 @@ const INITIAL_CONTENT = dedent`
<link href='/homebrew/bundle.css' type="text/css" rel='stylesheet' /> <link href='/homebrew/bundle.css' type="text/css" rel='stylesheet' />
<link href="${brewRendererStylesUrl}" rel="stylesheet" /> <link href="${brewRendererStylesUrl}" rel="stylesheet" />
<link href="${headerNavStylesUrl}" rel="stylesheet" /> <link href="${headerNavStylesUrl}" rel="stylesheet" />
<base target=_blank> <base target="_top">
</head><body style='overflow: hidden'><div></div></body></html>`; </head><body style='overflow: hidden'><div></div></body></html>`;
@@ -272,6 +272,13 @@ const BrewRenderer = (props)=>{
const frameDidMount = ()=>{ //This triggers when iFrame finishes internal "componentDidMount" const frameDidMount = ()=>{ //This triggers when iFrame finishes internal "componentDidMount"
scrollToHash(window.location.hash); scrollToHash(window.location.hash);
navigation.addEventListener('navigate', (e)=>{
if(e.hashChange && e.destination.sameDocument){
const dest = e.destination.url.slice(e.destination.url.indexOf('#'));
scrollToHash(dest);
}
});
setTimeout(()=>{ //We still see a flicker where the style isn't applied yet, so wait 100ms before showing iFrame setTimeout(()=>{ //We still see a flicker where the style isn't applied yet, so wait 100ms before showing iFrame
renderPages(); //Make sure page is renderable before showing renderPages(); //Make sure page is renderable before showing
setState((prevState)=>({ setState((prevState)=>({
@@ -104,7 +104,7 @@ const HeaderNavItem = ({ link, text, depth, className })=>{
if(!link || !text) return; if(!link || !text) return;
return <li> return <li>
<a href={`#${link}`} target='_self' className={`depth-${depth} ${className ?? ''}`}> <a href={`#${link}`} className={`depth-${depth} ${className ?? ''}`}>
{trimString(text, depth)} {trimString(text, depth)}
</a> </a>
</li>; </li>;
+29 -6
View File
@@ -76,9 +76,6 @@ const Editor = createReactClass({
document.getElementById('BrewRenderer').addEventListener('keydown', this.handleControlKeys); document.getElementById('BrewRenderer').addEventListener('keydown', this.handleControlKeys);
document.addEventListener('keydown', this.handleControlKeys); document.addEventListener('keydown', this.handleControlKeys);
this.codeEditor.current.codeMirror?.on('cursorActivity', (cm)=>{this.updateCurrentCursorPage(cm.getCursor());});
this.codeEditor.current.codeMirror?.on('scroll', _.throttle(()=>{this.updateCurrentViewPage(this.codeEditor.current.getTopVisibleLine());}, 200));
const editorTheme = window.localStorage.getItem(EDITOR_THEME_KEY); const editorTheme = window.localStorage.getItem(EDITOR_THEME_KEY);
if(editorTheme) { if(editorTheme) {
this.setState({ this.setState({
@@ -436,6 +433,29 @@ const Editor = createReactClass({
this.forceUpdate(); this.forceUpdate();
}, },
//temporary fix until cm6 comes next update
attachCodeMirrorListeners : function(cm) {
if(!cm) return;
// detach previous (important on remount / view switch)
if(this._cm) {
this._cm.off('cursorActivity', this._onCursor);
this._cm.off('scroll', this._onScroll);
}
this._cm = cm;
this._onCursor = ()=>{
this.updateCurrentCursorPage(cm.getCursor());
};
this._onScroll = _.throttle(()=>{
const topLine = cm.lineAtHeight(cm.getScrollInfo().top, 'local');
this.updateCurrentViewPage(topLine);
}, 200);
cm.on('cursorActivity', this._onCursor);
cm.on('scroll', this._onScroll);
},
renderEditor : function(){ renderEditor : function(){
if(this.isText()){ if(this.isText()){
return <> return <>
@@ -448,7 +468,8 @@ const Editor = createReactClass({
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)` }}
onReady={this.attachCodeMirrorListeners}/>
</>; </>;
} }
if(this.isStyle()){ if(this.isStyle()){
@@ -463,7 +484,8 @@ const Editor = createReactClass({
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)` }}
onReady={this.attachCodeMirrorListeners}/>
</>; </>;
} }
if(this.isMeta()){ if(this.isMeta()){
@@ -493,7 +515,8 @@ const Editor = createReactClass({
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)` }}
onReady={this.attachCodeMirrorListeners}/>
</>; </>;
} }
}, },
@@ -1,4 +1,4 @@
export default [ export const tagSuggestionList = [
// ############################## Systems // ############################## Systems
// D&D // D&D
'system:D&D Original', 'system:D&D Original',
@@ -208,3 +208,12 @@ export default [
'SW5e', 'SW5e',
'Star Wars 5e', 'Star Wars 5e',
]; ];
// substrings to be normalized to the first value on the array
export const canonizationList = [
['5e 2024', '5.5e', '5e\'24', '5.24', '5e24', '5.5'],
['5e', '5th Edition'],
['Dungeons & Dragons', 'Dungeons and Dragons', 'Dungeons n dragons'],
['D&D', 'DnD', 'dnd', 'Dnd', 'dnD', 'd&d', 'd&D', 'D&d'],
['P2e', 'p2e', 'P2E', 'Pathfinder 2e'],
];
+2 -11
View File
@@ -2,7 +2,7 @@ import './tagInput.less';
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import Combobox from '../../../components/combobox.jsx'; import Combobox from '../../../components/combobox.jsx';
import tagSuggestionList from './curatedTagSuggestionList.js'; import { tagSuggestionList, canonizationList } from './curatedTagSuggestionList.js';
const TagInput = ({ tooltip, label, valuePatterns, values = [], unique = true, placeholder = '', smallText = '', onChange })=>{ const TagInput = ({ tooltip, label, valuePatterns, values = [], unique = true, placeholder = '', smallText = '', onChange })=>{
const [tagList, setTagList] = useState( const [tagList, setTagList] = useState(
@@ -35,20 +35,11 @@ const TagInput = ({ tooltip, label, valuePatterns, values = [], unique = true, p
}); });
}, [tagList]); }, [tagList]);
// substrings to be normalized to the first value on the array
const duplicateGroups = [
['5e 2024', '5.5e', '5e\'24', '5.24', '5e24', '5.5'],
['5e', '5th Edition'],
['Dungeons & Dragons', 'Dungeons and Dragons', 'Dungeons n dragons'],
['D&D', 'DnD', 'dnd', 'Dnd', 'dnD', 'd&d', 'd&D', 'D&d'],
['P2e', 'p2e', 'P2E', 'Pathfinder 2e'],
];
const normalizeValue = (input)=>{ const normalizeValue = (input)=>{
const lowerInput = input.toLowerCase(); const lowerInput = input.toLowerCase();
let normalizedTag = input; let normalizedTag = input;
for (const group of duplicateGroups) { for (const group of canonizationList) {
for (const tag of group) { for (const tag of group) {
if(!tag) continue; if(!tag) continue;
+13
View File
@@ -52,6 +52,19 @@ const Homebrew = (props)=>{
updateLocalStorage(); updateLocalStorage();
if(brew.pureError) {
return (
<Router>
<div className={`homebrew${(config?.deployment || config?.local) ? ' deployment' : ''}`} style={backgroundObject()}>
<Routes>
<Route path={brew.originalUrl} element={<WithRoute el={ErrorPage} brew={brew} />} />
</Routes>
</div>
</Router>
);
}
return ( return (
<Router> <Router>
<div className={`homebrew${(config?.deployment || config?.local) ? ' deployment' : ''}`} style={backgroundObject()}> <div className={`homebrew${(config?.deployment || config?.local) ? ' deployment' : ''}`} style={backgroundObject()}>
@@ -46,11 +46,6 @@ const MetadataNav = createReactClass({
</>; </>;
}, },
getSystems : function(){
if(!this.props.brew.systems || this.props.brew.systems.length == 0) return 'No systems';
return this.props.brew.systems.join(', ');
},
renderMetaWindow : function(){ renderMetaWindow : function(){
return <div className={`window ${this.state.showMetaWindow ? 'active' : 'inactive'}`}> return <div className={`window ${this.state.showMetaWindow ? 'active' : 'inactive'}`}>
<div className='row'> <div className='row'>
@@ -65,10 +60,6 @@ const MetadataNav = createReactClass({
<h4>Tags</h4> <h4>Tags</h4>
<p>{this.getTags()}</p> <p>{this.getTags()}</p>
</div> </div>
<div className='row'>
<h4>Systems</h4>
<p>{this.getSystems()}</p>
</div>
<div className='row'> <div className='row'>
<h4>Updated</h4> <h4>Updated</h4>
<p>{Moment(this.props.brew.updatedAt).fromNow()}</p> <p>{Moment(this.props.brew.updatedAt).fromNow()}</p>
+1 -1
View File
@@ -24,7 +24,7 @@ const NewBrew = ()=>{
localStorage.setItem(BREWKEY, newBrew.text); localStorage.setItem(BREWKEY, newBrew.text);
localStorage.setItem(STYLEKEY, newBrew.style); localStorage.setItem(STYLEKEY, newBrew.style);
localStorage.setItem(METAKEY, JSON.stringify( localStorage.setItem(METAKEY, JSON.stringify(
_.pick(newBrew, ['title', 'description', 'tags', 'systems', 'renderer', 'theme', 'lang']) _.pick(newBrew, ['title', 'description', 'tags', 'renderer', 'theme', 'lang'])
)); ));
window.location.href = '/new'; window.location.href = '/new';
return; return;
@@ -1,7 +1,6 @@
.homebrew { .homebrew {
.uiPage.sitePage { .uiPage.sitePage:has(.errorTitle) {
.errorTitle { .errorTitle {
//background-color: @orange;
color : #D02727; color : #D02727;
text-align : center; text-align : center;
} }
+22 -1
View File
@@ -19,7 +19,28 @@
<main id="reactRoot"></main> <main id="reactRoot"></main>
<script type="module"> <script type="module">
if (window.location.pathname.startsWith('/admin')) { const props = window.__INITIAL_PROPS__ || {};
const url = props.config?.baseUrl;
const title = props.brew?.title;
let prefix = '';
if (url && url?.includes('://homebrewery-stage.')) {
prefix = `Stage `;
} else if (url?.includes('://homebrewery-pr-')) {
const match = url.match(/pr-(\d+)/);
if (match) prefix = `PR-${match[1]} `;
} else if (url?.includes('://localhost')) {
prefix = 'Local ';
}
if (title) {
document.title = `${prefix} - ${title} - The Homebrewery`;
} else if (prefix) {
document.title = `${prefix} - The Homebrewery`;
}
if (window.location.pathname.startsWith('/admin')) {
import('/client/admin/main.jsx'); import('/client/admin/main.jsx');
} else { } else {
import('/client/homebrew/main.jsx'); import('/client/homebrew/main.jsx');
+1109 -1220
View File
File diff suppressed because it is too large Load Diff
+20 -20
View File
@@ -1,11 +1,11 @@
{ {
"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.1", "version": "3.21.0",
"type": "module", "type": "module",
"engines": { "engines": {
"npm": "^10.8.x", "npm": ">=10.8 <12",
"node": "^20.18.x" "node": ">=20.18 <25"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@@ -88,9 +88,9 @@
"dependencies": { "dependencies": {
"@babel/core": "^7.29.0", "@babel/core": "^7.29.0",
"@babel/plugin-transform-runtime": "^7.29.0", "@babel/plugin-transform-runtime": "^7.29.0",
"@babel/preset-env": "^7.29.0", "@babel/preset-env": "^7.29.2",
"@babel/preset-react": "^7.28.5", "@babel/preset-react": "^7.28.5",
"@babel/runtime": "^7.28.6", "@babel/runtime": "^7.29.2",
"@dmsnell/diff-match-patch": "^1.1.0", "@dmsnell/diff-match-patch": "^1.1.0",
"@googleapis/drive": "^20.1.0", "@googleapis/drive": "^20.1.0",
"@sanity/diff-match-patch": "^3.2.0", "@sanity/diff-match-patch": "^3.2.0",
@@ -99,7 +99,7 @@
"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.49.0",
"cors": "^2.8.5", "cors": "^2.8.5",
"create-react-class": "^15.7.0", "create-react-class": "^15.7.0",
"dedent": "^1.7.1", "dedent": "^1.7.1",
@@ -112,8 +112,8 @@
"idb-keyval": "^6.2.2", "idb-keyval": "^6.2.2",
"js-yaml": "^4.1.1", "js-yaml": "^4.1.1",
"jwt-simple": "^0.5.6", "jwt-simple": "^0.5.6",
"less": "^4.5.1", "less": "^4.6.4",
"lodash": "^4.17.21", "lodash": "^4.18.1",
"marked": "15.0.12", "marked": "15.0.12",
"marked-alignment-paragraphs": "^1.0.0", "marked-alignment-paragraphs": "^1.0.0",
"marked-definition-lists": "^1.0.1", "marked-definition-lists": "^1.0.1",
@@ -126,32 +126,32 @@
"marked-variables": "^1.0.5", "marked-variables": "^1.0.5",
"markedLegacy": "npm:marked@^0.3.19", "markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.30.1", "moment": "^2.30.1",
"mongoose": "^9.2.1", "mongoose": "^9.3.3",
"nanoid": "5.1.6", "nanoid": "5.1.7",
"nconf": "^0.13.0", "nconf": "^0.13.0",
"node": "^25.7.0", "node": "^25.9.0",
"react": "^19.2.4", "react": "^19.2.4",
"react-dom": "^19.2.4", "react-dom": "^19.2.4",
"react-frame-component": "^5.2.7", "react-frame-component": "^5.3.2",
"react-router": "^7.13.1", "react-router": "^7.14.0",
"sanitize-filename": "1.6.3", "sanitize-filename": "1.6.4",
"superagent": "^10.2.1" "superagent": "^10.2.1"
}, },
"devDependencies": { "devDependencies": {
"@stylistic/stylelint-plugin": "^5.0.1", "@stylistic/stylelint-plugin": "^5.0.1",
"babel-jest": "^30.2.0", "babel-jest": "^30.3.0",
"babel-plugin-transform-import-meta": "^2.3.3", "babel-plugin-transform-import-meta": "^2.3.3",
"eslint": "^9.39.1", "eslint": "9.7",
"eslint-plugin-jest": "^29.1.0", "eslint-plugin-jest": "^29.15.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.3.0",
"jest-expect-message": "^1.1.3", "jest-expect-message": "^1.1.3",
"jsdom": "^28.1.0", "jsdom": "^28.1.0",
"jsdom-global": "^3.0.2", "jsdom-global": "^3.0.2",
"postcss-less": "^6.0.0", "postcss-less": "^6.0.0",
"stylelint": "^17.4.0", "stylelint": "^17.6.0",
"stylelint-config-recess-order": "^7.6.1", "stylelint-config-recess-order": "^7.7.0",
"stylelint-config-recommended": "^18.0.0", "stylelint-config-recommended": "^18.0.0",
"supertest": "^7.1.4", "supertest": "^7.1.4",
"vite": "^7.3.1" "vite": "^7.3.1"
-1
View File
@@ -14,7 +14,6 @@ const DEFAULT_BREW = {
theme : '5ePHB', theme : '5ePHB',
authors : [], authors : [],
tags : [], tags : [],
systems : [],
lang : 'en', lang : 'en',
thumbnail : '', thumbnail : '',
views : 0, views : 0,
-2
View File
@@ -151,7 +151,6 @@ const GoogleActions = {
description : file.description, description : file.description,
views : parseInt(file.properties.views), views : parseInt(file.properties.views),
published : file.properties.published ? file.properties.published == 'true' : false, published : file.properties.published ? file.properties.published == 'true' : false,
systems : [],
lang : file.properties.lang, lang : file.properties.lang,
thumbnail : file.properties.thumbnail, thumbnail : file.properties.thumbnail,
webViewLink : file.webViewLink webViewLink : file.webViewLink
@@ -298,7 +297,6 @@ const GoogleActions = {
text : file.data, text : file.data,
description : obj.data.description, description : obj.data.description,
systems : obj.data.properties.systems ? obj.data.properties.systems.split(',') : [],
authors : [], authors : [],
lang : obj.data.properties.lang, lang : obj.data.properties.lang,
published : obj.data.properties.published ? obj.data.properties.published == 'true' : false, published : obj.data.properties.published ? obj.data.properties.published == 'true' : false,
+29 -2
View File
@@ -31,6 +31,27 @@ const isStaticTheme = (renderer, themeName)=>{
// }); // });
// }; // };
const migrateSystemsToTags = (brew) => {
if (!('systems' in brew)) return brew;
if (!Array.isArray(brew.systems) || brew.systems.length === 0) {
brew.systems = undefined;
return brew;
}
const systemMap = {
'5e': 'system:D&D 5e',
'4e': 'system:D&D 4e',
'3.5e': 'system:D&D 3.5e',
'Pathfinder': 'system:Pathfinder 2e'
};
const systemTags = brew.systems.map(s => systemMap[s]);
brew.tags = _.uniq([...(brew.tags || []), ...systemTags]);
brew.systems = undefined;
return brew;
};
const MAX_TITLE_LENGTH = 100; const MAX_TITLE_LENGTH = 100;
const api = { const api = {
@@ -167,7 +188,10 @@ const api = {
stub.renderer = stub.renderer || undefined; // Clear empty strings stub.renderer = stub.renderer || undefined; // Clear empty strings
stub = _.defaults(stub, DEFAULT_BREW_LOAD); // Fill in blank fields stub = _.defaults(stub, DEFAULT_BREW_LOAD); // Fill in blank fields
req.brew = stub;
const fixedStub = migrateSystemsToTags(stub);
req.brew = fixedStub;
next(); next();
}; };
}, },
@@ -193,7 +217,7 @@ const api = {
`\`\`\`\n\n` + `\`\`\`\n\n` +
`${text}`; `${text}`;
} }
const metadata = _.pick(brew, ['title', 'description', 'tags', 'systems', 'renderer', 'theme']); const metadata = _.pick(brew, ['title', 'description', 'tags', 'renderer', 'theme']);
const snippetsArray = brewSnippetsToJSON('brew_snippets', brew.snippets, null, false).snippets; const snippetsArray = brewSnippetsToJSON('brew_snippets', brew.snippets, null, false).snippets;
metadata.snippets = snippetsArray.length > 0 ? snippetsArray : undefined; metadata.snippets = snippetsArray.length > 0 ? snippetsArray : undefined;
text = `\`\`\`metadata\n` + text = `\`\`\`metadata\n` +
@@ -392,6 +416,9 @@ const api = {
} }
let brew = _.assign(brewFromServer, brewFromClient); let brew = _.assign(brewFromServer, brewFromClient);
migrateSystemsToTags(brew);
brew.title = brew.title.trim(); brew.title = brew.title.trim();
brew.description = brew.description.trim() || ''; brew.description = brew.description.trim() || '';
brew.text = api.mergeBrewText(brew); brew.text = api.mergeBrewText(brew);
-27
View File
@@ -63,7 +63,6 @@ describe('Tests for api', ()=>{
title : 'some title', title : 'some title',
description : 'this is a description', description : 'this is a description',
tags : ['something', 'fun'], tags : ['something', 'fun'],
systems : ['D&D 5e'],
lang : 'en', lang : 'en',
renderer : 'v3', renderer : 'v3',
theme : 'phb', theme : 'phb',
@@ -351,7 +350,6 @@ describe('Tests for api', ()=>{
renderer : 'legacy', renderer : 'legacy',
lang : 'en', lang : 'en',
shareId : undefined, shareId : undefined,
systems : [],
tags : [], tags : [],
theme : '5ePHB', theme : '5ePHB',
thumbnail : '', thumbnail : '',
@@ -390,7 +388,6 @@ describe('Tests for api', ()=>{
title : 'some title', title : 'some title',
description : 'this is a description', description : 'this is a description',
tags : ['something', 'fun'], tags : ['something', 'fun'],
systems : ['D&D 5e'],
renderer : 'v3', renderer : 'v3',
theme : 'phb', theme : 'phb',
googleId : '12345' googleId : '12345'
@@ -402,8 +399,6 @@ description: this is a description
tags: tags:
- something - something
- fun - fun
systems:
- D&D 5e
renderer: v3 renderer: v3
theme: phb theme: phb
@@ -419,7 +414,6 @@ brew`);
title : 'some title', title : 'some title',
description : 'this is a description', description : 'this is a description',
tags : ['something', 'fun'], tags : ['something', 'fun'],
systems : ['D&D 5e'],
renderer : 'v3', renderer : 'v3',
theme : 'phb', theme : 'phb',
googleId : '12345' googleId : '12345'
@@ -431,8 +425,6 @@ description: this is a description
tags: tags:
- something - something
- fun - fun
systems:
- D&D 5e
renderer: v3 renderer: v3
theme: phb theme: phb
@@ -463,7 +455,6 @@ brew`);
expect(sent).toEqual(googleBrew); expect(sent).toEqual(googleBrew);
expect(result.tags).toBeUndefined(); expect(result.tags).toBeUndefined();
expect(result.systems).toBeUndefined();
expect(result.published).toBeUndefined(); expect(result.published).toBeUndefined();
expect(result.authors).toBeUndefined(); expect(result.authors).toBeUndefined();
expect(result.owner).toBeUndefined(); expect(result.owner).toBeUndefined();
@@ -558,7 +549,6 @@ brew`);
lang : 'en', lang : 'en',
shareId : expect.any(String), shareId : expect.any(String),
style : undefined, style : undefined,
systems : [],
tags : [], tags : [],
text : undefined, text : undefined,
textBin : expect.objectContaining({}), textBin : expect.objectContaining({}),
@@ -618,7 +608,6 @@ brew`);
shareId : expect.any(String), shareId : expect.any(String),
googleId : expect.any(String), googleId : expect.any(String),
style : undefined, style : undefined,
systems : [],
tags : [], tags : [],
text : undefined, text : undefined,
textBin : undefined, textBin : undefined,
@@ -1076,7 +1065,6 @@ brew`);
'title: title\n' + 'title: title\n' +
'description: description\n' + 'description: description\n' +
'tags: [ \'tag a\' , \'tag b\' ]\n' + 'tags: [ \'tag a\' , \'tag b\' ]\n' +
'systems: [ test system ]\n' +
'renderer: legacy\n' + 'renderer: legacy\n' +
'theme: 5ePHB\n' + 'theme: 5ePHB\n' +
'lang: en\n' + 'lang: en\n' +
@@ -1097,8 +1085,6 @@ brew`);
// Metadata // Metadata
expect(testBrew.title).toEqual('title'); expect(testBrew.title).toEqual('title');
expect(testBrew.description).toEqual('description'); expect(testBrew.description).toEqual('description');
expect(testBrew.tags).toEqual(['tag a', 'tag b']);
expect(testBrew.systems).toEqual(['test system']);
expect(testBrew.renderer).toEqual('legacy'); expect(testBrew.renderer).toEqual('legacy');
expect(testBrew.theme).toEqual('5ePHB'); expect(testBrew.theme).toEqual('5ePHB');
expect(testBrew.lang).toEqual('en'); expect(testBrew.lang).toEqual('en');
@@ -1107,19 +1093,6 @@ brew`);
// Text // Text
expect(testBrew.text).toEqual('text\n'); expect(testBrew.text).toEqual('text\n');
}); });
it('convert tags string to array', async ()=>{
const testBrew = {
text : '```metadata\n' +
'tags: tag a\n' +
'```\n\n'
};
splitTextStyleAndMetadata(testBrew);
// Metadata
expect(testBrew.tags).toEqual(['tag a']);
});
}); });
describe('updateBrew', ()=>{ describe('updateBrew', ()=>{
+1 -1
View File
@@ -15,7 +15,7 @@ const HomebrewSchema = mongoose.Schema({
description : { type: String, default: '' }, description : { type: String, default: '' },
tags : { type: [String], index: true }, tags : { type: [String], index: true },
systems : [String], systems : { type: [String], default: undefined },
lang : { type: String, default: 'en', index: true }, lang : { type: String, default: 'en', index: true },
renderer : { type: String, default: '', index: true }, renderer : { type: String, default: '', index: true },
authors : { type: [String], index: true }, authors : { type: [String], index: true },
+1 -1
View File
@@ -91,7 +91,7 @@ const splitTextStyleAndMetadata = (brew)=>{
const index = brew.text.indexOf('\n```\n\n'); const index = brew.text.indexOf('\n```\n\n');
const metadataSection = brew.text.slice(11, index + 1); const metadataSection = brew.text.slice(11, index + 1);
const metadata = yaml.load(metadataSection); const metadata = yaml.load(metadataSection);
Object.assign(brew, _.pick(metadata, ['title', 'description', 'tags', 'systems', 'renderer', 'theme', 'lang'])); Object.assign(brew, _.pick(metadata, ['title', 'description', 'renderer', 'theme', 'lang']));
brew.snippets = yamlSnippetsToText(_.pick(metadata, ['snippets']).snippets || ''); brew.snippets = yamlSnippetsToText(_.pick(metadata, ['snippets']).snippets || '');
brew.text = brew.text.slice(index + 6); brew.text = brew.text.slice(index + 6);
} }
+3 -3
View File
@@ -70,9 +70,9 @@ renderer.link = function (token) {
if(title) { if(title) {
out += ` title="${escape(title)}"`; out += ` title="${escape(title)}"`;
} }
if(self) { // if(self) {
out += ' target="_self"'; // out += ' target="_self"';
} // }
out += `>${text}</a>`; out += `>${text}</a>`;
return out; return out;
}; };
+3 -3
View File
@@ -34,9 +34,9 @@ renderer.link = function (href, title, text) {
if(title) { if(title) {
out += ` title="${title}"`; out += ` title="${title}"`;
} }
if(self) { // if(self) {
out += ' target="_self"'; // out += ' target="_self"';
} // }
out += `>${text}</a>`; out += `>${text}</a>`;
return out; return out;
}; };
+7 -5
View File
@@ -8,8 +8,10 @@ test('Processes the markdown within an HTML block if its just a class wrapper',
expect(rendered).toBe('<div> <p><em>Bold text</em></p>\n </div>'); expect(rendered).toBe('<div> <p><em>Bold text</em></p>\n </div>');
}); });
test('Check markdown is using the custom renderer; specifically that it adds target=_self attribute to internal links in HTML blocks', function() { // TEST REMOVED AS IT IS NO LONGER REQUIRED
const source = '<div>[Has _self Attribute?](#p1)</div>'; //
const rendered = Markdown.render(source); // test('Check markdown is using the custom renderer; specifically that it adds target=_self attribute to internal links in HTML blocks', function() {
expect(rendered).toBe('<div> <p><a href="#p1" target="_self">Has _self Attribute?</a></p>\n </div>'); // const source = '<div>[Has _self Attribute?](#p1)</div>';
}); // const rendered = Markdown.render(source);
// expect(rendered).toBe('<div> <p><a href="#p1" target="_self">Has _self Attribute?</a></p>\n </div>');
// });
+2 -2
View File
@@ -143,8 +143,8 @@ export default [
gen : function(){ gen : function(){
return dedent` return dedent`
{{artist,top:90px,right:30px {{artist,top:90px,right:30px
##### Starry Night ##### Bird with autumn foliage
[Van Gogh](https://www.vangoghmuseum.nl/en) [by L. Prang & Co.](https://www.loc.gov/resource/pga.14148)
}} }}
\n`; \n`;
}, },
+8 -7
View File
@@ -1,5 +1,6 @@
import _ from 'lodash'; import _ from 'lodash';
import dedent from 'dedent'; import dedent from 'dedent';
const domain = window.location.origin;
const titles = [ const titles = [
'The Burning Gallows', 'The Ring of Nenlast', 'The Burning Gallows', 'The Ring of Nenlast',
@@ -84,7 +85,7 @@ export default {
return dedent` return dedent`
{{frontCover}} {{frontCover}}
{{logo ![](https://homebrewery.naturalcrit.com/assets/naturalCritLogoRed.svg)}} {{logo ![](${domain}/assets/naturalCritLogoRed.svg)}}
# ${_.sample(titles)} # ${_.sample(titles)}
## ${_.sample(subtitles)} ## ${_.sample(subtitles)}
@@ -96,7 +97,7 @@ export default {
${_.sample(footnote)} ${_.sample(footnote)}
}} }}
![background image](https://homebrewery.naturalcrit.com/assets/demontemple.jpg){position:absolute,bottom:0,left:0,height:100%} ![The Departure, 1837, by Thomas Cole](${domain}/assets/the_departure.webp){position:absolute,bottom:0,right:-400px,height:100%}
\page`; \page`;
}, },
@@ -110,10 +111,10 @@ export default {
___ ___
{{imageMaskCenter${_.random(1, 16)},--offsetX:0%,--offsetY:0%,--rotation:0 {{imageMaskCenter${_.random(1, 16)},--offsetX:0%,--offsetY:0%,--rotation:0
![background image](https://homebrewery.naturalcrit.com/assets/mountaincottage.jpg){position:absolute,bottom:0,left:0,height:100%} ![The Spirit of War, 1851, by Jasper Francis Cropsey](${domain}/assets/the_spirit_of_war.webp){position:absolute,bottom:100px,right:70px,height:70%}
}} }}
{{logo ![](https://homebrewery.naturalcrit.com/assets/naturalCritLogoRed.svg)}} {{logo ![](${domain}/assets/naturalCritLogoRed.svg)}}
\page`; \page`;
}, },
@@ -126,7 +127,7 @@ export default {
## ${_.sample(subtitles)} ## ${_.sample(subtitles)}
{{imageMaskEdge${_.random(1, 8)},--offset:10cm,--rotation:180 {{imageMaskEdge${_.random(1, 8)},--offset:10cm,--rotation:180
![Background image](https://homebrewery.naturalcrit.com/assets/nightchapel.jpg){position:absolute,bottom:0,left:0,height:100%} ![The United States Frigate "President" Engaging the British Squadron, 1815, 1850, by Fitz Henry Lane](${domain}/assets/frigate.webp){position:absolute,bottom:0,right:0,height:100%}
}} }}
\page`; \page`;
@@ -143,10 +144,10 @@ export default {
For use with any fantasy roleplaying ruleset. Play the best game of your life! For use with any fantasy roleplaying ruleset. Play the best game of your life!
![background image](https://homebrewery.naturalcrit.com/assets/shopvials.jpg){position:absolute,bottom:0,left:0,height:100%} ![Italian Coast Scene with Ruined Tower, 1838, by Thomas Cole](${domain}/assets/ruined_tower.webp){position:absolute,bottom:0,right:-250px,height:100%}
{{logo {{logo
![](https://homebrewery.naturalcrit.com/assets/naturalCritLogoWhite.svg) ![](${domain}/assets/naturalCritLogoWhite.svg)
Homebrewery.Naturalcrit.com Homebrewery.Naturalcrit.com
}}`; }}`;
+5 -4
View File
@@ -11,6 +11,7 @@ import LicenseDTTRPGGCC from './snippets/licenseDTRPGCC.gen.js';
import LicenseMongoosePublishing from './snippets/licenseMongoose.gen.js'; import LicenseMongoosePublishing from './snippets/licenseMongoose.gen.js';
import TableOfContentsGen from './snippets/tableOfContents.gen.js'; import TableOfContentsGen from './snippets/tableOfContents.gen.js';
import indexGen from './snippets/index.gen.js'; import indexGen from './snippets/index.gen.js';
const domain = window.location.origin;
export default [ export default [
@@ -645,25 +646,25 @@ export default [
name : 'Image', name : 'Image',
icon : 'fas fa-image', icon : 'fas fa-image',
gen : dedent` gen : dedent`
![cat warrior](https://homebrewery.naturalcrit.com/assets/catwarrior.jpg) {width:325px,mix-blend-mode:multiply}` ![Bird with autumn foliage by L. Prang & Co.](${domain}/assets/bird.webp) {width:325px}`
}, },
{ {
name : 'Image Wrap Left', name : 'Image Wrap Left',
icon : 'fac image-wrap-left', icon : 'fac image-wrap-left',
gen : dedent` gen : dedent`
![homebrewery_mug](https://homebrewery.naturalcrit.com/assets/homebrewerymug.png) {width:280px,margin-right:-3cm,wrapLeft}` ![homebrewery_mug](${domain}/assets/homebrewerymug.png) {width:280px,margin-right:-3cm,wrapLeft}`
}, },
{ {
name : 'Image Wrap Right', name : 'Image Wrap Right',
icon : 'fac image-wrap-right', icon : 'fac image-wrap-right',
gen : dedent` gen : dedent`
![homebrewery_mug](https://homebrewery.naturalcrit.com/assets/homebrewerymug.png) {width:280px,margin-left:-3cm,wrapRight}` ![homebrewery_mug](${domain}/assets/homebrewerymug.png) {width:280px,margin-left:-3cm,wrapRight}`
}, },
{ {
name : 'Background Image', name : 'Background Image',
icon : 'fas fa-tree', icon : 'fas fa-tree',
gen : dedent` gen : dedent`
![homebrew mug](https://homebrewery.naturalcrit.com/assets/homebrewerymug.png) {position:absolute,top:50px,right:30px,width:280px}` ![homebrew mug](${domain}/assets/homebrewerymug.png) {position:absolute,top:50px,right:30px,width:280px}`
}, },
{ {
name : 'Watercolor Splatter', name : 'Watercolor Splatter',
+19 -4
View File
@@ -1,11 +1,12 @@
import _ from 'lodash'; import _ from 'lodash';
import dedent from 'dedent'; import dedent from 'dedent';
const domain = window.location.origin;
export default { export default {
center : ()=>{ center : ()=>{
return dedent` return dedent`
{{imageMaskCenter${_.random(1, 16)},--offsetX:0%,--offsetY:0%,--rotation:0 {{imageMaskCenter${_.random(1, 16)},--offsetX:0%,--offsetY:0%,--rotation:0
![](https://homebrewery.naturalcrit.com/assets/dragoninflight.jpg){height:100%} ![The Roman Theater at Taormina, 1828, by Louise-Joséphine sarazin de Belmont](${domain}/assets/roman_theatre.webp){height:100%}
}} }}
<!-- Use --offsetX to shift the mask left or right (can use cm instead of %) <!-- Use --offsetX to shift the mask left or right (can use cm instead of %)
Use --offsetY to shift the mask up or down Use --offsetY to shift the mask up or down
@@ -13,6 +14,20 @@ export default {
}, },
edge : (side = 'bottom')=>{ edge : (side = 'bottom')=>{
const styles = ()=>{
switch (side) {
case 'bottom':
return `{width:100%,bottom:0%}`
break;
case 'top':
return `{width:100%,top:0%}`
break;
default:
return `{height:100%}`
break;
}
}
const rotation = { const rotation = {
'bottom' : 0, 'bottom' : 0,
'top' : 180, 'top' : 180,
@@ -20,8 +35,8 @@ export default {
'right' : 270 'right' : 270
}[side]; }[side];
return dedent` return dedent`
{{imageMaskEdge${_.random(1, 8)},--offset:0%,--rotation:${rotation} {{imageMaskEdge${_.random(1, 8)},--offset:10%,--rotation:${rotation}
![](https://homebrewery.naturalcrit.com/assets/dragoninflight.jpg){height:100%} ![The Roman Theater at Taormina, 1828, by Louise-Joséphine sarazin de Belmont](${domain}/assets/roman_theatre.webp)${styles()}
}} }}
<!-- Use --offset to shift the mask away from page center (can use cm instead of %) <!-- Use --offset to shift the mask away from page center (can use cm instead of %)
Use --rotation to set rotation angle in degrees. -->\n\n`; Use --rotation to set rotation angle in degrees. -->\n\n`;
@@ -32,7 +47,7 @@ export default {
const offsetY = (y == 'top' ? '50%' : '-50%'); const offsetY = (y == 'top' ? '50%' : '-50%');
return dedent` return dedent`
{{imageMaskCorner${_.random(1, 37)},--offsetX:${offsetX},--offsetY:${offsetY},--rotation:0 {{imageMaskCorner${_.random(1, 37)},--offsetX:${offsetX},--offsetY:${offsetY},--rotation:0
![](https://homebrewery.naturalcrit.com/assets/dragoninflight.jpg){height:100%} ![The Roman Theater at Taormina, 1828, by Louise-Joséphine sarazin de Belmont](${domain}/assets/roman_theatre.webp){height:100%}
}} }}
<!-- Use --offsetX to shift the mask left or right (can use cm instead of %) <!-- Use --offsetX to shift the mask left or right (can use cm instead of %)
Use --offsetY to shift the mask up or down Use --offsetY to shift the mask up or down
+4 -3
View File
@@ -1,5 +1,6 @@
import dedent from 'dedent'; import dedent from 'dedent';
const domain = window.location.origin;
// Small and one-off licenses // Small and one-off licenses
// Licenses in this file consist of one or two functions at most. If something is larger, // Licenses in this file consist of one or two functions at most. If something is larger,
@@ -50,10 +51,10 @@ export default {
ccbyndBadge : `![CC BY-ND](https://mirrors.creativecommons.org/presskit/buttons/88x31/svg/by-nd.svg)`, ccbyndBadge : `![CC BY-ND](https://mirrors.creativecommons.org/presskit/buttons/88x31/svg/by-nd.svg)`,
ccbyncndBadge : `![CC BY-NC-ND](https://mirrors.creativecommons.org/presskit/buttons/88x31/svg/by-nc-nd.svg)`, ccbyncndBadge : `![CC BY-NC-ND](https://mirrors.creativecommons.org/presskit/buttons/88x31/svg/by-nc-nd.svg)`,
shadowDarkNotice : `\[Product Name]\ is an independent product published under the Shadowdark RPG Third-Party License and is not affiliated with The Arcane Library, LLC. Shadowdark RPG © 2023 The Arcane Library, LLC.\n`, shadowDarkNotice : `\[Product Name]\ is an independent product published under the Shadowdark RPG Third-Party License and is not affiliated with The Arcane Library, LLC. Shadowdark RPG © 2023 The Arcane Library, LLC.\n`,
shadowDarkBlack : `![Shadowdark Black Logo](https://homebrewery.naturalcrit.com/assets/license_logos/The-Arcane-Library_Third-Party-License_Black.png){width:200px}`, shadowDarkBlack : `![Shadowdark Black Logo](${domain}/assets/license_logos/The-Arcane-Library_Third-Party-License_Black.png){width:200px}`,
shadowDarkWhite : `![Shadowdark White Logo](https://homebrewery.naturalcrit.com/assets/license_logos/The-Arcane-Library_Third-Party-License_White.png){width:200px}`, shadowDarkWhite : `![Shadowdark White Logo](${domain}/assets/license_logos/The-Arcane-Library_Third-Party-License_White.png){width:200px}`,
bladesDarkNotice : `This work is based on Blades in the Dark \(found at (http://www.bladesinthedark.com/)\), product of One Seven Design, developed and authored by John Harper, and licensed for our use under the Creative Commons Attribution 3.0 Unported license \(http://creativecommons.org/licenses/by/3.0/\).\n`, bladesDarkNotice : `This work is based on Blades in the Dark \(found at (http://www.bladesinthedark.com/)\), product of One Seven Design, developed and authored by John Harper, and licensed for our use under the Creative Commons Attribution 3.0 Unported license \(http://creativecommons.org/licenses/by/3.0/\).\n`,
bladesDarkLogo : `![Forged in the Dark](https://homebrewery.naturalcrit.com/assets/license_logos/Evil-Hat_Forged-In-The-Dark_Logo-V2.png)`, bladesDarkLogo : `![Forged in the Dark](${domain}/assets/license_logos/Evil-Hat_Forged-In-The-Dark_Logo-V2.png)`,
bladesDarkLogoAttribution : `*Blades in the Dark^tm^ is a trademark of One Seven Design. The Forged in the Dark Logo is © One Seven Design, and is used with permission.*`, bladesDarkLogoAttribution : `*Blades in the Dark^tm^ is a trademark of One Seven Design. The Forged in the Dark Logo is © One Seven Design, and is used with permission.*`,
iconsCompatibility : 'Compatibility with Icons requires Icons Superpowered Roleplaying from Ad Infinitum Adventures. Ad Infinitum Adventures does not guarantee compatibility, and does not endorse this product.', iconsCompatibility : 'Compatibility with Icons requires Icons Superpowered Roleplaying from Ad Infinitum Adventures. Ad Infinitum Adventures does not guarantee compatibility, and does not endorse this product.',
iconsTrademark : 'Icons Superpowered Roleplaying is a trademark of Steve Kenson, published exclusively by Ad Infinitum Adventures. The Icons Superpowered Roleplaying Compatibility Logo is a trademark of Ad Infinitum Adventures and is used under the Icons Superpowered Roleplaying Compatibility License.', iconsTrademark : 'Icons Superpowered Roleplaying is a trademark of Steve Kenson, published exclusively by Ad Infinitum Adventures. The Icons Superpowered Roleplaying Compatibility Logo is a trademark of Ad Infinitum Adventures and is used under the Icons Superpowered Roleplaying Compatibility License.',
@@ -1,5 +1,6 @@
import dedent from 'dedent'; import dedent from 'dedent';
const domain = window.location.origin;
// DriveThruRPG/OneBookShelf Community Content Programs // DriveThruRPG/OneBookShelf Community Content Programs
@@ -101,10 +102,10 @@ export default {
}, },
// Verify Logo redistribution // Verify Logo redistribution
greenRoninAgeCreatorsAllianceCover : `Requires the \[Game Title\] Rulebook from Green Ronin Publishing for use.`, greenRoninAgeCreatorsAllianceCover : `Requires the \[Game Title\] Rulebook from Green Ronin Publishing for use.`,
greenRoninAgeCreatorsAllianceLogo : `![Age Creators Alliance](https://homebrewery.naturalcrit.com/assets/license_logos/Green-Ronin_AGE-Creators-Alliance_General-Compatibility-Logo.png){width:200px}`, greenRoninAgeCreatorsAllianceLogo : `![Age Creators Alliance](${domain}/assets/license_logos/Green-Ronin_AGE-Creators-Alliance_General-Compatibility-Logo.png){width:200px}`,
greenRoninAgeCreatorsAllianceBlueRoseLogo : `![Age Creators Alliance](https://homebrewery.naturalcrit.com/assets/license_logos/Green-Ronin_AGE-Creators-Alliance_Blue-Rose-Compatibility-Logo.png){width:200px}`, greenRoninAgeCreatorsAllianceBlueRoseLogo : `![Age Creators Alliance](${domain}/assets/license_logos/Green-Ronin_AGE-Creators-Alliance_Blue-Rose-Compatibility-Logo.png){width:200px}`,
greenRoninAgeCreatorsAllianceFantasyAgeCompatible : `![Fantasy AGE Compatible](https://homebrewery.naturalcrit.com/assets/license_logos/Green-Ronin_AGE-Creators-Alliance_Fantasy-AGE-Compatibility-Logo.png){width:200px}`, greenRoninAgeCreatorsAllianceFantasyAgeCompatible : `![Fantasy AGE Compatible](${domain}/assets/license_logos/Green-Ronin_AGE-Creators-Alliance_Fantasy-AGE-Compatibility-Logo.png){width:200px}`,
greenRoninAgeCreatorsAllianceModernAGECompatible : `![Modern AGE Compatible](https://homebrewery.naturalcrit.com/assets/license_logos/Green-Ronin_AGE-Creators-Alliance_Modern-AGE-Compatibility-Logo.png){width:200px}`, greenRoninAgeCreatorsAllianceModernAGECompatible : `![Modern AGE Compatible](${domain}/assets/license_logos/Green-Ronin_AGE-Creators-Alliance_Modern-AGE-Compatibility-Logo.png){width:200px}`,
// Green Ronin's Chronicle - Verify Art and Access // Green Ronin's Chronicle - Verify Art and Access
greenRoninChronicleSystemGuildColophon : function() { greenRoninChronicleSystemGuildColophon : function() {
return dedent` return dedent`
@@ -179,10 +180,10 @@ export default {
`; `;
}, },
// Verify Logo redistribution // Verify Logo redistribution
monteCookLogoDarkLarge : `![Cypher System Compatible](https://homebrewery.naturalcrit.com/assets/license_logos/CSCDarkLarge.png)`, monteCookLogoDarkLarge : `![Cypher System Compatible](${domain}/assets/license_logos/CSCDarkLarge.png)`,
monteCookLogoDarkSmall : `![Cypher System Compatible](https://homebrewery.naturalcrit.com/assets/license_logos/CSCDarkSmall.png)`, monteCookLogoDarkSmall : `![Cypher System Compatible](${domain}/assets/license_logos/CSCDarkSmall.png)`,
monteCookLogoLightLarge : `![Cypher System Compatible](https://homebrewery.naturalcrit.com/assets/license_logos/CSCLightLarge.png)`, monteCookLogoLightLarge : `![Cypher System Compatible](${domain}/assets/license_logos/CSCLightLarge.png)`,
monteCookLogoLightSmall : `![Cypher System Compatible](https://homebrewery.naturalcrit.com/assets/license_logos/CSCLightSmall.png)`, monteCookLogoLightSmall : `![Cypher System Compatible](${domain}/assets/license_logos/CSCLightSmall.png)`,
// Onyx Path Canis Minor - Verify logos and access // Onyx Path Canis Minor - Verify logos and access
onyxPathCanisMinorColophon : function () { onyxPathCanisMinorColophon : function () {
return dedent` return dedent`
Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 366 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 278 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 219 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

+4 -4
View File
@@ -33,26 +33,26 @@
font-family : "NodestoCapsCondensed"; font-family : "NodestoCapsCondensed";
font-style : normal; font-style : normal;
font-weight : normal; font-weight : normal;
src : url('../fonts/5e/Nodesto Caps Condensed.woff2'); src : url('../../../fonts/5e/Nodesto Caps Condensed.woff2');
} }
@font-face { @font-face {
font-family : "NodestoCapsCondensed"; font-family : "NodestoCapsCondensed";
font-style : normal; font-style : normal;
font-weight : bold; font-weight : bold;
src : url('../fonts/5e/Nodesto Caps Condensed Bold.woff2'); src : url('../../../fonts/5e/Nodesto Caps Condensed Bold.woff2');
} }
@font-face { @font-face {
font-family : "NodestoCapsCondensed"; font-family : "NodestoCapsCondensed";
font-style : italic; font-style : italic;
font-weight : normal; font-weight : normal;
src : url('../fonts/5e/Nodesto Caps Condensed Italic.woff2'); src : url('../../../fonts/5e/Nodesto Caps Condensed Italic.woff2');
} }
@font-face { @font-face {
font-family : "NodestoCapsCondensed"; font-family : "NodestoCapsCondensed";
font-style : italic; font-style : italic;
font-weight : bold; font-weight : bold;
src : url('../fonts/5e/Nodesto Caps Condensed Bold Italic.woff2'); src : url('../../../fonts/5e/Nodesto Caps Condensed Bold Italic.woff2');
} }