{this.renderPublish()}
Published brews are searchable in the Vault and visible on your user page. Unpublished brews are not indexed in the Vault or visible on your user page, but can still be shared and indexed by search engines. You can unpublish a brew any time.
diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.less b/client/homebrew/editor/metadataEditor/metadataEditor.less
deleted file mode 100644
index 3d3267f80..000000000
--- a/client/homebrew/editor/metadataEditor/metadataEditor.less
+++ /dev/null
@@ -1,374 +0,0 @@
-@import '@sharedStyles/core.less';
-
-.userThemeName {
- padding-right : 10px;
- padding-left : 10px;
-}
-
-.metadataEditor {
- position : absolute;
- box-sizing : border-box;
- width : 100%;
- 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;
- font-size : 13px;
- background-color : #999999;
-
- h1 {
- margin : 0 0 40px;
- font-weight : bold;
- text-transform : uppercase;
- }
-
- h2 {
- margin : 20px 0;
- font-weight : bold;
- color : #555555;
- border-bottom : 2px solid gray;
- }
-
- & > div { margin-bottom : 10px; }
-
- .field-group {
- display : flex;
- flex-wrap : wrap;
- gap : 10px;
- width : 100%;
- }
-
- .field-column {
- display : flex;
- flex : 5 0 200px;
- flex-direction : column;
- gap : 10px;
- }
-
- .field {
- position : relative;
- display : flex;
- flex-wrap : wrap;
- width : 100%;
- min-width : 200px;
- & > label {
- width : 80px;
- font-size : 0.9em;
- font-weight : 800;
- line-height : 1.8em;
- text-transform : uppercase;
- }
- & > .value {
- flex : 1 1 auto;
- width : 50px;
- &[data-tooltip-right] { max-width : 380px; }
- &:invalid { background : #FFB9B9; }
- small {
- display : block;
- font-size : 0.9em;
- font-style : italic;
- line-height : 1.4em;
- }
- }
- input[type='text'], textarea {
- border : 1px solid gray;
- &:focus { outline : 1px solid #444444; }
- }
-
- &.description {
- flex : 1;
- textarea.value {
- height : auto;
- font-family : 'Open Sans', sans-serif;
- resize : none;
- }
- }
-
- &.thumbnail, &.themes {
- label { line-height : 2.0em; }
- .value {
- overflow : hidden;
- text-overflow : ellipsis;
- }
- button {
- .colorButton();
- padding : 0px 5px;
- color : white;
- background-color : black;
- border : 1px solid #999999;
- &:hover { background-color : #777777; }
- }
- }
-
- &.tags .tagInput-dropdown {
- z-index : 400;
- max-width : 200px;
- }
- &.language .value {
- z-index : 300;
- max-width : 150px;
- }
-
- &.themes {
- .value {
- overflow : visible;
- text-overflow : auto;
- }
- button {
- padding-right : 5px;
- padding-left : 5px;
- }
- }
-
- &.invitedAuthors .value {
- z-index : 100;
-
- .tagInput-dropdown { max-width : 200px; }
- }
- }
-
- .thumbnail-preview {
- position : relative;
- flex : 1 1;
- justify-self : center;
- width : 80px;
- height : min-content;
- max-height : 115px;
- aspect-ratio : 1 / 1;
- object-fit : contain;
- background-color : #AAAAAA;
- }
-
- .renderers.field .value {
- label {
- display : inline-flex;
- align-items : center;
- margin-right : 15px;
- font-size : 0.9em;
- font-weight : 800;
- vertical-align : middle;
- white-space : nowrap;
- cursor : pointer;
- user-select : none;
- }
- input {
- margin : 3px;
- vertical-align : middle;
- cursor : pointer;
- }
- }
- .publish.field .value {
- position : relative;
- margin-bottom : 15px;
- button { width : 100%; }
- button.publish {
- .colorButton(@blueLight);
- }
- button.unpublish {
- .colorButton(@silver);
- }
- }
-
- .delete.field .value {
- button {
- .colorButton(@red);
- }
- }
- .authors.field {
- .tag {
- font-weight:300;
- transition:background-color 0.2s;
-
- &.owner {
- position: relative;
- background-color:@silverLight;
- min-width:25px;
- display:grid;
- place-items:center;
- font-weight: 900;
-
- &::after {
- content: "\f521";
- font-family: "Font Awesome 6 Free";
- color:gold;
- position: absolute;
- top: 0;
- left: 0;
- width:15px;
- height:15px;
- rotate:-25deg;
- translate:-30% -50%;
- transform: scaleY(0.7);
- }
- }
- &:has(button) a {
- padding-right:5px;
- }
- &:has(button:hover) {
- background:#d97d7d;
- }
-
- button {
- color:@red;
- }
-
-
- }
- a {
- color:black;
- text-underline-offset:0.2em;
- }
- }
-
- .themes.field {
- & .dropdown-container {
- position : relative;
- z-index : 200;
- background-color : white;
- }
- & .dropdown-options { overflow-y : visible; }
- .disabled {
- font-style : italic;
- color : dimgray;
- background-color : darkgray;
- }
- .item {
- position : relative;
- padding : 3px 3px;
- overflow : visible;
- background-color : white;
- border-top : 1px solid rgb(118, 118, 118);
- .preview {
- position : absolute;
- top : 0;
- right : 0;
- z-index : 1;
- display : flex;
- flex-direction : column;
- width : 200px;
- overflow : hidden;
- color : black;
- background : #CCCCCC;
- border-radius : 5px;
- box-shadow : 0 0 5px black;
- opacity : 0;
- transition : opacity 250ms ease;
- h6 {
- padding-block : 0.5em;
- padding-inline : 1em;
- font-weight : 900;
- border-bottom : 2px solid hsl(0,0%,40%);
- }
- }
-
- .texture-container {
- position : absolute;
- top : 0;
- left : 0;
- width : 100%;
- height : 100%;
- min-height : 100%;
- overflow : hidden;
- > img {
- position : absolute;
- top : 0;
- right : 0;
- width : 50%;
- min-height : 100%;
- -webkit-mask-image : linear-gradient(90deg, transparent, black 20%);
- mask-image : linear-gradient(90deg, transparent, black 20%);
- }
- }
-
- &:hover {
- color : white;
- background-color : @blue;
- filter : unset;
- }
- &:hover > .preview { opacity : 1; }
- }
- }
-
- .field .list {
- display : flex;
- flex : 1 0;
- flex-wrap : wrap;
-
- > * { flex : 0 0 auto; }
-
- #groupedIcon {
- #backgroundColors;
- position : relative;
- top : -0.3em;
- right : -0.3em;
- display : inline-block;
- min-width : 20px;
- height : ~'calc(100% + 0.6em)';
- color : white;
- text-align : center;
- cursor : pointer;
-
- i {
- position : relative;
- top : 50%;
- transform : translateY(-50%);
- }
-
- &:not(:last-child) { border-right : 1px solid black; }
-
- &:last-child { border-radius : 0 0.5em 0.5em 0; }
- }
-
- .tag {
- padding : 0.35em;
- margin : 2px;
- font-size : 0.95em;
- background-color : #DDDDDD;
- border-radius : 0.5em;
-
- .icon { #groupedIcon; }
-
- button {
- cursor : pointer;
- }
- }
-
- .input-group {
- height : ~'calc(.9em + 4px + .6em)';
-
- input { border-radius : 0.5em 0 0 0.5em; }
-
- input:last-child { border-radius : 0.5em; }
-
- .value {
- width : 7.5vw;
- min-width : 75px;
- height : 100%;
- }
-
- .input-group {
- height : ~'calc(.9em + 4px + .6em)';
-
- input { border-radius : 0.5em 0 0 0.5em; }
-
- input:last-child { border-radius : 0.5em; }
-
- .value {
- width : 7.5vw;
- min-width : 75px;
- height : 100%;
- }
-
- .invalid:focus { background-color : pink; }
-
- .icon {
- #groupedIcon;
- top : -0.54em;
- right : 1px;
- height : 97%;
-
- i { font-size : 1.125em; }
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/client/homebrew/editor/settingsEditor/settingsEditor.jsx b/client/homebrew/editor/settingsEditor/settingsEditor.jsx
new file mode 100644
index 000000000..294d148b3
--- /dev/null
+++ b/client/homebrew/editor/settingsEditor/settingsEditor.jsx
@@ -0,0 +1,143 @@
+import '../uiEditor.less';
+import React from 'react';
+
+const SettingsEditor = ({ settings, updateSettings = ()=>{}, EditorThemeNameList })=>{
+
+ const validations = {};
+
+ const handleFieldChange = (setting, e)=>{
+ const value =
+ e.target.type === 'checkbox'
+ ? e.target.checked
+ : e.target.value;
+
+ const inputRules = validations[setting] ?? [];
+
+ const validationErrors = inputRules
+ .map((rule)=>rule(value))
+ .filter(Boolean);
+
+ if(validationErrors.length > 0) {
+ e.target.setCustomValidity(validationErrors.join('\n'));
+ e.target.reportValidity();
+ return;
+ }
+
+ e.target.setCustomValidity('');
+
+ const updatedSettings = {
+ ...settings,
+ [setting] : e.target.type === 'number'
+ ? Number(value)
+ : value,
+ };
+
+ updateSettings(updatedSettings);
+ };
+
+ return (
+
+
Editor Settings
+
+
+
+
+
+
+
+
+
+
+
+ handleFieldChange('autoCloseBrackets', e)}
+ />
+
+
+
+
+
+
+ handleFieldChange('showImagePreviews', e)}
+ />
+
+
+
+
+
+
+ handleFieldChange('activeLineShading', e)}
+ />
+
+
+
+
+
+
+
+ handleFieldChange('lineNumbers', e)}
+ />
+
+
+
+
+
+
+
+ from 7px to 26px
+ handleFieldChange('fontSize', e)}
+ />
+
+
+
+
+
+ );
+};
+
+export default SettingsEditor;
\ No newline at end of file
diff --git a/client/homebrew/editor/snippetbar/snippetbar.jsx b/client/homebrew/editor/snippetbar/snippetbar.jsx
index 4bc46723c..9aa6b5ab7 100644
--- a/client/homebrew/editor/snippetbar/snippetbar.jsx
+++ b/client/homebrew/editor/snippetbar/snippetbar.jsx
@@ -10,6 +10,7 @@ import cx from 'classnames';
import { loadHistory } from '../../utils/versionHistory.js';
import { brewSnippetsToJSON } from '@shared/helpers.js';
+/*eslint-disable camelcase*/
import Legacy5ePHB from '@themes/Legacy/5ePHB/snippets.js';
import V3_5ePHB from '@themes/V3/5ePHB/snippets.js';
import V3_5eDMG from '@themes/V3/5eDMG/snippets.js';
@@ -23,26 +24,7 @@ const ThemeSnippets = {
V3_Journal : V3_Journal,
V3_Blank : V3_Blank,
};
-
-import defaultCM5Theme from '@themes/codeMirror/default.js';
-import darkbrewery from '@themes/codeMirror/darkbrewery.js';
-import cm5Themes from 'codemirror-5-themes';
-
-const themes = { default: defaultCM5Theme, ...cm5Themes, darkbrewery };
-
-const themeNames = Object.entries(themes)
- .filter(([name, value])=>Array.isArray(value) &&
- !name.endsWith('Init') &&
- !name.endsWith('Style')
- )
- .map(([name])=>name);
-
-const EditorThemes = [
- 'default',
- ...themeNames
- .filter((name)=>name !== 'default')
- .sort((a, b)=>a.localeCompare(b))
-];
+/*eslint-enable camelcase */
const execute = function(val, props){
if(_.isFunction(val)) return val(props);
@@ -53,30 +35,28 @@ const Snippetbar = createReactClass({
displayName : 'SnippetBar',
getDefaultProps : function() {
return {
- brew : {},
- view : 'text',
- onViewChange : ()=>{},
- onInject : ()=>{},
- onToggle : ()=>{},
- showEditButtons : true,
- renderer : 'legacy',
- undo : ()=>{},
- redo : ()=>{},
- historySize : ()=>{},
- foldCode : ()=>{},
- unfoldCode : ()=>{},
- formatCode : ()=>{},
- updateEditorTheme : ()=>{},
- cursorPos : {},
- themeBundle : [],
- updateBrew : ()=>{}
+ brew : {},
+ view : 'text',
+ onViewChange : ()=>{},
+ onInject : ()=>{},
+ onToggle : ()=>{},
+ showEditButtons : true,
+ renderer : 'legacy',
+ undo : ()=>{},
+ redo : ()=>{},
+ historySize : ()=>{},
+ foldCode : ()=>{},
+ unfoldCode : ()=>{},
+ formatCode : ()=>{},
+ cursorPos : {},
+ themeBundle : [],
+ updateBrew : ()=>{}
};
},
getInitialState : function() {
return {
renderer : this.props.renderer,
- themeSelector : false,
snippets : [],
showHistory : false,
historyExists : false,
@@ -93,7 +73,6 @@ const Snippetbar = createReactClass({
componentDidUpdate : async function(prevProps, prevState) {
if(prevProps.renderer != this.props.renderer ||
- prevProps.theme != this.props.theme ||
prevProps.themeBundle != this.props.themeBundle ||
prevProps.brew.snippets != this.props.brew.snippets) {
this.setState({
@@ -158,33 +137,6 @@ const Snippetbar = createReactClass({
this.props.onInject(injectedText);
},
- toggleThemeSelector : function(e){
- if(e.target.tagName != 'SELECT'){
- this.setState({
- themeSelector : !this.state.themeSelector
- });
- }
- },
-
- changeTheme : function(e){
- if(e.target.value == this.props.currentEditorTheme) return;
- this.props.updateEditorTheme(e.target.value);
-
- this.setState({
- themeSelector : false,
- });
- },
-
- renderThemeSelector : function(){
- return
-
-
;
- },
-
renderSnippetGroups : function(){
const snippets = this.state.snippets.filter((snippetGroup)=>snippetGroup.view === this.props.view);
if(snippets.length === 0) return null;
@@ -246,7 +198,7 @@ const Snippetbar = createReactClass({
return (
- {this.props.view !== 'meta' && <>
+ {this.props.view !== 'meta' && this.props.view !== 'settings' && <>
-
>}
@@ -298,6 +245,10 @@ const Snippetbar = createReactClass({
onClick={()=>this.props.onViewChange('meta')}>
+
@@ -346,7 +297,7 @@ const SnippetGroup = createReactClass({
{this.renderSnippets(snippet.subsnippets)}
- )
+ );
}
});
diff --git a/client/homebrew/editor/snippetbar/snippetbar.less b/client/homebrew/editor/snippetbar/snippetbar.less
index 7b96fa523..10c67a817 100644
--- a/client/homebrew/editor/snippetbar/snippetbar.less
+++ b/client/homebrew/editor/snippetbar/snippetbar.less
@@ -3,8 +3,10 @@
@import (less) '@themes/fonts/5e/fonts.less';
.snippetBar {
- --activeTriggerColor: inherit;
--menuColor : #DDDDDD;
+ --textColor : black;
+ --hoverMenuColor : #999;
+
@menuHeight : 25px;
position : relative;
display : flex;
@@ -12,8 +14,8 @@
reading-flow : flex-visual;
justify-content : space-between;
height : auto;
- color : black;
- background-color : #DDDDDD;
+ color : var(--textColor);
+ background-color : var(--menuColor);
font-size : .65rem;
font-family: 'Open Sans', sans-serif;
text-transform: uppercase;
@@ -23,7 +25,7 @@
display : flex;
justify-content : flex-end;
min-width : 275px; //must be controlled every time an item is added, must be hardcoded for the wrapping as it is applied
- font-size: .85rem;
+ font-size : 0.85rem;
&:only-child {min-width : unset; margin-left : auto;}
reading-order : 2;
@@ -44,7 +46,7 @@
&.editorTool:not(.active) { cursor : not-allowed; }
- &:hover,&.selected { background-color : #999999; }
+ &:hover,&.selected { background-color : var(--hoverMenuColor) }
&.text {
.tooltipLeft('Brew Editor');
}
@@ -101,11 +103,6 @@
background-color : #999999;
}
}
- &.divider {
- width : 5px;
- background : linear-gradient(currentColor, currentColor) no-repeat center/1px 100%;
- &:hover { background-color : inherit; }
- }
}
.themeSelector {
position : absolute;
@@ -138,36 +135,32 @@
}
// removed caret for top level items, by request (makes buttons too wide).
- .menu-wrapper .menu-item:is(.snippets > .menu-wrapper > .menu-item):first-child .caret { display: none; }
+ .menu-wrapper .menu-item:is(.snippets > .menu-wrapper > .menu-item):first-child .caret { display : none; }
.menu-item {
- position : relative;
- display : flex;
- justify-content: space-between;
- align-items : center;
- min-width : max-content;
- padding : 5px;
- cursor : pointer;
- width: 100%;
- &:is(.menu-list .menu-item) [class*="name"] {
- padding-inline: 8px; // additional space between icon and name (helpful in Fonts menu especially).
+ position : relative;
+ display : flex;
+ align-items : center;
+ justify-content : space-between;
+ width : 100%;
+ min-width : max-content;
+ padding : 5px;
+ cursor : pointer;
+ &:is(.menu-list .menu-item) [class*='name'] {
+ padding-inline : 8px; // additional space between icon and name (helpful in Fonts menu especially).
}
.menu-name {
- flex: 1;
- text-align: left;
- text-box-trim: trim-end;
+ flex : 1;
+ text-align : left;
+ text-box-trim : trim-end;
}
i {
min-width : 25px;
- height : .85rem;
+ height : 0.85rem;
font-size : 1.2em;
text-align : center;
- &.caret {
- margin-right: 0;
- }
- &.caret:is(.menu-wrapper .menu-wrapper * ) {
- text-align: right;
- }
+ &.caret { margin-right : 0; }
+ &.caret:is(.menu-wrapper .menu-wrapper *) { text-align : right; }
/* Fonts */
&.font {
height : auto;
@@ -207,17 +200,17 @@
border-radius : 12px;
}
&:hover {
- background-color : #999999;
+ background-color : var(--hoverMenuColor);
}
&:disabled {
- color: gray;
- cursor: not-allowed;
- &:hover { background-color: unset; }
+ color : gray;
+ cursor : not-allowed;
+ &:hover { background-color : unset; }
}
}
}
@container editor (width < 841px) {
- .snippetBar {
+ .snippetBar {
.editors {
flex : 1;
justify-content : space-between;
@@ -233,3 +226,8 @@
}
}
+.editor.darkMode .snippetBar {
+ --menuColor : #666;
+ --textColor : #eee;
+ --hoverMenuColor : #444;
+}
diff --git a/client/homebrew/editor/tagInput/tagInput.jsx b/client/homebrew/editor/tagInput/tagInput.jsx
index 2ec4b3db9..a153fef8b 100644
--- a/client/homebrew/editor/tagInput/tagInput.jsx
+++ b/client/homebrew/editor/tagInput/tagInput.jsx
@@ -4,7 +4,7 @@ import Combobox from '@components/combobox.jsx';
import { tagSuggestionList, canonizationList } from './curatedTagSuggestionList.js';
-const TagInput = ({ tooltip, label, valuePatterns, values = [], unique = true, placeholder = '', smallText = '', onChange })=>{
+const TagInput = ({ id, tooltip, label, valuePatterns, values = [], unique = true, placeholder = '', smallText = '', onChange })=>{
const [tagList, setTagList] = useState(
values.map((value)=>({
value,
@@ -128,6 +128,7 @@ const TagInput = ({ tooltip, label, valuePatterns, values = [], unique = true, p
return (
{tagList.map((t, i)=>t.editing ? (
div ,& > fieldset { margin-bottom : 10px; }
+
+ .field-group {
+ display : flex;
+ flex-wrap : wrap;
+ gap : 10px;
+ width : 100%;
+ }
+
+ .field-column {
+ display : flex;
+ flex : 5 0 250px;
+ flex-direction : column;
+ gap : 10px;
+ }
+
+ .field {
+ position : relative;
+ display : flex;
+ flex-wrap : wrap;
+ width : 100%;
+ min-width : 250px;
+ padding-left : 10px;
+
+ & > label {
+ width : 100px;
+ font-size : 1em;
+ font-weight : 800;
+ line-height : 1.8em;
+ color : inherit;
+ text-transform : capitalize;
+ }
+ & > .value {
+ flex : 1 1 auto;
+ width : 50px;
+ &[data-tooltip-right] { max-width : 380px; }
+ &:invalid { background : #FFB9B9; }
+ small {
+ display : block;
+ width : fit-content;
+ margin-inline : 5px;
+ font-size : 0.9em;
+ font-style : italic;
+ line-height : 1.4em;
+ }
+
+ }
+
+ input[type='checkbox'], input[type='number'] {
+ float : right;
+ text-align : end;
+ }
+ input[type='text'], textarea, select {
+ color : var(--input-text-clr);
+ background-color : var(--input-bg);
+ border : 1px solid var(--input-placeholder-clr);
+ &:hover, :focus { outline : 1px solid var(--input-placeholder-clr); background-color : var(--input-bg-hover); }
+ &::placeholder { color : var(--input-placeholder-clr); }
+ }
+
+ input[type='range'] {
+ color: var(--input-text-clr);
+ }
+
+ &.description {
+ flex : 1;
+ textarea.value {
+ height : auto;
+ font-family : 'Open Sans', sans-serif;
+ resize : none;
+ }
+ }
+ &.thumbnail, &.themes {
+ label { line-height : 2.0em; }
+ .value {
+ overflow : hidden;
+ text-overflow : ellipsis;
+ }
+ button {
+ .colorButton();
+ padding : 0px 5px;
+ color : var(--input-text-clr);
+ background-color : var(--input-bg);
+ border : 1px solid #999999;
+ &:hover { background-color : #777777; }
+ }
+ }
+ &.tags .tagInput-dropdown {
+ z-index : 400;
+ max-width : 200px;
+
+ .dropdown-options {
+ color : var(--input-text-clr);
+ background-color : var(--input-bg);
+
+ .item:hover {
+ color : var(--input-bg);
+ background-color : var(--input-text-clr);
+ }
+ }
+ }
+ &.language .value {
+ z-index : 300;
+ max-width : 150px;
+ }
+ &.themes {
+ .value {
+ overflow : visible;
+ }
+ button {
+ padding-right : 5px;
+ padding-left : 5px;
+ }
+ & .dropdown-container { z-index : 200; }
+ & .dropdown-options { overflow-y : visible; }
+ .disabled {
+ font-style : italic;
+ color : dimgray;
+ background-color : darkgray;
+ }
+ .item.dropdown-input { border:none;}
+ .item {
+ position : relative;
+ overflow : visible;
+ color : inherit;
+ background-color : var(--input-bg);
+ border-top : 1px solid #767676;
+ .preview {
+ position : absolute;
+ top : 0;
+ right : 0;
+ z-index : 10;
+ display : flex;
+ flex-direction : column;
+ width : 200px;
+ overflow : hidden;
+ color : var(--input-text-clr);
+ background : var(--input-bg);
+ border-radius : 5px;
+ box-shadow : 0 0 5px var(--input-text-clr);
+ opacity : 0;
+ transition : opacity 250ms ease;
+ h6 {
+ padding-block : 0.5em;
+ padding-inline : 1em;
+ font-weight : 900;
+ border-bottom : 2px solid #666666;
+ }
+ }
+
+ input { padding-right : 25px; }
+
+ .texture-container {
+ position : absolute;
+ top : 0;
+ left : 0;
+ width : 100%;
+ height : 100%;
+ min-height : 100%;
+ overflow : hidden;
+ > img {
+ position : absolute;
+ top : 0;
+ right : 0;
+ width : 50%;
+ min-height : 100%;
+ -webkit-mask-image : linear-gradient(90deg, transparent, black 20%);
+ mask-image : linear-gradient(90deg, transparent, black 20%);
+ }
+ }
+
+ &:hover > .preview { opacity : 1; }
+ }
+ }
+ &.renderers .value {
+ label {
+ display : inline-flex;
+ align-items : center;
+ margin-right : 15px;
+ font-size : 0.9em;
+ font-weight : 800;
+ vertical-align : middle;
+ white-space : nowrap;
+ cursor : pointer;
+ user-select : none;
+ }
+ input {
+ margin : 3px;
+ vertical-align : middle;
+ cursor : pointer;
+ }
+ }
+
+ &.authors {
+ .tag {
+ font-weight : 300;
+ transition : background-color 0.2s;
+
+ &.owner {
+ position : relative;
+ display : grid;
+ place-items : center;
+ min-width : 25px;
+ font-weight : 900;
+ background-color : @silverLight;
+
+ &::after {
+ position : absolute;
+ top : 0;
+ left : 0;
+ width : 15px;
+ height : 15px;
+ font-family : 'Font Awesome 6 Free';
+ color : gold;
+ content : '\f521';
+ transform : scaleY(0.7);
+ rotate : -25deg;
+ translate : -30% -50%;
+ }
+ }
+ &:has(button) a { padding-right : 5px; }
+ &:has(button:hover) { background : #D97D7D; }
+
+ button { color : @red; }
+
+ }
+ a { text-underline-offset : 0.2em; }
+ }
+ &.invitedAuthors .value {
+ z-index : 100;
+
+ .tagInput-dropdown { max-width : 200px; }
+ }
+
+ &.publish .value {
+ position : relative;
+ margin-bottom : 15px;
+ button { width : 100%; }
+ button.publish {
+ .colorButton(@blueLight);
+ }
+ button.unpublish {
+ .colorButton(@silver);
+ }
+ }
+ &.delete .value {
+ button {
+ .colorButton(@red);
+ }
+ }
+
+ .list {
+ display : flex;
+ flex : 1 0;
+ flex-wrap : wrap;
+
+ > * { flex : 0 0 auto; }
+
+ #groupedIcon {
+ #backgroundColors;
+ position : relative;
+ top : -0.3em;
+ right : -0.3em;
+ display : inline-block;
+ min-width : 20px;
+ height : ~'calc(100% + 0.6em)';
+ color : white;
+ text-align : center;
+ cursor : pointer;
+
+ i {
+ position : relative;
+ top : 50%;
+ transform : translateY(-50%);
+ }
+
+ &:not(:last-child) { border-right : 1px solid black; }
+
+ &:last-child { border-radius : 0 0.5em 0.5em 0; }
+ }
+
+ .tag {
+ padding : 0.35em;
+ margin : 2px;
+ font-size : 0.95em;
+ border-radius : 0.5em;
+
+ .icon { #groupedIcon; }
+
+ button {
+ cursor : pointer;
+
+ &:hover { color : @redLight; }
+ }
+ }
+
+ .input-group {
+ height : ~'calc(.9em + 4px + .6em)';
+
+ input { border-radius : 0.5em 0 0 0.5em; }
+
+ input:last-child { border-radius : 0.5em; }
+
+ .value {
+ width : 7.5vw;
+ min-width : 75px;
+ height : 100%;
+ }
+
+ .input-group {
+ height : ~'calc(.9em + 4px + .6em)';
+
+ input { border-radius : 0.5em 0 0 0.5em; }
+
+ input:last-child { border-radius : 0.5em; }
+
+ .value {
+ width : 7.5vw;
+ min-width : 75px;
+ height : 100%;
+ }
+
+ .invalid:focus { background-color : pink; }
+
+ .icon {
+ #groupedIcon;
+ top : -0.54em;
+ right : 1px;
+ height : 97%;
+
+ i { font-size : 1.125em; }
+ }
+ }
+ }
+ }
+ }
+
+ .thumbnail-preview {
+ position : relative;
+ flex : 1 1;
+ justify-self : center;
+ width : 80px;
+ height : min-content;
+ max-height : 115px;
+ aspect-ratio : 1 / 1;
+ object-fit : contain;
+ background-color : #AAAAAA;
+ }
+
+ .tag {
+ color : var(--input-bg);
+ background : var(--input-text-clr);
+ }
+}
+
+.settingsEditor .field {
+ padding-bottom : 10px;
+ border-bottom : 1px solid black;
+
+ .value {
+
+ display : flex;
+ justify-content : end;
+ }
+
+ > label {
+ width : fit-content;
+ max-width : calc(100% - 200px);
+ }
+}
+
+.editor.darkMode .uiEditor {
+ --bg-clr : #555555;
+ --bg-image : @backgroundImageAltDark;
+ --h1-clr : white;
+ --h2-clr : #AAAAFF;
+ --label-clr : #DDDDDD;
+ --input-bg : #333333;
+ --input-bg-hover : #666666;
+ --input-text-clr : #EEEEEE;
+ --input-placeholder-clr : #AAAAAA;
+
+ .field { border-color : var(--h1-clr); }
+
+ a {
+ color : @blueLight;
+
+ &:visited { color : #CB8AD8; }
+ }
+
+ .thumbnail-preview[src='/client/homebrew/thumbnail.png'] { filter : invert(0.8); }
+ button.publish {
+ .colorButton(#3137de) !important;
+ }
+}
\ No newline at end of file
diff --git a/client/homebrew/homebrew.jsx b/client/homebrew/homebrew.jsx
index 716291764..1ee5efa2a 100644
--- a/client/homebrew/homebrew.jsx
+++ b/client/homebrew/homebrew.jsx
@@ -46,7 +46,7 @@ const Homebrew = (props)=>{
global.enablev4 = enablev4;
const backgroundObject = ()=>{
- if(config?.deployment || (config?.local && config?.development)) {
+ if(config?.deployment || config?.developmentStyle) {
const bgText = config?.deployment || 'Local';
return {
backgroundImage : `url("data:image/svg+xml;utf8,")`
@@ -60,7 +60,7 @@ const Homebrew = (props)=>{
if(brew.pureError) {
return (
-
+
} />
@@ -72,7 +72,7 @@ const Homebrew = (props)=>{
return (
-
+
} />
} />
diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx
index 4033d0193..dbf3ac9cb 100644
--- a/client/homebrew/pages/editPage/editPage.jsx
+++ b/client/homebrew/pages/editPage/editPage.jsx
@@ -294,7 +294,6 @@ const EditPage = (props)=>{
lang={currentBrew.lang}
onPageChange={setCurrentBrewRendererPageNum}
currentEditorCursorPageNum={currentEditorCursorPageNum}
- currentBrewRendererPageNum={currentBrewRendererPageNum}
allowPrint={true}
/>
diff --git a/client/homebrew/pages/homePage/homePage.jsx b/client/homebrew/pages/homePage/homePage.jsx
index ef2853792..1d35ef0e1 100644
--- a/client/homebrew/pages/homePage/homePage.jsx
+++ b/client/homebrew/pages/homePage/homePage.jsx
@@ -141,7 +141,6 @@ const HomePage =(props)=>{
themeBundle={themeBundle}
onPageChange={setCurrentBrewRendererPageNum}
currentEditorCursorPageNum={currentEditorCursorPageNum}
- currentBrewRendererPageNum={currentBrewRendererPageNum}
/>
diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx
index c4eee3e8d..edf4d2125 100644
--- a/client/homebrew/pages/newPage/newPage.jsx
+++ b/client/homebrew/pages/newPage/newPage.jsx
@@ -188,7 +188,6 @@ const NewPage = (props)=>{
lang={currentBrew.lang}
onPageChange={setCurrentBrewRendererPageNum}
currentEditorCursorPageNum={currentEditorCursorPageNum}
- currentBrewRendererPageNum={currentBrewRendererPageNum}
allowPrint={true}
/>
diff --git a/client/homebrew/pages/sharePage/sharePage.jsx b/client/homebrew/pages/sharePage/sharePage.jsx
index 99ef3e35c..5280fc850 100644
--- a/client/homebrew/pages/sharePage/sharePage.jsx
+++ b/client/homebrew/pages/sharePage/sharePage.jsx
@@ -149,7 +149,6 @@ const SharePage = (props)=>{
theme={currentBrew.theme}
themeBundle={themeBundle}
onPageChange={handleBrewRendererPageChange}
- currentBrewRendererPageNum={currentBrewRendererPageNum}
allowPrint={true}
/>
diff --git a/config/default.json b/config/default.json
index e55903405..37cb24f7d 100644
--- a/config/default.json
+++ b/config/default.json
@@ -1,5 +1,5 @@
{
- "development": true,
+ "development_style": false,
"host" : "homebrewery.local.naturalcrit.com:8000",
"naturalcrit_url" : "local.naturalcrit.com:8010",
"secret" : "secret",
diff --git a/server/app.js b/server/app.js
index faae8adbb..0c4201377 100644
--- a/server/app.js
+++ b/server/app.js
@@ -277,11 +277,12 @@ export default async function createApp(vite) {
// Create configuration object
const configuration = {
- local : isLocalEnvironment,
- publicUrl : config.get('publicUrl') ?? '',
- baseUrl : `${req.protocol}://${req.get('host')}`,
- environment : nodeEnv,
- deployment : config.get('heroku_app_name') ?? ''
+ local : isLocalEnvironment,
+ publicUrl : config.get('publicUrl') ?? '',
+ baseUrl : `${req.protocol}://${req.get('host')}`,
+ environment : nodeEnv,
+ deployment : config.get('heroku_app_name') ?? '',
+ developmentStyle : config.get('development_style')
};
const props = {
version : version,
@@ -311,9 +312,14 @@ export default async function createApp(vite) {
html = await vite.transformIndexHtml(req.originalUrl, html);
}
+ const safeProps = JSON.stringify(props).replace(/<(?=\/?script)/ig, '\\u003c');
html = html.replace(
'',
- ()=>{ return `\n\n${ogMetaTags}`; }
+ `\n`
+ + `\n`
+ + ogMetaTags
);
return html;
diff --git a/themes/assets/assets.less b/themes/assets/assets.less
index f880bce77..6515ef417 100644
--- a/themes/assets/assets.less
+++ b/themes/assets/assets.less
@@ -2,12 +2,14 @@
@footerAccentImage : url('/assets/PHB_footerAccent.png');
@frameBorderImage : url('/assets/frameBorder.png');
@backgroundImage : url('/assets/parchmentBackground.jpg');
+@backgroundImageAlt : url('/assets/fluffy_background.webp');
+@backgroundImageAltDark : url('/assets/fluffy_background_dark.webp');
@redTriangleImage : url('/assets/redTriangle.png');
@monsterBorderImageLegacy : url('/assets/monsterBorderLegacy.png');
@noteBorderImage : url('/assets/noteBorder.png');
@descriptiveBoxImage : url('/assets/descriptiveBorder.png');
@monsterBlockBackground : url('/assets/parchmentBackgroundGrayscale.jpg');
-@monsterBlockOverlay : url('/assets/parchmentBackgroundOverlayed.jpg');
+@monsterBlockOverlay : url('/assets/parchmentBackgroundOverlayed.jpg');
@monsterBorderImage : url('/assets/monsterBorderFancy.png');
@codeBorderImage : url('/assets/codeBorder.png');
@classTableDecoration : url('/assets/classTableDecoration.png');
diff --git a/themes/assets/fluffy_background.webp b/themes/assets/fluffy_background.webp
new file mode 100644
index 000000000..90292d55b
Binary files /dev/null and b/themes/assets/fluffy_background.webp differ
diff --git a/themes/assets/fluffy_background_dark.webp b/themes/assets/fluffy_background_dark.webp
new file mode 100644
index 000000000..16aee37d4
Binary files /dev/null and b/themes/assets/fluffy_background_dark.webp differ