Merge branch 'master' into showThumbnailOnUserPage-#2331
20
changelog.md
@@ -39,6 +39,26 @@ pre {
|
||||
## changelog
|
||||
For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery).
|
||||
|
||||
### Friday 08/09/2022 - v3.2.2
|
||||
{{taskList
|
||||
|
||||
##### Jeddai:
|
||||
|
||||
* [x] Fix brews not deleting from User page when removed from Google Drive externally.
|
||||
|
||||
Fixes issues: [#2325](https://github.com/naturalcrit/homebrewery/issues/2325)
|
||||
|
||||
##### G-Ambatte:
|
||||
|
||||
* [x] Brew Tags are now searchable on the User page
|
||||
|
||||
Fixes issues [#2317](https://github.com/naturalcrit/homebrewery/issues/2317), [#2319](https://github.com/naturalcrit/homebrewery/issues/2319), [#2334](https://github.com/naturalcrit/homebrewery/issues/2334)
|
||||
|
||||
* [x] Several tweaks to the User page
|
||||
|
||||
Fixes issues: [#1797](https://github.com/naturalcrit/homebrewery/issues/1797), [#2315](https://github.com/naturalcrit/homebrewery/issues/2315), [#2326](https://github.com/naturalcrit/homebrewery/issues/2326), [#2328](https://github.com/naturalcrit/homebrewery/issues/2328)
|
||||
}}
|
||||
|
||||
### Wednesday 31/08/2022 - v3.2.1
|
||||
{{taskList
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/*eslint max-lines: ["warn", {"max": 300, "skipBlankLines": true, "skipComments": true}]*/
|
||||
require('./brewRenderer.less');
|
||||
const React = require('react');
|
||||
const createClass = require('create-react-class');
|
||||
@@ -13,6 +14,8 @@ const RenderWarnings = require('homebrewery/renderWarnings/renderWarnings.jsx');
|
||||
const NotificationPopup = require('./notificationPopup/notificationPopup.jsx');
|
||||
const Frame = require('react-frame-component').default;
|
||||
|
||||
const Themes = require('themes/themes.json');
|
||||
|
||||
const PAGE_HEIGHT = 1056;
|
||||
const PPR_THRESHOLD = 50;
|
||||
|
||||
@@ -23,6 +26,7 @@ const BrewRenderer = createClass({
|
||||
text : '',
|
||||
style : '',
|
||||
renderer : 'legacy',
|
||||
theme : '5ePHB',
|
||||
errors : []
|
||||
};
|
||||
},
|
||||
@@ -177,6 +181,9 @@ const BrewRenderer = createClass({
|
||||
render : function(){
|
||||
//render in iFrame so broken code doesn't crash the site.
|
||||
//Also render dummy page while iframe is mounting.
|
||||
const rendererPath = this.props.renderer == 'V3' ? 'V3' : 'Legacy';
|
||||
const themePath = this.props.theme ?? '5ePHB';
|
||||
const baseThemePath = Themes[rendererPath][themePath].baseTheme;
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
@@ -200,7 +207,11 @@ const BrewRenderer = createClass({
|
||||
<RenderWarnings />
|
||||
<NotificationPopup />
|
||||
</div>
|
||||
<link href={`${this.props.renderer == 'legacy' ? '/themes/5ePhbLegacy.style.css' : '/themes/5ePhb.style.css'}`} rel='stylesheet'/>
|
||||
<link href={`/themes/${rendererPath}/Blank/style.css`} rel='stylesheet'/>
|
||||
{baseThemePath &&
|
||||
<link href={`/themes/${rendererPath}/${baseThemePath}/style.css`} rel='stylesheet'/>
|
||||
}
|
||||
<link href={`/themes/${rendererPath}/${themePath}/style.css`} rel='stylesheet'/>
|
||||
{/* Apply CSS from Style tab and render pages from Markdown tab */}
|
||||
{this.state.isMounted
|
||||
&&
|
||||
|
||||
@@ -327,6 +327,7 @@ const Editor = createClass({
|
||||
onInject={this.handleInject}
|
||||
showEditButtons={this.props.showEditButtons}
|
||||
renderer={this.props.renderer}
|
||||
theme={this.props.brew.theme}
|
||||
undo={this.undo}
|
||||
redo={this.redo}
|
||||
historySize={this.historySize()} />
|
||||
|
||||
@@ -5,8 +5,11 @@ const createClass = require('create-react-class');
|
||||
const _ = require('lodash');
|
||||
const cx = require('classnames');
|
||||
const request = require('superagent');
|
||||
const Nav = require('naturalcrit/nav/nav.jsx');
|
||||
const StringArrayEditor = require('../stringArrayEditor/stringArrayEditor.jsx');
|
||||
|
||||
const Themes = require('themes/themes.json');
|
||||
|
||||
const SYSTEMS = ['5e', '4e', '3.5e', 'Pathfinder'];
|
||||
|
||||
const homebreweryThumbnail = require('../../thumbnail.png');
|
||||
@@ -23,7 +26,8 @@ const MetadataEditor = createClass({
|
||||
published : false,
|
||||
authors : [],
|
||||
systems : [],
|
||||
renderer : 'legacy'
|
||||
renderer : 'legacy',
|
||||
theme : '5ePHB'
|
||||
},
|
||||
onChange : ()=>{}
|
||||
};
|
||||
@@ -63,6 +67,8 @@ const MetadataEditor = createClass({
|
||||
handleRenderer : function(renderer, e){
|
||||
if(e.target.checked){
|
||||
this.props.metadata.renderer = renderer;
|
||||
if(renderer == 'legacy')
|
||||
this.props.metadata.theme = '5ePHB';
|
||||
}
|
||||
this.props.onChange(this.props.metadata);
|
||||
},
|
||||
@@ -73,6 +79,12 @@ const MetadataEditor = createClass({
|
||||
});
|
||||
},
|
||||
|
||||
handleTheme : function(theme){
|
||||
this.props.metadata.renderer = theme.renderer;
|
||||
this.props.metadata.theme = theme.path;
|
||||
this.props.onChange(this.props.metadata);
|
||||
},
|
||||
|
||||
handleDelete : function(){
|
||||
if(this.props.metadata.authors && this.props.metadata.authors.length <= 1){
|
||||
if(!confirm('Are you sure you want to delete this brew? Because you are the only owner of this brew, the document will be deleted permanently.')) return;
|
||||
@@ -139,6 +151,45 @@ const MetadataEditor = createClass({
|
||||
</div>;
|
||||
},
|
||||
|
||||
renderThemeDropdown : function(){
|
||||
if(!global.enable_themes) return;
|
||||
|
||||
const listThemes = (renderer)=>{
|
||||
return _.map(_.values(Themes[renderer]), (theme)=>{
|
||||
return <div className='item' key={''} onClick={()=>this.handleTheme(theme)} title={''}>
|
||||
{`${theme.renderer} : ${theme.name}`}
|
||||
<img src={`/themes/${theme.renderer}/${theme.path}/dropdownTexture.png`}/>
|
||||
</div>;
|
||||
});
|
||||
};
|
||||
|
||||
const currentTheme = Themes[`${_.upperFirst(this.props.metadata.renderer)}`][this.props.metadata.theme];
|
||||
let dropdown;
|
||||
|
||||
if(this.props.metadata.renderer == 'legacy') {
|
||||
dropdown =
|
||||
<Nav.dropdown className='disabled' trigger='disabled'>
|
||||
<div>
|
||||
{`Themes are not supported in the Legacy Renderer`} <i className='fas fa-caret-down'></i>
|
||||
</div>
|
||||
</Nav.dropdown>;
|
||||
} else {
|
||||
dropdown =
|
||||
<Nav.dropdown trigger='click'>
|
||||
<div>
|
||||
{`${_.upperFirst(currentTheme.renderer)} : ${currentTheme.name}`} <i className='fas fa-caret-down'></i>
|
||||
</div>
|
||||
{/*listThemes('Legacy')*/}
|
||||
{listThemes('V3')}
|
||||
</Nav.dropdown>;
|
||||
}
|
||||
|
||||
return <div className='field themes'>
|
||||
<label>theme</label>
|
||||
{dropdown}
|
||||
</div>;
|
||||
},
|
||||
|
||||
renderRenderOptions : function(){
|
||||
if(!global.enable_v3) return;
|
||||
|
||||
@@ -212,6 +263,8 @@ const MetadataEditor = createClass({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{this.renderThemeDropdown()}
|
||||
|
||||
{this.renderRenderOptions()}
|
||||
|
||||
<div className='field publish'>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
display : inline-block;
|
||||
vertical-align : top;
|
||||
width : 80px;
|
||||
font-size : 0.7em;
|
||||
font-size : 11px;
|
||||
font-weight : 800;
|
||||
line-height : 1.8em;
|
||||
text-transform : uppercase;
|
||||
@@ -110,6 +110,56 @@
|
||||
line-height : 1.5em;
|
||||
}
|
||||
|
||||
.themes.field{
|
||||
font-size : 13.33px;
|
||||
.navDropdownContainer {
|
||||
background-color : white;
|
||||
width : 100%;
|
||||
position : relative;
|
||||
z-index : 500;
|
||||
&.disabled {
|
||||
font-style :italic;
|
||||
font-style : italic;
|
||||
background-color : darkgray;
|
||||
color : dimgray;
|
||||
}
|
||||
&>div:first-child {
|
||||
border : 2px solid rgb(118,118,118);
|
||||
padding : 6px 3px;
|
||||
background-color : inherit;
|
||||
i {
|
||||
float : right;
|
||||
}
|
||||
&:hover {
|
||||
background-color : @blue;
|
||||
color : white;
|
||||
}
|
||||
}
|
||||
.navDropdown {
|
||||
box-shadow : 0px 5px 10px rgba(0, 0, 0, 0.3);
|
||||
position : absolute;
|
||||
width : 100%;
|
||||
.item {
|
||||
padding : 3px 3px;
|
||||
border-top : 1px solid rgb(118, 118, 118);
|
||||
position : relative;
|
||||
overflow : hidden;
|
||||
background-color : white;
|
||||
&:hover {
|
||||
background-color : @blue;
|
||||
color : white;
|
||||
}
|
||||
img {
|
||||
mask-image : linear-gradient(90deg, transparent, black 20%);
|
||||
-webkit-mask-image : linear-gradient(90deg, transparent, black 20%);
|
||||
position : absolute;
|
||||
left : ~"max(100px, 100% - 300px)";
|
||||
top : 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.field .list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
@@ -4,9 +4,16 @@ const createClass = require('create-react-class');
|
||||
const _ = require('lodash');
|
||||
const cx = require('classnames');
|
||||
|
||||
//Import all themes
|
||||
|
||||
const SnippetsLegacy = require('./snippetsLegacy/snippets.js');
|
||||
const SnippetsV3 = require('./snippets/snippets.js');
|
||||
const Themes = require('themes/themes.json');
|
||||
|
||||
const ThemeSnippets = {};
|
||||
ThemeSnippets['Legacy_5ePHB'] = require('themes/Legacy/5ePHB/snippets.js');
|
||||
ThemeSnippets['V3_5ePHB'] = require('themes/V3/5ePHB/snippets.js');
|
||||
ThemeSnippets['V3_5eDMG'] = require('themes/V3/5eDMG/snippets.js');
|
||||
ThemeSnippets['V3_Journal'] = require('themes/V3/Journal/snippets.js');
|
||||
ThemeSnippets['V3_Blank'] = require('themes/V3/Blank/snippets.js');
|
||||
|
||||
const execute = function(val, brew){
|
||||
if(_.isFunction(val)) return val(brew);
|
||||
@@ -32,21 +39,63 @@ const Snippetbar = createClass({
|
||||
|
||||
getInitialState : function() {
|
||||
return {
|
||||
renderer : this.props.renderer
|
||||
renderer : this.props.renderer,
|
||||
snippets : []
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount : async function() {
|
||||
const rendererPath = this.props.renderer == 'V3' ? 'V3' : 'Legacy';
|
||||
const themePath = this.props.theme ?? '5ePHB';
|
||||
let snippets = _.cloneDeep(ThemeSnippets[`${rendererPath}_${themePath}`]);
|
||||
snippets = this.compileSnippets(rendererPath, themePath, snippets);
|
||||
this.setState({
|
||||
snippets : snippets
|
||||
});
|
||||
},
|
||||
|
||||
componentDidUpdate : async function(prevProps) {
|
||||
if(prevProps.renderer != this.props.renderer || prevProps.theme != this.props.theme) {
|
||||
const rendererPath = this.props.renderer == 'V3' ? 'V3' : 'Legacy';
|
||||
const themePath = this.props.theme ?? '5ePHB';
|
||||
let snippets = _.cloneDeep(ThemeSnippets[`${rendererPath}_${themePath}`]);
|
||||
snippets = this.compileSnippets(rendererPath, themePath, snippets);
|
||||
this.setState({
|
||||
snippets : snippets
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
mergeCustomizer : function(valueA, valueB, key) {
|
||||
if(key == 'snippets') {
|
||||
const result = _.reverse(_.unionBy(_.reverse(valueB), _.reverse(valueA), 'name')); // Join snippets together, with preference for the current theme over the base theme
|
||||
return _.filter(result, 'gen'); //Only keep snippets with a 'gen' property.
|
||||
}
|
||||
},
|
||||
|
||||
compileSnippets : function(rendererPath, themePath, snippets) {
|
||||
let compiledSnippets = snippets;
|
||||
const baseSnippetsPath = Themes[rendererPath][themePath].baseSnippets;
|
||||
|
||||
const objB = _.keyBy(compiledSnippets, 'groupName');
|
||||
|
||||
if(baseSnippetsPath) {
|
||||
const objA = _.keyBy(_.cloneDeep(ThemeSnippets[`${rendererPath}_${baseSnippetsPath}`]), 'groupName');
|
||||
compiledSnippets = _.values(_.mergeWith(objA, objB, this.mergeCustomizer));
|
||||
compiledSnippets = this.compileSnippets(rendererPath, baseSnippetsPath, _.cloneDeep(compiledSnippets));
|
||||
} else {
|
||||
const objA = _.keyBy(_.cloneDeep(ThemeSnippets[`${rendererPath}_Blank`]), 'groupName');
|
||||
compiledSnippets = _.values(_.mergeWith(objA, objB, this.mergeCustomizer));
|
||||
}
|
||||
return compiledSnippets;
|
||||
},
|
||||
|
||||
handleSnippetClick : function(injectedText){
|
||||
this.props.onInject(injectedText);
|
||||
},
|
||||
|
||||
renderSnippetGroups : function(){
|
||||
let snippets = [];
|
||||
|
||||
if(this.props.renderer === 'V3')
|
||||
snippets = SnippetsV3.filter((snippetGroup)=>snippetGroup.view === this.props.view);
|
||||
else
|
||||
snippets = SnippetsLegacy.filter((snippetGroup)=>snippetGroup.view === this.props.view);
|
||||
const snippets = this.state.snippets.filter((snippetGroup)=>snippetGroup.view === this.props.view);
|
||||
|
||||
return _.map(snippets, (snippetGroup)=>{
|
||||
return <SnippetGroup
|
||||
|
||||
@@ -54,6 +54,7 @@ const Homebrew = createClass({
|
||||
global.account = this.props.account;
|
||||
global.version = this.props.version;
|
||||
global.enable_v3 = this.props.enable_v3;
|
||||
global.enable_themes = this.props.enable_themes;
|
||||
global.config = this.props.config;
|
||||
|
||||
return {};
|
||||
|
||||
@@ -95,6 +95,9 @@ const BrewItem = createClass({
|
||||
|
||||
render : function(){
|
||||
const brew = this.props.brew;
|
||||
if(Array.isArray(brew.tags)) { // temporary fix until dud tags are cleaned
|
||||
brew.tags = brew.tags?.filter(tag => tag); //remove tags that are empty strings
|
||||
}
|
||||
const dateFormatString = 'YYYY-MM-DD HH:mm:ss';
|
||||
|
||||
return <div className='brewItem'>
|
||||
@@ -110,11 +113,15 @@ const BrewItem = createClass({
|
||||
</div>
|
||||
<hr />
|
||||
<div className='info'>
|
||||
{brew.tags ? <>
|
||||
<span className='brewTags' title={`Tags:\n${brew.tags.join('\n')}`}>
|
||||
<i className='fas fa-tags'/> {brew.tags.join(', ')}
|
||||
</span>
|
||||
<br />
|
||||
|
||||
{brew.tags?.length ? <>
|
||||
<div className='brewTags' title={`Tags:\n${brew.tags.join('\n')}`}>
|
||||
<i className='fas fa-tags'/>
|
||||
{brew.tags.map((tag, idx)=>{
|
||||
let matches = tag.match(/^(?:([^:]+):)?([^:]+)$/);
|
||||
return <span className={matches[1]}>{matches[2]}</span>;
|
||||
})}
|
||||
</div>
|
||||
</> : <></>
|
||||
}
|
||||
<span title={`Authors:\n${brew.authors?.join('\n')}`}>
|
||||
|
||||
@@ -44,13 +44,23 @@
|
||||
.info{
|
||||
position: initial;
|
||||
bottom: 2px;
|
||||
font-family : ScalySans;
|
||||
font-family : ScalySansRemake;
|
||||
font-size : 1.2em;
|
||||
&>span{
|
||||
margin-right : 12px;
|
||||
line-height : 1.5em;
|
||||
}
|
||||
}
|
||||
.brewTags span {
|
||||
background-color: #c8ac6e3b;
|
||||
margin: 2px;
|
||||
padding: 2px;
|
||||
border: 1px solid #c8ac6e;
|
||||
border-radius: 4px;
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
}
|
||||
&:hover{
|
||||
.links{
|
||||
opacity : 1;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/*eslint max-lines: ["warn", {"max": 300, "skipBlankLines": true, "skipComments": true}]*/
|
||||
require('./listPage.less');
|
||||
const React = require('react');
|
||||
const createClass = require('create-react-class');
|
||||
@@ -6,7 +7,10 @@ const moment = require('moment');
|
||||
|
||||
const BrewItem = require('./brewItem/brewItem.jsx');
|
||||
|
||||
const USERPAGE_KEY_PREFIX = 'HOMEBREWERY-LISTPAGE-VISIBILITY';
|
||||
const USERPAGE_KEY_PREFIX = 'HOMEBREWERY-LISTPAGE';
|
||||
|
||||
const DEFAULT_SORT_TYPE = 'alpha';
|
||||
const DEFAULT_SORT_DIR = 'asc';
|
||||
|
||||
const ListPage = createClass({
|
||||
displayName : 'ListPage',
|
||||
@@ -30,10 +34,10 @@ const ListPage = createClass({
|
||||
});
|
||||
|
||||
return {
|
||||
filterString : this.props.query?.filter || '',
|
||||
sortType : this.props.query?.sort || 'alpha',
|
||||
sortDir : this.props.query?.dir || 'asc',
|
||||
query : this.props.query,
|
||||
filterString : this.props.query?.filter || '',
|
||||
sortType : this.props.query?.sort || null,
|
||||
sortDir : this.props.query?.dir || null,
|
||||
query : this.props.query,
|
||||
brewCollection : brewCollection
|
||||
};
|
||||
},
|
||||
@@ -44,12 +48,19 @@ const ListPage = createClass({
|
||||
|
||||
// LOAD FROM LOCAL STORAGE
|
||||
if(typeof window !== 'undefined') {
|
||||
const newSortType = (this.state.sortType ?? (localStorage.getItem(`${USERPAGE_KEY_PREFIX}-SORTTYPE`) || DEFAULT_SORT_TYPE));
|
||||
const newSortDir = (this.state.sortDir ?? (localStorage.getItem(`${USERPAGE_KEY_PREFIX}-SORTDIR`) || DEFAULT_SORT_DIR));
|
||||
this.updateUrl(this.state.filterString, newSortType, newSortDir);
|
||||
|
||||
const brewCollection = this.props.brewCollection.map((brewGroup)=>{
|
||||
brewGroup.visible = (localStorage.getItem(`${USERPAGE_KEY_PREFIX}-${brewGroup.class}`) ?? 'true')=='true';
|
||||
brewGroup.visible = (localStorage.getItem(`${USERPAGE_KEY_PREFIX}-VISIBILITY-${brewGroup.class}`) ?? 'true')=='true';
|
||||
return brewGroup;
|
||||
});
|
||||
|
||||
this.setState({
|
||||
brewCollection : brewCollection
|
||||
brewCollection : brewCollection,
|
||||
sortType : newSortType,
|
||||
sortDir : newSortDir
|
||||
});
|
||||
};
|
||||
},
|
||||
@@ -60,8 +71,10 @@ const ListPage = createClass({
|
||||
|
||||
saveToLocalStorage : function() {
|
||||
this.state.brewCollection.map((brewGroup)=>{
|
||||
localStorage.setItem(`${USERPAGE_KEY_PREFIX}-${brewGroup.class}`, `${brewGroup.visible}`);
|
||||
localStorage.setItem(`${USERPAGE_KEY_PREFIX}-VISIBILITY-${brewGroup.class}`, `${brewGroup.visible}`);
|
||||
});
|
||||
localStorage.setItem(`${USERPAGE_KEY_PREFIX}-SORTTYPE`, this.state.sortType);
|
||||
localStorage.setItem(`${USERPAGE_KEY_PREFIX}-SORTDIR`, this.state.sortDir);
|
||||
},
|
||||
|
||||
renderBrews : function(brews){
|
||||
@@ -183,11 +196,16 @@ const ListPage = createClass({
|
||||
|
||||
getSortedBrews : function(brews){
|
||||
const testString = _.deburr(this.state.filterString).toLowerCase();
|
||||
brews = _.filter(brews, (brew)=>{
|
||||
return (_.deburr(brew.title).toLowerCase().includes(testString)) ||
|
||||
(_.deburr(brew.description).toLowerCase().includes(testString));
|
||||
});
|
||||
|
||||
brews = _.filter(brews, (brew)=>{
|
||||
const brewStrings = _.deburr([
|
||||
brew.title,
|
||||
brew.description,
|
||||
brew.tags].join('\n')
|
||||
.toLowerCase());
|
||||
|
||||
return brewStrings.includes(testString);
|
||||
});
|
||||
return _.orderBy(brews, (brew)=>{ return this.sortBrewOrder(brew); }, this.state.sortDir);
|
||||
},
|
||||
|
||||
@@ -213,7 +231,7 @@ const ListPage = createClass({
|
||||
|
||||
render : function(){
|
||||
return <div className='listPage sitePage'>
|
||||
<link href='/themes/5ePhb.style.css' rel='stylesheet'/>
|
||||
<link href='/themes/V3/5ePHB/style.css' rel='stylesheet'/>
|
||||
{this.props.navItems}
|
||||
|
||||
<div className='content V3'>
|
||||
|
||||
@@ -418,7 +418,7 @@ const EditPage = createClass({
|
||||
onMetaChange={this.handleMetaChange}
|
||||
renderer={this.state.brew.renderer}
|
||||
/>
|
||||
<BrewRenderer text={this.state.brew.text} style={this.state.brew.style} renderer={this.state.brew.renderer} errors={this.state.htmlErrors} />
|
||||
<BrewRenderer text={this.state.brew.text} style={this.state.brew.style} renderer={this.state.brew.renderer} theme={this.state.brew.theme} errors={this.state.htmlErrors} />
|
||||
</SplitPane>
|
||||
</div>
|
||||
</div>;
|
||||
|
||||
@@ -27,41 +27,32 @@ const NewPage = createClass({
|
||||
getDefaultProps : function() {
|
||||
return {
|
||||
brew : {
|
||||
text : '',
|
||||
style : undefined,
|
||||
shareId : null,
|
||||
editId : null,
|
||||
createdAt : null,
|
||||
updatedAt : null,
|
||||
gDrive : false,
|
||||
|
||||
text : '',
|
||||
style : undefined,
|
||||
title : '',
|
||||
description : '',
|
||||
tags : '',
|
||||
published : false,
|
||||
authors : [],
|
||||
systems : []
|
||||
renderer : 'V3',
|
||||
theme : '5ePHB'
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
getInitialState : function() {
|
||||
const brew = this.props.brew;
|
||||
let brew = this.props.brew;
|
||||
|
||||
if(this.props.brew.shareId) {
|
||||
brew = {
|
||||
text : brew.text ?? '',
|
||||
style : brew.style ?? undefined,
|
||||
title : brew.title ?? '',
|
||||
description : brew.description ?? '',
|
||||
renderer : brew.renderer ?? 'legacy',
|
||||
theme : brew.theme ?? '5ePHB'
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
brew : {
|
||||
text : brew.text || '',
|
||||
style : brew.style || undefined,
|
||||
gDrive : false,
|
||||
title : brew.title || '',
|
||||
description : brew.description || '',
|
||||
tags : brew.tags || '',
|
||||
published : false,
|
||||
authors : [],
|
||||
systems : brew.systems || [],
|
||||
renderer : brew.renderer || 'V3'
|
||||
},
|
||||
|
||||
brew : brew,
|
||||
isSaving : false,
|
||||
saveGoogle : (global.account && global.account.googleId ? true : false),
|
||||
errors : null,
|
||||
@@ -74,27 +65,26 @@ const NewPage = createClass({
|
||||
|
||||
const brew = this.state.brew;
|
||||
|
||||
if(typeof window !== 'undefined') { //Load from localStorage if in client browser
|
||||
if(!this.props.brew.shareId && typeof window !== 'undefined') { //Load from localStorage if in client browser
|
||||
const brewStorage = localStorage.getItem(BREWKEY);
|
||||
const styleStorage = localStorage.getItem(STYLEKEY);
|
||||
const metaStorage = JSON.parse(localStorage.getItem(METAKEY));
|
||||
|
||||
if(!brew.text || !brew.style){
|
||||
brew.text = brew.text || (brewStorage ?? '');
|
||||
brew.style = brew.style || (styleStorage ?? undefined);
|
||||
// brew.title = metaStorage?.title || this.state.brew.title;
|
||||
// brew.description = metaStorage?.description || this.state.brew.description;
|
||||
brew.renderer = brew.renderer || metaStorage?.renderer;
|
||||
brew.text = brewStorage ?? brew.text;
|
||||
brew.style = styleStorage ?? brew.style;
|
||||
// brew.title = metaStorage?.title || this.state.brew.title;
|
||||
// brew.description = metaStorage?.description || this.state.brew.description;
|
||||
brew.renderer = metaStorage?.renderer ?? brew.renderer;
|
||||
brew.theme = metaStorage?.theme ?? brew.theme;
|
||||
|
||||
this.setState({
|
||||
brew : brew
|
||||
});
|
||||
}
|
||||
this.setState({
|
||||
brew : brew
|
||||
});
|
||||
}
|
||||
|
||||
localStorage.setItem(BREWKEY, brew.text);
|
||||
localStorage.setItem(STYLEKEY, brew.style);
|
||||
localStorage.setItem(METAKEY, JSON.stringify({'renderer' : brew.renderer}));
|
||||
localStorage.setItem(METAKEY, JSON.stringify({ 'renderer': brew.renderer, 'theme': brew.theme }));
|
||||
},
|
||||
componentWillUnmount : function() {
|
||||
document.removeEventListener('keydown', this.handleControlKeys);
|
||||
@@ -142,7 +132,8 @@ const NewPage = createClass({
|
||||
localStorage.setItem(METAKEY, JSON.stringify({
|
||||
// 'title' : this.state.brew.title,
|
||||
// 'description' : this.state.brew.description,
|
||||
'renderer' : this.state.brew.renderer
|
||||
'renderer' : this.state.brew.renderer,
|
||||
'theme' : this.state.brew.theme
|
||||
}));
|
||||
},
|
||||
|
||||
@@ -300,7 +291,7 @@ const NewPage = createClass({
|
||||
onMetaChange={this.handleMetaChange}
|
||||
renderer={this.state.brew.renderer}
|
||||
/>
|
||||
<BrewRenderer text={this.state.brew.text} style={this.state.brew.style} renderer={this.state.brew.renderer} errors={this.state.htmlErrors}/>
|
||||
<BrewRenderer text={this.state.brew.text} style={this.state.brew.style} renderer={this.state.brew.renderer} theme={this.state.brew.theme} errors={this.state.htmlErrors}/>
|
||||
</SplitPane>
|
||||
</div>
|
||||
</div>;
|
||||
|
||||
@@ -7,6 +7,8 @@ const { Meta } = require('vitreum/headtags');
|
||||
const MarkdownLegacy = require('naturalcrit/markdownLegacy.js');
|
||||
const Markdown = require('naturalcrit/markdown.js');
|
||||
|
||||
const Themes = require('themes/themes.json');
|
||||
|
||||
const BREWKEY = 'homebrewery-new';
|
||||
const STYLEKEY = 'homebrewery-new-style';
|
||||
const METAKEY = 'homebrewery-new-meta';
|
||||
@@ -45,7 +47,8 @@ const PrintPage = createClass({
|
||||
brew : {
|
||||
text : brewStorage,
|
||||
style : styleStorage,
|
||||
renderer : metaStorage?.renderer || 'legacy'
|
||||
renderer : metaStorage?.renderer || 'legacy',
|
||||
theme : metaStorage?.theme || '5ePHB'
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -82,9 +85,16 @@ const PrintPage = createClass({
|
||||
},
|
||||
|
||||
render : function(){
|
||||
const rendererPath = this.state.brew.renderer == 'V3' ? 'V3' : 'Legacy';
|
||||
const themePath = this.state.brew.theme ?? '5ePHB';
|
||||
const baseThemePath = Themes[rendererPath][themePath].baseTheme;
|
||||
|
||||
return <div>
|
||||
<Meta name='robots' content='noindex, nofollow' />
|
||||
<link href={`${this.state.brew.renderer == 'legacy' ? '/themes/5ePhbLegacy.style.css' : '/themes/5ePhb.style.css'}`} rel='stylesheet'/>
|
||||
{baseThemePath &&
|
||||
<link href={`/themes/${rendererPath}/${baseThemePath}/style.css`} rel='stylesheet'/>
|
||||
}
|
||||
<link href={`/themes/${rendererPath}/${themePath}/style.css`} rel='stylesheet'/>
|
||||
{/* Apply CSS from Style tab */}
|
||||
{this.renderStyle()}
|
||||
<div className='pages' ref='pages'>
|
||||
|
||||
@@ -86,7 +86,7 @@ const SharePage = createClass({
|
||||
</Navbar>
|
||||
|
||||
<div className='content'>
|
||||
<BrewRenderer text={this.props.brew.text} style={this.props.brew.style} renderer={this.props.brew.renderer} />
|
||||
<BrewRenderer text={this.props.brew.text} style={this.props.brew.style} renderer={this.props.brew.renderer} theme={this.props.brew.theme} />
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ const UserPage = createClass({
|
||||
};
|
||||
},
|
||||
getInitialState : function() {
|
||||
const usernameWithS = this.props.username + (this.props.username.endsWith('s') ? `'` : `'s`);
|
||||
const usernameWithS = this.props.username + (this.props.username.endsWith('s') ? `’` : `’s`);
|
||||
|
||||
const brews = _.groupBy(this.props.brews, (brew)=>{
|
||||
return (brew.published ? 'published' : 'private');
|
||||
|
||||
45466
package-lock.json
generated
12
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "homebrewery",
|
||||
"description": "Create authentic looking D&D homebrews using only markdown",
|
||||
"version": "3.2.1",
|
||||
"version": "3.2.2",
|
||||
"engines": {
|
||||
"node": "16.11.x"
|
||||
},
|
||||
@@ -51,9 +51,9 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.18.13",
|
||||
"@babel/core": "^7.19.0",
|
||||
"@babel/plugin-transform-runtime": "^7.18.10",
|
||||
"@babel/preset-env": "^7.18.10",
|
||||
"@babel/preset-env": "^7.19.0",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"body-parser": "^1.20.0",
|
||||
"classnames": "^2.3.1",
|
||||
@@ -74,7 +74,7 @@
|
||||
"marked-extended-tables": "^1.0.5",
|
||||
"markedLegacy": "npm:marked@^0.3.19",
|
||||
"moment": "^2.29.4",
|
||||
"mongoose": "^6.5.4",
|
||||
"mongoose": "^6.6.0",
|
||||
"nanoid": "3.3.4",
|
||||
"nconf": "^0.12.0",
|
||||
"react": "^16.14.0",
|
||||
@@ -87,8 +87,8 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^8.23.0",
|
||||
"eslint-plugin-react": "^7.31.1",
|
||||
"jest": "^29.0.1",
|
||||
"eslint-plugin-react": "^7.31.7",
|
||||
"jest": "^29.0.2",
|
||||
"supertest": "^6.2.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ const assetTransform = require('vitreum/transforms/asset.js');
|
||||
const babel = require('@babel/core');
|
||||
const less = require('less');
|
||||
|
||||
const babelify = async (code)=>(await babel.transformAsync(code, { presets: ['@babel/preset-env', '@babel/preset-react'], plugins: ['@babel/plugin-transform-runtime'] })).code;
|
||||
const babelify = async (code)=>(await babel.transformAsync(code, { presets: [['@babel/preset-env', { 'exclude': ['proposal-dynamic-import'] }], '@babel/preset-react'], plugins: ['@babel/plugin-transform-runtime'] })).code;
|
||||
|
||||
const transforms = {
|
||||
'.js' : (code, filename, opts)=>babelify(code),
|
||||
@@ -24,29 +24,8 @@ const build = async ({ bundle, render, ssr })=>{
|
||||
await fs.outputFile('./build/homebrew/bundle.css', css);
|
||||
await fs.outputFile('./build/homebrew/bundle.js', bundle);
|
||||
await fs.outputFile('./build/homebrew/ssr.js', ssr);
|
||||
await fs.copy('./themes/fonts', './build/fonts');
|
||||
await fs.copy('./themes/assets', './build/assets');
|
||||
|
||||
await fs.copy('./client/homebrew/favicon.ico', './build/assets/favicon.ico');
|
||||
let src = './themes/5ePhbLegacy.style.less';
|
||||
//Parse brew theme files
|
||||
less.render(fs.readFileSync(src).toString(), {
|
||||
compress : !isDev
|
||||
}, function(e, output) {
|
||||
fs.outputFile('./build/themes/5ePhbLegacy.style.css', output.css);
|
||||
});
|
||||
src = './themes/5ePhb.style.less';
|
||||
less.render(fs.readFileSync(src).toString(), {
|
||||
compress : !isDev
|
||||
}, function(e, output) {
|
||||
fs.outputFile('./build/themes/5ePhb.style.css', output.css);
|
||||
});
|
||||
// await less.render(lessCode, {
|
||||
// compress : !dev,
|
||||
// sourceMap : (dev ? {
|
||||
// sourceMapFileInline: true,
|
||||
// outputSourceFiles: true
|
||||
// } : false),
|
||||
// })
|
||||
|
||||
//compress files in production
|
||||
if(!isDev){
|
||||
@@ -61,16 +40,98 @@ const build = async ({ bundle, render, ssr })=>{
|
||||
};
|
||||
|
||||
fs.emptyDirSync('./build');
|
||||
pack('./client/homebrew/homebrew.jsx', {
|
||||
paths : ['./shared'],
|
||||
libs : Proj.libs,
|
||||
dev : isDev && build,
|
||||
transforms
|
||||
})
|
||||
.then(build)
|
||||
.catch(console.error);
|
||||
|
||||
|
||||
(async ()=>{
|
||||
|
||||
//v==----------------------------- COMPILE THEMES --------------------------------==v//
|
||||
|
||||
// Update list of all Theme files
|
||||
const themes = { Legacy: {}, V3: {} };
|
||||
|
||||
let themeFiles = fs.readdirSync('./themes/Legacy');
|
||||
for (dir of themeFiles) {
|
||||
const themeData = JSON.parse(fs.readFileSync(`./themes/Legacy/${dir}/settings.json`).toString());
|
||||
themeData.path = dir;
|
||||
themes.Legacy[dir] = (themeData);
|
||||
//fs.copy(`./themes/Legacy/${dir}/dropdownTexture.png`, `./build/themes/Legacy/${dir}/dropdownTexture.png`);
|
||||
const src = `./themes/Legacy/${dir}/style.less`;
|
||||
((outputDirectory)=>{
|
||||
less.render(fs.readFileSync(src).toString(), {
|
||||
compress : !isDev
|
||||
}, function(e, output) {
|
||||
fs.outputFile(outputDirectory, output.css);
|
||||
});
|
||||
})(`./build/themes/Legacy/${dir}/style.css`);
|
||||
|
||||
}
|
||||
|
||||
themeFiles = fs.readdirSync('./themes/V3');
|
||||
for (dir of themeFiles) {
|
||||
const themeData = JSON.parse(fs.readFileSync(`./themes/V3/${dir}/settings.json`).toString());
|
||||
themeData.path = dir;
|
||||
themes.V3[dir] = (themeData);
|
||||
fs.copy(`./themes/V3/${dir}/dropdownTexture.png`, `./build/themes/V3/${dir}/dropdownTexture.png`);
|
||||
const src = `./themes/V3/${dir}/style.less`;
|
||||
((outputDirectory)=>{
|
||||
less.render(fs.readFileSync(src).toString(), {
|
||||
compress : !isDev
|
||||
}, function(e, output) {
|
||||
fs.outputFile(outputDirectory, output.css);
|
||||
});
|
||||
})(`./build/themes/V3/${dir}/style.css`);
|
||||
}
|
||||
|
||||
await fs.outputFile('./themes/themes.json', JSON.stringify(themes, null, 2));
|
||||
|
||||
// await less.render(lessCode, {
|
||||
// compress : !dev,
|
||||
// sourceMap : (dev ? {
|
||||
// sourceMapFileInline: true,
|
||||
// outputSourceFiles: true
|
||||
// } : false),
|
||||
// })
|
||||
|
||||
// Move assets
|
||||
await fs.copy('./themes/fonts', './build/fonts');
|
||||
await fs.copy('./themes/assets', './build/assets');
|
||||
|
||||
//v==----------------------------- BUNDLE PACKAGES --------------------------------==v//
|
||||
|
||||
const bundles = await pack('./client/homebrew/homebrew.jsx', {
|
||||
paths : ['./shared', './'],
|
||||
libs : Proj.libs,
|
||||
dev : isDev && build,
|
||||
transforms
|
||||
});
|
||||
build(bundles);
|
||||
|
||||
// Possible method for generating separate bundles for theme snippets: factor-bundle first sending all common files to bundle.js, then again using default settings, keeping only snippet bundles
|
||||
// await fs.outputFile('./build/junk.js', '');
|
||||
// await fs.outputFile('./build/themes/Legacy/5ePHB/snippets.js', '');
|
||||
//
|
||||
// const files = ['./client/homebrew/homebrew.jsx','./themes/Legacy/5ePHB/snippets.js'];
|
||||
//
|
||||
// bundles = await pack(files, {
|
||||
// dedupe: false,
|
||||
// plugin : [['factor-bundle', { outputs: [ './build/junk.js','./build/themes/Legacy/5ePHB/snippets.js'], threshold : function(row, groups) {
|
||||
// console.log(groups);
|
||||
// if (groups.some(group => /.*homebrew.jsx$/.test(group))) {
|
||||
// console.log("found homebrewery")
|
||||
// return true;
|
||||
// }
|
||||
// return this._defaultThreshold(row, groups);
|
||||
// }}]],
|
||||
// paths : ['./shared','./','./build'],
|
||||
// libs : Proj.libs,
|
||||
// dev : isDev && build,
|
||||
// transforms
|
||||
// });
|
||||
// build(bundles);
|
||||
//
|
||||
|
||||
})().catch(console.error);
|
||||
|
||||
//In development set up a watch server and livereload
|
||||
if(isDev){
|
||||
livereload('./build');
|
||||
|
||||
@@ -21,7 +21,7 @@ const splitTextStyleAndMetadata = (brew)=>{
|
||||
const index = brew.text.indexOf('```\n\n');
|
||||
const metadataSection = brew.text.slice(12, index - 1);
|
||||
const metadata = yaml.load(metadataSection);
|
||||
Object.assign(brew, _.pick(metadata, ['title', 'description', 'tags', 'systems', 'renderer']));
|
||||
Object.assign(brew, _.pick(metadata, ['title', 'description', 'tags', 'systems', 'renderer', 'theme']));
|
||||
brew.text = brew.text.slice(index + 5);
|
||||
}
|
||||
if(brew.text.startsWith('```css')) {
|
||||
@@ -29,6 +29,7 @@ const splitTextStyleAndMetadata = (brew)=>{
|
||||
brew.style = brew.text.slice(7, index - 1);
|
||||
brew.text = brew.text.slice(index + 5);
|
||||
}
|
||||
_.defaults(brew, { 'renderer': 'legacy', 'theme': '5ePHB' });
|
||||
};
|
||||
|
||||
const sanitizeBrew = (brew, accessType)=>{
|
||||
@@ -287,14 +288,15 @@ app.use(asyncHandler(async (req, res, next)=>{
|
||||
environment : nodeEnv
|
||||
};
|
||||
const props = {
|
||||
version : require('./../package.json').version,
|
||||
url : req.originalUrl,
|
||||
brew : req.brew,
|
||||
brews : req.brews,
|
||||
googleBrews : req.googleBrews,
|
||||
account : req.account,
|
||||
enable_v3 : config.get('enable_v3'),
|
||||
config : configuration
|
||||
version : require('./../package.json').version,
|
||||
url : req.originalUrl,
|
||||
brew : req.brew,
|
||||
brews : req.brews,
|
||||
googleBrews : req.googleBrews,
|
||||
account : req.account,
|
||||
enable_v3 : config.get('enable_v3'),
|
||||
enable_themes : config.get('enable_themes'),
|
||||
config : configuration
|
||||
};
|
||||
const title = req.brew ? req.brew.title : '';
|
||||
const page = await templateFn('homebrew', title, props)
|
||||
|
||||
@@ -15,17 +15,24 @@ const { nanoid } = require('nanoid');
|
||||
// });
|
||||
// };
|
||||
|
||||
const getId = (req)=>{
|
||||
// Set the id and initial potential google id, where the google id is present on the existing brew.
|
||||
let id = req.params.id, googleId = req.body?.googleId;
|
||||
|
||||
// If the id is longer than 12, then it's a google id + the edit id. This splits the longer id up.
|
||||
if(id.length > 12) {
|
||||
googleId = id.slice(0, -12);
|
||||
id = id.slice(-12);
|
||||
}
|
||||
return { id, googleId };
|
||||
};
|
||||
|
||||
const getBrew = (accessType)=>{
|
||||
// Create middleware with the accessType passed in as part of the scope
|
||||
return async (req, res, next)=>{
|
||||
// Set the id and initial potential google id, where the google id is present on the existing brew.
|
||||
let id = req.params.id, googleId = req.body?.googleId;
|
||||
// Get relevant IDs for the brew
|
||||
const { id, googleId } = getId(req);
|
||||
|
||||
// If the id is longer than 12, then it's a google id + the edit id. This splits the longer id up.
|
||||
if(id.length > 12) {
|
||||
googleId = id.slice(0, -12);
|
||||
id = id.slice(-12);
|
||||
}
|
||||
// Try to find the document in the Homebrewery database -- if it doesn't exist, that's fine.
|
||||
let stub = await HomebrewModel.get(accessType === 'edit' ? { editId: id } : { shareId: id })
|
||||
.catch((err)=>{
|
||||
@@ -73,7 +80,7 @@ const mergeBrewText = (brew)=>{
|
||||
`\`\`\`\n\n` +
|
||||
`${text}`;
|
||||
}
|
||||
const metadata = _.pick(brew, ['title', 'description', 'tags', 'systems', 'renderer']);
|
||||
const metadata = _.pick(brew, ['title', 'description', 'tags', 'systems', 'renderer', 'theme']);
|
||||
text = `\`\`\`metadata\n` +
|
||||
`${yaml.dump(metadata)}\n` +
|
||||
`\`\`\`\n\n` +
|
||||
@@ -259,7 +266,17 @@ const deleteGoogleBrew = async (account, id, editId, res)=>{
|
||||
return true;
|
||||
};
|
||||
|
||||
const deleteBrew = async (req, res)=>{
|
||||
const deleteBrew = async (req, res, next)=>{
|
||||
// Delete an orphaned stub if its Google brew doesn't exist
|
||||
try {
|
||||
await getBrew('edit')(req, res, ()=>{});
|
||||
} catch (err) {
|
||||
const { id, googleId } = getId(req);
|
||||
console.warn(`No google brew found for id ${googleId}, the stub with id ${id} will be deleted.`);
|
||||
await HomebrewModel.deleteOne({ editId: id });
|
||||
return next();
|
||||
}
|
||||
|
||||
let brew = req.brew;
|
||||
const { googleId, editId } = brew;
|
||||
const account = req.account;
|
||||
@@ -312,8 +329,8 @@ const deleteBrew = async (req, res)=>{
|
||||
router.post('/api', asyncHandler(newBrew));
|
||||
router.put('/api/:id', asyncHandler(getBrew('edit')), asyncHandler(updateBrew));
|
||||
router.put('/api/update/:id', asyncHandler(getBrew('edit')), asyncHandler(updateBrew));
|
||||
router.delete('/api/:id', asyncHandler(getBrew('edit')), asyncHandler(deleteBrew));
|
||||
router.get('/api/remove/:id', asyncHandler(getBrew('edit')), asyncHandler(deleteBrew));
|
||||
router.delete('/api/:id', asyncHandler(deleteBrew));
|
||||
router.get('/api/remove/:id', asyncHandler(deleteBrew));
|
||||
|
||||
module.exports = {
|
||||
homebrewApi : router,
|
||||
|
||||
@@ -73,18 +73,35 @@ const Nav = {
|
||||
|
||||
dropdown : createClass({
|
||||
displayName : 'Nav.dropdown',
|
||||
getDefaultProps : function() {
|
||||
return {
|
||||
trigger : 'hover'
|
||||
};
|
||||
},
|
||||
getInitialState : function() {
|
||||
return {
|
||||
showDropdown : false
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount : function() {
|
||||
if(this.props.trigger == 'click')
|
||||
document.addEventListener('click', this.handleClickOutside);
|
||||
},
|
||||
componentWillUnmount : function() {
|
||||
if(this.props.trigger == 'click')
|
||||
document.removeEventListener('click', this.handleClickOutside);
|
||||
},
|
||||
handleClickOutside : function(e){
|
||||
// Close dropdown when clicked outside
|
||||
if(this.refs.dropdown && !this.refs.dropdown.contains(e.target)) {
|
||||
this.handleDropdown(false);
|
||||
}
|
||||
},
|
||||
handleDropdown : function(show){
|
||||
this.setState({
|
||||
showDropdown : show
|
||||
});
|
||||
},
|
||||
|
||||
renderDropdown : function(dropdownChildren){
|
||||
if(!this.state.showDropdown) return null;
|
||||
|
||||
@@ -94,7 +111,6 @@ const Nav = {
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
render : function () {
|
||||
const dropdownChildren = React.Children.map(this.props.children, (child, i)=>{
|
||||
// Ignore the first child
|
||||
@@ -102,10 +118,12 @@ const Nav = {
|
||||
return child;
|
||||
});
|
||||
return (
|
||||
<div className='navDropdownContainer'
|
||||
onMouseEnter={()=>this.handleDropdown(true)}
|
||||
onMouseLeave={()=>this.handleDropdown(false)}>
|
||||
{this.props.children[0]}
|
||||
<div className={`navDropdownContainer ${this.props.className}`}
|
||||
ref='dropdown'
|
||||
onMouseEnter={this.props.trigger == 'hover' ? ()=>{this.handleDropdown(true);} : undefined}
|
||||
onClick= {this.props.trigger == 'click' ? ()=>{this.handleDropdown(true);} : undefined}
|
||||
onMouseLeave={this.props.trigger == 'hover' ? ()=>{this.handleDropdown(false);} : undefined}>
|
||||
{this.props.children[0] || this.props.children /*children is not an array when only one child*/}
|
||||
{this.renderDropdown(dropdownChildren)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1 +1,27 @@
|
||||
html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{border:0;font-size:100%;font:inherit;vertical-align:baseline;margin:0;padding:0}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:none}table{border-collapse:collapse;border-spacing:0}
|
||||
:where(html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video){
|
||||
border:0;font-size:100%;font:inherit;vertical-align:baseline;margin:0;padding:0
|
||||
}
|
||||
|
||||
:where(article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section){
|
||||
display:block
|
||||
}
|
||||
|
||||
:where(body){
|
||||
line-height:1
|
||||
}
|
||||
|
||||
:where(ol,ul){
|
||||
list-style:none
|
||||
}
|
||||
|
||||
:where(blockquote,q){
|
||||
quotes:none
|
||||
}
|
||||
|
||||
:where(blockquote:before,blockquote:after,q:before,q:after){
|
||||
content:none
|
||||
}
|
||||
|
||||
:where(table){
|
||||
border-collapse:collapse;border-spacing:0
|
||||
}
|
||||
|
||||
5
themes/Legacy/5ePHB/settings.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name" : "5e PHB",
|
||||
"renderer" : "legacy",
|
||||
"baseTheme" : false
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
/* eslint-disable max-lines */
|
||||
|
||||
const MagicGen = require('./magic.gen.js');
|
||||
const ClassTableGen = require('./classtable.gen.js');
|
||||
const MonsterBlockGen = require('./monsterblock.gen.js');
|
||||
const ClassFeatureGen = require('./classfeature.gen.js');
|
||||
const CoverPageGen = require('./coverpage.gen.js');
|
||||
const TableOfContentsGen = require('./tableOfContents.gen.js');
|
||||
const dedent = require('dedent-tabs').default;
|
||||
const MagicGen = require('./snippets/magic.gen.js');
|
||||
const ClassTableGen = require('./snippets/classtable.gen.js');
|
||||
const MonsterBlockGen = require('./snippets/monsterblock.gen.js');
|
||||
const ClassFeatureGen = require('./snippets/classfeature.gen.js');
|
||||
const CoverPageGen = require('./snippets/coverpage.gen.js');
|
||||
const TableOfContentsGen = require('./snippets/tableOfContents.gen.js');
|
||||
const dedent = require('dedent-tabs').default;
|
||||
|
||||
module.exports = [
|
||||
|
||||
BIN
themes/V3/5eDMG/dropdownTexture.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
6
themes/V3/5eDMG/settings.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name" : "5e DMG",
|
||||
"renderer" : "V3",
|
||||
"baseTheme" : "5ePHB",
|
||||
"baseSnippets" : "5ePHB"
|
||||
}
|
||||
4
themes/V3/5eDMG/snippets.js
Normal file
@@ -0,0 +1,4 @@
|
||||
/* eslint-disable max-lines */
|
||||
|
||||
module.exports = [
|
||||
];
|
||||
19
themes/V3/5eDMG/style.less
Normal file
@@ -0,0 +1,19 @@
|
||||
:root {
|
||||
//Colors
|
||||
--HB_Color_Accent : #EBCEC3; // Salmon
|
||||
--HB_Color_Footnotes : #5C5C5C; // Dark gray
|
||||
}
|
||||
|
||||
.page {
|
||||
background-image : url(/assets/DMG_background.png);
|
||||
background-size : cover;
|
||||
|
||||
&:after {
|
||||
background-image : url(/assets/DMG_footerAccent.png);
|
||||
height: 58px;
|
||||
}
|
||||
|
||||
.footnote {
|
||||
bottom : 40px;
|
||||
}
|
||||
}
|
||||
BIN
themes/V3/5ePHB/dropdownTexture.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
6
themes/V3/5ePHB/settings.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name" : "5e PHB",
|
||||
"renderer" : "V3",
|
||||
"baseTheme" : false,
|
||||
"baseSnippets" : false
|
||||
}
|
||||
264
themes/V3/5ePHB/snippets.js
Normal file
@@ -0,0 +1,264 @@
|
||||
/* eslint-disable max-lines */
|
||||
|
||||
const MagicGen = require('./snippets/magic.gen.js');
|
||||
const ClassTableGen = require('./snippets/classtable.gen.js');
|
||||
const MonsterBlockGen = require('./snippets/monsterblock.gen.js');
|
||||
const ClassFeatureGen = require('./snippets/classfeature.gen.js');
|
||||
const CoverPageGen = require('./snippets/coverpage.gen.js');
|
||||
const TableOfContentsGen = require('./snippets/tableOfContents.gen.js');
|
||||
const dedent = require('dedent-tabs').default;
|
||||
|
||||
|
||||
|
||||
module.exports = [
|
||||
|
||||
{
|
||||
groupName : 'Text Editor',
|
||||
icon : 'fas fa-pencil-alt',
|
||||
view : 'text',
|
||||
snippets : [
|
||||
{
|
||||
name : 'Page Number',
|
||||
icon : 'fas fa-bookmark',
|
||||
gen : '{{pageNumber 1}}\n{{footnote PART 1 | SECTION NAME}}\n\n'
|
||||
},
|
||||
{
|
||||
name : 'Auto-incrementing Page Number',
|
||||
icon : 'fas fa-sort-numeric-down',
|
||||
gen : '{{pageNumber,auto}}\n{{footnote PART 1 | SECTION NAME}}\n\n'
|
||||
},
|
||||
{
|
||||
name : 'Table of Contents',
|
||||
icon : 'fas fa-book',
|
||||
gen : TableOfContentsGen
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
groupName : 'Style Editor',
|
||||
icon : 'fas fa-pencil-alt',
|
||||
view : 'style',
|
||||
snippets : [
|
||||
{
|
||||
name : 'Remove Drop Cap',
|
||||
icon : 'fas fa-remove-format',
|
||||
gen : dedent`/* Removes Drop Caps */
|
||||
.page h1+p:first-letter {
|
||||
all: unset;
|
||||
}\n\n
|
||||
/* Removes Small-Caps in first line */
|
||||
.page h1+p:first-line {
|
||||
all: unset;
|
||||
}`
|
||||
},
|
||||
{
|
||||
name : 'Tweak Drop Cap',
|
||||
icon : 'fas fa-sliders-h',
|
||||
gen : dedent`/* Drop Cap settings */
|
||||
.page h1 + p::first-letter {
|
||||
font-family: SolberaImitationRemake;
|
||||
font-size: 3.5cm;
|
||||
background-image: linear-gradient(-45deg, #322814, #998250, #322814);
|
||||
line-height: 1em;
|
||||
}\n\n`
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
/*********************** IMAGES *******************/
|
||||
{
|
||||
groupName : 'Images',
|
||||
icon : 'fas fa-images',
|
||||
view : 'text',
|
||||
snippets : [
|
||||
{
|
||||
name : 'Image',
|
||||
icon : 'fas fa-image',
|
||||
gen : dedent`
|
||||
 {width:325px,mix-blend-mode:multiply}
|
||||
|
||||
{{artist,position:relative,top:-230px,left:10px,margin-bottom:-30px
|
||||
##### Cat Warrior
|
||||
[Kyoung Hwan Kim](https://www.artstation.com/tahra)
|
||||
}}`
|
||||
},
|
||||
{
|
||||
name : 'Background Image',
|
||||
icon : 'fas fa-tree',
|
||||
gen : dedent`
|
||||
 {position:absolute,top:50px,right:30px,width:280px}
|
||||
|
||||
{{artist,top:80px,right:30px
|
||||
##### Homebrew Mug
|
||||
[naturalcrit](https://homebrew.naturalcrit.com)
|
||||
}}`
|
||||
},
|
||||
{
|
||||
name : 'Watermark',
|
||||
icon : 'fas fa-id-card',
|
||||
gen : dedent`
|
||||
{{watermark Homebrewery}}\n`
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
/************************* PHB ********************/
|
||||
|
||||
{
|
||||
groupName : 'PHB',
|
||||
icon : 'fas fa-book',
|
||||
view : 'text',
|
||||
snippets : [
|
||||
{
|
||||
name : 'Spell',
|
||||
icon : 'fas fa-magic',
|
||||
gen : MagicGen.spell,
|
||||
},
|
||||
{
|
||||
name : 'Spell List',
|
||||
icon : 'fas fa-scroll',
|
||||
gen : MagicGen.spellList,
|
||||
},
|
||||
{
|
||||
name : 'Class Feature',
|
||||
icon : 'fas fa-mask',
|
||||
gen : ClassFeatureGen,
|
||||
},
|
||||
{
|
||||
name : 'Note',
|
||||
icon : 'fas fa-sticky-note',
|
||||
gen : function(){
|
||||
return dedent`
|
||||
{{note
|
||||
##### Time to Drop Knowledge
|
||||
Use notes to point out some interesting information.
|
||||
|
||||
**Tables and lists** both work within a note.
|
||||
}}
|
||||
\n`;
|
||||
},
|
||||
},
|
||||
{
|
||||
name : 'Descriptive Text Box',
|
||||
icon : 'fas fa-comment-alt',
|
||||
gen : function(){
|
||||
return dedent`
|
||||
{{descriptive
|
||||
##### Time to Drop Knowledge
|
||||
Use descriptive boxes to highlight text that should be read aloud.
|
||||
|
||||
**Tables and lists** both work within a descriptive box.
|
||||
}}
|
||||
\n`;
|
||||
},
|
||||
},
|
||||
{
|
||||
name : 'Monster Stat Block (unframed)',
|
||||
icon : 'fas fa-paw',
|
||||
gen : MonsterBlockGen.monster('monster', 2),
|
||||
},
|
||||
{
|
||||
name : 'Monster Stat Block',
|
||||
icon : 'fas fa-spider',
|
||||
gen : MonsterBlockGen.monster('monster,frame', 2),
|
||||
},
|
||||
{
|
||||
name : 'Wide Monster Stat Block',
|
||||
icon : 'fas fa-dragon',
|
||||
gen : MonsterBlockGen.monster('monster,frame,wide', 4),
|
||||
},
|
||||
{
|
||||
name : 'Cover Page',
|
||||
icon : 'fas fa-file-word',
|
||||
gen : CoverPageGen,
|
||||
},
|
||||
{
|
||||
name : 'Magic Item',
|
||||
icon : 'fas fa-hat-wizard',
|
||||
gen : MagicGen.item,
|
||||
},
|
||||
{
|
||||
name : 'Artist Credit',
|
||||
icon : 'fas fa-signature',
|
||||
gen : function(){
|
||||
return dedent`
|
||||
{{artist,top:90px,right:30px
|
||||
##### Starry Night
|
||||
[Van Gogh](https://www.vangoghmuseum.nl/en)
|
||||
}}
|
||||
\n`;
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
|
||||
/********************* TABLES *********************/
|
||||
|
||||
{
|
||||
groupName : 'Tables',
|
||||
icon : 'fas fa-table',
|
||||
view : 'text',
|
||||
snippets : [
|
||||
{
|
||||
name : 'Class Table',
|
||||
icon : 'fas fa-table',
|
||||
gen : ClassTableGen.full('classTable,frame,decoration,wide'),
|
||||
},
|
||||
{
|
||||
name : 'Class Table (unframed)',
|
||||
icon : 'fas fa-border-none',
|
||||
gen : ClassTableGen.full('classTable,wide'),
|
||||
},
|
||||
{
|
||||
name : '1/2 Class Table',
|
||||
icon : 'fas fa-list-alt',
|
||||
gen : ClassTableGen.half('classTable,decoration,frame'),
|
||||
},
|
||||
{
|
||||
name : '1/2 Class Table (unframed)',
|
||||
icon : 'fas fa-border-none',
|
||||
gen : ClassTableGen.half('classTable'),
|
||||
},
|
||||
{
|
||||
name : '1/3 Class Table',
|
||||
icon : 'fas fa-border-all',
|
||||
gen : ClassTableGen.third('classTable,frame'),
|
||||
},
|
||||
{
|
||||
name : '1/3 Class Table (unframed)',
|
||||
icon : 'fas fa-border-none',
|
||||
gen : ClassTableGen.third('classTable'),
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
/**************** PAGE *************/
|
||||
|
||||
{
|
||||
groupName : 'Print',
|
||||
icon : 'fas fa-print',
|
||||
view : 'style',
|
||||
snippets : [
|
||||
{
|
||||
name : 'Ink Friendly',
|
||||
icon : 'fas fa-tint',
|
||||
gen : dedent`
|
||||
/* Ink Friendly */
|
||||
*:is(.page,.monster,.note,.descriptive) {
|
||||
background : white !important;
|
||||
filter : drop-shadow(0px 0px 3px #888) !important;
|
||||
}
|
||||
|
||||
.page img {
|
||||
visibility : hidden;
|
||||
}\n\n`
|
||||
},
|
||||
]
|
||||
}
|
||||
];
|
||||
@@ -17,15 +17,15 @@ module.exports = function(classname){
|
||||
|
||||
return dedent`
|
||||
## Class Features
|
||||
As a ${classname}, you gain the following class features
|
||||
#### Hit Points
|
||||
|
||||
As a ${classname}, you gain the following class features
|
||||
|
||||
#### Hit Points
|
||||
**Hit Dice:** :: 1d${hitDie} per ${classname} level
|
||||
**Hit Points at 1st Level:** :: ${hitDie} + your Constitution modifier
|
||||
**Hit Points at Higher Levels:** :: 1d${hitDie} (or ${hitDie/2 + 1}) + your Constitution modifier per ${classname} level after 1st
|
||||
|
||||
#### Proficiencies
|
||||
|
||||
**Armor:** :: ${_.sampleSize(['Light armor', 'Medium armor', 'Heavy armor', 'Shields'], _.random(0, 3)).join(', ') || 'None'}
|
||||
**Weapons:** :: ${_.sampleSize(['Squeegee', 'Rubber Chicken', 'Simple weapons', 'Martial weapons'], _.random(0, 2)).join(', ') || 'None'}
|
||||
**Tools:** :: ${_.sampleSize(['Artisan\'s tools', 'one musical instrument', 'Thieves\' tools'], _.random(0, 2)).join(', ') || 'None'}
|
||||
@@ -34,7 +34,6 @@ module.exports = function(classname){
|
||||
**Skills:** :: Choose two from ${_.sampleSize(skillList, _.random(4, 6)).join(', ')}
|
||||
|
||||
#### Spellcasting Ability
|
||||
|
||||
{{text-align:center
|
||||
**Spell save DC**:: = ${_.sample([6, 8, 10])} + your proficiency bonus + your ${spellSkill} modifier
|
||||
|
||||
@@ -46,6 +45,5 @@ module.exports = function(classname){
|
||||
- *(a)* a martial weapon and a shield or *(b)* two martial weapons
|
||||
- *(a)* five javelins or *(b)* any simple melee weapon
|
||||
- ${_.sample(['10 lint fluffs', '1 button', 'a cherished lost sock'])}
|
||||
|
||||
`;
|
||||
};
|
||||
@@ -1,15 +1,19 @@
|
||||
@import (less) './themes/fonts/5e/fonts.less';
|
||||
@import (less) './themes/assets/assets.less';
|
||||
|
||||
//Colors
|
||||
@background : #EEE5CE; // Light parchment
|
||||
@noteGreen : #e0e5c1; // Pastel green
|
||||
@headerUnderline : #c9ad6a; // Gold
|
||||
@horizontalRule : #9c2b1b; // Maroon
|
||||
@headerText : #58180D; // Dark maroon
|
||||
@monsterStatBackground : #EEDBAB; // Light orange parchment
|
||||
@captionText : #766649; // Brown
|
||||
@watercolorStain : #BBAD82; // Light brown
|
||||
:root {
|
||||
//Colors
|
||||
--HB_Color_Background : #EEE5CE; // Light parchment
|
||||
--HB_Color_Accent : #E0E5C1; // Pastel green
|
||||
--HB_Color_HeaderUnderline : #C0AD6A; // Gold
|
||||
--HB_Color_HorizontalRule : #9C2B1B; // Maroon
|
||||
--HB_Color_HeaderText : #58180D; // Dark Maroon
|
||||
--HB_Color_MonsterStatBackground : #EEDBAB; // Light orange parchment
|
||||
--HB_Color_CaptionText : #766649; // Brown
|
||||
--HB_Color_WatercolorStain : #BBAD82; // Light brown
|
||||
--HB_Color_Footnotes : #C9AD6A; // Gold
|
||||
}
|
||||
|
||||
@page { margin: 0; }
|
||||
body {
|
||||
counter-reset : phb-page-numbers;
|
||||
@@ -65,7 +69,7 @@ body {
|
||||
overflow : hidden;
|
||||
height : 279.4mm;
|
||||
width : 215.9mm;
|
||||
background-color : @background;
|
||||
background-color : var(--HB_Color_Background);
|
||||
background-image : @backgroundImage;
|
||||
padding : 1.4cm 1.9cm 1.7cm;
|
||||
font-family : BookInsanityRemake;
|
||||
@@ -131,12 +135,13 @@ body {
|
||||
h1,h2,h3,h4{
|
||||
font-family : MrEavesRemake;
|
||||
font-weight : 800;
|
||||
color : @headerText;
|
||||
color : var(--HB_Color_HeaderText);
|
||||
}
|
||||
h1{
|
||||
margin-bottom : 0.18cm; //Margin-bottom only because this is WIDE
|
||||
column-span : all;
|
||||
font-size : 0.89cm;
|
||||
line-height : 1em;
|
||||
-webkit-column-span : all;
|
||||
-moz-column-span : all;
|
||||
&+p::first-letter{
|
||||
@@ -168,7 +173,7 @@ body {
|
||||
//margin-top : -0.1cm; //Font is misaligned. Shift up slightly
|
||||
//margin-bottom : 0.1cm;
|
||||
font-size : 0.575cm;
|
||||
border-bottom : 2px solid @headerUnderline;
|
||||
border-bottom : 2px solid var(--HB_Color_HeaderUnderline);;
|
||||
line-height : 0.995em; //Font is misaligned. Shift up slightly
|
||||
}
|
||||
h4{
|
||||
@@ -211,7 +216,7 @@ body {
|
||||
padding : 0.14em 0.4em;
|
||||
}
|
||||
&:nth-child(odd){
|
||||
background-color : @noteGreen;
|
||||
background-color : var(--HB_Color_Accent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -221,7 +226,7 @@ body {
|
||||
// *****************************/
|
||||
.note{
|
||||
.useSansSerif();
|
||||
background-color : @noteGreen;
|
||||
background-color : var(--HB_Color_Accent);
|
||||
border-style : solid;
|
||||
border-width : 1px;
|
||||
border-image : @noteBorderImage 12 stretch;
|
||||
@@ -287,7 +292,7 @@ body {
|
||||
text-align : center;
|
||||
font-family : WalterTurncoat;
|
||||
font-size : 0.27cm;
|
||||
color : @captionText;
|
||||
color : var(--HB_Color_CaptionText);
|
||||
p, p + p {
|
||||
margin : unset;
|
||||
text-indent : unset;
|
||||
@@ -340,7 +345,7 @@ body {
|
||||
mask-size : contain;
|
||||
mask-repeat : no-repeat;
|
||||
background-size : cover;
|
||||
background-color : @watercolorStain; /*default color*/
|
||||
background-color : var(--HB_Color_WatercolorStain); /*default color*/
|
||||
--wc : @watercolor1; /*default image*/
|
||||
z-index : -2;
|
||||
}
|
||||
@@ -366,7 +371,7 @@ body {
|
||||
&.frame {
|
||||
border-style : solid;
|
||||
border-width : 7px 6px;
|
||||
background-color : @monsterStatBackground;
|
||||
background-color : var(--HB_Color_MonsterStatBackground);
|
||||
background-image : @monsterBlockBackground;
|
||||
border-image : @monsterBorderImage 14 round;
|
||||
border-image-outset : 0px 2px;
|
||||
@@ -397,7 +402,7 @@ body {
|
||||
font-family : ScalySansRemake;
|
||||
font-weight : 800;
|
||||
font-variant : small-caps;
|
||||
border-bottom : 2px solid @headerText;
|
||||
border-bottom : 2px solid var(--HB_Color_HeaderText);
|
||||
// margin-top : 0.05cm; //Font is misaligned. Shift up slightly
|
||||
padding-bottom : 0.05cm;
|
||||
}
|
||||
@@ -414,7 +419,7 @@ body {
|
||||
|
||||
//Attribute Lists - All text between HRs is red
|
||||
hr ~ :is(dl,p) {
|
||||
color : @headerText;
|
||||
color : var(--HB_Color_HeaderText);
|
||||
}
|
||||
hr:last-of-type {
|
||||
& ~ :is(dl,p) {
|
||||
@@ -429,7 +434,7 @@ body {
|
||||
hr + table:first-of-type{
|
||||
margin : 0;
|
||||
column-span : none;
|
||||
color : @headerText;
|
||||
color : var(--HB_Color_HeaderText);
|
||||
background-color : transparent;
|
||||
border-style : none;
|
||||
border-image : none;
|
||||
@@ -484,7 +489,7 @@ body {
|
||||
bottom : 22px;
|
||||
width : 50px;
|
||||
font-size : 0.9em;
|
||||
color : #c9ad6a;
|
||||
color : var(--HB_Color_Footnotes);
|
||||
text-align : center;
|
||||
text-indent : 0;
|
||||
&.auto::after {
|
||||
@@ -498,7 +503,7 @@ body {
|
||||
z-index : 150;
|
||||
width : 200px;
|
||||
font-size : 0.8em;
|
||||
color : #c9ad6a;
|
||||
color : var(--HB_Color_Footnotes);
|
||||
text-align : right;
|
||||
}
|
||||
//************************************
|
||||
BIN
themes/V3/Blank/dropdownTexture.png
Normal file
|
After Width: | Height: | Size: 236 B |
6
themes/V3/Blank/settings.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name" : "Blank",
|
||||
"renderer" : "V3",
|
||||
"baseTheme" : false,
|
||||
"baseSnippets" : false
|
||||
}
|
||||
@@ -1,13 +1,8 @@
|
||||
/* eslint-disable max-lines */
|
||||
|
||||
const MagicGen = require('./magic.gen.js');
|
||||
const ClassTableGen = require('./classtable.gen.js');
|
||||
const MonsterBlockGen = require('./monsterblock.gen.js');
|
||||
const ClassFeatureGen = require('./classfeature.gen.js');
|
||||
const CoverPageGen = require('./coverpage.gen.js');
|
||||
const TableOfContentsGen = require('./tableOfContents.gen.js');
|
||||
const dedent = require('dedent-tabs').default;
|
||||
const watercolorGen = require('./watercolor.gen.js');
|
||||
const WatercolorGen = require('./snippets/watercolor.gen.js');
|
||||
const dedent = require('dedent-tabs').default;
|
||||
|
||||
|
||||
|
||||
module.exports = [
|
||||
@@ -59,26 +54,11 @@ module.exports = [
|
||||
`&size=100x100) {width:100px;mix-blend-mode:multiply}`;
|
||||
}
|
||||
},
|
||||
{
|
||||
name : 'Page Number',
|
||||
icon : 'fas fa-bookmark',
|
||||
gen : '{{pageNumber 1}}\n{{footnote PART 1 | SECTION NAME}}\n\n'
|
||||
},
|
||||
{
|
||||
name : 'Auto-incrementing Page Number',
|
||||
icon : 'fas fa-sort-numeric-down',
|
||||
gen : '{{pageNumber,auto}}\n{{footnote PART 1 | SECTION NAME}}\n\n'
|
||||
},
|
||||
{
|
||||
name : 'Link to page',
|
||||
icon : 'fas fa-link',
|
||||
gen : '[Click here](#p3) to go to page 3\n'
|
||||
},
|
||||
{
|
||||
name : 'Table of Contents',
|
||||
icon : 'fas fa-book',
|
||||
gen : TableOfContentsGen
|
||||
},
|
||||
{
|
||||
name : 'Add Comment',
|
||||
icon : 'fas fa-code',
|
||||
@@ -91,29 +71,6 @@ module.exports = [
|
||||
icon : 'fas fa-pencil-alt',
|
||||
view : 'style',
|
||||
snippets : [
|
||||
{
|
||||
name : 'Remove Drop Cap',
|
||||
icon : 'fas fa-remove-format',
|
||||
gen : dedent`/* Removes Drop Caps */
|
||||
.page h1+p:first-letter {
|
||||
all: unset;
|
||||
}\n\n
|
||||
/* Removes Small-Caps in first line */
|
||||
.page h1+p:first-line {
|
||||
all: unset;
|
||||
}`
|
||||
},
|
||||
{
|
||||
name : 'Tweak Drop Cap',
|
||||
icon : 'fas fa-sliders-h',
|
||||
gen : dedent`/* Drop Cap settings */
|
||||
.page h1 + p::first-letter {
|
||||
font-family: SolberaImitationRemake;
|
||||
font-size: 3.5cm;
|
||||
background-image: linear-gradient(-45deg, #322814, #998250, #322814);
|
||||
line-height: 1em;
|
||||
}\n\n`
|
||||
},
|
||||
{
|
||||
name : 'Add Comment',
|
||||
icon : 'fas fa-code',
|
||||
@@ -132,28 +89,18 @@ module.exports = [
|
||||
name : 'Image',
|
||||
icon : 'fas fa-image',
|
||||
gen : dedent`
|
||||
 {width:325px,mix-blend-mode:multiply}
|
||||
|
||||
{{artist,position:relative,top:-230px,left:10px,margin-bottom:-30px
|
||||
##### Cat Warrior
|
||||
[Kyoung Hwan Kim](https://www.artstation.com/tahra)
|
||||
}}`
|
||||
 {width:325px,mix-blend-mode:multiply}`
|
||||
},
|
||||
{
|
||||
name : 'Background Image',
|
||||
icon : 'fas fa-tree',
|
||||
gen : dedent`
|
||||
 {position:absolute,top:50px,right:30px,width:280px}
|
||||
|
||||
{{artist,top:80px,right:30px
|
||||
##### Homebrew Mug
|
||||
[naturalcrit](https://homebrew.naturalcrit.com)
|
||||
}}`
|
||||
 {position:absolute,top:50px,right:30px,width:280px}`
|
||||
},
|
||||
{
|
||||
name : 'Watercolor Splatter',
|
||||
icon : 'fas fa-fill-drip',
|
||||
gen : watercolorGen,
|
||||
gen : WatercolorGen,
|
||||
},
|
||||
{
|
||||
name : 'Watermark',
|
||||
@@ -164,99 +111,6 @@ module.exports = [
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
/************************* PHB ********************/
|
||||
|
||||
{
|
||||
groupName : 'PHB',
|
||||
icon : 'fas fa-book',
|
||||
view : 'text',
|
||||
snippets : [
|
||||
{
|
||||
name : 'Spell',
|
||||
icon : 'fas fa-magic',
|
||||
gen : MagicGen.spell,
|
||||
},
|
||||
{
|
||||
name : 'Spell List',
|
||||
icon : 'fas fa-scroll',
|
||||
gen : MagicGen.spellList,
|
||||
},
|
||||
{
|
||||
name : 'Class Feature',
|
||||
icon : 'fas fa-mask',
|
||||
gen : ClassFeatureGen,
|
||||
},
|
||||
{
|
||||
name : 'Note',
|
||||
icon : 'fas fa-sticky-note',
|
||||
gen : function(){
|
||||
return dedent`
|
||||
{{note
|
||||
##### Time to Drop Knowledge
|
||||
Use notes to point out some interesting information.
|
||||
|
||||
**Tables and lists** both work within a note.
|
||||
}}
|
||||
\n`;
|
||||
},
|
||||
},
|
||||
{
|
||||
name : 'Descriptive Text Box',
|
||||
icon : 'fas fa-comment-alt',
|
||||
gen : function(){
|
||||
return dedent`
|
||||
{{descriptive
|
||||
##### Time to Drop Knowledge
|
||||
Use descriptive boxes to highlight text that should be read aloud.
|
||||
|
||||
**Tables and lists** both work within a descriptive box.
|
||||
}}
|
||||
\n`;
|
||||
},
|
||||
},
|
||||
{
|
||||
name : 'Monster Stat Block (unframed)',
|
||||
icon : 'fas fa-paw',
|
||||
gen : MonsterBlockGen.monster('monster', 2),
|
||||
},
|
||||
{
|
||||
name : 'Monster Stat Block',
|
||||
icon : 'fas fa-spider',
|
||||
gen : MonsterBlockGen.monster('monster,frame', 2),
|
||||
},
|
||||
{
|
||||
name : 'Wide Monster Stat Block',
|
||||
icon : 'fas fa-dragon',
|
||||
gen : MonsterBlockGen.monster('monster,frame,wide', 4),
|
||||
},
|
||||
{
|
||||
name : 'Cover Page',
|
||||
icon : 'fas fa-file-word',
|
||||
gen : CoverPageGen,
|
||||
},
|
||||
{
|
||||
name : 'Magic Item',
|
||||
icon : 'fas fa-hat-wizard',
|
||||
gen : MagicGen.item,
|
||||
},
|
||||
{
|
||||
name : 'Artist Credit',
|
||||
icon : 'fas fa-signature',
|
||||
gen : function(){
|
||||
return dedent`
|
||||
{{artist,top:90px,right:30px
|
||||
##### Starry Night
|
||||
[Van Gogh](https://www.vangoghmuseum.nl/en)
|
||||
}}
|
||||
\n`;
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
|
||||
/********************* TABLES *********************/
|
||||
|
||||
{
|
||||
@@ -323,43 +177,10 @@ module.exports = [
|
||||
}}
|
||||
\n`;
|
||||
}
|
||||
},
|
||||
{
|
||||
name : 'Class Table',
|
||||
icon : 'fas fa-table',
|
||||
gen : ClassTableGen.full('classTable,frame,decoration,wide'),
|
||||
},
|
||||
{
|
||||
name : 'Class Table (unframed)',
|
||||
icon : 'fas fa-border-none',
|
||||
gen : ClassTableGen.full('classTable,wide'),
|
||||
},
|
||||
{
|
||||
name : '1/2 Class Table',
|
||||
icon : 'fas fa-list-alt',
|
||||
gen : ClassTableGen.half('classTable,decoration,frame'),
|
||||
},
|
||||
{
|
||||
name : '1/2 Class Table (unframed)',
|
||||
icon : 'fas fa-border-none',
|
||||
gen : ClassTableGen.half('classTable'),
|
||||
},
|
||||
{
|
||||
name : '1/3 Class Table',
|
||||
icon : 'fas fa-border-all',
|
||||
gen : ClassTableGen.third('classTable,frame'),
|
||||
},
|
||||
{
|
||||
name : '1/3 Class Table (unframed)',
|
||||
icon : 'fas fa-border-none',
|
||||
gen : ClassTableGen.third('classTable'),
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
/**************** PAGE *************/
|
||||
|
||||
{
|
||||
@@ -392,7 +213,7 @@ module.exports = [
|
||||
icon : 'fas fa-tint',
|
||||
gen : dedent`
|
||||
/* Ink Friendly */
|
||||
*:is(.page,.monster,.note,.descriptive) {
|
||||
*:is(.page) {
|
||||
background : white !important;
|
||||
filter : drop-shadow(0px 0px 3px #888) !important;
|
||||
}
|
||||
@@ -402,6 +223,5 @@ module.exports = [
|
||||
}\n\n`
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
}
|
||||
];
|
||||
5
themes/V3/Blank/snippets/watercolor.gen.js
Normal file
@@ -0,0 +1,5 @@
|
||||
const _ = require('lodash');
|
||||
|
||||
module.exports = ()=>{
|
||||
return `{{watercolor${_.random(1, 12)},top:20px,left:30px,width:300px,background-color:#BBAD82,opacity:80%}}\n\n`;
|
||||
};
|
||||
273
themes/V3/Blank/style.less
Normal file
@@ -0,0 +1,273 @@
|
||||
@import (less) './themes/fonts/5e/fonts.less';
|
||||
@import (less) './themes/assets/assets.less';
|
||||
|
||||
:root {
|
||||
//Colors
|
||||
--HB_Color_Background : #FFFFFF; // White
|
||||
--HB_Color_WatercolorStain : #000000; // Black
|
||||
}
|
||||
|
||||
@page { margin: 0; }
|
||||
body {
|
||||
counter-reset : phb-page-numbers;
|
||||
}
|
||||
*{
|
||||
-webkit-print-color-adjust : exact;
|
||||
}
|
||||
|
||||
.useColumns(@multiplier : 1, @fillMode: balance){
|
||||
column-fill : @fillMode;
|
||||
column-count : 2;
|
||||
}
|
||||
.columnWrapper{
|
||||
max-height : 100%;
|
||||
column-span : all;
|
||||
columns : inherit;
|
||||
column-gap : inherit;
|
||||
}
|
||||
.page{
|
||||
.useColumns();
|
||||
height : 279.4mm;
|
||||
width : 215.9mm;
|
||||
padding : 1.4cm 1.9cm 1.7cm;
|
||||
counter-increment : phb-page-numbers;
|
||||
background-color : var(--HB_Color_Background);
|
||||
position : relative;
|
||||
z-index : 15;
|
||||
box-sizing : border-box;
|
||||
overflow : hidden;
|
||||
text-rendering : optimizeLegibility;
|
||||
page-break-before : always;
|
||||
page-break-after : always;
|
||||
}
|
||||
//*****************************
|
||||
// * BASE
|
||||
// *****************************/
|
||||
:where(.page){
|
||||
p{
|
||||
overflow-wrap : break-word;
|
||||
display : block;
|
||||
}
|
||||
strong{
|
||||
font-weight : bold;
|
||||
}
|
||||
em{
|
||||
font-style : italic;
|
||||
}
|
||||
sup{
|
||||
vertical-align : super;
|
||||
font-size : smaller;
|
||||
line-height : 0;
|
||||
}
|
||||
sub{
|
||||
vertical-align : sub;
|
||||
font-size : smaller;
|
||||
line-height : 0;
|
||||
}
|
||||
ul {
|
||||
list-style-position : outside; //Needed for multiline list items
|
||||
list-style-type : disc;
|
||||
padding-left : 1.4em;
|
||||
}
|
||||
ol {
|
||||
list-style-position : outside;
|
||||
list-style-type : decimal;
|
||||
padding-left : 1.4em;
|
||||
}
|
||||
img{
|
||||
z-index : -1;
|
||||
}
|
||||
:not(:where(.wide,.columnSplit,.blank,hr)) + :where(h1,h2,h3,h4,h5,h6,table,dl,.block) {
|
||||
margin-top : 1em; //NOTE: MAKE ALL MARGINS TOP-ONLY FOR BEST RESULTS WITH COLUMN BREAKS. USE * + * STYLE SELECTORS
|
||||
}
|
||||
|
||||
:where(h1,h3,h3,h4,h5,h6) + * {
|
||||
margin-top : 0;
|
||||
}
|
||||
//*****************************
|
||||
// * HEADERS
|
||||
// *****************************/
|
||||
h1,h2,h3,h4,h5,h6{
|
||||
font-weight : bold;
|
||||
line-height : 1.2em;
|
||||
}
|
||||
h1{
|
||||
font-size : 2em;
|
||||
}
|
||||
h2{
|
||||
font-size : 1.5em;
|
||||
}
|
||||
h3{
|
||||
font-size : 1.17em;
|
||||
}
|
||||
h4{
|
||||
font-size : 1em;
|
||||
}
|
||||
h5{
|
||||
font-size : 0.83em;
|
||||
}
|
||||
//*****************************
|
||||
// * TABLE
|
||||
// *****************************/
|
||||
table{
|
||||
width : 100%;
|
||||
thead{
|
||||
display : table-row-group;
|
||||
font-weight : bold;
|
||||
}
|
||||
}
|
||||
|
||||
/* Watermark */
|
||||
.watermark {
|
||||
display : grid !important;
|
||||
place-items : center;
|
||||
justify-content : center;
|
||||
position : absolute;
|
||||
margin : 0;
|
||||
top : 0;
|
||||
left : 0;
|
||||
width : 100%;
|
||||
height : 100%;
|
||||
font-size : 120px;
|
||||
text-transform : uppercase;
|
||||
color : black;
|
||||
mix-blend-mode : overlay;
|
||||
opacity : 30%;
|
||||
transform : rotate(-45deg);
|
||||
z-index : 500;
|
||||
p {
|
||||
margin-bottom : none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Watercolor */
|
||||
[class*="watercolor"] {
|
||||
position : absolute;
|
||||
width : 2000px; /* dimensions need to be real big so the user can set */
|
||||
height : 2000px; /* height or width and the image will maintain aspect ratio */
|
||||
-webkit-mask-image : var(--wc);
|
||||
-webkit-mask-size : contain;
|
||||
-webkit-mask-repeat : no-repeat;
|
||||
mask-image : var(--wc);
|
||||
mask-size : contain;
|
||||
mask-repeat : no-repeat;
|
||||
background-size : cover;
|
||||
background-color : var(--HB_Color_WatercolorStain); /*default color*/
|
||||
--wc : @watercolor1; /*default image*/
|
||||
z-index : -2;
|
||||
}
|
||||
|
||||
.watercolor1 { --wc : @watercolor1; }
|
||||
.watercolor2 { --wc : @watercolor2; }
|
||||
.watercolor3 { --wc : @watercolor3; }
|
||||
.watercolor4 { --wc : @watercolor4; }
|
||||
.watercolor5 { --wc : @watercolor5; }
|
||||
.watercolor6 { --wc : @watercolor6; }
|
||||
.watercolor7 { --wc : @watercolor7; }
|
||||
.watercolor8 { --wc : @watercolor8; }
|
||||
.watercolor9 { --wc : @watercolor9; }
|
||||
.watercolor10 { --wc : @watercolor10; }
|
||||
.watercolor11 { --wc : @watercolor11; }
|
||||
.watercolor12 { --wc : @watercolor12; }
|
||||
|
||||
//************************************
|
||||
// * CODE BLOCKS
|
||||
// ************************************/
|
||||
code{
|
||||
font-family : "Courier New", Courier, monospace;
|
||||
white-space : pre-wrap;
|
||||
overflow-wrap : break-word;
|
||||
}
|
||||
|
||||
pre code{
|
||||
width : 100%;
|
||||
display : inline-block;
|
||||
}
|
||||
//*****************************
|
||||
// * EXTRAS
|
||||
// *****************************/
|
||||
.columnSplit {
|
||||
visibility : hidden;
|
||||
-webkit-column-break-after : always;
|
||||
break-after : always;
|
||||
-moz-column-break-after : always;
|
||||
}
|
||||
//Avoid breaking up
|
||||
blockquote,table{
|
||||
z-index : 15;
|
||||
-webkit-column-break-inside : avoid;
|
||||
page-break-inside : avoid;
|
||||
break-inside : avoid;
|
||||
}
|
||||
// Nested lists
|
||||
ul ul,ol ol,ul ol,ol ul{
|
||||
margin-bottom : 0px;
|
||||
margin-left : 1.5em;
|
||||
}
|
||||
li{
|
||||
-webkit-column-break-inside : avoid;
|
||||
page-break-inside : avoid;
|
||||
break-inside : avoid;
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************
|
||||
// * MUSTACHE DIVS/SPANS
|
||||
// *****************************/
|
||||
:where(.page) {
|
||||
.block {
|
||||
break-inside : avoid;
|
||||
display : inline-block;
|
||||
.page :where(&) {
|
||||
width : 100%;
|
||||
}
|
||||
}
|
||||
.inline-block {
|
||||
display : inline-block;
|
||||
text-indent : initial;
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************
|
||||
// * DEFINITION LISTS
|
||||
// *****************************/
|
||||
:where(.page) {
|
||||
dl {
|
||||
padding-left : 1em;
|
||||
white-space : pre-line;
|
||||
}
|
||||
dt {
|
||||
display : inline;
|
||||
margin-right : 0.5ch;
|
||||
margin-left : -1em;
|
||||
}
|
||||
dd {
|
||||
display : inline;
|
||||
margin-left : 0;
|
||||
text-indent : 0;
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************
|
||||
// * BLANK LINE
|
||||
// *****************************/
|
||||
:where(.page) {
|
||||
.blank {
|
||||
height : 1em;
|
||||
margin-top : 0;
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************
|
||||
// * WIDE
|
||||
// *****************************/
|
||||
:where(.page) {
|
||||
.wide{
|
||||
column-span : all;
|
||||
display : block;
|
||||
margin-bottom : 1em;
|
||||
&+* {
|
||||
margin-top : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
themes/V3/Journal/dropdownTexture.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
6
themes/V3/Journal/settings.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name" : "Journal",
|
||||
"renderer" : "V3",
|
||||
"baseTheme" : false,
|
||||
"baseSnippets" : "5ePHB"
|
||||
}
|
||||
4
themes/V3/Journal/snippets.js
Normal file
@@ -0,0 +1,4 @@
|
||||
/* eslint-disable max-lines */
|
||||
|
||||
module.exports = [
|
||||
];
|
||||
559
themes/V3/Journal/style.less
Normal file
@@ -0,0 +1,559 @@
|
||||
@import (less) './themes/fonts/Journal/fonts.less';
|
||||
@import (less) './themes/assets/assets.less';
|
||||
|
||||
:root {
|
||||
//Colors
|
||||
--HB_Color_Background : unset; // Light parchment
|
||||
--HB_Color_Text : #412121; // Dark Maroon Brown
|
||||
--HB_Color_Text2 : #261C13CC; //Dark Brown
|
||||
--HB_Color_HeaderText : #58180D; // Dark Maroon
|
||||
--HB_Color_CaptionText : #766649; // Brown
|
||||
--HB_Color_WatercolorStain : #BBAD82; // Light brown
|
||||
}
|
||||
|
||||
.useSansSerif(){
|
||||
font-family : PermanentMarker;
|
||||
font-size : 0.3cm;
|
||||
line-height : 1.2em;
|
||||
color : var(--HB_Color_Text2);
|
||||
p,dl,ul,ol {
|
||||
line-height : 1.2em;
|
||||
}
|
||||
ul, ol {
|
||||
padding-left : 1em;
|
||||
}
|
||||
em{
|
||||
font-style : italic;
|
||||
}
|
||||
strong{
|
||||
font-weight : 800;
|
||||
font-size : 1.1em;
|
||||
}
|
||||
h5 + * {
|
||||
margin-top : 0.1cm;
|
||||
}
|
||||
}
|
||||
.useColumns(@multiplier : 1, @fillMode: balance){
|
||||
column-gap : 0.5cm;
|
||||
}
|
||||
|
||||
.page{
|
||||
background-size : 200% 100%;
|
||||
background-repeat : no-repeat;
|
||||
filter : drop-shadow(1px 4px 14px black);
|
||||
background-image : url(/assets/Journal/Background1.webp);
|
||||
padding : 2.1cm 1.9cm 1.7cm 3.8cm;
|
||||
&:nth-of-type(2n + 1) {
|
||||
background-position : left;
|
||||
}
|
||||
&:nth-of-type(2n) {
|
||||
background-position : right;
|
||||
padding : 2.1cm 3.9cm 1.7cm 1.8cm;
|
||||
}
|
||||
&:nth-of-type(2) {
|
||||
background-image : url(/assets/Journal/Background2.webp); //Only first page should show ribbon
|
||||
}
|
||||
|
||||
& .columnWrapper {
|
||||
//transform: rotate(-0.5deg); // Breaks absolute positioning of images/footers. Wait for Chrome fix
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************
|
||||
// * BASE
|
||||
// *****************************/
|
||||
:where(.page){
|
||||
color : var(--HB_Color_Text);
|
||||
font-family : ReenieBeanie;
|
||||
font-size : 0.53cm;
|
||||
line-height : 0.8em;
|
||||
p + * {
|
||||
margin-top : 0.325cm;
|
||||
}
|
||||
p + p{
|
||||
margin-top : 0;
|
||||
}
|
||||
ul{
|
||||
margin-bottom : 0.8em;
|
||||
}
|
||||
ol{
|
||||
margin-bottom : 0.8em;
|
||||
}
|
||||
em{
|
||||
text-decoration : underline;
|
||||
font-style : unset;
|
||||
}
|
||||
del{
|
||||
text-decoration-style: double;
|
||||
}
|
||||
|
||||
//Indents after p or lists
|
||||
p+p, ul+p, ol+p{
|
||||
text-indent : 1em;
|
||||
}
|
||||
//*****************************
|
||||
// * HEADERS
|
||||
// *****************************/
|
||||
h1,h2,h3,h4,h5{
|
||||
font-family : FrederickaTheGreat;
|
||||
font-weight : unset;
|
||||
color : var(--HB_Color_HeaderText);
|
||||
}
|
||||
h1{
|
||||
margin-bottom : 0.18cm; //Margin-bottom only because this is WIDE
|
||||
font-size : 0.89cm;
|
||||
line-height : 1em;
|
||||
font-variant : small-caps;
|
||||
&+p::first-letter{
|
||||
float : left;
|
||||
font-family : FrederickaTheGreat;
|
||||
line-height : 1em;
|
||||
font-size : 1.9em;
|
||||
padding-left : 40px; //Allow background color to extend into margins
|
||||
margin-top : -0.3cm;
|
||||
margin-bottom : -20px;
|
||||
margin-left : -40px;
|
||||
margin-right : 0.1em;
|
||||
padding-top : 0.3em;
|
||||
padding-bottom : 2px;
|
||||
}
|
||||
&+p::first-line{
|
||||
font-variant : small-caps;
|
||||
}
|
||||
}
|
||||
h2{
|
||||
font-size : 0.62cm;
|
||||
line-height : 0.988em; //Font is misaligned. Shift up slightly
|
||||
}
|
||||
h3{
|
||||
font-size : 0.575cm;
|
||||
line-height : 0.995em; //Font is misaligned. Shift up slightly
|
||||
margin-left : -0.9em;
|
||||
}
|
||||
h4{
|
||||
font-size : 0.55cm;
|
||||
line-height : 0.971em; //Font is misaligned. Shift up slightly
|
||||
color : var(--HB_Color_Text);
|
||||
padding-bottom : 5px;
|
||||
transform:rotate(0deg);
|
||||
&:nth-of-type(2n) {
|
||||
transform:rotate(1deg);
|
||||
}
|
||||
&:nth-of-type(3n) {
|
||||
transform:rotate(-1.5deg);
|
||||
}
|
||||
}
|
||||
h5{
|
||||
font-family : PermanentMarker;
|
||||
font-size : 0.4cm;
|
||||
color : var(--HB_Color_Text2);
|
||||
font-weight : bold;
|
||||
line-height : 0.951em; //Font is misaligned. Shift up slightly
|
||||
& + * {
|
||||
margin-top : 0.2cm;
|
||||
}
|
||||
}
|
||||
//*****************************
|
||||
// * TABLE
|
||||
// *****************************/
|
||||
table{
|
||||
.useSansSerif();
|
||||
& + * {
|
||||
margin-top : 0.325cm;
|
||||
}
|
||||
thead{
|
||||
th{
|
||||
vertical-align : bottom;
|
||||
padding : 0.14em 0;
|
||||
}
|
||||
}
|
||||
tbody{
|
||||
tr{
|
||||
td{
|
||||
padding : 0.14em 0;
|
||||
}
|
||||
&:nth-child(odd){
|
||||
background-image : linear-gradient(to left, #41212100, #41212122, #41212100);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//*****************************
|
||||
// * NOTE
|
||||
// *****************************/
|
||||
.note{
|
||||
.useSansSerif();
|
||||
border-style : solid;
|
||||
border-width : 1px;
|
||||
border-image-source : url(/assets/Journal/Border1.png);
|
||||
border-image-slice : 18 18 18 18;
|
||||
border-image-width : 6px 6px 6px 6px;
|
||||
border-image-outset : 5px 5px 5px 5px;
|
||||
border-image-repeat : stretch stretch;
|
||||
background-image : url(/assets/Journal/HashMarks.png),
|
||||
linear-gradient(to bottom right, #ff000000, #a36a4e14, #41212100);
|
||||
background-size : 120% 120%;
|
||||
background-repeat : no-repeat;
|
||||
background-position : center;
|
||||
padding : 0.2cm;
|
||||
:where(&) {
|
||||
margin-top : 9px; //Prevent top border getting cut off on colbreak
|
||||
}
|
||||
& + * {
|
||||
margin-top : 0.45cm;
|
||||
}
|
||||
h5 {
|
||||
font-size : 0.375cm;
|
||||
}
|
||||
p{
|
||||
padding-bottom : 0px;
|
||||
}
|
||||
:last-child {
|
||||
margin-bottom : 0;
|
||||
}
|
||||
}
|
||||
//************************************
|
||||
// * DESCRIPTIVE TEXT BOX
|
||||
// ************************************/
|
||||
* + .descriptive {
|
||||
margin-top : 0.6cm;
|
||||
}
|
||||
.descriptive{
|
||||
.useSansSerif();
|
||||
border-style : solid;
|
||||
border-width : 1px;
|
||||
border-image-source : url('/assets/Journal/Border2.png');
|
||||
border-image-slice : 48 48 48 48;
|
||||
border-image-width : 20px;
|
||||
border-image-outset : 16px 20px 16px 20px;
|
||||
border-image-repeat : stretch stretch;
|
||||
background-image : url(/assets/Journal/HashMarks.png),
|
||||
linear-gradient(to bottom right, #ff000000, #41212114, #41212100);
|
||||
background-size : 120% 120%;
|
||||
background-repeat : no-repeat;
|
||||
background-position : center;
|
||||
padding : 0.2cm;
|
||||
:where(&) {
|
||||
margin-top : 4px; //Prevent top border getting cut off on colbreak
|
||||
}
|
||||
& + * {
|
||||
margin-top : 0.45cm;
|
||||
}
|
||||
h5 {
|
||||
font-size : 0.375cm;
|
||||
}
|
||||
p{
|
||||
padding-bottom : 0px;
|
||||
}
|
||||
:last-child {
|
||||
margin-bottom : 0;
|
||||
}
|
||||
}
|
||||
//*****************************
|
||||
// * Images Snippets
|
||||
// *****************************/
|
||||
|
||||
/* Arist Credit */
|
||||
.artist {
|
||||
position : absolute;
|
||||
width : auto;
|
||||
text-align : center;
|
||||
font-family : WalterTurncoat;
|
||||
font-size : 0.27cm;
|
||||
color : var(--HB_Color_CaptionText);
|
||||
p, p + p {
|
||||
margin : unset;
|
||||
text-indent : unset;
|
||||
line-height : 1em;
|
||||
}
|
||||
h5 {
|
||||
font-size : 1.3em;
|
||||
font-family : WalterTurncoat;
|
||||
}
|
||||
a{
|
||||
color : inherit;
|
||||
text-decoration : unset;
|
||||
&:hover {
|
||||
text-decoration : underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************
|
||||
// * MONSTER STAT BLOCK
|
||||
// *****************************/
|
||||
.monster {
|
||||
.useSansSerif();
|
||||
&.frame {
|
||||
border-style : solid;
|
||||
border-width : 7px 6px;
|
||||
border-image-source : url('/assets/Journal/Border3.png');
|
||||
border-image-slice : 63 74 63 74;
|
||||
border-image-width : 15px 20px 15px 20px;
|
||||
border-image-outset : 12px 12px 12px 12px;
|
||||
border-image-repeat : stretch round;
|
||||
background-image : url('/assets/Journal/HashMarks.png'),
|
||||
linear-gradient(to bottom right, #ff000000, #a36a4e14, #41212100);
|
||||
background-blend-mode : screen multiply;
|
||||
background-size : 100%;
|
||||
padding : 0.2cm;
|
||||
}
|
||||
|
||||
color: var(--HB_Color_Text);
|
||||
position : relative;
|
||||
padding : 0px;
|
||||
margin-bottom : 0.325cm;
|
||||
|
||||
//Headers
|
||||
h2{
|
||||
font-size : 0.62cm;
|
||||
line-height : 1em;
|
||||
margin : 0;
|
||||
&+p {
|
||||
margin-bottom : 0; //Monster size and type subtext
|
||||
}
|
||||
}
|
||||
h3{
|
||||
margin-left : 0;
|
||||
font-variant : small-caps;
|
||||
padding-bottom : 0.05cm;
|
||||
}
|
||||
hr{
|
||||
visibility : visible;
|
||||
height : 6px;
|
||||
margin : 0.12cm 0cm;
|
||||
background-image : url('/assets/Journal/HorizontalRule.png');
|
||||
background-size : 100% 100%;
|
||||
}
|
||||
hr:last-of-type + * {
|
||||
margin-top : 0.325cm; // Space after last HR
|
||||
}
|
||||
|
||||
// Monster Ability table
|
||||
hr + table:first-of-type{
|
||||
margin : 0;
|
||||
column-span : none;
|
||||
background-image : none;
|
||||
border-style : none;
|
||||
border-image : none;
|
||||
color : inherit;
|
||||
tr {
|
||||
background-image : none;
|
||||
}
|
||||
td,th {
|
||||
padding: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
:last-child {
|
||||
margin-bottom : 0;
|
||||
}
|
||||
|
||||
strong, em {
|
||||
font-style : normal;
|
||||
text-decoration : none;
|
||||
}
|
||||
}
|
||||
|
||||
//Full Width
|
||||
.monster.wide{
|
||||
.useColumns(0.96, @fillMode: balance);
|
||||
}
|
||||
|
||||
//*****************************
|
||||
// * FOOTER
|
||||
// *****************************/
|
||||
&:nth-child(odd){
|
||||
.pageNumber{
|
||||
left : 3cm;
|
||||
}
|
||||
.footnote{
|
||||
left : 4.5cm;
|
||||
text-align : left;
|
||||
}
|
||||
}
|
||||
.pageNumber{
|
||||
font-family : FrederickaTheGreat;
|
||||
position : absolute;
|
||||
right : 3cm;
|
||||
bottom : 1.25cm;
|
||||
width : 50px;
|
||||
font-size : 0.9em;
|
||||
color : var(--HB_Color_HeaderText);
|
||||
text-align : center;
|
||||
text-indent : 0;
|
||||
&.auto::after {
|
||||
content : counter(phb-page-numbers);
|
||||
}
|
||||
}
|
||||
.footnote{
|
||||
position : absolute;
|
||||
right : 4.5cm;
|
||||
bottom : 1.25cm;
|
||||
z-index : 150;
|
||||
width : 200px;
|
||||
font-size : 0.8em;
|
||||
color : var(--HB_Color_HeaderText);
|
||||
text-align : right;
|
||||
}
|
||||
//************************************
|
||||
// * CODE BLOCKS
|
||||
// ************************************/
|
||||
code{
|
||||
font-size : 0.3cm;
|
||||
padding : 0px 4px;
|
||||
color : var(--HB_Color_Text);
|
||||
vertical-align : middle;
|
||||
background-color : #faf7ea;
|
||||
border-radius : 4px;
|
||||
}
|
||||
|
||||
pre code{
|
||||
border-style : solid;
|
||||
border-width : 1px;
|
||||
border-image : @codeBorderImage 26 stretch;
|
||||
border-image-width : 10px;
|
||||
border-image-outset : 2px;
|
||||
border-radius : 12px;
|
||||
margin-bottom : 2px;
|
||||
padding : 0.15cm;
|
||||
.page :where(&) {
|
||||
margin-top : 2px; //Prevent top border getting cut off on colbreak
|
||||
}
|
||||
& + * {
|
||||
margin-top : 0.325cm;
|
||||
}
|
||||
}
|
||||
//*****************************
|
||||
// * EXTRAS
|
||||
// *****************************/
|
||||
hr{
|
||||
visibility : hidden;
|
||||
border : none;
|
||||
margin : 0px;
|
||||
}
|
||||
//Text indent right after table
|
||||
table+p{
|
||||
text-indent : 1em;
|
||||
}
|
||||
a, a:visited, a:hover {
|
||||
color: var(--HB_Color_Text);
|
||||
transition:all 1s ease;
|
||||
}
|
||||
a:hover {
|
||||
color:red;
|
||||
}
|
||||
}
|
||||
//*****************************
|
||||
// * SPELL LIST
|
||||
// *****************************/
|
||||
|
||||
.page .spellList{
|
||||
.useSansSerif();
|
||||
font-family : PermanentMarker;
|
||||
column-count : 2;
|
||||
ul+h5{
|
||||
margin-top : 15px;
|
||||
}
|
||||
ul{
|
||||
margin-bottom : 0.5em;
|
||||
padding-left : 1em;
|
||||
text-indent : -1em;
|
||||
list-style-type : none;
|
||||
-webkit-column-break-inside : auto;
|
||||
page-break-inside : auto;
|
||||
break-inside : auto;
|
||||
}
|
||||
&.wide{
|
||||
column-count : 4;
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************
|
||||
// * CLASS TABLE
|
||||
// *****************************/
|
||||
.page .classTable{
|
||||
th[colspan]:not([rowspan]) {
|
||||
white-space : nowrap;
|
||||
}
|
||||
h5 + table{
|
||||
margin-top : 0.2cm;
|
||||
}
|
||||
}
|
||||
//*****************************
|
||||
// * TABLE OF CONTENTS
|
||||
// *****************************/
|
||||
.page .toc{
|
||||
-webkit-column-break-inside : avoid;
|
||||
page-break-inside : avoid;
|
||||
break-inside : avoid;
|
||||
h1 {
|
||||
text-align : center;
|
||||
margin-bottom : 0.3cm;
|
||||
}
|
||||
a{
|
||||
display : inline;
|
||||
color : inherit;
|
||||
text-decoration : none;
|
||||
&:hover{
|
||||
text-decoration : underline;
|
||||
}
|
||||
}
|
||||
h4 {
|
||||
margin-top : 0.2cm;
|
||||
line-height : 0.4cm;
|
||||
& + ul li {
|
||||
line-height: 1.2em;
|
||||
}
|
||||
}
|
||||
ul{
|
||||
padding-left : 0;
|
||||
list-style-type : none;
|
||||
li + li h3 {
|
||||
margin-top : 0.26cm;
|
||||
line-height : 1em
|
||||
}
|
||||
h3 span:first-child::after {
|
||||
border : none;
|
||||
}
|
||||
span {
|
||||
display : table-cell;
|
||||
&:first-child {
|
||||
position : relative;
|
||||
overflow : hidden;
|
||||
&::after {
|
||||
content : "";
|
||||
position : absolute;
|
||||
bottom : 0.08cm;
|
||||
margin-left : 0.06cm; /* Spacing before dot leaders */
|
||||
width : 100%;
|
||||
border-bottom : 0.05cm dotted #000;
|
||||
}
|
||||
}
|
||||
&:last-child {
|
||||
font-family : ReenieBeanie;
|
||||
font-size : 0.34cm;
|
||||
font-weight : normal;
|
||||
color : black;
|
||||
text-align : right;
|
||||
vertical-align : bottom; /* Keep page number bottom-aligned */
|
||||
width : 1%;
|
||||
padding-left : 0.06cm; /* Spacing after dot leaders */
|
||||
/*white-space : nowrap; /* Uncomment if needed */
|
||||
}
|
||||
}
|
||||
ul { /*List indent*/
|
||||
margin-left : 1em;
|
||||
}
|
||||
}
|
||||
&.wide{
|
||||
.useColumns(0.96, @fillMode: balance);
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************
|
||||
// * WIDE
|
||||
// *****************************/
|
||||
:where(.page) .wide {
|
||||
margin-bottom : 0.45cm;
|
||||
}
|
||||
BIN
themes/assets/DMG_background.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
themes/assets/DMG_footerAccent.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
themes/assets/Journal/Background1.webp
Normal file
|
After Width: | Height: | Size: 151 KiB |
BIN
themes/assets/Journal/Background2.webp
Normal file
|
After Width: | Height: | Size: 143 KiB |
BIN
themes/assets/Journal/Border1.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
themes/assets/Journal/Border2.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
themes/assets/Journal/Border3.png
Normal file
|
After Width: | Height: | Size: 170 KiB |
BIN
themes/assets/Journal/HashMarks.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
themes/assets/Journal/HashMarksLight.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
themes/assets/Journal/HashMarksLight2.png
Normal file
|
After Width: | Height: | Size: 545 KiB |
BIN
themes/assets/Journal/HorizontalRule.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
@@ -1,26 +1,26 @@
|
||||
// PHB
|
||||
@footerAccentImage : data-uri('./themes/assets/footerAccent.png');
|
||||
@frameBorderImage : data-uri('./themes/assets/frameBorder.png');
|
||||
@backgroundImage : data-uri('./themes/assets/parchmentBackground.jpg');
|
||||
@redTriangleImage : data-uri('./themes/assets/redTriangle.png');
|
||||
@monsterBorderImageLegacy : data-uri('./themes/assets/monsterBorderLegacy.png');
|
||||
@noteBorderImage : data-uri('./themes/assets/noteBorder.png');
|
||||
@descriptiveBoxImage : data-uri('./themes/assets/descriptiveBorder.png');
|
||||
@monsterBlockBackground : data-uri('./themes/assets/parchmentBackgroundGrayscale.jpg');
|
||||
@monsterBorderImage : data-uri('./themes/assets/monsterBorderFancy.png');
|
||||
@codeBorderImage : data-uri('./themes/assets/codeBorder.png');
|
||||
@classTableDecoration : data-uri('./themes/assets/classTableDecoration.png');
|
||||
@footerAccentImage : url('/assets/PHB_footerAccent.png');
|
||||
@frameBorderImage : url('/assets/frameBorder.png');
|
||||
@backgroundImage : url('/assets/parchmentBackground.jpg');
|
||||
@redTriangleImage : url('/assets/redTriangle.png');
|
||||
@monsterBorderImageLegacy : url('/assets/monsterBorderLegacy.png');
|
||||
@noteBorderImage : url('/assets/noteBorder.png');
|
||||
@descriptiveBoxImage : url('/assets/descriptiveBorder.png');
|
||||
@monsterBlockBackground : url('/assets/parchmentBackgroundGrayscale.jpg');
|
||||
@monsterBorderImage : url('/assets/monsterBorderFancy.png');
|
||||
@codeBorderImage : url('/assets/codeBorder.png');
|
||||
@classTableDecoration : url('/assets/classTableDecoration.png');
|
||||
|
||||
// Watercolor Images
|
||||
@watercolor1 : data-uri('./themes/assets/watercolor/watercolor1.png');
|
||||
@watercolor2 : data-uri('./themes/assets/watercolor/watercolor2.png');
|
||||
@watercolor3 : data-uri('./themes/assets/watercolor/watercolor3.png');
|
||||
@watercolor4 : data-uri('./themes/assets/watercolor/watercolor4.png');
|
||||
@watercolor5 : data-uri('./themes/assets/watercolor/watercolor5.png');
|
||||
@watercolor6 : data-uri('./themes/assets/watercolor/watercolor6.png');
|
||||
@watercolor7 : data-uri('./themes/assets/watercolor/watercolor7.png');
|
||||
@watercolor8 : data-uri('./themes/assets/watercolor/watercolor8.png');
|
||||
@watercolor9 : data-uri('./themes/assets/watercolor/watercolor9.png');
|
||||
@watercolor10 : data-uri('./themes/assets/watercolor/watercolor10.png');
|
||||
@watercolor11 : data-uri('./themes/assets/watercolor/watercolor11.png');
|
||||
@watercolor12 : data-uri('./themes/assets/watercolor/watercolor12.png');
|
||||
@watercolor1 : url('/assets/watercolor/watercolor1.png');
|
||||
@watercolor2 : url('/assets/watercolor/watercolor2.png');
|
||||
@watercolor3 : url('/assets/watercolor/watercolor3.png');
|
||||
@watercolor4 : url('/assets/watercolor/watercolor4.png');
|
||||
@watercolor5 : url('/assets/watercolor/watercolor5.png');
|
||||
@watercolor6 : url('/assets/watercolor/watercolor6.png');
|
||||
@watercolor7 : url('/assets/watercolor/watercolor7.png');
|
||||
@watercolor8 : url('/assets/watercolor/watercolor8.png');
|
||||
@watercolor9 : url('/assets/watercolor/watercolor9.png');
|
||||
@watercolor10 : url('/assets/watercolor/watercolor10.png');
|
||||
@watercolor11 : url('/assets/watercolor/watercolor11.png');
|
||||
@watercolor12 : url('/assets/watercolor/watercolor12.png');
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
/* Main Font, serif */
|
||||
@font-face {
|
||||
font-family: BookSanity;
|
||||
src: url('../fonts/5e legacy/Bookinsanity.woff2');
|
||||
src: url('../../../fonts/5e legacy/Bookinsanity.woff2');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
@font-face {
|
||||
font-family: BookSanity;
|
||||
src: url('../fonts/5e legacy/Bookinsanity Bold.woff2');
|
||||
src: url('../../../fonts/5e legacy/Bookinsanity Bold.woff2');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
@font-face {
|
||||
font-family: BookSanity;
|
||||
src: url('../fonts/5e legacy/Bookinsanity Italic.woff2');
|
||||
src: url('../../../fonts/5e legacy/Bookinsanity Italic.woff2');
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
}
|
||||
@font-face {
|
||||
font-family: BookSanity;
|
||||
src: url('../fonts/5e legacy/Bookinsanity Bold Italic.woff2');
|
||||
src: url('../../../fonts/5e legacy/Bookinsanity Bold Italic.woff2');
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
}
|
||||
@@ -27,19 +27,19 @@
|
||||
/* Notes and Tables, sans-serif */
|
||||
@font-face {
|
||||
font-family: ScalySans;
|
||||
src: url('../fonts/5e legacy/Scaly Sans.woff2');
|
||||
src: url('../../../fonts/5e legacy/Scaly Sans.woff2');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
@font-face {
|
||||
font-family: ScalySansSmallCaps;
|
||||
src: url('../fonts/5e legacy/Scaly Sans Caps.woff2');
|
||||
src: url('../../../fonts/5e legacy/Scaly Sans Caps.woff2');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
@font-face {
|
||||
font-family: WalterTurncoat;
|
||||
src: url('../fonts/5e legacy/WalterTurncoat-Regular.woff2');
|
||||
src: url('../../../fonts/5e legacy/WalterTurncoat-Regular.woff2');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
@@ -47,7 +47,7 @@
|
||||
/* Headers */
|
||||
@font-face {
|
||||
font-family: MrJeeves;
|
||||
src: url('../fonts/5e legacy/Mr Eaves Small Caps.woff2');
|
||||
src: url('../../../fonts/5e legacy/Mr Eaves Small Caps.woff2');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
@@ -55,7 +55,7 @@
|
||||
/* Fancy Drop Cap */
|
||||
@font-face {
|
||||
font-family: Solberry;
|
||||
src: url('../fonts/5e legacy/Solbera Imitation.woff2');
|
||||
src: url('../../../fonts/5e legacy/Solbera Imitation.woff2');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
/* Main Font, serif */
|
||||
@font-face {
|
||||
font-family: BookInsanityRemake;
|
||||
src: url('../fonts/5e/Bookinsanity.woff2');
|
||||
src: url('../../../fonts/5e/Bookinsanity.woff2');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
@font-face {
|
||||
font-family: BookInsanityRemake;
|
||||
src: url('../fonts/5e/Bookinsanity Bold.woff2');
|
||||
src: url('../../../fonts/5e/Bookinsanity Bold.woff2');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
@font-face {
|
||||
font-family: BookInsanityRemake;
|
||||
src: url('../fonts/5e/Bookinsanity Italic.woff2');
|
||||
src: url('../../../fonts/5e/Bookinsanity Italic.woff2');
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
}
|
||||
@font-face {
|
||||
font-family: BookInsanityRemake;
|
||||
src: url('../fonts/5e/Bookinsanity Bold Italic.woff2');
|
||||
src: url('../../../fonts/5e/Bookinsanity Bold Italic.woff2');
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
}
|
||||
@@ -27,37 +27,37 @@
|
||||
/* Notes and Tables, sans-serif */
|
||||
@font-face {
|
||||
font-family: ScalySansRemake;
|
||||
src: url('../fonts/5e/Scaly Sans.woff2');
|
||||
src: url('../../../fonts/5e/Scaly Sans.woff2');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
@font-face {
|
||||
font-family: ScalySansRemake;
|
||||
src: url('../fonts/5e/Scaly Sans Bold.woff2');
|
||||
src: url('../../../fonts/5e/Scaly Sans Bold.woff2');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
@font-face {
|
||||
font-family: ScalySansRemake;
|
||||
src: url('../fonts/5e/Scaly Sans Italic.woff2');
|
||||
src: url('../../../fonts/5e/Scaly Sans Italic.woff2');
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
}
|
||||
@font-face {
|
||||
font-family: ScalySansRemake;
|
||||
src: url('../fonts/5e/Scaly Sans Bold Italic.woff2');
|
||||
src: url('../../../fonts/5e/Scaly Sans Bold Italic.woff2');
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
}
|
||||
@font-face {
|
||||
font-family: ScalySansSmallCapsRemake;
|
||||
src: url('../fonts/5e/Scaly Sans Caps.woff2');
|
||||
src: url('../../../fonts/5e/Scaly Sans Caps.woff2');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
@font-face {
|
||||
font-family: WalterTurncoat;
|
||||
src: url('../fonts/5e/WalterTurncoat-Regular.woff2');
|
||||
src: url('../../../fonts/5e/WalterTurncoat-Regular.woff2');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
@@ -65,7 +65,7 @@
|
||||
/* Headers */
|
||||
@font-face {
|
||||
font-family: MrEavesRemake;
|
||||
src: url('../fonts/5e/Mr Eaves Small Caps.woff2');
|
||||
src: url('../../../fonts/5e/Mr Eaves Small Caps.woff2');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
@@ -73,7 +73,7 @@
|
||||
/* Fancy Drop Cap */
|
||||
@font-face {
|
||||
font-family: SolberaImitationRemake; //Tweaked 5e version
|
||||
src: url('../fonts/5e/Solbera Imitation Tweak.woff2');
|
||||
src: url('../../../fonts/5e/Solbera Imitation Tweak.woff2');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
BIN
themes/fonts/Journal/FrederickaTheGreat-Regular.woff2
Normal file
202
themes/fonts/Journal/LICENSE - PermanentMarker.txt
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
BIN
themes/fonts/Journal/PermanentMarker-Regular.woff2
Normal file
BIN
themes/fonts/Journal/ReenieBeanie-Regular.woff2
Normal file
58
themes/fonts/Journal/fonts.less
Normal file
@@ -0,0 +1,58 @@
|
||||
/* Main Font, serif */
|
||||
@font-face {
|
||||
font-family: ReenieBeanie;
|
||||
src: url('../../../fonts/Journal/ReenieBeanie-Regular.woff2');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* Notes and Tables, sans-serif */
|
||||
@font-face {
|
||||
font-family: PermanentMarker;
|
||||
src: url('../../../fonts/Journal/PermanentMarker-Regular.woff2');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
@font-face {
|
||||
font-family: WalterTurncoat;
|
||||
src: url('../../../fonts/5e/WalterTurncoat-Regular.woff2');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* Headers */
|
||||
@font-face {
|
||||
font-family: FrederickaTheGreat;
|
||||
src: url('../../../fonts/Journal/FrederickaTheGreat-Regular.woff2');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* Cover Page */
|
||||
@font-face {
|
||||
font-family: NodestoCapsCondensed;
|
||||
src: url('../fonts/5e/Nodesto Caps Condensed.woff2');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: NodestoCapsCondensed;
|
||||
src: url('../fonts/5e/Nodesto Caps Condensed Bold.woff2');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: NodestoCapsCondensed;
|
||||
src: url('../fonts/5e/Nodesto Caps Condensed Italic.woff2');
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: NodestoCapsCondensed;
|
||||
src: url('../fonts/5e/Nodesto Caps Condensed Bold Italic.woff2');
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
}
|
||||
40
themes/themes.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"Legacy": {
|
||||
"5ePHB": {
|
||||
"name": "5e PHB",
|
||||
"renderer": "legacy",
|
||||
"baseTheme": false,
|
||||
"path": "5ePHB"
|
||||
}
|
||||
},
|
||||
"V3": {
|
||||
"5eDMG": {
|
||||
"name": "5e DMG",
|
||||
"renderer": "V3",
|
||||
"baseTheme": "5ePHB",
|
||||
"baseSnippets": "5ePHB",
|
||||
"path": "5eDMG"
|
||||
},
|
||||
"5ePHB": {
|
||||
"name": "5e PHB",
|
||||
"renderer": "V3",
|
||||
"baseTheme": false,
|
||||
"baseSnippets": false,
|
||||
"path": "5ePHB"
|
||||
},
|
||||
"Blank": {
|
||||
"name": "Blank",
|
||||
"renderer": "V3",
|
||||
"baseTheme": false,
|
||||
"baseSnippets": false,
|
||||
"path": "Blank"
|
||||
},
|
||||
"Journal": {
|
||||
"name": "Journal",
|
||||
"renderer": "V3",
|
||||
"baseTheme": false,
|
||||
"baseSnippets": "5ePHB",
|
||||
"path": "Journal"
|
||||
}
|
||||
}
|
||||
}
|
||||