Merge branch 'master' of https://github.com/naturalcrit/homebrewery into fix-codemirror

This commit is contained in:
Víctor Losada Hernández
2026-09-28 23:05:19 +02:00
62 changed files with 5127 additions and 8251 deletions
+3
View File
@@ -6,6 +6,9 @@ updates:
interval: daily
open-pull-requests-limit: 99
groups:
eslint-bundle:
patterns: ["*eslint*"]
update-types: ["patch", "minor", "major"]
dev-dependencies:
dependency-type: "development"
patterns: ["*"]
+4 -4
View File
@@ -107,14 +107,14 @@ body {
}
th, td {
max-width : 50ch;
padding : 5px 10px;
overflow : hidden;
text-overflow : ellipsis;
vertical-align : middle;
text-align : center;
white-space : nowrap;
border-right : 1px solid;
max-width:50ch;
overflow:hidden;
text-overflow: ellipsis;
white-space: nowrap;
&:last-child { border-right : none; }
}
@@ -10,7 +10,7 @@ const BrewCleanup = ({})=>{
const [error, setError] = useState(null);
const find = async (type)=>{
if(type === 'junk') try {
setPendingJunk(true);
@@ -109,18 +109,18 @@ const BrewCleanup = ({})=>{
<td style={{ width: '200px' }}>{Moment(brew.updatedAt).fromNow()}</td>
<td>{brew.lastViewed ? Moment(brew.lastViewed).fromNow() : 'No last viewed date'}</td>
<td>{brew.googleId ? 'Google' : 'Homebrewery'}</td>
</tr>
</tr>;
})}
</tbody>
</table>
</>;
};
const renderFound = (type)=>{
const deleteButton = !(type === 'junk' && junkBrewCollection.length === 0 || type === 'lost' && lostBrewCollection.length === 0);
const deleteButton = !(type === 'junk' && junkBrewCollection.length === 0 || type === 'lost' && lostBrewCollection.length === 0);
return <div className='result'>
{deleteButton && <button onClick={()=>cleanup(type)} className='remove'>
{pendingLost && type === "lost" || pendingJunk && type === "junk"
{pendingLost && type === 'lost' || pendingJunk && type === 'junk'
? <i className='fas fa-spin fa-spinner' />
: <span><i className='fas fa-times' /> Remove</span>
}
+2 -2
View File
@@ -16,7 +16,7 @@
margin-left : 10px;
}
&.checkbox {
line-height: 1.5em;
line-height : 1.5em;
input {
width : 1.5em;
height : 1.5em;
@@ -26,9 +26,9 @@
}
.lockSuggestions {
columns : 2;
line-height : 1.2em;
break-inside : avoid;
columns : 2;
h2 { column-span : all; }
h3 { margin-top : 0px; }
b { font-weight : 600; }
+1 -1
View File
@@ -2,8 +2,8 @@
.anchored-box {
position : absolute;
inset-block-start : anchor(bottom);
visibility : hidden;
justify-self : anchor-center;
inset-block-start : anchor(bottom);
&.active { visibility : visible; }
}
@@ -1,6 +1,6 @@
/*
This file basically checks support for Anchor Positioning API in the browser,
and then loads the Oddbird polyfill if support is lacking.
and then loads the Oddbird polyfill if support is lacking.
*/
let polyfillPromise;
+1 -1
View File
@@ -46,7 +46,7 @@ const settingsCompartment = new Compartment();
import { generalKeymap, markdownKeymap, cssKeymap, formatCSS } from './extensions/customKeyMaps.js';
import foldOnPages from './extensions/customFolding.js';
import { customHighlightStyle , customHighlightPlugin } from './extensions/customHighlight.js';
import { customHighlightStyle, customHighlightPlugin } from './extensions/customHighlight.js';
import { legacyCustomHighlightStyle } from './extensions/legacyCustomHighlight.js';
const PAGEBREAK_REGEX_V3 = /^(?=\\page(?:break)?(?: *{[^\n{}]*})?$)/m;
+39 -44
View File
@@ -16,15 +16,15 @@
}
@keyframes slideacross {
0% {
bottom: -200px;
left: -200px;
}
0% {
bottom : -200px;
left : -200px;
}
100% {
bottom:100%;
left:100%;
}
100% {
bottom : 100%;
left : 100%;
}
}
:where(.codeEditor) {
@@ -37,22 +37,22 @@
outline : none !important;
&.cm-flash {
position:relative;
position : relative;
&::after {
position:absolute;
content:'';
bottom:-200px;
left:-200px;
translate:-50%;
width:200%;
height:100px;
background:linear-gradient(0deg, #89eafc00 0px, #89ebfc8e 50px, #89eafc00 100px, transparent);
display:block;
position : absolute;
bottom : -200px;
left : -200px;
display : block;
width : 200%;
height : 100px;
content : '';
background : linear-gradient(0deg, #89EAFC00 0px, #89EBFC8E 50px, #89EAFC00 100px, transparent);
rotate:30deg;
rotate : 30deg;
translate : -50%;
@media screen and (prefers-reduced-motion: no-preference) {
animation: .5s linear 1 slideacross ;
@media screen and (prefers-reduced-motion : no-preference) {
animation : 0.5s linear 1 slideacross;
}
}
}
@@ -134,9 +134,7 @@
vertical-align : sub;
color : rgb(123, 123, 15);
}
.cm-strikethrough {
text-decoration: line-through;
}
.cm-strikethrough { text-decoration : line-through; }
.cm-definitionList {
.cm-definitionTerm { color : rgb(96, 117, 143); }
@@ -196,30 +194,27 @@
}
.cm-image {
position:relative;
position : relative;
.cm-preview {
object-fit: contain;
position:absolute;
bottom:0;
left:0;
height:200px;
width:200px;
height:200px;
padding:5px;
background-color: #fff;
border-radius:10px;
border:3px solid grey;
pointer-events: none;
opacity:0;
transition:0.2s opacity 0.5s;
translate:0 100%;
z-index:1000;
position : absolute;
bottom : 0;
left : 0;
z-index : 1000;
width : 200px;
height : 200px;
padding : 5px;
pointer-events : none;
object-fit : contain;
background-color : #FFFFFF;
border : 3px solid grey;
border-radius : 10px;
opacity : 0;
translate : 0 100%;
transition : 0.2s opacity 0.5s;
}
&:hover .cm-preview {
opacity:1;
}
&:hover .cm-preview { opacity : 1; }
}
/* Tab character visualization (optional) */
+1 -1
View File
@@ -7,7 +7,7 @@ const Combobox = createReactClass({
displayName : 'Combobox',
getDefaultProps : function() {
return {
id : '',
id : '',
className : '',
trigger : 'hover',
default : '',
+2 -4
View File
@@ -31,14 +31,12 @@
font-family : 'Open Sans';
font-size : 11px;
cursor : default;
&:hover {
background-color : #ddd;
}
&:hover { background-color : #DDDDDD; }
.detail {
width : 100%;
font-size : 9px;
font-style : italic;
color : #7c7c7c;
color : #7C7C7C;
text-align : left;
}
}
+2 -2
View File
@@ -1,11 +1,11 @@
/**
* A dropdown menu component that uses the Anchor Positioning API to position the elements. It supports nested submenus as well.
* Anchor Positioning is now supported in all major browsers. A polyfill is conditionally loaded for older browsers.
*
*
* As-is, the menus will always open down aligned on left to trigger, submenus open to the right initially.
* If no space, menus will still open down, but aligned to the right of the trigger. Submenus will flip to the other side of the top menu.
* This could be customized either in more specific CSS, or as a `direction` prop on the component (in future iterations).
*
*
* @param {string} props.groupName - Name of the menu. Appears as the trigger text.
* @param {string} [props.icon] - Icon to display in the trigger.
* @param {string} [props.color] - Color class to add to the trigger.
+18 -20
View File
@@ -1,37 +1,35 @@
@property --menuColor {
syntax: '<color>';
inherits: true;
initial-value: #DDD;
syntax : '<color>';
inherits : true;
initial-value : #DDDDDD;
}
@property --activeTriggerColor {
syntax: '<color>';
inherits: true;
initial-value: #999;
syntax : '<color>';
inherits : true;
initial-value : #999999;
}
:root{
--activeTriggerColor : var(--activeTriggerColor);
}
:root { --activeTriggerColor : var(--activeTriggerColor); }
.menu-list {
contain : content;
position : fixed;
top : anchor(bottom);
left : anchor(left);
position-try: flip-inline flip-block;
color: inherit; // [popover] gets a `canvastext` color value from useragent.
background: var(--menuColor);
position-try : flip-inline flip-block;
contain : content;
color : inherit; // [popover] gets a `canvastext` color value from useragent.
background : var(--menuColor);
li > .menu-list {
margin: 0 0px;
top : anchor(top);
left : anchor(right);
position-try: flip-inline;
}
top : anchor(top);
left : anchor(right);
margin : 0 0px;
position-try : flip-inline;
}
}
.menu-wrapper:has(:popover-open) > button { // if menu is open...
background-color: var(--activeTriggerColor, hsl(from var(--menuColor) h s calc(l * .85))); // tint menu triggers based on menu color
background-color : var(--activeTriggerColor, hsl(from var(--menuColor) h s calc(l * 0.85))); // tint menu triggers based on menu color
}
.darkMode .menu-wrapper:has(:popover-open) > button { // if menu is open...
--activeTriggerColor : #444; // tint menu triggers based on menu color
--activeTriggerColor : #444444; // tint menu triggers based on menu color
}
@@ -103,8 +103,8 @@ const BrewRenderer = (props)=>{
const pagesRef = useRef(null);
const [visiblePages, setVisiblePages] = useState([]);
const [centerPage , setCenterPage ] = useState(1);
const [headerState , setHeaderState ] = useState(false);
const [centerPage, setCenterPage] = useState(1);
const [headerState, setHeaderState] = useState(false);
const [state, setState] = useState({
isMounted : false,
@@ -158,10 +158,9 @@ const BrewRenderer = (props)=>{
return false;
};
const renderDummyPage = (index)=>
<div className='phb page' id={`p${index + 1}`} key={index}>
<i className='fas fa-spinner fa-spin' />
</div>;
const renderDummyPage = (index)=><div className='phb page' id={`p${index + 1}`} key={index}>
<i className='fas fa-spinner fa-spin' />
</div>;
const renderStyle = ()=>{
const themeStyles = props.themeBundle?.joinedStyles ?? '<style>@import url("/themes/V3/Blank/style.css");</style>';
@@ -61,9 +61,7 @@
}
@supports (break-after:always) {
.columnSplit {
margin-bottom: 100vh;
}
.columnSplit { margin-bottom : 100vh; }
}
}
@@ -76,13 +74,11 @@
height : 100%;
padding : unset;
overflow-y : unset;
&:has(.facing, .flow) {
padding : unset;
}
&:has(.facing, .flow) { padding : unset; }
.pages {
display : block;
margin : 0px;
zoom : 100% !important;
display : block;
& > .page { box-shadow : unset; }
}
}
@@ -99,13 +99,13 @@ const ToolBar = ({ displayOptions, onDisplayOptionsChange, visiblePages, totalPa
return (
<div id='preview-toolbar' className={`toolBar ${toolsVisible ? 'visible' : 'hidden'}`} role='toolbar'>
<div className='toggleButton'>
<button data-tooltip-right={`${toolsVisible ? 'Hide' : 'Show'} Preview Toolbar`}
aria-label={`${toolsVisible ? 'Hide' : 'Show'} Preview Toolbar`}
<button data-tooltip-right={`${toolsVisible ? 'Hide' : 'Show'} Preview Toolbar`}
aria-label={`${toolsVisible ? 'Hide' : 'Show'} Preview Toolbar`}
onClick={()=>{ setToolsVisible(!toolsVisible); localStorage.setItem(TOOLBAR_VISIBILITY, !toolsVisible); }}>
<i aria-hidden='true' className='fas fa-glasses' />
</button>
<button data-tooltip-right={`${headerState ? 'Hide' : 'Show'} Header Navigation`}
aria-label={`${headerState ? 'Hide' : 'Show'} Header Navigation`}
<button data-tooltip-right={`${headerState ? 'Hide' : 'Show'} Header Navigation`}
aria-label={`${headerState ? 'Hide' : 'Show'} Header Navigation`}
onClick={()=>{setHeaderState(!headerState);}}>
<i aria-hidden='true' className='fas fa-rectangle-list' />
</button>
@@ -1,4 +1,4 @@
@import (less) './client/icons/customIcons.less';
@import (less) '../../../icons/customIcons.less';
.toolBar {
position : absolute;
@@ -176,9 +176,7 @@
transition : all 0.2s ease;
}
.toggleButton button i {
filter: drop-shadow(0 0 2px black) drop-shadow(0 0 1px black);
}
.toggleButton button i { filter : drop-shadow(0 0 2px black) drop-shadow(0 0 1px black); }
}
}
+1 -1
View File
@@ -338,7 +338,7 @@ const Editor = forwardRef(
view={view}
style={{ display: 'none' }}
editorTheme={editorSettings.editorTheme}
onThemeChange={setIsDark}
onThemeChange={setIsDark}
settings={editorSettings}
/>
<SettingsEditor
@@ -131,7 +131,7 @@ const SettingsEditor = ({ settings, updateSettings = ()=>{}, EditorThemeNameList
onChange={(e)=>handleFieldChange('fontSize', e)}
/>
<datalist id='font-sizes'>
<option value='1' />
<option value='1' />
</datalist>
</div>
@@ -1,25 +1,25 @@
@import '@sharedStyles/core.less';
@import (less) './client/icons/customIcons.less';
@import (less) '../../../icons/customIcons.less';
@import (less) '@themes/fonts/5e/fonts.less';
.snippetBar {
--menuColor : #DDDDDD;
--textColor : black;
--hoverMenuColor : #999;
--hoverMenuColor : #999999;
@menuHeight : 25px;
position : relative;
display : flex;
flex-wrap : wrap-reverse;
reading-flow : flex-visual;
justify-content : space-between;
height : auto;
font-family : 'Open Sans', sans-serif;
font-size : 0.65rem;
font-weight : 800;
color : var(--textColor);
text-transform : uppercase;
background-color : var(--menuColor);
font-size : .65rem;
font-family: 'Open Sans', sans-serif;
text-transform: uppercase;
font-weight: 800;
reading-flow : flex-visual;
.editors {
display : flex;
@@ -46,7 +46,7 @@
&.editorTool:not(.active) { cursor : not-allowed; }
&:hover,&.selected { background-color : var(--hoverMenuColor) }
&:hover,&.selected { background-color : var(--hoverMenuColor); }
&.text {
.tooltipLeft('Brew Editor');
}
@@ -199,9 +199,7 @@
background : grey;
border-radius : 12px;
}
&:hover {
background-color : var(--hoverMenuColor);
}
&:hover { background-color : var(--hoverMenuColor); }
&:disabled {
color : gray;
cursor : not-allowed;
@@ -227,7 +225,7 @@
}
.editor.darkMode .snippetBar {
--menuColor : #666;
--textColor : #eee;
--hoverMenuColor : #444;
--menuColor : #666666;
--textColor : #EEEEEE;
--hoverMenuColor : #444444;
}
+8 -18
View File
@@ -1,30 +1,20 @@
.tags {
.tagInputWrap {
display:grid;
grid-template-columns: 200px 3fr;
gap:10px;
display : grid;
grid-template-columns : 200px 3fr;
gap : 10px;
}
.list input {
border-radius: 5px;
}
.list input { border-radius : 5px; }
.tagInput-dropdown {
.dropdown-options {
.item {
&.type {
background-color: #00800035;
}
&.group {
background-color: #50505035;
}
&.meta {
background-color: #00008035;
}
&.system {
background-color: #80000035;
}
&.type { background-color : #00800035; }
&.group { background-color : #50505035; }
&.meta { background-color : #00008035; }
&.system { background-color : #80000035; }
}
}
}
File diff suppressed because it is too large Load Diff
+3 -7
View File
@@ -105,9 +105,7 @@
&::placeholder { color : var(--input-placeholder-clr); }
}
input[type='range'] {
color: var(--input-text-clr);
}
input[type='range'] { color : var(--input-text-clr); }
&.description {
flex : 1;
@@ -151,9 +149,7 @@
max-width : 150px;
}
&.themes {
.value {
overflow : visible;
}
.value { overflow : visible; }
button {
padding-right : 5px;
padding-left : 5px;
@@ -165,7 +161,7 @@
color : dimgray;
background-color : darkgray;
}
.item.dropdown-input { border:none;}
.item.dropdown-input { border : none;}
.item {
position : relative;
overflow : visible;
+2 -2
View File
@@ -1,7 +1,7 @@
@import '@sharedStyles/core.less';
.homebrew {
height : 100%;
background-color:@steel;
height : 100%;
background-color : @steel;
&.deployment { background-color : darkred; }
.sitePage {
+1 -3
View File
@@ -39,9 +39,7 @@
flex-grow : 1;
min-width : 300px;
}
>.brewTitle {
cursor:auto;
}
>.brewTitle { cursor : auto; }
}
// "NaturalCrit" logo
.navLogo {
+1 -1
View File
@@ -12,7 +12,7 @@ export default function(){
return ()=>{
document.removeEventListener('print:startprep', handlePrintStartPrep);
document.removeEventListener('print:finishedprep', handlePrintPrepFinished);
}
};
}, []);
const handlePrintStartPrep = ()=>{ setPrinting(true); };
@@ -18,7 +18,7 @@
box-shadow : 0px 4px 5px 0px #333333;
break-inside : avoid;
-webkit-column-break-inside : avoid;
page-break-inside : avoid;
break-inside : avoid;
.thumbnail {
position : absolute;
top : 0;
@@ -43,7 +43,7 @@
.info {
position : initial;
bottom : 2px;
font-family : "ScalySansRemake";
font-family : 'ScalySansRemake';
font-size : 1.2em;
& > span {
margin-right : 12px;
@@ -106,26 +106,26 @@
a, button {
.animate(opacity);
display : block;
width : 100%;
margin : 8px 0px;
font-size : 1.3em;
color : white;
text-decoration : unset;
opacity : 0.6;
width : 100%;
&:hover { opacity : 1; }
i { cursor : pointer; }
}
}
.googleDriveIcon {
height : 18px;
padding : 0px;
margin : -5px;
height : 18px;
}
.homebreweryIcon {
position : relative;
padding : 0px;
top : 5px;
left : -7.5px;
height : 18px;
padding : 0px;
}
}
@@ -1,15 +1,15 @@
.noColumns() {
column-count : auto;
column-fill : auto;
column-gap : normal;
-webkit-column-width : auto;
-moz-column-width : auto;
column-width : auto;
-webkit-column-count : auto;
-moz-column-count : auto;
-webkit-column-width : auto;
-moz-column-width : auto;
column-count : auto;
column-fill : auto;
-webkit-column-gap : normal;
-moz-column-gap : normal;
column-gap : normal;
height : auto;
min-height : 279.4mm;
margin : 20px auto;
+2 -2
View File
@@ -9,7 +9,7 @@ import _ from 'lodash';
import { DEFAULT_BREW_LOAD } from '../../../../server/brewDefaults.js';
import useCommonEditPageFunctions from '../../utils/commonEditPageFunctions.jsx'
import useCommonEditPageFunctions from '../../utils/commonEditPageFunctions.jsx';
import SplitPane from '@components/splitPane/splitPane.jsx';
import Editor from '../../editor/editor.jsx';
@@ -163,7 +163,7 @@ const EditPage = (props)=>{
{alertOwnershipToTransfer && (
<div className='errorContainer'>
You must be the Owner to transfer between the Homebrewery and Google Drive!
You must be the Owner to transfer between the Homebrewery and Google Drive!
The owner of this file is {currentBrew.authors[0]}.
<br></br>
<div className='confirm' onClick={closeAlerts}> Okay </div>
+1 -1
View File
@@ -9,7 +9,7 @@ import _ from 'lodash';
import { DEFAULT_BREW } from '../../../../server/brewDefaults.js';
import useCommonEditPageFunctions from '../../utils/commonEditPageFunctions.jsx'
import useCommonEditPageFunctions from '../../utils/commonEditPageFunctions.jsx';
import SplitPane from '@components/splitPane/splitPane.jsx';
import Editor from '../../editor/editor.jsx';
+5 -5
View File
@@ -37,14 +37,14 @@
.navItem.save {
background-color : @orange;
transition:all 0.2s;
transition : all 0.2s;
&:hover { background-color : @green; }
&.neverSaved {
translate:-100%;
opacity: 0;
background-color :#333;
cursor:auto;
cursor : auto;
background-color : #333333;
opacity : 0;
translate : -100%;
}
}
}
+2 -2
View File
@@ -1,4 +1,4 @@
/* eslint-disable max-lines */
import './newPage.less';
// Common imports
@@ -10,7 +10,7 @@ import _ from 'lodash';
import { DEFAULT_BREW } from '../../../../server/brewDefaults.js';
import { printCurrentBrew, fetchThemeBundle, splitTextStyleAndMetadata } from '@shared/helpers.js';
import useCommonEditPageFunctions from '../../utils/commonEditPageFunctions.jsx'
import useCommonEditPageFunctions from '../../utils/commonEditPageFunctions.jsx';
import SplitPane from '@components/splitPane/splitPane.jsx';
import Editor from '../../editor/editor.jsx';
+5 -5
View File
@@ -3,14 +3,14 @@
.newPage {
.navItem.save {
background-color : @orange;
transition:all 0.2s;
transition : all 0.2s;
&:hover { background-color : @green; }
&.neverSaved {
translate:-100%;
opacity: 0;
background-color :#333;
cursor:auto;
cursor : auto;
background-color : #333333;
opacity : 0;
translate : -100%;
}
}
}
@@ -6,9 +6,7 @@
*:not(input) { user-select : none; }
.form {
background:white;
}
.form { background : white; }
:where(.content .dataGroup) {
width : 100%;
@@ -174,8 +172,8 @@
height : 100%;
max-height : 100%;
padding : 70px 50px;
overflow-y : scroll;
container-type : inline-size;
overflow-y : scroll;
h3 { font-size : 25px; }
@@ -30,11 +30,11 @@ export default function useCommonEditPageFunctions(dependencies) {
save,
} = dependencies;
const [isSaving , setIsSaving] = useState(false);
const [lastSavedTime , setLastSavedTime] = useState(new Date());
const [autoSaveEnabled , setAutoSaveEnabled] = useState(!sandbox);
const [isSaving, setIsSaving] = useState(false);
const [lastSavedTime, setLastSavedTime] = useState(new Date());
const [autoSaveEnabled, setAutoSaveEnabled] = useState(!sandbox);
const [warnUnsavedChanges, setWarnUnsavedChanges] = useState(true);
const [unsavedChanges , setUnsavedChanges] = useState(false);
const [unsavedChanges, setUnsavedChanges] = useState(false);
const unsavedChangesRef = useRef(unsavedChanges); // onBeforeUnload lives outside React and needs ref to unsavedChanges
const warnUnsavedTimeout = useRef(null); // timers live outside React and need ref to consistently track time
@@ -105,7 +105,7 @@ export default function useCommonEditPageFunctions(dependencies) {
if(field == 'metadata') localStorage.setItem(METAKEY, JSON.stringify({
renderer : value.renderer,
theme : value.theme,
lang : value.lang
lang : value.lang
}));
}
};
@@ -155,7 +155,7 @@ export default function useCommonEditPageFunctions(dependencies) {
return <Nav.item className='save error' icon='fas fa-exclamation-circle'>
Reminder...
<div className='errorContainer'>{text}</div>
<div className='errorContainer'>{text}</div>
</Nav.item>;
}
@@ -180,5 +180,5 @@ export default function useCommonEditPageFunctions(dependencies) {
renderSaveButton,
autoSaveEnabled,
unsavedChanges,
}
};
}
+1886 -352
View File
File diff suppressed because it is too large Load Diff
+14 -27
View File
@@ -94,20 +94,18 @@
"@babel/runtime": "^8.0.5",
"@codemirror/autocomplete": "^6.20.3",
"@codemirror/commands": "^6.11.1",
"@codemirror/highlight": "^0.19.8",
"@codemirror/lang-css": "^6.3.1",
"@codemirror/lang-javascript": "^6.2.5",
"@codemirror/lang-html": "^6.4.12",
"@codemirror/lang-markdown": "^6.5.2",
"@codemirror/language": "^6.12.2",
"@codemirror/language-data": "^6.5.2",
"@codemirror/search": "^6.6.0",
"@codemirror/state": "^6.7.5",
"@codemirror/view": "^6.43.12",
"@dmsnell/diff-match-patch": "^1.1.0",
"@googleapis/drive": "^26.0.0",
"@lezer/highlight": "^1.2.3",
"@codemirror/state": "^6.7.6",
"@codemirror/view": "^6.43.13",
"@googleapis/drive": "^26.0.1",
"@lezer/highlight": "^1.2.4",
"@oddbird/css-anchor-positioning": "^0.10.2",
"@sanity/diff-match-patch": "^3.2.0",
"@sanity/diff-match-patch": "^3.2.1",
"@vitejs/plugin-react": "^6.0.5",
"body-parser": "^2.3.0",
"classnames": "^2.5.1",
@@ -121,38 +119,27 @@
"express-async-handler": "^1.2.0",
"express-static-gzip": "3.0.2",
"fflate": "^0.8.3",
"fs-extra": "^11.3.5",
"fs-extra": "^11.4.1",
"hash-wasm": "^4.12.0",
"idb-keyval": "^6.2.5",
"js-yaml": "^5.4.2",
"jwt-simple": "^0.5.6",
"less": "^4.9.1",
"lodash": "^4.18.1",
"marked": "15.0.12",
"marked-alignment-paragraphs": "^1.0.0",
"marked-definition-lists": "^1.0.1",
"marked-diagrams-markdeep": "^1.0.1",
"marked-emoji": "^3.0.0",
"marked-extended-tables": "^2.0.1",
"marked-gfm-heading-id": "^4.1.4",
"marked-hbfm": "^1.0.1",
"marked-nonbreaking-spaces": "^1.0.1",
"marked-smartypants-lite": "^1.0.3",
"marked-subsuper-text": "^1.0.4",
"marked-variables": "^1.0.5",
"markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.31.0",
"mongoose": "^9.10.1",
"mongoose": "^9.10.2",
"nanoid": "6.0.1",
"nconf": "^0.13.0",
"node": "^26.9.0",
"prettier": "^3.9.8",
"node": "^26.10.0",
"prettier": "^3.9.9",
"react": "^19.3.0",
"react-dom": "^19.3.0",
"react-frame-component": "^5.3.2",
"react-router": "^8.4.0",
"sanitize-filename": "1.6.4",
"superagent": "^10.2.1"
"superagent": "^10.4.1"
},
"devDependencies": {
"@stylistic/stylelint-plugin": "^5.3.0",
@@ -164,13 +151,13 @@
"globals": "^16.4.0",
"jest": "^30.5.2",
"jest-expect-message": "^1.1.3",
"jsdom": "^30.1.0",
"jsdom": "^30.1.1",
"jsdom-global": "^3.0.2",
"postcss-less": "^6.0.0",
"stylelint": "^17.15.0",
"stylelint-config-recess-order": "^7.7.0",
"stylelint-config-recommended": "^18.0.0",
"supertest": "^7.1.4",
"vite": "^8.3.0"
"supertest": "^7.3.0",
"vite": "^8.3.1"
}
}
+9 -9
View File
@@ -37,14 +37,14 @@ export default function createAdminApi(vite) {
throw { HBErrorCode: '52', code: 401, message: 'Access denied' };
}
};
// Search for up to 300 brews that have not been viewed or updated in 30 days and are shorter than 140 bytes
const junkBrewsPipeline = [
{ $match : {
updatedAt : { $lt: Moment().subtract(30, 'days').toDate() },
lastViewed : { $lt: Moment().subtract(30, 'days').toDate() }
} },
{ $project: { _id: 1, textBinSize: { $binarySize: '$textBin' }, updatedAt: 1, lastViewed: 1} },
{ $project: { _id: 1, textBinSize: { $binarySize: '$textBin' }, updatedAt: 1, lastViewed: 1 } },
{ $match: { textBinSize: { $lt: 140 } } },
{ $limit: 300 }
];
@@ -52,14 +52,14 @@ export default function createAdminApi(vite) {
// Search for up to 500 unauthored brews that have not been viewed or updated in two years
const lostBrewsPipeline = [
{
$match: {
authors: [],
updatedAt: { $lt: Moment().subtract(2, 'years').toDate() },
lastViewed: { $lt: Moment().subtract(2, 'years').toDate() }
$match : {
authors : [],
updatedAt : { $lt: Moment().subtract(2, 'years').toDate() },
lastViewed : { $lt: Moment().subtract(2, 'years').toDate() }
}
},
{
$limit: 500
$limit : 500
}
];
@@ -70,7 +70,7 @@ export default function createAdminApi(vite) {
router.get('/admin/cleanupJunk', mw.adminOnly, (req, res)=>{
HomebrewModel.aggregate(junkBrewsPipeline).option({ maxTimeMS: 60000 })
.then((objs)=>res.json({ count: objs.length, brewCollection : objs }))
.then((objs)=>res.json({ count: objs.length, brewCollection: objs }))
.catch((error)=>{
console.error(error);
res.status(500).json({ error: 'Internal Server Error' });
@@ -93,7 +93,7 @@ export default function createAdminApi(vite) {
router.get('/admin/cleanupLost', mw.adminOnly, (req, res)=>{
HomebrewModel.aggregate(lostBrewsPipeline).option({ maxTimeMS: 60000 })
.then((objs)=>res.json({ count: objs.length, brewCollection : objs }))
.then((objs)=>res.json({ count: objs.length, brewCollection: objs }))
.catch((error)=>{
console.error(error);
res.status(500).json({ error: 'Internal Server Error' });
+8 -6
View File
@@ -137,7 +137,7 @@ export default async function createApp(vite) {
return res.sendFile(`robots.txt`, { root: process.cwd() });
});
//serve brew for sharepage rerender
app.get('/api/fetch/:id', asyncHandler(getBrew('share')), asyncHandler(async (req, res) => {
app.get('/api/fetch/:id', asyncHandler(getBrew('share')), asyncHandler(async (req, res)=>{
const { brew } = req;
brew.authors.includes(req.account?.username)
? sanitizeBrew(brew, 'shareAuthor')
@@ -283,11 +283,13 @@ export default async function createApp(vite) {
const safeProps = JSON.stringify(props).replace(/<(?=\/?script)/ig, '\\u003c');
html = html.replace(
'<head>',
`<head>\n`
+ `<script id="props">`
+ `window.__INITIAL_PROPS__ = ` + safeProps
+ `</script>\n`
+ ogMetaTags
()=>{ //Replace must use a function instead of string, else brews with `$` in contents are treated as replacement patterns
return `<head>\n`
+ `<script id="props">`
+ `window.__INITIAL_PROPS__ = ${safeProps
}</script>\n${
ogMetaTags}`;
}
);
return html;
+111 -111
View File
@@ -360,25 +360,25 @@ describe('Tests for api', ()=>{
trashed : false,
updatedAt : undefined,
views : 0,
bleedSize: {
top: '.125in',
bottom: '.125in',
inner: '.125in',
outer: '.125in',
bleedSize : {
top : '.125in',
bottom : '.125in',
inner : '.125in',
outer : '.125in',
},
columns: '2',
columnGutter: '.125in',
legalAuthors: '',
license: 'None',
safetySpace: {
top: '.25in',
bottom: '.25in',
outer: '.25in',
inner: '.5in',
columns : '2',
columnGutter : '.125in',
legalAuthors : '',
license : 'None',
safetySpace : {
top : '.25in',
bottom : '.25in',
outer : '.25in',
inner : '.5in',
},
trimSize: {
width: '8.5in',
height: '11in',
trimSize : {
width : '8.5in',
height : '11in',
},
});
expect(next).toHaveBeenCalled();
@@ -471,25 +471,25 @@ describe('Tests for api', ()=>{
renderer : 'v3',
theme : 'phb',
googleId : '12345',
bleedSize: {
top: '.125in',
bottom: '.125in',
inner: '.125in',
outer: '.125in',
bleedSize : {
top : '.125in',
bottom : '.125in',
inner : '.125in',
outer : '.125in',
},
columns: '2',
columnGutter: '.125in',
legalAuthors: '',
license: 'None',
safetySpace: {
top: '.25in',
bottom: '.25in',
outer: '.25in',
inner: '.5in',
columns : '2',
columnGutter : '.125in',
legalAuthors : '',
license : 'None',
safetySpace : {
top : '.25in',
bottom : '.25in',
outer : '.25in',
inner : '.5in',
},
trimSize: {
width: '8.5in',
height: '11in',
trimSize : {
width : '8.5in',
height : '11in',
},
});
@@ -534,25 +534,25 @@ brew`);
renderer : 'v3',
theme : 'phb',
googleId : '12345',
bleedSize: {
top: '.125in',
bottom: '.125in',
inner: '.125in',
outer: '.125in',
bleedSize : {
top : '.125in',
bottom : '.125in',
inner : '.125in',
outer : '.125in',
},
columns: '2',
columnGutter: '.125in',
legalAuthors: '',
license: 'None',
safetySpace: {
top: '.25in',
bottom: '.25in',
outer: '.25in',
inner: '.5in',
columns : '2',
columnGutter : '.125in',
legalAuthors : '',
license : 'None',
safetySpace : {
top : '.25in',
bottom : '.25in',
outer : '.25in',
inner : '.5in',
},
trimSize: {
width: '8.5in',
height: '11in',
trimSize : {
width : '8.5in',
height : '11in',
},
});
@@ -687,16 +687,16 @@ brew`);
expect(res.status).toHaveBeenCalledWith(200);
expect(res.send).toHaveBeenCalledWith({
_id : '1',
authors : ['test user'],
createdAt : undefined,
description : '',
editId : expect.any(String),
gDrive : false,
pageCount : 1,
published : false,
renderer : 'V3',
lang : 'en',
_id : '1',
authors : ['test user'],
createdAt : undefined,
description : '',
editId : expect.any(String),
gDrive : false,
pageCount : 1,
published : false,
renderer : 'V3',
lang : 'en',
shareId : expect.any(String),
style : undefined,
tags : [],
@@ -708,25 +708,25 @@ brew`);
trashed : false,
updatedAt : undefined,
views : 0,
bleedSize: {
top: '.125in',
bottom: '.125in',
inner: '.125in',
outer: '.125in',
bleedSize : {
top : '.125in',
bottom : '.125in',
inner : '.125in',
outer : '.125in',
},
columns: '2',
columnGutter: '.125in',
legalAuthors: '',
license: 'None',
safetySpace: {
top: '.25in',
bottom: '.25in',
outer: '.25in',
inner: '.5in',
columns : '2',
columnGutter : '.125in',
legalAuthors : '',
license : 'None',
safetySpace : {
top : '.25in',
bottom : '.25in',
outer : '.25in',
inner : '.5in',
},
trimSize: {
width: '8.5in',
height: '11in',
trimSize : {
width : '8.5in',
height : '11in',
},
});
});
@@ -765,16 +765,16 @@ brew`);
expect(google.newGoogleBrew).toHaveBeenCalled();
expect(res.status).toHaveBeenCalledWith(200);
expect(res.send).toHaveBeenCalledWith({
_id : '1',
authors : ['test user'],
bleedSize: {
top: '.125in',
bottom: '.125in',
inner: '.125in',
outer: '.125in',
_id : '1',
authors : ['test user'],
bleedSize : {
top : '.125in',
bottom : '.125in',
inner : '.125in',
outer : '.125in',
},
columns: '2',
columnGutter: '.125in',
columns : '2',
columnGutter : '.125in',
createdAt : undefined,
description : '',
editId : expect.any(String),
@@ -784,29 +784,29 @@ brew`);
renderer : 'V3',
lang : 'en',
shareId : expect.any(String),
legalAuthors: '',
license: 'None',
safetySpace: {
top: '.25in',
bottom: '.25in',
outer: '.25in',
inner: '.5in',
legalAuthors : '',
license : 'None',
safetySpace : {
top : '.25in',
bottom : '.25in',
outer : '.25in',
inner : '.5in',
},
googleId : expect.any(String),
style : undefined,
tags : [],
text : undefined,
textBin : undefined,
theme : '5ePHB',
thumbnail : '',
title : 'asdf',
trashed : false,
trimSize: {
width: '8.5in',
height: '11in',
googleId : expect.any(String),
style : undefined,
tags : [],
text : undefined,
textBin : undefined,
theme : '5ePHB',
thumbnail : '',
title : 'asdf',
trashed : false,
trimSize : {
width : '8.5in',
height : '11in',
},
updatedAt : undefined,
views : 0
updatedAt : undefined,
views : 0
});
});
});
@@ -1031,7 +1031,7 @@ brew`);
);
});
});
describe('deleteGoogleBrew', ()=>{
it('should check auth and delete brew', async ()=>{
const result = await api.deleteGoogleBrew({ username: 'test user' }, 'id', 'editId', res);
@@ -1261,7 +1261,7 @@ brew`);
expect(saved.googleId).toEqual(brew.googleId);
});
});
describe('Split Text, Style, and Metadata', ()=>{
it('basic splitting', async ()=>{
@@ -1372,5 +1372,5 @@ brew`);
expect(testBrew.text).toEqual('text\n');
});
});
});
+12 -21
View File
@@ -42,7 +42,6 @@
transition-timing-function : @easing;
}
.transition (@prop, @duration: @defaultDuration) {
-webkit-transition : @prop @duration, -webkit-transform @duration;
-moz-transition : @prop @duration, -moz-transform @duration;
@@ -58,13 +57,13 @@
transform : @transform;
}
.delay(@delay) {
-webkit-transition-delay : @delay;
transition-delay : @delay;
-webkit-animation-delay : @delay;
animation-delay : @delay;
}
.keep() {
-webkit-animation-fill-mode : forwards;
-moz-animation-fill-mode : forwards;
@@ -73,7 +72,6 @@
animation-fill-mode : forwards;
}
.sequentialDelay(@delayInc : 0.2s, @initialDelay : 0s) {
&:nth-child(1) {.delay(0*@delayInc + @initialDelay); }
&:nth-child(2) {.delay(1*@delayInc + @initialDelay); }
@@ -97,14 +95,12 @@
&:nth-child(20) {.delay(19*@delayInc + @initialDelay); }
}
.createFrames(@name, @from, @to) {
@frames: {
from { @from(); }
to { @to(); }
};
@-webkit-keyframes @name {@frames();}
@-webkit-keyframes @name {@frames();}
@-moz-keyframes @name {@frames();}
@-ms-keyframes @name {@frames();}
@-o-keyframes @name {@frames();}
@@ -126,8 +122,6 @@
animation-timing-function : @easing;
}
/***************************
Standard Animations
****************************/
@@ -136,7 +130,7 @@
.createAnimation(fadeIn; @duration; @easing);
.createFrames(fadeIn,
{ opacity : 0; },
{ opacity : 1; }
{ opacity : 1; }
);
}
@@ -144,7 +138,7 @@
.createAnimation(fadeInDown; @duration; @easing);
.createFrames(fadeInDown,
{ opacity : 0; .transform(translateY(20px));},
{ opacity : 1; .transform(translateY(0px));}
{ opacity : 1; .transform(translateY(0px));}
);
}
@@ -152,7 +146,7 @@
.createAnimation(fadeInTop; @duration; @easing);
.createFrames(fadeInTop,
{ opacity : 0; .transform(translateY(-20px)); },
{ opacity : 1; .transform(translateY(0px));}
{ opacity : 1; .transform(translateY(0px));}
);
}
@@ -160,7 +154,7 @@
.createAnimation(fadeInLeft; @duration; @easing);
.createFrames(fadeInLeft,
{ opacity: 0; .transform(translateX(-20px));},
{ opacity: 1; .transform(translateX(0));}
{ opacity: 1; .transform(translateX(0));}
);
}
@@ -168,7 +162,7 @@
.createAnimation(fadeInRight; @duration; @easing);
.createFrames(fadeInRight,
{ opacity: 0; .transform(translateX(20px));},
{ opacity: 1; .transform(translateX(0));}
{ opacity: 1; .transform(translateX(0));}
);
}
@@ -176,7 +170,7 @@
.createAnimation(fadeOut; @duration; @easing);
.createFrames(fadeOut,
{ opacity : 1; },
{ opacity : 0; }
{ opacity : 0; }
);
}
@@ -184,7 +178,7 @@
.createAnimation(fadeOutDown; @duration; @easing);
.createFrames(fadeOutDown,
{ opacity : 1; .transform(translateY(0)); visibility: visible;},
{ opacity : 0; .transform(translateY(20px)); visibility: hidden;}
{ opacity : 0; .transform(translateY(20px)); visibility: hidden;}
);
}
@@ -192,7 +186,7 @@
.createAnimation(fadeOutTop; @duration; @easing);
.createFrames(fadeOutTop,
{ opacity : 1; .transform(translateY(0)); },
{ opacity : 0; .transform(translateY(-20px)); }
{ opacity : 0; .transform(translateY(-20px)); }
);
}
@@ -200,7 +194,7 @@
.createAnimation(fadeOutLeft; @duration; @easing);
.createFrames(fadeOutLeft,
{ opacity : 1; .transform(translateX(0));},
{ opacity : 0; .transform(translateX(-20px));}
{ opacity : 0; .transform(translateX(-20px));}
);
}
@@ -208,13 +202,10 @@
.createAnimation(fadeOutRight; @duration; @easing);
.createFrames(fadeOutRight,
{ opacity : 1; .transform(translateX(0));},
{ opacity : 0; .transform(translateX(20px));}
{ opacity : 0; .transform(translateX(20px));}
);
}
/***************************
Fun Animations
****************************/
+2 -2
View File
@@ -40,7 +40,7 @@ p {
color : @copyGrey;
}
code {
font-family : 'Courier', "mono";
font-family : 'Courier', 'mono';
color : black;
white-space : pre;
background-color : #F8F8F8;
@@ -54,7 +54,7 @@ button {
.animate(background-color);
display : inline-block;
padding : 0.6em 1.2em;
font-family : 'Lato', "Helvetica", "Arial", sans-serif;
font-family : 'Lato', 'Helvetica', 'Arial', sans-serif;
font-size : 15px;
color : white;
text-decoration : none;
+1 -1
View File
@@ -22,4 +22,4 @@
background-color : unset;
}
:where(i){ text-box-trim: trim-both }
:where(i) { text-box-trim : trim-both; }
+26 -26
View File
@@ -3,23 +3,23 @@
@arrowSize : 6px;
@arrowPosition : 18px;
[data-tooltip] {
position:relative;
position : relative;
.tooltip(attr(data-tooltip));
}
[data-tooltip-top] {
position:relative;
position : relative;
.tooltipTop(attr(data-tooltip-top));
}
[data-tooltip-bottom] {
position:relative;
position : relative;
.tooltipBottom(attr(data-tooltip-bottom));
}
[data-tooltip-left] {
position:relative;
position : relative;
.tooltipLeft(attr(data-tooltip-left));
}
[data-tooltip-right] {
position:relative;
position : relative;
.tooltipRight(attr(data-tooltip-right));
}
.tooltip(@content) {
@@ -33,9 +33,9 @@
}
&::after { margin-left : -18px; }
&::before, &::after {
bottom : 100%;
left : 50%;
translate: -50% 0;
bottom : 100%;
left : 50%;
translate : -50% 0;
}
&:hover::after, &:hover::before, &:focus::after, &:focus::before {
.transform(translateY(-(@arrowSize + 2)));
@@ -49,9 +49,9 @@
}
&::after { margin-left : -18px; }
&::before, &::after {
top : 100%;
left : 50%;
translate: -50% 0;
top : 100%;
left : 50%;
translate : -50% 0;
}
&:hover::after, &:hover::before, &:focus::after, &:focus::before {
.transform(translateY(@arrowSize + 2));
@@ -65,8 +65,8 @@
border-left-color : @tooltipColor;
}
&::after {
max-width : 50ch;
margin-bottom : -14px;
max-width : 50ch;
}
&::before, &::after {
right : 100%;
@@ -84,13 +84,13 @@
border-right-color : @tooltipColor;
}
&::after {
max-width : 50ch;
margin-bottom : -14px;
max-width : 50ch;
}
&::before, &::after {
top : 50%;
left : 100%;
translate:0 -50%;
top : 50%;
left : 100%;
translate : 0 -50%;
}
&:hover::after, &:hover::before, &:focus::after, &:focus::before {
.transform(translateX(@arrowSize + 2));
@@ -115,17 +115,17 @@
}
//Box
&::after {
visibility : hidden;
padding : 8px 10px;
font-size : 12px;
line-height : 12px;
color : white;
content : @content;
background : @tooltipColor;
max-width : 60ch;
width :max-content;
word-break : break-word;
visibility : hidden;
width : max-content;
max-width : 60ch;
padding : 8px 10px;
font-size : 12px;
line-height : 12px;
color : white;
word-break : break-word;
overflow-wrap : break-word;
content : @content;
background : @tooltipColor;
}
&:hover::before, &:hover::after {
visibility : visible;
+21 -21
View File
@@ -47,19 +47,19 @@ describe(`brewSnippetsToJSON`, ()=>{
gen : 'I am the first brew snippet!\n',
name : 'First Brew Snippet'
}, {
gen : 'I am the second brew Snippet!',
name: 'Second Brew Snippet'
gen : 'I am the second brew Snippet!',
name : 'Second Brew Snippet'
}
]}]
] }]
};
const rendered = brewSnippetsToJSON(`Test Snippets JSON without theme snippets`, brewSnippetsBrewTest, null, true);
expect(rendered).toStrictEqual(testMenuObject);
});
it('converts raw brew snippets with theme snippets to JSON', function() {
it('converts raw brew snippets with theme snippets to JSON', function() {
const testMenuObject = {
groupName : 'Brew Snippets',
icon : 'fas fa-th-list',
icon : 'fas fa-th-list',
view : 'text',
snippets : [{
gen : '',
@@ -76,20 +76,20 @@ describe(`brewSnippetsToJSON`, ()=>{
icon : '',
name : 'Second Theme Snippet',
},
]},
{
name : 'Test Snippets JSON with theme snippets',
subsnippets : [
{
gen : 'I am the first brew snippet!\n',
name : 'First Brew Snippet'
},
{
gen : 'I am the second brew Snippet!',
name: 'Second Brew Snippet'
}
]
}]};
] },
{
name : 'Test Snippets JSON with theme snippets',
subsnippets : [
{
gen : 'I am the first brew snippet!\n',
name : 'First Brew Snippet'
},
{
gen : 'I am the second brew Snippet!',
name : 'Second Brew Snippet'
}
]
}] };
const rendered = brewSnippetsToJSON(`Test Snippets JSON with theme snippets`, brewSnippetsBrewTest, brewSnippetsThemeTest, true);
expect(rendered).toStrictEqual(testMenuObject);
});
@@ -103,8 +103,8 @@ describe(`YAMLSnippetsToText`, ()=>{
gen : 'I am the first brew snippet!\n',
name : 'First Brew Snippet'
}, {
gen : 'I am the second brew Snippet!',
name: 'Second Brew Snippet'
gen : 'I am the second brew Snippet!',
name : 'Second Brew Snippet'
}
]
}];
+1 -1
View File
@@ -1,6 +1,6 @@
import {hbfm} from 'marked-hbfm';
import { hbfm } from 'marked-hbfm';
describe('Non-Breaking Spaces Interactions', ()=>{
test('I am actually a single-line definition list!', function() {
+16 -16
View File
@@ -25,16 +25,16 @@ body { counter-reset : phb-page-numbers; }
}
}
.useColumns(@multiplier : 1) {
column-count : 2;
column-fill : auto;
column-gap : 1cm;
-webkit-column-width : 8cm * @multiplier;
-moz-column-width : 8cm * @multiplier;
column-width : 8cm * @multiplier;
-webkit-column-count : 2;
-moz-column-count : 2;
-webkit-column-width : 8cm * @multiplier;
-moz-column-width : 8cm * @multiplier;
column-count : 2;
column-fill : auto;
-webkit-column-gap : 1cm;
-moz-column-gap : 1cm;
column-gap : 1cm;
}
.phb, .page {
.useColumns();
@@ -43,8 +43,11 @@ body { counter-reset : phb-page-numbers; }
box-sizing : border-box;
width : 215.9mm;
height : 279.4mm;
contain-intrinsic-size : auto none;
padding : 1.0cm 1.7cm;
padding-bottom : 1.5cm;
contain : strict;
content-visibility : auto;
overflow : hidden;
font-family : 'BookSanity';
font-size : 0.317cm;
@@ -52,11 +55,8 @@ body { counter-reset : phb-page-numbers; }
background-color : @background;
background-image : @backgroundImage;
text-rendering : optimizeLegibility;
page-break-before : always;
page-break-after : always;
contain : strict;
content-visibility : auto;
contain-intrinsic-size : auto none;
break-before : page;
break-after : page;
}
.phb {
@@ -111,10 +111,10 @@ body { counter-reset : phb-page-numbers; }
color : @headerText;
}
h1 {
column-span : all;
font-size : 0.987cm;
-webkit-column-span : all;
-moz-column-span : all;
column-span : all;
font-size : 0.987cm;
& + p::first-letter {
float : left;
font-family : 'Solberry';
@@ -308,7 +308,7 @@ body { counter-reset : phb-page-numbers; }
p,blockquote,table {
z-index : 15;
-webkit-column-break-inside : avoid;
page-break-inside : avoid;
break-inside : avoid;
break-inside : avoid;
}
//Better spacing for spell blocks
@@ -322,7 +322,7 @@ body { counter-reset : phb-page-numbers; }
}
li {
-webkit-column-break-inside : avoid;
page-break-inside : avoid;
break-inside : avoid;
break-inside : avoid;
}
}
@@ -347,7 +347,7 @@ body { counter-reset : phb-page-numbers; }
list-style-type : none;
break-inside : auto;
-webkit-column-break-inside : auto;
page-break-inside : auto;
break-inside : auto;
}
}
//*****************************
@@ -436,7 +436,7 @@ body { counter-reset : phb-page-numbers; }
// *****************************/
.phb .toc {
-webkit-column-break-inside : avoid;
page-break-inside : avoid;
break-inside : avoid;
break-inside : avoid;
a {
color : black;
+26 -26
View File
@@ -27,16 +27,16 @@
h5 + * { margin-top : 0.1cm; }
}
.useColumns(@multiplier : 1, @fillMode: auto) {
column-count : 2;
column-fill : @fillMode;
column-gap : 0.9cm;
-webkit-column-width : 8cm * @multiplier;
-moz-column-width : 8cm * @multiplier;
column-width : 8cm * @multiplier;
-webkit-column-count : 2;
-moz-column-count : 2;
-webkit-column-width : 8cm * @multiplier;
-moz-column-width : 8cm * @multiplier;
column-count : 2;
column-fill : @fillMode;
-webkit-column-gap : 0.9cm;
-moz-column-gap : 0.9cm;
column-gap : 0.9cm;
}
.page {
.useColumns();
@@ -79,12 +79,12 @@
color : var(--HB_Color_HeaderText);
}
h1 {
margin-bottom : 0.18cm; //Margin-bottom only because this is WIDE
column-span : all;
font-size : 0.89cm;
line-height : 1em;
-webkit-column-span : all;
-moz-column-span : all;
column-span : all;
margin-bottom : 0.18cm; //Margin-bottom only because this is WIDE
font-size : 0.89cm;
line-height : 1em;
& + p::first-line { font-variant : small-caps; }
}
p.first-letter::first-letter,
@@ -363,13 +363,13 @@
// Monster Ability table
hr + table:first-of-type {
margin : 0;
-webkit-column-span : none;
column-span : none;
margin : 0;
color : var(--HB_Color_HeaderText);
background-color : transparent;
border-style : none;
border-image : none;
-webkit-column-span : none;
tr { background-color : transparent; }
td,th { padding : 0px; }
}
@@ -420,15 +420,15 @@
color : var(--HB_Color_Footnotes);
}
.footnote {
text-transform: uppercase;
position : absolute;
right : 80px;
bottom : 32px;
z-index : 150;
width : 200px;
font-size : 0.8em;
color : var(--HB_Color_Footnotes);
text-align : right;
position : absolute;
right : 80px;
bottom : 32px;
z-index : 150;
width : 200px;
font-size : 0.8em;
color : var(--HB_Color_Footnotes);
text-align : right;
text-transform : uppercase;
}
// ************************************
// * CODE BLOCKS
@@ -488,7 +488,7 @@
text-indent : -1em;
list-style-type : none;
-webkit-column-break-inside : auto;
page-break-inside : auto;
break-inside : auto;
break-inside : auto;
}
&.wide { column-count : 4; }
@@ -615,9 +615,9 @@
font-size : 0.496cm;
color : white;
text-align : center;
-webkit-text-stroke : 0.1cm black;
text-transform : none;
paint-order : stroke;
text-transform : none;
-webkit-text-stroke : 0.1cm black;
}
.logo {
position : absolute;
@@ -675,10 +675,10 @@
// * BACK COVER
// *****************************/
.page:has(.backCover) {
columns : 1;
padding : 2.25cm 1.3cm 2cm 1.3cm;
line-height : 1.4em;
color : #FFFFFF;
columns : 1;
&::after { display : none; }
.columnWrapper { width : 7.6cm; }
.backCover {
@@ -756,9 +756,9 @@
// * PART COVER
// *****************************/
.page:has(.partCover) {
columns : 1;
padding-top : 0;
text-align : center;
columns : 1;
.partCover {
position : absolute;
@@ -807,7 +807,7 @@
&:has(.toc)::after { display : none; }
.toc {
-webkit-column-break-inside : avoid;
page-break-inside : avoid;
break-inside : avoid;
break-inside : avoid;
h1 {
margin-bottom : 0.3cm;
+1 -1
View File
@@ -329,7 +329,7 @@ export default [
},
{
name : 'DTRPG Community Content',
icon : null,
icon : null,
subsnippets : [
{
name : 'Chronicle System Guild Colophon',
+45 -57
View File
@@ -34,15 +34,15 @@ body { counter-reset : page-numbers 0; }
}
.useColumns(@multiplier : 1, @fillMode: auto) {
column-fill : @fillMode;
column-count : 2;
column-fill : @fillMode;
}
.columnWrapper {
columns : inherit;
column-span : all;
column-fill : inherit;
column-gap : inherit;
max-height : 100%;
column-span : all;
columns : inherit;
column-fill : inherit;
}
.page {
.useColumns();
@@ -51,13 +51,13 @@ body { counter-reset : page-numbers 0; }
box-sizing : border-box;
width : 215.9mm;
height : 279.4mm;
contain-intrinsic-size : auto none;
padding : 1.4cm 1.9cm 1.7cm;
contain : strict;
content-visibility : auto;
overflow : clip;
background-color : var(--HB_Color_Background);
text-rendering : optimizeLegibility;
contain : strict;
content-visibility : auto;
contain-intrinsic-size : auto none;
}
//*****************************
// * BASE
@@ -145,7 +145,7 @@ body { counter-reset : page-numbers 0; }
blockquote,table {
z-index : 15;
-webkit-column-break-inside : avoid;
page-break-inside : avoid;
break-inside : avoid;
break-inside : avoid;
}
// Nested lists
@@ -155,20 +155,20 @@ body { counter-reset : page-numbers 0; }
}
li {
-webkit-column-break-inside : avoid;
page-break-inside : avoid;
break-inside : avoid;
break-inside : avoid;
}
/* Wrap Text */
.wrapLeft {
shape-outside : var(--HB_src);
float : right;
shape-outside : var(--HB_src);
shape-margin : 0.2cm;
}
.wrapRight {
shape-outside : var(--HB_src);
float : left;
shape-outside : var(--HB_src);
shape-margin : 0.2cm;
}
@@ -433,8 +433,8 @@ body { counter-reset : page-numbers 0; }
// *****************************/
.page {
.wide {
column-span : all;
display : block;
column-span : all;
margin-bottom : 1em;
& + * { margin-top : 0; }
}
@@ -502,66 +502,54 @@ body { counter-reset : page-numbers 0; }
// * Ordered List Type Overrides
// *****************************/
@counter-style lower-alpha-trailing-paren {
system: extends lower-alpha;
prefix: "";
suffix: ") ";
}
system : extends lower-alpha;
prefix : '';
suffix : ') ';
}
.page{
.ol-ccby ol {
list-style-type: lower-alpha;
}
.page {
.ol-ccby ol { list-style-type : lower-alpha; }
.ol-ccby ol ol{
padding-left: 0px !important;
list-style-type: greek;
.ol-ccby ol ol {
padding-left : 0px !important;
list-style-type : greek;
}
.ol-ccby ol ol ol {
padding-left: 0px !important;
list-style-type: upper-alpha;
padding-left : 0px !important;
list-style-type : upper-alpha;
}
.ol-ccby ol ol ol ol {
padding-left: 0px !important;
list-style-type: lower-roman;
padding-left : 0px !important;
list-style-type : lower-roman;
}
.ol-ccby p {
padding-left: 25px;
text-indent: 0em !important;
padding-left : 25px;
text-indent : 0em !important;
}
// Non-indented, numerical lists with slight gap between paragraphs.
.ol-lowerLetters ol { list-style-type : lower-alpha-trailing-paren; }
.ol-lowerLetters ol li p { display : inline; }
.ol-lowerLetters ol {
list-style-type: lower-alpha-trailing-paren;
padding : 0px;
list-style-position : inside;
}
.ol-lowerLetters ol li p {
display: inline;
}
.ol-lowerLetters ol {
list-style-position: inside;
padding: 0px;
}
.ol-lowerLetters ol li:not(:last-child) {
margin-bottom: 0.5em;
}
.ol-lowerLetters ol li:not(:last-child) { margin-bottom : 0.5em; }
.ol-noIndent ol {
list-style-position: inside;
padding: 0px;
padding : 0px;
list-style-position : inside;
}
.ol-noIndent ol li p {
display: inline;
}
.ol-noIndent ol li p { display : inline; }
.ol-noIndent ol li:not(:last-child) {
margin-bottom: 0.5em;
}
.ol-noIndent ol li:not(:last-child) { margin-bottom : 0.5em; }
}
// *****************************
@@ -617,7 +605,7 @@ h6,
&:has(.toc)::after { display : none; }
.toc {
-webkit-column-break-inside : avoid;
page-break-inside : avoid;
break-inside : avoid;
break-inside : avoid;
h1 {
margin-bottom : 0.3cm;
@@ -684,10 +672,10 @@ Firefox endruns
**********************************/
@supports (-moz-user-select: none) { // This section will only apply to Firefox; it's the only browser that supports `-mos-xyz...`
.page {
blockquote, table {
page-break-inside: auto;
break-inside: auto;
}
}
.page {
blockquote, table {
break-inside : auto;
break-inside : auto;
}
}
}
+4 -4
View File
@@ -275,12 +275,12 @@
// Monster Ability table
hr + table:first-of-type {
column-span : none;
margin : 0;
color : inherit;
background-image : none;
border-style : none;
border-image : none;
column-span : none;
tr { background-image : none; }
td,th { padding : 0px; }
}
@@ -372,8 +372,8 @@
.page .spellList {
.useSansSerif();
font-family : 'PermanentMarker';
column-count : 2;
font-family : 'PermanentMarker';
ul + h5 { margin-top : 15px; }
ul {
padding-left : 1em;
@@ -382,7 +382,7 @@
list-style-type : none;
break-inside : auto;
-webkit-column-break-inside : auto;
page-break-inside : auto;
break-inside : auto;
}
&.wide { column-count : 4; }
}
@@ -399,7 +399,7 @@
// *****************************/
.page .toc {
-webkit-column-break-inside : avoid;
page-break-inside : avoid;
break-inside : avoid;
break-inside : avoid;
h1 {
margin-bottom : 0.3cm;
+13 -21
View File
@@ -8,31 +8,23 @@
}
.page {
font-family: Cambria,Georgia,serif;
font-size: 14px;
font-family : "Cambria","Georgia",serif;
font-size : 14px;
h1, h2, h3, h4 {
font-variant: small-caps;
font-weight: normal;
font-weight : normal;
font-variant : small-caps;
}
h1 {
column-span: all;
-webkit-column-span: all;
font-size: 40px;
}
h2 {
font-size: 26px;
-webkit-column-span : all;
column-span : all;
font-size : 40px;
}
h2 { font-size : 26px; }
h3 {
font-size: 20px;
border-bottom: 2px solid black;
}
h4 {
font-size: 18px;
}
h5 {
font-size: 16px;
}
h6 {
font-size: 14px;
font-size : 20px;
border-bottom : 2px solid black;
}
h4 { font-size : 18px; }
h5 { font-size : 16px; }
h6 { font-size : 14px; }
}
+9 -9
View File
@@ -1,24 +1,24 @@
/* Main Font, serif */
@font-face {
font-family : "BookSanity";
font-family : 'BookSanity';
font-style : normal;
font-weight : normal;
src : url('../../../fonts/5e legacy/Bookinsanity.woff2');
}
@font-face {
font-family : "BookSanity";
font-family : 'BookSanity';
font-style : normal;
font-weight : bold;
src : url('../../../fonts/5e legacy/Bookinsanity Bold.woff2');
}
@font-face {
font-family : "BookSanity";
font-family : 'BookSanity';
font-style : italic;
font-weight : normal;
src : url('../../../fonts/5e legacy/Bookinsanity Italic.woff2');
}
@font-face {
font-family : "BookSanity";
font-family : 'BookSanity';
font-style : italic;
font-weight : bold;
src : url('../../../fonts/5e legacy/Bookinsanity Bold Italic.woff2');
@@ -26,19 +26,19 @@
/* Notes and Tables, sans-serif */
@font-face {
font-family : "ScalySans";
font-family : 'ScalySans';
font-style : normal;
font-weight : normal;
src : url('../../../fonts/5e legacy/Scaly Sans.woff2');
}
@font-face {
font-family : "ScalySansSmallCaps";
font-family : 'ScalySansSmallCaps';
font-style : normal;
font-weight : normal;
src : url('../../../fonts/5e legacy/Scaly Sans Caps.woff2');
}
@font-face {
font-family : "WalterTurncoat";
font-family : 'WalterTurncoat';
font-style : normal;
font-weight : normal;
src : url('../../../fonts/5e legacy/WalterTurncoat-Regular.woff2');
@@ -46,7 +46,7 @@
/* Headers */
@font-face {
font-family : "MrJeeves";
font-family : 'MrJeeves';
font-style : normal;
font-weight : normal;
src : url('../../../fonts/5e legacy/Mr Eaves Small Caps.woff2');
@@ -54,7 +54,7 @@
/* Fancy Drop Cap */
@font-face {
font-family : "Solberry";
font-family : 'Solberry';
font-style : normal;
font-weight : normal;
src : url('../../../fonts/5e legacy/Solbera Imitation.woff2');
+21 -21
View File
@@ -1,24 +1,24 @@
/* Main Font, serif */
@font-face {
font-family : "BookInsanityRemake";
font-family : 'BookInsanityRemake';
font-style : normal;
font-weight : normal;
src : url('../../../fonts/5e/Bookinsanity.woff2');
}
@font-face {
font-family : "BookInsanityRemake";
font-family : 'BookInsanityRemake';
font-style : normal;
font-weight : bold;
src : url('../../../fonts/5e/Bookinsanity Bold.woff2');
}
@font-face {
font-family : "BookInsanityRemake";
font-family : 'BookInsanityRemake';
font-style : italic;
font-weight : normal;
src : url('../../../fonts/5e/Bookinsanity Italic.woff2');
}
@font-face {
font-family : "BookInsanityRemake";
font-family : 'BookInsanityRemake';
font-style : italic;
font-weight : bold;
src : url('../../../fonts/5e/Bookinsanity Bold Italic.woff2');
@@ -26,37 +26,37 @@
/* Notes and Tables, sans-serif */
@font-face {
font-family : "ScalySansRemake";
font-family : 'ScalySansRemake';
font-style : normal;
font-weight : normal;
src : url('../../../fonts/5e/Scaly Sans.woff2');
}
@font-face {
font-family : "ScalySansRemake";
font-family : 'ScalySansRemake';
font-style : normal;
font-weight : bold;
src : url('../../../fonts/5e/Scaly Sans Bold.woff2');
}
@font-face {
font-family : "ScalySansRemake";
font-family : 'ScalySansRemake';
font-style : italic;
font-weight : normal;
src : url('../../../fonts/5e/Scaly Sans Italic.woff2');
}
@font-face {
font-family : "ScalySansRemake";
font-family : 'ScalySansRemake';
font-style : italic;
font-weight : bold;
src : url('../../../fonts/5e/Scaly Sans Bold Italic.woff2');
}
@font-face {
font-family : "ScalySansSmallCapsRemake";
font-family : 'ScalySansSmallCapsRemake';
font-style : normal;
font-weight : normal;
src : url('../../../fonts/5e/Scaly Sans Caps.woff2');
}
@font-face {
font-family : "WalterTurncoat";
font-family : 'WalterTurncoat';
font-style : normal;
font-weight : normal;
src : url('../../../fonts/5e/WalterTurncoat-Regular.woff2');
@@ -64,7 +64,7 @@
/* Headers */
@font-face {
font-family : "MrEavesRemake";
font-family : 'MrEavesRemake';
font-style : normal;
font-weight : normal;
src : url('../../../fonts/5e/Mr Eaves Small Caps.woff2');
@@ -72,7 +72,7 @@
/* Fancy Drop Cap */
@font-face {
font-family : "SolberaImitationRemake"; //Tweaked 5e version
font-family : 'SolberaImitationRemake'; //Tweaked 5e version
font-style : normal;
font-style : italic;
font-weight : 100 1000;
@@ -81,62 +81,62 @@
/* Cover Page */
@font-face {
font-family : "NodestoCapsCondensed";
font-family : 'NodestoCapsCondensed';
font-style : normal;
font-weight : normal;
src : url('../../../fonts/5e/Nodesto Caps Condensed.woff2');
}
@font-face {
font-family : "NodestoCapsCondensed";
font-family : 'NodestoCapsCondensed';
font-style : normal;
font-weight : bold;
src : url('../../../fonts/5e/Nodesto Caps Condensed Bold.woff2');
}
@font-face {
font-family : "NodestoCapsCondensed";
font-family : 'NodestoCapsCondensed';
font-style : italic;
font-weight : normal;
src : url('../../../fonts/5e/Nodesto Caps Condensed Italic.woff2');
}
@font-face {
font-family : "NodestoCapsCondensed";
font-family : 'NodestoCapsCondensed';
font-style : italic;
font-weight : bold;
src : url('../../../fonts/5e/Nodesto Caps Condensed Bold Italic.woff2');
}
@font-face {
font-family : "NodestoCapsWide";
font-family : 'NodestoCapsWide';
font-style : normal;
font-weight : normal;
src : url('../../../fonts/5e/Nodesto Caps Wide.woff2');
}
@font-face {
font-family : "Overpass";
font-family : 'Overpass';
font-style : normal;
font-weight : 500;
src : url('../../../fonts/5e/Overpass Medium.woff2');
}
@font-face {
font-family : "Davek";
font-family : 'Davek';
font-style : normal;
font-weight : 500;
src : url('../../../fonts/5e/Davek.woff2');
}
@font-face {
font-family : "Iokharic";
font-family : 'Iokharic';
font-style : normal;
font-weight : 500;
src : url('../../../fonts/5e/Iokharic.woff2');
}
@font-face {
font-family : "Rellanic";
font-family : 'Rellanic';
font-style : normal;
font-weight : 500;
src : url('../../../fonts/5e/Rellanic.woff2');
+4 -4
View File
@@ -18,28 +18,28 @@ License:
*/
@font-face {
font-family : "Pagella";
font-family : 'Pagella';
font-style : normal;
font-weight : normal;
src : url('../../../fonts/Blank/texgyrepagella-regular.woff2');
}
@font-face {
font-family : "Pagella";
font-family : 'Pagella';
font-style : normal;
font-weight : bold;
src : url('../../../fonts/Blank/texgyrepagella-bold.woff2');
}
@font-face {
font-family : "Pagella";
font-family : 'Pagella';
font-style : italic;
font-weight : normal;
src : url('../../../fonts/Blank/texgyrepagella-italic.woff2');
}
@font-face {
font-family : "Pagella";
font-family : 'Pagella';
font-style : italic;
font-weight : bold;
src : url('../../../fonts/Blank/texgyrepagella-bolditalic.woff2');
+8 -8
View File
@@ -1,6 +1,6 @@
/* Main Font, serif */
@font-face {
font-family : "ReenieBeanie";
font-family : 'ReenieBeanie';
font-style : normal;
font-weight : normal;
src : url('../../../fonts/Journal/ReenieBeanie-Regular.woff2');
@@ -8,13 +8,13 @@
/* Notes and Tables, sans-serif */
@font-face {
font-family : "PermanentMarker";
font-family : 'PermanentMarker';
font-style : normal;
font-weight : normal;
src : url('../../../fonts/Journal/PermanentMarker-Regular.woff2');
}
@font-face {
font-family : "WalterTurncoat";
font-family : 'WalterTurncoat';
font-style : normal;
font-weight : normal;
src : url('../../../fonts/5e/WalterTurncoat-Regular.woff2');
@@ -22,7 +22,7 @@
/* Headers */
@font-face {
font-family : "FrederickaTheGreat";
font-family : 'FrederickaTheGreat';
font-style : normal;
font-weight : normal;
src : url('../../../fonts/Journal/FrederickaTheGreat-Regular.woff2');
@@ -30,28 +30,28 @@
/* Cover Page */
@font-face {
font-family : "NodestoCapsCondensed";
font-family : 'NodestoCapsCondensed';
font-style : normal;
font-weight : normal;
src : url('../../../fonts/5e/Nodesto Caps Condensed.woff2');
}
@font-face {
font-family : "NodestoCapsCondensed";
font-family : 'NodestoCapsCondensed';
font-style : normal;
font-weight : bold;
src : url('../../../fonts/5e/Nodesto Caps Condensed Bold.woff2');
}
@font-face {
font-family : "NodestoCapsCondensed";
font-family : 'NodestoCapsCondensed';
font-style : italic;
font-weight : normal;
src : url('../../../fonts/5e/Nodesto Caps Condensed Italic.woff2');
}
@font-face {
font-family : "NodestoCapsCondensed";
font-family : 'NodestoCapsCondensed';
font-style : italic;
font-weight : bold;
src : url('../../../fonts/5e/Nodesto Caps Condensed Bold Italic.woff2');
+12 -12
View File
@@ -25,19 +25,19 @@
&.F-minus::before { content : '\f191'; }
&.F-plus::before { content : '\f192'; }
&.F-zero::before { content : '\f193'; }
&.d10::before { content : '\f194'; }
&.d10-0::before { content : '\f100'; }
&.d10-1:before { content : '\f101'; }
&.d10::before { content : '\f194'; }
&.d10-0::before { content : '\f100'; }
&.d10-1::before { content : '\f101'; }
&.d10-10::before { content : '\f102'; }
&.d10-2:before { content : '\f103'; }
&.d10-3::before { content : '\f104'; }
&.d10-4::before { content : '\f105'; }
&.d10-5::before { content : '\f106'; }
&.d10-6::before { content : '\f107'; }
&.d10-7::before { content : '\f108'; }
&.d10-8::before { content : '\f109'; }
&.d10-9::before { content : '\f10A'; }
&.d12::before { content : '\f195'; }
&.d10-2::before { content : '\f103'; }
&.d10-3::before { content : '\f104'; }
&.d10-4::before { content : '\f105'; }
&.d10-5::before { content : '\f106'; }
&.d10-6::before { content : '\f107'; }
&.d10-7::before { content : '\f108'; }
&.d10-8::before { content : '\f109'; }
&.d10-9::before { content : '\f10A'; }
&.d12::before { content : '\f195'; }
&.d12-1::before { content : '\f10b'; }
&.d12-10::before { content : '\f10c'; }
&.d12-11::before { content : '\f10d'; }
+4 -4
View File
@@ -1,7 +1,7 @@
@import (less) "./themes/fonts/iconFonts/fontawesome-free.less";
@import (less) "./themes/fonts/iconFonts/fontawesome-solid.less";
@import (less) "./themes/fonts/iconFonts/fontawesome-brands.less";
@import (less) "./themes/fonts/iconFonts/fontawesome-regular.less";
@import (less) './themes/fonts/iconFonts/fontawesome-free.less';
@import (less) './themes/fonts/iconFonts/fontawesome-solid.less';
@import (less) './themes/fonts/iconFonts/fontawesome-brands.less';
@import (less) './themes/fonts/iconFonts/fontawesome-regular.less';
/* Icon Font: Font Awesome */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -4,16 +4,15 @@
* Copyright 2024 Fonticons, Inc.
*/
:root, :host {
--fa-style-family-classic: 'Font Awesome 6 Free';
--fa-font-regular: normal 400 1em/1 'Font Awesome 6 Free'; }
--fa-style-family-classic : 'Font Awesome 6 Free';
--fa-font-regular : normal 400 1em/1 'Font Awesome 6 Free'; }
@font-face {
font-family: 'Font Awesome 6 Free';
font-style: normal;
font-weight: 400;
font-display: block;
src: url("/fonts/iconFonts/fa-regular-400.woff2") format("woff2"), url("/fonts/iconFonts/fa-regular-400.ttf") format("truetype"); }
font-family : 'Font Awesome 6 Free';
font-style : normal;
font-weight : normal;
src : url('/fonts/iconFonts/fa-regular-400.woff2') format('woff2'), url('/fonts/iconFonts/fa-regular-400.ttf') format('truetype');
font-display : block; }
.far,
.fa-regular {
font-weight: 400; }
.fa-regular { font-weight : normal; }
@@ -4,16 +4,15 @@
* Copyright 2024 Fonticons, Inc.
*/
:root, :host {
--fa-style-family-classic: 'Font Awesome 6 Free';
--fa-font-solid: normal 900 1em/1 'Font Awesome 6 Free'; }
--fa-style-family-classic : 'Font Awesome 6 Free';
--fa-font-solid : normal 900 1em/1 'Font Awesome 6 Free'; }
@font-face {
font-family: 'Font Awesome 6 Free';
font-style: normal;
font-weight: 900;
font-display: block;
src: url("/fonts/iconFonts/fa-solid-900.woff2") format("woff2"), url("/fonts/iconFonts/fa-solid-900.ttf") format("truetype"); }
font-family : 'Font Awesome 6 Free';
font-style : normal;
font-weight : 900;
src : url('/fonts/iconFonts/fa-solid-900.woff2') format('woff2'), url('/fonts/iconFonts/fa-solid-900.ttf') format('truetype');
font-display : block; }
.fas,
.fa-solid {
font-weight: 900; }
.fa-solid { font-weight : 900; }
+12 -75
View File
@@ -1,91 +1,28 @@
import React, { useEffect } from 'react';
//old vitreum file, still imported in some pages
const injectTag = (tag, props, children)=>{
const injectNode = document.createElement(tag);
Object.entries(props).forEach(([key, val])=>injectNode[key] = val);
if(children) injectNode.appendChild(document.createTextNode(children));
document.getElementsByTagName('head')[0].appendChild(injectNode);
};
const obj2props = (obj)=>Object.entries(obj)
.map(([k, v])=>`${k}="${v}"`)
const obj2props = (obj) =>
Object.entries(obj)
.map(([k, v]) => `${k}="${v}"`)
.join(' ');
const toStr = (chld)=>(Array.isArray(chld) ? chld.join('') : chld);
const onServer = typeof window === 'undefined';
let NamedTags = {};
let UnnamedTags = [];
export const HeadComponents = {
Title({ children }) {
if(onServer) NamedTags.title = `<title>${toStr(children)}</title>`;
useEffect(()=>{
document.title = toStr(children);
}, [children]);
return null;
},
Favicon({ type = 'image/png', href = '', rel = 'icon', id = 'favicon' }) {
if(onServer) NamedTags.favicon = `<link rel='shortcut icon' type="${type}" id="${id}" href="${href}" />`;
useEffect(()=>{
document.getElementById(id).href = href;
}, [id, href]);
return null;
},
Description({ children }) {
if(onServer) NamedTags.description = `<meta name='description' content='${toStr(children)}' />`;
return null;
},
Noscript({ children }) {
if(onServer) UnnamedTags.push(`<noscript>${toStr(children)}</noscript>`);
return null;
},
Script({ children = [], ...props }) {
if(onServer) {
UnnamedTags.push(
children.length
? `<script ${obj2props(props)}>${toStr(children)}</script>`
: `<script ${obj2props(props)} />`,
);
}
return null;
},
const HeadComponents = {
Meta(props) {
const tag = `<meta ${obj2props(props)} />`;
props.property || props.name ? (NamedTags[props.property || props.name] = tag) : UnnamedTags.push(tag);
useEffect(()=>{
props.property || props.name
? (NamedTags[props.property || props.name] = tag)
: null;
useEffect(() => {
document
.getElementsByTagName('head')[0]
.insertAdjacentHTML('beforeend', Object.values(NamedTags).join('\n'));
}, [NamedTags]);
return null;
},
Style({ children, type = 'text/css' }) {
if(onServer) UnnamedTags.push(`<style type="${type}">${toStr(children)}</style>`);
return null;
},
};
export const Inject = ({ tag, children, ...props })=>{
useEffect(()=>{
injectTag(tag, props, children);
}, []);
return null;
};
export const generate = ()=>Object.values(NamedTags).concat(UnnamedTags).join('\n');
export const flush = ()=>{
NamedTags = {};
UnnamedTags = [];
};
export const Meta = HeadComponents.Meta;
export default {
Inject,
...HeadComponents,
generate,
flush,
};
export default HeadComponents;