mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-01-27 22:33:07 +00:00
Compare commits
138 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa945c4177 | ||
|
|
cbc6dcdc35 | ||
|
|
5894dc5a7a | ||
|
|
284bfe565b | ||
|
|
075c8805e0 | ||
|
|
5c4187cd06 | ||
|
|
1719cc68fa | ||
|
|
3ba67fb3d0 | ||
|
|
f58d52c4b6 | ||
|
|
e1ad6f8114 | ||
|
|
22257a95e0 | ||
|
|
713c978f08 | ||
|
|
3eb0c7acfe | ||
|
|
c3e6c01ec1 | ||
|
|
5bb5cdec05 | ||
|
|
f8e68c1485 | ||
|
|
60ccd08bce | ||
|
|
f241024167 | ||
|
|
f1fd75574d | ||
|
|
31352e417f | ||
|
|
643af98ca3 | ||
|
|
3b61cd355f | ||
|
|
8df19e3b8f | ||
|
|
91d6548822 | ||
|
|
ef797b2a69 | ||
|
|
33a62a0ac7 | ||
|
|
5a9025f555 | ||
|
|
0a494633bb | ||
|
|
aeaea5b5e0 | ||
|
|
e03ec34104 | ||
|
|
c65ee59998 | ||
|
|
4d59a14f74 | ||
|
|
3c8aaa7465 | ||
|
|
ac70403203 | ||
|
|
a5e7ad882d | ||
|
|
061925e89a | ||
|
|
5fc8b508d1 | ||
|
|
cb444bef9d | ||
|
|
481f2e7d39 | ||
|
|
7559652a32 | ||
|
|
8e15466063 | ||
|
|
8ef319d2cd | ||
|
|
1513a983f7 | ||
|
|
1b71bbaefb | ||
|
|
fcd5279381 | ||
|
|
4276d38152 | ||
|
|
d6bf2dec7e | ||
|
|
423a4a521a | ||
|
|
05d4d5b1ff | ||
|
|
ad1e8d50d7 | ||
|
|
c926f0de79 | ||
|
|
4337c67f69 | ||
|
|
bb06a3e4d4 | ||
|
|
6af9c9e432 | ||
|
|
84d0d15c5a | ||
|
|
b185fe8e35 | ||
|
|
adbb9e54c1 | ||
|
|
1d3c2d7cd6 | ||
|
|
2dc397e9f1 | ||
|
|
6465564b6f | ||
|
|
e1fe640e92 | ||
|
|
6f99fe7455 | ||
|
|
342963dae6 | ||
|
|
957b1ed9e7 | ||
|
|
423ed28fbd | ||
|
|
a4f17259e1 | ||
|
|
c2678e5f2c | ||
|
|
d797333b97 | ||
|
|
40777a3794 | ||
|
|
ac1005c2b0 | ||
|
|
c77395149b | ||
|
|
fb0580fff1 | ||
|
|
0e953d08b2 | ||
|
|
7fce362a52 | ||
|
|
3e7844ba6d | ||
|
|
7619f8f420 | ||
|
|
bac52f8376 | ||
|
|
5c72cd9d47 | ||
|
|
89b59a52bc | ||
|
|
a6f2a1a4c8 | ||
|
|
e9e9fbe21c | ||
|
|
e7108947d6 | ||
|
|
8b68f24135 | ||
|
|
e32ae9a792 | ||
|
|
758a951bf5 | ||
|
|
21ac50cd27 | ||
|
|
fc67a40167 | ||
|
|
7949df1865 | ||
|
|
8ed013cbb2 | ||
|
|
0138c27863 | ||
|
|
7930c209ff | ||
|
|
26fdc1ba91 | ||
|
|
8681994747 | ||
|
|
0e684b14a7 | ||
|
|
974f84d49f | ||
|
|
5a6abef4fb | ||
|
|
15200e0c6e | ||
|
|
79c22f383f | ||
|
|
915f9aafa8 | ||
|
|
11f8809c5e | ||
|
|
27a4831ea0 | ||
|
|
1abced20d6 | ||
|
|
251d03b7be | ||
|
|
29bbf3fef9 | ||
|
|
fac0d151b6 | ||
|
|
4f950b6024 | ||
|
|
1c1d331df9 | ||
|
|
d640ad6bb7 | ||
|
|
2af2ad629d | ||
|
|
2fc7aa454f | ||
|
|
fde797c044 | ||
|
|
6693fb1c13 | ||
|
|
17f8de48a8 | ||
|
|
aebfcc7885 | ||
|
|
2c4f3473e5 | ||
|
|
9a4cc5f63e | ||
|
|
c82b62f953 | ||
|
|
f830104531 | ||
|
|
fed65f5430 | ||
|
|
c209a86f90 | ||
|
|
0cf79ceeb1 | ||
|
|
7b9bd70554 | ||
|
|
a413dc8d4f | ||
|
|
74ee09397e | ||
|
|
a06aa2a103 | ||
|
|
853f048812 | ||
|
|
4564066c63 | ||
|
|
435fb6ecfe | ||
|
|
8a10fac81e | ||
|
|
7f1949a7f4 | ||
|
|
47b56398b1 | ||
|
|
2ea2f41bd0 | ||
|
|
65d6eb11dd | ||
|
|
a591763d10 | ||
|
|
62bf982a73 | ||
|
|
6294b12ad5 | ||
|
|
b7f88d53d0 | ||
|
|
cb8d98266c |
@@ -3,7 +3,7 @@
|
|||||||
"stylelint-config-recess-order",
|
"stylelint-config-recess-order",
|
||||||
"stylelint-config-recommended"],
|
"stylelint-config-recommended"],
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"stylelint-stylistic",
|
"@stylistic/stylelint-plugin",
|
||||||
"./stylelint_plugins/declaration-colon-align.js",
|
"./stylelint_plugins/declaration-colon-align.js",
|
||||||
"./stylelint_plugins/declaration-colon-min-space-before",
|
"./stylelint_plugins/declaration-colon-min-space-before",
|
||||||
"./stylelint_plugins/declaration-block-multi-line-min-declarations"
|
"./stylelint_plugins/declaration-block-multi-line-min-declarations"
|
||||||
@@ -16,32 +16,32 @@
|
|||||||
"font-family-no-missing-generic-family-keyword" : null,
|
"font-family-no-missing-generic-family-keyword" : null,
|
||||||
"font-weight-notation" : "named-where-possible",
|
"font-weight-notation" : "named-where-possible",
|
||||||
"font-family-name-quotes" : "always-unless-keyword",
|
"font-family-name-quotes" : "always-unless-keyword",
|
||||||
"stylistic/indentation" : "tab",
|
"@stylistic/indentation" : "tab",
|
||||||
"no-duplicate-selectors" : true,
|
"no-duplicate-selectors" : true,
|
||||||
"stylistic/color-hex-case" : "upper",
|
"@stylistic/color-hex-case" : "upper",
|
||||||
"color-hex-length" : "long",
|
"color-hex-length" : "long",
|
||||||
"stylistic/selector-combinator-space-after" : "always",
|
"@stylistic/selector-combinator-space-after" : "always",
|
||||||
"stylistic/selector-combinator-space-before" : "always",
|
"@stylistic/selector-combinator-space-before" : "always",
|
||||||
"stylistic/selector-attribute-operator-space-before" : "never",
|
"@stylistic/selector-attribute-operator-space-before" : "never",
|
||||||
"stylistic/selector-attribute-operator-space-after" : "never",
|
"@stylistic/selector-attribute-operator-space-after" : "never",
|
||||||
"stylistic/selector-attribute-brackets-space-inside" : "never",
|
"@stylistic/selector-attribute-brackets-space-inside" : "never",
|
||||||
"selector-attribute-quotes" : "always",
|
"selector-attribute-quotes" : "always",
|
||||||
"selector-pseudo-element-colon-notation" : "double",
|
"selector-pseudo-element-colon-notation" : "double",
|
||||||
"stylistic/selector-pseudo-class-parentheses-space-inside" : "never",
|
"@stylistic/selector-pseudo-class-parentheses-space-inside" : "never",
|
||||||
"stylistic/block-opening-brace-space-before" : "always",
|
"@stylistic/block-opening-brace-space-before" : "always",
|
||||||
"naturalcrit/declaration-colon-min-space-before" : 1,
|
"naturalcrit/declaration-colon-min-space-before" : 1,
|
||||||
"stylistic/declaration-block-trailing-semicolon" : "always",
|
"@stylistic/declaration-block-trailing-semicolon" : "always",
|
||||||
"stylistic/declaration-colon-space-after" : "always",
|
"@stylistic/declaration-colon-space-after" : "always",
|
||||||
"stylistic/number-leading-zero" : "always",
|
"@stylistic/number-leading-zero" : "always",
|
||||||
"function-url-quotes" : ["always", { "except": ["empty"] }],
|
"function-url-quotes" : ["always", { "except": ["empty"] }],
|
||||||
"function-url-scheme-disallowed-list" : ["data","http"],
|
"function-url-scheme-disallowed-list" : ["data","http"],
|
||||||
"comment-whitespace-inside" : "always",
|
"comment-whitespace-inside" : "always",
|
||||||
"stylistic/string-quotes" : "single",
|
"@stylistic/string-quotes" : "single",
|
||||||
"stylistic/media-feature-range-operator-space-before" : "always",
|
"@stylistic/media-feature-range-operator-space-before" : "always",
|
||||||
"stylistic/media-feature-range-operator-space-after" : "always",
|
"@stylistic/media-feature-range-operator-space-after" : "always",
|
||||||
"stylistic/media-feature-parentheses-space-inside" : "never",
|
"@stylistic/media-feature-parentheses-space-inside" : "never",
|
||||||
"stylistic/media-feature-colon-space-before" : "always",
|
"@stylistic/media-feature-colon-space-before" : "always",
|
||||||
"stylistic/media-feature-colon-space-after" : "always",
|
"@stylistic/media-feature-colon-space-after" : "always",
|
||||||
"naturalcrit/declaration-colon-align" : true,
|
"naturalcrit/declaration-colon-align" : true,
|
||||||
"naturalcrit/declaration-block-multi-line-min-declarations": 1
|
"naturalcrit/declaration-block-multi-line-min-declarations": 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM node:18-alpine
|
FROM node:20-alpine
|
||||||
RUN apk --no-cache add git
|
RUN apk --no-cache add git
|
||||||
|
|
||||||
ENV NODE_ENV=docker
|
ENV NODE_ENV=docker
|
||||||
|
|||||||
59
changelog.md
59
changelog.md
@@ -84,6 +84,65 @@ pre {
|
|||||||
## changelog
|
## changelog
|
||||||
For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery).
|
For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery).
|
||||||
|
|
||||||
|
### Tuesday 8/13/2024 - v3.14.1
|
||||||
|
{{taskList
|
||||||
|
|
||||||
|
##### abquintic
|
||||||
|
|
||||||
|
* [x] Allow Table of Contents to flow across columns
|
||||||
|
|
||||||
|
Fixes issues [#2563](https://github.com/naturalcrit/homebrewery/issues/2563)
|
||||||
|
|
||||||
|
* [x] Fix unusual margin spacing for adjacent `.descriptive` and `.wide` blocks
|
||||||
|
|
||||||
|
Fixes issues [#2688](https://github.com/naturalcrit/homebrewery/issues/2688)
|
||||||
|
|
||||||
|
* [x] Add code folding to :fas_paintbrush: {{openSans **STYLE**}} tab
|
||||||
|
|
||||||
|
##### G-Ambatte
|
||||||
|
|
||||||
|
* [x] Fix edge case where Table of Contents generator changed capitalization of headings
|
||||||
|
|
||||||
|
Fixes issues [#3572](https://github.com/naturalcrit/homebrewery/issues/3572)
|
||||||
|
|
||||||
|
* [x] Fix **Ink Friendly** snippet causing unselectable PDF text
|
||||||
|
|
||||||
|
Fixes issues [#3563](https://github.com/naturalcrit/homebrewery/issues/3563)
|
||||||
|
|
||||||
|
* [x] Prevent brews selecting themselves as a theme
|
||||||
|
|
||||||
|
Fixes issues [#3614](https://github.com/naturalcrit/homebrewery/issues/3614)
|
||||||
|
|
||||||
|
* [x] Fix info pages (`/faq`, `/migrate`, etc.) showing blank authorship info
|
||||||
|
|
||||||
|
Fixes issues [#3568](https://github.com/naturalcrit/homebrewery/issues/3568)
|
||||||
|
|
||||||
|
* [x] Add `abs()`, `sign()` and `signed()` functions to variable syntax math handler
|
||||||
|
|
||||||
|
Fixes issues [#3537](https://github.com/naturalcrit/homebrewery/issues/3537)
|
||||||
|
|
||||||
|
* [x] Fix variable math handler not processing commas (i.e., in `$[max(varA,varB)]`
|
||||||
|
|
||||||
|
Fixes issues [#3613](https://github.com/naturalcrit/homebrewery/issues/3613)
|
||||||
|
|
||||||
|
* [x] Fix variable math handler scrambling variables with names that are subsets of other variables
|
||||||
|
|
||||||
|
Fixes issues [#3622](https://github.com/naturalcrit/homebrewery/issues/3622)
|
||||||
|
|
||||||
|
|
||||||
|
##### calculuschild
|
||||||
|
|
||||||
|
* [x] Fix `/migrate` page using an editor context instead of share context
|
||||||
|
|
||||||
|
|
||||||
|
##### 5e-Cleric
|
||||||
|
|
||||||
|
* [x] Fix Monster Stat Blocks losing color in Safari
|
||||||
|
|
||||||
|
}}
|
||||||
|
|
||||||
|
\page
|
||||||
|
|
||||||
### Monday 7/29/2024 - v3.14.0
|
### Monday 7/29/2024 - v3.14.0
|
||||||
{{taskList
|
{{taskList
|
||||||
|
|
||||||
|
|||||||
@@ -367,7 +367,7 @@ const Editor = createClass({
|
|||||||
view={this.state.view}
|
view={this.state.view}
|
||||||
value={this.props.brew.style ?? DEFAULT_STYLE_TEXT}
|
value={this.props.brew.style ?? DEFAULT_STYLE_TEXT}
|
||||||
onChange={this.props.onStyleChange}
|
onChange={this.props.onStyleChange}
|
||||||
enableFolding={false}
|
enableFolding={true}
|
||||||
editorTheme={this.state.editorTheme}
|
editorTheme={this.state.editorTheme}
|
||||||
rerenderParent={this.rerenderParent} />
|
rerenderParent={this.rerenderParent} />
|
||||||
</>;
|
</>;
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ const MetadataEditor = createClass({
|
|||||||
return {
|
return {
|
||||||
metadata : {
|
metadata : {
|
||||||
editId : null,
|
editId : null,
|
||||||
|
shareId : null,
|
||||||
title : '',
|
title : '',
|
||||||
description : '',
|
description : '',
|
||||||
thumbnail : '',
|
thumbnail : '',
|
||||||
@@ -196,6 +197,7 @@ const MetadataEditor = createClass({
|
|||||||
|
|
||||||
const listThemes = (renderer)=>{
|
const listThemes = (renderer)=>{
|
||||||
return _.map(_.values(mergedThemes[renderer]), (theme)=>{
|
return _.map(_.values(mergedThemes[renderer]), (theme)=>{
|
||||||
|
if(theme.path == this.props.metadata.shareId) return;
|
||||||
const preview = theme.thumbnail || `/themes/${theme.renderer}/${theme.path}/dropdownPreview.png`;
|
const preview = theme.thumbnail || `/themes/${theme.renderer}/${theme.path}/dropdownPreview.png`;
|
||||||
const texture = theme.thumbnail || `/themes/${theme.renderer}/${theme.path}/dropdownTexture.png`;
|
const texture = theme.thumbnail || `/themes/${theme.renderer}/${theme.path}/dropdownTexture.png`;
|
||||||
return <div className='item' key={`${renderer}_${theme.name}`} onClick={()=>this.handleTheme(theme)} title={''}>
|
return <div className='item' key={`${renderer}_${theme.name}`} onClick={()=>this.handleTheme(theme)} title={''}>
|
||||||
|
|||||||
@@ -1,258 +1,239 @@
|
|||||||
@import 'naturalcrit/styles/colors.less';
|
@import 'naturalcrit/styles/colors.less';
|
||||||
|
|
||||||
.metadataEditor{
|
.metadataEditor {
|
||||||
position : absolute;
|
position : absolute;
|
||||||
z-index : 5;
|
z-index : 5;
|
||||||
box-sizing : border-box;
|
box-sizing : border-box;
|
||||||
width : 100%;
|
width : 100%;
|
||||||
padding : 25px;
|
|
||||||
background-color : #999;
|
|
||||||
height : calc(100vh - 54px); // 54px is the height of the navbar + snippet bar. probably a better way to dynamic get this.
|
height : calc(100vh - 54px); // 54px is the height of the navbar + snippet bar. probably a better way to dynamic get this.
|
||||||
|
padding : 25px;
|
||||||
overflow-y : auto;
|
overflow-y : auto;
|
||||||
|
background-color : #999999;
|
||||||
|
|
||||||
.sectionHead {
|
.sectionHead {
|
||||||
font-weight: 1000;
|
margin : 20px 0;
|
||||||
margin: 20px 0;
|
font-weight : 1000;
|
||||||
|
|
||||||
&:first-of-type {
|
&:first-of-type { margin-top : 0; }
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
& > div {
|
& > div { margin-bottom : 10px; }
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.field-group {
|
.field-group {
|
||||||
display: flex;
|
display : flex;
|
||||||
width: 100%;
|
flex-wrap : wrap;
|
||||||
flex-wrap: wrap;
|
gap : 10px;
|
||||||
gap: 10px;
|
width : 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.field-column {
|
.field-column {
|
||||||
display: flex;
|
display : flex;
|
||||||
flex-direction: column;
|
flex : 5 0 200px;
|
||||||
flex: 5 0 200px;
|
flex-direction : column;
|
||||||
gap: 10px;
|
gap : 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.field{
|
.field {
|
||||||
|
position : relative;
|
||||||
display : flex;
|
display : flex;
|
||||||
flex-wrap : wrap;
|
flex-wrap : wrap;
|
||||||
width : 100%;
|
width : 100%;
|
||||||
min-width : 200px;
|
min-width : 200px;
|
||||||
position : relative;
|
& > label {
|
||||||
&>label{
|
|
||||||
width : 80px;
|
width : 80px;
|
||||||
font-size : 11px;
|
font-size : 11px;
|
||||||
font-weight : 800;
|
font-weight : 800;
|
||||||
line-height : 1.8em;
|
line-height : 1.8em;
|
||||||
text-transform : uppercase;
|
text-transform : uppercase;
|
||||||
}
|
}
|
||||||
&>.value{
|
& > .value {
|
||||||
flex : 1 1 auto;
|
flex : 1 1 auto;
|
||||||
width : 50px;
|
width : 50px;
|
||||||
&:invalid {
|
&:invalid { background : #FFB9B9; }
|
||||||
background : #ffb9b9;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
input[type='text'], textarea {
|
input[type='text'], textarea {
|
||||||
border : 1px solid gray;
|
border : 1px solid gray;
|
||||||
&:focus {
|
&:focus { outline : 1px solid #444444; }
|
||||||
outline: 1px solid #444;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
&.thumbnail{
|
&.thumbnail {
|
||||||
height : 1.4em;
|
height : 1.4em;
|
||||||
label{
|
label { line-height : 2.0em; }
|
||||||
line-height: 2.0em;
|
.value {
|
||||||
|
overflow : hidden;
|
||||||
|
text-overflow : ellipsis;
|
||||||
}
|
}
|
||||||
.value{
|
button {
|
||||||
overflow: hidden;
|
padding : 0px 5px;
|
||||||
text-overflow: ellipsis;
|
color : white;
|
||||||
}
|
background-color : black;
|
||||||
button{
|
border : 1px solid #999999;
|
||||||
border: 1px solid #999;
|
&:hover { background-color : #777777; }
|
||||||
color: white;
|
|
||||||
padding: 0px 5px;
|
|
||||||
background-color: black;
|
|
||||||
&:hover{
|
|
||||||
background-color: #777;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.description {
|
&.description {
|
||||||
flex: 1;
|
flex : 1;
|
||||||
textarea.value {
|
textarea.value {
|
||||||
resize : none;
|
|
||||||
height : auto;
|
height : auto;
|
||||||
font-family : 'Open Sans', sans-serif;
|
font-family : 'Open Sans', sans-serif;
|
||||||
font-size : 0.8em;
|
font-size : 0.8em;
|
||||||
|
resize : none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.language .language-dropdown {
|
&.language .language-dropdown {
|
||||||
max-width : 150px;
|
|
||||||
z-index : 200;
|
z-index : 200;
|
||||||
|
max-width : 150px;
|
||||||
}
|
}
|
||||||
small {
|
small {
|
||||||
|
display : inline-block;
|
||||||
font-size : 0.6em;
|
font-size : 0.6em;
|
||||||
font-style : italic;
|
font-style : italic;
|
||||||
line-height : 1.4em;
|
line-height : 1.4em;
|
||||||
display : inline-block;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.thumbnail-preview {
|
.thumbnail-preview {
|
||||||
position: relative;
|
position : relative;
|
||||||
justify-self: center;
|
flex : 1 1;
|
||||||
width: 80px;
|
justify-self : center;
|
||||||
height: min-content;
|
width : 80px;
|
||||||
flex: 1 1;
|
height : min-content;
|
||||||
max-height: 115px;
|
max-height : 115px;
|
||||||
aspect-ratio: 1 / 1;
|
aspect-ratio : 1 / 1;
|
||||||
object-fit: contain;
|
object-fit : contain;
|
||||||
background-color: #AAA;
|
background-color : #AAAAAA;
|
||||||
}
|
}
|
||||||
|
|
||||||
.systems.field .value{
|
.systems.field .value {
|
||||||
label{
|
label {
|
||||||
vertical-align : middle;
|
|
||||||
margin-right : 15px;
|
|
||||||
cursor : pointer;
|
|
||||||
font-size : 0.7em;
|
|
||||||
font-weight : 800;
|
|
||||||
user-select : none;
|
|
||||||
white-space : nowrap;
|
|
||||||
display : inline-flex;
|
display : inline-flex;
|
||||||
align-items : center;
|
align-items : center;
|
||||||
}
|
margin-right : 15px;
|
||||||
a {
|
font-size : 0.7em;
|
||||||
font-size : 0.7em;
|
font-weight : 800;
|
||||||
font-weight : 800;
|
white-space : nowrap;
|
||||||
display : inline-flex;
|
|
||||||
}
|
|
||||||
input{
|
|
||||||
vertical-align : middle;
|
vertical-align : middle;
|
||||||
cursor : pointer;
|
cursor : pointer;
|
||||||
|
user-select : none;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
display : inline-flex;
|
||||||
|
font-size : 0.7em;
|
||||||
|
font-weight : 800;
|
||||||
|
}
|
||||||
|
input {
|
||||||
margin : 3px;
|
margin : 3px;
|
||||||
|
vertical-align : middle;
|
||||||
|
cursor : pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.publish.field .value{
|
.publish.field .value {
|
||||||
position : relative;
|
position : relative;
|
||||||
margin-bottom: 15px;
|
margin-bottom : 15px;
|
||||||
button{
|
button { width : 100%; }
|
||||||
width:100%;
|
button.publish {
|
||||||
}
|
|
||||||
button.publish{
|
|
||||||
.button(@blueLight);
|
.button(@blueLight);
|
||||||
}
|
}
|
||||||
button.unpublish{
|
button.unpublish {
|
||||||
.button(@silver);
|
.button(@silver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.delete.field .value{
|
.delete.field .value {
|
||||||
button{
|
button {
|
||||||
.button(@red);
|
.button(@red);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.authors.field .value{
|
.authors.field .value {
|
||||||
font-size: 0.8em;
|
font-size : 0.8em;
|
||||||
line-height : 1.5em;
|
line-height : 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.themes.field{
|
.themes.field {
|
||||||
font-size : 13.33px;
|
font-size : 13.33px;
|
||||||
.navDropdownContainer {
|
.navDropdownContainer {
|
||||||
background-color : white;
|
position : relative;
|
||||||
position : relative;
|
z-index : 100;
|
||||||
z-index : 100;
|
background-color : white;
|
||||||
&.disabled {
|
&.disabled {
|
||||||
font-style :italic;
|
font-style : italic;
|
||||||
font-style : italic;
|
color : dimgray;
|
||||||
background-color : darkgray;
|
background-color : darkgray;
|
||||||
color : dimgray;
|
|
||||||
}
|
}
|
||||||
&>div:first-child {
|
& > div:first-child {
|
||||||
border : 2px solid rgb(118,118,118);
|
padding : 6px 3px;
|
||||||
padding : 6px 3px;
|
background-color : inherit;
|
||||||
background-color : inherit;
|
border : 2px solid rgb(118,118,118);
|
||||||
i {
|
i { float : right; }
|
||||||
float : right;
|
|
||||||
}
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color : @blue;
|
color : white;
|
||||||
color : white;
|
background-color : @blue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navDropdown .item > p {
|
.navDropdown .item > p {
|
||||||
width: 45%;
|
width : 45%;
|
||||||
white-space: nowrap;
|
height : 1.1em;
|
||||||
text-overflow: ellipsis;
|
overflow : hidden;
|
||||||
overflow: hidden;
|
text-overflow : ellipsis;
|
||||||
height: 1.1em;
|
white-space : nowrap;
|
||||||
}
|
}
|
||||||
.navDropdown {
|
.navDropdown {
|
||||||
box-shadow : 0px 5px 10px rgba(0, 0, 0, 0.3);
|
|
||||||
position : absolute;
|
position : absolute;
|
||||||
width : 100%;
|
width : 100%;
|
||||||
|
box-shadow : 0px 5px 10px rgba(0, 0, 0, 0.3);
|
||||||
.item {
|
.item {
|
||||||
padding : 3px 3px;
|
|
||||||
border-top : 1px solid rgb(118, 118, 118);
|
|
||||||
position : relative;
|
position : relative;
|
||||||
|
padding : 3px 3px;
|
||||||
overflow : visible;
|
overflow : visible;
|
||||||
background-color : white;
|
background-color : white;
|
||||||
|
border-top : 1px solid rgb(118, 118, 118);
|
||||||
.preview {
|
.preview {
|
||||||
display : flex;
|
position : absolute;
|
||||||
flex-direction: column;
|
top : 0;
|
||||||
background : #ccc;
|
right : 0;
|
||||||
border-radius : 5px;
|
z-index : 1;
|
||||||
box-shadow : 0 0 5px black;
|
display : flex;
|
||||||
width : 200px;
|
flex-direction : column;
|
||||||
color :black;
|
width : 200px;
|
||||||
position : absolute;
|
overflow : hidden;
|
||||||
top : 0;
|
color : black;
|
||||||
right : 0;
|
background : #CCCCCC;
|
||||||
opacity : 0;
|
border-radius : 5px;
|
||||||
transition : opacity 250ms ease;
|
box-shadow : 0 0 5px black;
|
||||||
z-index : 1;
|
opacity : 0;
|
||||||
overflow :hidden;
|
transition : opacity 250ms ease;
|
||||||
h6 {
|
h6 {
|
||||||
font-weight : 900;
|
padding-block : 0.5em;
|
||||||
padding-inline:1em;
|
padding-inline : 1em;
|
||||||
padding-block :.5em;
|
font-weight : 900;
|
||||||
border-bottom :2px solid hsl(0,0%,40%);
|
border-bottom : 2px solid hsl(0,0%,40%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color : @blue;
|
color : white;
|
||||||
color : white;
|
background-color : @blue;
|
||||||
}
|
|
||||||
&:hover > .preview {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
}
|
||||||
|
&:hover > .preview { opacity : 1; }
|
||||||
.texture-container {
|
.texture-container {
|
||||||
position: absolute;
|
position : absolute;
|
||||||
width: 100%;
|
top : 0;
|
||||||
height: 100%;
|
left : 0;
|
||||||
min-height: 100%;
|
width : 100%;
|
||||||
top: 0;
|
height : 100%;
|
||||||
left: 0;
|
min-height : 100%;
|
||||||
overflow: hidden;
|
overflow : hidden;
|
||||||
> img {
|
> img {
|
||||||
mask-image : linear-gradient(90deg, transparent, black 20%);
|
position : absolute;
|
||||||
-webkit-mask-image : linear-gradient(90deg, transparent, black 20%);
|
top : 0px;
|
||||||
position : absolute;
|
right : 0;
|
||||||
right : 0;
|
width : 50%;
|
||||||
top : 0px;
|
|
||||||
width : 50%;
|
|
||||||
min-height : 100%;
|
min-height : 100%;
|
||||||
|
-webkit-mask-image : linear-gradient(90deg, transparent, black 20%);
|
||||||
|
mask-image : linear-gradient(90deg, transparent, black 20%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -260,84 +241,69 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.field .list {
|
.field .list {
|
||||||
display: flex;
|
display : flex;
|
||||||
flex: 1 0;
|
flex : 1 0;
|
||||||
flex-wrap: wrap;
|
flex-wrap : wrap;
|
||||||
|
|
||||||
> * {
|
> * { flex : 0 0 auto; }
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
#groupedIcon {
|
#groupedIcon {
|
||||||
#backgroundColors;
|
#backgroundColors;
|
||||||
display: inline-block;
|
position : relative;
|
||||||
height: ~"calc(100% + 0.6em)";
|
top : -0.3em;
|
||||||
position: relative;
|
right : -0.3em;
|
||||||
top: -0.3em;
|
display : inline-block;
|
||||||
right: -0.3em;
|
min-width : 20px;
|
||||||
cursor: pointer;
|
height : ~'calc(100% + 0.6em)';
|
||||||
min-width: 20px;
|
color : white;
|
||||||
text-align: center;
|
text-align : center;
|
||||||
color: white;
|
cursor : pointer;
|
||||||
|
|
||||||
i {
|
i {
|
||||||
position: relative;
|
position : relative;
|
||||||
top: 50%;
|
top : 50%;
|
||||||
transform: translateY(-50%);
|
transform : translateY(-50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(:last-child) {
|
&:not(:last-child) { border-right : 1px solid black; }
|
||||||
border-right: 1px solid black;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
&:last-child { border-radius : 0 0.5em 0.5em 0; }
|
||||||
border-radius: 0 0.5em 0.5em 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.badge {
|
.badge {
|
||||||
background-color: #dddddd;
|
padding : 0.3em;
|
||||||
border-radius: .5em;
|
margin : 2px;
|
||||||
font-size: .9em;
|
font-size : 0.9em;
|
||||||
margin: 2px;
|
background-color : #DDDDDD;
|
||||||
padding: .3em;
|
border-radius : 0.5em;
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
#groupedIcon
|
#groupedIcon; }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-group {
|
.input-group {
|
||||||
height: ~"calc(.9em + 4px + .6em)";
|
height : ~'calc(.9em + 4px + .6em)';
|
||||||
|
|
||||||
input {
|
input { border-radius : 0.5em 0 0 0.5em; }
|
||||||
border-radius: .5em 0 0 .5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
input:last-child {
|
input:last-child { border-radius : 0.5em; }
|
||||||
border-radius: .5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.value {
|
.value {
|
||||||
width: 7.5vw;
|
width : 7.5vw;
|
||||||
min-width: 75px;
|
min-width : 75px;
|
||||||
height: 100%;
|
height : 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.invalid:focus {
|
.invalid:focus { background-color : pink; }
|
||||||
background-color: pink;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
#groupedIcon;
|
#groupedIcon;
|
||||||
height: 97%;
|
top : -0.54em;
|
||||||
font-size: .8em;
|
right : 1px;
|
||||||
right: 1px;
|
height : 97%;
|
||||||
top: -.54em;
|
font-size : 0.8em;
|
||||||
|
|
||||||
i {
|
i { font-size : 1.125em; }
|
||||||
font-size: 1.125em;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,8 +71,9 @@ const Homebrew = createClass({
|
|||||||
<Route path='/new/:id' element={<WithRoute el={NewPage} brew={this.props.brew} userThemes={this.props.userThemes}/>} />
|
<Route path='/new/:id' element={<WithRoute el={NewPage} brew={this.props.brew} userThemes={this.props.userThemes}/>} />
|
||||||
<Route path='/new' element={<WithRoute el={NewPage} userThemes={this.props.userThemes}/> } />
|
<Route path='/new' element={<WithRoute el={NewPage} userThemes={this.props.userThemes}/> } />
|
||||||
<Route path='/user/:username' element={<WithRoute el={UserPage} brews={this.props.brews} />} />
|
<Route path='/user/:username' element={<WithRoute el={UserPage} brews={this.props.brews} />} />
|
||||||
<Route path='/changelog' element={<WithRoute el={SharePage} brew={this.props.brew} />} />
|
<Route path='/changelog' element={<WithRoute el={SharePage} brew={this.props.brew} disableMeta={true} />} />
|
||||||
<Route path='/faq' element={<WithRoute el={SharePage} brew={this.props.brew} />} />
|
<Route path='/faq' element={<WithRoute el={SharePage} brew={this.props.brew} disableMeta={true} />} />
|
||||||
|
<Route path='/migrate' element={<WithRoute el={SharePage} brew={this.props.brew} disableMeta={true} />} />
|
||||||
<Route path='/account' element={<WithRoute el={AccountPage} brew={this.props.brew} accountDetails={this.props.brew.accountDetails} />} />
|
<Route path='/account' element={<WithRoute el={AccountPage} brew={this.props.brew} accountDetails={this.props.brew.accountDetails} />} />
|
||||||
<Route path='/legacy' element={<WithRoute el={HomePage} brew={this.props.brew} />} />
|
<Route path='/legacy' element={<WithRoute el={HomePage} brew={this.props.brew} />} />
|
||||||
<Route path='/error' element={<WithRoute el={ErrorPage} brew={this.props.brew} />} />
|
<Route path='/error' element={<WithRoute el={ErrorPage} brew={this.props.brew} />} />
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ const HomePage = createClass({
|
|||||||
onTextChange={this.handleTextChange}
|
onTextChange={this.handleTextChange}
|
||||||
renderer={this.state.brew.renderer}
|
renderer={this.state.brew.renderer}
|
||||||
showEditButtons={false}
|
showEditButtons={false}
|
||||||
|
snippetBundle={this.state.themeBundle.snippets}
|
||||||
/>
|
/>
|
||||||
<BrewRenderer
|
<BrewRenderer
|
||||||
text={this.state.brew.text}
|
text={this.state.brew.text}
|
||||||
|
|||||||
@@ -217,6 +217,7 @@ const NewPage = createClass({
|
|||||||
onMetaChange={this.handleMetaChange}
|
onMetaChange={this.handleMetaChange}
|
||||||
renderer={this.state.brew.renderer}
|
renderer={this.state.brew.renderer}
|
||||||
userThemes={this.props.userThemes}
|
userThemes={this.props.userThemes}
|
||||||
|
snippetBundle={this.state.themeBundle.snippets}
|
||||||
/>
|
/>
|
||||||
<BrewRenderer
|
<BrewRenderer
|
||||||
text={this.state.brew.text}
|
text={this.state.brew.text}
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ const SharePage = createClass({
|
|||||||
displayName : 'SharePage',
|
displayName : 'SharePage',
|
||||||
getDefaultProps : function() {
|
getDefaultProps : function() {
|
||||||
return {
|
return {
|
||||||
brew : DEFAULT_BREW_LOAD,
|
brew : DEFAULT_BREW_LOAD,
|
||||||
|
disableMeta : false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -68,13 +69,21 @@ const SharePage = createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
render : function(){
|
render : function(){
|
||||||
|
const titleStyle = this.props.disableMeta ? { cursor: 'default' } : {};
|
||||||
|
const titleEl = <Nav.item className='brewTitle' style={titleStyle}>{this.props.brew.title}</Nav.item>;
|
||||||
|
|
||||||
return <div className='sharePage sitePage'>
|
return <div className='sharePage sitePage'>
|
||||||
<Meta name='robots' content='noindex, nofollow' />
|
<Meta name='robots' content='noindex, nofollow' />
|
||||||
<Navbar>
|
<Navbar>
|
||||||
<Nav.section className='titleSection'>
|
<Nav.section className='titleSection'>
|
||||||
<MetadataNav brew={this.props.brew}>
|
{
|
||||||
<Nav.item className='brewTitle'>{this.props.brew.title}</Nav.item>
|
this.props.disableMeta ?
|
||||||
</MetadataNav>
|
titleEl
|
||||||
|
:
|
||||||
|
<MetadataNav brew={this.props.brew}>
|
||||||
|
{titleEl}
|
||||||
|
</MetadataNav>
|
||||||
|
}
|
||||||
</Nav.section>
|
</Nav.section>
|
||||||
|
|
||||||
<Nav.section>
|
<Nav.section>
|
||||||
|
|||||||
4996
package-lock.json
generated
4996
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
26
package.json
26
package.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "homebrewery",
|
"name": "homebrewery",
|
||||||
"description": "Create authentic looking D&D homebrews using only markdown",
|
"description": "Create authentic looking D&D homebrews using only markdown",
|
||||||
"version": "3.14.0",
|
"version": "3.14.1",
|
||||||
"engines": {
|
"engines": {
|
||||||
"npm": "^10.2.x",
|
"npm": "^10.2.x",
|
||||||
"node": "^20.8.x"
|
"node": "^20.8.x"
|
||||||
@@ -83,9 +83,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "^7.24.7",
|
"@babel/core": "^7.25.2",
|
||||||
"@babel/plugin-transform-runtime": "^7.24.7",
|
"@babel/plugin-transform-runtime": "^7.24.7",
|
||||||
"@babel/preset-env": "^7.24.7",
|
"@babel/preset-env": "^7.25.3",
|
||||||
"@babel/preset-react": "^7.24.7",
|
"@babel/preset-react": "^7.24.7",
|
||||||
"@googleapis/drive": "^8.11.0",
|
"@googleapis/drive": "^8.11.0",
|
||||||
"body-parser": "^1.20.2",
|
"body-parser": "^1.20.2",
|
||||||
@@ -94,7 +94,7 @@
|
|||||||
"cookie-parser": "^1.4.6",
|
"cookie-parser": "^1.4.6",
|
||||||
"create-react-class": "^15.7.0",
|
"create-react-class": "^15.7.0",
|
||||||
"dedent-tabs": "^0.10.3",
|
"dedent-tabs": "^0.10.3",
|
||||||
"dompurify": "^3.1.5",
|
"dompurify": "^3.1.6",
|
||||||
"expr-eval": "^2.0.2",
|
"expr-eval": "^2.0.2",
|
||||||
"express": "^4.19.2",
|
"express": "^4.19.2",
|
||||||
"express-async-handler": "^1.2.0",
|
"express-async-handler": "^1.2.0",
|
||||||
@@ -105,34 +105,34 @@
|
|||||||
"less": "^3.13.1",
|
"less": "^3.13.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"marked": "11.2.0",
|
"marked": "11.2.0",
|
||||||
"marked-emoji": "^1.4.1",
|
"marked-emoji": "^1.4.2",
|
||||||
"marked-extended-tables": "^1.0.8",
|
"marked-extended-tables": "^1.0.8",
|
||||||
"marked-gfm-heading-id": "^3.2.0",
|
"marked-gfm-heading-id": "^3.2.0",
|
||||||
"marked-smartypants-lite": "^1.0.2",
|
"marked-smartypants-lite": "^1.0.2",
|
||||||
"markedLegacy": "npm:marked@^0.3.19",
|
"markedLegacy": "npm:marked@^0.3.19",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"mongoose": "^8.4.5",
|
"mongoose": "^8.5.2",
|
||||||
"nanoid": "3.3.4",
|
"nanoid": "3.3.4",
|
||||||
"nconf": "^0.12.1",
|
"nconf": "^0.12.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-frame-component": "^4.1.3",
|
"react-frame-component": "^4.1.3",
|
||||||
"react-router-dom": "6.24.1",
|
"react-router-dom": "6.26.0",
|
||||||
"sanitize-filename": "1.6.3",
|
"sanitize-filename": "1.6.3",
|
||||||
"superagent": "^9.0.2",
|
"superagent": "^9.0.2",
|
||||||
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
|
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@stylistic/stylelint-plugin": "^3.0.0",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-plugin-jest": "^28.6.0",
|
"eslint-plugin-jest": "^28.8.0",
|
||||||
"eslint-plugin-react": "^7.34.3",
|
"eslint-plugin-react": "^7.35.0",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"jest-expect-message": "^1.1.3",
|
"jest-expect-message": "^1.1.3",
|
||||||
"postcss-less": "^6.0.0",
|
"postcss-less": "^6.0.0",
|
||||||
"stylelint": "^15.11.0",
|
"stylelint": "^16.8.0",
|
||||||
"stylelint-config-recess-order": "^4.6.0",
|
"stylelint-config-recess-order": "^5.0.1",
|
||||||
"stylelint-config-recommended": "^13.0.0",
|
"stylelint-config-recommended": "^14.0.1",
|
||||||
"stylelint-stylistic": "^0.4.3",
|
|
||||||
"supertest": "^7.0.0"
|
"supertest": "^7.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,7 +115,8 @@ app.get('/legacy', (req, res, next)=>{
|
|||||||
app.get('/migrate', (req, res, next)=>{
|
app.get('/migrate', (req, res, next)=>{
|
||||||
req.brew = {
|
req.brew = {
|
||||||
text : migrateText,
|
text : migrateText,
|
||||||
renderer : 'V3'
|
renderer : 'V3',
|
||||||
|
theme : '5ePHB'
|
||||||
},
|
},
|
||||||
|
|
||||||
req.ogMeta = { ...defaultMetaTags,
|
req.ogMeta = { ...defaultMetaTags,
|
||||||
@@ -132,7 +133,8 @@ app.get('/changelog', async (req, res, next)=>{
|
|||||||
req.brew = {
|
req.brew = {
|
||||||
title : 'Changelog',
|
title : 'Changelog',
|
||||||
text : changelogText,
|
text : changelogText,
|
||||||
renderer : 'V3'
|
renderer : 'V3',
|
||||||
|
theme : '5ePHB'
|
||||||
},
|
},
|
||||||
|
|
||||||
req.ogMeta = { ...defaultMetaTags,
|
req.ogMeta = { ...defaultMetaTags,
|
||||||
@@ -149,7 +151,8 @@ app.get('/faq', async (req, res, next)=>{
|
|||||||
req.brew = {
|
req.brew = {
|
||||||
title : 'FAQ',
|
title : 'FAQ',
|
||||||
text : faqText,
|
text : faqText,
|
||||||
renderer : 'V3'
|
renderer : 'V3',
|
||||||
|
theme : '5ePHB'
|
||||||
},
|
},
|
||||||
|
|
||||||
req.ogMeta = { ...defaultMetaTags,
|
req.ogMeta = { ...defaultMetaTags,
|
||||||
|
|||||||
@@ -46,6 +46,9 @@ const api = {
|
|||||||
},
|
},
|
||||||
//Get array of any of this user's brews tagged with `meta:theme`
|
//Get array of any of this user's brews tagged with `meta:theme`
|
||||||
getUsersBrewThemes : async (username)=>{
|
getUsersBrewThemes : async (username)=>{
|
||||||
|
if(!username)
|
||||||
|
return {};
|
||||||
|
|
||||||
const fields = [
|
const fields = [
|
||||||
'title',
|
'title',
|
||||||
'tags',
|
'tags',
|
||||||
@@ -183,7 +186,7 @@ const api = {
|
|||||||
return modified;
|
return modified;
|
||||||
},
|
},
|
||||||
excludeStubProps : (brew)=>{
|
excludeStubProps : (brew)=>{
|
||||||
const propsToExclude = ['text', 'textBin', 'renderer', 'pageCount'];
|
const propsToExclude = ['text', 'textBin'];
|
||||||
for (const prop of propsToExclude) {
|
for (const prop of propsToExclude) {
|
||||||
brew[prop] = undefined;
|
brew[prop] = undefined;
|
||||||
}
|
}
|
||||||
@@ -251,16 +254,12 @@ const api = {
|
|||||||
res.status(200).send(saved);
|
res.status(200).send(saved);
|
||||||
},
|
},
|
||||||
getThemeBundle : async(req, res)=>{
|
getThemeBundle : async(req, res)=>{
|
||||||
/*
|
/* getThemeBundle: Collects the theme and all parent themes
|
||||||
getThemeBundle: Collects the theme and all parent themes
|
returns an object containing an array of css, and an array of snippets, in render order
|
||||||
returns an object containing an array of css, in render order, and an array
|
|
||||||
of snippets ( currently empty )
|
req.params.id : The shareId ( User theme ) or name ( static theme )
|
||||||
Important parameter members:
|
req.params.renderer : The Markdown renderer used for this theme */
|
||||||
req.params.id: This is the shareId ( User theme ) or name ( static theme )
|
|
||||||
loaded first.
|
|
||||||
req.params.renderer: This is the Markdown+ version for the static theme. If a
|
|
||||||
User theme the value will come from the User Theme metadata.
|
|
||||||
*/
|
|
||||||
req.params.renderer = _.upperFirst(req.params.renderer);
|
req.params.renderer = _.upperFirst(req.params.renderer);
|
||||||
let currentTheme;
|
let currentTheme;
|
||||||
const completeStyles = [];
|
const completeStyles = [];
|
||||||
|
|||||||
@@ -408,8 +408,8 @@ brew`);
|
|||||||
expect(sent).not.toEqual(googleBrew);
|
expect(sent).not.toEqual(googleBrew);
|
||||||
expect(result.text).toBeUndefined();
|
expect(result.text).toBeUndefined();
|
||||||
expect(result.textBin).toBeUndefined();
|
expect(result.textBin).toBeUndefined();
|
||||||
expect(result.renderer).toBeUndefined();
|
expect(result.renderer).toBe('v3');
|
||||||
expect(result.pageCount).toBeUndefined();
|
expect(result.pageCount).toBe(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -540,9 +540,9 @@ brew`);
|
|||||||
description : '',
|
description : '',
|
||||||
editId : expect.any(String),
|
editId : expect.any(String),
|
||||||
gDrive : false,
|
gDrive : false,
|
||||||
pageCount : undefined,
|
pageCount : 1,
|
||||||
published : false,
|
published : false,
|
||||||
renderer : undefined,
|
renderer : 'V3',
|
||||||
lang : 'en',
|
lang : 'en',
|
||||||
shareId : expect.any(String),
|
shareId : expect.any(String),
|
||||||
googleId : expect.any(String),
|
googleId : expect.any(String),
|
||||||
|
|||||||
@@ -39,8 +39,10 @@ if(typeof window !== 'undefined'){
|
|||||||
//Autocompletion
|
//Autocompletion
|
||||||
require('codemirror/addon/hint/show-hint.js');
|
require('codemirror/addon/hint/show-hint.js');
|
||||||
|
|
||||||
const foldCode = require('./fold-code');
|
const foldPagesCode = require('./fold-pages');
|
||||||
foldCode.registerHomebreweryHelper(CodeMirror);
|
foldPagesCode.registerHomebreweryHelper(CodeMirror);
|
||||||
|
const foldCSSCode = require('./fold-css');
|
||||||
|
foldCSSCode.registerHomebreweryHelper(CodeMirror);
|
||||||
}
|
}
|
||||||
|
|
||||||
const CodeEditor = createClass({
|
const CodeEditor = createClass({
|
||||||
@@ -411,11 +413,11 @@ const CodeEditor = createClass({
|
|||||||
foldOptions : function(cm){
|
foldOptions : function(cm){
|
||||||
return {
|
return {
|
||||||
scanUp : true,
|
scanUp : true,
|
||||||
rangeFinder : CodeMirror.fold.homebrewery,
|
rangeFinder : this.props.language === 'css' ? CodeMirror.fold.homebrewerycss : CodeMirror.fold.homebrewery,
|
||||||
widget : (from, to)=>{
|
widget : (from, to)=>{
|
||||||
let text = '';
|
let text = '';
|
||||||
let currentLine = from.line;
|
let currentLine = from.line;
|
||||||
const maxLength = 50;
|
let maxLength = 50;
|
||||||
|
|
||||||
let foldPreviewText = '';
|
let foldPreviewText = '';
|
||||||
while (currentLine <= to.line && text.length <= maxLength) {
|
while (currentLine <= to.line && text.length <= maxLength) {
|
||||||
@@ -430,10 +432,15 @@ const CodeEditor = createClass({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
text = foldPreviewText || `Lines ${from.line+1}-${to.line+1}`;
|
text = foldPreviewText || `Lines ${from.line+1}-${to.line+1}`;
|
||||||
|
text = text.replace('{', '').trim();
|
||||||
|
|
||||||
|
// Truncate data URLs at `data:`
|
||||||
|
const startOfData = text.indexOf('data:');
|
||||||
|
if(startOfData > 0)
|
||||||
|
maxLength = Math.min(startOfData + 5, maxLength);
|
||||||
|
|
||||||
text = text.trim();
|
|
||||||
if(text.length > maxLength)
|
if(text.length > maxLength)
|
||||||
text = `${text.substr(0, maxLength)}...`;
|
text = `${text.slice(0, maxLength)}...`;
|
||||||
|
|
||||||
return `\u21A4 ${text} \u21A6`;
|
return `\u21A4 ${text} \u21A6`;
|
||||||
}
|
}
|
||||||
@@ -450,3 +457,4 @@ const CodeEditor = createClass({
|
|||||||
});
|
});
|
||||||
|
|
||||||
module.exports = CodeEditor;
|
module.exports = CodeEditor;
|
||||||
|
|
||||||
|
|||||||
44
shared/naturalcrit/codeEditor/fold-css.js
Normal file
44
shared/naturalcrit/codeEditor/fold-css.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
module.exports = {
|
||||||
|
registerHomebreweryHelper : function(CodeMirror) {
|
||||||
|
CodeMirror.registerHelper('fold', 'homebrewerycss', function(cm, start) {
|
||||||
|
|
||||||
|
// BRACE FOLDING
|
||||||
|
const startMatcher = /\{[ \t]*$/;
|
||||||
|
const endMatcher = /\}[ \t]*$/;
|
||||||
|
const activeLine = cm.getLine(start.line);
|
||||||
|
|
||||||
|
|
||||||
|
if(activeLine.match(startMatcher)) {
|
||||||
|
const lastLineNo = cm.lastLine();
|
||||||
|
let end = start.line + 1;
|
||||||
|
let braceCount = 1;
|
||||||
|
|
||||||
|
while (end < lastLineNo) {
|
||||||
|
const curLine = cm.getLine(end);
|
||||||
|
if(curLine.match(startMatcher)) braceCount++;
|
||||||
|
if(curLine.match(endMatcher)) braceCount--;
|
||||||
|
if(braceCount == 0) break;
|
||||||
|
++end;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
from : CodeMirror.Pos(start.line, 0),
|
||||||
|
to : CodeMirror.Pos(end, cm.getLine(end).length)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// @import and data-url folding
|
||||||
|
const importMatcher = /^@import.*?;/;
|
||||||
|
const dataURLMatcher = /url\(.*?data\:.*\)/;
|
||||||
|
|
||||||
|
if(activeLine.match(importMatcher) || activeLine.match(dataURLMatcher)) {
|
||||||
|
return {
|
||||||
|
from : CodeMirror.Pos(start.line, 0),
|
||||||
|
to : CodeMirror.Pos(start.line, activeLine.length)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -28,17 +28,18 @@ const mathParser = new MathParser({
|
|||||||
round : true,
|
round : true,
|
||||||
floor : true,
|
floor : true,
|
||||||
ceil : true,
|
ceil : true,
|
||||||
|
abs : true,
|
||||||
|
|
||||||
sin : false, cos : false, tan : false, asin : false, acos : false,
|
sin : false, cos : false, tan : false, asin : false, acos : false,
|
||||||
atan : false, sinh : false, cosh : false, tanh : false, asinh : false,
|
atan : false, sinh : false, cosh : false, tanh : false, asinh : false,
|
||||||
acosh : false, atanh : false, sqrt : false, cbrt : false, log : false,
|
acosh : false, atanh : false, sqrt : false, cbrt : false, log : false,
|
||||||
log2 : false, ln : false, lg : false, log10 : false, expm1 : false,
|
log2 : false, ln : false, lg : false, log10 : false, expm1 : false,
|
||||||
log1p : false, abs : false, trunc : false, join : false, sum : false,
|
log1p : false, trunc : false, join : false, sum : false, indexOf : false,
|
||||||
'-' : false, '+' : false, exp : false, not : false, length : false,
|
'-' : false, '+' : false, exp : false, not : false, length : false,
|
||||||
'!' : false, sign : false, random : false, fac : false, min : false,
|
'!' : false, sign : false, random : false, fac : false, min : false,
|
||||||
max : false, hypot : false, pyt : false, pow : false, atan2 : false,
|
max : false, hypot : false, pyt : false, pow : false, atan2 : false,
|
||||||
'if' : false, gamma : false, roundTo : false, map : false, fold : false,
|
'if' : false, gamma : false, roundTo : false, map : false, fold : false,
|
||||||
filter : false, indexOf : false,
|
filter : false,
|
||||||
|
|
||||||
remainder : false, factorial : false,
|
remainder : false, factorial : false,
|
||||||
comparison : false, concatenate : false,
|
comparison : false, concatenate : false,
|
||||||
@@ -46,6 +47,16 @@ const mathParser = new MathParser({
|
|||||||
array : false, fndef : false
|
array : false, fndef : false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// Add sign function
|
||||||
|
mathParser.functions.sign = function (a) {
|
||||||
|
if(a >= 0) return '+';
|
||||||
|
return '-';
|
||||||
|
};
|
||||||
|
// Add signed function
|
||||||
|
mathParser.functions.signed = function (a) {
|
||||||
|
if(a >= 0) return `+${a}`;
|
||||||
|
return `${a}`;
|
||||||
|
};
|
||||||
|
|
||||||
//Processes the markdown within an HTML block if it's just a class-wrapper
|
//Processes the markdown within an HTML block if it's just a class-wrapper
|
||||||
renderer.html = function (html) {
|
renderer.html = function (html) {
|
||||||
@@ -441,7 +452,7 @@ const replaceVar = function(input, hoist=false, allowUnresolved=false) {
|
|||||||
const label = match[2];
|
const label = match[2];
|
||||||
|
|
||||||
//v=====--------------------< HANDLE MATH >-------------------=====v//
|
//v=====--------------------< HANDLE MATH >-------------------=====v//
|
||||||
const mathRegex = /[a-z]+\(|[+\-*/^()]/g;
|
const mathRegex = /[a-z]+\(|[+\-*/^(),]/g;
|
||||||
const matches = label.split(mathRegex);
|
const matches = label.split(mathRegex);
|
||||||
const mathVars = matches.filter((match)=>isNaN(match))?.map((s)=>s.trim()); // Capture any variable names
|
const mathVars = matches.filter((match)=>isNaN(match))?.map((s)=>s.trim()); // Capture any variable names
|
||||||
|
|
||||||
@@ -451,7 +462,7 @@ const replaceVar = function(input, hoist=false, allowUnresolved=false) {
|
|||||||
mathVars?.forEach((variable)=>{
|
mathVars?.forEach((variable)=>{
|
||||||
const foundVar = lookupVar(variable, globalPageNumber, hoist);
|
const foundVar = lookupVar(variable, globalPageNumber, hoist);
|
||||||
if(foundVar && foundVar.resolved && foundVar.content && !isNaN(foundVar.content)) // Only subsitute math values if fully resolved, not empty strings, and numbers
|
if(foundVar && foundVar.resolved && foundVar.content && !isNaN(foundVar.content)) // Only subsitute math values if fully resolved, not empty strings, and numbers
|
||||||
replacedLabel = replacedLabel.replaceAll(variable, foundVar.content);
|
replacedLabel = replacedLabel.replaceAll(new RegExp(`(?<!\\w)(${variable})(?!\\w)`, 'g'), foundVar.content);
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
const stylelint = require('stylelint');
|
const stylelint = require('stylelint');
|
||||||
const { isNumber } = require('stylelint/lib/utils/validateTypes');
|
const { isNumber } = require('stylelint/lib/utils/validateTypes.cjs');
|
||||||
|
|
||||||
const { report, ruleMessages, validateOptions } = stylelint.utils;
|
const { report, ruleMessages, validateOptions } = stylelint.utils;
|
||||||
const ruleName = 'naturalcrit/declaration-block-multi-line-min-declarations';
|
const ruleName = 'naturalcrit/declaration-block-multi-line-min-declarations';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
const stylelint = require('stylelint');
|
const stylelint = require('stylelint');
|
||||||
const { isNumber } = require('stylelint/lib/utils/validateTypes');
|
const { isNumber } = require('stylelint/lib/utils/validateTypes.cjs');
|
||||||
|
|
||||||
const { report, ruleMessages, validateOptions } = stylelint.utils;
|
const { report, ruleMessages, validateOptions } = stylelint.utils;
|
||||||
const ruleName = 'naturalcrit/declaration-colon-min-space-before';
|
const ruleName = 'naturalcrit/declaration-colon-min-space-before';
|
||||||
|
|||||||
@@ -371,3 +371,35 @@ describe('Cross-page variables', ()=>{
|
|||||||
expect(rendered, `Input:\n${[source0, source1].join('\n\\page\n')}`, { showPrefix: false }).toBe('<p>two</p><p>one</p>\\page<p>two</p>');
|
expect(rendered, `Input:\n${[source0, source1].join('\n\\page\n')}`, { showPrefix: false }).toBe('<p>two</p><p>one</p>\\page<p>two</p>');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Math function parameter handling', ()=>{
|
||||||
|
it('allows variables in single-parameter functions', function() {
|
||||||
|
const source = '[var]:4.1\n\n$[floor(var)]';
|
||||||
|
const rendered = Markdown.render(source).trimReturns();
|
||||||
|
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<p>4</p>`);
|
||||||
|
});
|
||||||
|
it('allows one variable and a number in two-parameter functions', function() {
|
||||||
|
const source = '[var]:4\n\n$[min(1,var)]';
|
||||||
|
const rendered = Markdown.render(source).trimReturns();
|
||||||
|
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<p>1</p>`);
|
||||||
|
});
|
||||||
|
it('allows two variables in two-parameter functions', function() {
|
||||||
|
const source = '[var1]:4\n\n[var2]:8\n\n$[min(var1,var2)]';
|
||||||
|
const rendered = Markdown.render(source).trimReturns();
|
||||||
|
expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe(`<p>4</p>`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Variable names that are subsets of other names', ()=>{
|
||||||
|
it('do not conflict with function names', function() {
|
||||||
|
const source = `[a]: -1\n\n$[abs(a)]`;
|
||||||
|
const rendered = Markdown.render(source).trimReturns();
|
||||||
|
expect(rendered).toBe('<p>1</p>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('do not conflict with other variable names', function() {
|
||||||
|
const source = `[ab]: 2\n\n[aba]: 8\n\n[ba]: 4\n\n$[ab + aba + ba]`;
|
||||||
|
const rendered = Markdown.render(source).trimReturns();
|
||||||
|
expect(rendered).toBe('<p>14</p>');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -349,7 +349,7 @@ module.exports = [
|
|||||||
/* Ink Friendly */
|
/* Ink Friendly */
|
||||||
*:is(.page,.monster,.note,.descriptive) {
|
*:is(.page,.monster,.note,.descriptive) {
|
||||||
background : white !important;
|
background : white !important;
|
||||||
filter : drop-shadow(0px 0px 3px #888) !important;
|
box-shadow : 1px 4px 14px #888 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page img {
|
.page img {
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ const getTOC = (pages)=>{
|
|||||||
const ToCExclude = getComputedStyle(heading).getPropertyValue('--TOC');
|
const ToCExclude = getComputedStyle(heading).getPropertyValue('--TOC');
|
||||||
|
|
||||||
if(ToCExclude != 'exclude') {
|
if(ToCExclude != 'exclude') {
|
||||||
recursiveAdd(heading.innerText.trim(), onPage, headerDepth.indexOf(heading.tagName), res);
|
recursiveAdd(heading.textContent.trim(), onPage, headerDepth.indexOf(heading.tagName), res);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return res;
|
return res;
|
||||||
|
|||||||
@@ -382,6 +382,14 @@
|
|||||||
.useColumns(0.96, @fillMode: balance);
|
.useColumns(0.96, @fillMode: balance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//only for IOS devices
|
||||||
|
@supports (-webkit-touch-callout: none) {
|
||||||
|
.page .monster.frame {
|
||||||
|
background-repeat : no-repeat;
|
||||||
|
background-size : cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// *****************************
|
// *****************************
|
||||||
// * FOOTER
|
// * FOOTER
|
||||||
// *****************************/
|
// *****************************/
|
||||||
@@ -459,6 +467,7 @@
|
|||||||
margin-left : 1.5em;
|
margin-left : 1.5em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// *****************************
|
// *****************************
|
||||||
// * SPELL LIST
|
// * SPELL LIST
|
||||||
// *****************************/
|
// *****************************/
|
||||||
@@ -883,6 +892,9 @@ h6,
|
|||||||
.useColumns(0.96, @fillMode: balance);
|
.useColumns(0.96, @fillMode: balance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.toc.wide li {
|
||||||
|
break-inside: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// *****************************
|
// *****************************
|
||||||
@@ -907,6 +919,10 @@ h6,
|
|||||||
|
|
||||||
.page h1 + * { margin-top : 0; }
|
.page h1 + * { margin-top : 0; }
|
||||||
|
|
||||||
|
.page .descriptive.wide + * {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
//*****************************
|
//*****************************
|
||||||
// * RUNE TABLE
|
// * RUNE TABLE
|
||||||
// *****************************/
|
// *****************************/
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
@noteBorderImage : url('/assets/noteBorder.png');
|
@noteBorderImage : url('/assets/noteBorder.png');
|
||||||
@descriptiveBoxImage : url('/assets/descriptiveBorder.png');
|
@descriptiveBoxImage : url('/assets/descriptiveBorder.png');
|
||||||
@monsterBlockBackground : url('/assets/parchmentBackgroundGrayscale.jpg');
|
@monsterBlockBackground : url('/assets/parchmentBackgroundGrayscale.jpg');
|
||||||
|
@monsterBlockOverlay : url('/assets/parchmentBackgroundOverlayed.jpg');
|
||||||
@monsterBorderImage : url('/assets/monsterBorderFancy.png');
|
@monsterBorderImage : url('/assets/monsterBorderFancy.png');
|
||||||
@codeBorderImage : url('/assets/codeBorder.png');
|
@codeBorderImage : url('/assets/codeBorder.png');
|
||||||
@classTableDecoration : url('/assets/classTableDecoration.png');
|
@classTableDecoration : url('/assets/classTableDecoration.png');
|
||||||
|
|||||||
Reference in New Issue
Block a user