mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2025-12-25 20:33:51 +00:00
Merge branch 'master' into addCreditsSnippet-#283
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
/*eslint max-lines: ["warn", {"max": 300, "skipBlankLines": true, "skipComments": true}]*/
|
||||
require('./brewRenderer.less');
|
||||
const React = require('react');
|
||||
const createClass = require('create-react-class');
|
||||
const { useState, useRef, useEffect } = React;
|
||||
const _ = require('lodash');
|
||||
const cx = require('classnames');
|
||||
|
||||
const MarkdownLegacy = require('naturalcrit/markdownLegacy.js');
|
||||
const Markdown = require('naturalcrit/markdown.js');
|
||||
@@ -13,244 +12,214 @@ const ErrorBar = require('./errorBar/errorBar.jsx');
|
||||
const RenderWarnings = require('homebrewery/renderWarnings/renderWarnings.jsx');
|
||||
const NotificationPopup = require('./notificationPopup/notificationPopup.jsx');
|
||||
const Frame = require('react-frame-component').default;
|
||||
const dedent = require('dedent-tabs').default;
|
||||
|
||||
const Themes = require('themes/themes.json');
|
||||
|
||||
const PAGE_HEIGHT = 1056;
|
||||
const PPR_THRESHOLD = 50;
|
||||
|
||||
const BrewRenderer = createClass({
|
||||
displayName : 'BrewRenderer',
|
||||
getDefaultProps : function() {
|
||||
return {
|
||||
text : '',
|
||||
style : '',
|
||||
renderer : 'legacy',
|
||||
theme : '5ePHB',
|
||||
lang : '',
|
||||
errors : []
|
||||
};
|
||||
},
|
||||
getInitialState : function() {
|
||||
let pages;
|
||||
if(this.props.renderer == 'legacy') {
|
||||
pages = this.props.text.split('\\page');
|
||||
} else {
|
||||
pages = this.props.text.split(/^\\page$/gm);
|
||||
}
|
||||
const INITIAL_CONTENT = dedent`
|
||||
<!DOCTYPE html><html><head>
|
||||
<link href="//use.fontawesome.com/releases/v5.15.1/css/all.css" rel="stylesheet" />
|
||||
<link href="//fonts.googleapis.com/css?family=Open+Sans:400,300,600,700" rel="stylesheet" type="text/css" />
|
||||
<link href='/homebrew/bundle.css' rel='stylesheet' />
|
||||
<base target=_blank>
|
||||
</head><body style='overflow: hidden'><div></div></body></html>`;
|
||||
|
||||
return {
|
||||
viewablePageNumber : 0,
|
||||
height : 0,
|
||||
isMounted : false,
|
||||
//v=====----------------------< Brew Page Component >---------------------=====v//
|
||||
const BrewPage = (props)=>{
|
||||
props = {
|
||||
contents : '',
|
||||
index : 0,
|
||||
...props
|
||||
};
|
||||
return <div className={props.className} id={`p${props.index + 1}`} >
|
||||
<div className='columnWrapper' dangerouslySetInnerHTML={{ __html: props.contents }} />
|
||||
</div>;
|
||||
};
|
||||
|
||||
pages : pages,
|
||||
usePPR : pages.length >= PPR_THRESHOLD,
|
||||
visibility : 'hidden',
|
||||
initialContent : `<!DOCTYPE html><html><head>
|
||||
<link href="//use.fontawesome.com/releases/v5.15.1/css/all.css" rel="stylesheet" />
|
||||
<link href="//fonts.googleapis.com/css?family=Open+Sans:400,300,600,700" rel="stylesheet" type="text/css" />
|
||||
<link href='/homebrew/bundle.css' rel='stylesheet' />
|
||||
<base target=_blank>
|
||||
</head><body style='overflow: hidden'><div></div></body></html>`
|
||||
};
|
||||
},
|
||||
height : 0,
|
||||
lastRender : <div></div>,
|
||||
|
||||
componentWillUnmount : function() {
|
||||
window.removeEventListener('resize', this.updateSize);
|
||||
},
|
||||
//v=====--------------------< Brew Renderer Component >-------------------=====v//
|
||||
const renderedPages = [];
|
||||
let rawPages = [];
|
||||
|
||||
componentDidUpdate : function(prevProps) {
|
||||
if(prevProps.text !== this.props.text) {
|
||||
let pages;
|
||||
if(this.props.renderer == 'legacy') {
|
||||
pages = this.props.text.split('\\page');
|
||||
} else {
|
||||
pages = this.props.text.split(/^\\page$/gm);
|
||||
}
|
||||
this.setState({
|
||||
pages : pages,
|
||||
usePPR : pages.length >= PPR_THRESHOLD
|
||||
});
|
||||
}
|
||||
},
|
||||
const BrewRenderer = (props)=>{
|
||||
props = {
|
||||
text : '',
|
||||
style : '',
|
||||
renderer : 'legacy',
|
||||
theme : '5ePHB',
|
||||
lang : '',
|
||||
errors : [],
|
||||
...props
|
||||
};
|
||||
|
||||
updateSize : function() {
|
||||
this.setState({
|
||||
height : this.refs.main.parentNode.clientHeight,
|
||||
});
|
||||
},
|
||||
const [state, setState] = useState({
|
||||
viewablePageNumber : 0,
|
||||
height : PAGE_HEIGHT,
|
||||
isMounted : false,
|
||||
visibility : 'hidden',
|
||||
});
|
||||
|
||||
handleScroll : function(e){
|
||||
const target = e.target;
|
||||
this.setState((prevState)=>({
|
||||
viewablePageNumber : Math.floor(target.scrollTop / target.scrollHeight * prevState.pages.length)
|
||||
const mainRef = useRef(null);
|
||||
|
||||
if(props.renderer == 'legacy') {
|
||||
rawPages = props.text.split('\\page');
|
||||
} else {
|
||||
rawPages = props.text.split(/^\\page$/gm);
|
||||
}
|
||||
|
||||
useEffect(()=>{ // Unmounting steps
|
||||
return ()=>{window.removeEventListener('resize', updateSize);};
|
||||
}, []);
|
||||
|
||||
const updateSize = ()=>{
|
||||
setState((prevState)=>({
|
||||
...prevState,
|
||||
height : mainRef.current.parentNode.clientHeight,
|
||||
}));
|
||||
},
|
||||
};
|
||||
|
||||
shouldRender : function(pageText, index){
|
||||
if(!this.state.isMounted) return false;
|
||||
const handleScroll = (e)=>{
|
||||
const target = e.target;
|
||||
setState((prevState)=>({
|
||||
...prevState,
|
||||
viewablePageNumber : Math.floor(target.scrollTop / target.scrollHeight * rawPages.length)
|
||||
}));
|
||||
};
|
||||
|
||||
const viewIndex = this.state.viewablePageNumber;
|
||||
if(index == viewIndex - 3) return true;
|
||||
if(index == viewIndex - 2) return true;
|
||||
if(index == viewIndex - 1) return true;
|
||||
if(index == viewIndex) return true;
|
||||
if(index == viewIndex + 1) return true;
|
||||
if(index == viewIndex + 2) return true;
|
||||
if(index == viewIndex + 3) return true;
|
||||
const shouldRender = (index)=>{
|
||||
if(!state.isMounted) return false;
|
||||
|
||||
//Check for style tages
|
||||
if(pageText.indexOf('<style>') !== -1) return true;
|
||||
if(Math.abs(index - state.viewablePageNumber) <= 3)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
},
|
||||
};
|
||||
|
||||
sanitizeScriptTags : function(content) {
|
||||
const sanitizeScriptTags = (content)=>{
|
||||
return content
|
||||
.replace(/<script/ig, '<script')
|
||||
.replace(/<\/script>/ig, '</script>');
|
||||
},
|
||||
};
|
||||
|
||||
renderPageInfo : function(){
|
||||
return <div className='pageInfo' ref='main'>
|
||||
const renderPageInfo = ()=>{
|
||||
return <div className='pageInfo' ref={mainRef}>
|
||||
<div>
|
||||
{this.props.renderer}
|
||||
{props.renderer}
|
||||
</div>
|
||||
<div>
|
||||
{this.state.viewablePageNumber + 1} / {this.state.pages.length}
|
||||
{state.viewablePageNumber + 1} / {rawPages.length}
|
||||
</div>
|
||||
</div>;
|
||||
},
|
||||
};
|
||||
|
||||
renderPPRmsg : function(){
|
||||
if(!this.state.usePPR) return;
|
||||
|
||||
return <div className='ppr_msg'>
|
||||
Partial Page Renderer is enabled, because your brew is so large. May affect rendering.
|
||||
</div>;
|
||||
},
|
||||
|
||||
renderDummyPage : function(index){
|
||||
const renderDummyPage = (index)=>{
|
||||
return <div className='phb page' id={`p${index + 1}`} key={index}>
|
||||
<i className='fas fa-spinner fa-spin' />
|
||||
</div>;
|
||||
},
|
||||
};
|
||||
|
||||
renderStyle : function() {
|
||||
if(!this.props.style) return;
|
||||
const cleanStyle = this.sanitizeScriptTags(this.props.style);
|
||||
//return <div style={{ display: 'none' }} dangerouslySetInnerHTML={{ __html: `<style>@layer styleTab {\n${this.sanitizeScriptTags(this.props.style)}\n} </style>` }} />;
|
||||
const renderStyle = ()=>{
|
||||
if(!props.style) return;
|
||||
const cleanStyle = sanitizeScriptTags(props.style);
|
||||
//return <div style={{ display: 'none' }} dangerouslySetInnerHTML={{ __html: `<style>@layer styleTab {\n${sanitizeScriptTags(props.style)}\n} </style>` }} />;
|
||||
return <div style={{ display: 'none' }} dangerouslySetInnerHTML={{ __html: `<style> ${cleanStyle} </style>` }} />;
|
||||
},
|
||||
};
|
||||
|
||||
renderPage : function(pageText, index){
|
||||
let cleanPageText = this.sanitizeScriptTags(pageText);
|
||||
if(this.props.renderer == 'legacy')
|
||||
return <div className='phb page' id={`p${index + 1}`} dangerouslySetInnerHTML={{ __html: MarkdownLegacy.render(cleanPageText) }} key={index} />;
|
||||
else {
|
||||
const renderPage = (pageText, index)=>{
|
||||
let cleanPageText = sanitizeScriptTags(pageText);
|
||||
if(props.renderer == 'legacy') {
|
||||
const html = MarkdownLegacy.render(cleanPageText);
|
||||
return <BrewPage className='page phb' index={index} key={index} contents={html} />;
|
||||
} else {
|
||||
cleanPageText += `\n\n \n\\column\n `; //Artificial column break at page end to emulate column-fill:auto (until `wide` is used, when column-fill:balance will reappear)
|
||||
return (
|
||||
<div className='page' id={`p${index + 1}`} key={index} >
|
||||
<div className='columnWrapper' dangerouslySetInnerHTML={{ __html: Markdown.render(cleanPageText) }} />
|
||||
</div>
|
||||
);
|
||||
const html = Markdown.render(cleanPageText);
|
||||
return <BrewPage className='page' index={index} key={index} contents={html} />;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
renderPages : function(){
|
||||
if(this.state.usePPR){
|
||||
return _.map(this.state.pages, (page, index)=>{
|
||||
if(this.shouldRender(page, index) && typeof window !== 'undefined'){
|
||||
return this.renderPage(page, index);
|
||||
} else {
|
||||
return this.renderDummyPage(index);
|
||||
}
|
||||
});
|
||||
}
|
||||
if(this.props.errors && this.props.errors.length) return this.lastRender;
|
||||
this.lastRender = _.map(this.state.pages, (page, index)=>{
|
||||
if(typeof window !== 'undefined') {
|
||||
return this.renderPage(page, index);
|
||||
} else {
|
||||
return this.renderDummyPage(index);
|
||||
const renderPages = ()=>{
|
||||
if(props.errors && props.errors.length)
|
||||
return renderedPages;
|
||||
|
||||
_.forEach(rawPages, (page, index)=>{
|
||||
if((shouldRender(index) || !renderedPages[index]) && typeof window !== 'undefined'){
|
||||
renderedPages[index] = renderPage(page, index); // Render any page not yet rendered, but only re-render those in PPR range
|
||||
}
|
||||
});
|
||||
return this.lastRender;
|
||||
},
|
||||
return renderedPages;
|
||||
};
|
||||
|
||||
frameDidMount : function(){ //This triggers when iFrame finishes internal "componentDidMount"
|
||||
const frameDidMount = ()=>{ //This triggers when iFrame finishes internal "componentDidMount"
|
||||
setTimeout(()=>{ //We still see a flicker where the style isn't applied yet, so wait 100ms before showing iFrame
|
||||
this.updateSize();
|
||||
window.addEventListener('resize', this.updateSize);
|
||||
this.renderPages(); //Make sure page is renderable before showing
|
||||
this.setState({
|
||||
updateSize();
|
||||
window.addEventListener('resize', updateSize);
|
||||
renderPages(); //Make sure page is renderable before showing
|
||||
setState((prevState)=>({
|
||||
...prevState,
|
||||
isMounted : true,
|
||||
visibility : 'visible'
|
||||
});
|
||||
}));
|
||||
}, 100);
|
||||
},
|
||||
};
|
||||
|
||||
emitClick : function(){
|
||||
// console.log('iFrame clicked');
|
||||
const emitClick = ()=>{ // Allow clicks inside iFrame to interact with dropdowns, etc. from outside
|
||||
if(!window || !document) return;
|
||||
document.dispatchEvent(new MouseEvent('click'));
|
||||
},
|
||||
};
|
||||
|
||||
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>
|
||||
{!this.state.isMounted
|
||||
? <div className='brewRenderer' onScroll={this.handleScroll}>
|
||||
<div className='pages' ref='pages'>
|
||||
{this.renderDummyPage(1)}
|
||||
</div>
|
||||
const rendererPath = props.renderer == 'V3' ? 'V3' : 'Legacy';
|
||||
const themePath = props.theme ?? '5ePHB';
|
||||
const baseThemePath = Themes[rendererPath][themePath].baseTheme;
|
||||
|
||||
return (
|
||||
<>
|
||||
{/*render dummy page while iFrame is mounting.*/}
|
||||
{!state.isMounted
|
||||
? <div className='brewRenderer' onScroll={handleScroll}>
|
||||
<div className='pages'>
|
||||
{renderDummyPage(1)}
|
||||
</div>
|
||||
: null}
|
||||
</div>
|
||||
: null}
|
||||
|
||||
<Frame id='BrewRenderer' initialContent={this.state.initialContent}
|
||||
style={{ width: '100%', height: '100%', visibility: this.state.visibility }}
|
||||
contentDidMount={this.frameDidMount}
|
||||
onClick={()=>{this.emitClick();}}
|
||||
>
|
||||
<div className={'brewRenderer'}
|
||||
onScroll={this.handleScroll}
|
||||
style={{ height: this.state.height }}>
|
||||
{/*render in iFrame so broken code doesn't crash the site.*/}
|
||||
<Frame id='BrewRenderer' initialContent={INITIAL_CONTENT}
|
||||
style={{ width: '100%', height: '100%', visibility: state.visibility }}
|
||||
contentDidMount={frameDidMount}
|
||||
onClick={()=>{emitClick();}}
|
||||
>
|
||||
<div className={'brewRenderer'}
|
||||
onScroll={handleScroll}
|
||||
style={{ height: state.height }}>
|
||||
|
||||
<ErrorBar errors={this.props.errors} />
|
||||
<div className='popups'>
|
||||
<RenderWarnings />
|
||||
<NotificationPopup />
|
||||
</div>
|
||||
<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
|
||||
&&
|
||||
<>
|
||||
{this.renderStyle()}
|
||||
<div className='pages' ref='pages' lang={`${this.props.lang || 'en'}`}>
|
||||
{this.renderPages()}
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
<ErrorBar errors={props.errors} />
|
||||
<div className='popups'>
|
||||
<RenderWarnings />
|
||||
<NotificationPopup />
|
||||
</div>
|
||||
</Frame>
|
||||
{this.renderPageInfo()}
|
||||
{this.renderPPRmsg()}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
});
|
||||
<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 */}
|
||||
{state.isMounted
|
||||
&&
|
||||
<>
|
||||
{renderStyle()}
|
||||
<div className='pages' lang={`${props.lang || 'en'}`}>
|
||||
{renderPages()}
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
</div>
|
||||
</Frame>
|
||||
{renderPageInfo()}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
module.exports = BrewRenderer;
|
||||
|
||||
@@ -1,46 +1,44 @@
|
||||
@import (multiple, less) 'shared/naturalcrit/styles/reset.less';
|
||||
|
||||
.brewRenderer{
|
||||
.brewRenderer {
|
||||
will-change : transform;
|
||||
overflow-y : scroll;
|
||||
.pages{
|
||||
.pages {
|
||||
margin : 30px 0px;
|
||||
&>.page{
|
||||
& > .page {
|
||||
width : 215.9mm;
|
||||
height : 279.4mm;
|
||||
margin-right : auto;
|
||||
margin-bottom : 30px;
|
||||
margin-left : auto;
|
||||
box-shadow : 1px 4px 14px #000;
|
||||
box-shadow : 1px 4px 14px #000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
.pane{
|
||||
position : relative;
|
||||
}
|
||||
.pageInfo{
|
||||
.pane { position : relative; }
|
||||
.pageInfo {
|
||||
position : absolute;
|
||||
right : 17px;
|
||||
bottom : 0;
|
||||
z-index : 1000;
|
||||
background-color : #333;
|
||||
font-size : 10px;
|
||||
font-weight : 800;
|
||||
color : white;
|
||||
background-color : #333333;
|
||||
div {
|
||||
display: inline-block;
|
||||
display : inline-block;
|
||||
padding : 8px 10px;
|
||||
&:not(:last-child){
|
||||
border-right: 1px solid #666;
|
||||
}
|
||||
&:not(:last-child) { border-right : 1px solid #666666; }
|
||||
}
|
||||
}
|
||||
.ppr_msg{
|
||||
.ppr_msg {
|
||||
position : absolute;
|
||||
left : 0px;
|
||||
bottom : 0;
|
||||
left : 0px;
|
||||
z-index : 1000;
|
||||
padding : 8px 10px;
|
||||
background-color : #333;
|
||||
font-size : 10px;
|
||||
font-weight : 800;
|
||||
color : white;
|
||||
background-color : #333333;
|
||||
}
|
||||
|
||||
@@ -160,6 +160,24 @@ const Editor = createClass({
|
||||
}
|
||||
}
|
||||
|
||||
// Superscript
|
||||
if(line.includes('\^')) {
|
||||
const regex = /\^(?!\s)(?=([^\n\^]*[^\s\^]))\1\^/g;
|
||||
let match;
|
||||
while ((match = regex.exec(line)) != null) {
|
||||
codeMirror.markText({ line: lineNumber, ch: line.indexOf(match[1]) - 1 }, { line: lineNumber, ch: line.indexOf(match[1]) + match[1].length + 1 }, { className: 'superscript' });
|
||||
}
|
||||
}
|
||||
|
||||
// Subscript
|
||||
if(line.includes('^^')) {
|
||||
const regex = /\^\^(?!\s)(?=([^\n\^]*[^\s\^]))\1\^\^/g;
|
||||
let match;
|
||||
while ((match = regex.exec(line)) != null) {
|
||||
codeMirror.markText({ line: lineNumber, ch: line.indexOf(match[1]) - 2 }, { line: lineNumber, ch: line.indexOf(match[1]) + match[1].length + 2 }, { className: 'subscript' });
|
||||
}
|
||||
}
|
||||
|
||||
// Highlight injectors {style}
|
||||
if(line.includes('{') && line.includes('}')){
|
||||
const regex = /(?:^|[^{\n])({(?=((?::(?:"[\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"':{}\s]*)*))\2})/gm;
|
||||
@@ -341,6 +359,14 @@ const Editor = createClass({
|
||||
return this.refs.codeEditor?.undo();
|
||||
},
|
||||
|
||||
foldCode : function(){
|
||||
return this.refs.codeEditor?.foldAllCode();
|
||||
},
|
||||
|
||||
unfoldCode : function(){
|
||||
return this.refs.codeEditor?.unfoldAllCode();
|
||||
},
|
||||
|
||||
render : function(){
|
||||
return (
|
||||
<div className='editor' ref='main'>
|
||||
@@ -354,6 +380,8 @@ const Editor = createClass({
|
||||
theme={this.props.brew.theme}
|
||||
undo={this.undo}
|
||||
redo={this.redo}
|
||||
foldCode={this.foldCode}
|
||||
unfoldCode={this.unfoldCode}
|
||||
historySize={this.historySize()}
|
||||
currentEditorTheme={this.state.editorTheme}
|
||||
updateEditorTheme={this.updateEditorTheme}
|
||||
|
||||
@@ -43,6 +43,18 @@
|
||||
font-weight : bold;
|
||||
color : green;
|
||||
}
|
||||
.superscript:not(.cm-comment) {
|
||||
font-weight : bold;
|
||||
color : goldenrod;
|
||||
vertical-align : super;
|
||||
font-size : 0.9em;
|
||||
}
|
||||
.subscript:not(.cm-comment) {
|
||||
font-weight : bold;
|
||||
color : rgb(123, 123, 15);
|
||||
vertical-align : sub;
|
||||
font-size : 0.9em;
|
||||
}
|
||||
}
|
||||
|
||||
.brewJump {
|
||||
|
||||
@@ -37,6 +37,8 @@ const Snippetbar = createClass({
|
||||
undo : ()=>{},
|
||||
redo : ()=>{},
|
||||
historySize : ()=>{},
|
||||
foldCode : ()=>{},
|
||||
unfoldCode : ()=>{},
|
||||
updateEditorTheme : ()=>{},
|
||||
cursorPos : {}
|
||||
};
|
||||
@@ -144,6 +146,22 @@ const Snippetbar = createClass({
|
||||
renderEditorButtons : function(){
|
||||
if(!this.props.showEditButtons) return;
|
||||
|
||||
let foldButtons;
|
||||
if(this.props.view == 'text'){
|
||||
foldButtons =
|
||||
<>
|
||||
<div className={`editorTool foldAll ${this.props.foldCode ? 'active' : ''}`}
|
||||
onClick={this.props.foldCode} >
|
||||
<i className='fas fa-compress-alt' />
|
||||
</div>
|
||||
<div className={`editorTool unfoldAll ${this.props.unfoldCode ? 'active' : ''}`}
|
||||
onClick={this.props.unfoldCode} >
|
||||
<i className='fas fa-expand-alt' />
|
||||
</div>
|
||||
</>
|
||||
|
||||
}
|
||||
|
||||
return <div className='editors'>
|
||||
<div className={`editorTool undo ${this.props.historySize.undo ? 'active' : ''}`}
|
||||
onClick={this.props.undo} >
|
||||
@@ -154,6 +172,7 @@ const Snippetbar = createClass({
|
||||
<i className='fas fa-redo' />
|
||||
</div>
|
||||
<div className='divider'></div>
|
||||
{foldButtons}
|
||||
<div className={`editorTool editorTheme ${this.state.themeSelector ? 'active' : ''}`}
|
||||
onClick={this.toggleThemeSelector} >
|
||||
<i className='fas fa-palette' />
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
top : 0px;
|
||||
right : 0px;
|
||||
height : @menuHeight;
|
||||
width : 125px;
|
||||
justify-content : space-between;
|
||||
&>div{
|
||||
height : @menuHeight;
|
||||
@@ -46,6 +45,22 @@
|
||||
color : black;
|
||||
}
|
||||
}
|
||||
&.foldAll{
|
||||
.tooltipLeft('Fold All');
|
||||
font-size : 0.75em;
|
||||
color : grey;
|
||||
&.active{
|
||||
color : black;
|
||||
}
|
||||
}
|
||||
&.unfoldAll{
|
||||
.tooltipLeft('Unfold All');
|
||||
font-size : 0.75em;
|
||||
color : grey;
|
||||
&.active{
|
||||
color : black;
|
||||
}
|
||||
}
|
||||
&.editorTheme{
|
||||
.tooltipLeft('Editor Themes');
|
||||
font-size : 0.75em;
|
||||
|
||||
@@ -22,18 +22,18 @@ const errorIndex = (props)=>{
|
||||
## We can't find this brew in Google Drive!
|
||||
|
||||
This file was saved on Google Drive, but this link doesn't work anymore.
|
||||
${ props.brew.authors?.length > 0
|
||||
? `Note that this brew belongs to the Homebrewery account **${ props.brew.authors[0] }**,
|
||||
${ props.brew.account
|
||||
? `which is
|
||||
${props.brew.authors?.length > 0
|
||||
? `Note that this brew belongs to the Homebrewery account **${props.brew.authors[0]}**,
|
||||
${props.brew.account
|
||||
? `which is
|
||||
${props.brew.authors[0] == props.brew.account
|
||||
? `your account.`
|
||||
: `not your account (you are currently signed in as **${props.brew.account}**).`
|
||||
}`
|
||||
: 'and you are not currently signed in to any account.'
|
||||
}`
|
||||
: ''
|
||||
}
|
||||
? `your account.`
|
||||
: `not your account (you are currently signed in as **${props.brew.account}**).`
|
||||
}`
|
||||
: 'and you are not currently signed in to any account.'
|
||||
}`
|
||||
: ''
|
||||
}
|
||||
The Homebrewery cannot delete files from Google Drive on its own, so there
|
||||
are three most likely possibilities:
|
||||
:
|
||||
@@ -75,7 +75,9 @@ const errorIndex = (props)=>{
|
||||
|
||||
**Brew Title:** ${props.brew.brewTitle || 'Unable to show title'}
|
||||
|
||||
**Current Authors:** ${props.brew.authors?.map((author)=>{return `${author}`;}).join(', ') || 'Unable to list authors'}`,
|
||||
**Current Authors:** ${props.brew.authors?.map((author)=>{return `${author}`;}).join(', ') || 'Unable to list authors'}
|
||||
|
||||
[Click here to be redirected to the brew's share page.](/share/${props.brew.shareId})`,
|
||||
|
||||
// User is not signed in; must be a user on the Authors List
|
||||
'04' : dedent`
|
||||
|
||||
4
faq.md
4
faq.md
@@ -102,7 +102,7 @@ The best way to avoid this is to leave space at the end of a column equal to one
|
||||
|
||||
### Why do I need to manually create a new page? Why doesn't text flow between pages?
|
||||
|
||||
A Homebrewery document is at it's core an HTML & CSS document, and currently limited by the specs of those technologies. It is currently not possible to flow content from inside one box ("page") to the inside of another box. It seems likely that someday CSS will add this capability, and if/when that happens, Homebrewery will adopt it as soon as possible.
|
||||
A Homebrewery document is at its core an HTML & CSS document, and currently limited by the specs of those technologies. It is currently not possible to flow content from inside one box ("page") to the inside of another box. It seems likely that someday CSS will add this capability, and if/when that happens, Homebrewery will adopt it as soon as possible.
|
||||
|
||||
### Where do I get images?
|
||||
The Homebrewery does not provide images for use besides some page elements and example images for snippets. You will need to find your own images for use and be sure you are following the appropriate license requirements.
|
||||
@@ -126,4 +126,4 @@ The Homebrewery defaults to creating US Letter page sizes. If you are printing
|
||||
|
||||
### Typing `#### Adhesion` in the text editor doesn't show the header at all in the completed page?
|
||||
|
||||
Your ad-blocking software is mistakenly assuming your text to be an ad. Whitelist homebrewery.naturalcrit.com in your ad-blocking software.
|
||||
Your ad-blocking software is mistakenly assuming your text to be an ad. Whitelist homebrewery.naturalcrit.com in your ad-blocking software.
|
||||
|
||||
1047
package-lock.json
generated
1047
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
28
package.json
28
package.json
@@ -4,7 +4,7 @@
|
||||
"version": "3.10.0",
|
||||
"engines": {
|
||||
"npm": "^10.2.x",
|
||||
"node": ">=20.8.x"
|
||||
"node": "^20.8.x"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -79,10 +79,10 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.23.2",
|
||||
"@babel/plugin-transform-runtime": "^7.23.2",
|
||||
"@babel/preset-env": "^7.23.2",
|
||||
"@babel/preset-react": "^7.22.15",
|
||||
"@babel/core": "^7.23.5",
|
||||
"@babel/plugin-transform-runtime": "^7.23.4",
|
||||
"@babel/preset-env": "^7.23.5",
|
||||
"@babel/preset-react": "^7.23.3",
|
||||
"@googleapis/drive": "^8.4.0",
|
||||
"body-parser": "^1.20.2",
|
||||
"classnames": "^2.3.2",
|
||||
@@ -93,37 +93,37 @@
|
||||
"express": "^4.18.2",
|
||||
"express-async-handler": "^1.2.0",
|
||||
"express-static-gzip": "2.1.7",
|
||||
"fs-extra": "11.1.1",
|
||||
"fs-extra": "11.2.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"jwt-simple": "^0.5.6",
|
||||
"less": "^3.13.1",
|
||||
"lodash": "^4.17.21",
|
||||
"marked": "5.1.1",
|
||||
"marked-extended-tables": "^1.0.7",
|
||||
"marked-gfm-heading-id": "^3.1.0",
|
||||
"marked-gfm-heading-id": "^3.1.2",
|
||||
"marked-smartypants-lite": "^1.0.1",
|
||||
"markedLegacy": "npm:marked@^0.3.19",
|
||||
"moment": "^2.29.4",
|
||||
"mongoose": "^7.6.1",
|
||||
"mongoose": "^8.0.2",
|
||||
"nanoid": "3.3.4",
|
||||
"nconf": "^0.12.0",
|
||||
"nconf": "^0.12.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-frame-component": "^4.1.3",
|
||||
"react-router-dom": "6.16.0",
|
||||
"react-router-dom": "6.20.1",
|
||||
"sanitize-filename": "1.6.3",
|
||||
"superagent": "^8.1.2",
|
||||
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^8.51.0",
|
||||
"eslint-plugin-jest": "^27.4.2",
|
||||
"eslint": "^8.55.0",
|
||||
"eslint-plugin-jest": "^27.6.0",
|
||||
"eslint-plugin-react": "^7.33.2",
|
||||
"jest": "^29.7.0",
|
||||
"jest-expect-message": "^1.1.3",
|
||||
"postcss-less": "^6.0.0",
|
||||
"stylelint": "^15.10.3",
|
||||
"stylelint-config-recess-order": "^4.3.0",
|
||||
"stylelint": "^15.11.0",
|
||||
"stylelint-config-recess-order": "^4.4.0",
|
||||
"stylelint-config-recommended": "^13.0.0",
|
||||
"stylelint-stylistic": "^0.4.3",
|
||||
"supertest": "^6.3.3"
|
||||
|
||||
@@ -101,7 +101,10 @@ fs.emptyDirSync('./build');
|
||||
|
||||
//v==---------------------------MOVE CM EDITOR THEMES -----------------------------==v//
|
||||
|
||||
editorThemeFiles = fs.readdirSync('./node_modules/codemirror/theme');
|
||||
const editorThemesBuildDir = './build/homebrew/cm-themes';
|
||||
await fs.copy('./node_modules/codemirror/theme', editorThemesBuildDir);
|
||||
await fs.copy('./themes/codeMirror/customThemes', editorThemesBuildDir);
|
||||
editorThemeFiles = fs.readdirSync(editorThemesBuildDir);
|
||||
|
||||
const editorThemeFile = './themes/codeMirror/editorThemes.json';
|
||||
if(fs.existsSync(editorThemeFile)) fs.rmSync(editorThemeFile);
|
||||
@@ -114,7 +117,7 @@ fs.emptyDirSync('./build');
|
||||
stream.write('\n]\n');
|
||||
stream.end();
|
||||
|
||||
await fs.copy('./node_modules/codemirror/theme', './build/homebrew/cm-themes');
|
||||
|
||||
await fs.copy('./themes/codeMirror', './build/homebrew/codeMirror');
|
||||
|
||||
//v==----------------------------- BUNDLE PACKAGES --------------------------------==v//
|
||||
@@ -151,14 +154,14 @@ fs.emptyDirSync('./build');
|
||||
// build(bundles);
|
||||
//
|
||||
|
||||
})().catch(console.error);
|
||||
//In development, set up LiveReload (refreshes browser), and Nodemon (restarts server)
|
||||
if(isDev){
|
||||
livereload('./build'); // Install the Chrome extension LiveReload to automatically refresh the browser
|
||||
watchFile('./server.js', { // Restart server when change detected to this file or any nested directory from here
|
||||
ignore : ['./build', './client', './themes'], // Ignore folders that are not running server code / avoids unneeded restarts
|
||||
ext : 'js json' // Extensions to watch (only .js/.json by default)
|
||||
//watch : ['./server', './themes'], // Watch additional folders if needed
|
||||
});
|
||||
}
|
||||
|
||||
//In development, set up LiveReload (refreshes browser), and Nodemon (restarts server)
|
||||
if(isDev){
|
||||
livereload('./build'); // Install the Chrome extension LiveReload to automatically refresh the browser
|
||||
watchFile('./server.js', { // Restart server when change detected to this file or any nested directory from here
|
||||
ignore : ['./build', './client', './themes'], // Ignore folders that are not running server code / avoids unneeded restarts
|
||||
ext : 'js json' // Extensions to watch (only .js/.json by default)
|
||||
//watch : ['./server', './themes'], // Watch additional folders if needed
|
||||
});
|
||||
}
|
||||
})().catch(console.error);
|
||||
@@ -79,7 +79,7 @@ const api = {
|
||||
if(accessType === 'edit' && (authorsExist && !(isAuthor || isInvited))) {
|
||||
const accessError = { name: 'Access Error', status: 401 };
|
||||
if(req.account){
|
||||
throw { ...accessError, message: 'User is not an Author', HBErrorCode: '03', authors: stub.authors, brewTitle: stub.title };
|
||||
throw { ...accessError, message: 'User is not an Author', HBErrorCode: '03', authors: stub.authors, brewTitle: stub.title, shareId: stub.shareId };
|
||||
}
|
||||
throw { ...accessError, message: 'User is not logged in', HBErrorCode: '04', authors: stub.authors, brewTitle: stub.title };
|
||||
}
|
||||
|
||||
@@ -112,6 +112,10 @@ const CodeEditor = createClass({
|
||||
'Shift-Tab' : this.dedent,
|
||||
'Ctrl-B' : this.makeBold,
|
||||
'Cmd-B' : this.makeBold,
|
||||
'Shift-Ctrl-=' : this.makeSuper,
|
||||
'Shift-Cmd-=' : this.makeSuper,
|
||||
'Ctrl-=' : this.makeSub,
|
||||
'Cmd-=' : this.makeSub,
|
||||
'Ctrl-I' : this.makeItalic,
|
||||
'Cmd-I' : this.makeItalic,
|
||||
'Ctrl-U' : this.makeUnderline,
|
||||
@@ -219,6 +223,25 @@ const CodeEditor = createClass({
|
||||
}
|
||||
},
|
||||
|
||||
makeSuper : function() {
|
||||
const selection = this.codeMirror.getSelection(), t = selection.slice(0, 1) === '^' && selection.slice(-1) === '^';
|
||||
this.codeMirror.replaceSelection(t ? selection.slice(1, -1) : `^${selection}^`, 'around');
|
||||
if(selection.length === 0){
|
||||
const cursor = this.codeMirror.getCursor();
|
||||
this.codeMirror.setCursor({ line: cursor.line, ch: cursor.ch - 1 });
|
||||
}
|
||||
},
|
||||
|
||||
makeSub : function() {
|
||||
const selection = this.codeMirror.getSelection(), t = selection.slice(0, 2) === '^^' && selection.slice(-2) === '^^';
|
||||
this.codeMirror.replaceSelection(t ? selection.slice(2, -2) : `^^${selection}^^`, 'around');
|
||||
if(selection.length === 0){
|
||||
const cursor = this.codeMirror.getCursor();
|
||||
this.codeMirror.setCursor({ line: cursor.line, ch: cursor.ch - 2 });
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
makeNbsp : function() {
|
||||
this.codeMirror.replaceSelection(' ', 'end');
|
||||
},
|
||||
|
||||
@@ -206,6 +206,34 @@ const mustacheInjectBlock = {
|
||||
}
|
||||
};
|
||||
|
||||
const superSubScripts = {
|
||||
name : 'superSubScript',
|
||||
level : 'inline',
|
||||
start(src) { return src.match(/\^/m)?.index; }, // Hint to Marked.js to stop and check for a match
|
||||
tokenizer(src, tokens) {
|
||||
const superRegex = /^\^(?!\s)(?=([^\n\^]*[^\s\^]))\1\^/m;
|
||||
const subRegex = /^\^\^(?!\s)(?=([^\n\^]*[^\s\^]))\1\^\^/m;
|
||||
let isSuper = false;
|
||||
let match = subRegex.exec(src);
|
||||
if(!match){
|
||||
match = superRegex.exec(src);
|
||||
if(match)
|
||||
isSuper = true;
|
||||
}
|
||||
if(match?.length) {
|
||||
return {
|
||||
type : 'superSubScript', // Should match "name" above
|
||||
raw : match[0], // Text to consume from the source
|
||||
tag : isSuper ? 'sup' : 'sub',
|
||||
tokens : this.lexer.inlineTokens(match[1])
|
||||
};
|
||||
}
|
||||
},
|
||||
renderer(token) {
|
||||
return `<${token.tag}>${this.parser.parseInline(token.tokens)}</${token.tag}>`;
|
||||
}
|
||||
};
|
||||
|
||||
const definitionLists = {
|
||||
name : 'definitionLists',
|
||||
level : 'block',
|
||||
@@ -238,7 +266,7 @@ const definitionLists = {
|
||||
}
|
||||
};
|
||||
|
||||
Marked.use({ extensions: [mustacheSpans, mustacheDivs, mustacheInjectInline, definitionLists] });
|
||||
Marked.use({ extensions: [mustacheSpans, mustacheDivs, mustacheInjectInline, definitionLists, superSubScripts] });
|
||||
Marked.use(mustacheInjectBlock);
|
||||
Marked.use({ renderer: renderer, mangle: false });
|
||||
Marked.use(MarkedExtendedTables(), MarkedGFMHeadingId(), MarkedSmartypantsLite());
|
||||
|
||||
@@ -40,7 +40,7 @@ body {
|
||||
-webkit-column-gap : 1cm;
|
||||
-moz-column-gap : 1cm;
|
||||
}
|
||||
.phb{
|
||||
.phb, .page{
|
||||
.useColumns();
|
||||
counter-increment : phb-page-numbers;
|
||||
position : relative;
|
||||
@@ -59,6 +59,9 @@ body {
|
||||
page-break-before : always;
|
||||
page-break-after : always;
|
||||
contain : size;
|
||||
}
|
||||
|
||||
.phb{
|
||||
//*****************************
|
||||
// * BASE
|
||||
// *****************************/
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
body { counter-reset : phb-page-numbers; }
|
||||
* { -webkit-print-color-adjust : exact; }
|
||||
.useSansSerif() {
|
||||
font-family : "ScalySansRemake";
|
||||
font-family : 'ScalySansRemake';
|
||||
font-size : 0.318cm;
|
||||
line-height : 1.2em;
|
||||
p,dl,ul,ol { line-height : 1.2em; }
|
||||
@@ -57,14 +57,12 @@ body { counter-reset : phb-page-numbers; }
|
||||
height : 279.4mm;
|
||||
padding : 1.4cm 1.9cm 1.7cm;
|
||||
overflow : hidden;
|
||||
font-family : "BookInsanityRemake";
|
||||
font-family : 'BookInsanityRemake';
|
||||
font-size : 0.34cm;
|
||||
counter-increment : phb-page-numbers;
|
||||
background-color : var(--HB_Color_Background);
|
||||
background-image : @backgroundImage;
|
||||
text-rendering : optimizeLegibility;
|
||||
page-break-before : always;
|
||||
page-break-after : always;
|
||||
}
|
||||
//*****************************
|
||||
// * BASE
|
||||
@@ -114,7 +112,7 @@ body { counter-reset : phb-page-numbers; }
|
||||
// * HEADERS
|
||||
// *****************************/
|
||||
h1,h2,h3,h4 {
|
||||
font-family : "MrEavesRemake";
|
||||
font-family : 'MrEavesRemake';
|
||||
font-weight : 800;
|
||||
color : var(--HB_Color_HeaderText);
|
||||
}
|
||||
@@ -132,7 +130,7 @@ body { counter-reset : phb-page-numbers; }
|
||||
margin-top : -0.3cm;
|
||||
margin-bottom : -20px;
|
||||
margin-left : -40px;
|
||||
font-family : "SolberaImitationRemake";
|
||||
font-family : 'SolberaImitationRemake';
|
||||
font-size : 3.5cm;
|
||||
line-height : 1em;
|
||||
color : rgba(0, 0, 0, 0);
|
||||
@@ -172,7 +170,7 @@ body { counter-reset : phb-page-numbers; }
|
||||
h5 {
|
||||
//margin-top : -0.02cm; //Font is misaligned. Shift up slightly
|
||||
//margin-bottom : 0.02cm;
|
||||
font-family : "ScalySansSmallCapsRemake";
|
||||
font-family : 'ScalySansSmallCapsRemake';
|
||||
font-size : 0.423cm;
|
||||
font-weight : 900;
|
||||
line-height : 0.951em; //Font is misaligned. Shift up slightly
|
||||
@@ -299,7 +297,7 @@ body { counter-reset : phb-page-numbers; }
|
||||
.artist {
|
||||
position : absolute;
|
||||
width : auto;
|
||||
font-family : "WalterTurncoat";
|
||||
font-family : 'WalterTurncoat';
|
||||
font-size : 0.27cm;
|
||||
color : var(--HB_Color_CaptionText);
|
||||
text-align : center;
|
||||
@@ -309,7 +307,7 @@ body { counter-reset : phb-page-numbers; }
|
||||
text-indent : unset;
|
||||
}
|
||||
h5 {
|
||||
font-family : "WalterTurncoat";
|
||||
font-family : 'WalterTurncoat';
|
||||
font-size : 1.3em;
|
||||
}
|
||||
a {
|
||||
@@ -405,12 +403,9 @@ body { counter-reset : phb-page-numbers; }
|
||||
}
|
||||
}
|
||||
h3 {
|
||||
// margin-top : 0.05cm; //Font is misaligned. Shift up slightly
|
||||
padding-bottom : 0.05cm;
|
||||
font-family : "ScalySansRemake";
|
||||
font-weight : 800;
|
||||
font-variant : small-caps;
|
||||
border-bottom : 2px solid var(--HB_Color_HeaderText);
|
||||
font-family : 'ScalySansSmallCapsRemake';
|
||||
font-size : 0.45cm;
|
||||
border-bottom : 1.5px solid var(--HB_Color_HeaderText);
|
||||
}
|
||||
|
||||
//Triangle dividers
|
||||
@@ -446,6 +441,8 @@ body { counter-reset : phb-page-numbers; }
|
||||
tr { background-color : transparent; }
|
||||
td,th { padding : 0px; }
|
||||
}
|
||||
//indent fix after bulleted lists
|
||||
:is(ul,ol) + p { text-indent : 0; }
|
||||
|
||||
:last-child { margin-bottom : 0; }
|
||||
}
|
||||
@@ -503,7 +500,7 @@ body { counter-reset : phb-page-numbers; }
|
||||
// ************************************/
|
||||
code {
|
||||
padding : 0px 4px;
|
||||
font-family : 'Courier New', "Courier", monospace;
|
||||
font-family : 'Courier New', 'Courier', monospace;
|
||||
font-size : 0.325;
|
||||
color : #58180D;
|
||||
overflow-wrap : break-word;
|
||||
@@ -641,7 +638,7 @@ body { counter-reset : phb-page-numbers; }
|
||||
h1 {
|
||||
margin-top : 1.2cm;
|
||||
margin-bottom : 0;
|
||||
font-family : "NodestoCapsCondensed";
|
||||
font-family : 'NodestoCapsCondensed';
|
||||
font-size : 2.245cm;
|
||||
font-weight : normal;
|
||||
line-height : 0.85em;
|
||||
@@ -654,7 +651,7 @@ body { counter-reset : phb-page-numbers; }
|
||||
drop-shadow(0 0 0 black) drop-shadow(0 0 0 black);
|
||||
}
|
||||
h2 {
|
||||
font-family : "NodestoCapsCondensed";
|
||||
font-family : 'NodestoCapsCondensed';
|
||||
font-size : 0.85cm;
|
||||
font-weight : normal;
|
||||
color : white;
|
||||
@@ -687,7 +684,7 @@ body { counter-reset : phb-page-numbers; }
|
||||
height : 1.7cm;
|
||||
padding-top : 0.1cm;
|
||||
padding-left : 1cm;
|
||||
font-family : "NodestoCapsCondensed";
|
||||
font-family : 'NodestoCapsCondensed';
|
||||
font-size : 1cm;
|
||||
font-weight : normal;
|
||||
color : white;
|
||||
@@ -704,7 +701,7 @@ body { counter-reset : phb-page-numbers; }
|
||||
width : 70%;
|
||||
margin-right : auto;
|
||||
margin-left : auto;
|
||||
font-family : "Overpass";
|
||||
font-family : 'Overpass';
|
||||
font-size : 0.496cm;
|
||||
color : white;
|
||||
text-align : center;
|
||||
@@ -735,14 +732,14 @@ body { counter-reset : phb-page-numbers; }
|
||||
h1 {
|
||||
margin-top : 1.2cm;
|
||||
margin-bottom : 0;
|
||||
font-family : "NodestoCapsCondensed";
|
||||
font-family : 'NodestoCapsCondensed';
|
||||
font-size : 2.1cm;
|
||||
font-weight : normal;
|
||||
line-height : 0.85em;
|
||||
text-transform : uppercase;
|
||||
}
|
||||
h2 {
|
||||
font-family : "NodestoCapsCondensed";
|
||||
font-family : 'NodestoCapsCondensed';
|
||||
font-size : 0.85cm;
|
||||
font-weight : normal;
|
||||
letter-spacing : 0.5cm;
|
||||
@@ -791,7 +788,7 @@ body { counter-reset : phb-page-numbers; }
|
||||
.blank { height : 1.4em; }
|
||||
h1 {
|
||||
margin-bottom : 0.3cm;
|
||||
font-family : "NodestoCapsCondensed";
|
||||
font-family : 'NodestoCapsCondensed';
|
||||
font-size : 1.35cm;
|
||||
line-height : 0.95em;
|
||||
color : #ED1C24;
|
||||
@@ -817,7 +814,7 @@ body { counter-reset : phb-page-numbers; }
|
||||
border : none;
|
||||
}
|
||||
p {
|
||||
font-family : "Overpass";
|
||||
font-family : 'Overpass';
|
||||
font-size : 0.332cm;
|
||||
line-height : 1.5em;
|
||||
}
|
||||
@@ -841,7 +838,7 @@ body { counter-reset : phb-page-numbers; }
|
||||
p {
|
||||
position : relative;
|
||||
width : 100%;
|
||||
font-family : "NodestoCapsWide";
|
||||
font-family : 'NodestoCapsWide';
|
||||
font-size : 0.4cm;
|
||||
line-height : 1em;
|
||||
color : #FFFFFF;
|
||||
@@ -874,7 +871,7 @@ body { counter-reset : phb-page-numbers; }
|
||||
h1 {
|
||||
position : relative;
|
||||
margin-top : 0.4cm;
|
||||
font-family : "NodestoCapsCondensed";
|
||||
font-family : 'NodestoCapsCondensed';
|
||||
font-size : 2.3cm;
|
||||
text-align : center;
|
||||
text-transform : uppercase;
|
||||
@@ -885,7 +882,7 @@ body { counter-reset : phb-page-numbers; }
|
||||
margin-top : -0.7em;
|
||||
margin-right : auto;
|
||||
margin-left : auto;
|
||||
font-family : "Overpass";
|
||||
font-family : 'Overpass';
|
||||
font-size : 0.45cm;
|
||||
line-height : 1.1em;
|
||||
}
|
||||
@@ -968,9 +965,8 @@ body { counter-reset : phb-page-numbers; }
|
||||
padding-left : 1em;
|
||||
line-height : 1.25em;
|
||||
white-space : pre-line;
|
||||
& + * { margin-top : 0.28cm; }
|
||||
& + * { margin-top : 0.17cm; }
|
||||
}
|
||||
dl + * { margin-top : 0.17cm; }
|
||||
p + dl { margin-top : 0.17cm; }
|
||||
dt {
|
||||
display : inline;
|
||||
@@ -1009,7 +1005,7 @@ body { counter-reset : phb-page-numbers; }
|
||||
outline : 1px solid #000000;
|
||||
}
|
||||
th {
|
||||
font-family : "BookInsanityRemake";
|
||||
font-family : 'BookInsanityRemake';
|
||||
font-size : 0.45cm;
|
||||
}
|
||||
td { font-size : 0.7cm; }
|
||||
|
||||
@@ -56,8 +56,6 @@ body {
|
||||
box-sizing : border-box;
|
||||
overflow : hidden;
|
||||
text-rendering : optimizeLegibility;
|
||||
page-break-before : always;
|
||||
page-break-after : always;
|
||||
contain : size;
|
||||
}
|
||||
//*****************************
|
||||
|
||||
129
themes/codeMirror/customThemes/darkbrewery-v301.css
Normal file
129
themes/codeMirror/customThemes/darkbrewery-v301.css
Normal file
@@ -0,0 +1,129 @@
|
||||
/* Main BG color and normal text color */
|
||||
.CodeMirror {
|
||||
background: #293134;
|
||||
color: #91A6AA;
|
||||
}
|
||||
|
||||
/* Brew BG */
|
||||
.brewRenderer {
|
||||
background-color: #293134;
|
||||
}
|
||||
/* Blinking cursor */
|
||||
.CodeMirror-cursor {
|
||||
border-left: 1px solid #e0e2e4;
|
||||
}
|
||||
|
||||
/* HB DARK NAV START*/
|
||||
|
||||
/* Bars at the top */
|
||||
.snippetBar {
|
||||
background-color: #2F393C;
|
||||
color: white;
|
||||
}
|
||||
nav {
|
||||
background-color: #293134;
|
||||
}
|
||||
nav .navItem {
|
||||
background-color: #293134;
|
||||
}
|
||||
/* Fix for Homebrewery custom Snippet icons */
|
||||
.snippetBar .fac {
|
||||
filter: invert(1);
|
||||
}
|
||||
.snippetBar .snippetGroup .dropdown {
|
||||
background-color: #2F393C;
|
||||
}
|
||||
/* HB DARK NAV END */
|
||||
|
||||
/* Line number stuff */
|
||||
.CodeMirror-gutter-elt {
|
||||
color: #81969A;
|
||||
}
|
||||
.CodeMirror-linenumber {
|
||||
background-color: #293134;
|
||||
}
|
||||
.CodeMirror-gutter {
|
||||
background-color: #293134;
|
||||
}
|
||||
/* column splits */
|
||||
.editor .codeEditor .columnSplit {
|
||||
font-style: italic;
|
||||
color: inherit;
|
||||
background-color:#1f5763;
|
||||
border-bottom: #299 solid 1px;
|
||||
}
|
||||
|
||||
/* Colors for headings and such */
|
||||
/* ###Headings */
|
||||
.cm-s-default .cm-header {
|
||||
color: #c51b1b;
|
||||
-webkit-text-stroke-width: 0.1px;
|
||||
-webkit-text-stroke-color: #000;
|
||||
}
|
||||
/* bold points */
|
||||
.cm-header, .cm-strong {
|
||||
font-weight: bold;
|
||||
color: #309dd2;
|
||||
}
|
||||
/* Link headings */
|
||||
.cm-s-default .cm-link {
|
||||
color: #dd6300;
|
||||
}
|
||||
/* links */
|
||||
.cm-s-default .cm-string {
|
||||
color: #aa8261;
|
||||
}
|
||||
/*@import*/
|
||||
.cm-s-default .cm-def {
|
||||
color:#2986cc;
|
||||
}
|
||||
/* Bullets and such */
|
||||
.cm-s-default .cm-variable-2 {
|
||||
color: #3cbf30;
|
||||
}
|
||||
/* blocks */
|
||||
.editor .codeEditor .block:not(.cm-comment) {
|
||||
color: #e3e3e3;
|
||||
}
|
||||
/* inline blocks */
|
||||
.editor .codeEditor .inline-block {
|
||||
color: #e3e3e3;
|
||||
}
|
||||
/* Tags (divs) */
|
||||
.cm-s-default .cm-tag {
|
||||
color: #e3ff00;
|
||||
}
|
||||
.cm-s-default .cm-attribute {
|
||||
color: #e3ff00;
|
||||
}
|
||||
.cm-s-default .cm-atom {
|
||||
color:#000;
|
||||
}
|
||||
.cm-s-default .cm-qualifier{
|
||||
color:#ee1919;
|
||||
}
|
||||
.cm-s-default .cm-comment{
|
||||
color:#bbc700;
|
||||
}
|
||||
.cm-s-default .cm-keyword {
|
||||
color:#c302df;
|
||||
background-color:#b1b1b1;
|
||||
}
|
||||
.cm-s-default .cm-property.cm-error {
|
||||
color:#c50202;
|
||||
}
|
||||
|
||||
.CodeMirror-foldmarker {
|
||||
color:#f0ff00;
|
||||
}
|
||||
|
||||
/* New page */
|
||||
.editor .codeEditor .pageLine {
|
||||
background: #000;
|
||||
color:#000;
|
||||
border-bottom: 1px solid #fff;
|
||||
}
|
||||
|
||||
.cm-s-default .cm-builtin {
|
||||
color:#fff;
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
"cobalt",
|
||||
"colorforth",
|
||||
"darcula",
|
||||
"darkbrewery-v301",
|
||||
"dracula",
|
||||
"duotone-dark",
|
||||
"duotone-light",
|
||||
|
||||
Reference in New Issue
Block a user